Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 13 Jan 2011 18:32:54 +0000 (10:32 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 13 Jan 2011 18:32:54 +0000 (10:32 -0800)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (348 commits)
  ALSA: hda - Fix NULL-derefence with a single mic in STAC auto-mic detection
  ALSA: hda - Add missing NID 0x19 fixup for Sony VAIO
  ALSA: hda - Fix ALC275 enable hardware EQ for SONY VAIO
  ALSA: oxygen: fix Xonar DG input
  ALSA: hda - Fix EAPD on Lenovo NB ALC269 to low
  ALSA: hda - Fix missing EAPD for Acer 4930G
  ALSA: hda: Disable 4/6 channels on some NVIDIA GPUs.
  ALSA: hda - Add static_hdmi_pcm option to HDMI codec parser
  ALSA: hda - Don't refer ELD when unplugged
  ASoC: tpa6130a2: Fix compiler warning
  ASoC: tlv320dac33: Add DAPM selection for LOM invert
  ASoC: DMIC codec: Adding a generic DMIC codec
  ALSA: snd-usb-us122l: Fix missing NULL checks
  ALSA: snd-usb-us122l: Fix MIDI output
  ASoC: soc-cache: Fix invalid memory access during snd_soc_lzo_cache_sync()
  ASoC: Fix section mismatch in wm8995.c
  ALSA: oxygen: add S/PDIF source selection for Claro cards
  ALSA: oxygen: fix CD/MIDI for X-Meridian (2G)
  ASoC: fix migor audio build
  ALSA: include delay.h for msleep in Xonar DG support
  ...

329 files changed:
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/HD-Audio-Models.txt
MAINTAINERS
arch/arm/mach-kirkwood/openrd-setup.c
arch/arm/mach-s3c2410/mach-h1940.c
arch/arm/mach-s3c2440/mach-rx1950.c
arch/arm/mach-s3c64xx/clock.c
arch/arm/mach-s3c64xx/dev-audio.c
arch/arm/mach-s3c64xx/mach-smdk6410.c
arch/arm/mach-s5p6442/dev-audio.c
arch/arm/mach-s5p64x0/clock-s5p6440.c
arch/arm/mach-s5p64x0/clock-s5p6450.c
arch/arm/mach-s5p64x0/dev-audio.c
arch/arm/mach-s5pc100/dev-audio.c
arch/arm/mach-s5pc100/mach-smdkc100.c
arch/arm/mach-s5pv210/clock.c
arch/arm/mach-s5pv210/dev-audio.c
arch/arm/mach-s5pv310/Kconfig
arch/arm/mach-s5pv310/Makefile
arch/arm/mach-s5pv310/dev-audio.c [new file with mode: 0644]
arch/arm/mach-s5pv310/dma.c [new file with mode: 0644]
arch/arm/mach-s5pv310/include/mach/dma.h [new file with mode: 0644]
arch/arm/mach-s5pv310/include/mach/irqs.h
arch/arm/mach-s5pv310/include/mach/map.h
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/plat-s3c24xx/devs.c
arch/arm/plat-samsung/Makefile
arch/arm/plat-samsung/dev-asocdma.c [new file with mode: 0644]
arch/arm/plat-samsung/include/plat/audio.h
arch/arm/plat-samsung/include/plat/devs.h
arch/sh/boards/mach-se/7724/setup.c
drivers/gpio/wm8994-gpio.c
drivers/mfd/wm8994-core.c
drivers/regulator/wm8994-regulator.c
drivers/video/sh_mobile_hdmi.c
include/linux/mfd/wm8994/core.h
include/linux/mfd/wm8994/pdata.h
include/linux/mfd/wm8994/registers.h
include/sound/alc5623.h [new file with mode: 0644]
include/sound/asound.h
include/sound/control.h
include/sound/hdsp.h
include/sound/minors.h
include/sound/pcm.h
include/sound/soc-dai.h
include/sound/soc-dapm.h
include/sound/soc.h
include/trace/events/asoc.h [new file with mode: 0644]
sound/ac97_bus.c
sound/aoa/codecs/onyx.c
sound/aoa/core/gpio-feature.c
sound/aoa/core/gpio-pmf.c
sound/core/control.c
sound/core/oss/pcm_oss.c
sound/core/pcm_lib.c
sound/core/pcm_native.c
sound/core/seq/seq.c
sound/core/sound.c
sound/core/timer.c
sound/drivers/ml403-ac97cr.c
sound/i2c/other/ak4113.c
sound/i2c/other/ak4114.c
sound/pci/Kconfig
sound/pci/ac97/ac97_codec.c
sound/pci/azt3328.c
sound/pci/bt87x.c
sound/pci/cmipci.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_analog.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/delta.c
sound/pci/ice1712/delta.h
sound/pci/oxygen/Makefile
sound/pci/oxygen/cs4245.h [new file with mode: 0644]
sound/pci/oxygen/hifier.c [deleted file]
sound/pci/oxygen/oxygen.c
sound/pci/oxygen/oxygen.h
sound/pci/oxygen/oxygen_io.c
sound/pci/oxygen/oxygen_lib.c
sound/pci/oxygen/oxygen_mixer.c
sound/pci/oxygen/oxygen_pcm.c
sound/pci/oxygen/oxygen_regs.h
sound/pci/oxygen/xonar.h
sound/pci/oxygen/xonar_cs43xx.c
sound/pci/oxygen/xonar_dg.c [new file with mode: 0644]
sound/pci/oxygen/xonar_dg.h [new file with mode: 0644]
sound/pci/oxygen/xonar_hdmi.c
sound/pci/oxygen/xonar_lib.c
sound/pci/oxygen/xonar_pcm179x.c
sound/pci/oxygen/xonar_wm87x6.c
sound/pci/rme9652/hdsp.c
sound/pci/ymfpci/ymfpci_main.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/atmel/playpaq_wm8510.c
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/atmel/snd-soc-afeb9260.c
sound/soc/au1x/db1200.c
sound/soc/blackfin/bf5xx-ad1836.c
sound/soc/blackfin/bf5xx-ad193x.c
sound/soc/blackfin/bf5xx-ad73311.c
sound/soc/blackfin/bf5xx-ssm2602.c
sound/soc/codecs/88pm860x-codec.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ad1836.c
sound/soc/codecs/ad193x.c
sound/soc/codecs/ad1980.c
sound/soc/codecs/ak4535.c
sound/soc/codecs/ak4642.c
sound/soc/codecs/ak4671.c
sound/soc/codecs/alc5623.c [new file with mode: 0644]
sound/soc/codecs/alc5623.h [new file with mode: 0644]
sound/soc/codecs/cq93vc.c
sound/soc/codecs/cs4270.c
sound/soc/codecs/cs42l51.c
sound/soc/codecs/cx20442.c
sound/soc/codecs/da7210.c
sound/soc/codecs/dmic.c [new file with mode: 0644]
sound/soc/codecs/jz4740.c
sound/soc/codecs/max98088.c
sound/soc/codecs/ssm2602.c
sound/soc/codecs/stac9766.c
sound/soc/codecs/tlv320aic23.c
sound/soc/codecs/tlv320aic26.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320dac33.c
sound/soc/codecs/tpa6130a2.c
sound/soc/codecs/tpa6130a2.h
sound/soc/codecs/twl4030.c
sound/soc/codecs/twl6040.c
sound/soc/codecs/twl6040.h
sound/soc/codecs/uda134x.c
sound/soc/codecs/uda1380.c
sound/soc/codecs/wl1273.c
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8523.c
sound/soc/codecs/wm8580.c
sound/soc/codecs/wm8711.c
sound/soc/codecs/wm8728.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8737.c [new file with mode: 0644]
sound/soc/codecs/wm8737.h [new file with mode: 0644]
sound/soc/codecs/wm8741.c
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8770.c [new file with mode: 0644]
sound/soc/codecs/wm8770.h [new file with mode: 0644]
sound/soc/codecs/wm8776.c
sound/soc/codecs/wm8804.c
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8903.h
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8940.c
sound/soc/codecs/wm8955.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8961.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8971.c
sound/soc/codecs/wm8974.c
sound/soc/codecs/wm8978.c
sound/soc/codecs/wm8985.c
sound/soc/codecs/wm8988.c
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm8994-tables.c [new file with mode: 0644]
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8994.h
sound/soc/codecs/wm8995.c [new file with mode: 0644]
sound/soc/codecs/wm8995.h [new file with mode: 0644]
sound/soc/codecs/wm9081.c
sound/soc/codecs/wm9090.c
sound/soc/codecs/wm9705.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm_hubs.c
sound/soc/codecs/wm_hubs.h
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-sffsdr.c
sound/soc/ep93xx/ep93xx-i2s.c
sound/soc/ep93xx/ep93xx-pcm.c
sound/soc/ep93xx/snappercl15.c
sound/soc/imx/eukrea-tlv320.c
sound/soc/imx/imx-ssi.c
sound/soc/imx/phycore-ac97.c
sound/soc/imx/wm1133-ev1.c
sound/soc/jz4740/jz4740-i2s.c
sound/soc/jz4740/qi_lb60.c
sound/soc/kirkwood/Kconfig
sound/soc/kirkwood/Makefile
sound/soc/kirkwood/kirkwood-openrd.c
sound/soc/kirkwood/kirkwood-t5325.c [new file with mode: 0644]
sound/soc/nuc900/nuc900-audio.c
sound/soc/omap/am3517evm.c
sound/soc/omap/ams-delta.c
sound/soc/omap/igep0020.c
sound/soc/omap/n810.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-mcbsp.h
sound/soc/omap/omap2evm.c
sound/soc/omap/omap3beagle.c
sound/soc/omap/omap3evm.c
sound/soc/omap/omap3pandora.c
sound/soc/omap/osk5912.c
sound/soc/omap/overo.c
sound/soc/omap/rx51.c
sound/soc/omap/sdp3430.c
sound/soc/omap/sdp4430.c
sound/soc/omap/zoom2.c
sound/soc/pxa/corgi.c
sound/soc/pxa/e740_wm9705.c
sound/soc/pxa/e750_wm9705.c
sound/soc/pxa/e800_wm9712.c
sound/soc/pxa/em-x270.c
sound/soc/pxa/magician.c
sound/soc/pxa/mioa701_wm9713.c
sound/soc/pxa/palm27x.c
sound/soc/pxa/poodle.c
sound/soc/pxa/raumfeld.c
sound/soc/pxa/saarb.c
sound/soc/pxa/spitz.c
sound/soc/pxa/tavorevb3.c
sound/soc/pxa/tosa.c
sound/soc/pxa/z2.c
sound/soc/pxa/zylonite.c
sound/soc/s3c24xx/Kconfig [deleted file]
sound/soc/s3c24xx/Makefile [deleted file]
sound/soc/s3c24xx/aquila_wm8994.c [deleted file]
sound/soc/s3c24xx/goni_wm8994.c [deleted file]
sound/soc/s3c24xx/jive_wm8750.c [deleted file]
sound/soc/s3c24xx/lm4857.h [deleted file]
sound/soc/s3c24xx/ln2440sbc_alc650.c [deleted file]
sound/soc/s3c24xx/neo1973_gta02_wm8753.c [deleted file]
sound/soc/s3c24xx/neo1973_wm8753.c [deleted file]
sound/soc/s3c24xx/regs-i2s-v2.h [deleted file]
sound/soc/s3c24xx/rx1950_uda1380.c [deleted file]
sound/soc/s3c24xx/s3c-ac97.c [deleted file]
sound/soc/s3c24xx/s3c-ac97.h [deleted file]
sound/soc/s3c24xx/s3c-dma.c [deleted file]
sound/soc/s3c24xx/s3c-dma.h [deleted file]
sound/soc/s3c24xx/s3c-i2s-v2.c [deleted file]
sound/soc/s3c24xx/s3c-i2s-v2.h [deleted file]
sound/soc/s3c24xx/s3c-pcm.c [deleted file]
sound/soc/s3c24xx/s3c-pcm.h [deleted file]
sound/soc/s3c24xx/s3c2412-i2s.c [deleted file]
sound/soc/s3c24xx/s3c2412-i2s.h [deleted file]
sound/soc/s3c24xx/s3c24xx-i2s.c [deleted file]
sound/soc/s3c24xx/s3c24xx-i2s.h [deleted file]
sound/soc/s3c24xx/s3c24xx_simtec.c [deleted file]
sound/soc/s3c24xx/s3c24xx_simtec.h [deleted file]
sound/soc/s3c24xx/s3c24xx_simtec_hermes.c [deleted file]
sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c [deleted file]
sound/soc/s3c24xx/s3c24xx_uda134x.c [deleted file]
sound/soc/s3c24xx/s3c64xx-i2s-v4.c [deleted file]
sound/soc/s3c24xx/s3c64xx-i2s.c [deleted file]
sound/soc/s3c24xx/s3c64xx-i2s.h [deleted file]
sound/soc/s3c24xx/smartq_wm8987.c [deleted file]
sound/soc/s3c24xx/smdk2443_wm9710.c [deleted file]
sound/soc/s3c24xx/smdk64xx_wm8580.c [deleted file]
sound/soc/s3c24xx/smdk_spdif.c [deleted file]
sound/soc/s3c24xx/smdk_wm9713.c [deleted file]
sound/soc/s3c24xx/spdif.c [deleted file]
sound/soc/s3c24xx/spdif.h [deleted file]
sound/soc/s6000/s6105-ipcam.c
sound/soc/samsung/Kconfig [new file with mode: 0644]
sound/soc/samsung/Makefile [new file with mode: 0644]
sound/soc/samsung/ac97.c [new file with mode: 0644]
sound/soc/samsung/ac97.h [new file with mode: 0644]
sound/soc/samsung/dma.c [new file with mode: 0644]
sound/soc/samsung/dma.h [new file with mode: 0644]
sound/soc/samsung/goni_wm8994.c [new file with mode: 0644]
sound/soc/samsung/h1940_uda1380.c [new file with mode: 0644]
sound/soc/samsung/i2s.c [new file with mode: 0644]
sound/soc/samsung/i2s.h [new file with mode: 0644]
sound/soc/samsung/jive_wm8750.c [new file with mode: 0644]
sound/soc/samsung/lm4857.h [new file with mode: 0644]
sound/soc/samsung/ln2440sbc_alc650.c [new file with mode: 0644]
sound/soc/samsung/neo1973_gta02_wm8753.c [new file with mode: 0644]
sound/soc/samsung/neo1973_wm8753.c [new file with mode: 0644]
sound/soc/samsung/pcm.c [new file with mode: 0644]
sound/soc/samsung/pcm.h [new file with mode: 0644]
sound/soc/samsung/regs-i2s-v2.h [new file with mode: 0644]
sound/soc/samsung/rx1950_uda1380.c [new file with mode: 0644]
sound/soc/samsung/s3c-i2s-v2.c [new file with mode: 0644]
sound/soc/samsung/s3c-i2s-v2.h [new file with mode: 0644]
sound/soc/samsung/s3c2412-i2s.c [new file with mode: 0644]
sound/soc/samsung/s3c2412-i2s.h [new file with mode: 0644]
sound/soc/samsung/s3c24xx-i2s.c [new file with mode: 0644]
sound/soc/samsung/s3c24xx-i2s.h [new file with mode: 0644]
sound/soc/samsung/s3c24xx_simtec.c [new file with mode: 0644]
sound/soc/samsung/s3c24xx_simtec.h [new file with mode: 0644]
sound/soc/samsung/s3c24xx_simtec_hermes.c [new file with mode: 0644]
sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c [new file with mode: 0644]
sound/soc/samsung/s3c24xx_uda134x.c [new file with mode: 0644]
sound/soc/samsung/smartq_wm8987.c [new file with mode: 0644]
sound/soc/samsung/smdk2443_wm9710.c [new file with mode: 0644]
sound/soc/samsung/smdk_spdif.c [new file with mode: 0644]
sound/soc/samsung/smdk_wm8580.c [new file with mode: 0644]
sound/soc/samsung/smdk_wm8994.c [new file with mode: 0644]
sound/soc/samsung/smdk_wm9713.c [new file with mode: 0644]
sound/soc/samsung/spdif.c [new file with mode: 0644]
sound/soc/samsung/spdif.h [new file with mode: 0644]
sound/soc/sh/Kconfig
sound/soc/sh/fsi-ak4642.c
sound/soc/sh/fsi-da7210.c
sound/soc/sh/fsi.c
sound/soc/sh/migor.c
sound/soc/sh/sh7760-ac97.c
sound/soc/sh/siu.h
sound/soc/sh/siu_dai.c
sound/soc/sh/siu_pcm.c
sound/soc/soc-cache.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-jack.c
sound/usb/format.c
sound/usb/midi.c
sound/usb/mixer.c
sound/usb/quirks-table.h
sound/usb/usx2y/us122l.c

index d0eb696..3c1eddd 100644 (file)
@@ -974,13 +974,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     See hdspm.txt for details.
 
-  Module snd-hifier
-  -----------------
-
-    Module for the MediaTek/TempoTec HiFier Fantasia sound card.
-
-    This module supports autoprobe and multiple cards.
-
   Module snd-ice1712
   ------------------
 
@@ -1531,15 +1524,20 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
   Module snd-oxygen
   -----------------
 
-    Module for sound cards based on the C-Media CMI8788 chip:
+    Module for sound cards based on the C-Media CMI8786/8787/8788 chip:
     * Asound A-8788
+    * Asus Xonar DG
     * AuzenTech X-Meridian
+    * AuzenTech X-Meridian 2G
     * Bgears b-Enspirer
     * Club3D Theatron DTS
     * HT-Omega Claro (plus)
     * HT-Omega Claro halo (XT)
+    * Kuroutoshikou CMI8787-HG2PCI
     * Razer Barracuda AC-1
     * Sondigo Inferno
+    * TempoTec HiFier Fantasia
+    * TempoTec HiFier Serenade
 
     This module supports autoprobe and multiple cards.
 
@@ -2006,9 +2004,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
   Module snd-virtuoso
   -------------------
 
-    Module for sound cards based on the Asus AV100/AV200 chips,
-    i.e., Xonar D1, DX, D2, D2X, DS, HDAV1.3 (Deluxe), Essence ST
-    (Deluxe) and Essence STX.
+    Module for sound cards based on the Asus AV66/AV100/AV200 chips,
+    i.e., Xonar D1, DX, D2, D2X, DS, Essence ST (Deluxe), Essence STX,
+    HDAV1.3 (Deluxe), and HDAV1.3 Slim.
 
     This module supports autoprobe and multiple cards.
 
index 37c6aad..16ae430 100644 (file)
@@ -149,7 +149,6 @@ ALC882/883/885/888/889
   acer-aspire-7730g Acer Aspire 7730G
   acer-aspire-8930g Acer Aspire 8930G
   medion       Medion Laptops
-  medion-md2   Medion MD2
   targa-dig    Targa/MSI
   targa-2ch-dig        Targa/MSI with 2-channel
   targa-8ch-dig Targa/MSI with 8-channel (MSI GX620)
index 78162c4..3dd5c6f 100644 (file)
@@ -1523,6 +1523,14 @@ S:       Supported
 F:     block/bsg.c
 F:     include/linux/bsg.h
 
+BT87X AUDIO DRIVER
+M:     Clemens Ladisch <clemens@ladisch.de>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+T:     git git://git.alsa-project.org/alsa-kernel.git
+S:     Maintained
+F:     Documentation/sound/alsa/Bt87x.txt
+F:     sound/pci/bt87x.c
+
 BT8XXGPIO DRIVER
 M:     Michael Buesch <mb@bu3sch.de>
 W:     http://bu3sch.de/btgpio.php
@@ -1548,6 +1556,13 @@ S:       Maintained
 F:     Documentation/video4linux/bttv/
 F:     drivers/media/video/bt8xx/bttv*
 
+C-MEDIA CMI8788 DRIVER
+M:     Clemens Ladisch <clemens@ladisch.de>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+T:     git git://git.alsa-project.org/alsa-kernel.git
+S:     Maintained
+F:     sound/pci/oxygen/
+
 CACHEFILES: FS-CACHE BACKEND FOR CACHING ON MOUNTED FILESYSTEMS
 M:     David Howells <dhowells@redhat.com>
 L:     linux-cachefs@redhat.com
@@ -2339,6 +2354,13 @@ W:       bluesmoke.sourceforge.net
 S:     Maintained
 F:     drivers/edac/r82600_edac.c
 
+EDIROL UA-101/UA-1000 DRIVER
+M:     Clemens Ladisch <clemens@ladisch.de>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+T:     git git://git.alsa-project.org/alsa-kernel.git
+S:     Maintained
+F:     sound/usb/misc/ua101.c
+
 EEEPC LAPTOP EXTRAS DRIVER
 M:     Corentin Chary <corentincj@iksaif.net>
 L:     acpi4asus-user@lists.sourceforge.net
@@ -3507,6 +3529,13 @@ L:       linux-serial@vger.kernel.org
 S:     Maintained
 F:     drivers/serial/jsm/
 
+K10TEMP HARDWARE MONITORING DRIVER
+M:     Clemens Ladisch <clemens@ladisch.de>
+L:     lm-sensors@lm-sensors.org
+S:     Maintained
+F:     Documentation/hwmon/k10temp
+F:     drivers/hwmon/k10temp.c
+
 K8TEMP HARDWARE MONITORING DRIVER
 M:     Rudolf Marek <r.marek@assembler.cz>
 L:     lm-sensors@lm-sensors.org
@@ -4537,6 +4566,13 @@ F:       drivers/of
 F:     include/linux/of*.h
 K:     of_get_property
 
+OPL4 DRIVER
+M:     Clemens Ladisch <clemens@ladisch.de>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+T:     git git://git.alsa-project.org/alsa-kernel.git
+S:     Maintained
+F:     sound/drivers/opl4/
+
 OPROFILE
 M:     Robert Richter <robert.richter@amd.com>
 L:     oprofile-list@lists.sf.net
@@ -5283,7 +5319,7 @@ SAMSUNG AUDIO (ASoC) DRIVERS
 M:     Jassi Brar <jassi.brar@samsung.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Supported
-F:     sound/soc/s3c24xx
+F:     sound/soc/samsung
 
 TIMEKEEPING, NTP
 M:     John Stultz <johnstul@us.ibm.com>
@@ -6291,6 +6327,13 @@ S:       Maintained
 W:     http://www.one-eyed-alien.net/~mdharm/linux-usb/
 F:     drivers/usb/storage/
 
+USB MIDI DRIVER
+M:     Clemens Ladisch <clemens@ladisch.de>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+T:     git git://git.alsa-project.org/alsa-kernel.git
+S:     Maintained
+F:     sound/usb/midi.*
+
 USB OHCI DRIVER
 M:     David Brownell <dbrownell@users.sourceforge.net>
 L:     linux-usb@vger.kernel.org
index c9d77fa..cfcca41 100644 (file)
@@ -171,7 +171,7 @@ static void __init openrd_init(void)
 
        kirkwood_i2c_init();
 
-       if (machine_is_openrd_client()) {
+       if (machine_is_openrd_client() || machine_is_openrd_ultimate()) {
                i2c_register_board_info(0, i2c_board_info,
                        ARRAY_SIZE(i2c_board_info));
                kirkwood_audio_init();
index d7ada8c..1a81fe1 100644 (file)
@@ -387,7 +387,7 @@ static struct platform_device *h1940_devices[] __initdata = {
        &s3c_device_wdt,
        &s3c_device_i2c0,
        &s3c_device_iis,
-       &s3c_device_pcm,
+       &samsung_asoc_dma,
        &s3c_device_usbgadget,
        &h1940_device_leds,
        &h1940_device_bluetooth,
index e0622bb..eab6ae5 100644 (file)
@@ -692,7 +692,7 @@ static struct platform_device *rx1950_devices[] __initdata = {
        &s3c_device_wdt,
        &s3c_device_i2c0,
        &s3c_device_iis,
-       &s3c_device_pcm,
+       &samsung_asoc_dma,
        &s3c_device_usbgadget,
        &s3c_device_rtc,
        &s3c_device_nand,
index 7e03f0a..1c98d2f 100644 (file)
@@ -695,7 +695,7 @@ static struct clksrc_clk clksrcs[] = {
        }, {
                .clk    = {
                        .name           = "audio-bus",
-                       .id             = -1,  /* There's only one IISv4 port */
+                       .id             = 2,
                        .ctrlbit        = S3C6410_CLKCON_SCLK_AUDIO2,
                        .enable         = s3c64xx_sclk_ctrl,
                },
index 76426a3..cad6702 100644 (file)
 #include <plat/audio.h>
 #include <plat/gpio-cfg.h>
 
-static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev)
+static const char *rclksrc[] = {
+       [0] = "iis",
+       [1] = "audio-bus",
+};
+
+static int s3c64xx_i2s_cfg_gpio(struct platform_device *pdev)
 {
        unsigned int base;
 
@@ -33,6 +38,12 @@ static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev)
        case 1:
                base = S3C64XX_GPE(0);
                break;
+       case 2:
+               s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C_GPIO_SFN(5));
+               s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C_GPIO_SFN(5));
+               s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C_GPIO_SFN(5));
+               s3c_gpio_cfgpin_range(S3C64XX_GPH(6), 4, S3C_GPIO_SFN(5));
+               return 0;
        default:
                printk(KERN_DEBUG "Invalid I2S Controller number: %d\n",
                        pdev->id);
@@ -44,16 +55,6 @@ static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev)
        return 0;
 }
 
-static int s3c64xx_i2sv4_cfg_gpio(struct platform_device *pdev)
-{
-       s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C_GPIO_SFN(5));
-       s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C_GPIO_SFN(5));
-       s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C_GPIO_SFN(5));
-       s3c_gpio_cfgpin_range(S3C64XX_GPH(6), 4, S3C_GPIO_SFN(5));
-
-       return 0;
-}
-
 static struct resource s3c64xx_iis0_resource[] = {
        [0] = {
                .start = S3C64XX_PA_IIS0,
@@ -72,17 +73,22 @@ static struct resource s3c64xx_iis0_resource[] = {
        },
 };
 
-static struct s3c_audio_pdata s3c_i2s0_pdata = {
-       .cfg_gpio = s3c64xx_i2sv3_cfg_gpio,
+static struct s3c_audio_pdata i2sv3_pdata = {
+       .cfg_gpio = s3c64xx_i2s_cfg_gpio,
+       .type = {
+               .i2s = {
+                       .src_clk = rclksrc,
+               },
+       },
 };
 
 struct platform_device s3c64xx_device_iis0 = {
-       .name             = "s3c64xx-iis",
+       .name             = "samsung-i2s",
        .id               = 0,
        .num_resources    = ARRAY_SIZE(s3c64xx_iis0_resource),
        .resource         = s3c64xx_iis0_resource,
        .dev = {
-               .platform_data = &s3c_i2s0_pdata,
+               .platform_data = &i2sv3_pdata,
        },
 };
 EXPORT_SYMBOL(s3c64xx_device_iis0);
@@ -105,17 +111,13 @@ static struct resource s3c64xx_iis1_resource[] = {
        },
 };
 
-static struct s3c_audio_pdata s3c_i2s1_pdata = {
-       .cfg_gpio = s3c64xx_i2sv3_cfg_gpio,
-};
-
 struct platform_device s3c64xx_device_iis1 = {
-       .name             = "s3c64xx-iis",
+       .name             = "samsung-i2s",
        .id               = 1,
        .num_resources    = ARRAY_SIZE(s3c64xx_iis1_resource),
        .resource         = s3c64xx_iis1_resource,
        .dev = {
-               .platform_data = &s3c_i2s1_pdata,
+               .platform_data = &i2sv3_pdata,
        },
 };
 EXPORT_SYMBOL(s3c64xx_device_iis1);
@@ -138,17 +140,23 @@ static struct resource s3c64xx_iisv4_resource[] = {
        },
 };
 
-static struct s3c_audio_pdata s3c_i2sv4_pdata = {
-       .cfg_gpio = s3c64xx_i2sv4_cfg_gpio,
+static struct s3c_audio_pdata i2sv4_pdata = {
+       .cfg_gpio = s3c64xx_i2s_cfg_gpio,
+       .type = {
+               .i2s = {
+                       .quirks = QUIRK_PRI_6CHAN,
+                       .src_clk = rclksrc,
+               },
+       },
 };
 
 struct platform_device s3c64xx_device_iisv4 = {
-       .name             = "s3c64xx-iis-v4",
-       .id               = -1,
+       .name = "samsung-i2s",
+       .id = 2,
        .num_resources    = ARRAY_SIZE(s3c64xx_iisv4_resource),
        .resource         = s3c64xx_iisv4_resource,
        .dev = {
-               .platform_data = &s3c_i2sv4_pdata,
+               .platform_data = &i2sv4_pdata,
        },
 };
 EXPORT_SYMBOL(s3c64xx_device_iisv4);
@@ -288,7 +296,7 @@ static struct s3c_audio_pdata s3c_ac97_pdata;
 static u64 s3c64xx_ac97_dmamask = DMA_BIT_MASK(32);
 
 struct platform_device s3c64xx_device_ac97 = {
-       .name             = "s3c-ac97",
+       .name             = "samsung-ac97",
        .id               = -1,
        .num_resources    = ARRAY_SIZE(s3c64xx_ac97_resource),
        .resource         = s3c64xx_ac97_resource,
@@ -307,16 +315,3 @@ void __init s3c64xx_ac97_setup_gpio(int num)
        else
                s3c_ac97_pdata.cfg_gpio = s3c64xx_ac97_cfg_gpe;
 }
-
-static u64 s3c_device_audio_dmamask = 0xffffffffUL;
-
-struct platform_device s3c_device_pcm = {
-       .name             = "s3c24xx-pcm-audio",
-       .id               = -1,
-       .dev              = {
-               .dma_mask = &s3c_device_audio_dmamask,
-               .coherent_dma_mask = 0xffffffffUL
-       }
-};
-EXPORT_SYMBOL(s3c_device_pcm);
-
index 77488fa..e85192a 100644 (file)
@@ -283,7 +283,7 @@ static struct platform_device *smdk6410_devices[] __initdata = {
        &s3c_device_fb,
        &s3c_device_ohci,
        &s3c_device_usb_hsotg,
-       &s3c_device_pcm,
+       &samsung_asoc_dma,
        &s3c64xx_device_iisv4,
        &samsung_device_keypad,
 
index 3462197..8719dc4 100644 (file)
@@ -29,7 +29,7 @@ static int s5p6442_cfg_i2s(struct platform_device *pdev)
                base = S5P6442_GPC1(0);
                break;
 
-       case -1:
+       case 0:
                base = S5P6442_GPC0(0);
                break;
 
@@ -42,8 +42,19 @@ static int s5p6442_cfg_i2s(struct platform_device *pdev)
        return 0;
 }
 
-static struct s3c_audio_pdata s3c_i2s_pdata = {
+static const char *rclksrc_v35[] = {
+       [0] = "busclk",
+       [1] = "i2sclk",
+};
+
+static struct s3c_audio_pdata i2sv35_pdata = {
        .cfg_gpio = s5p6442_cfg_i2s,
+       .type = {
+               .i2s = {
+                       .quirks = QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR,
+                       .src_clk = rclksrc_v35,
+               },
+       },
 };
 
 static struct resource s5p6442_iis0_resource[] = {
@@ -62,15 +73,34 @@ static struct resource s5p6442_iis0_resource[] = {
                .end   = DMACH_I2S0_RX,
                .flags = IORESOURCE_DMA,
        },
+       [3] = {
+               .start = DMACH_I2S0S_TX,
+               .end = DMACH_I2S0S_TX,
+               .flags = IORESOURCE_DMA,
+       },
 };
 
 struct platform_device s5p6442_device_iis0 = {
-       .name             = "s3c64xx-iis-v4",
-       .id               = -1,
+       .name = "samsung-i2s",
+       .id = 0,
        .num_resources    = ARRAY_SIZE(s5p6442_iis0_resource),
        .resource         = s5p6442_iis0_resource,
        .dev = {
-               .platform_data = &s3c_i2s_pdata,
+               .platform_data = &i2sv35_pdata,
+       },
+};
+
+static const char *rclksrc_v3[] = {
+       [0] = "iis",
+       [1] = "sclk_audio",
+};
+
+static struct s3c_audio_pdata i2sv3_pdata = {
+       .cfg_gpio = s5p6442_cfg_i2s,
+       .type = {
+               .i2s = {
+                       .src_clk = rclksrc_v3,
+               },
        },
 };
 
@@ -93,12 +123,12 @@ static struct resource s5p6442_iis1_resource[] = {
 };
 
 struct platform_device s5p6442_device_iis1 = {
-       .name             = "s3c64xx-iis",
+       .name             = "samsung-i2s",
        .id               = 1,
        .num_resources    = ARRAY_SIZE(s5p6442_iis1_resource),
        .resource         = s5p6442_iis1_resource,
        .dev = {
-               .platform_data = &s3c_i2s_pdata,
+               .platform_data = &i2sv3_pdata,
        },
 };
 
index e4883dc..409c5fc 100644 (file)
@@ -261,7 +261,7 @@ static struct clk init_clocks_disable[] = {
                .enable         = s5p64x0_pclk_ctrl,
                .ctrlbit        = (1 << 25),
        }, {
-               .name           = "i2s_v40",
+               .name           = "iis",
                .id             = 0,
                .parent         = &clk_pclk_low.clk,
                .enable         = s5p64x0_pclk_ctrl,
index 7dbf3c9..7fc6abd 100644 (file)
@@ -256,7 +256,7 @@ static struct clk init_clocks_disable[] = {
                .ctrlbit        = (1 << 22),
        }, {
                .name           = "iis",
-               .id             = -1,
+               .id             = 0,
                .parent         = &clk_pclk_low.clk,
                .enable         = s5p64x0_pclk_ctrl,
                .ctrlbit        = (1 << 26),
index 396bacc..14f89e7 100644 (file)
 #include <mach/dma.h>
 #include <mach/irqs.h>
 
-static int s5p6440_cfg_i2s(struct platform_device *pdev)
+static const char *rclksrc[] = {
+       [0] = "iis",
+       [1] = "sclk_audio2",
+};
+
+static int s5p64x0_cfg_i2s(struct platform_device *pdev)
 {
        /* configure GPIO for i2s port */
        switch (pdev->id) {
-       case -1:
+       case 0:
                s3c_gpio_cfgpin_range(S5P6440_GPR(4), 5, S3C_GPIO_SFN(5));
                s3c_gpio_cfgpin_range(S5P6440_GPR(13), 2, S3C_GPIO_SFN(5));
                break;
-
        default:
                printk(KERN_ERR "Invalid Device %d\n", pdev->id);
                return -EINVAL;
@@ -36,31 +40,14 @@ static int s5p6440_cfg_i2s(struct platform_device *pdev)
        return 0;
 }
 
-static int s5p6450_cfg_i2s(struct platform_device *pdev)
-{
-       /* configure GPIO for i2s port */
-       switch (pdev->id) {
-       case -1:
-               s3c_gpio_cfgpin(S5P6450_GPB(4), S3C_GPIO_SFN(5));
-               s3c_gpio_cfgpin_range(S5P6450_GPR(4), 5, S3C_GPIO_SFN(5));
-               s3c_gpio_cfgpin_range(S5P6450_GPR(13), 2, S3C_GPIO_SFN(5));
-
-               break;
-
-       default:
-               printk(KERN_ERR "Invalid Device %d\n", pdev->id);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static struct s3c_audio_pdata s5p6440_i2s_pdata = {
-       .cfg_gpio = s5p6440_cfg_i2s,
-};
-
-static struct s3c_audio_pdata s5p6450_i2s_pdata = {
-       .cfg_gpio = s5p6450_cfg_i2s,
+static struct s3c_audio_pdata s5p64x0_i2s_pdata = {
+       .cfg_gpio = s5p64x0_cfg_i2s,
+       .type = {
+               .i2s = {
+                       .quirks = QUIRK_PRI_6CHAN,
+                       .src_clk = rclksrc,
+               },
+       },
 };
 
 static struct resource s5p64x0_iis0_resource[] = {
@@ -82,22 +69,22 @@ static struct resource s5p64x0_iis0_resource[] = {
 };
 
 struct platform_device s5p6440_device_iis = {
-       .name           = "s3c64xx-iis-v4",
-       .id             = -1,
+       .name           = "samsung-i2s",
+       .id             = 0,
        .num_resources  = ARRAY_SIZE(s5p64x0_iis0_resource),
        .resource       = s5p64x0_iis0_resource,
        .dev = {
-               .platform_data = &s5p6440_i2s_pdata,
+               .platform_data = &s5p64x0_i2s_pdata,
        },
 };
 
 struct platform_device s5p6450_device_iis0 = {
-       .name           = "s3c64xx-iis-v4",
-       .id             = -1,
+       .name           = "samsung-i2s",
+       .id             = 0,
        .num_resources  = ARRAY_SIZE(s5p64x0_iis0_resource),
        .resource       = s5p64x0_iis0_resource,
        .dev = {
-               .platform_data = &s5p6450_i2s_pdata,
+               .platform_data = &s5p64x0_i2s_pdata,
        },
 };
 
index 564e195..ab2d271 100644 (file)
@@ -23,17 +23,14 @@ static int s5pc100_cfg_i2s(struct platform_device *pdev)
 {
        /* configure GPIO for i2s port */
        switch (pdev->id) {
+       case 0: /* Dedicated pins */
+               break;
        case 1:
                s3c_gpio_cfgpin_range(S5PC100_GPC(0), 5, S3C_GPIO_SFN(2));
                break;
-
        case 2:
                s3c_gpio_cfgpin_range(S5PC100_GPG3(0), 5, S3C_GPIO_SFN(4));
                break;
-
-       case -1: /* Dedicated pins */
-               break;
-
        default:
                printk(KERN_ERR "Invalid Device %d\n", pdev->id);
                return -EINVAL;
@@ -42,8 +39,20 @@ static int s5pc100_cfg_i2s(struct platform_device *pdev)
        return 0;
 }
 
-static struct s3c_audio_pdata s3c_i2s_pdata = {
+static const char *rclksrc_v5[] = {
+       [0] = "iis",
+       [1] = "i2sclkd2",
+};
+
+static struct s3c_audio_pdata i2sv5_pdata = {
        .cfg_gpio = s5pc100_cfg_i2s,
+       .type = {
+               .i2s = {
+                       .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI
+                                        | QUIRK_NEED_RSTCLR,
+                       .src_clk = rclksrc_v5,
+               },
+       },
 };
 
 static struct resource s5pc100_iis0_resource[] = {
@@ -62,15 +71,34 @@ static struct resource s5pc100_iis0_resource[] = {
                .end   = DMACH_I2S0_RX,
                .flags = IORESOURCE_DMA,
        },
+       [3] = {
+               .start = DMACH_I2S0S_TX,
+               .end = DMACH_I2S0S_TX,
+               .flags = IORESOURCE_DMA,
+       },
 };
 
 struct platform_device s5pc100_device_iis0 = {
-       .name             = "s3c64xx-iis-v4",
-       .id               = -1,
+       .name = "samsung-i2s",
+       .id = 0,
        .num_resources    = ARRAY_SIZE(s5pc100_iis0_resource),
        .resource         = s5pc100_iis0_resource,
        .dev = {
-               .platform_data = &s3c_i2s_pdata,
+               .platform_data = &i2sv5_pdata,
+       },
+};
+
+static const char *rclksrc_v3[] = {
+       [0] = "iis",
+       [1] = "sclk_audio",
+};
+
+static struct s3c_audio_pdata i2sv3_pdata = {
+       .cfg_gpio = s5pc100_cfg_i2s,
+       .type = {
+               .i2s = {
+                       .src_clk = rclksrc_v3,
+               },
        },
 };
 
@@ -93,12 +121,12 @@ static struct resource s5pc100_iis1_resource[] = {
 };
 
 struct platform_device s5pc100_device_iis1 = {
-       .name             = "s3c64xx-iis",
+       .name             = "samsung-i2s",
        .id               = 1,
        .num_resources    = ARRAY_SIZE(s5pc100_iis1_resource),
        .resource         = s5pc100_iis1_resource,
        .dev = {
-               .platform_data = &s3c_i2s_pdata,
+               .platform_data = &i2sv3_pdata,
        },
 };
 
@@ -121,12 +149,12 @@ static struct resource s5pc100_iis2_resource[] = {
 };
 
 struct platform_device s5pc100_device_iis2 = {
-       .name             = "s3c64xx-iis",
+       .name             = "samsung-i2s",
        .id               = 2,
        .num_resources    = ARRAY_SIZE(s5pc100_iis2_resource),
        .resource         = s5pc100_iis2_resource,
        .dev = {
-               .platform_data = &s3c_i2s_pdata,
+               .platform_data = &i2sv3_pdata,
        },
 };
 
@@ -253,7 +281,7 @@ static struct s3c_audio_pdata s3c_ac97_pdata = {
 static u64 s5pc100_ac97_dmamask = DMA_BIT_MASK(32);
 
 struct platform_device s5pc100_device_ac97 = {
-       .name             = "s3c-ac97",
+       .name             = "samsung-ac97",
        .id               = -1,
        .num_resources    = ARRAY_SIZE(s5pc100_ac97_resource),
        .resource         = s5pc100_ac97_resource,
index 18b405d..dd192a2 100644 (file)
@@ -96,6 +96,7 @@ static struct s3c2410_uartcfg smdkc100_uartcfgs[] __initdata = {
 
 /* I2C0 */
 static struct i2c_board_info i2c_devs0[] __initdata = {
+       {I2C_BOARD_INFO("wm8580", 0x1b),},
 };
 
 /* I2C1 */
@@ -190,6 +191,7 @@ static struct platform_device *smdkc100_devices[] __initdata = {
        &s3c_device_ts,
        &s3c_device_wdt,
        &smdkc100_lcd_powerdev,
+       &samsung_asoc_dma,
        &s5pc100_device_iis0,
        &samsung_device_keypad,
        &s5pc100_device_ac97,
index 019c3a6..b774ff1 100644 (file)
@@ -467,20 +467,20 @@ static struct clk init_clocks_disable[] = {
                .enable         = s5pv210_clk_ip3_ctrl,
                .ctrlbit        = (1<<21),
        }, {
-               .name           = "i2s_v50",
+               .name           = "iis",
                .id             = 0,
                .parent         = &clk_p,
                .enable         = s5pv210_clk_ip3_ctrl,
                .ctrlbit        = (1<<4),
        }, {
-               .name           = "i2s_v32",
-               .id             = 0,
+               .name           = "iis",
+               .id             = 1,
                .parent         = &clk_p,
                .enable         = s5pv210_clk_ip3_ctrl,
                .ctrlbit        = (1 << 5),
        }, {
-               .name           = "i2s_v32",
-               .id             = 1,
+               .name           = "iis",
+               .id             = 2,
                .parent         = &clk_p,
                .enable         = s5pv210_clk_ip3_ctrl,
                .ctrlbit        = (1 << 6),
index 1303fcb..8d58f19 100644 (file)
 #include <mach/dma.h>
 #include <mach/irqs.h>
 
+static const char *rclksrc[] = {
+       [0] = "busclk",
+       [1] = "i2sclk",
+};
+
 static int s5pv210_cfg_i2s(struct platform_device *pdev)
 {
        /* configure GPIO for i2s port */
        switch (pdev->id) {
+       case 0:
+               s3c_gpio_cfgpin_range(S5PV210_GPI(0), 7, S3C_GPIO_SFN(2));
+               break;
        case 1:
                s3c_gpio_cfgpin_range(S5PV210_GPC0(0), 5, S3C_GPIO_SFN(2));
                break;
-
        case 2:
                s3c_gpio_cfgpin_range(S5PV210_GPC1(0), 5, S3C_GPIO_SFN(4));
                break;
-
-       case -1:
-               s3c_gpio_cfgpin_range(S5PV210_GPI(0), 7, S3C_GPIO_SFN(2));
-               break;
-
        default:
                printk(KERN_ERR "Invalid Device %d\n", pdev->id);
                return -EINVAL;
@@ -43,8 +45,15 @@ static int s5pv210_cfg_i2s(struct platform_device *pdev)
        return 0;
 }
 
-static struct s3c_audio_pdata s3c_i2s_pdata = {
+static struct s3c_audio_pdata i2sv5_pdata = {
        .cfg_gpio = s5pv210_cfg_i2s,
+       .type = {
+               .i2s = {
+                       .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI
+                                        | QUIRK_NEED_RSTCLR,
+                       .src_clk = rclksrc,
+               },
+       },
 };
 
 static struct resource s5pv210_iis0_resource[] = {
@@ -63,15 +72,34 @@ static struct resource s5pv210_iis0_resource[] = {
                .end   = DMACH_I2S0_RX,
                .flags = IORESOURCE_DMA,
        },
+       [3] = {
+               .start = DMACH_I2S0S_TX,
+               .end = DMACH_I2S0S_TX,
+               .flags = IORESOURCE_DMA,
+       },
 };
 
 struct platform_device s5pv210_device_iis0 = {
-       .name             = "s3c64xx-iis-v4",
-       .id               = -1,
+       .name = "samsung-i2s",
+       .id = 0,
        .num_resources    = ARRAY_SIZE(s5pv210_iis0_resource),
        .resource         = s5pv210_iis0_resource,
        .dev = {
-               .platform_data = &s3c_i2s_pdata,
+               .platform_data = &i2sv5_pdata,
+       },
+};
+
+static const char *rclksrc_v3[] = {
+       [0] = "iis",
+       [1] = "audio-bus",
+};
+
+static struct s3c_audio_pdata i2sv3_pdata = {
+       .cfg_gpio = s5pv210_cfg_i2s,
+       .type = {
+               .i2s = {
+                       .src_clk = rclksrc_v3,
+               },
        },
 };
 
@@ -94,12 +122,12 @@ static struct resource s5pv210_iis1_resource[] = {
 };
 
 struct platform_device s5pv210_device_iis1 = {
-       .name             = "s3c64xx-iis",
+       .name             = "samsung-i2s",
        .id               = 1,
        .num_resources    = ARRAY_SIZE(s5pv210_iis1_resource),
        .resource         = s5pv210_iis1_resource,
        .dev = {
-               .platform_data = &s3c_i2s_pdata,
+               .platform_data = &i2sv3_pdata,
        },
 };
 
@@ -122,12 +150,12 @@ static struct resource s5pv210_iis2_resource[] = {
 };
 
 struct platform_device s5pv210_device_iis2 = {
-       .name             = "s3c64xx-iis",
+       .name             = "samsung-i2s",
        .id               = 2,
        .num_resources    = ARRAY_SIZE(s5pv210_iis2_resource),
        .resource         = s5pv210_iis2_resource,
        .dev = {
-               .platform_data = &s3c_i2s_pdata,
+               .platform_data = &i2sv3_pdata,
        },
 };
 
@@ -283,7 +311,7 @@ static struct s3c_audio_pdata s3c_ac97_pdata = {
 static u64 s5pv210_ac97_dmamask = DMA_BIT_MASK(32);
 
 struct platform_device s5pv210_device_ac97 = {
-       .name             = "s3c-ac97",
+       .name             = "samsung-ac97",
        .id               = -1,
        .num_resources    = ARRAY_SIZE(s5pv210_ac97_resource),
        .resource         = s5pv210_ac97_resource,
index 1150b36..d64efe0 100644 (file)
@@ -11,6 +11,7 @@ if ARCH_S5PV310
 
 config CPU_S5PV310
        bool
+       select S3C_PL330_DMA
        help
          Enable S5PV310 CPU support
 
index 84afc64..61e3cb6 100644 (file)
@@ -13,7 +13,7 @@ obj-                          :=
 # Core support for S5PV310 system
 
 obj-$(CONFIG_CPU_S5PV310)      += cpu.o init.o clock.o irq-combiner.o
-obj-$(CONFIG_CPU_S5PV310)      += setup-i2c0.o time.o gpiolib.o irq-eint.o
+obj-$(CONFIG_CPU_S5PV310)      += setup-i2c0.o time.o gpiolib.o irq-eint.o dma.o
 
 obj-$(CONFIG_SMP)              += platsmp.o headsmp.o
 obj-$(CONFIG_LOCAL_TIMERS)     += localtimer.o
@@ -27,6 +27,7 @@ obj-$(CONFIG_MACH_UNIVERSAL_C210)     += mach-universal_c210.o
 
 # device support
 
+obj-y += dev-audio.o
 obj-$(CONFIG_S5PV310_SETUP_I2C1)       += setup-i2c1.o
 obj-$(CONFIG_S5PV310_SETUP_I2C2)       += setup-i2c2.o
 obj-$(CONFIG_S5PV310_SETUP_I2C3)       += setup-i2c3.o
diff --git a/arch/arm/mach-s5pv310/dev-audio.c b/arch/arm/mach-s5pv310/dev-audio.c
new file mode 100644 (file)
index 0000000..a196424
--- /dev/null
@@ -0,0 +1,364 @@
+/* linux/arch/arm/mach-s5pv310/dev-audio.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ *     Jaswinder Singh <jassi.brar@samsung.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/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/gpio.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/audio.h>
+
+#include <mach/map.h>
+#include <mach/dma.h>
+#include <mach/irqs.h>
+
+static const char *rclksrc[] = {
+       [0] = "busclk",
+       [1] = "i2sclk",
+};
+
+static int s5pv310_cfg_i2s(struct platform_device *pdev)
+{
+       /* configure GPIO for i2s port */
+       switch (pdev->id) {
+       case 0:
+               s3c_gpio_cfgpin_range(S5PV310_GPZ(0), 7, S3C_GPIO_SFN(2));
+               break;
+       case 1:
+               s3c_gpio_cfgpin_range(S5PV310_GPC0(0), 5, S3C_GPIO_SFN(2));
+               break;
+       case 2:
+               s3c_gpio_cfgpin_range(S5PV310_GPC1(0), 5, S3C_GPIO_SFN(4));
+               break;
+       default:
+               printk(KERN_ERR "Invalid Device %d\n", pdev->id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct s3c_audio_pdata i2sv5_pdata = {
+       .cfg_gpio = s5pv310_cfg_i2s,
+       .type = {
+               .i2s = {
+                       .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI
+                                        | QUIRK_NEED_RSTCLR,
+                       .src_clk = rclksrc,
+               },
+       },
+};
+
+static struct resource s5pv310_i2s0_resource[] = {
+       [0] = {
+               .start  = S5PV310_PA_I2S0,
+               .end    = S5PV310_PA_I2S0 + 0x100 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = DMACH_I2S0_TX,
+               .end    = DMACH_I2S0_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start  = DMACH_I2S0_RX,
+               .end    = DMACH_I2S0_RX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start  = DMACH_I2S0S_TX,
+               .end    = DMACH_I2S0S_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+struct platform_device s5pv310_device_i2s0 = {
+       .name = "samsung-i2s",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(s5pv310_i2s0_resource),
+       .resource = s5pv310_i2s0_resource,
+       .dev = {
+               .platform_data = &i2sv5_pdata,
+       },
+};
+
+static const char *rclksrc_v3[] = {
+       [0] = "sclk_i2s",
+       [1] = "no_such_clock",
+};
+
+static struct s3c_audio_pdata i2sv3_pdata = {
+       .cfg_gpio = s5pv310_cfg_i2s,
+       .type = {
+               .i2s = {
+                       .quirks = QUIRK_NO_MUXPSR,
+                       .src_clk = rclksrc_v3,
+               },
+       },
+};
+
+static struct resource s5pv310_i2s1_resource[] = {
+       [0] = {
+               .start  = S5PV310_PA_I2S1,
+               .end    = S5PV310_PA_I2S1 + 0x100 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = DMACH_I2S1_TX,
+               .end    = DMACH_I2S1_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start  = DMACH_I2S1_RX,
+               .end    = DMACH_I2S1_RX,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+struct platform_device s5pv310_device_i2s1 = {
+       .name = "samsung-i2s",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(s5pv310_i2s1_resource),
+       .resource = s5pv310_i2s1_resource,
+       .dev = {
+               .platform_data = &i2sv3_pdata,
+       },
+};
+
+static struct resource s5pv310_i2s2_resource[] = {
+       [0] = {
+               .start  = S5PV310_PA_I2S2,
+               .end    = S5PV310_PA_I2S2 + 0x100 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = DMACH_I2S2_TX,
+               .end    = DMACH_I2S2_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start  = DMACH_I2S2_RX,
+               .end    = DMACH_I2S2_RX,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+struct platform_device s5pv310_device_i2s2 = {
+       .name = "samsung-i2s",
+       .id = 2,
+       .num_resources = ARRAY_SIZE(s5pv310_i2s2_resource),
+       .resource = s5pv310_i2s2_resource,
+       .dev = {
+               .platform_data = &i2sv3_pdata,
+       },
+};
+
+/* PCM Controller platform_devices */
+
+static int s5pv310_pcm_cfg_gpio(struct platform_device *pdev)
+{
+       switch (pdev->id) {
+       case 0:
+               s3c_gpio_cfgpin_range(S5PV310_GPZ(0), 5, S3C_GPIO_SFN(3));
+               break;
+       case 1:
+               s3c_gpio_cfgpin_range(S5PV310_GPC0(0), 5, S3C_GPIO_SFN(3));
+               break;
+       case 2:
+               s3c_gpio_cfgpin_range(S5PV310_GPC1(0), 5, S3C_GPIO_SFN(3));
+               break;
+       default:
+               printk(KERN_DEBUG "Invalid PCM Controller number!");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct s3c_audio_pdata s3c_pcm_pdata = {
+       .cfg_gpio = s5pv310_pcm_cfg_gpio,
+};
+
+static struct resource s5pv310_pcm0_resource[] = {
+       [0] = {
+               .start  = S5PV310_PA_PCM0,
+               .end    = S5PV310_PA_PCM0 + 0x100 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = DMACH_PCM0_TX,
+               .end    = DMACH_PCM0_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start  = DMACH_PCM0_RX,
+               .end    = DMACH_PCM0_RX,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+struct platform_device s5pv310_device_pcm0 = {
+       .name = "samsung-pcm",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(s5pv310_pcm0_resource),
+       .resource = s5pv310_pcm0_resource,
+       .dev = {
+               .platform_data = &s3c_pcm_pdata,
+       },
+};
+
+static struct resource s5pv310_pcm1_resource[] = {
+       [0] = {
+               .start  = S5PV310_PA_PCM1,
+               .end    = S5PV310_PA_PCM1 + 0x100 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = DMACH_PCM1_TX,
+               .end    = DMACH_PCM1_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start  = DMACH_PCM1_RX,
+               .end    = DMACH_PCM1_RX,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+struct platform_device s5pv310_device_pcm1 = {
+       .name = "samsung-pcm",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(s5pv310_pcm1_resource),
+       .resource = s5pv310_pcm1_resource,
+       .dev = {
+               .platform_data = &s3c_pcm_pdata,
+       },
+};
+
+static struct resource s5pv310_pcm2_resource[] = {
+       [0] = {
+               .start  = S5PV310_PA_PCM2,
+               .end    = S5PV310_PA_PCM2 + 0x100 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = DMACH_PCM2_TX,
+               .end    = DMACH_PCM2_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start  = DMACH_PCM2_RX,
+               .end    = DMACH_PCM2_RX,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+struct platform_device s5pv310_device_pcm2 = {
+       .name = "samsung-pcm",
+       .id = 2,
+       .num_resources = ARRAY_SIZE(s5pv310_pcm2_resource),
+       .resource = s5pv310_pcm2_resource,
+       .dev = {
+               .platform_data = &s3c_pcm_pdata,
+       },
+};
+
+/* AC97 Controller platform devices */
+
+static int s5pv310_ac97_cfg_gpio(struct platform_device *pdev)
+{
+       return s3c_gpio_cfgpin_range(S5PV310_GPC0(0), 5, S3C_GPIO_SFN(4));
+}
+
+static struct resource s5pv310_ac97_resource[] = {
+       [0] = {
+               .start  = S5PV310_PA_AC97,
+               .end    = S5PV310_PA_AC97 + 0x100 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = DMACH_AC97_PCMOUT,
+               .end    = DMACH_AC97_PCMOUT,
+               .flags  = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start  = DMACH_AC97_PCMIN,
+               .end    = DMACH_AC97_PCMIN,
+               .flags  = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start  = DMACH_AC97_MICIN,
+               .end    = DMACH_AC97_MICIN,
+               .flags  = IORESOURCE_DMA,
+       },
+       [4] = {
+               .start  = IRQ_AC97,
+               .end    = IRQ_AC97,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct s3c_audio_pdata s3c_ac97_pdata = {
+       .cfg_gpio = s5pv310_ac97_cfg_gpio,
+};
+
+static u64 s5pv310_ac97_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device s5pv310_device_ac97 = {
+       .name = "samsung-ac97",
+       .id = -1,
+       .num_resources = ARRAY_SIZE(s5pv310_ac97_resource),
+       .resource = s5pv310_ac97_resource,
+       .dev = {
+               .platform_data = &s3c_ac97_pdata,
+               .dma_mask = &s5pv310_ac97_dmamask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+};
+
+/* S/PDIF Controller platform_device */
+
+static int s5pv310_spdif_cfg_gpio(struct platform_device *pdev)
+{
+       s3c_gpio_cfgpin_range(S5PV310_GPC1(0), 2, S3C_GPIO_SFN(3));
+
+       return 0;
+}
+
+static struct resource s5pv310_spdif_resource[] = {
+       [0] = {
+               .start  = S5PV310_PA_SPDIF,
+               .end    = S5PV310_PA_SPDIF + 0x100 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = DMACH_SPDIF,
+               .end    = DMACH_SPDIF,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+static struct s3c_audio_pdata samsung_spdif_pdata = {
+       .cfg_gpio = s5pv310_spdif_cfg_gpio,
+};
+
+static u64 s5pv310_spdif_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device s5pv310_device_spdif = {
+       .name = "samsung-spdif",
+       .id = -1,
+       .num_resources = ARRAY_SIZE(s5pv310_spdif_resource),
+       .resource = s5pv310_spdif_resource,
+       .dev = {
+               .platform_data = &samsung_spdif_pdata,
+               .dma_mask = &s5pv310_spdif_dmamask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+};
diff --git a/arch/arm/mach-s5pv310/dma.c b/arch/arm/mach-s5pv310/dma.c
new file mode 100644 (file)
index 0000000..20066c7
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2010 Samsung Electronics Co. Ltd.
+ *     Jaswinder Singh <jassi.brar@samsung.com>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <plat/devs.h>
+#include <plat/irqs.h>
+
+#include <mach/map.h>
+#include <mach/irqs.h>
+
+#include <plat/s3c-pl330-pdata.h>
+
+static u64 dma_dmamask = DMA_BIT_MASK(32);
+
+static struct resource s5pv310_pdma0_resource[] = {
+       [0] = {
+               .start  = S5PV310_PA_PDMA0,
+               .end    = S5PV310_PA_PDMA0 + SZ_4K,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_PDMA0,
+               .end    = IRQ_PDMA0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct s3c_pl330_platdata s5pv310_pdma0_pdata = {
+       .peri = {
+               [0] = DMACH_PCM0_RX,
+               [1] = DMACH_PCM0_TX,
+               [2] = DMACH_PCM2_RX,
+               [3] = DMACH_PCM2_TX,
+               [4] = DMACH_MSM_REQ0,
+               [5] = DMACH_MSM_REQ2,
+               [6] = DMACH_SPI0_RX,
+               [7] = DMACH_SPI0_TX,
+               [8] = DMACH_SPI2_RX,
+               [9] = DMACH_SPI2_TX,
+               [10] = DMACH_I2S0S_TX,
+               [11] = DMACH_I2S0_RX,
+               [12] = DMACH_I2S0_TX,
+               [13] = DMACH_I2S2_RX,
+               [14] = DMACH_I2S2_TX,
+               [15] = DMACH_UART0_RX,
+               [16] = DMACH_UART0_TX,
+               [17] = DMACH_UART2_RX,
+               [18] = DMACH_UART2_TX,
+               [19] = DMACH_UART4_RX,
+               [20] = DMACH_UART4_TX,
+               [21] = DMACH_SLIMBUS0_RX,
+               [22] = DMACH_SLIMBUS0_TX,
+               [23] = DMACH_SLIMBUS2_RX,
+               [24] = DMACH_SLIMBUS2_TX,
+               [25] = DMACH_SLIMBUS4_RX,
+               [26] = DMACH_SLIMBUS4_TX,
+               [27] = DMACH_AC97_MICIN,
+               [28] = DMACH_AC97_PCMIN,
+               [29] = DMACH_AC97_PCMOUT,
+               [30] = DMACH_MAX,
+               [31] = DMACH_MAX,
+       },
+};
+
+static struct platform_device s5pv310_device_pdma0 = {
+       .name           = "s3c-pl330",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(s5pv310_pdma0_resource),
+       .resource       = s5pv310_pdma0_resource,
+       .dev            = {
+               .dma_mask = &dma_dmamask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+               .platform_data = &s5pv310_pdma0_pdata,
+       },
+};
+
+static struct resource s5pv310_pdma1_resource[] = {
+       [0] = {
+               .start  = S5PV310_PA_PDMA1,
+               .end    = S5PV310_PA_PDMA1 + SZ_4K,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_PDMA1,
+               .end    = IRQ_PDMA1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct s3c_pl330_platdata s5pv310_pdma1_pdata = {
+       .peri = {
+               [0] = DMACH_PCM0_RX,
+               [1] = DMACH_PCM0_TX,
+               [2] = DMACH_PCM1_RX,
+               [3] = DMACH_PCM1_TX,
+               [4] = DMACH_MSM_REQ1,
+               [5] = DMACH_MSM_REQ3,
+               [6] = DMACH_SPI1_RX,
+               [7] = DMACH_SPI1_TX,
+               [8] = DMACH_I2S0S_TX,
+               [9] = DMACH_I2S0_RX,
+               [10] = DMACH_I2S0_TX,
+               [11] = DMACH_I2S1_RX,
+               [12] = DMACH_I2S1_TX,
+               [13] = DMACH_UART0_RX,
+               [14] = DMACH_UART0_TX,
+               [15] = DMACH_UART1_RX,
+               [16] = DMACH_UART1_TX,
+               [17] = DMACH_UART3_RX,
+               [18] = DMACH_UART3_TX,
+               [19] = DMACH_SLIMBUS1_RX,
+               [20] = DMACH_SLIMBUS1_TX,
+               [21] = DMACH_SLIMBUS3_RX,
+               [22] = DMACH_SLIMBUS3_TX,
+               [23] = DMACH_SLIMBUS5_RX,
+               [24] = DMACH_SLIMBUS5_TX,
+               [25] = DMACH_SLIMBUS0AUX_RX,
+               [26] = DMACH_SLIMBUS0AUX_TX,
+               [27] = DMACH_SPDIF,
+               [28] = DMACH_MAX,
+               [29] = DMACH_MAX,
+               [30] = DMACH_MAX,
+               [31] = DMACH_MAX,
+       },
+};
+
+static struct platform_device s5pv310_device_pdma1 = {
+       .name           = "s3c-pl330",
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(s5pv310_pdma1_resource),
+       .resource       = s5pv310_pdma1_resource,
+       .dev            = {
+               .dma_mask = &dma_dmamask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+               .platform_data = &s5pv310_pdma1_pdata,
+       },
+};
+
+static struct platform_device *s5pv310_dmacs[] __initdata = {
+       &s5pv310_device_pdma0,
+       &s5pv310_device_pdma1,
+};
+
+static int __init s5pv310_dma_init(void)
+{
+       platform_add_devices(s5pv310_dmacs, ARRAY_SIZE(s5pv310_dmacs));
+
+       return 0;
+}
+arch_initcall(s5pv310_dma_init);
diff --git a/arch/arm/mach-s5pv310/include/mach/dma.h b/arch/arm/mach-s5pv310/include/mach/dma.h
new file mode 100644 (file)
index 0000000..81209eb
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 Samsung Electronics Co. Ltd.
+ *     Jaswinder Singh <jassi.brar@samsung.com>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MACH_DMA_H
+#define __MACH_DMA_H
+
+/* This platform uses the common S3C DMA API driver for PL330 */
+#include <plat/s3c-dma-pl330.h>
+
+#endif /* __MACH_DMA_H */
index 99e7dad..3c05c58 100644 (file)
@@ -54,6 +54,9 @@
 #define COMBINER_GROUP(x)      ((x) * MAX_IRQ_IN_COMBINER + IRQ_SPI(64))
 #define COMBINER_IRQ(x, y)     (COMBINER_GROUP(x) + y)
 
+#define IRQ_PDMA0              COMBINER_IRQ(21, 0)
+#define IRQ_PDMA1              COMBINER_IRQ(21, 1)
+
 #define IRQ_TIMER0_VIC         COMBINER_IRQ(22, 0)
 #define IRQ_TIMER1_VIC         COMBINER_IRQ(22, 1)
 #define IRQ_TIMER2_VIC         COMBINER_IRQ(22, 2)
index 7acf4e7..5399446 100644 (file)
 #define S5PV310_PA_GIC_DIST            (0x10501000)
 #define S5PV310_PA_L2CC                        (0x10502000)
 
+/* DMA */
+#define S5PV310_PA_MDMA                0x10810000
+#define S5PV310_PA_PDMA0       0x12680000
+#define S5PV310_PA_PDMA1       0x12690000
+
 #define S5PV310_PA_GPIO1               (0x11400000)
 #define S5PV310_PA_GPIO2               (0x11000000)
 #define S5PV310_PA_GPIO3               (0x03860000)
 
 #define S5PV310_PA_SROMC               (0x12570000)
 
+/* S/PDIF */
+#define S5PV310_PA_SPDIF       0xE1100000
+
+/* I2S */
+#define S5PV310_PA_I2S0                0x03830000
+#define S5PV310_PA_I2S1                0xE3100000
+#define S5PV310_PA_I2S2                0xE2A00000
+
+/* PCM */
+#define S5PV310_PA_PCM0                0x03840000
+#define S5PV310_PA_PCM1                0x13980000
+#define S5PV310_PA_PCM2                0x13990000
+
+/* AC97 */
+#define S5PV310_PA_AC97                0x139A0000
+
 #define S5PV310_PA_UART                        (0x13800000)
 
 #define S5P_PA_UART(x)                 (S5PV310_PA_UART + ((x) * S3C_UART_OFFSET))
index cd79d7c..5b9937c 100644 (file)
@@ -711,6 +711,10 @@ static struct platform_device fsi_device = {
        },
 };
 
+static struct platform_device fsi_ak4643_device = {
+       .name           = "sh_fsi2_a_ak4643",
+};
+
 static struct sh_mobile_lcdc_info sh_mobile_lcdc1_info = {
        .clock_source = LCDC_CLK_EXTERNAL,
        .ch[0] = {
@@ -933,6 +937,7 @@ static struct platform_device *ap4evb_devices[] __initdata = {
        &sdhi1_device,
        &usb1_host_device,
        &fsi_device,
+       &fsi_ak4643_device,
        &sh_mmcif_device,
        &lcdc1_device,
        &lcdc_device,
index 2f91057..8a42bc4 100644 (file)
@@ -259,21 +259,6 @@ struct platform_device s3c_device_iis = {
 
 EXPORT_SYMBOL(s3c_device_iis);
 
-/* ASoC PCM DMA */
-
-static u64 s3c_device_audio_dmamask = 0xffffffffUL;
-
-struct platform_device s3c_device_pcm = {
-       .name             = "s3c24xx-pcm-audio",
-       .id               = -1,
-       .dev              = {
-               .dma_mask = &s3c_device_audio_dmamask,
-               .coherent_dma_mask = 0xffffffffUL
-       }
-};
-
-EXPORT_SYMBOL(s3c_device_pcm);
-
 /* RTC */
 
 static struct resource s3c_rtc_resource[] = {
@@ -496,8 +481,10 @@ static struct resource s3c_ac97_resource[] = {
        },
 };
 
+static u64 s3c_device_audio_dmamask = 0xffffffffUL;
+
 struct platform_device s3c_device_ac97 = {
-       .name             = "s3c-ac97",
+       .name             = "samsung-ac97",
        .id               = -1,
        .num_resources    = ARRAY_SIZE(s3c_ac97_resource),
        .resource         = s3c_ac97_resource,
index afcce47..19d8a16 100644 (file)
@@ -17,6 +17,7 @@ obj-y                         += clock.o
 obj-y                          += pwm-clock.o
 obj-y                          += gpio.o
 obj-y                          += gpio-config.o
+obj-y                          += dev-asocdma.o
 
 obj-$(CONFIG_SAMSUNG_GPIOLIB_4BIT)     += gpiolib.o
 obj-$(CONFIG_SAMSUNG_CLKSRC)   += clock-clksrc.o
diff --git a/arch/arm/plat-samsung/dev-asocdma.c b/arch/arm/plat-samsung/dev-asocdma.c
new file mode 100644 (file)
index 0000000..a068c4f
--- /dev/null
@@ -0,0 +1,25 @@
+/* linux/arch/arm/plat-samsung/dev-asocdma.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ *     Jaswinder Singh <jassi.brar@samsung.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/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <plat/devs.h>
+
+static u64 audio_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device samsung_asoc_dma = {
+       .name             = "samsung-audio",
+       .id               = -1,
+       .dev              = {
+               .dma_mask = &audio_dmamask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       }
+};
+EXPORT_SYMBOL(samsung_asoc_dma);
index 7712ff6..a0826ed 100644 (file)
@@ -25,10 +25,34 @@ extern void s3c64xx_ac97_setup_gpio(int);
 #define S5PC100_SPDIF_GPG3 1
 extern void s5pc100_spdif_setup_gpio(int);
 
+struct samsung_i2s {
+/* If the Primary DAI has 5.1 Channels */
+#define QUIRK_PRI_6CHAN                (1 << 0)
+/* If the I2S block has a Stereo Overlay Channel */
+#define QUIRK_SEC_DAI          (1 << 1)
+/*
+ * If the I2S block has no internal prescalar or MUX (I2SMOD[10] bit)
+ * The Machine driver must provide suitably set clock to the I2S block.
+ */
+#define QUIRK_NO_MUXPSR                (1 << 2)
+#define QUIRK_NEED_RSTCLR      (1 << 3)
+       /* Quirks of the I2S controller */
+       u32 quirks;
+
+       /*
+        * Array of clock names that can be used to generate I2S signals.
+        * Also corresponds to clocks of I2SMOD[10]
+        */
+       const char **src_clk;
+};
+
 /**
  * struct s3c_audio_pdata - common platform data for audio device drivers
  * @cfg_gpio: Callback function to setup mux'ed pins in I2S/PCM/AC97 mode
  */
 struct s3c_audio_pdata {
        int (*cfg_gpio)(struct platform_device *);
+       union {
+               struct samsung_i2s i2s;
+       } type;
 };
index 2d82a6c..e9e3b6e 100644 (file)
@@ -32,7 +32,7 @@ extern struct platform_device s3c64xx_device_iisv4;
 extern struct platform_device s3c64xx_device_spi0;
 extern struct platform_device s3c64xx_device_spi1;
 
-extern struct platform_device s3c_device_pcm;
+extern struct platform_device samsung_asoc_dma;
 
 extern struct platform_device s3c64xx_device_pcm0;
 extern struct platform_device s3c64xx_device_pcm1;
@@ -96,6 +96,15 @@ extern struct platform_device s5pv210_device_iis1;
 extern struct platform_device s5pv210_device_iis2;
 extern struct platform_device s5pv210_device_spdif;
 
+extern struct platform_device s5pv310_device_ac97;
+extern struct platform_device s5pv310_device_pcm0;
+extern struct platform_device s5pv310_device_pcm1;
+extern struct platform_device s5pv310_device_pcm2;
+extern struct platform_device s5pv310_device_i2s0;
+extern struct platform_device s5pv310_device_i2s1;
+extern struct platform_device s5pv310_device_i2s2;
+extern struct platform_device s5pv310_device_spdif;
+
 extern struct platform_device s5p6442_device_pcm0;
 extern struct platform_device s5p6442_device_pcm1;
 extern struct platform_device s5p6442_device_iis0;
index 527a0cd..b710757 100644 (file)
@@ -318,6 +318,10 @@ static struct platform_device fsi_device = {
        },
 };
 
+static struct platform_device fsi_ak4642_device = {
+       .name           = "sh_fsi_a_ak4642",
+};
+
 /* KEYSC in SoC (Needs SW33-2 set to ON) */
 static struct sh_keysc_info keysc_info = {
        .mode = SH_KEYSC_MODE_1,
@@ -590,6 +594,7 @@ static struct platform_device *ms7724se_devices[] __initdata = {
        &sh7724_usb0_host_device,
        &sh7724_usb1_gadget_device,
        &fsi_device,
+       &fsi_ak4642_device,
        &sdhi0_cn7_device,
        &sdhi1_cn8_device,
        &irda_device,
index 618398e..c822baa 100644 (file)
@@ -35,6 +35,29 @@ static inline struct wm8994_gpio *to_wm8994_gpio(struct gpio_chip *chip)
        return container_of(chip, struct wm8994_gpio, gpio_chip);
 }
 
+static int wm8994_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
+       struct wm8994 *wm8994 = wm8994_gpio->wm8994;
+
+       switch (wm8994->type) {
+       case WM8958:
+               switch (offset) {
+               case 1:
+               case 2:
+               case 3:
+               case 4:
+               case 6:
+                       return -EINVAL;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
 static int wm8994_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 {
        struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
@@ -136,6 +159,7 @@ static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 static struct gpio_chip template_chip = {
        .label                  = "wm8994",
        .owner                  = THIS_MODULE,
+       .request                = wm8994_gpio_request,
        .direction_input        = wm8994_gpio_direction_in,
        .get                    = wm8994_gpio_get,
        .direction_output       = wm8994_gpio_direction_out,
index b3b2aaf..8d221ba 100644 (file)
@@ -218,6 +218,18 @@ static const char *wm8994_main_supplies[] = {
        "SPKVDD2",
 };
 
+static const char *wm8958_main_supplies[] = {
+       "DBVDD1",
+       "DBVDD2",
+       "DBVDD3",
+       "DCVDD",
+       "AVDD1",
+       "AVDD2",
+       "CPVDD",
+       "SPKVDD1",
+       "SPKVDD2",
+};
+
 #ifdef CONFIG_PM
 static int wm8994_device_suspend(struct device *dev)
 {
@@ -239,7 +251,7 @@ static int wm8994_device_suspend(struct device *dev)
        if (ret < 0)
                dev_err(dev, "Failed to save LDO registers: %d\n", ret);
 
-       ret = regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies),
+       ret = regulator_bulk_disable(wm8994->num_supplies,
                                     wm8994->supplies);
        if (ret != 0) {
                dev_err(dev, "Failed to disable supplies: %d\n", ret);
@@ -254,7 +266,7 @@ static int wm8994_device_resume(struct device *dev)
        struct wm8994 *wm8994 = dev_get_drvdata(dev);
        int ret;
 
-       ret = regulator_bulk_enable(ARRAY_SIZE(wm8994_main_supplies),
+       ret = regulator_bulk_enable(wm8994->num_supplies,
                                    wm8994->supplies);
        if (ret != 0) {
                dev_err(dev, "Failed to enable supplies: %d\n", ret);
@@ -305,9 +317,10 @@ static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo)
 /*
  * Instantiate the generic non-control parts of the device.
  */
-static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
+static int wm8994_device_init(struct wm8994 *wm8994, int irq)
 {
        struct wm8994_pdata *pdata = wm8994->dev->platform_data;
+       const char *devname;
        int ret, i;
 
        mutex_init(&wm8994->io_lock);
@@ -323,25 +336,48 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
                goto err;
        }
 
+       switch (wm8994->type) {
+       case WM8994:
+               wm8994->num_supplies = ARRAY_SIZE(wm8994_main_supplies);
+               break;
+       case WM8958:
+               wm8994->num_supplies = ARRAY_SIZE(wm8958_main_supplies);
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
        wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
-                                  ARRAY_SIZE(wm8994_main_supplies),
+                                  wm8994->num_supplies,
                                   GFP_KERNEL);
        if (!wm8994->supplies) {
                ret = -ENOMEM;
                goto err;
        }
 
-       for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++)
-               wm8994->supplies[i].supply = wm8994_main_supplies[i];
-
-       ret = regulator_bulk_get(wm8994->dev, ARRAY_SIZE(wm8994_main_supplies),
+       switch (wm8994->type) {
+       case WM8994:
+               for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++)
+                       wm8994->supplies[i].supply = wm8994_main_supplies[i];
+               break;
+       case WM8958:
+               for (i = 0; i < ARRAY_SIZE(wm8958_main_supplies); i++)
+                       wm8994->supplies[i].supply = wm8958_main_supplies[i];
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+               
+       ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies,
                                 wm8994->supplies);
        if (ret != 0) {
                dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret);
                goto err_supplies;
        }
 
-       ret = regulator_bulk_enable(ARRAY_SIZE(wm8994_main_supplies),
+       ret = regulator_bulk_enable(wm8994->num_supplies,
                                    wm8994->supplies);
        if (ret != 0) {
                dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret);
@@ -353,7 +389,22 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
                dev_err(wm8994->dev, "Failed to read ID register\n");
                goto err_enable;
        }
-       if (ret != 0x8994) {
+       switch (ret) {
+       case 0x8994:
+               devname = "WM8994";
+               if (wm8994->type != WM8994)
+                       dev_warn(wm8994->dev, "Device registered as type %d\n",
+                                wm8994->type);
+               wm8994->type = WM8994;
+               break;
+       case 0x8958:
+               devname = "WM8958";
+               if (wm8994->type != WM8958)
+                       dev_warn(wm8994->dev, "Device registered as type %d\n",
+                                wm8994->type);
+               wm8994->type = WM8958;
+               break;
+       default:
                dev_err(wm8994->dev, "Device is not a WM8994, ID is %x\n",
                        ret);
                ret = -EINVAL;
@@ -370,14 +421,16 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
        switch (ret) {
        case 0:
        case 1:
-               dev_warn(wm8994->dev, "revision %c not fully supported\n",
-                       'A' + ret);
+               if (wm8994->type == WM8994)
+                       dev_warn(wm8994->dev,
+                                "revision %c not fully supported\n",
+                                'A' + ret);
                break;
        default:
-               dev_info(wm8994->dev, "revision %c\n", 'A' + ret);
                break;
        }
 
+       dev_info(wm8994->dev, "%s revision %c\n", devname, 'A' + ret);
 
        if (pdata) {
                wm8994->irq_base = pdata->irq_base;
@@ -423,10 +476,10 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
 err_irq:
        wm8994_irq_exit(wm8994);
 err_enable:
-       regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies),
+       regulator_bulk_disable(wm8994->num_supplies,
                               wm8994->supplies);
 err_get:
-       regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies);
+       regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
 err_supplies:
        kfree(wm8994->supplies);
 err:
@@ -439,9 +492,9 @@ static void wm8994_device_exit(struct wm8994 *wm8994)
 {
        mfd_remove_devices(wm8994->dev);
        wm8994_irq_exit(wm8994);
-       regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies),
+       regulator_bulk_disable(wm8994->num_supplies,
                               wm8994->supplies);
-       regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies);
+       regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
        kfree(wm8994->supplies);
        kfree(wm8994);
 }
@@ -506,8 +559,9 @@ static int wm8994_i2c_probe(struct i2c_client *i2c,
        wm8994->read_dev = wm8994_i2c_read_device;
        wm8994->write_dev = wm8994_i2c_write_device;
        wm8994->irq = i2c->irq;
+       wm8994->type = id->driver_data;
 
-       return wm8994_device_init(wm8994, id->driver_data, i2c->irq);
+       return wm8994_device_init(wm8994, i2c->irq);
 }
 
 static int wm8994_i2c_remove(struct i2c_client *i2c)
@@ -535,7 +589,8 @@ static int wm8994_i2c_resume(struct i2c_client *i2c)
 #endif
 
 static const struct i2c_device_id wm8994_i2c_id[] = {
-       { "wm8994", 0 },
+       { "wm8994", WM8994 },
+       { "wm8958", WM8958 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id);
index 594f88e..35b2958 100644 (file)
@@ -130,10 +130,19 @@ static struct regulator_ops wm8994_ldo1_ops = {
 static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev,
                                    unsigned int selector)
 {
+       struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
+
        if (selector > WM8994_LDO2_MAX_SELECTOR)
                return -EINVAL;
 
-       return (selector * 100000) + 900000;
+       switch (ldo->wm8994->type) {
+       case WM8994:
+               return (selector * 100000) + 900000;
+       case WM8958:
+               return (selector * 100000) + 1000000;
+       default:
+               return -EINVAL;
+       }
 }
 
 static int wm8994_ldo2_get_voltage_sel(struct regulator_dev *rdev)
@@ -154,7 +163,17 @@ static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev,
        struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
        int selector, v;
 
-       selector = (min_uV - 900000) / 100000;
+       switch (ldo->wm8994->type) {
+       case WM8994:
+               selector = (min_uV - 900000) / 100000;
+               break;
+       case WM8958:
+               selector = (min_uV - 1000000) / 100000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
        v = wm8994_ldo2_list_voltage(rdev, selector);
        if (v < 0 || v > max_uV)
                return -EINVAL;
index 8c59cc8..e7594e1 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
+#include <sound/soc.h>
 #include <sound/soc-dapm.h>
 #include <sound/initval.h>
 
index de79bae..3fd3684 100644 (file)
 
 #include <linux/interrupt.h>
 
+enum wm8994_type {
+       WM8994 = 0,
+       WM8958 = 1,
+};
+
 struct regulator_dev;
 struct regulator_bulk_data;
 
@@ -48,6 +53,8 @@ struct wm8994 {
        struct mutex io_lock;
        struct mutex irq_lock;
 
+       enum wm8994_type type;
+
        struct device *dev;
        int (*read_dev)(struct wm8994 *wm8994, unsigned short reg,
                        int bytes, void *dest);
@@ -68,6 +75,7 @@ struct wm8994 {
        u16 gpio_regs[WM8994_NUM_GPIO_REGS];
 
        struct regulator_dev *dbvdd;
+       int num_supplies;
        struct regulator_bulk_data *supplies;
 };
 
index add8a1b..9eab263 100644 (file)
@@ -30,6 +30,8 @@ struct wm8994_ldo_pdata {
 
 #define WM8994_DRC_REGS 5
 #define WM8994_EQ_REGS  20
+#define WM8958_MBC_CUTOFF_REGS 20
+#define WM8958_MBC_COEFF_REGS  48
 
 /**
  * DRC configurations are specified with a label and a set of register
@@ -59,6 +61,18 @@ struct wm8994_retune_mobile_cfg {
         u16 regs[WM8994_EQ_REGS];
 };
 
+/**
+ * Multiband compressor configurations are specified with a label and
+ * two sets of values to write.  Configurations are expected to be
+ * generated using the multiband compressor configuration panel in
+ * WISCE - see http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8958_mbc_cfg {
+       const char *name;
+       u16 cutoff_regs[WM8958_MBC_CUTOFF_REGS];
+       u16 coeff_regs[WM8958_MBC_COEFF_REGS];
+};
+
 struct wm8994_pdata {
        int gpio_base;
 
@@ -78,6 +92,9 @@ struct wm8994_pdata {
         int num_retune_mobile_cfgs;
         struct wm8994_retune_mobile_cfg *retune_mobile_cfgs;
 
+       int num_mbc_cfgs;
+       struct wm8958_mbc_cfg *mbc_cfgs;
+
         /* LINEOUT can be differential or single ended */
         unsigned int lineout1_diff:1;
         unsigned int lineout2_diff:1;
index 967f62f..be072fa 100644 (file)
 #define WM8994_LDO_1                            0x3B
 #define WM8994_LDO_2                            0x3C
 #define WM8994_CHARGE_PUMP_1                    0x4C
+#define WM8958_CHARGE_PUMP_2                    0x4D
 #define WM8994_CLASS_W_1                        0x51
 #define WM8994_DC_SERVO_1                       0x54
 #define WM8994_DC_SERVO_2                       0x55
 #define WM8994_DC_SERVO_4                       0x57
 #define WM8994_DC_SERVO_READBACK                0x58
 #define WM8994_ANALOGUE_HP_1                    0x60
+#define WM8958_MIC_DETECT_1                     0xD0
+#define WM8958_MIC_DETECT_2                     0xD1
+#define WM8958_MIC_DETECT_3                     0xD2
 #define WM8994_CHIP_REVISION                    0x100
 #define WM8994_CONTROL_INTERFACE                0x101
 #define WM8994_WRITE_SEQUENCER_CTRL_1           0x110
 #define WM8994_AIF2DAC_LRCLK                    0x315
 #define WM8994_AIF2DAC_DATA                     0x316
 #define WM8994_AIF2ADC_DATA                     0x317
+#define WM8958_AIF3_CONTROL_1                   0x320
+#define WM8958_AIF3_CONTROL_2                   0x321
+#define WM8958_AIF3DAC_DATA                     0x322
+#define WM8958_AIF3ADC_DATA                     0x323
 #define WM8994_AIF1_ADC1_LEFT_VOLUME            0x400
 #define WM8994_AIF1_ADC1_RIGHT_VOLUME           0x401
 #define WM8994_AIF1_DAC1_LEFT_VOLUME            0x402
 #define WM8994_INTERRUPT_STATUS_2_MASK          0x739
 #define WM8994_INTERRUPT_CONTROL                0x740
 #define WM8994_IRQ_DEBOUNCE                     0x748
+#define WM8958_DSP2_PROGRAM                     0x900
+#define WM8958_DSP2_CONFIG                      0x901
+#define WM8958_DSP2_MAGICNUM                    0xA00
+#define WM8958_DSP2_RELEASEYEAR                 0xA01
+#define WM8958_DSP2_RELEASEMONTHDAY             0xA02
+#define WM8958_DSP2_RELEASETIME                 0xA03
+#define WM8958_DSP2_VERMAJMIN                   0xA04
+#define WM8958_DSP2_VERBUILD                    0xA05
+#define WM8958_DSP2_EXECCONTROL                 0xA0D
+#define WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1     0x2200
+#define WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_2     0x2201
+#define WM8958_MBC_BAND_2_LOWER_CUTOFF_C2_1     0x2202
+#define WM8958_MBC_BAND_2_LOWER_CUTOFF_C2_2     0x2203
+#define WM8958_MBC_BAND_2_LOWER_CUTOFF_C3_1     0x2204
+#define WM8958_MBC_BAND_2_LOWER_CUTOFF_C3_2     0x2205
+#define WM8958_MBC_BAND_2_UPPER_CUTOFF_C2_1     0x2206
+#define WM8958_MBC_BAND_2_UPPER_CUTOFF_C2_2     0x2207
+#define WM8958_MBC_BAND_2_UPPER_CUTOFF_C3_1     0x2208
+#define WM8958_MBC_BAND_2_UPPER_CUTOFF_C3_2     0x2209
+#define WM8958_MBC_BAND_2_UPPER_CUTOFF_C1_1     0x220A
+#define WM8958_MBC_BAND_2_UPPER_CUTOFF_C1_2     0x220B
+#define WM8958_MBC_BAND_1_UPPER_CUTOFF_C1_1     0x220C
+#define WM8958_MBC_BAND_1_UPPER_CUTOFF_C1_2     0x220D
+#define WM8958_MBC_BAND_1_UPPER_CUTOFF_C2_1     0x220E
+#define WM8958_MBC_BAND_1_UPPER_CUTOFF_C2_2     0x220F
+#define WM8958_MBC_BAND_1_UPPER_CUTOFF_C3_1     0x2210
+#define WM8958_MBC_BAND_1_UPPER_CUTOFF_C3_2     0x2211
+#define WM8958_MBC_BAND_1_LOWER_CUTOFF_1        0x2212
+#define WM8958_MBC_BAND_1_LOWER_CUTOFF_2        0x2213
+#define WM8958_MBC_BAND_1_K_1                   0x2400
+#define WM8958_MBC_BAND_1_K_2                   0x2401
+#define WM8958_MBC_BAND_1_N1_1                  0x2402
+#define WM8958_MBC_BAND_1_N1_2                  0x2403
+#define WM8958_MBC_BAND_1_N2_1                  0x2404
+#define WM8958_MBC_BAND_1_N2_2                  0x2405
+#define WM8958_MBC_BAND_1_N3_1                  0x2406
+#define WM8958_MBC_BAND_1_N3_2                  0x2407
+#define WM8958_MBC_BAND_1_N4_1                  0x2408
+#define WM8958_MBC_BAND_1_N4_2                  0x2409
+#define WM8958_MBC_BAND_1_N5_1                  0x240A
+#define WM8958_MBC_BAND_1_N5_2                  0x240B
+#define WM8958_MBC_BAND_1_X1_1                  0x240C
+#define WM8958_MBC_BAND_1_X1_2                  0x240D
+#define WM8958_MBC_BAND_1_X2_1                  0x240E
+#define WM8958_MBC_BAND_1_X2_2                  0x240F
+#define WM8958_MBC_BAND_1_X3_1                  0x2410
+#define WM8958_MBC_BAND_1_X3_2                  0x2411
+#define WM8958_MBC_BAND_1_ATTACK_1              0x2412
+#define WM8958_MBC_BAND_1_ATTACK_2              0x2413
+#define WM8958_MBC_BAND_1_DECAY_1               0x2414
+#define WM8958_MBC_BAND_1_DECAY_2               0x2415
+#define WM8958_MBC_BAND_2_K_1                   0x2416
+#define WM8958_MBC_BAND_2_K_2                   0x2417
+#define WM8958_MBC_BAND_2_N1_1                  0x2418
+#define WM8958_MBC_BAND_2_N1_2                  0x2419
+#define WM8958_MBC_BAND_2_N2_1                  0x241A
+#define WM8958_MBC_BAND_2_N2_2                  0x241B
+#define WM8958_MBC_BAND_2_N3_1                  0x241C
+#define WM8958_MBC_BAND_2_N3_2                  0x241D
+#define WM8958_MBC_BAND_2_N4_1                  0x241E
+#define WM8958_MBC_BAND_2_N4_2                  0x241F
+#define WM8958_MBC_BAND_2_N5_1                  0x2420
+#define WM8958_MBC_BAND_2_N5_2                  0x2421
+#define WM8958_MBC_BAND_2_X1_1                  0x2422
+#define WM8958_MBC_BAND_2_X1_2                  0x2423
+#define WM8958_MBC_BAND_2_X2_1                  0x2424
+#define WM8958_MBC_BAND_2_X2_2                  0x2425
+#define WM8958_MBC_BAND_2_X3_1                  0x2426
+#define WM8958_MBC_BAND_2_X3_2                  0x2427
+#define WM8958_MBC_BAND_2_ATTACK_1              0x2428
+#define WM8958_MBC_BAND_2_ATTACK_2              0x2429
+#define WM8958_MBC_BAND_2_DECAY_1               0x242A
+#define WM8958_MBC_BAND_2_DECAY_2               0x242B
+#define WM8958_MBC_B2_PG2_1                     0x242C
+#define WM8958_MBC_B2_PG2_2                     0x242D
+#define WM8958_MBC_B1_PG2_1                     0x242E
+#define WM8958_MBC_B1_PG2_2                     0x242F
 #define WM8994_WRITE_SEQUENCER_0                0x3000
 #define WM8994_WRITE_SEQUENCER_1                0x3001
 #define WM8994_WRITE_SEQUENCER_2                0x3002
 /*
  * R6 (0x06) - Power Management (6)
  */
+#define WM8958_AIF3ADC_SRC_MASK                 0x0600  /* AIF3ADC_SRC - [10:9] */
+#define WM8958_AIF3ADC_SRC_SHIFT                     9  /* AIF3ADC_SRC - [10:9] */
+#define WM8958_AIF3ADC_SRC_WIDTH                     2  /* AIF3ADC_SRC - [10:9] */
+#define WM8958_AIF2DAC_SRC_MASK                 0x0180  /* AIF2DAC_SRC - [8:7] */
+#define WM8958_AIF2DAC_SRC_SHIFT                     7  /* AIF2DAC_SRC - [8:7] */
+#define WM8958_AIF2DAC_SRC_WIDTH                     2  /* AIF2DAC_SRC - [8:7] */
 #define WM8994_AIF3_TRI                         0x0020  /* AIF3_TRI */
 #define WM8994_AIF3_TRI_MASK                    0x0020  /* AIF3_TRI */
 #define WM8994_AIF3_TRI_SHIFT                        5  /* AIF3_TRI */
 #define WM8994_CP_ENA_SHIFT                         15  /* CP_ENA */
 #define WM8994_CP_ENA_WIDTH                          1  /* CP_ENA */
 
+/*
+ * R77 (0x4D) - Charge Pump (2)
+ */
+#define WM8958_CP_DISCH                         0x8000  /* CP_DISCH */
+#define WM8958_CP_DISCH_MASK                    0x8000  /* CP_DISCH */
+#define WM8958_CP_DISCH_SHIFT                       15  /* CP_DISCH */
+#define WM8958_CP_DISCH_WIDTH                        1  /* CP_DISCH */
+
 /*
  * R81 (0x51) - Class W (1)
  */
 #define WM8994_HPOUT1R_DLY_SHIFT                     1  /* HPOUT1R_DLY */
 #define WM8994_HPOUT1R_DLY_WIDTH                     1  /* HPOUT1R_DLY */
 
+/*
+ * R208 (0xD0) - Mic Detect 1
+ */
+#define WM8958_MICD_BIAS_STARTTIME_MASK         0xF000  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8958_MICD_BIAS_STARTTIME_SHIFT            12  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8958_MICD_BIAS_STARTTIME_WIDTH             4  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8958_MICD_RATE_MASK                   0x0F00  /* MICD_RATE - [11:8] */
+#define WM8958_MICD_RATE_SHIFT                       8  /* MICD_RATE - [11:8] */
+#define WM8958_MICD_RATE_WIDTH                       4  /* MICD_RATE - [11:8] */
+#define WM8958_MICD_DBTIME                      0x0002  /* MICD_DBTIME */
+#define WM8958_MICD_DBTIME_MASK                 0x0002  /* MICD_DBTIME */
+#define WM8958_MICD_DBTIME_SHIFT                     1  /* MICD_DBTIME */
+#define WM8958_MICD_DBTIME_WIDTH                     1  /* MICD_DBTIME */
+#define WM8958_MICD_ENA                         0x0001  /* MICD_ENA */
+#define WM8958_MICD_ENA_MASK                    0x0001  /* MICD_ENA */
+#define WM8958_MICD_ENA_SHIFT                        0  /* MICD_ENA */
+#define WM8958_MICD_ENA_WIDTH                        1  /* MICD_ENA */
+
+/*
+ * R209 (0xD1) - Mic Detect 2
+ */
+#define WM8958_MICD_LVL_SEL_MASK                0x00FF  /* MICD_LVL_SEL - [7:0] */
+#define WM8958_MICD_LVL_SEL_SHIFT                    0  /* MICD_LVL_SEL - [7:0] */
+#define WM8958_MICD_LVL_SEL_WIDTH                    8  /* MICD_LVL_SEL - [7:0] */
+
+/*
+ * R210 (0xD2) - Mic Detect 3
+ */
+#define WM8958_MICD_LVL_MASK                    0x07FC  /* MICD_LVL - [10:2] */
+#define WM8958_MICD_LVL_SHIFT                        2  /* MICD_LVL - [10:2] */
+#define WM8958_MICD_LVL_WIDTH                        9  /* MICD_LVL - [10:2] */
+#define WM8958_MICD_VALID                       0x0002  /* MICD_VALID */
+#define WM8958_MICD_VALID_MASK                  0x0002  /* MICD_VALID */
+#define WM8958_MICD_VALID_SHIFT                      1  /* MICD_VALID */
+#define WM8958_MICD_VALID_WIDTH                      1  /* MICD_VALID */
+#define WM8958_MICD_STS                         0x0001  /* MICD_STS */
+#define WM8958_MICD_STS_MASK                    0x0001  /* MICD_STS */
+#define WM8958_MICD_STS_SHIFT                        0  /* MICD_STS */
+#define WM8958_MICD_STS_WIDTH                        1  /* MICD_STS */
+
 /*
  * R256 (0x100) - Chip Revision
  */
 /*
  * R520 (0x208) - Clocking (1)
  */
+#define WM8958_DSP2CLK_ENA                      0x4000  /* DSP2CLK_ENA */
+#define WM8958_DSP2CLK_ENA_MASK                 0x4000  /* DSP2CLK_ENA */
+#define WM8958_DSP2CLK_ENA_SHIFT                    14  /* DSP2CLK_ENA */
+#define WM8958_DSP2CLK_ENA_WIDTH                     1  /* DSP2CLK_ENA */
+#define WM8958_DSP2CLK_SRC                      0x1000  /* DSP2CLK_SRC */
+#define WM8958_DSP2CLK_SRC_MASK                 0x1000  /* DSP2CLK_SRC */
+#define WM8958_DSP2CLK_SRC_SHIFT                    12  /* DSP2CLK_SRC */
+#define WM8958_DSP2CLK_SRC_WIDTH                     1  /* DSP2CLK_SRC */
 #define WM8994_TOCLK_ENA                        0x0010  /* TOCLK_ENA */
 #define WM8994_TOCLK_ENA_MASK                   0x0010  /* TOCLK_ENA */
 #define WM8994_TOCLK_ENA_SHIFT                       4  /* TOCLK_ENA */
 #define WM8994_AIF2ADCR_DAT_INV_SHIFT                0  /* AIF2ADCR_DAT_INV */
 #define WM8994_AIF2ADCR_DAT_INV_WIDTH                1  /* AIF2ADCR_DAT_INV */
 
+/*
+ * R800 (0x320) - AIF3 Control (1)
+ */
+#define WM8958_AIF3_LRCLK_INV                   0x0080  /* AIF3_LRCLK_INV */
+#define WM8958_AIF3_LRCLK_INV_MASK              0x0080  /* AIF3_LRCLK_INV */
+#define WM8958_AIF3_LRCLK_INV_SHIFT                  7  /* AIF3_LRCLK_INV */
+#define WM8958_AIF3_LRCLK_INV_WIDTH                  1  /* AIF3_LRCLK_INV */
+#define WM8958_AIF3_WL_MASK                     0x0060  /* AIF3_WL - [6:5] */
+#define WM8958_AIF3_WL_SHIFT                         5  /* AIF3_WL - [6:5] */
+#define WM8958_AIF3_WL_WIDTH                         2  /* AIF3_WL - [6:5] */
+#define WM8958_AIF3_FMT_MASK                    0x0018  /* AIF3_FMT - [4:3] */
+#define WM8958_AIF3_FMT_SHIFT                        3  /* AIF3_FMT - [4:3] */
+#define WM8958_AIF3_FMT_WIDTH                        2  /* AIF3_FMT - [4:3] */
+
+/*
+ * R801 (0x321) - AIF3 Control (2)
+ */
+#define WM8958_AIF3DAC_BOOST_MASK               0x0C00  /* AIF3DAC_BOOST - [11:10] */
+#define WM8958_AIF3DAC_BOOST_SHIFT                  10  /* AIF3DAC_BOOST - [11:10] */
+#define WM8958_AIF3DAC_BOOST_WIDTH                   2  /* AIF3DAC_BOOST - [11:10] */
+#define WM8958_AIF3DAC_COMP                     0x0010  /* AIF3DAC_COMP */
+#define WM8958_AIF3DAC_COMP_MASK                0x0010  /* AIF3DAC_COMP */
+#define WM8958_AIF3DAC_COMP_SHIFT                    4  /* AIF3DAC_COMP */
+#define WM8958_AIF3DAC_COMP_WIDTH                    1  /* AIF3DAC_COMP */
+#define WM8958_AIF3DAC_COMPMODE                 0x0008  /* AIF3DAC_COMPMODE */
+#define WM8958_AIF3DAC_COMPMODE_MASK            0x0008  /* AIF3DAC_COMPMODE */
+#define WM8958_AIF3DAC_COMPMODE_SHIFT                3  /* AIF3DAC_COMPMODE */
+#define WM8958_AIF3DAC_COMPMODE_WIDTH                1  /* AIF3DAC_COMPMODE */
+#define WM8958_AIF3ADC_COMP                     0x0004  /* AIF3ADC_COMP */
+#define WM8958_AIF3ADC_COMP_MASK                0x0004  /* AIF3ADC_COMP */
+#define WM8958_AIF3ADC_COMP_SHIFT                    2  /* AIF3ADC_COMP */
+#define WM8958_AIF3ADC_COMP_WIDTH                    1  /* AIF3ADC_COMP */
+#define WM8958_AIF3ADC_COMPMODE                 0x0002  /* AIF3ADC_COMPMODE */
+#define WM8958_AIF3ADC_COMPMODE_MASK            0x0002  /* AIF3ADC_COMPMODE */
+#define WM8958_AIF3ADC_COMPMODE_SHIFT                1  /* AIF3ADC_COMPMODE */
+#define WM8958_AIF3ADC_COMPMODE_WIDTH                1  /* AIF3ADC_COMPMODE */
+#define WM8958_AIF3_LOOPBACK                    0x0001  /* AIF3_LOOPBACK */
+#define WM8958_AIF3_LOOPBACK_MASK               0x0001  /* AIF3_LOOPBACK */
+#define WM8958_AIF3_LOOPBACK_SHIFT                   0  /* AIF3_LOOPBACK */
+#define WM8958_AIF3_LOOPBACK_WIDTH                   1  /* AIF3_LOOPBACK */
+
+/*
+ * R802 (0x322) - AIF3DAC Data
+ */
+#define WM8958_AIF3DAC_DAT_INV                  0x0001  /* AIF3DAC_DAT_INV */
+#define WM8958_AIF3DAC_DAT_INV_MASK             0x0001  /* AIF3DAC_DAT_INV */
+#define WM8958_AIF3DAC_DAT_INV_SHIFT                 0  /* AIF3DAC_DAT_INV */
+#define WM8958_AIF3DAC_DAT_INV_WIDTH                 1  /* AIF3DAC_DAT_INV */
+
+/*
+ * R803 (0x323) - AIF3ADC Data
+ */
+#define WM8958_AIF3ADC_DAT_INV                  0x0001  /* AIF3ADC_DAT_INV */
+#define WM8958_AIF3ADC_DAT_INV_MASK             0x0001  /* AIF3ADC_DAT_INV */
+#define WM8958_AIF3ADC_DAT_INV_SHIFT                 0  /* AIF3ADC_DAT_INV */
+#define WM8958_AIF3ADC_DAT_INV_WIDTH                 1  /* AIF3ADC_DAT_INV */
+
 /*
  * R1024 (0x400) - AIF1 ADC1 Left Volume
  */
 #define WM8994_TEMP_SHUT_DB_SHIFT                    0  /* TEMP_SHUT_DB */
 #define WM8994_TEMP_SHUT_DB_WIDTH                    1  /* TEMP_SHUT_DB */
 
+/*
+ * R2304 (0x900) - DSP2_Program
+ */
+#define WM8958_DSP2_ENA                         0x0001  /* DSP2_ENA */
+#define WM8958_DSP2_ENA_MASK                    0x0001  /* DSP2_ENA */
+#define WM8958_DSP2_ENA_SHIFT                        0  /* DSP2_ENA */
+#define WM8958_DSP2_ENA_WIDTH                        1  /* DSP2_ENA */
+
+/*
+ * R2305 (0x901) - DSP2_Config
+ */
+#define WM8958_MBC_SEL_MASK                     0x0030  /* MBC_SEL - [5:4] */
+#define WM8958_MBC_SEL_SHIFT                         4  /* MBC_SEL - [5:4] */
+#define WM8958_MBC_SEL_WIDTH                         2  /* MBC_SEL - [5:4] */
+#define WM8958_MBC_ENA                          0x0001  /* MBC_ENA */
+#define WM8958_MBC_ENA_MASK                     0x0001  /* MBC_ENA */
+#define WM8958_MBC_ENA_SHIFT                         0  /* MBC_ENA */
+#define WM8958_MBC_ENA_WIDTH                         1  /* MBC_ENA */
+
+/*
+ * R2560 (0xA00) - DSP2_MagicNum
+ */
+#define WM8958_DSP2_MAGIC_NUM_MASK              0xFFFF  /* DSP2_MAGIC_NUM - [15:0] */
+#define WM8958_DSP2_MAGIC_NUM_SHIFT                  0  /* DSP2_MAGIC_NUM - [15:0] */
+#define WM8958_DSP2_MAGIC_NUM_WIDTH                 16  /* DSP2_MAGIC_NUM - [15:0] */
+
+/*
+ * R2561 (0xA01) - DSP2_ReleaseYear
+ */
+#define WM8958_DSP2_RELEASE_YEAR_MASK           0xFFFF  /* DSP2_RELEASE_YEAR - [15:0] */
+#define WM8958_DSP2_RELEASE_YEAR_SHIFT               0  /* DSP2_RELEASE_YEAR - [15:0] */
+#define WM8958_DSP2_RELEASE_YEAR_WIDTH              16  /* DSP2_RELEASE_YEAR - [15:0] */
+
+/*
+ * R2562 (0xA02) - DSP2_ReleaseMonthDay
+ */
+#define WM8958_DSP2_RELEASE_MONTH_MASK          0xFF00  /* DSP2_RELEASE_MONTH - [15:8] */
+#define WM8958_DSP2_RELEASE_MONTH_SHIFT              8  /* DSP2_RELEASE_MONTH - [15:8] */
+#define WM8958_DSP2_RELEASE_MONTH_WIDTH              8  /* DSP2_RELEASE_MONTH - [15:8] */
+#define WM8958_DSP2_RELEASE_DAY_MASK            0x00FF  /* DSP2_RELEASE_DAY - [7:0] */
+#define WM8958_DSP2_RELEASE_DAY_SHIFT                0  /* DSP2_RELEASE_DAY - [7:0] */
+#define WM8958_DSP2_RELEASE_DAY_WIDTH                8  /* DSP2_RELEASE_DAY - [7:0] */
+
+/*
+ * R2563 (0xA03) - DSP2_ReleaseTime
+ */
+#define WM8958_DSP2_RELEASE_HOURS_MASK          0xFF00  /* DSP2_RELEASE_HOURS - [15:8] */
+#define WM8958_DSP2_RELEASE_HOURS_SHIFT              8  /* DSP2_RELEASE_HOURS - [15:8] */
+#define WM8958_DSP2_RELEASE_HOURS_WIDTH              8  /* DSP2_RELEASE_HOURS - [15:8] */
+#define WM8958_DSP2_RELEASE_MINS_MASK           0x00FF  /* DSP2_RELEASE_MINS - [7:0] */
+#define WM8958_DSP2_RELEASE_MINS_SHIFT               0  /* DSP2_RELEASE_MINS - [7:0] */
+#define WM8958_DSP2_RELEASE_MINS_WIDTH               8  /* DSP2_RELEASE_MINS - [7:0] */
+
+/*
+ * R2564 (0xA04) - DSP2_VerMajMin
+ */
+#define WM8958_DSP2_MAJOR_VER_MASK              0xFF00  /* DSP2_MAJOR_VER - [15:8] */
+#define WM8958_DSP2_MAJOR_VER_SHIFT                  8  /* DSP2_MAJOR_VER - [15:8] */
+#define WM8958_DSP2_MAJOR_VER_WIDTH                  8  /* DSP2_MAJOR_VER - [15:8] */
+#define WM8958_DSP2_MINOR_VER_MASK              0x00FF  /* DSP2_MINOR_VER - [7:0] */
+#define WM8958_DSP2_MINOR_VER_SHIFT                  0  /* DSP2_MINOR_VER - [7:0] */
+#define WM8958_DSP2_MINOR_VER_WIDTH                  8  /* DSP2_MINOR_VER - [7:0] */
+
+/*
+ * R2565 (0xA05) - DSP2_VerBuild
+ */
+#define WM8958_DSP2_BUILD_VER_MASK              0xFFFF  /* DSP2_BUILD_VER - [15:0] */
+#define WM8958_DSP2_BUILD_VER_SHIFT                  0  /* DSP2_BUILD_VER - [15:0] */
+#define WM8958_DSP2_BUILD_VER_WIDTH                 16  /* DSP2_BUILD_VER - [15:0] */
+
+/*
+ * R2573 (0xA0D) - DSP2_ExecControl
+ */
+#define WM8958_DSP2_STOPC                       0x0020  /* DSP2_STOPC */
+#define WM8958_DSP2_STOPC_MASK                  0x0020  /* DSP2_STOPC */
+#define WM8958_DSP2_STOPC_SHIFT                      5  /* DSP2_STOPC */
+#define WM8958_DSP2_STOPC_WIDTH                      1  /* DSP2_STOPC */
+#define WM8958_DSP2_STOPS                       0x0010  /* DSP2_STOPS */
+#define WM8958_DSP2_STOPS_MASK                  0x0010  /* DSP2_STOPS */
+#define WM8958_DSP2_STOPS_SHIFT                      4  /* DSP2_STOPS */
+#define WM8958_DSP2_STOPS_WIDTH                      1  /* DSP2_STOPS */
+#define WM8958_DSP2_STOPI                       0x0008  /* DSP2_STOPI */
+#define WM8958_DSP2_STOPI_MASK                  0x0008  /* DSP2_STOPI */
+#define WM8958_DSP2_STOPI_SHIFT                      3  /* DSP2_STOPI */
+#define WM8958_DSP2_STOPI_WIDTH                      1  /* DSP2_STOPI */
+#define WM8958_DSP2_STOP                        0x0004  /* DSP2_STOP */
+#define WM8958_DSP2_STOP_MASK                   0x0004  /* DSP2_STOP */
+#define WM8958_DSP2_STOP_SHIFT                       2  /* DSP2_STOP */
+#define WM8958_DSP2_STOP_WIDTH                       1  /* DSP2_STOP */
+#define WM8958_DSP2_RUNR                        0x0002  /* DSP2_RUNR */
+#define WM8958_DSP2_RUNR_MASK                   0x0002  /* DSP2_RUNR */
+#define WM8958_DSP2_RUNR_SHIFT                       1  /* DSP2_RUNR */
+#define WM8958_DSP2_RUNR_WIDTH                       1  /* DSP2_RUNR */
+#define WM8958_DSP2_RUN                         0x0001  /* DSP2_RUN */
+#define WM8958_DSP2_RUN_MASK                    0x0001  /* DSP2_RUN */
+#define WM8958_DSP2_RUN_SHIFT                        0  /* DSP2_RUN */
+#define WM8958_DSP2_RUN_WIDTH                        1  /* DSP2_RUN */
+
 #endif
diff --git a/include/sound/alc5623.h b/include/sound/alc5623.h
new file mode 100644 (file)
index 0000000..422c97d
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _INCLUDE_SOUND_ALC5623_H
+#define _INCLUDE_SOUND_ALC5623_H
+struct alc5623_platform_data {
+       /* configure :                              */
+       /* Lineout/Speaker Amps Vmid ratio control  */
+       /* enable/disable adc/dac high pass filters */
+       unsigned int add_ctrl;
+       /* configure :                              */
+       /* output to enable when jack is low        */
+       /* output to enable when jack is high       */
+       /* jack detect (gpio/nc/jack detect [12]    */
+       unsigned int jack_det_ctrl;
+};
+#endif
+
index a1803ec..5d6074f 100644 (file)
@@ -259,6 +259,7 @@ typedef int __bitwise snd_pcm_subformat_t;
 #define SNDRV_PCM_INFO_HALF_DUPLEX     0x00100000      /* only half duplex */
 #define SNDRV_PCM_INFO_JOINT_DUPLEX    0x00200000      /* playback and capture stream are somewhat correlated */
 #define SNDRV_PCM_INFO_SYNC_START      0x00400000      /* pcm support some kind of sync go */
+#define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP        0x00800000      /* period wakeup can be disabled */
 #define SNDRV_PCM_INFO_FIFO_IN_FRAMES  0x80000000      /* internal kernel flag - FIFO size is in frames */
 
 typedef int __bitwise snd_pcm_state_t;
@@ -334,6 +335,8 @@ typedef int snd_pcm_hw_param_t;
 #define        SNDRV_PCM_HW_PARAM_LAST_INTERVAL        SNDRV_PCM_HW_PARAM_TICK_TIME
 
 #define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0)  /* avoid rate resampling */
+#define SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER      (1<<1)  /* export buffer */
+#define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP   (1<<2)  /* disable period wakeups */
 
 struct snd_interval {
        unsigned int min, max;
index 112374d..7715e6f 100644 (file)
@@ -160,12 +160,14 @@ static inline struct snd_ctl_elem_id *snd_ctl_build_ioff(struct snd_ctl_elem_id
 }
 
 /*
- * Frequently used control callbacks
+ * Frequently used control callbacks/helpers
  */
 int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_info *uinfo);
 int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_info *uinfo);
+int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels,
+                     unsigned int items, const char *const names[]);
 
 /*
  * virtual master control
index d98a78d..0909a38 100644 (file)
@@ -28,6 +28,7 @@ enum HDSP_IO_Type {
        Multiface,
        H9652,
        H9632,
+       RPM,
        Undefined,
 };
 
index a81798a..8f76420 100644 (file)
@@ -31,8 +31,8 @@
 /* these minors can still be used for autoloading devices (/dev/aload*) */
 #define SNDRV_MINOR_CONTROL            0       /* 0 */
 #define SNDRV_MINOR_GLOBAL             1       /* 1 */
-#define SNDRV_MINOR_SEQUENCER          (SNDRV_MINOR_GLOBAL + 0 * 32)
-#define SNDRV_MINOR_TIMER              (SNDRV_MINOR_GLOBAL + 1 * 32)
+#define SNDRV_MINOR_SEQUENCER          1       /* SNDRV_MINOR_GLOBAL + 0 * 32 */
+#define SNDRV_MINOR_TIMER              33      /* SNDRV_MINOR_GLOBAL + 1 * 32 */
 
 #ifndef CONFIG_SND_DYNAMIC_MINORS
                                                /* 2 - 3 (reserved) */
index dfd9b76..e731f8d 100644 (file)
@@ -297,6 +297,7 @@ struct snd_pcm_runtime {
        unsigned int info;
        unsigned int rate_num;
        unsigned int rate_den;
+       unsigned int no_period_wakeup: 1;
 
        /* -- SW params -- */
        int tstamp_mode;                /* mmap timestamp is updated */
index e7b6802..1bafe95 100644 (file)
@@ -16,8 +16,6 @@
 
 #include <linux/list.h>
 
-#include <sound/soc.h>
-
 struct snd_pcm_substream;
 
 /*
@@ -205,7 +203,7 @@ struct snd_soc_dai_driver {
        int (*resume)(struct snd_soc_dai *dai);
 
        /* ops */
-       struct snd_soc_dai_ops *ops;
+       const struct snd_soc_dai_ops *ops;
 
        /* DAI capabilities */
        struct snd_soc_pcm_stream capture;
index 8fd3b41..8031769 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/device.h>
 #include <linux/types.h>
 #include <sound/control.h>
-#include <sound/soc.h>
 
 /* widget has no PM register bit */
 #define SND_SOC_NOPM   -1
         wcontrols, wncontrols) \
 {      .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
        .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
+#define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\
+        wcontrols, wncontrols) \
+{      .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
+       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
         wcontrols, wncontrols)\
 {      .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
@@ -90,6 +93,9 @@
 #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
 {      .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
        .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
+#define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \
+{      .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
+       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \
 {      .id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \
        .shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
 {      .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
        .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
        .event = wevent, .event_flags = wflags}
+#define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \
+       wncontrols, wevent, wflags) \
+{      .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
+       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
+       .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
        wncontrols, wevent, wflags) \
 {      .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
 {      .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
        .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
        .event = wevent, .event_flags = wflags}
+#define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
+       wevent, wflags) \
+{      .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
+       .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
+       .event = wevent, .event_flags = wflags}
 
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 #define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
        .info = snd_soc_info_volsw, \
        .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
        .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
-#define SOC_DAPM_DOUBLE(xname, reg, shift_left, shift_right, max, invert, \
-       power) \
-{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
-       .info = snd_soc_info_volsw, \
-       .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
-       .private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) |\
-               ((max) << 16) | ((invert) << 24) }
 #define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_info_volsw, \
        .tlv.p = (tlv_array), \
        .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
        .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
-#define SOC_DAPM_DOUBLE_TLV(xname, reg, shift_left, shift_right, max, invert, \
-       power, tlv_array) \
-{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
-       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\
-       .tlv.p = (tlv_array), \
-       .info = snd_soc_info_volsw, \
-       .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
-       .private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) |\
-               ((max) << 16) | ((invert) << 24) }
 #define SOC_DAPM_ENUM(xname, xenum) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_info_enum_double, \
@@ -297,6 +297,7 @@ enum snd_soc_dapm_type;
 struct snd_soc_dapm_path;
 struct snd_soc_dapm_pin;
 struct snd_soc_dapm_route;
+struct snd_soc_dapm_context;
 
 int dapm_reg_event(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol, int event);
@@ -324,16 +325,16 @@ int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *uncontrol);
 int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *uncontrol);
-int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
+int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
        const struct snd_soc_dapm_widget *widget);
-int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
+int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
        const struct snd_soc_dapm_widget *widget,
        int num);
 
 /* dapm path setup */
-int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec);
-void snd_soc_dapm_free(struct snd_soc_codec *codec);
-int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
+int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm);
+void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm);
+int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
                            const struct snd_soc_dapm_route *route, int num);
 
 /* dapm events */
@@ -343,27 +344,33 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card);
 
 /* dapm sys fs - used by the core */
 int snd_soc_dapm_sys_add(struct device *dev);
-void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec);
+void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm);
 
 /* dapm audio pin control and status */
-int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, const char *pin);
-int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, const char *pin);
-int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, const char *pin);
-int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, const char *pin);
-int snd_soc_dapm_sync(struct snd_soc_codec *codec);
-int snd_soc_dapm_force_enable_pin(struct snd_soc_codec *codec,
+int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm,
+                           const char *pin);
+int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
+                            const char *pin);
+int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
+                               const char *pin);
+int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm);
+int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
                                  const char *pin);
-int snd_soc_dapm_ignore_suspend(struct snd_soc_codec *codec, const char *pin);
+int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
+                               const char *pin);
 
 /* dapm widget types */
 enum snd_soc_dapm_type {
        snd_soc_dapm_input = 0,         /* input pin */
        snd_soc_dapm_output,            /* output pin */
        snd_soc_dapm_mux,                       /* selects 1 analog signal from many inputs */
+       snd_soc_dapm_virt_mux,                  /* virtual version of snd_soc_dapm_mux */
        snd_soc_dapm_value_mux,                 /* selects 1 analog signal from many inputs */
        snd_soc_dapm_mixer,                     /* mixes several analog signals together */
        snd_soc_dapm_mixer_named_ctl,           /* mixer with named controls */
        snd_soc_dapm_pga,                       /* programmable gain/attenuation (volume) */
+       snd_soc_dapm_out_drv,                   /* output driver */
        snd_soc_dapm_adc,                       /* analog to digital converter */
        snd_soc_dapm_dac,                       /* digital to analog converter */
        snd_soc_dapm_micbias,           /* microphone bias (power) */
@@ -425,6 +432,7 @@ struct snd_soc_dapm_widget {
        char *sname;    /* stream name */
        struct snd_soc_codec *codec;
        struct list_head list;
+       struct snd_soc_dapm_context *dapm;
 
        /* dapm control */
        short reg;                                              /* negative reg = no direct dapm */
@@ -461,4 +469,35 @@ struct snd_soc_dapm_widget {
        struct list_head power_list;
 };
 
+struct snd_soc_dapm_update {
+       struct snd_soc_dapm_widget *widget;
+       struct snd_kcontrol *kcontrol;
+       int reg;
+       int mask;
+       int val;
+};
+
+/* DAPM context */
+struct snd_soc_dapm_context {
+       int n_widgets; /* number of widgets in this context */
+       enum snd_soc_bias_level bias_level;
+       enum snd_soc_bias_level suspend_bias_level;
+       struct delayed_work delayed_work;
+       unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
+
+       struct snd_soc_dapm_update *update;
+
+       struct device *dev; /* from parent - for debug */
+       struct snd_soc_codec *codec; /* parent codec */
+       struct snd_soc_card *card; /* parent card */
+
+       /* used during DAPM updates */
+       int dev_power;
+       struct list_head list;
+
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *debugfs_dapm;
+#endif
+};
+
 #endif
index 5c3bce8..74921f2 100644 (file)
@@ -222,10 +222,8 @@ enum snd_soc_bias_level {
 
 struct snd_jack;
 struct snd_soc_card;
-struct snd_soc_device;
 struct snd_soc_pcm_stream;
 struct snd_soc_ops;
-struct snd_soc_dai_mode;
 struct snd_soc_pcm_runtime;
 struct snd_soc_dai;
 struct snd_soc_dai_driver;
@@ -235,9 +233,10 @@ struct snd_soc_platform_driver;
 struct snd_soc_codec;
 struct snd_soc_codec_driver;
 struct soc_enum;
-struct snd_soc_ac97_ops;
 struct snd_soc_jack;
 struct snd_soc_jack_pin;
+struct snd_soc_cache_ops;
+#include <sound/soc-dapm.h>
 
 #ifdef CONFIG_GPIOLIB
 struct snd_soc_jack_gpio;
@@ -253,17 +252,30 @@ enum snd_soc_control_type {
        SND_SOC_SPI,
 };
 
+enum snd_soc_compress_type {
+       SND_SOC_FLAT_COMPRESSION = 1,
+       SND_SOC_LZO_COMPRESSION,
+       SND_SOC_RBTREE_COMPRESSION
+};
+
 int snd_soc_register_platform(struct device *dev,
                struct snd_soc_platform_driver *platform_drv);
 void snd_soc_unregister_platform(struct device *dev);
 int snd_soc_register_codec(struct device *dev,
-               struct snd_soc_codec_driver *codec_drv,
+               const struct snd_soc_codec_driver *codec_drv,
                struct snd_soc_dai_driver *dai_drv, int num_dai);
 void snd_soc_unregister_codec(struct device *dev);
 int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg);
 int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
                               int addr_bits, int data_bits,
                               enum snd_soc_control_type control);
+int snd_soc_cache_sync(struct snd_soc_codec *codec);
+int snd_soc_cache_init(struct snd_soc_codec *codec);
+int snd_soc_cache_exit(struct snd_soc_codec *codec);
+int snd_soc_cache_write(struct snd_soc_codec *codec,
+                       unsigned int reg, unsigned int value);
+int snd_soc_cache_read(struct snd_soc_codec *codec,
+                      unsigned int reg, unsigned int *value);
 
 /* Utility functions to get clock rates from various things */
 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
@@ -420,23 +432,37 @@ struct snd_soc_ops {
        int (*trigger)(struct snd_pcm_substream *, int);
 };
 
+/* SoC cache ops */
+struct snd_soc_cache_ops {
+       const char *name;
+       enum snd_soc_compress_type id;
+       int (*init)(struct snd_soc_codec *codec);
+       int (*exit)(struct snd_soc_codec *codec);
+       int (*read)(struct snd_soc_codec *codec, unsigned int reg,
+               unsigned int *value);
+       int (*write)(struct snd_soc_codec *codec, unsigned int reg,
+               unsigned int value);
+       int (*sync)(struct snd_soc_codec *codec);
+};
+
 /* SoC Audio Codec device */
 struct snd_soc_codec {
        const char *name;
+       const char *name_prefix;
        int id;
        struct device *dev;
-       struct snd_soc_codec_driver *driver;
+       const struct snd_soc_codec_driver *driver;
 
        struct mutex mutex;
        struct snd_soc_card *card;
        struct list_head list;
        struct list_head card_list;
        int num_dai;
+       enum snd_soc_compress_type compress_type;
 
        /* runtime */
        struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
        unsigned int active;
-       unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
        unsigned int cache_only:1;  /* Suppress writes to hardware */
        unsigned int cache_sync:1; /* Cache needs to be synced to hardware */
        unsigned int suspended:1; /* Codec is in suspend PM state */
@@ -444,25 +470,25 @@ struct snd_soc_codec {
        unsigned int ac97_registered:1; /* Codec has been AC97 registered */
        unsigned int ac97_created:1; /* Codec has been created by SoC */
        unsigned int sysfs_registered:1; /* codec has been sysfs registered */
+       unsigned int cache_init:1; /* codec cache has been initialized */
 
        /* codec IO */
        void *control_data; /* codec control (i2c/3wire) data */
        hw_write_t hw_write;
        unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
+       unsigned int (*read)(struct snd_soc_codec *, unsigned int);
+       int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
        void *reg_cache;
+       const void *reg_def_copy;
+       const struct snd_soc_cache_ops *cache_ops;
+       struct mutex cache_rw_mutex;
 
        /* dapm */
-       u32 pop_time;
-       struct list_head dapm_widgets;
-       struct list_head dapm_paths;
-       enum snd_soc_bias_level bias_level;
-       enum snd_soc_bias_level suspend_bias_level;
-       struct delayed_work delayed_work;
+       struct snd_soc_dapm_context dapm;
 
 #ifdef CONFIG_DEBUG_FS
        struct dentry *debugfs_codec_root;
        struct dentry *debugfs_reg;
-       struct dentry *debugfs_pop_time;
        struct dentry *debugfs_dapm;
 #endif
 };
@@ -488,6 +514,7 @@ struct snd_soc_codec_driver {
        short reg_cache_step;
        short reg_word_size;
        const void *reg_cache_default;
+       enum snd_soc_compress_type compress_type;
 
        /* codec bias level */
        int (*set_bias_level)(struct snd_soc_codec *,
@@ -554,6 +581,30 @@ struct snd_soc_dai_link {
        struct snd_soc_ops *ops;
 };
 
+struct snd_soc_codec_conf {
+       const char *dev_name;
+
+       /*
+        * optional map of kcontrol, widget and path name prefixes that are
+        * associated per device
+        */
+       const char *name_prefix;
+
+       /*
+        * set this to the desired compression type if you want to
+        * override the one supplied in codec->driver->compress_type
+        */
+       enum snd_soc_compress_type compress_type;
+};
+
+struct snd_soc_aux_dev {
+       const char *name;               /* Codec name */
+       const char *codec_name;         /* for multi-codec */
+
+       /* codec/machine specific init - e.g. add machine controls */
+       int (*init)(struct snd_soc_dapm_context *dapm);
+};
+
 /* SoC card */
 struct snd_soc_card {
        const char *name;
@@ -579,6 +630,8 @@ struct snd_soc_card {
        /* callbacks */
        int (*set_bias_level)(struct snd_soc_card *,
                              enum snd_soc_bias_level level);
+       int (*set_bias_level_post)(struct snd_soc_card *,
+                                  enum snd_soc_bias_level level);
 
        long pmdown_time;
 
@@ -588,12 +641,35 @@ struct snd_soc_card {
        struct snd_soc_pcm_runtime *rtd;
        int num_rtd;
 
+       /* optional codec specific configuration */
+       struct snd_soc_codec_conf *codec_conf;
+       int num_configs;
+
+       /*
+        * optional auxiliary devices such as amplifiers or codecs with DAI
+        * link unused
+        */
+       struct snd_soc_aux_dev *aux_dev;
+       int num_aux_devs;
+       struct snd_soc_pcm_runtime *rtd_aux;
+       int num_aux_rtd;
+
        struct work_struct deferred_resume_work;
 
        /* lists of probed devices belonging to this card */
        struct list_head codec_dev_list;
        struct list_head platform_dev_list;
        struct list_head dai_dev_list;
+
+       struct list_head widgets;
+       struct list_head paths;
+       struct list_head dapm_list;
+
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *debugfs_card_root;
+       struct dentry *debugfs_pop_time;
+#endif
+       u32 pop_time;
 };
 
 /* SoC machine DAI configuration, glues a codec and cpu DAI together */
@@ -639,17 +715,9 @@ struct soc_enum {
 };
 
 /* codec IO */
-static inline unsigned int snd_soc_read(struct snd_soc_codec *codec,
-                                       unsigned int reg)
-{
-       return codec->driver->read(codec, reg);
-}
-
-static inline unsigned int snd_soc_write(struct snd_soc_codec *codec,
-                                        unsigned int reg, unsigned int val)
-{
-       return codec->driver->write(codec, reg, val);
-}
+unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
+unsigned int snd_soc_write(struct snd_soc_codec *codec,
+                          unsigned int reg, unsigned int val);
 
 /* device driver data */
 
diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h
new file mode 100644 (file)
index 0000000..186e84d
--- /dev/null
@@ -0,0 +1,235 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM asoc
+
+#if !defined(_TRACE_ASOC_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_ASOC_H
+
+#include <linux/ktime.h>
+#include <linux/tracepoint.h>
+
+struct snd_soc_jack;
+struct snd_soc_codec;
+struct snd_soc_card;
+struct snd_soc_dapm_widget;
+
+/*
+ * Log register events
+ */
+DECLARE_EVENT_CLASS(snd_soc_reg,
+
+       TP_PROTO(struct snd_soc_codec *codec, unsigned int reg,
+                unsigned int val),
+
+       TP_ARGS(codec, reg, val),
+
+       TP_STRUCT__entry(
+               __string(       name,           codec->name     )
+               __field(        int,            id              )
+               __field(        unsigned int,   reg             )
+               __field(        unsigned int,   val             )
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, codec->name);
+               __entry->id = codec->id;
+               __entry->reg = reg;
+               __entry->val = val;
+       ),
+
+       TP_printk("codec=%s.%d reg=%x val=%x", __get_str(name),
+                 (int)__entry->id, (unsigned int)__entry->reg,
+                 (unsigned int)__entry->val)
+);
+
+DEFINE_EVENT(snd_soc_reg, snd_soc_reg_write,
+
+       TP_PROTO(struct snd_soc_codec *codec, unsigned int reg,
+                unsigned int val),
+
+       TP_ARGS(codec, reg, val)
+
+);
+
+DEFINE_EVENT(snd_soc_reg, snd_soc_reg_read,
+
+       TP_PROTO(struct snd_soc_codec *codec, unsigned int reg,
+                unsigned int val),
+
+       TP_ARGS(codec, reg, val)
+
+);
+
+DECLARE_EVENT_CLASS(snd_soc_card,
+
+       TP_PROTO(struct snd_soc_card *card, int val),
+
+       TP_ARGS(card, val),
+
+       TP_STRUCT__entry(
+               __string(       name,           card->name      )
+               __field(        int,            val             )
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, card->name);
+               __entry->val = val;
+       ),
+
+       TP_printk("card=%s val=%d", __get_str(name), (int)__entry->val)
+);
+
+DEFINE_EVENT(snd_soc_card, snd_soc_bias_level_start,
+
+       TP_PROTO(struct snd_soc_card *card, int val),
+
+       TP_ARGS(card, val)
+
+);
+
+DEFINE_EVENT(snd_soc_card, snd_soc_bias_level_done,
+
+       TP_PROTO(struct snd_soc_card *card, int val),
+
+       TP_ARGS(card, val)
+
+);
+
+DECLARE_EVENT_CLASS(snd_soc_dapm_basic,
+
+       TP_PROTO(struct snd_soc_card *card),
+
+       TP_ARGS(card),
+
+       TP_STRUCT__entry(
+               __string(       name,   card->name      )
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, card->name);
+       ),
+
+       TP_printk("card=%s", __get_str(name))
+);
+
+DEFINE_EVENT(snd_soc_dapm_basic, snd_soc_dapm_start,
+
+       TP_PROTO(struct snd_soc_card *card),
+
+       TP_ARGS(card)
+
+);
+
+DEFINE_EVENT(snd_soc_dapm_basic, snd_soc_dapm_done,
+
+       TP_PROTO(struct snd_soc_card *card),
+
+       TP_ARGS(card)
+
+);
+
+DECLARE_EVENT_CLASS(snd_soc_dapm_widget,
+
+       TP_PROTO(struct snd_soc_dapm_widget *w, int val),
+
+       TP_ARGS(w, val),
+
+       TP_STRUCT__entry(
+               __string(       name,   w->name         )
+               __field(        int,    val             )
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, w->name);
+               __entry->val = val;
+       ),
+
+       TP_printk("widget=%s val=%d", __get_str(name),
+                 (int)__entry->val)
+);
+
+DEFINE_EVENT(snd_soc_dapm_widget, snd_soc_dapm_widget_power,
+
+       TP_PROTO(struct snd_soc_dapm_widget *w, int val),
+
+       TP_ARGS(w, val)
+
+);
+
+DEFINE_EVENT(snd_soc_dapm_widget, snd_soc_dapm_widget_event_start,
+
+       TP_PROTO(struct snd_soc_dapm_widget *w, int val),
+
+       TP_ARGS(w, val)
+
+);
+
+DEFINE_EVENT(snd_soc_dapm_widget, snd_soc_dapm_widget_event_done,
+
+       TP_PROTO(struct snd_soc_dapm_widget *w, int val),
+
+       TP_ARGS(w, val)
+
+);
+
+TRACE_EVENT(snd_soc_jack_irq,
+
+       TP_PROTO(const char *name),
+
+       TP_ARGS(name),
+
+       TP_STRUCT__entry(
+               __string(       name,   name            )
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, name);
+       ),
+
+       TP_printk("%s", __get_str(name))
+);
+
+TRACE_EVENT(snd_soc_jack_report,
+
+       TP_PROTO(struct snd_soc_jack *jack, int mask, int val),
+
+       TP_ARGS(jack, mask, val),
+
+       TP_STRUCT__entry(
+               __string(       name,           jack->jack->name        )
+               __field(        int,            mask                    )
+               __field(        int,            val                     )
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, jack->jack->name);
+               __entry->mask = mask;
+               __entry->val = val;
+       ),
+
+       TP_printk("jack=%s %x/%x", __get_str(name), (int)__entry->val,
+                 (int)__entry->mask)
+);
+
+TRACE_EVENT(snd_soc_jack_notify,
+
+       TP_PROTO(struct snd_soc_jack *jack, int val),
+
+       TP_ARGS(jack, val),
+
+       TP_STRUCT__entry(
+               __string(       name,           jack->jack->name        )
+               __field(        int,            val                     )
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, jack->jack->name);
+               __entry->val = val;
+       ),
+
+       TP_printk("jack=%s %x", __get_str(name), (int)__entry->val)
+);
+
+#endif /* _TRACE_ASOC_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index a351dd0..2b50cbe 100644 (file)
@@ -19,8 +19,8 @@
 
 /*
  * Let drivers decide whether they want to support given codec from their
- * probe method.  Drivers have direct access to the struct snd_ac97 structure and may
- * decide based on the id field amongst other things.
+ * probe method. Drivers have direct access to the struct snd_ac97
+ * structure and may  decide based on the id field amongst other things.
  */
 static int ac97_bus_match(struct device *dev, struct device_driver *drv)
 {
index 91852e4..3687a6c 100644 (file)
@@ -1114,7 +1114,6 @@ static int onyx_i2c_remove(struct i2c_client *client)
        of_node_put(onyx->codec.node);
        if (onyx->codec_info)
                kfree(onyx->codec_info);
-       i2c_set_clientdata(client, onyx);
        kfree(onyx);
        return 0;
 }
index de8e03a..faa3174 100644 (file)
@@ -287,10 +287,9 @@ static void ftr_gpio_exit(struct gpio_runtime *rt)
                free_irq(linein_detect_irq, &rt->line_in_notify);
        if (rt->line_out_notify.gpio_private)
                free_irq(lineout_detect_irq, &rt->line_out_notify);
-       cancel_delayed_work(&rt->headphone_notify.work);
-       cancel_delayed_work(&rt->line_in_notify.work);
-       cancel_delayed_work(&rt->line_out_notify.work);
-       flush_scheduled_work();
+       cancel_delayed_work_sync(&rt->headphone_notify.work);
+       cancel_delayed_work_sync(&rt->line_in_notify.work);
+       cancel_delayed_work_sync(&rt->line_out_notify.work);
        mutex_destroy(&rt->headphone_notify.mutex);
        mutex_destroy(&rt->line_in_notify.mutex);
        mutex_destroy(&rt->line_out_notify.mutex);
index 7e267c9..c8d8a1a 100644 (file)
@@ -107,10 +107,9 @@ static void pmf_gpio_exit(struct gpio_runtime *rt)
 
        /* make sure no work is pending before freeing
         * all things */
-       cancel_delayed_work(&rt->headphone_notify.work);
-       cancel_delayed_work(&rt->line_in_notify.work);
-       cancel_delayed_work(&rt->line_out_notify.work);
-       flush_scheduled_work();
+       cancel_delayed_work_sync(&rt->headphone_notify.work);
+       cancel_delayed_work_sync(&rt->line_in_notify.work);
+       cancel_delayed_work_sync(&rt->line_out_notify.work);
 
        mutex_destroy(&rt->headphone_notify.mutex);
        mutex_destroy(&rt->line_in_notify.mutex);
index 45a8180..9ce00ed 100644 (file)
@@ -1488,7 +1488,7 @@ int snd_ctl_create(struct snd_card *card)
 }
 
 /*
- * Frequently used control callbacks
+ * Frequently used control callbacks/helpers
  */
 int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_info *uinfo)
@@ -1513,3 +1513,29 @@ int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
 }
 
 EXPORT_SYMBOL(snd_ctl_boolean_stereo_info);
+
+/**
+ * snd_ctl_enum_info - fills the info structure for an enumerated control
+ * @info: the structure to be filled
+ * @channels: the number of the control's channels; often one
+ * @items: the number of control values; also the size of @names
+ * @names: an array containing the names of all control values
+ *
+ * Sets all required fields in @info to their appropriate values.
+ * If the control's accessibility is not the default (readable and writable),
+ * the caller has to fill @info->access.
+ */
+int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels,
+                     unsigned int items, const char *const names[])
+{
+       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       info->count = channels;
+       info->value.enumerated.items = items;
+       if (info->value.enumerated.item >= items)
+               info->value.enumerated.item = items - 1;
+       strlcpy(info->value.enumerated.name,
+               names[info->value.enumerated.item],
+               sizeof(info->value.enumerated.name));
+       return 0;
+}
+EXPORT_SYMBOL(snd_ctl_enum_info);
index b753ec6..a2e4eb3 100644 (file)
@@ -453,8 +453,10 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
        } else {
                *params = *save;
                max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
-               if (max < 0)
+               if (max < 0) {
+                       kfree(save);
                        return max;
+               }
                last = 1;
        }
  _end:
index 11446a1..a82e375 100644 (file)
@@ -373,6 +373,27 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
                           (unsigned long)new_hw_ptr,
                           (unsigned long)runtime->hw_ptr_base);
        }
+
+       if (runtime->no_period_wakeup) {
+               /*
+                * Without regular period interrupts, we have to check
+                * the elapsed time to detect xruns.
+                */
+               jdelta = jiffies - runtime->hw_ptr_jiffies;
+               if (jdelta < runtime->hw_ptr_buffer_jiffies / 2)
+                       goto no_delta_check;
+               hdelta = jdelta - delta * HZ / runtime->rate;
+               while (hdelta > runtime->hw_ptr_buffer_jiffies / 2 + 1) {
+                       delta += runtime->buffer_size;
+                       hw_base += runtime->buffer_size;
+                       if (hw_base >= runtime->boundary)
+                               hw_base = 0;
+                       new_hw_ptr = hw_base + pos;
+                       hdelta -= runtime->hw_ptr_buffer_jiffies;
+               }
+               goto no_delta_check;
+       }
+
        /* something must be really wrong */
        if (delta >= runtime->buffer_size + runtime->period_size) {
                hw_ptr_error(substream,
@@ -442,6 +463,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
                             (long)old_hw_ptr);
        }
 
+ no_delta_check:
        if (runtime->status->hw_ptr == new_hw_ptr)
                return 0;
 
index c0ebb51..4be45e7 100644 (file)
@@ -422,6 +422,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
        runtime->info = params->info;
        runtime->rate_num = params->rate_num;
        runtime->rate_den = params->rate_den;
+       runtime->no_period_wakeup =
+                       (params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) &&
+                       (params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP);
 
        bits = snd_pcm_format_physical_width(runtime->format);
        runtime->sample_bits = bits;
index bf09a5a..119fddb 100644 (file)
@@ -32,6 +32,7 @@
 #include "seq_timer.h"
 #include "seq_system.h"
 #include "seq_info.h"
+#include <sound/minors.h>
 #include <sound/seq_device.h>
 
 #if defined(CONFIG_SND_SEQ_DUMMY_MODULE)
@@ -73,6 +74,9 @@ MODULE_PARM_DESC(seq_default_timer_subdevice, "The default timer subdevice numbe
 module_param(seq_default_timer_resolution, int, 0644);
 MODULE_PARM_DESC(seq_default_timer_resolution, "The default timer resolution in Hz.");
 
+MODULE_ALIAS_CHARDEV(CONFIG_SND_MAJOR, SNDRV_MINOR_SEQUENCER);
+MODULE_ALIAS("devname:snd/seq");
+
 /*
  *  INIT PART
  */
index 66691fe..1c7a3ef 100644 (file)
@@ -188,14 +188,22 @@ static const struct file_operations snd_fops =
 };
 
 #ifdef CONFIG_SND_DYNAMIC_MINORS
-static int snd_find_free_minor(void)
+static int snd_find_free_minor(int type)
 {
        int minor;
 
+       /* static minors for module auto loading */
+       if (type == SNDRV_DEVICE_TYPE_SEQUENCER)
+               return SNDRV_MINOR_SEQUENCER;
+       if (type == SNDRV_DEVICE_TYPE_TIMER)
+               return SNDRV_MINOR_TIMER;
+
        for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) {
-               /* skip minors still used statically for autoloading devices */
-               if (SNDRV_MINOR_DEVICE(minor) == SNDRV_MINOR_CONTROL ||
-                   minor == SNDRV_MINOR_SEQUENCER)
+               /* skip static minors still used for module auto loading */
+               if (SNDRV_MINOR_DEVICE(minor) == SNDRV_MINOR_CONTROL)
+                       continue;
+               if (minor == SNDRV_MINOR_SEQUENCER ||
+                   minor == SNDRV_MINOR_TIMER)
                        continue;
                if (!snd_minors[minor])
                        return minor;
@@ -269,7 +277,7 @@ int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
        preg->private_data = private_data;
        mutex_lock(&sound_mutex);
 #ifdef CONFIG_SND_DYNAMIC_MINORS
-       minor = snd_find_free_minor();
+       minor = snd_find_free_minor(type);
 #else
        minor = snd_kernel_minor(type, card, dev);
        if (minor >= 0 && snd_minors[minor])
index 13afb60..ed01632 100644 (file)
@@ -34,8 +34,8 @@
 #include <sound/initval.h>
 #include <linux/kmod.h>
 
-#if defined(CONFIG_SND_HPET) || defined(CONFIG_SND_HPET_MODULE)
-#define DEFAULT_TIMER_LIMIT 3
+#if defined(CONFIG_SND_HRTIMER) || defined(CONFIG_SND_HRTIMER_MODULE)
+#define DEFAULT_TIMER_LIMIT 4
 #elif defined(CONFIG_SND_RTCTIMER) || defined(CONFIG_SND_RTCTIMER_MODULE)
 #define DEFAULT_TIMER_LIMIT 2
 #else
@@ -52,6 +52,9 @@ MODULE_PARM_DESC(timer_limit, "Maximum global timers in system.");
 module_param(timer_tstamp_monotonic, int, 0444);
 MODULE_PARM_DESC(timer_tstamp_monotonic, "Use posix monotonic clock source for timestamps (default).");
 
+MODULE_ALIAS_CHARDEV(CONFIG_SND_MAJOR, SNDRV_MINOR_TIMER);
+MODULE_ALIAS("devname:snd/timer");
+
 struct snd_timer_user {
        struct snd_timer_instance *timeri;
        int tread;              /* enhanced read with timestamps and events */
index a1282c1..5cfcb90 100644 (file)
@@ -1143,8 +1143,8 @@ snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev,
                                             (resource->start) + 1);
        if (ml403_ac97cr->port == NULL) {
                snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": "
-                          "unable to remap memory region (%x to %x)\n",
-                          resource->start, resource->end);
+                          "unable to remap memory region (%pR)\n",
+                          resource);
                snd_ml403_ac97cr_free(ml403_ac97cr);
                return -EBUSY;
        }
index 971a84a..c424d32 100644 (file)
@@ -57,8 +57,7 @@ static void snd_ak4113_free(struct ak4113 *chip)
 {
        chip->init = 1; /* don't schedule new work */
        mb();
-       cancel_delayed_work(&chip->work);
-       flush_scheduled_work();
+       cancel_delayed_work_sync(&chip->work);
        kfree(chip);
 }
 
@@ -141,7 +140,7 @@ void snd_ak4113_reinit(struct ak4113 *chip)
 {
        chip->init = 1;
        mb();
-       flush_scheduled_work();
+       flush_delayed_work_sync(&chip->work);
        ak4113_init_regs(chip);
        /* bring up statistics / event queing */
        chip->init = 0;
index 0341451..d9fb537 100644 (file)
@@ -67,8 +67,7 @@ static void snd_ak4114_free(struct ak4114 *chip)
 {
        chip->init = 1; /* don't schedule new work */
        mb();
-       cancel_delayed_work(&chip->work);
-       flush_scheduled_work();
+       cancel_delayed_work_sync(&chip->work);
        kfree(chip);
 }
 
@@ -154,7 +153,7 @@ void snd_ak4114_reinit(struct ak4114 *chip)
 {
        chip->init = 1;
        mb();
-       flush_scheduled_work();
+       flush_delayed_work_sync(&chip->work);
        ak4114_init_regs(chip);
        /* bring up statistics / event queing */
        chip->init = 0;
index 12e3465..9823d59 100644 (file)
@@ -209,7 +209,7 @@ config SND_OXYGEN_LIB
         tristate
 
 config SND_OXYGEN
-       tristate "C-Media 8788 (Oxygen)"
+       tristate "C-Media 8786, 8787, 8788 (Oxygen)"
        select SND_OXYGEN_LIB
        select SND_PCM
        select SND_MPU401_UART
@@ -217,13 +217,18 @@ config SND_OXYGEN
          Say Y here to include support for sound cards based on the
          C-Media CMI8788 (Oxygen HD Audio) chip:
           * Asound A-8788
+          * Asus Xonar DG
           * AuzenTech X-Meridian
+          * AuzenTech X-Meridian 2G
           * Bgears b-Enspirer
           * Club3D Theatron DTS
           * HT-Omega Claro (plus)
           * HT-Omega Claro halo (XT)
+          * Kuroutoshikou CMI8787-HG2PCI
           * Razer Barracuda AC-1
           * Sondigo Inferno
+          * TempoTec/MediaTek HiFier Fantasia
+          * TempoTec/MediaTek HiFier Serenade
 
          To compile this driver as a module, choose M here: the module
          will be called snd-oxygen.
@@ -578,18 +583,6 @@ config SND_HDSPM
          To compile this driver as a module, choose M here: the module
          will be called snd-hdspm.
 
-config SND_HIFIER
-       tristate "TempoTec HiFier Fantasia"
-       select SND_OXYGEN_LIB
-       select SND_PCM
-       select SND_MPU401_UART
-       help
-         Say Y here to include support for the MediaTek/TempoTec HiFier
-         Fantasia sound card.
-
-         To compile this driver as a module, choose M here: the module
-         will be called snd-hifier.
-
 config SND_ICE1712
        tristate "ICEnsemble ICE1712 (Envy24)"
        select SND_MPU401_UART
@@ -826,8 +819,8 @@ config SND_VIRTUOSO
          Say Y here to include support for sound cards based on the
          Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS,
          Essence ST (Deluxe), and Essence STX.
-         Support for the HDAV1.3 (Deluxe) is incomplete; for the
-         HDAV1.3 Slim and Xense, missing.
+         Support for the HDAV1.3 (Deluxe) and HDAV1.3 Slim is experimental;
+         for the Xense, missing.
 
          To compile this driver as a module, choose M here: the module
          will be called snd-virtuoso.
index a7630e9..0fc614c 100644 (file)
@@ -1014,8 +1014,7 @@ static int snd_ac97_free(struct snd_ac97 *ac97)
 {
        if (ac97) {
 #ifdef CONFIG_SND_AC97_POWER_SAVE
-               cancel_delayed_work(&ac97->power_work);
-               flush_scheduled_work();
+               cancel_delayed_work_sync(&ac97->power_work);
 #endif
                snd_ac97_proc_done(ac97);
                if (ac97->bus)
@@ -2456,8 +2455,7 @@ void snd_ac97_suspend(struct snd_ac97 *ac97)
        if (ac97->build_ops->suspend)
                ac97->build_ops->suspend(ac97);
 #ifdef CONFIG_SND_AC97_POWER_SAVE
-       cancel_delayed_work(&ac97->power_work);
-       flush_scheduled_work();
+       cancel_delayed_work_sync(&ac97->power_work);
 #endif
        snd_ac97_powerdown(ac97);
 }
index 2f3cacb..6117595 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168).
- *  Copyright (C) 2002, 2005 - 2009 by Andreas Mohr <andi AT lisas.de>
+ *  Copyright (C) 2002, 2005 - 2010 by Andreas Mohr <andi AT lisas.de>
  *
  *  Framework borrowed from Bart Hartgers's als4000.c.
  *  Driver developed on PCI168 AP(W) version (PCI rev. 10, subsystem ID 1801),
 
 #include <asm/io.h>
 #include <linux/init.h>
+#include <linux/bug.h> /* WARN_ONCE */
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
@@ -201,14 +202,15 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}");
 
 /* === Debug settings ===
   Further diagnostic functionality than the settings below
-  does not need to be provided, since one can easily write a bash script
+  does not need to be provided, since one can easily write a POSIX shell script
   to dump the card's I/O ports (those listed in lspci -v -v):
-  function dump()
+  dump()
   {
     local descr=$1; local addr=$2; local count=$3
 
     echo "${descr}: ${count} @ ${addr}:"
-    dd if=/dev/port skip=$[${addr}] count=${count} bs=1 2>/dev/null| hexdump -C
+    dd if=/dev/port skip=`printf %d ${addr}` count=${count} bs=1 \
+      2>/dev/null| hexdump -C
   }
   and then use something like
   "dump joy200 0x200 8", "dump mpu388 0x388 4", "dump joy 0xb400 8",
@@ -216,14 +218,14 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}");
   possibly within a "while true; do ... sleep 1; done" loop.
   Tweaking ports could be done using
   VALSTRING="`printf "%02x" $value`"
-  printf "\x""$VALSTRING"|dd of=/dev/port seek=$[${addr}] bs=1 2>/dev/null
+  printf "\x""$VALSTRING"|dd of=/dev/port seek=`printf %d ${addr}` bs=1 \
+    2>/dev/null
 */
 
 #define DEBUG_MISC     0
 #define DEBUG_CALLS    0
 #define DEBUG_MIXER    0
 #define DEBUG_CODEC    0
-#define DEBUG_IO       0
 #define DEBUG_TIMER    0
 #define DEBUG_GAME     0
 #define DEBUG_PM       0
@@ -291,19 +293,23 @@ static int seqtimer_scaling = 128;
 module_param(seqtimer_scaling, int, 0444);
 MODULE_PARM_DESC(seqtimer_scaling, "Set 1024000Hz sequencer timer scale factor (lockup danger!). Default 128.");
 
-struct snd_azf3328_codec_data {
-       unsigned long io_base;
-       struct snd_pcm_substream *substream;
-       bool running;
-       const char *name;
-};
-
 enum snd_azf3328_codec_type {
+  /* warning: fixed indices (also used for bitmask checks!) */
   AZF_CODEC_PLAYBACK = 0,
   AZF_CODEC_CAPTURE = 1,
   AZF_CODEC_I2S_OUT = 2,
 };
 
+struct snd_azf3328_codec_data {
+       unsigned long io_base; /* keep first! (avoid offset calc) */
+       unsigned int dma_base; /* helper to avoid an indirection in hotpath */
+       spinlock_t *lock; /* TODO: convert to our own per-codec lock member */
+       struct snd_pcm_substream *substream;
+       bool running;
+       enum snd_azf3328_codec_type type;
+       const char *name;
+};
+
 struct snd_azf3328 {
        /* often-used fields towards beginning, then grouped */
 
@@ -362,6 +368,9 @@ MODULE_DEVICE_TABLE(pci, snd_azf3328_ids);
 static int
 snd_azf3328_io_reg_setb(unsigned reg, u8 mask, bool do_set)
 {
+       /* Well, strictly spoken, the inb/outb sequence isn't atomic
+          and would need locking. However we currently don't care
+          since it potentially complicates matters. */
        u8 prev = inb(reg), new;
 
        new = (do_set) ? (prev|mask) : (prev & ~mask);
@@ -413,6 +422,21 @@ snd_azf3328_codec_outl(const struct snd_azf3328_codec_data *codec,
        outl(value, codec->io_base + reg);
 }
 
+static inline void
+snd_azf3328_codec_outl_multi(const struct snd_azf3328_codec_data *codec,
+                            unsigned reg, const void *buffer, int count
+)
+{
+       unsigned long addr = codec->io_base + reg;
+       if (count) {
+               const u32 *buf = buffer;
+               do {
+                       outl(*buf++, addr);
+                       addr += 4;
+               } while (--count);
+       }
+}
+
 static inline u32
 snd_azf3328_codec_inl(const struct snd_azf3328_codec_data *codec, unsigned reg)
 {
@@ -943,38 +967,43 @@ snd_azf3328_hw_free(struct snd_pcm_substream *substream)
 }
 
 static void
-snd_azf3328_codec_setfmt(struct snd_azf3328 *chip,
-                              enum snd_azf3328_codec_type codec_type,
+snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec,
                               enum azf_freq_t bitrate,
                               unsigned int format_width,
                               unsigned int channels
 )
 {
        unsigned long flags;
-       const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
        u16 val = 0xff00;
+       u8 freq = 0;
 
        snd_azf3328_dbgcallenter();
        switch (bitrate) {
-       case AZF_FREQ_4000:  val |= SOUNDFORMAT_FREQ_SUSPECTED_4000; break;
-       case AZF_FREQ_4800:  val |= SOUNDFORMAT_FREQ_SUSPECTED_4800; break;
-       case AZF_FREQ_5512:
-               /* the AZF3328 names it "5510" for some strange reason */
-                            val |= SOUNDFORMAT_FREQ_5510; break;
-       case AZF_FREQ_6620:  val |= SOUNDFORMAT_FREQ_6620; break;
-       case AZF_FREQ_8000:  val |= SOUNDFORMAT_FREQ_8000; break;
-       case AZF_FREQ_9600:  val |= SOUNDFORMAT_FREQ_9600; break;
-       case AZF_FREQ_11025: val |= SOUNDFORMAT_FREQ_11025; break;
-       case AZF_FREQ_13240: val |= SOUNDFORMAT_FREQ_SUSPECTED_13240; break;
-       case AZF_FREQ_16000: val |= SOUNDFORMAT_FREQ_16000; break;
-       case AZF_FREQ_22050: val |= SOUNDFORMAT_FREQ_22050; break;
-       case AZF_FREQ_32000: val |= SOUNDFORMAT_FREQ_32000; break;
+#define AZF_FMT_XLATE(in_freq, out_bits) \
+       do { \
+               case AZF_FREQ_ ## in_freq: \
+                       freq = SOUNDFORMAT_FREQ_ ## out_bits; \
+                       break; \
+       } while (0);
+       AZF_FMT_XLATE(4000, SUSPECTED_4000)
+       AZF_FMT_XLATE(4800, SUSPECTED_4800)
+       /* the AZF3328 names it "5510" for some strange reason: */
+       AZF_FMT_XLATE(5512, 5510)
+       AZF_FMT_XLATE(6620, 6620)
+       AZF_FMT_XLATE(8000, 8000)
+       AZF_FMT_XLATE(9600, 9600)
+       AZF_FMT_XLATE(11025, 11025)
+       AZF_FMT_XLATE(13240, SUSPECTED_13240)
+       AZF_FMT_XLATE(16000, 16000)
+       AZF_FMT_XLATE(22050, 22050)
+       AZF_FMT_XLATE(32000, 32000)
        default:
                snd_printk(KERN_WARNING "unknown bitrate %d, assuming 44.1kHz!\n", bitrate);
                /* fall-through */
-       case AZF_FREQ_44100: val |= SOUNDFORMAT_FREQ_44100; break;
-       case AZF_FREQ_48000: val |= SOUNDFORMAT_FREQ_48000; break;
-       case AZF_FREQ_66200: val |= SOUNDFORMAT_FREQ_SUSPECTED_66200; break;
+       AZF_FMT_XLATE(44100, 44100)
+       AZF_FMT_XLATE(48000, 48000)
+       AZF_FMT_XLATE(66200, SUSPECTED_66200)
+#undef AZF_FMT_XLATE
        }
        /* val = 0xff07; 3m27.993s (65301Hz; -> 64000Hz???) hmm, 66120, 65967, 66123 */
        /* val = 0xff09; 17m15.098s (13123,478Hz; -> 12000Hz???) hmm, 13237.2Hz? */
@@ -986,13 +1015,15 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip,
        /* val = 0xff0d; 41m23.135s (5523,600Hz; -> 5512Hz???) */
        /* val = 0xff0e; 28m30.777s (8017Hz; -> 8000Hz???) */
 
+       val |= freq;
+
        if (channels == 2)
                val |= SOUNDFORMAT_FLAG_2CHANNELS;
 
        if (format_width == 16)
                val |= SOUNDFORMAT_FLAG_16BIT;
 
-       spin_lock_irqsave(&chip->reg_lock, flags);
+       spin_lock_irqsave(codec->lock, flags);
 
        /* set bitrate/format */
        snd_azf3328_codec_outw(codec, IDX_IO_CODEC_SOUNDFORMAT, val);
@@ -1004,7 +1035,8 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip,
         * (FIXME: yes, it works, but what exactly am I doing here?? :)
         * FIXME: does this have some side effects for full-duplex
         * or other dramatic side effects? */
-       if (codec_type == AZF_CODEC_PLAYBACK) /* only do it for playback */
+       /* do it for non-capture codecs only */
+       if (codec->type != AZF_CODEC_CAPTURE)
                snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
                        snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS) |
                        DMA_RUN_SOMETHING1 |
@@ -1014,20 +1046,19 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip,
                        DMA_SOMETHING_ELSE
                );
 
-       spin_unlock_irqrestore(&chip->reg_lock, flags);
+       spin_unlock_irqrestore(codec->lock, flags);
        snd_azf3328_dbgcallleave();
 }
 
 static inline void
-snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328 *chip,
-                           enum snd_azf3328_codec_type codec_type
+snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328_codec_data *codec
 )
 {
        /* choose lowest frequency for low power consumption.
         * While this will cause louder noise due to rather coarse frequency,
         * it should never matter since output should always
         * get disabled properly when idle anyway. */
-       snd_azf3328_codec_setfmt(chip, codec_type, AZF_FREQ_4000, 8, 1);
+       snd_azf3328_codec_setfmt(codec, AZF_FREQ_4000, 8, 1);
 }
 
 static void
@@ -1101,69 +1132,87 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip,
                /* ...and adjust clock, too
                 * (reduce noise and power consumption) */
                if (!enable)
-                       snd_azf3328_codec_setfmt_lowpower(
-                               chip,
-                               codec_type
-                       );
+                       snd_azf3328_codec_setfmt_lowpower(codec);
                codec->running = enable;
        }
 }
 
 static void
-snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip,
-                               enum snd_azf3328_codec_type codec_type,
+snd_azf3328_codec_setdmaa(struct snd_azf3328_codec_data *codec,
                                unsigned long addr,
-                               unsigned int count,
-                               unsigned int size
+                               unsigned int period_bytes,
+                               unsigned int buffer_bytes
 )
 {
-       const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
        snd_azf3328_dbgcallenter();
+       WARN_ONCE(period_bytes & 1, "odd period length!?\n");
+       WARN_ONCE(buffer_bytes != 2 * period_bytes,
+                "missed our input expectations! %u vs. %u\n",
+                buffer_bytes, period_bytes);
        if (!codec->running) {
                /* AZF3328 uses a two buffer pointer DMA transfer approach */
 
-               unsigned long flags, addr_area2;
+               unsigned long flags;
 
                /* width 32bit (prevent overflow): */
-               u32 count_areas, lengths;
+               u32 area_length;
+               struct codec_setup_io {
+                       u32 dma_start_1;
+                       u32 dma_start_2;
+                       u32 dma_lengths;
+               } __attribute__((packed)) setup_io;
+
+               area_length = buffer_bytes/2;
+
+               setup_io.dma_start_1 = addr;
+               setup_io.dma_start_2 = addr+area_length;
 
-               count_areas = size/2;
-               addr_area2 = addr+count_areas;
-               snd_azf3328_dbgcodec("setdma: buffers %08lx[%u] / %08lx[%u]\n",
-                               addr, count_areas, addr_area2, count_areas);
+               snd_azf3328_dbgcodec(
+                       "setdma: buffers %08x[%u] / %08x[%u], %u, %u\n",
+                               setup_io.dma_start_1, area_length,
+                               setup_io.dma_start_2, area_length,
+                               period_bytes, buffer_bytes);
 
-               count_areas--; /* max. index */
+               /* Hmm, are we really supposed to decrement this by 1??
+                  Most definitely certainly not: configuring full length does
+                  work properly (i.e. likely better), and BTW we
+                  violated possibly differing frame sizes with this...
+
+               area_length--; |* max. index *|
+               */
 
                /* build combined I/O buffer length word */
-               lengths = (count_areas << 16) | (count_areas);
-               spin_lock_irqsave(&chip->reg_lock, flags);
-               snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_1, addr);
-               snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_2,
-                                                               addr_area2);
-               snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_LENGTHS,
-                                                               lengths);
-               spin_unlock_irqrestore(&chip->reg_lock, flags);
+               setup_io.dma_lengths = (area_length << 16) | (area_length);
+
+               spin_lock_irqsave(codec->lock, flags);
+               snd_azf3328_codec_outl_multi(
+                       codec, IDX_IO_CODEC_DMA_START_1, &setup_io, 3
+               );
+               spin_unlock_irqrestore(codec->lock, flags);
        }
        snd_azf3328_dbgcallleave();
 }
 
 static int
-snd_azf3328_codec_prepare(struct snd_pcm_substream *substream)
+snd_azf3328_pcm_prepare(struct snd_pcm_substream *substream)
 {
-#if 0
-       struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
        struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_azf3328_codec_data *codec = runtime->private_data;
+#if 0
         unsigned int size = snd_pcm_lib_buffer_bytes(substream);
        unsigned int count = snd_pcm_lib_period_bytes(substream);
 #endif
 
        snd_azf3328_dbgcallenter();
+
+       codec->dma_base = runtime->dma_addr;
+
 #if 0
-       snd_azf3328_codec_setfmt(chip, AZF_CODEC_...,
+       snd_azf3328_codec_setfmt(codec,
                runtime->rate,
                snd_pcm_format_width(runtime->format),
                runtime->channels);
-       snd_azf3328_codec_setdmaa(chip, AZF_CODEC_...,
+       snd_azf3328_codec_setdmaa(codec,
                                        runtime->dma_addr, count, size);
 #endif
        snd_azf3328_dbgcallleave();
@@ -1171,24 +1220,23 @@ snd_azf3328_codec_prepare(struct snd_pcm_substream *substream)
 }
 
 static int
-snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
-                       struct snd_pcm_substream *substream, int cmd)
+snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
        struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
-       const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
        struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_azf3328_codec_data *codec = runtime->private_data;
        int result = 0;
        u16 flags1;
        bool previously_muted = 0;
-       bool is_playback_codec = (AZF_CODEC_PLAYBACK == codec_type);
+       bool is_main_mixer_playback_codec = (AZF_CODEC_PLAYBACK == codec->type);
 
-       snd_azf3328_dbgcalls("snd_azf3328_codec_trigger cmd %d\n", cmd);
+       snd_azf3328_dbgcalls("snd_azf3328_pcm_trigger cmd %d\n", cmd);
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
                snd_azf3328_dbgcodec("START %s\n", codec->name);
 
-               if (is_playback_codec) {
+               if (is_main_mixer_playback_codec) {
                        /* mute WaveOut (avoid clicking during setup) */
                        previously_muted =
                                snd_azf3328_mixer_set_mute(
@@ -1196,12 +1244,12 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
                                );
                }
 
-               snd_azf3328_codec_setfmt(chip, codec_type,
+               snd_azf3328_codec_setfmt(codec,
                        runtime->rate,
                        snd_pcm_format_width(runtime->format),
                        runtime->channels);
 
-               spin_lock(&chip->reg_lock);
+               spin_lock(codec->lock);
                /* first, remember current value: */
                flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS);
 
@@ -1211,14 +1259,14 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
 
                /* FIXME: clear interrupts or what??? */
                snd_azf3328_codec_outw(codec, IDX_IO_CODEC_IRQTYPE, 0xffff);
-               spin_unlock(&chip->reg_lock);
+               spin_unlock(codec->lock);
 
-               snd_azf3328_codec_setdmaa(chip, codec_type, runtime->dma_addr,
+               snd_azf3328_codec_setdmaa(codec, runtime->dma_addr,
                        snd_pcm_lib_period_bytes(substream),
                        snd_pcm_lib_buffer_bytes(substream)
                );
 
-               spin_lock(&chip->reg_lock);
+               spin_lock(codec->lock);
 #ifdef WIN9X
                /* FIXME: enable playback/recording??? */
                flags1 |= DMA_RUN_SOMETHING1 | DMA_RUN_SOMETHING2;
@@ -1242,10 +1290,10 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
                        DMA_EPILOGUE_SOMETHING |
                        DMA_SOMETHING_ELSE);
 #endif
-               spin_unlock(&chip->reg_lock);
-               snd_azf3328_ctrl_codec_activity(chip, codec_type, 1);
+               spin_unlock(codec->lock);
+               snd_azf3328_ctrl_codec_activity(chip, codec->type, 1);
 
-               if (is_playback_codec) {
+               if (is_main_mixer_playback_codec) {
                        /* now unmute WaveOut */
                        if (!previously_muted)
                                snd_azf3328_mixer_set_mute(
@@ -1258,19 +1306,19 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
        case SNDRV_PCM_TRIGGER_RESUME:
                snd_azf3328_dbgcodec("RESUME %s\n", codec->name);
                /* resume codec if we were active */
-               spin_lock(&chip->reg_lock);
+               spin_lock(codec->lock);
                if (codec->running)
                        snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS,
                                snd_azf3328_codec_inw(
                                        codec, IDX_IO_CODEC_DMA_FLAGS
                                ) | DMA_RESUME
                        );
-               spin_unlock(&chip->reg_lock);
+               spin_unlock(codec->lock);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
                snd_azf3328_dbgcodec("STOP %s\n", codec->name);
 
-               if (is_playback_codec) {
+               if (is_main_mixer_playback_codec) {
                        /* mute WaveOut (avoid clicking during setup) */
                        previously_muted =
                                snd_azf3328_mixer_set_mute(
@@ -1278,7 +1326,7 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
                                );
                }
 
-               spin_lock(&chip->reg_lock);
+               spin_lock(codec->lock);
                /* first, remember current value: */
                flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS);
 
@@ -1293,10 +1341,10 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
 
                flags1 &= ~DMA_RUN_SOMETHING1;
                snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1);
-               spin_unlock(&chip->reg_lock);
-               snd_azf3328_ctrl_codec_activity(chip, codec_type, 0);
+               spin_unlock(codec->lock);
+               snd_azf3328_ctrl_codec_activity(chip, codec->type, 0);
 
-               if (is_playback_codec) {
+               if (is_main_mixer_playback_codec) {
                        /* now unmute WaveOut */
                        if (!previously_muted)
                                snd_azf3328_mixer_set_mute(
@@ -1330,67 +1378,29 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type,
        return result;
 }
 
-static int
-snd_azf3328_codec_playback_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       return snd_azf3328_codec_trigger(AZF_CODEC_PLAYBACK, substream, cmd);
-}
-
-static int
-snd_azf3328_codec_capture_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       return snd_azf3328_codec_trigger(AZF_CODEC_CAPTURE, substream, cmd);
-}
-
-static int
-snd_azf3328_codec_i2s_out_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       return snd_azf3328_codec_trigger(AZF_CODEC_I2S_OUT, substream, cmd);
-}
-
 static snd_pcm_uframes_t
-snd_azf3328_codec_pointer(struct snd_pcm_substream *substream,
-                         enum snd_azf3328_codec_type codec_type
+snd_azf3328_pcm_pointer(struct snd_pcm_substream *substream
 )
 {
-       const struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
-       const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
-       unsigned long bufptr, result;
+       const struct snd_azf3328_codec_data *codec =
+               substream->runtime->private_data;
+       unsigned long result;
        snd_pcm_uframes_t frmres;
 
-#ifdef QUERY_HARDWARE
-       bufptr = snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_START_1);
-#else
-       bufptr = substream->runtime->dma_addr;
-#endif
        result = snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_CURRPOS);
 
        /* calculate offset */
-       result -= bufptr;
+#ifdef QUERY_HARDWARE
+       result -= snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_START_1);
+#else
+       result -= codec->dma_base;
+#endif
        frmres = bytes_to_frames( substream->runtime, result);
-       snd_azf3328_dbgcodec("%s @ 0x%8lx, frames %8ld\n",
-                               codec->name, result, frmres);
+       snd_azf3328_dbgcodec("%08li %s @ 0x%8lx, frames %8ld\n",
+                               jiffies, codec->name, result, frmres);
        return frmres;
 }
 
-static snd_pcm_uframes_t
-snd_azf3328_codec_playback_pointer(struct snd_pcm_substream *substream)
-{
-       return snd_azf3328_codec_pointer(substream, AZF_CODEC_PLAYBACK);
-}
-
-static snd_pcm_uframes_t
-snd_azf3328_codec_capture_pointer(struct snd_pcm_substream *substream)
-{
-       return snd_azf3328_codec_pointer(substream, AZF_CODEC_CAPTURE);
-}
-
-static snd_pcm_uframes_t
-snd_azf3328_codec_i2s_out_pointer(struct snd_pcm_substream *substream)
-{
-       return snd_azf3328_codec_pointer(substream, AZF_CODEC_I2S_OUT);
-}
-
 /******************************************************************/
 
 #ifdef SUPPORT_GAMEPORT
@@ -1532,7 +1542,7 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport,
                }
        }
 
-       /* trigger next axes sampling, to be evaluated the next time we
+       /* trigger next sampling of axes, to be evaluated the next time we
         * enter this function */
 
        /* for some very, very strange reason we cannot enable
@@ -1624,29 +1634,29 @@ snd_azf3328_irq_log_unknown_type(u8 which)
 }
 
 static inline void
-snd_azf3328_codec_interrupt(struct snd_azf3328 *chip, u8 status)
+snd_azf3328_pcm_interrupt(const struct snd_azf3328_codec_data *first_codec,
+                         u8 status
+)
 {
        u8 which;
        enum snd_azf3328_codec_type codec_type;
-       const struct snd_azf3328_codec_data *codec;
+       const struct snd_azf3328_codec_data *codec = first_codec;
 
        for (codec_type = AZF_CODEC_PLAYBACK;
                 codec_type <= AZF_CODEC_I2S_OUT;
-                        ++codec_type) {
+                        ++codec_type, ++codec) {
 
                /* skip codec if there's no interrupt for it */
                if (!(status & (1 << codec_type)))
                        continue;
 
-               codec = &chip->codecs[codec_type];
-
-               spin_lock(&chip->reg_lock);
+               spin_lock(codec->lock);
                which = snd_azf3328_codec_inb(codec, IDX_IO_CODEC_IRQTYPE);
                /* ack all IRQ types immediately */
                snd_azf3328_codec_outb(codec, IDX_IO_CODEC_IRQTYPE, which);
-               spin_unlock(&chip->reg_lock);
+               spin_unlock(codec->lock);
 
-               if ((chip->pcm[codec_type]) && (codec->substream)) {
+               if (codec->substream) {
                        snd_pcm_period_elapsed(codec->substream);
                        snd_azf3328_dbgcodec("%s period done (#%x), @ %x\n",
                                codec->name,
@@ -1701,7 +1711,7 @@ snd_azf3328_interrupt(int irq, void *dev_id)
        }
 
        if (status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT))
-               snd_azf3328_codec_interrupt(chip, status);
+               snd_azf3328_pcm_interrupt(chip->codecs, status);
 
        if (status & IRQ_GAMEPORT)
                snd_azf3328_gameport_interrupt(chip);
@@ -1789,101 +1799,85 @@ snd_azf3328_pcm_open(struct snd_pcm_substream *substream,
 {
        struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
        struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type];
 
        snd_azf3328_dbgcallenter();
-       chip->codecs[codec_type].substream = substream;
+       codec->substream = substream;
 
        /* same parameters for all our codecs - at least we think so... */
        runtime->hw = snd_azf3328_hardware;
 
        snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
                                   &snd_azf3328_hw_constraints_rates);
+       runtime->private_data = codec;
        snd_azf3328_dbgcallleave();
        return 0;
 }
 
 static int
-snd_azf3328_playback_open(struct snd_pcm_substream *substream)
+snd_azf3328_pcm_playback_open(struct snd_pcm_substream *substream)
 {
        return snd_azf3328_pcm_open(substream, AZF_CODEC_PLAYBACK);
 }
 
 static int
-snd_azf3328_capture_open(struct snd_pcm_substream *substream)
+snd_azf3328_pcm_capture_open(struct snd_pcm_substream *substream)
 {
        return snd_azf3328_pcm_open(substream, AZF_CODEC_CAPTURE);
 }
 
 static int
-snd_azf3328_i2s_out_open(struct snd_pcm_substream *substream)
+snd_azf3328_pcm_i2s_out_open(struct snd_pcm_substream *substream)
 {
        return snd_azf3328_pcm_open(substream, AZF_CODEC_I2S_OUT);
 }
 
 static int
-snd_azf3328_pcm_close(struct snd_pcm_substream *substream,
-                     enum snd_azf3328_codec_type codec_type
+snd_azf3328_pcm_close(struct snd_pcm_substream *substream
 )
 {
-       struct snd_azf3328 *chip = snd_pcm_substream_chip(substream);
+       struct snd_azf3328_codec_data *codec =
+               substream->runtime->private_data;
 
        snd_azf3328_dbgcallenter();
-       chip->codecs[codec_type].substream = NULL;
+       codec->substream = NULL;
        snd_azf3328_dbgcallleave();
        return 0;
 }
 
-static int
-snd_azf3328_playback_close(struct snd_pcm_substream *substream)
-{
-       return snd_azf3328_pcm_close(substream, AZF_CODEC_PLAYBACK);
-}
-
-static int
-snd_azf3328_capture_close(struct snd_pcm_substream *substream)
-{
-       return snd_azf3328_pcm_close(substream, AZF_CODEC_CAPTURE);
-}
-
-static int
-snd_azf3328_i2s_out_close(struct snd_pcm_substream *substream)
-{
-       return snd_azf3328_pcm_close(substream, AZF_CODEC_I2S_OUT);
-}
-
 /******************************************************************/
 
 static struct snd_pcm_ops snd_azf3328_playback_ops = {
-       .open =         snd_azf3328_playback_open,
-       .close =        snd_azf3328_playback_close,
+       .open =         snd_azf3328_pcm_playback_open,
+       .close =        snd_azf3328_pcm_close,
        .ioctl =        snd_pcm_lib_ioctl,
        .hw_params =    snd_azf3328_hw_params,
        .hw_free =      snd_azf3328_hw_free,
-       .prepare =      snd_azf3328_codec_prepare,
-       .trigger =      snd_azf3328_codec_playback_trigger,
-       .pointer =      snd_azf3328_codec_playback_pointer
+       .prepare =      snd_azf3328_pcm_prepare,
+       .trigger =      snd_azf3328_pcm_trigger,
+       .pointer =      snd_azf3328_pcm_pointer
 };
 
 static struct snd_pcm_ops snd_azf3328_capture_ops = {
-       .open =         snd_azf3328_capture_open,
-       .close =        snd_azf3328_capture_close,
+       .open =         snd_azf3328_pcm_capture_open,
+       .close =        snd_azf3328_pcm_close,
        .ioctl =        snd_pcm_lib_ioctl,
        .hw_params =    snd_azf3328_hw_params,
        .hw_free =      snd_azf3328_hw_free,
-       .prepare =      snd_azf3328_codec_prepare,
-       .trigger =      snd_azf3328_codec_capture_trigger,
-       .pointer =      snd_azf3328_codec_capture_pointer
+       .prepare =      snd_azf3328_pcm_prepare,
+       .trigger =      snd_azf3328_pcm_trigger,
+       .pointer =      snd_azf3328_pcm_pointer
 };
 
 static struct snd_pcm_ops snd_azf3328_i2s_out_ops = {
-       .open =         snd_azf3328_i2s_out_open,
-       .close =        snd_azf3328_i2s_out_close,
+       .open =         snd_azf3328_pcm_i2s_out_open,
+       .close =        snd_azf3328_pcm_close,
        .ioctl =        snd_pcm_lib_ioctl,
        .hw_params =    snd_azf3328_hw_params,
        .hw_free =      snd_azf3328_hw_free,
-       .prepare =      snd_azf3328_codec_prepare,
-       .trigger =      snd_azf3328_codec_i2s_out_trigger,
-       .pointer =      snd_azf3328_codec_i2s_out_pointer
+       .prepare =      snd_azf3328_pcm_prepare,
+       .trigger =      snd_azf3328_pcm_trigger,
+       .pointer =      snd_azf3328_pcm_pointer
 };
 
 static int __devinit
@@ -1966,7 +1960,7 @@ snd_azf3328_timer_start(struct snd_timer *timer)
                snd_azf3328_dbgtimer("delay was too low (%d)!\n", delay);
                delay = 49; /* minimum time is 49 ticks */
        }
-       snd_azf3328_dbgtimer("setting timer countdown value %d, add COUNTDOWN|IRQ\n", delay);
+       snd_azf3328_dbgtimer("setting timer countdown value %d\n", delay);
        delay |= TIMER_COUNTDOWN_ENABLE | TIMER_IRQ_ENABLE;
        spin_lock_irqsave(&chip->reg_lock, flags);
        snd_azf3328_ctrl_outl(chip, IDX_IO_TIMER_VALUE, delay);
@@ -2180,6 +2174,7 @@ snd_azf3328_create(struct snd_card *card,
        };
        u8 dma_init;
        enum snd_azf3328_codec_type codec_type;
+       struct snd_azf3328_codec_data *codec_setup;
 
        *rchip = NULL;
 
@@ -2217,15 +2212,23 @@ snd_azf3328_create(struct snd_card *card,
        chip->opl3_io  = pci_resource_start(pci, 3);
        chip->mixer_io = pci_resource_start(pci, 4);
 
-       chip->codecs[AZF_CODEC_PLAYBACK].io_base =
-                               chip->ctrl_io + AZF_IO_OFFS_CODEC_PLAYBACK;
-       chip->codecs[AZF_CODEC_PLAYBACK].name = "PLAYBACK";
-       chip->codecs[AZF_CODEC_CAPTURE].io_base =
-                               chip->ctrl_io + AZF_IO_OFFS_CODEC_CAPTURE;
-       chip->codecs[AZF_CODEC_CAPTURE].name = "CAPTURE";
-       chip->codecs[AZF_CODEC_I2S_OUT].io_base =
-                               chip->ctrl_io + AZF_IO_OFFS_CODEC_I2S_OUT;
-       chip->codecs[AZF_CODEC_I2S_OUT].name = "I2S_OUT";
+       codec_setup = &chip->codecs[AZF_CODEC_PLAYBACK];
+       codec_setup->io_base = chip->ctrl_io + AZF_IO_OFFS_CODEC_PLAYBACK;
+       codec_setup->lock = &chip->reg_lock;
+       codec_setup->type = AZF_CODEC_PLAYBACK;
+       codec_setup->name = "PLAYBACK";
+
+       codec_setup = &chip->codecs[AZF_CODEC_CAPTURE];
+       codec_setup->io_base = chip->ctrl_io + AZF_IO_OFFS_CODEC_CAPTURE;
+       codec_setup->lock = &chip->reg_lock;
+       codec_setup->type = AZF_CODEC_CAPTURE;
+       codec_setup->name = "CAPTURE";
+
+       codec_setup = &chip->codecs[AZF_CODEC_I2S_OUT];
+       codec_setup->io_base = chip->ctrl_io + AZF_IO_OFFS_CODEC_I2S_OUT;
+       codec_setup->lock = &chip->reg_lock;
+       codec_setup->type = AZF_CODEC_I2S_OUT;
+       codec_setup->name = "I2S_OUT";
 
        if (request_irq(pci->irq, snd_azf3328_interrupt,
                        IRQF_SHARED, card->shortname, chip)) {
@@ -2257,15 +2260,15 @@ snd_azf3328_create(struct snd_card *card,
                struct snd_azf3328_codec_data *codec =
                         &chip->codecs[codec_type];
 
-               /* shutdown codecs to save power */
+               /* shutdown codecs to reduce power / noise */
                        /* have ...ctrl_codec_activity() act properly */
                codec->running = 1;
                snd_azf3328_ctrl_codec_activity(chip, codec_type, 0);
 
-               spin_lock_irq(&chip->reg_lock);
+               spin_lock_irq(codec->lock);
                snd_azf3328_codec_outb(codec, IDX_IO_CODEC_DMA_FLAGS,
                                                 dma_init);
-               spin_unlock_irq(&chip->reg_lock);
+               spin_unlock_irq(codec->lock);
        }
 
        snd_card_set_dev(card, &pci->dev);
@@ -2419,6 +2422,7 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state)
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
 
+       /* same pcm object for playback/capture */
        snd_pcm_suspend_all(chip->pcm[AZF_CODEC_PLAYBACK]);
        snd_pcm_suspend_all(chip->pcm[AZF_CODEC_I2S_OUT]);
 
index 37e1b5d..2958a05 100644 (file)
@@ -637,15 +637,9 @@ static struct snd_kcontrol_new snd_bt87x_capture_boost = {
 static int snd_bt87x_capture_source_info(struct snd_kcontrol *kcontrol,
                                         struct snd_ctl_elem_info *info)
 {
-       static char *texts[3] = {"TV Tuner", "FM", "Mic/Line"};
+       static const char *const texts[3] = {"TV Tuner", "FM", "Mic/Line"};
 
-       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       info->count = 1;
-       info->value.enumerated.items = 3;
-       if (info->value.enumerated.item > 2)
-               info->value.enumerated.item = 2;
-       strcpy(info->value.enumerated.name, texts[info->value.enumerated.item]);
-       return 0;
+       return snd_ctl_enum_info(info, 1, 3, texts);
 }
 
 static int snd_bt87x_capture_source_get(struct snd_kcontrol *kcontrol,
index 329968e..b5bb036 100644 (file)
@@ -2507,14 +2507,12 @@ static int snd_cmipci_line_in_mode_info(struct snd_kcontrol *kcontrol,
                                        struct snd_ctl_elem_info *uinfo)
 {
        struct cmipci *cm = snd_kcontrol_chip(kcontrol);
-       static char *texts[3] = { "Line-In", "Rear Output", "Bass Output" };
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = cm->chip_version >= 39 ? 3 : 2;
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
-       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-       return 0;
+       static const char *const texts[3] = {
+               "Line-In", "Rear Output", "Bass Output"
+       };
+
+       return snd_ctl_enum_info(uinfo, 1,
+                                cm->chip_version >= 39 ? 3 : 2, texts);
 }
 
 static inline unsigned int get_line_in_mode(struct cmipci *cm)
@@ -2564,14 +2562,9 @@ static int snd_cmipci_line_in_mode_put(struct snd_kcontrol *kcontrol,
 static int snd_cmipci_mic_in_mode_info(struct snd_kcontrol *kcontrol,
                                       struct snd_ctl_elem_info *uinfo)
 {
-       static char *texts[2] = { "Mic-In", "Center/LFE Output" };
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = 2;
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
-       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-       return 0;
+       static const char *const texts[2] = { "Mic-In", "Center/LFE Output" };
+
+       return snd_ctl_enum_info(uinfo, 1, 2, texts);
 }
 
 static int snd_cmipci_mic_in_mode_get(struct snd_kcontrol *kcontrol,
index 98b6d02..05e5ec8 100644 (file)
@@ -4571,6 +4571,9 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                }
                memset(cfg->hp_pins + cfg->hp_outs, 0,
                       sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs));
+               if (!cfg->hp_outs)
+                       cfg->line_out_type = AUTO_PIN_HP_OUT;
+
        }
 
        /* sort by sequence */
index a1c4008..d3d18be 100644 (file)
@@ -1235,7 +1235,8 @@ static int azx_setup_periods(struct azx *chip,
                        pos_adj = 0;
                } else {
                        ofs = setup_bdle(substream, azx_dev,
-                                        &bdl, ofs, pos_adj, 1);
+                                        &bdl, ofs, pos_adj,
+                                        !substream->runtime->no_period_wakeup);
                        if (ofs < 0)
                                goto error;
                }
@@ -1247,7 +1248,8 @@ static int azx_setup_periods(struct azx *chip,
                                         period_bytes - pos_adj, 0);
                else
                        ofs = setup_bdle(substream, azx_dev, &bdl, ofs,
-                                        period_bytes, 1);
+                                        period_bytes,
+                                        !substream->runtime->no_period_wakeup);
                if (ofs < 0)
                        goto error;
        }
@@ -1515,7 +1517,8 @@ static struct snd_pcm_hardware azx_pcm_hw = {
                                 /* No full-resume yet implemented */
                                 /* SNDRV_PCM_INFO_RESUME |*/
                                 SNDRV_PCM_INFO_PAUSE |
-                                SNDRV_PCM_INFO_SYNC_START),
+                                SNDRV_PCM_INFO_SYNC_START |
+                                SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
        .formats =              SNDRV_PCM_FMTBIT_S16_LE,
        .rates =                SNDRV_PCM_RATE_48000,
        .rate_min =             48000,
index f7ff3f7..4678067 100644 (file)
@@ -666,7 +666,7 @@ static struct snd_kcontrol_new ad1986a_mixers[] = {
        HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
@@ -729,7 +729,7 @@ static struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
        HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
        /* 
           HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
           HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */
@@ -775,7 +775,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
        HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
        {
@@ -1358,7 +1358,7 @@ static struct snd_kcontrol_new ad1983_mixers[] = {
        HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
        {
@@ -1515,8 +1515,8 @@ static struct snd_kcontrol_new ad1981_mixers[] = {
        HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
        {
@@ -1726,8 +1726,8 @@ static struct snd_kcontrol_new ad1981_hp_mixers[] = {
        HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
 #endif
-       HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost", 0x18, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
        {
@@ -1774,7 +1774,7 @@ static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
        HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
        {
@@ -2160,8 +2160,8 @@ static struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
        HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
 
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
 
        { } /* end */
 };
@@ -2203,8 +2203,8 @@ static struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
        HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
 
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Channel Mode",
@@ -2232,7 +2232,7 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
        HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
 
-       HDA_CODEC_VOLUME("Mic Boost", 0x39, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
 
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -2902,7 +2902,7 @@ static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
                idx = ad1988_pin_idx(pin);
                bnid = ad1988_boost_nids[idx];
                if (bnid) {
-                       sprintf(name, "%s Boost", ctlname);
+                       sprintf(name, "%s Boost Volume", ctlname);
                        return add_control(spec, AD_CTL_WIDGET_VOL, name,
                                           HDA_COMPOSE_AMP_VAL(bnid, 3, idx, HDA_OUTPUT));
 
@@ -3300,8 +3300,8 @@ static struct snd_kcontrol_new ad1884_base_mixers[] = {
        HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
@@ -3499,9 +3499,9 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
        HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
        HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Docking Mic Boost", 0x25, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
@@ -3560,8 +3560,8 @@ static struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
        HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line-In Boost", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line-In Boost Volume", 0x15, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
@@ -3745,9 +3745,9 @@ static struct snd_kcontrol_new ad1884a_base_mixers[] = {
        HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Boost", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
@@ -3888,9 +3888,9 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
        HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
        HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
        { } /* end */
@@ -4126,8 +4126,8 @@ static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
        HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
        {
@@ -4255,8 +4255,8 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
        HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
        { } /* end */
 };
 
@@ -4494,9 +4494,9 @@ static struct snd_kcontrol_new ad1882_base_mixers[] = {
        HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
 
-       HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line-In Boost", 0x3a, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Line-In Boost Volume", 0x3a, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
@@ -4547,7 +4547,7 @@ static struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
        HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
-       HDA_CODEC_VOLUME("Digital Mic Boost", 0x1f, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Digital Mic Boost Volume", 0x1f, 0x0, HDA_INPUT),
        { } /* end */
 };
 
index 76bd58a..e96581f 100644 (file)
@@ -869,16 +869,16 @@ static void cxt5045_hp_unsol_event(struct hda_codec *codec,
 }
 
 static struct snd_kcontrol_new cxt5045_mixers[] = {
-       HDA_CODEC_VOLUME("Int Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Int Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Ext Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Ext Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x17, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Int Mic Playback Switch", 0x17, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x17, 0x2, HDA_INPUT),
-       HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x17, 0x2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x2, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x2, HDA_INPUT),
        HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -910,16 +910,16 @@ static struct snd_kcontrol_new cxt5045_benq_mixers[] = {
 };
 
 static struct snd_kcontrol_new cxt5045_mixers_hp530[] = {
-       HDA_CODEC_VOLUME("Int Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Int Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Ext Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("Ext Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
        HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x17, 0x2, HDA_INPUT),
-       HDA_CODEC_MUTE("Int Mic Playback Switch", 0x17, 0x2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x17, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x17, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x2, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x1, HDA_INPUT),
        HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -947,7 +947,7 @@ static struct hda_verb cxt5045_init_verbs[] = {
        {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
        {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
        {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* Record selector: Int mic */
+       /* Record selector: Internal mic */
        {0x1a, AC_VERB_SET_CONNECT_SEL,0x1},
        {0x1a, AC_VERB_SET_AMP_GAIN_MUTE,
         AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
@@ -960,7 +960,7 @@ static struct hda_verb cxt5045_init_verbs[] = {
 };
 
 static struct hda_verb cxt5045_benq_init_verbs[] = {
-       /* Int Mic, Mic */
+       /* Internal Mic, Mic */
        {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
        /* Line In,HP, Amp  */
@@ -973,7 +973,7 @@ static struct hda_verb cxt5045_benq_init_verbs[] = {
        {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
        {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
        {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* Record selector: Int mic */
+       /* Record selector: Internal mic */
        {0x1a, AC_VERB_SET_CONNECT_SEL, 0x1},
        {0x1a, AC_VERB_SET_AMP_GAIN_MUTE,
         AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
@@ -1376,7 +1376,7 @@ static void cxt5047_hp_unsol_event(struct hda_codec *codec,
 static struct snd_kcontrol_new cxt5047_base_mixers[] = {
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x1a, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT),
        HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT),
@@ -1796,8 +1796,8 @@ static struct snd_kcontrol_new cxt5051_playback_mixers[] = {
 static struct snd_kcontrol_new cxt5051_capture_mixers[] = {
        HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
        HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT),
        HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT),
        HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT),
        {}
@@ -1806,8 +1806,8 @@ static struct snd_kcontrol_new cxt5051_capture_mixers[] = {
 static struct snd_kcontrol_new cxt5051_hp_mixers[] = {
        HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
        HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("External Mic Volume", 0x15, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("External Mic Switch", 0x15, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Volume", 0x15, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Switch", 0x15, 0x00, HDA_INPUT),
        {}
 };
 
@@ -1826,8 +1826,8 @@ static struct snd_kcontrol_new cxt5051_f700_mixers[] = {
 static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = {
        HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
        HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT),
-       HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT),
        {}
 };
 
@@ -1847,7 +1847,7 @@ static struct hda_verb cxt5051_init_verbs[] = {
        {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
        /* DAC1 */      
        {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Record selector: Int mic */
+       /* Record selector: Internal mic */
        {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
        {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
@@ -1874,7 +1874,7 @@ static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = {
        {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
        /* DAC1 */
        {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Record selector: Int mic */
+       /* Record selector: Internal mic */
        {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
        {0x14, AC_VERB_SET_CONNECT_SEL, 0x1},
        /* SPDIF route: PCM */
@@ -1904,7 +1904,7 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
        {0x19, AC_VERB_SET_CONNECT_SEL, 0x00},
        /* DAC1 */
        {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Record selector: Int mic */
+       /* Record selector: Internal mic */
        {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
        {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
@@ -1932,7 +1932,7 @@ static struct hda_verb cxt5051_f700_init_verbs[] = {
        {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
        /* DAC1 */
        {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-       /* Record selector: Int mic */
+       /* Record selector: Internal mic */
        {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
        {0x14, AC_VERB_SET_CONNECT_SEL, 0x1},
        /* SPDIF route: PCM */
@@ -2111,6 +2111,11 @@ static struct hda_channel_mode cxt5066_modes[1] = {
        { 2, NULL },
 };
 
+#define HP_PRESENT_PORT_A      (1 << 0)
+#define HP_PRESENT_PORT_D      (1 << 1)
+#define hp_port_a_present(spec)        ((spec)->hp_present & HP_PRESENT_PORT_A)
+#define hp_port_d_present(spec)        ((spec)->hp_present & HP_PRESENT_PORT_D)
+
 static void cxt5066_update_speaker(struct hda_codec *codec)
 {
        struct conexant_spec *spec = codec->spec;
@@ -2120,24 +2125,20 @@ static void cxt5066_update_speaker(struct hda_codec *codec)
                    spec->hp_present, spec->cur_eapd);
 
        /* Port A (HP) */
-       pinctl = ((spec->hp_present & 1) && spec->cur_eapd) ? PIN_HP : 0;
+       pinctl = (hp_port_a_present(spec) && spec->cur_eapd) ? PIN_HP : 0;
        snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
                        pinctl);
 
        /* Port D (HP/LO) */
-       if (spec->dell_automute) {
-               /* DELL AIO Port Rule: PortA>  PortD>  IntSpk */
-               pinctl = (!(spec->hp_present & 1) && spec->cur_eapd)
-                       ? PIN_OUT : 0;
-       } else if (spec->thinkpad) {
-               if (spec->cur_eapd)
-                       pinctl = spec->port_d_mode;
-               /* Mute dock line-out if Port A (laptop HP) is present */
-               if (spec->hp_present&  1)
+       pinctl = spec->cur_eapd ? spec->port_d_mode : 0;
+       if (spec->dell_automute || spec->thinkpad) {
+               /* Mute if Port A is connected */
+               if (hp_port_a_present(spec))
                        pinctl = 0;
        } else {
-               pinctl = ((spec->hp_present & 2) && spec->cur_eapd)
-                       ? spec->port_d_mode : 0;
+               /* Thinkpad/Dell doesn't give pin-D status */
+               if (!hp_port_d_present(spec))
+                       pinctl = 0;
        }
        snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
                        pinctl);
@@ -2379,8 +2380,8 @@ static void cxt5066_hp_automute(struct hda_codec *codec)
        /* Port D */
        portD = snd_hda_jack_detect(codec, 0x1c);
 
-       spec->hp_present = !!(portA);
-       spec->hp_present |= portD ? 2 : 0;
+       spec->hp_present = portA ? HP_PRESENT_PORT_A : 0;
+       spec->hp_present |= portD ? HP_PRESENT_PORT_D : 0;
        snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n",
                portA, portD, spec->hp_present);
        cxt5066_update_speaker(codec);
@@ -2728,7 +2729,7 @@ static struct snd_kcontrol_new cxt5066_mixers[] = {
 static struct snd_kcontrol_new cxt5066_vostro_mixers[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Int Mic Boost Capture Enum",
+               .name = "Internal Mic Boost Capture Enum",
                .info = cxt5066_mic_boost_mux_enum_info,
                .get = cxt5066_mic_boost_mux_enum_get,
                .put = cxt5066_mic_boost_mux_enum_put,
@@ -2954,7 +2955,7 @@ static struct hda_verb cxt5066_init_verbs_ideapad[] = {
        {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 
        /* internal microphone */
-       {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */
+       {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable internal mic */
 
        /* EAPD */
        {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
@@ -3009,7 +3010,7 @@ static struct hda_verb cxt5066_init_verbs_thinkpad[] = {
        {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
 
        /* internal microphone */
-       {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */
+       {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable internal mic */
 
        /* EAPD */
        {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
@@ -3097,6 +3098,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
        SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO),
        SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD),
+       SND_PCI_QUIRK(0x1028, 0x0401, "Dell Vostro 1014", CXT5066_DELL_VOSTRO),
        SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO),
        SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP),
@@ -3108,16 +3110,9 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
                      CXT5066_LAPTOP),
        SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD),
-       SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD),
-       SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD),
-       SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD),
-       SND_PCI_QUIRK(0x17aa, 0x21c8, "Thinkpad Edge 11", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
-       SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G series", CXT5066_IDEAPAD),
-       SND_PCI_QUIRK(0x17aa, 0x390a, "Lenovo S10-3t", CXT5066_IDEAPAD),
-       SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G series (AMD)", CXT5066_IDEAPAD),
-       SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD),
+       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT5066_IDEAPAD), /* Fallback for Lenovos without dock mic */
        {}
 };
 
@@ -3422,6 +3417,9 @@ static void cx_auto_hp_automute(struct hda_codec *codec)
                                    AC_VERB_SET_PIN_WIDGET_CONTROL,
                                    present ? 0 : PIN_OUT);
        }
+       for (i = 0; !present && i < cfg->line_outs; i++)
+               if (snd_hda_jack_detect(codec, cfg->line_out_pins[i]))
+                       present = 1;
        for (i = 0; i < cfg->speaker_outs; i++) {
                snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
                                    AC_VERB_SET_PIN_WIDGET_CONTROL,
index 31df774..f29b97b 100644 (file)
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/moduleparam.h>
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 
+static bool static_hdmi_pcm;
+module_param(static_hdmi_pcm, bool, 0644);
+MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
+
 /*
  * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device
  * could support two independent pipes, each of them can be connected to one or
@@ -827,7 +832,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
                *codec_pars = *hinfo;
 
        eld = &spec->sink_eld[idx];
-       if (eld->sad_count > 0) {
+       if (!static_hdmi_pcm && eld->eld_valid && eld->sad_count > 0) {
                hdmi_eld_update_pcm_info(eld, hinfo, codec_pars);
                if (hinfo->channels_min > hinfo->channels_max ||
                    !hinfo->rates || !hinfo->formats)
@@ -904,23 +909,28 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
        spec->pin[spec->num_pins] = pin_nid;
        spec->num_pins++;
 
-       /*
-        * It is assumed that converter nodes come first in the node list and
-        * hence have been registered and usable now.
-        */
        return hdmi_read_pin_conn(codec, pin_nid);
 }
 
 static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid)
 {
+       int i, found_pin = 0;
        struct hdmi_spec *spec = codec->spec;
 
-       if (spec->num_cvts >= MAX_HDMI_CVTS) {
-               snd_printk(KERN_WARNING
-                          "HDMI: no space for converter %d\n", nid);
-               return -E2BIG;
+       for (i = 0; i < spec->num_pins; i++)
+               if (nid == spec->pin_cvt[i]) {
+                       found_pin = 1;
+                       break;
+               }
+
+       if (!found_pin) {
+               snd_printdd("HDMI: Skipping node %d (no connection)\n", nid);
+               return -EINVAL;
        }
 
+       if (snd_BUG_ON(spec->num_cvts >= MAX_HDMI_CVTS))
+               return -E2BIG;
+
        spec->cvt[spec->num_cvts] = nid;
        spec->num_cvts++;
 
@@ -931,6 +941,8 @@ static int hdmi_parse_codec(struct hda_codec *codec)
 {
        hda_nid_t nid;
        int i, nodes;
+       int num_tmp_cvts = 0;
+       hda_nid_t tmp_cvt[MAX_HDMI_CVTS];
 
        nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid);
        if (!nid || nodes < 0) {
@@ -941,6 +953,7 @@ static int hdmi_parse_codec(struct hda_codec *codec)
        for (i = 0; i < nodes; i++, nid++) {
                unsigned int caps;
                unsigned int type;
+               unsigned int config;
 
                caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
                type = get_wcaps_type(caps);
@@ -950,17 +963,32 @@ static int hdmi_parse_codec(struct hda_codec *codec)
 
                switch (type) {
                case AC_WID_AUD_OUT:
-                       hdmi_add_cvt(codec, nid);
+                       if (num_tmp_cvts >= MAX_HDMI_CVTS) {
+                               snd_printk(KERN_WARNING
+                                          "HDMI: no space for converter %d\n", nid);
+                               continue;
+                       }
+                       tmp_cvt[num_tmp_cvts] = nid;
+                       num_tmp_cvts++;
                        break;
                case AC_WID_PIN:
                        caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
                        if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
                                continue;
+
+                       config = snd_hda_codec_read(codec, nid, 0,
+                                            AC_VERB_GET_CONFIG_DEFAULT, 0);
+                       if (get_defcfg_connect(config) == AC_JACK_PORT_NONE)
+                               continue;
+
                        hdmi_add_pin(codec, nid);
                        break;
                }
        }
 
+       for (i = 0; i < num_tmp_cvts; i++)
+               hdmi_add_cvt(codec, tmp_cvt[i]);
+
        /*
         * G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event
         * can be lost and presence sense verb will become inaccurate if the
@@ -1165,11 +1193,53 @@ static int nvhdmi_7x_init(struct hda_codec *codec)
        return 0;
 }
 
+static unsigned int channels_2_6_8[] = {
+       2, 6, 8
+};
+
+static unsigned int channels_2_8[] = {
+       2, 8
+};
+
+static struct snd_pcm_hw_constraint_list hw_constraints_2_6_8_channels = {
+       .count = ARRAY_SIZE(channels_2_6_8),
+       .list = channels_2_6_8,
+       .mask = 0,
+};
+
+static struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = {
+       .count = ARRAY_SIZE(channels_2_8),
+       .list = channels_2_8,
+       .mask = 0,
+};
+
 static int simple_playback_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_hw_constraint_list *hw_constraints_channels = NULL;
+
+       switch (codec->preset->id) {
+       case 0x10de0002:
+       case 0x10de0003:
+       case 0x10de0005:
+       case 0x10de0006:
+               hw_constraints_channels = &hw_constraints_2_8_channels;
+               break;
+       case 0x10de0007:
+               hw_constraints_channels = &hw_constraints_2_6_8_channels;
+               break;
+       default:
+               break;
+       }
+
+       if (hw_constraints_channels != NULL) {
+               snd_pcm_hw_constraint_list(substream->runtime, 0,
+                               SNDRV_PCM_HW_PARAM_CHANNELS,
+                               hw_constraints_channels);
+       }
+
        return snd_hda_multi_out_dig_open(codec, &spec->multiout);
 }
 
@@ -1532,7 +1602,7 @@ static struct hda_codec_preset snd_hda_preset_hdmi[] = {
 { .id = 0x1002793c, .name = "RS600 HDMI",      .patch = patch_atihdmi },
 { .id = 0x10027919, .name = "RS600 HDMI",      .patch = patch_atihdmi },
 { .id = 0x1002791a, .name = "RS690/780 HDMI",  .patch = patch_atihdmi },
-{ .id = 0x1002aa01, .name = "R6xx HDMI",       .patch = patch_atihdmi },
+{ .id = 0x1002aa01, .name = "R6xx HDMI",       .patch = patch_generic_hdmi },
 { .id = 0x10951390, .name = "SiI1390 HDMI",    .patch = patch_generic_hdmi },
 { .id = 0x10951392, .name = "SiI1392 HDMI",    .patch = patch_generic_hdmi },
 { .id = 0x17e80047, .name = "Chrontel HDMI",   .patch = patch_generic_hdmi },
index 552a09e..51c08ed 100644 (file)
@@ -231,7 +231,6 @@ enum {
        ALC888_ACER_ASPIRE_8930G,
        ALC888_ACER_ASPIRE_7730G,
        ALC883_MEDION,
-       ALC883_MEDION_MD2,
        ALC883_MEDION_WIM2160,
        ALC883_LAPTOP_EAPD,
        ALC883_LENOVO_101E_2ch,
@@ -1678,29 +1677,32 @@ struct alc_pincfg {
        u32 val;
 };
 
+struct alc_model_fixup {
+       const int id;
+       const char *name;
+};
+
 struct alc_fixup {
        unsigned int sku;
        const struct alc_pincfg *pins;
        const struct hda_verb *verbs;
+       void (*func)(struct hda_codec *codec, const struct alc_fixup *fix,
+                    int pre_init);
 };
 
-static void alc_pick_fixup(struct hda_codec *codec,
-                          const struct snd_pci_quirk *quirk,
-                          const struct alc_fixup *fix,
-                          int pre_init)
+static void __alc_pick_fixup(struct hda_codec *codec,
+                            const struct alc_fixup *fix,
+                            const char *modelname,
+                            int pre_init)
 {
        const struct alc_pincfg *cfg;
        struct alc_spec *spec;
 
-       quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
-       if (!quirk)
-               return;
-       fix += quirk->value;
        cfg = fix->pins;
        if (pre_init && fix->sku) {
 #ifdef CONFIG_SND_DEBUG_VERBOSE
                snd_printdd(KERN_INFO "hda_codec: %s: Apply sku override for %s\n",
-                           codec->chip_name, quirk->name);
+                           codec->chip_name, modelname);
 #endif
                spec = codec->spec;
                spec->cdefine.sku_cfg = fix->sku;
@@ -1709,7 +1711,7 @@ static void alc_pick_fixup(struct hda_codec *codec,
        if (pre_init && cfg) {
 #ifdef CONFIG_SND_DEBUG_VERBOSE
                snd_printdd(KERN_INFO "hda_codec: %s: Apply pincfg for %s\n",
-                           codec->chip_name, quirk->name);
+                           codec->chip_name, modelname);
 #endif
                for (; cfg->nid; cfg++)
                        snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
@@ -1717,10 +1719,53 @@ static void alc_pick_fixup(struct hda_codec *codec,
        if (!pre_init && fix->verbs) {
 #ifdef CONFIG_SND_DEBUG_VERBOSE
                snd_printdd(KERN_INFO "hda_codec: %s: Apply fix-verbs for %s\n",
-                           codec->chip_name, quirk->name);
+                           codec->chip_name, modelname);
 #endif
                add_verb(codec->spec, fix->verbs);
        }
+       if (fix->func) {
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+               snd_printdd(KERN_INFO "hda_codec: %s: Apply fix-func for %s\n",
+                           codec->chip_name, modelname);
+#endif
+               fix->func(codec, fix, pre_init);
+       }
+}
+
+static void alc_pick_fixup(struct hda_codec *codec,
+                                const struct snd_pci_quirk *quirk,
+                                const struct alc_fixup *fix,
+                                int pre_init)
+{
+       quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
+       if (quirk) {
+               fix += quirk->value;
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+               __alc_pick_fixup(codec, fix, quirk->name, pre_init);
+#else
+               __alc_pick_fixup(codec, fix, NULL, pre_init);
+#endif
+       }
+}
+
+static void alc_pick_fixup_model(struct hda_codec *codec,
+                                const struct alc_model_fixup *models,
+                                const struct snd_pci_quirk *quirk,
+                                const struct alc_fixup *fix,
+                                int pre_init)
+{
+       if (codec->modelname && models) {
+               while (models->name) {
+                       if (!strcmp(codec->modelname, models->name)) {
+                               fix += models->id;
+                               break;
+                       }
+                       models++;
+               }
+               __alc_pick_fixup(codec, fix, codec->modelname, pre_init);
+       } else {
+               alc_pick_fixup(codec, quirk, fix, pre_init);
+       }
 }
 
 static int alc_read_coef_idx(struct hda_codec *codec,
@@ -1981,6 +2026,7 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
        {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
        { }
 };
 
@@ -2120,17 +2166,17 @@ static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
        {
                .num_items = 5,
                .items = {
-                       { "Ext Mic", 0x0 },
+                       { "Mic", 0x0 },
                        { "Line In", 0x2 },
                        { "CD", 0x4 },
                        { "Input Mix", 0xa },
-                       { "Int Mic", 0xb },
+                       { "Internal Mic", 0xb },
                },
        },
        {
                .num_items = 4,
                .items = {
-                       { "Ext Mic", 0x0 },
+                       { "Mic", 0x0 },
                        { "Line In", 0x2 },
                        { "CD", 0x4 },
                        { "Input Mix", 0xa },
@@ -2187,7 +2233,7 @@ static struct snd_kcontrol_new alc888_base_mixer[] = {
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        { } /* end */
 };
@@ -2205,7 +2251,7 @@ static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        { } /* end */
 };
@@ -2796,10 +2842,10 @@ static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
        HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        { } /* end */
 };
 
@@ -3307,7 +3353,7 @@ static struct hda_verb alc880_beep_init_verbs[] = {
 };
 
 /* auto-toggle front mic */
-static void alc880_uniwill_mic_automute(struct hda_codec *codec)
+static void alc88x_simple_mic_automute(struct hda_codec *codec)
 {
        unsigned int present;
        unsigned char bits;
@@ -3329,7 +3375,7 @@ static void alc880_uniwill_setup(struct hda_codec *codec)
 static void alc880_uniwill_init_hook(struct hda_codec *codec)
 {
        alc_automute_amp(codec);
-       alc880_uniwill_mic_automute(codec);
+       alc88x_simple_mic_automute(codec);
 }
 
 static void alc880_uniwill_unsol_event(struct hda_codec *codec,
@@ -3340,7 +3386,7 @@ static void alc880_uniwill_unsol_event(struct hda_codec *codec,
         */
        switch (res >> 28) {
        case ALC880_MIC_EVENT:
-               alc880_uniwill_mic_automute(codec);
+               alc88x_simple_mic_automute(codec);
                break;
        default:
                alc_automute_amp_unsol_event(codec, res);
@@ -5023,6 +5069,25 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
        return 0;
 }
 
+static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg,
+                                       bool can_be_master)
+{
+       if (!cfg->hp_outs && !cfg->speaker_outs && can_be_master)
+               return "Master";
+
+       switch (cfg->line_out_type) {
+       case AUTO_PIN_SPEAKER_OUT:
+               return "Speaker";
+       case AUTO_PIN_HP_OUT:
+               return "Headphone";
+       default:
+               if (cfg->line_outs == 1)
+                       return "PCM";
+               break;
+       }
+       return NULL;
+}
+
 /* add playback controls from the parsed DAC table */
 static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
                                             const struct auto_pin_cfg *cfg)
@@ -5030,6 +5095,7 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
        static const char *chname[4] = {
                "Front", "Surround", NULL /*CLFE*/, "Side"
        };
+       const char *pfx = alc_get_line_out_pfx(cfg, false);
        hda_nid_t nid;
        int i, err;
 
@@ -5037,7 +5103,7 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
                if (!spec->multiout.dac_nids[i])
                        continue;
                nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
-               if (i == 2) {
+               if (!pfx && i == 2) {
                        /* Center/LFE */
                        err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
                                              "Center",
@@ -5064,18 +5130,17 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
                        if (err < 0)
                                return err;
                } else {
-                       const char *pfx;
-                       if (cfg->line_outs == 1 &&
-                           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-                               pfx = "Speaker";
-                       else
-                               pfx = chname[i];
-                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
+                       const char *name = pfx;
+                       if (!name)
+                               name = chname[i];
+                       err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
+                                               name, i,
                                          HDA_COMPOSE_AMP_VAL(nid, 3, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
-                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
+                       err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
+                                              name, i,
                                          HDA_COMPOSE_AMP_VAL(nid, 3, 2,
                                                              HDA_INPUT));
                        if (err < 0)
@@ -5155,7 +5220,8 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec,
 {
        struct alc_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx, type, type_idx = 0;
+       int i, err, idx, type_idx = 0;
+       const char *prev_label = NULL;
 
        for (i = 0; i < cfg->num_inputs; i++) {
                hda_nid_t pin;
@@ -5165,12 +5231,13 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec,
                if (!alc_is_input_pin(codec, pin))
                        continue;
 
-               type = cfg->inputs[i].type;
-               if (i > 0 && type == cfg->inputs[i - 1].type)
+               label = hda_get_autocfg_input_label(codec, cfg, i);
+               if (prev_label && !strcmp(label, prev_label))
                        type_idx++;
                else
                        type_idx = 0;
-               label = hda_get_autocfg_input_label(codec, cfg, i);
+               prev_label = label;
+
                if (mixer) {
                        idx = get_connection_index(codec, mixer, pin);
                        if (idx >= 0) {
@@ -7406,7 +7473,7 @@ static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
        .num_items = 4,
        .items = {
                { "Mic", 0x0 },
-               { "Int Mic", 0x1 },
+               { "Internal Mic", 0x1 },
                { "Line", 0x2 },
                { "CD", 0x4 },
        },
@@ -7416,7 +7483,7 @@ static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
        .num_items = 2,
        .items = {
                { "Mic", 0x0 },
-               { "Int Mic", 0x1 },
+               { "Internal Mic", 0x1 },
        },
 };
 
@@ -7851,10 +7918,10 @@ static struct snd_kcontrol_new alc882_base_mixer[] = {
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        { } /* end */
 };
@@ -7878,8 +7945,8 @@ static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
        HDA_CODEC_MUTE  ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
        HDA_CODEC_MUTE  ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
        { } /* end */
 };
 
@@ -7896,8 +7963,8 @@ static struct snd_kcontrol_new alc885_mb5_mixer[] = {
        HDA_CODEC_MUTE  ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE  ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x19, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT),
        { } /* end */
 };
 
@@ -7912,7 +7979,7 @@ static struct snd_kcontrol_new alc885_macmini3_mixer[] = {
        HDA_BIND_MUTE   ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
        HDA_CODEC_MUTE  ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
        { } /* end */
 };
 
@@ -7931,7 +7998,7 @@ static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        { } /* end */
 };
@@ -7946,10 +8013,10 @@ static struct snd_kcontrol_new alc882_targa_mixer[] = {
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
        { } /* end */
 };
 
@@ -7969,7 +8036,7 @@ static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
        HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        { } /* end */
 };
 
@@ -7982,7 +8049,7 @@ static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        { } /* end */
 };
@@ -8763,10 +8830,10 @@ static struct snd_kcontrol_new alc883_mitac_mixer[] = {
        HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        { } /* end */
 };
@@ -8777,11 +8844,11 @@ static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
        HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        { } /* end */
 };
 
@@ -8791,11 +8858,11 @@ static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
        HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        { } /* end */
 };
 
@@ -8808,10 +8875,10 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        { } /* end */
 };
@@ -8831,10 +8898,10 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        { } /* end */
 };
@@ -8855,10 +8922,10 @@ static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        { } /* end */
 };
@@ -8879,10 +8946,10 @@ static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x1b, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x1b, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        { } /* end */
 };
@@ -8902,10 +8969,10 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        { } /* end */
 };
@@ -8926,7 +8993,7 @@ static struct snd_kcontrol_new alc883_targa_mixer[] = {
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        { } /* end */
 };
@@ -8939,20 +9006,20 @@ static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        { } /* end */
 };
 
 static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
        HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        { } /* end */
 };
 
@@ -8963,7 +9030,7 @@ static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
        HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        { } /* end */
 };
@@ -8976,21 +9043,8 @@ static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       { } /* end */
-};
-
-static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
-       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        { } /* end */
 };
 
@@ -9037,7 +9091,7 @@ static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        { } /* end */
 };
@@ -9050,7 +9104,7 @@ static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        { } /* end */
 };
@@ -9072,10 +9126,10 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        { } /* end */
 };
@@ -9096,8 +9150,8 @@ static struct snd_kcontrol_new alc889A_mb31_mixer[] = {
        HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
        HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
        /* Boost mixers */
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
        /* Input mixers */
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
@@ -9111,7 +9165,7 @@ static struct snd_kcontrol_new alc883_vaiott_mixer[] = {
        HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        { } /* end */
 };
@@ -9141,7 +9195,7 @@ static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        { } /* end */
 };
@@ -9182,16 +9236,6 @@ static void alc883_mitac_setup(struct hda_codec *codec)
        spec->autocfg.speaker_pins[1] = 0x17;
 }
 
-/* auto-toggle front mic */
-/*
-static void alc883_mitac_mic_automute(struct hda_codec *codec)
-{
-       unsigned char bits = snd_hda_jack_detect(codec, 0x18) ? HDA_AMP_MUTE : 0;
-
-       snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
-}
-*/
-
 static struct hda_verb alc883_mitac_verbs[] = {
        /* HP */
        {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
@@ -9435,18 +9479,8 @@ static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
                alc888_lenovo_ms7195_rca_automute(codec);
 }
 
-static struct hda_verb alc883_medion_md2_verbs[] = {
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
-       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       { } /* end */
-};
-
 /* toggle speaker-output according to the hp-jack state */
-static void alc883_medion_md2_setup(struct hda_codec *codec)
+static void alc883_lenovo_nb0763_setup(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
 
@@ -9458,15 +9492,6 @@ static void alc883_medion_md2_setup(struct hda_codec *codec)
 #define alc883_targa_init_hook         alc882_targa_init_hook
 #define alc883_targa_unsol_event       alc882_targa_unsol_event
 
-static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
-{
-       unsigned int present;
-
-       present = snd_hda_jack_detect(codec, 0x18);
-       snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
-                                HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-}
-
 static void alc883_clevo_m720_setup(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -9478,7 +9503,7 @@ static void alc883_clevo_m720_setup(struct hda_codec *codec)
 static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
 {
        alc_automute_amp(codec);
-       alc883_clevo_m720_mic_automute(codec);
+       alc88x_simple_mic_automute(codec);
 }
 
 static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
@@ -9486,7 +9511,7 @@ static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
 {
        switch (res >> 26) {
        case ALC880_MIC_EVENT:
-               alc883_clevo_m720_mic_automute(codec);
+               alc88x_simple_mic_automute(codec);
                break;
        default:
                alc_automute_amp_unsol_event(codec, res);
@@ -9731,7 +9756,6 @@ static const char *alc882_models[ALC882_MODEL_LAST] = {
        [ALC888_ACER_ASPIRE_8930G]      = "acer-aspire-8930g",
        [ALC888_ACER_ASPIRE_7730G]      = "acer-aspire-7730g",
        [ALC883_MEDION]         = "medion",
-       [ALC883_MEDION_MD2]     = "medion-md2",
        [ALC883_MEDION_WIM2160] = "medion-wim2160",
        [ALC883_LAPTOP_EAPD]    = "laptop-eapd",
        [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
@@ -10379,19 +10403,6 @@ static struct alc_config_preset alc882_presets[] = {
                .channel_mode = alc883_sixstack_modes,
                .input_mux = &alc883_capture_source,
        },
-       [ALC883_MEDION_MD2] = {
-               .mixers = { alc883_medion_md2_mixer},
-               .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
-               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
-               .dac_nids = alc883_dac_nids,
-               .dig_out_nid = ALC883_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
-               .channel_mode = alc883_3ST_2ch_modes,
-               .input_mux = &alc883_capture_source,
-               .unsol_event = alc_automute_amp_unsol_event,
-               .setup = alc883_medion_md2_setup,
-               .init_hook = alc_automute_amp,
-       },
        [ALC883_MEDION_WIM2160] = {
                .mixers = { alc883_medion_wim2160_mixer },
                .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
@@ -10468,7 +10479,7 @@ static struct alc_config_preset alc882_presets[] = {
                .need_dac_fix = 1,
                .input_mux = &alc883_lenovo_nb0763_capture_source,
                .unsol_event = alc_automute_amp_unsol_event,
-               .setup = alc883_medion_md2_setup,
+               .setup = alc883_lenovo_nb0763_setup,
                .init_hook = alc_automute_amp,
        },
        [ALC888_LENOVO_MS7195_DIG] = {
@@ -10830,25 +10841,30 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
-       int i, err, type;
+       int i, err;
        int type_idx = 0;
        hda_nid_t nid;
+       const char *prev_label = NULL;
 
        for (i = 0; i < cfg->num_inputs; i++) {
                if (cfg->inputs[i].type > AUTO_PIN_MIC)
                        break;
                nid = cfg->inputs[i].pin;
                if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
-                       char label[32];
-                       type = cfg->inputs[i].type;
-                       if (i > 0 && type == cfg->inputs[i - 1].type)
+                       const char *label;
+                       char boost_label[32];
+
+                       label = hda_get_autocfg_input_label(codec, cfg, i);
+                       if (prev_label && !strcmp(label, prev_label))
                                type_idx++;
                        else
                                type_idx = 0;
-                       snprintf(label, sizeof(label), "%s Boost",
-                                hda_get_autocfg_input_label(codec, cfg, i));
-                       err = add_control(spec, ALC_CTL_WIDGET_VOL, label,
-                                         type_idx,
+                       prev_label = label;
+
+                       snprintf(boost_label, sizeof(boost_label),
+                                "%s Boost Volume", label);
+                       err = add_control(spec, ALC_CTL_WIDGET_VOL,
+                                         boost_label, type_idx,
                                  HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
                        if (err < 0)
                                return err;
@@ -10857,6 +10873,9 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec)
        return 0;
 }
 
+static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
+                                            const struct auto_pin_cfg *cfg);
+
 /* almost identical with ALC880 parser... */
 static int alc882_parse_auto_config(struct hda_codec *codec)
 {
@@ -10874,7 +10893,10 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
        err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
        if (err < 0)
                return err;
-       err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       if (codec->vendor_id == 0x10ec0887)
+               err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       else
+               err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
        err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
@@ -11090,10 +11112,10 @@ static struct snd_kcontrol_new alc262_base_mixer[] = {
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
@@ -11194,10 +11216,10 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
                            HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
@@ -11219,7 +11241,7 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
                            HDA_OUTPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x1a, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
@@ -11230,7 +11252,7 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
 static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
        HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Rear Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT),
        { } /* end */
 };
 
@@ -11250,7 +11272,7 @@ static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        { } /* end */
 };
 
@@ -11357,10 +11379,10 @@ static struct snd_kcontrol_new alc262_hippo_mixer[] = {
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
        { } /* end */
 };
@@ -11374,10 +11396,10 @@ static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
        { } /* end */
 };
 
@@ -11445,10 +11467,10 @@ static struct snd_kcontrol_new alc262_tyan_mixer[] = {
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
        { } /* end */
 };
 
@@ -11632,7 +11654,7 @@ static struct snd_kcontrol_new alc262_nec_mixer[] = {
 
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
 
        HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
@@ -11687,7 +11709,7 @@ static struct hda_input_mux alc262_fujitsu_capture_source = {
        .num_items = 3,
        .items = {
                { "Mic", 0x0 },
-               { "Int Mic", 0x1 },
+               { "Internal Mic", 0x1 },
                { "CD", 0x4 },
        },
 };
@@ -11839,12 +11861,12 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
        },
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        { } /* end */
 };
 
@@ -11875,12 +11897,12 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
        },
        HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
        HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        { } /* end */
 };
 
@@ -11889,10 +11911,10 @@ static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
        ALC262_HIPPO_MASTER_SWITCH,
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
        { } /* end */
 };
 
@@ -11918,8 +11940,8 @@ static struct snd_kcontrol_new alc262_ultra_mixer[] = {
        HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Headphone Mic Boost", 0x15, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Headphone Mic Boost Volume", 0x15, 0, HDA_INPUT),
        { } /* end */
 };
 
@@ -12089,13 +12111,8 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
        spec->multiout.dac_nids = spec->private_dac_nids;
        spec->multiout.dac_nids[0] = 2;
 
-       if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
-               pfx = "Master";
-       else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-               pfx = "Speaker";
-       else if (cfg->line_out_type == AUTO_PIN_HP_OUT)
-               pfx = "Headphone";
-       else
+       pfx = alc_get_line_out_pfx(cfg, true);
+       if (!pfx)
                pfx = "Front";
        for (i = 0; i < 2; i++) {
                err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx, i);
@@ -12996,9 +13013,9 @@ static struct snd_kcontrol_new alc268_base_mixer[] = {
        HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
        { }
 };
 
@@ -13007,9 +13024,9 @@ static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
        HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
        ALC262_HIPPO_MASTER_SWITCH,
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
        { }
 };
 
@@ -13113,9 +13130,9 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = {
                .put = alc268_acer_master_sw_put,
                .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
        },
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
        { }
 };
 
@@ -13131,8 +13148,8 @@ static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
                .put = alc268_acer_master_sw_put,
                .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
        },
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
        { }
 };
 
@@ -13224,8 +13241,8 @@ static struct snd_kcontrol_new alc268_dell_mixer[] = {
        HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
        { }
 };
 
@@ -13258,8 +13275,8 @@ static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
        { }
 };
 
@@ -14082,10 +14099,10 @@ static struct snd_kcontrol_new alc269_base_mixer[] = {
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
        { } /* end */
@@ -14105,10 +14122,10 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
        },
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
        { }
 };
 
@@ -14126,13 +14143,13 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
        },
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
        HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
-       HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x1b, 0, HDA_INPUT),
        { }
 };
 
@@ -14162,30 +14179,30 @@ static struct snd_kcontrol_new alc269_asus_mixer[] = {
 static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
        HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
        { } /* end */
 };
 
 static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
        HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        { } /* end */
 };
 
 static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
        HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("IntMic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
        { } /* end */
 };
 
 static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
        HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        { } /* end */
 };
 
@@ -14804,12 +14821,23 @@ static int alc269_resume(struct hda_codec *codec)
 }
 #endif /* SND_HDA_NEEDS_RESUME */
 
+static void alc269_fixup_hweq(struct hda_codec *codec,
+                              const struct alc_fixup *fix, int pre_init)
+{
+       int coef;
+
+       coef = alc_read_coef_idx(codec, 0x1e);
+       alc_write_coef_idx(codec, 0x1e, coef | 0x80);
+}
+
 enum {
        ALC269_FIXUP_SONY_VAIO,
        ALC275_FIX_SONY_VAIO_GPIO2,
        ALC269_FIXUP_DELL_M101Z,
        ALC269_FIXUP_SKU_IGNORE,
        ALC269_FIXUP_ASUS_G73JW,
+       ALC269_FIXUP_LENOVO_EAPD,
+       ALC275_FIXUP_SONY_HWEQ,
 };
 
 static const struct alc_fixup alc269_fixups[] = {
@@ -14824,6 +14852,7 @@ static const struct alc_fixup alc269_fixups[] = {
                        {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
                        {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
                        {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
+                       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
                        { }
                }
        },
@@ -14844,17 +14873,34 @@ static const struct alc_fixup alc269_fixups[] = {
                        { }
                }
        },
+       [ALC269_FIXUP_LENOVO_EAPD] = {
+               .verbs = (const struct hda_verb[]) {
+                       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
+                       {}
+               }
+       },
+       [ALC275_FIXUP_SONY_HWEQ] = {
+               .func = alc269_fixup_hweq,
+               .verbs = (const struct hda_verb[]) {
+                       {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
+                       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
+                       {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
+                       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
+                       { }
+               }
+       }
 };
 
 static struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIX_SONY_VAIO_GPIO2),
-       SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIX_SONY_VAIO_GPIO2),
-       SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIX_SONY_VAIO_GPIO2),
+       SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
+       SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
        SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
        SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
        SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
+       SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
        {}
 };
 
@@ -15889,13 +15935,16 @@ static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
        return 0;
 }
 
-static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
-                               hda_nid_t nid, unsigned int chs)
+static int __alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
+                                 hda_nid_t nid, int idx, unsigned int chs)
 {
-       return add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx,
+       return __add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx, idx,
                           HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
 }
 
+#define alc861_create_out_sw(codec, pfx, nid, chs) \
+       __alc861_create_out_sw(codec, pfx, nid, 0, chs)
+
 /* add playback controls from the parsed DAC table */
 static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
                                             const struct auto_pin_cfg *cfg)
@@ -15904,26 +15953,15 @@ static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
        static const char *chname[4] = {
                "Front", "Surround", NULL /*CLFE*/, "Side"
        };
+       const char *pfx = alc_get_line_out_pfx(cfg, true);
        hda_nid_t nid;
        int i, err;
 
-       if (cfg->line_outs == 1) {
-               const char *pfx = NULL;
-               if (!cfg->hp_outs)
-                       pfx = "Master";
-               else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-                       pfx = "Speaker";
-               if (pfx) {
-                       nid = spec->multiout.dac_nids[0];
-                       return alc861_create_out_sw(codec, pfx, nid, 3);
-               }
-       }
-
        for (i = 0; i < cfg->line_outs; i++) {
                nid = spec->multiout.dac_nids[i];
                if (!nid)
                        continue;
-               if (i == 2) {
+               if (!pfx && i == 2) {
                        /* Center/LFE */
                        err = alc861_create_out_sw(codec, "Center", nid, 1);
                        if (err < 0)
@@ -15932,7 +15970,10 @@ static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
                        if (err < 0)
                                return err;
                } else {
-                       err = alc861_create_out_sw(codec, chname[i], nid, 3);
+                       const char *name = pfx;
+                       if (!name)
+                               name = chname[i];
+                       err = __alc861_create_out_sw(codec, name, nid, i, 3);
                        if (err < 0)
                                return err;
                }
@@ -16404,8 +16445,8 @@ static struct hda_input_mux alc861vd_capture_source = {
 static struct hda_input_mux alc861vd_dallas_capture_source = {
        .num_items = 2,
        .items = {
-               { "Ext Mic", 0x0 },
-               { "Int Mic", 0x1 },
+               { "Mic", 0x0 },
+               { "Internal Mic", 0x1 },
        },
 };
 
@@ -16484,11 +16525,11 @@ static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
 
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
 
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
 
@@ -16507,11 +16548,11 @@ static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
 
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
 
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
 
@@ -16531,11 +16572,11 @@ static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
 
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
 
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
 
-       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
        HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
 
@@ -16546,19 +16587,19 @@ static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
 };
 
 /* Pin assignment: Speaker=0x14, HP = 0x15,
- *                 Ext Mic=0x18, Int Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
+ *                 Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
  */
 static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
        HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
        HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
        HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
-       HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        { } /* end */
 };
 
@@ -16723,18 +16764,6 @@ static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
        {}
 };
 
-static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
-{
-       unsigned int present;
-       unsigned char bits;
-
-       present = snd_hda_jack_detect(codec, 0x18);
-       bits = present ? HDA_AMP_MUTE : 0;
-
-       snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
-                                HDA_AMP_MUTE, bits);
-}
-
 static void alc861vd_lenovo_setup(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -16745,7 +16774,7 @@ static void alc861vd_lenovo_setup(struct hda_codec *codec)
 static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
 {
        alc_automute_amp(codec);
-       alc861vd_lenovo_mic_automute(codec);
+       alc88x_simple_mic_automute(codec);
 }
 
 static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
@@ -16753,7 +16782,7 @@ static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
 {
        switch (res >> 26) {
        case ALC880_MIC_EVENT:
-               alc861vd_lenovo_mic_automute(codec);
+               alc88x_simple_mic_automute(codec);
                break;
        default:
                alc_automute_amp_unsol_event(codec, res);
@@ -17043,12 +17072,13 @@ static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
 #define alc861vd_idx_to_mixer_switch(nid)      ((nid) + 0x0c)
 
 /* add playback controls from the parsed DAC table */
-/* Based on ALC880 version. But ALC861VD has separate,
+/* Based on ALC880 version. But ALC861VD and ALC887 have separate,
  * different NIDs for mute/unmute switch and volume control */
 static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
                                             const struct auto_pin_cfg *cfg)
 {
        static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
+       const char *pfx = alc_get_line_out_pfx(cfg, true);
        hda_nid_t nid_v, nid_s;
        int i, err;
 
@@ -17062,7 +17092,7 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
                                alc880_dac_to_idx(
                                        spec->multiout.dac_nids[i]));
 
-               if (i == 2) {
+               if (!pfx && i == 2) {
                        /* Center/LFE */
                        err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
                                              "Center",
@@ -17089,24 +17119,17 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
                        if (err < 0)
                                return err;
                } else {
-                       const char *pfx;
-                       if (cfg->line_outs == 1 &&
-                           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
-                               if (!cfg->hp_pins)
-                                       pfx = "Speaker";
-                               else
-                                       pfx = "PCM";
-                       } else
-                               pfx = chname[i];
-                       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
+                       const char *name = pfx;
+                       if (!name)
+                               name = chname[i];
+                       err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
+                                               name, i,
                                          HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
                                                              HDA_OUTPUT));
                        if (err < 0)
                                return err;
-                       if (cfg->line_outs == 1 &&
-                           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-                               pfx = "Speaker";
-                       err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
+                       err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
+                                              name, i,
                                          HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
                                                              HDA_INPUT));
                        if (err < 0)
@@ -17570,13 +17593,13 @@ static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
        HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
        ALC262_HIPPO_MASTER_SWITCH,
 
-       HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
 
-       HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        { } /* end */
 };
 
@@ -17720,8 +17743,8 @@ static struct snd_kcontrol_new alc663_g71v_mixer[] = {
 
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        { } /* end */
 };
 
@@ -17732,8 +17755,8 @@ static struct snd_kcontrol_new alc663_g50v_mixer[] = {
 
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        { } /* end */
@@ -18566,13 +18589,13 @@ static struct snd_kcontrol_new alc662_ecs_mixer[] = {
        HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
        ALC262_HIPPO_MASTER_SWITCH,
 
-       HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("e-Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic/LineIn Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
 
-       HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
        { } /* end */
 };
 
@@ -18583,13 +18606,13 @@ static struct snd_kcontrol_new alc272_nc10_mixer[] = {
        HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
 
-       HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
 
-       HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
-       HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
        { } /* end */
 };
 
@@ -19094,20 +19117,24 @@ static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
        return 0;
 }
 
-static inline int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
-                             hda_nid_t nid, unsigned int chs)
+static inline int __alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
+                                      hda_nid_t nid, int idx, unsigned int chs)
 {
-       return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
+       return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx,
                           HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
 }
 
-static inline int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
-                            hda_nid_t nid, unsigned int chs)
+static inline int __alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
+                                     hda_nid_t nid, int idx, unsigned int chs)
 {
-       return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
+       return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx,
                           HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
 }
 
+#define alc662_add_vol_ctl(spec, pfx, nid, chs) \
+       __alc662_add_vol_ctl(spec, pfx, nid, 0, chs)
+#define alc662_add_sw_ctl(spec, pfx, nid, chs) \
+       __alc662_add_sw_ctl(spec, pfx, nid, 0, chs)
 #define alc662_add_stereo_vol(spec, pfx, nid) \
        alc662_add_vol_ctl(spec, pfx, nid, 3)
 #define alc662_add_stereo_sw(spec, pfx, nid) \
@@ -19121,6 +19148,7 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
        static const char *chname[4] = {
                "Front", "Surround", NULL /*CLFE*/, "Side"
        };
+       const char *pfx = alc_get_line_out_pfx(cfg, true);
        hda_nid_t nid, mix;
        int i, err;
 
@@ -19131,7 +19159,7 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
                mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
                if (!mix)
                        continue;
-               if (i == 2) {
+               if (!pfx && i == 2) {
                        /* Center/LFE */
                        err = alc662_add_vol_ctl(spec, "Center", nid, 1);
                        if (err < 0)
@@ -19146,22 +19174,13 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
                        if (err < 0)
                                return err;
                } else {
-                       const char *pfx;
-                       if (cfg->line_outs == 1 &&
-                           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
-                               if (cfg->hp_outs)
-                                       pfx = "Speaker";
-                               else
-                                       pfx = "PCM";
-                       } else
-                               pfx = chname[i];
-                       err = alc662_add_vol_ctl(spec, pfx, nid, 3);
+                       const char *name = pfx;
+                       if (!name)
+                               name = chname[i];
+                       err = __alc662_add_vol_ctl(spec, name, nid, i, 3);
                        if (err < 0)
                                return err;
-                       if (cfg->line_outs == 1 &&
-                           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-                               pfx = "Speaker";
-                       err = alc662_add_sw_ctl(spec, pfx, mix, 3);
+                       err = __alc662_add_sw_ctl(spec, name, mix, i, 3);
                        if (err < 0)
                                return err;
                }
@@ -19358,9 +19377,21 @@ static void alc662_auto_init(struct hda_codec *codec)
                alc_inithook(codec);
 }
 
+static void alc272_fixup_mario(struct hda_codec *codec,
+                              const struct alc_fixup *fix, int pre_init) {
+       if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
+                                     (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
+                                     (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                     (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                     (0 << AC_AMPCAP_MUTE_SHIFT)))
+               printk(KERN_WARNING
+                      "hda_codec: failed to override amp caps for NID 0x2\n");
+}
+
 enum {
        ALC662_FIXUP_ASPIRE,
        ALC662_FIXUP_IDEAPAD,
+       ALC272_FIXUP_MARIO,
 };
 
 static const struct alc_fixup alc662_fixups[] = {
@@ -19376,6 +19407,9 @@ static const struct alc_fixup alc662_fixups[] = {
                        { }
                }
        },
+       [ALC272_FIXUP_MARIO] = {
+               .func = alc272_fixup_mario,
+       }
 };
 
 static struct snd_pci_quirk alc662_fixup_tbl[] = {
@@ -19386,6 +19420,10 @@ static struct snd_pci_quirk alc662_fixup_tbl[] = {
        {}
 };
 
+static const struct alc_model_fixup alc662_fixup_models[] = {
+       {.id = ALC272_FIXUP_MARIO, .name = "mario"},
+       {}
+};
 
 
 static int patch_alc662(struct hda_codec *codec)
@@ -19485,7 +19523,8 @@ static int patch_alc662(struct hda_codec *codec)
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC662_AUTO) {
                spec->init_hook = alc662_auto_init;
-               alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 0);
+               alc_pick_fixup_model(codec, alc662_fixup_models,
+                                    alc662_fixup_tbl, alc662_fixups, 0);
        }
 
        alc_init_jacks(codec);
@@ -19612,9 +19651,9 @@ static struct snd_kcontrol_new alc680_base_mixer[] = {
        HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Int Mic Boost", 0x12, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("Line In Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT),
        { }
 };
 
index f03b2ff..4ab019d 100644 (file)
@@ -389,6 +389,9 @@ static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
        0x11, 0x20, 0
 };
 
+#define STAC92HD88XXX_NUM_DMICS        STAC92HD83XXX_NUM_DMICS
+#define stac92hd88xxx_dmic_nids        stac92hd83xxx_dmic_nids
+
 #define STAC92HD87B_NUM_DMICS   1
 static hda_nid_t stac92hd87b_dmic_nids[STAC92HD87B_NUM_DMICS + 1] = {
        0x11, 0
@@ -3591,7 +3594,7 @@ static int stac_check_auto_mic(struct hda_codec *codec)
                if (check_mic_pin(codec, spec->dmic_nids[i],
                    &fixed, &ext, &dock))
                        return 0;
-       if (!fixed && !ext && !dock)
+       if (!fixed || (!ext && !dock))
                return 0; /* no input to switch */
        if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
                return 0; /* no unsol support */
@@ -5422,7 +5425,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
        snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7ED, 0);
        codec->no_trigger_sense = 1;
        codec->spec = spec;
-       spec->linear_tone_beep = 1;
+       spec->linear_tone_beep = 0;
        codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
        spec->digbeep_nid = 0x21;
        spec->dmic_nids = stac92hd83xxx_dmic_nids;
@@ -5462,15 +5465,21 @@ again:
                spec->num_dmics = stac92xx_connected_ports(codec,
                                stac92hd87b_dmic_nids,
                                STAC92HD87B_NUM_DMICS);
-               /* Fall through */
+               spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids);
+               spec->pin_nids = stac92hd88xxx_pin_nids;
+               spec->mono_nid = 0;
+               spec->num_pwrs = 0;
+               break;
        case 0x111d7666:
        case 0x111d7667:
        case 0x111d7668:
        case 0x111d7669:
+               spec->num_dmics = stac92xx_connected_ports(codec,
+                               stac92hd88xxx_dmic_nids,
+                               STAC92HD88XXX_NUM_DMICS);
                spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids);
                spec->pin_nids = stac92hd88xxx_pin_nids;
                spec->mono_nid = 0;
-               spec->digbeep_nid = 0;
                spec->num_pwrs = 0;
                break;
        case 0x111d7604:
index d1c3f8d..7f4852a 100644 (file)
@@ -263,8 +263,7 @@ static void vt1708_stop_hp_work(struct via_spec *spec)
                return;
        snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81,
                            !spec->vt1708_jack_detectect);
-       cancel_delayed_work(&spec->vt1708_hp_work);
-       flush_scheduled_work();
+       cancel_delayed_work_sync(&spec->vt1708_hp_work);
 }
 
 
index 712c171..7b62de0 100644 (file)
@@ -96,6 +96,11 @@ static unsigned char ap_cs8427_codec_select(struct snd_ice1712 *ice)
                tmp |= ICE1712_DELTA_AP_CCLK | ICE1712_DELTA_AP_CS_CODEC;
                tmp &= ~ICE1712_DELTA_AP_CS_DIGITAL;
                break;
+       case ICE1712_SUBDEVICE_DELTA66E:
+               tmp |= ICE1712_DELTA_66E_CCLK | ICE1712_DELTA_66E_CS_CHIP_A |
+                      ICE1712_DELTA_66E_CS_CHIP_B;
+               tmp &= ~ICE1712_DELTA_66E_CS_CS8427;
+               break;
        case ICE1712_SUBDEVICE_VX442:
                tmp |= ICE1712_VX442_CCLK | ICE1712_VX442_CODEC_CHIP_A | ICE1712_VX442_CODEC_CHIP_B;
                tmp &= ~ICE1712_VX442_CS_DIGITAL;
@@ -119,6 +124,9 @@ static void ap_cs8427_codec_deassert(struct snd_ice1712 *ice, unsigned char tmp)
        case ICE1712_SUBDEVICE_DELTA410:
                tmp |= ICE1712_DELTA_AP_CS_DIGITAL;
                break;
+       case ICE1712_SUBDEVICE_DELTA66E:
+               tmp |= ICE1712_DELTA_66E_CS_CS8427;
+               break;
        case ICE1712_SUBDEVICE_VX442:
                tmp |= ICE1712_VX442_CS_DIGITAL;
                break;
@@ -275,6 +283,20 @@ static void delta1010lt_ak4524_lock(struct snd_akm4xxx *ak, int chip)
        priv->cs_addr = chip << 4;
 }
 
+/*
+ * AK4524 on Delta66 rev E to choose the chip address
+ */
+static void delta66e_ak4524_lock(struct snd_akm4xxx *ak, int chip)
+{
+       struct snd_ak4xxx_private *priv = (void *)ak->private_value[0];
+       struct snd_ice1712 *ice = ak->private_data[0];
+
+       snd_ice1712_save_gpio_status(ice);
+       priv->cs_mask =
+       priv->cs_addr = chip == 0 ? ICE1712_DELTA_66E_CS_CHIP_A :
+                                   ICE1712_DELTA_66E_CS_CHIP_B;
+}
+
 /*
  * AK4528 on VX442 to choose the chip mask
  */
@@ -487,6 +509,29 @@ static struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = {
        .mask_flags = 0,
 };
 
+static struct snd_akm4xxx akm_delta66e __devinitdata = {
+       .type = SND_AK4524,
+       .num_adcs = 4,
+       .num_dacs = 4,
+       .ops = {
+               .lock = delta66e_ak4524_lock,
+               .set_rate_val = delta_ak4524_set_rate_val
+       }
+};
+
+static struct snd_ak4xxx_private akm_delta66e_priv __devinitdata = {
+       .caddr = 2,
+       .cif = 0, /* the default level of the CIF pin from AK4524 */
+       .data_mask = ICE1712_DELTA_66E_DOUT,
+       .clk_mask = ICE1712_DELTA_66E_CCLK,
+       .cs_mask = 0,
+       .cs_addr = 0, /* set later */
+       .cs_none = 0,
+       .add_flags = 0,
+       .mask_flags = 0,
+};
+
+
 static struct snd_akm4xxx akm_delta44 __devinitdata = {
        .type = SND_AK4524,
        .num_adcs = 4,
@@ -644,9 +689,11 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
                err = snd_ice1712_akm4xxx_init(ak, &akm_delta44, &akm_delta44_priv, ice);
                break;
        case ICE1712_SUBDEVICE_VX442:
-       case ICE1712_SUBDEVICE_DELTA66E:
                err = snd_ice1712_akm4xxx_init(ak, &akm_vx442, &akm_vx442_priv, ice);
                break;
+       case ICE1712_SUBDEVICE_DELTA66E:
+               err = snd_ice1712_akm4xxx_init(ak, &akm_delta66e, &akm_delta66e_priv, ice);
+               break;
        default:
                snd_BUG();
                return -EINVAL;
index 1a0ac6c..11a9c3a 100644 (file)
@@ -144,6 +144,17 @@ extern struct snd_ice1712_card_info snd_ice1712_delta_cards[];
 #define ICE1712_DELTA_1010LT_CS_NONE   0x50    /* nothing */
 #define ICE1712_DELTA_1010LT_WORDCLOCK 0x80    /* sample clock source: 0 = Word Clock Input, 1 = S/PDIF Input ??? */
 
+/* M-Audio Delta 66 rev. E definitions.
+ * Newer revisions of Delta 66 have CS8427 over SPI for
+ * S/PDIF transceiver instead of CS8404/CS8414. */
+/* 0x01 = DFS */
+#define ICE1712_DELTA_66E_CCLK         0x02    /* SPI clock */
+#define ICE1712_DELTA_66E_DIN          0x04    /* data input */
+#define ICE1712_DELTA_66E_DOUT         0x08    /* data output */
+#define ICE1712_DELTA_66E_CS_CS8427    0x10    /* chip select, low = CS8427 */
+#define ICE1712_DELTA_66E_CS_CHIP_A    0x20    /* AK4524 #0 */
+#define ICE1712_DELTA_66E_CS_CHIP_B    0x40    /* AK4524 #1 */
+
 /* Digigram VX442 definitions */
 #define ICE1712_VX442_CCLK             0x02    /* SPI clock */
 #define ICE1712_VX442_DIN              0x04    /* data input */
index acd8f15..0f87265 100644 (file)
@@ -1,10 +1,8 @@
 snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o
-snd-hifier-objs := hifier.o
-snd-oxygen-objs := oxygen.o
+snd-oxygen-objs := oxygen.o xonar_dg.o
 snd-virtuoso-objs := virtuoso.o xonar_lib.o \
        xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o
 
 obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o
-obj-$(CONFIG_SND_HIFIER) += snd-hifier.o
 obj-$(CONFIG_SND_OXYGEN) += snd-oxygen.o
 obj-$(CONFIG_SND_VIRTUOSO) += snd-virtuoso.o
diff --git a/sound/pci/oxygen/cs4245.h b/sound/pci/oxygen/cs4245.h
new file mode 100644 (file)
index 0000000..5e0197e
--- /dev/null
@@ -0,0 +1,107 @@
+#define CS4245_CHIP_ID         0x01
+#define CS4245_POWER_CTRL      0x02
+#define CS4245_DAC_CTRL_1      0x03
+#define CS4245_ADC_CTRL                0x04
+#define CS4245_MCLK_FREQ       0x05
+#define CS4245_SIGNAL_SEL      0x06
+#define CS4245_PGA_B_CTRL      0x07
+#define CS4245_PGA_A_CTRL      0x08
+#define CS4245_ANALOG_IN       0x09
+#define CS4245_DAC_A_CTRL      0x0a
+#define CS4245_DAC_B_CTRL      0x0b
+#define CS4245_DAC_CTRL_2      0x0c
+#define CS4245_INT_STATUS      0x0d
+#define CS4245_INT_MASK                0x0e
+#define CS4245_INT_MODE_MSB    0x0f
+#define CS4245_INT_MODE_LSB    0x10
+
+/* Chip ID */
+#define CS4245_CHIP_PART_MASK  0xf0
+#define CS4245_CHIP_REV_MASK   0x0f
+
+/* Power Control */
+#define CS4245_FREEZE          0x80
+#define CS4245_PDN_MIC         0x08
+#define CS4245_PDN_ADC         0x04
+#define CS4245_PDN_DAC         0x02
+#define CS4245_PDN             0x01
+
+/* DAC Control */
+#define CS4245_DAC_FM_MASK     0xc0
+#define CS4245_DAC_FM_SINGLE   0x00
+#define CS4245_DAC_FM_DOUBLE   0x40
+#define CS4245_DAC_FM_QUAD     0x80
+#define CS4245_DAC_DIF_MASK    0x30
+#define CS4245_DAC_DIF_LJUST   0x00
+#define CS4245_DAC_DIF_I2S     0x10
+#define CS4245_DAC_DIF_RJUST_16        0x20
+#define CS4245_DAC_DIF_RJUST_24        0x30
+#define CS4245_RESERVED_1      0x08
+#define CS4245_MUTE_DAC                0x04
+#define CS4245_DEEMPH          0x02
+#define CS4245_DAC_MASTER      0x01
+
+/* ADC Control */
+#define CS4245_ADC_FM_MASK     0xc0
+#define CS4245_ADC_FM_SINGLE   0x00
+#define CS4245_ADC_FM_DOUBLE   0x40
+#define CS4245_ADC_FM_QUAD     0x80
+#define CS4245_ADC_DIF_MASK    0x10
+#define CS4245_ADC_DIF_LJUST   0x00
+#define CS4245_ADC_DIF_I2S     0x10
+#define CS4245_MUTE_ADC                0x04
+#define CS4245_HPF_FREEZE      0x02
+#define CS4245_ADC_MASTER      0x01
+
+/* MCLK Frequency */
+#define CS4245_MCLK1_MASK      0x70
+#define CS4245_MCLK1_SHIFT     4
+#define CS4245_MCLK2_MASK      0x07
+#define CS4245_MCLK2_SHIFT     0
+#define CS4245_MCLK_1          0
+#define CS4245_MCLK_1_5                1
+#define CS4245_MCLK_2          2
+#define CS4245_MCLK_3          3
+#define CS4245_MCLK_4          4
+
+/* Signal Selection */
+#define CS4245_A_OUT_SEL_MASK  0x60
+#define CS4245_A_OUT_SEL_HIZ   0x00
+#define CS4245_A_OUT_SEL_DAC   0x20
+#define CS4245_A_OUT_SEL_PGA   0x40
+#define CS4245_LOOP            0x02
+#define CS4245_ASYNCH          0x01
+
+/* Channel B/A PGA Control */
+#define CS4245_PGA_GAIN_MASK   0x3f
+
+/* ADC Input Control */
+#define CS4245_PGA_SOFT                0x10
+#define CS4245_PGA_ZERO                0x08
+#define CS4245_SEL_MASK                0x07
+#define CS4245_SEL_MIC         0x00
+#define CS4245_SEL_INPUT_1     0x01
+#define CS4245_SEL_INPUT_2     0x02
+#define CS4245_SEL_INPUT_3     0x03
+#define CS4245_SEL_INPUT_4     0x04
+#define CS4245_SEL_INPUT_5     0x05
+#define CS4245_SEL_INPUT_6     0x06
+
+/* DAC Channel A/B Volume Control */
+#define CS4245_VOL_MASK                0xff
+
+/* DAC Control 2 */
+#define CS4245_DAC_SOFT                0x80
+#define CS4245_DAC_ZERO                0x40
+#define CS4245_INVERT_DAC      0x20
+#define CS4245_INT_ACTIVE_HIGH 0x01
+
+/* Interrupt Status/Mask/Mode */
+#define CS4245_ADC_CLK_ERR     0x08
+#define CS4245_DAC_CLK_ERR     0x04
+#define CS4245_ADC_OVFL                0x02
+#define CS4245_ADC_UNDRFL      0x01
+
+
+#define CS4245_SPI_ADDRESS     (0x9e << 16)
+#define CS4245_SPI_WRITE       (0 << 16)
diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c
deleted file mode 100644 (file)
index 5a87d68..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * C-Media CMI8788 driver for the MediaTek/TempoTec HiFier Fantasia
- *
- * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
- *
- *
- *  This driver is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License, version 2.
- *
- *  This driver 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 driver; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-/*
- * CMI8788:
- *
- * SPI 0 -> AK4396
- */
-
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <sound/control.h>
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/tlv.h>
-#include "oxygen.h"
-#include "ak4396.h"
-
-MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
-MODULE_DESCRIPTION("TempoTec HiFier driver");
-MODULE_LICENSE("GPL v2");
-
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
-
-module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "card index");
-module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string");
-module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "enable card");
-
-static DEFINE_PCI_DEVICE_TABLE(hifier_ids) = {
-       { OXYGEN_PCI_SUBID(0x14c3, 0x1710) },
-       { OXYGEN_PCI_SUBID(0x14c3, 0x1711) },
-       { OXYGEN_PCI_SUBID_BROKEN_EEPROM },
-       { }
-};
-MODULE_DEVICE_TABLE(pci, hifier_ids);
-
-struct hifier_data {
-       u8 ak4396_regs[5];
-};
-
-static void ak4396_write(struct oxygen *chip, u8 reg, u8 value)
-{
-       struct hifier_data *data = chip->model_data;
-
-       oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER  |
-                        OXYGEN_SPI_DATA_LENGTH_2 |
-                        OXYGEN_SPI_CLOCK_160 |
-                        (0 << OXYGEN_SPI_CODEC_SHIFT) |
-                        OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
-                        AK4396_WRITE | (reg << 8) | value);
-       data->ak4396_regs[reg] = value;
-}
-
-static void ak4396_write_cached(struct oxygen *chip, u8 reg, u8 value)
-{
-       struct hifier_data *data = chip->model_data;
-
-       if (value != data->ak4396_regs[reg])
-               ak4396_write(chip, reg, value);
-}
-
-static void hifier_registers_init(struct oxygen *chip)
-{
-       struct hifier_data *data = chip->model_data;
-
-       ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN);
-       ak4396_write(chip, AK4396_CONTROL_2,
-                    data->ak4396_regs[AK4396_CONTROL_2]);
-       ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM);
-       ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]);
-       ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]);
-}
-
-static void hifier_init(struct oxygen *chip)
-{
-       struct hifier_data *data = chip->model_data;
-
-       data->ak4396_regs[AK4396_CONTROL_2] =
-               AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
-       hifier_registers_init(chip);
-
-       snd_component_add(chip->card, "AK4396");
-       snd_component_add(chip->card, "CS5340");
-}
-
-static void hifier_cleanup(struct oxygen *chip)
-{
-}
-
-static void hifier_resume(struct oxygen *chip)
-{
-       hifier_registers_init(chip);
-}
-
-static void set_ak4396_params(struct oxygen *chip,
-                              struct snd_pcm_hw_params *params)
-{
-       struct hifier_data *data = chip->model_data;
-       u8 value;
-
-       value = data->ak4396_regs[AK4396_CONTROL_2] & ~AK4396_DFS_MASK;
-       if (params_rate(params) <= 54000)
-               value |= AK4396_DFS_NORMAL;
-       else if (params_rate(params) <= 108000)
-               value |= AK4396_DFS_DOUBLE;
-       else
-               value |= AK4396_DFS_QUAD;
-
-       msleep(1); /* wait for the new MCLK to become stable */
-
-       if (value != data->ak4396_regs[AK4396_CONTROL_2]) {
-               ak4396_write(chip, AK4396_CONTROL_1,
-                            AK4396_DIF_24_MSB);
-               ak4396_write(chip, AK4396_CONTROL_2, value);
-               ak4396_write(chip, AK4396_CONTROL_1,
-                            AK4396_DIF_24_MSB | AK4396_RSTN);
-       }
-}
-
-static void update_ak4396_volume(struct oxygen *chip)
-{
-       ak4396_write_cached(chip, AK4396_LCH_ATT, chip->dac_volume[0]);
-       ak4396_write_cached(chip, AK4396_RCH_ATT, chip->dac_volume[1]);
-}
-
-static void update_ak4396_mute(struct oxygen *chip)
-{
-       struct hifier_data *data = chip->model_data;
-       u8 value;
-
-       value = data->ak4396_regs[AK4396_CONTROL_2] & ~AK4396_SMUTE;
-       if (chip->dac_mute)
-               value |= AK4396_SMUTE;
-       ak4396_write_cached(chip, AK4396_CONTROL_2, value);
-}
-
-static void set_cs5340_params(struct oxygen *chip,
-                             struct snd_pcm_hw_params *params)
-{
-}
-
-static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
-
-static const struct oxygen_model model_hifier = {
-       .shortname = "C-Media CMI8787",
-       .longname = "C-Media Oxygen HD Audio",
-       .chip = "CMI8788",
-       .init = hifier_init,
-       .cleanup = hifier_cleanup,
-       .resume = hifier_resume,
-       .get_i2s_mclk = oxygen_default_i2s_mclk,
-       .set_dac_params = set_ak4396_params,
-       .set_adc_params = set_cs5340_params,
-       .update_dac_volume = update_ak4396_volume,
-       .update_dac_mute = update_ak4396_mute,
-       .dac_tlv = ak4396_db_scale,
-       .model_data_size = sizeof(struct hifier_data),
-       .device_config = PLAYBACK_0_TO_I2S |
-                        PLAYBACK_1_TO_SPDIF |
-                        CAPTURE_0_FROM_I2S_1,
-       .dac_channels = 2,
-       .dac_volume_min = 0,
-       .dac_volume_max = 255,
-       .function_flags = OXYGEN_FUNCTION_SPI,
-       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-};
-
-static int __devinit get_hifier_model(struct oxygen *chip,
-                                     const struct pci_device_id *id)
-{
-       chip->model = model_hifier;
-       return 0;
-}
-
-static int __devinit hifier_probe(struct pci_dev *pci,
-                                 const struct pci_device_id *pci_id)
-{
-       static int dev;
-       int err;
-
-       if (dev >= SNDRV_CARDS)
-               return -ENODEV;
-       if (!enable[dev]) {
-               ++dev;
-               return -ENOENT;
-       }
-       err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE,
-                              hifier_ids, get_hifier_model);
-       if (err >= 0)
-               ++dev;
-       return err;
-}
-
-static struct pci_driver hifier_driver = {
-       .name = "CMI8787HiFier",
-       .id_table = hifier_ids,
-       .probe = hifier_probe,
-       .remove = __devexit_p(oxygen_pci_remove),
-#ifdef CONFIG_PM
-       .suspend = oxygen_pci_suspend,
-       .resume = oxygen_pci_resume,
-#endif
-};
-
-static int __init alsa_card_hifier_init(void)
-{
-       return pci_register_driver(&hifier_driver);
-}
-
-static void __exit alsa_card_hifier_exit(void)
-{
-       pci_unregister_driver(&hifier_driver);
-}
-
-module_init(alsa_card_hifier_init)
-module_exit(alsa_card_hifier_exit)
index 98a8eb3..d7e8ddd 100644 (file)
 /*
  * CMI8788:
  *
- * SPI 0 -> 1st AK4396 (front)
- * SPI 1 -> 2nd AK4396 (surround)
- * SPI 2 -> 3rd AK4396 (center/LFE)
- * SPI 3 -> WM8785
- * SPI 4 -> 4th AK4396 (back)
+ *   SPI 0 -> 1st AK4396 (front)
+ *   SPI 1 -> 2nd AK4396 (surround)
+ *   SPI 2 -> 3rd AK4396 (center/LFE)
+ *   SPI 3 -> WM8785
+ *   SPI 4 -> 4th AK4396 (back)
  *
- * GPIO 0 -> DFS0 of AK5385
- * GPIO 1 -> DFS1 of AK5385
- * GPIO 8 -> enable headphone amplifier on HT-Omega models
+ *   GPIO 0 -> DFS0 of AK5385
+ *   GPIO 1 -> DFS1 of AK5385
+ *
+ * X-Meridian models:
+ *   GPIO 4 -> enable extension S/PDIF input
+ *   GPIO 6 -> enable on-board S/PDIF input
+ *
+ * Claro models:
+ *   GPIO 6 -> S/PDIF from optical (0) or coaxial (1) input
+ *   GPIO 8 -> enable headphone amplifier
  *
  * CM9780:
  *
- * GPO 0 -> route line-in (0) or AC97 output (1) to ADC input
+ *   LINE_OUT -> input of ADC
+ *
+ *   AUX_IN <- aux
+ *   CD_IN  <- CD
+ *   MIC_IN <- mic
+ *
+ *   GPO 0 -> route line-in (0) or AC97 output (1) to ADC input
  */
 
 #include <linux/delay.h>
 #include <sound/ac97_codec.h>
 #include <sound/control.h>
 #include <sound/core.h>
+#include <sound/info.h>
 #include <sound/initval.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/tlv.h>
 #include "oxygen.h"
+#include "xonar_dg.h"
 #include "ak4396.h"
 #include "wm8785.h"
 
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_DESCRIPTION("C-Media CMI8788 driver");
 MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8788}}");
+MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8786}"
+                       ",{C-Media,CMI8787}"
+                       ",{C-Media,CMI8788}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
@@ -66,24 +83,46 @@ module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "enable card");
 
 enum {
-       MODEL_CMEDIA_REF,       /* C-Media's reference design */
-       MODEL_MERIDIAN,         /* AuzenTech X-Meridian */
-       MODEL_CLARO,            /* HT-Omega Claro */
-       MODEL_CLARO_HALO,       /* HT-Omega Claro halo */
+       MODEL_CMEDIA_REF,
+       MODEL_MERIDIAN,
+       MODEL_MERIDIAN_2G,
+       MODEL_CLARO,
+       MODEL_CLARO_HALO,
+       MODEL_FANTASIA,
+       MODEL_SERENADE,
+       MODEL_2CH_OUTPUT,
+       MODEL_HG2PCI,
+       MODEL_XONAR_DG,
 };
 
 static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = {
+       /* C-Media's reference design */
        { OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF },
+       { OXYGEN_PCI_SUBID(0x10b0, 0x0217), .driver_data = MODEL_CMEDIA_REF },
        { OXYGEN_PCI_SUBID(0x10b0, 0x0218), .driver_data = MODEL_CMEDIA_REF },
        { OXYGEN_PCI_SUBID(0x10b0, 0x0219), .driver_data = MODEL_CMEDIA_REF },
        { OXYGEN_PCI_SUBID(0x13f6, 0x0001), .driver_data = MODEL_CMEDIA_REF },
        { OXYGEN_PCI_SUBID(0x13f6, 0x0010), .driver_data = MODEL_CMEDIA_REF },
        { OXYGEN_PCI_SUBID(0x13f6, 0x8788), .driver_data = MODEL_CMEDIA_REF },
-       { OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_CMEDIA_REF },
        { OXYGEN_PCI_SUBID(0x147a, 0xa017), .driver_data = MODEL_CMEDIA_REF },
        { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
+       /* Asus Xonar DG */
+       { OXYGEN_PCI_SUBID(0x1043, 0x8467), .driver_data = MODEL_XONAR_DG },
+       /* PCI 2.0 HD Audio */
+       { OXYGEN_PCI_SUBID(0x13f6, 0x8782), .driver_data = MODEL_2CH_OUTPUT },
+       /* Kuroutoshikou CMI8787-HG2PCI */
+       { OXYGEN_PCI_SUBID(0x13f6, 0xffff), .driver_data = MODEL_HG2PCI },
+       /* TempoTec HiFier Fantasia */
+       { OXYGEN_PCI_SUBID(0x14c3, 0x1710), .driver_data = MODEL_FANTASIA },
+       /* TempoTec HiFier Serenade */
+       { OXYGEN_PCI_SUBID(0x14c3, 0x1711), .driver_data = MODEL_SERENADE },
+       /* AuzenTech X-Meridian */
        { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN },
+       /* AuzenTech X-Meridian 2G */
+       { OXYGEN_PCI_SUBID(0x5431, 0x017a), .driver_data = MODEL_MERIDIAN_2G },
+       /* HT-Omega Claro */
        { OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CLARO },
+       /* HT-Omega Claro halo */
        { OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_CLARO_HALO },
        { }
 };
@@ -95,9 +134,15 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids);
 #define GPIO_AK5385_DFS_DOUBLE 0x0001
 #define GPIO_AK5385_DFS_QUAD   0x0002
 
+#define GPIO_MERIDIAN_DIG_MASK 0x0050
+#define GPIO_MERIDIAN_DIG_EXT  0x0010
+#define GPIO_MERIDIAN_DIG_BOARD        0x0040
+
+#define GPIO_CLARO_DIG_COAX    0x0040
 #define GPIO_CLARO_HP          0x0100
 
 struct generic_data {
+       unsigned int dacs;
        u8 ak4396_regs[4][5];
        u16 wm8785_regs[3];
 };
@@ -148,7 +193,7 @@ static void ak4396_registers_init(struct oxygen *chip)
        struct generic_data *data = chip->model_data;
        unsigned int i;
 
-       for (i = 0; i < 4; ++i) {
+       for (i = 0; i < data->dacs; ++i) {
                ak4396_write(chip, i, AK4396_CONTROL_1,
                             AK4396_DIF_24_MSB | AK4396_RSTN);
                ak4396_write(chip, i, AK4396_CONTROL_2,
@@ -166,6 +211,7 @@ static void ak4396_init(struct oxygen *chip)
 {
        struct generic_data *data = chip->model_data;
 
+       data->dacs = chip->model.dac_channels_pcm / 2;
        data->ak4396_regs[0][AK4396_CONTROL_2] =
                AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL;
        ak4396_registers_init(chip);
@@ -207,6 +253,10 @@ static void generic_init(struct oxygen *chip)
 
 static void meridian_init(struct oxygen *chip)
 {
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+                         GPIO_MERIDIAN_DIG_MASK);
+       oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+                             GPIO_MERIDIAN_DIG_BOARD, GPIO_MERIDIAN_DIG_MASK);
        ak4396_init(chip);
        ak5385_init(chip);
 }
@@ -220,6 +270,8 @@ static void claro_enable_hp(struct oxygen *chip)
 
 static void claro_init(struct oxygen *chip)
 {
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_DIG_COAX);
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_DIG_COAX);
        ak4396_init(chip);
        wm8785_init(chip);
        claro_enable_hp(chip);
@@ -227,11 +279,24 @@ static void claro_init(struct oxygen *chip)
 
 static void claro_halo_init(struct oxygen *chip)
 {
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_DIG_COAX);
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_DIG_COAX);
        ak4396_init(chip);
        ak5385_init(chip);
        claro_enable_hp(chip);
 }
 
+static void fantasia_init(struct oxygen *chip)
+{
+       ak4396_init(chip);
+       snd_component_add(chip->card, "CS5340");
+}
+
+static void stereo_output_init(struct oxygen *chip)
+{
+       ak4396_init(chip);
+}
+
 static void generic_cleanup(struct oxygen *chip)
 {
 }
@@ -268,6 +333,11 @@ static void claro_resume(struct oxygen *chip)
        claro_enable_hp(chip);
 }
 
+static void stereo_resume(struct oxygen *chip)
+{
+       ak4396_registers_init(chip);
+}
+
 static void set_ak4396_params(struct oxygen *chip,
                              struct snd_pcm_hw_params *params)
 {
@@ -286,7 +356,7 @@ static void set_ak4396_params(struct oxygen *chip,
        msleep(1); /* wait for the new MCLK to become stable */
 
        if (value != data->ak4396_regs[0][AK4396_CONTROL_2]) {
-               for (i = 0; i < 4; ++i) {
+               for (i = 0; i < data->dacs; ++i) {
                        ak4396_write(chip, i, AK4396_CONTROL_1,
                                     AK4396_DIF_24_MSB);
                        ak4396_write(chip, i, AK4396_CONTROL_2, value);
@@ -298,9 +368,10 @@ static void set_ak4396_params(struct oxygen *chip,
 
 static void update_ak4396_volume(struct oxygen *chip)
 {
+       struct generic_data *data = chip->model_data;
        unsigned int i;
 
-       for (i = 0; i < 4; ++i) {
+       for (i = 0; i < data->dacs; ++i) {
                ak4396_write_cached(chip, i, AK4396_LCH_ATT,
                                    chip->dac_volume[i * 2]);
                ak4396_write_cached(chip, i, AK4396_RCH_ATT,
@@ -317,7 +388,7 @@ static void update_ak4396_mute(struct oxygen *chip)
        value = data->ak4396_regs[0][AK4396_CONTROL_2] & ~AK4396_SMUTE;
        if (chip->dac_mute)
                value |= AK4396_SMUTE;
-       for (i = 0; i < 4; ++i)
+       for (i = 0; i < data->dacs; ++i)
                ak4396_write_cached(chip, i, AK4396_CONTROL_2, value);
 }
 
@@ -356,6 +427,10 @@ static void set_ak5385_params(struct oxygen *chip,
                              value, GPIO_AK5385_DFS_MASK);
 }
 
+static void set_no_params(struct oxygen *chip, struct snd_pcm_hw_params *params)
+{
+}
+
 static int rolloff_info(struct snd_kcontrol *ctl,
                        struct snd_ctl_elem_info *info)
 {
@@ -363,13 +438,7 @@ static int rolloff_info(struct snd_kcontrol *ctl,
                "Sharp Roll-off", "Slow Roll-off"
        };
 
-       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       info->count = 1;
-       info->value.enumerated.items = 2;
-       if (info->value.enumerated.item >= 2)
-               info->value.enumerated.item = 1;
-       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
-       return 0;
+       return snd_ctl_enum_info(info, 1, 2, names);
 }
 
 static int rolloff_get(struct snd_kcontrol *ctl,
@@ -400,7 +469,7 @@ static int rolloff_put(struct snd_kcontrol *ctl,
                reg &= ~AK4396_SLOW;
        changed = reg != data->ak4396_regs[0][AK4396_CONTROL_2];
        if (changed) {
-               for (i = 0; i < 4; ++i)
+               for (i = 0; i < data->dacs; ++i)
                        ak4396_write(chip, i, AK4396_CONTROL_2, reg);
        }
        mutex_unlock(&chip->mutex);
@@ -421,13 +490,7 @@ static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
                "None", "High-pass Filter"
        };
 
-       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       info->count = 1;
-       info->value.enumerated.items = 2;
-       if (info->value.enumerated.item >= 2)
-               info->value.enumerated.item = 1;
-       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
-       return 0;
+       return snd_ctl_enum_info(info, 1, 2, names);
 }
 
 static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
@@ -466,6 +529,100 @@ static const struct snd_kcontrol_new hpf_control = {
        .put = hpf_put,
 };
 
+static int meridian_dig_source_info(struct snd_kcontrol *ctl,
+                                   struct snd_ctl_elem_info *info)
+{
+       static const char *const names[2] = { "On-board", "Extension" };
+
+       return snd_ctl_enum_info(info, 1, 2, names);
+}
+
+static int claro_dig_source_info(struct snd_kcontrol *ctl,
+                                struct snd_ctl_elem_info *info)
+{
+       static const char *const names[2] = { "Optical", "Coaxial" };
+
+       return snd_ctl_enum_info(info, 1, 2, names);
+}
+
+static int meridian_dig_source_get(struct snd_kcontrol *ctl,
+                                  struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+
+       value->value.enumerated.item[0] =
+               !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
+                  GPIO_MERIDIAN_DIG_EXT);
+       return 0;
+}
+
+static int claro_dig_source_get(struct snd_kcontrol *ctl,
+                               struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+
+       value->value.enumerated.item[0] =
+               !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
+                  GPIO_CLARO_DIG_COAX);
+       return 0;
+}
+
+static int meridian_dig_source_put(struct snd_kcontrol *ctl,
+                                  struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u16 old_reg, new_reg;
+       int changed;
+
+       mutex_lock(&chip->mutex);
+       old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+       new_reg = old_reg & ~GPIO_MERIDIAN_DIG_MASK;
+       if (value->value.enumerated.item[0] == 0)
+               new_reg |= GPIO_MERIDIAN_DIG_BOARD;
+       else
+               new_reg |= GPIO_MERIDIAN_DIG_EXT;
+       changed = new_reg != old_reg;
+       if (changed)
+               oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg);
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static int claro_dig_source_put(struct snd_kcontrol *ctl,
+                               struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u16 old_reg, new_reg;
+       int changed;
+
+       mutex_lock(&chip->mutex);
+       old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+       new_reg = old_reg & ~GPIO_CLARO_DIG_COAX;
+       if (value->value.enumerated.item[0])
+               new_reg |= GPIO_CLARO_DIG_COAX;
+       changed = new_reg != old_reg;
+       if (changed)
+               oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg);
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static const struct snd_kcontrol_new meridian_dig_source_control = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "IEC958 Source Capture Enum",
+       .info = meridian_dig_source_info,
+       .get = meridian_dig_source_get,
+       .put = meridian_dig_source_put,
+};
+
+static const struct snd_kcontrol_new claro_dig_source_control = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "IEC958 Source Capture Enum",
+       .info = claro_dig_source_info,
+       .get = claro_dig_source_get,
+       .put = claro_dig_source_put,
+};
+
 static int generic_mixer_init(struct oxygen *chip)
 {
        return snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip));
@@ -484,6 +641,81 @@ static int generic_wm8785_mixer_init(struct oxygen *chip)
        return 0;
 }
 
+static int meridian_mixer_init(struct oxygen *chip)
+{
+       int err;
+
+       err = generic_mixer_init(chip);
+       if (err < 0)
+               return err;
+       err = snd_ctl_add(chip->card,
+                         snd_ctl_new1(&meridian_dig_source_control, chip));
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+static int claro_mixer_init(struct oxygen *chip)
+{
+       int err;
+
+       err = generic_wm8785_mixer_init(chip);
+       if (err < 0)
+               return err;
+       err = snd_ctl_add(chip->card,
+                         snd_ctl_new1(&claro_dig_source_control, chip));
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+static int claro_halo_mixer_init(struct oxygen *chip)
+{
+       int err;
+
+       err = generic_mixer_init(chip);
+       if (err < 0)
+               return err;
+       err = snd_ctl_add(chip->card,
+                         snd_ctl_new1(&claro_dig_source_control, chip));
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+static void dump_ak4396_registers(struct oxygen *chip,
+                                 struct snd_info_buffer *buffer)
+{
+       struct generic_data *data = chip->model_data;
+       unsigned int dac, i;
+
+       for (dac = 0; dac < data->dacs; ++dac) {
+               snd_iprintf(buffer, "\nAK4396 %u:", dac + 1);
+               for (i = 0; i < 5; ++i)
+                       snd_iprintf(buffer, " %02x", data->ak4396_regs[dac][i]);
+       }
+       snd_iprintf(buffer, "\n");
+}
+
+static void dump_wm8785_registers(struct oxygen *chip,
+                                 struct snd_info_buffer *buffer)
+{
+       struct generic_data *data = chip->model_data;
+       unsigned int i;
+
+       snd_iprintf(buffer, "\nWM8785:");
+       for (i = 0; i < 3; ++i)
+               snd_iprintf(buffer, " %03x", data->wm8785_regs[i]);
+       snd_iprintf(buffer, "\n");
+}
+
+static void dump_oxygen_registers(struct oxygen *chip,
+                                 struct snd_info_buffer *buffer)
+{
+       dump_ak4396_registers(chip, buffer);
+       dump_wm8785_registers(chip, buffer);
+}
+
 static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
 
 static const struct oxygen_model model_generic = {
@@ -494,11 +726,11 @@ static const struct oxygen_model model_generic = {
        .mixer_init = generic_wm8785_mixer_init,
        .cleanup = generic_cleanup,
        .resume = generic_resume,
-       .get_i2s_mclk = oxygen_default_i2s_mclk,
        .set_dac_params = set_ak4396_params,
        .set_adc_params = set_wm8785_params,
        .update_dac_volume = update_ak4396_volume,
        .update_dac_mute = update_ak4396_mute,
+       .dump_registers = dump_oxygen_registers,
        .dac_tlv = ak4396_db_scale,
        .model_data_size = sizeof(struct generic_data),
        .device_config = PLAYBACK_0_TO_I2S |
@@ -508,11 +740,14 @@ static const struct oxygen_model model_generic = {
                         CAPTURE_1_FROM_SPDIF |
                         CAPTURE_2_FROM_AC97_1 |
                         AC97_CD_INPUT,
-       .dac_channels = 8,
+       .dac_channels_pcm = 8,
+       .dac_channels_mixer = 8,
        .dac_volume_min = 0,
        .dac_volume_max = 255,
        .function_flags = OXYGEN_FUNCTION_SPI |
                          OXYGEN_FUNCTION_ENABLE_SPI_4_5,
+       .dac_mclks = OXYGEN_MCLKS(256, 128, 128),
+       .adc_mclks = OXYGEN_MCLKS(256, 256, 128),
        .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
        .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
 };
@@ -520,42 +755,87 @@ static const struct oxygen_model model_generic = {
 static int __devinit get_oxygen_model(struct oxygen *chip,
                                      const struct pci_device_id *id)
 {
+       static const char *const names[] = {
+               [MODEL_MERIDIAN]        = "AuzenTech X-Meridian",
+               [MODEL_MERIDIAN_2G]     = "AuzenTech X-Meridian 2G",
+               [MODEL_CLARO]           = "HT-Omega Claro",
+               [MODEL_CLARO_HALO]      = "HT-Omega Claro halo",
+               [MODEL_FANTASIA]        = "TempoTec HiFier Fantasia",
+               [MODEL_SERENADE]        = "TempoTec HiFier Serenade",
+               [MODEL_HG2PCI]          = "CMI8787-HG2PCI",
+       };
+
        chip->model = model_generic;
        switch (id->driver_data) {
        case MODEL_MERIDIAN:
+       case MODEL_MERIDIAN_2G:
                chip->model.init = meridian_init;
-               chip->model.mixer_init = generic_mixer_init;
+               chip->model.mixer_init = meridian_mixer_init;
                chip->model.resume = meridian_resume;
                chip->model.set_adc_params = set_ak5385_params;
+               chip->model.dump_registers = dump_ak4396_registers;
                chip->model.device_config = PLAYBACK_0_TO_I2S |
                                            PLAYBACK_1_TO_SPDIF |
                                            CAPTURE_0_FROM_I2S_2 |
                                            CAPTURE_1_FROM_SPDIF;
+               if (id->driver_data == MODEL_MERIDIAN)
+                       chip->model.device_config |= AC97_CD_INPUT;
                break;
        case MODEL_CLARO:
                chip->model.init = claro_init;
+               chip->model.mixer_init = claro_mixer_init;
                chip->model.cleanup = claro_cleanup;
                chip->model.suspend = claro_suspend;
                chip->model.resume = claro_resume;
                break;
        case MODEL_CLARO_HALO:
                chip->model.init = claro_halo_init;
-               chip->model.mixer_init = generic_mixer_init;
+               chip->model.mixer_init = claro_halo_mixer_init;
                chip->model.cleanup = claro_cleanup;
                chip->model.suspend = claro_suspend;
                chip->model.resume = claro_resume;
                chip->model.set_adc_params = set_ak5385_params;
+               chip->model.dump_registers = dump_ak4396_registers;
                chip->model.device_config = PLAYBACK_0_TO_I2S |
                                            PLAYBACK_1_TO_SPDIF |
                                            CAPTURE_0_FROM_I2S_2 |
                                            CAPTURE_1_FROM_SPDIF;
                break;
+       case MODEL_FANTASIA:
+       case MODEL_SERENADE:
+       case MODEL_2CH_OUTPUT:
+       case MODEL_HG2PCI:
+               chip->model.shortname = "C-Media CMI8787";
+               chip->model.chip = "CMI8787";
+               if (id->driver_data == MODEL_FANTASIA)
+                       chip->model.init = fantasia_init;
+               else
+                       chip->model.init = stereo_output_init;
+               chip->model.resume = stereo_resume;
+               chip->model.mixer_init = generic_mixer_init;
+               chip->model.set_adc_params = set_no_params;
+               chip->model.dump_registers = dump_ak4396_registers;
+               chip->model.device_config = PLAYBACK_0_TO_I2S |
+                                           PLAYBACK_1_TO_SPDIF;
+               if (id->driver_data == MODEL_FANTASIA) {
+                       chip->model.device_config |= CAPTURE_0_FROM_I2S_1;
+                       chip->model.adc_mclks = OXYGEN_MCLKS(256, 128, 128);
+               }
+               chip->model.dac_channels_pcm = 2;
+               chip->model.dac_channels_mixer = 2;
+               break;
+       case MODEL_XONAR_DG:
+               chip->model = model_xonar_dg;
+               break;
        }
        if (id->driver_data == MODEL_MERIDIAN ||
+           id->driver_data == MODEL_MERIDIAN_2G ||
            id->driver_data == MODEL_CLARO_HALO) {
                chip->model.misc_flags = OXYGEN_MISC_MIDI;
                chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT;
        }
+       if (id->driver_data < ARRAY_SIZE(names) && names[id->driver_data])
+               chip->model.shortname = names[id->driver_data];
        return 0;
 }
 
index 7d5222c..c2ae63d 100644 (file)
 #define PCM_AC97       5
 #define PCM_COUNT      6
 
+#define OXYGEN_MCLKS(f_single, f_double, f_quad) ((MCLK_##f_single << 0) | \
+                                                 (MCLK_##f_double << 2) | \
+                                                 (MCLK_##f_quad   << 4))
+
 #define OXYGEN_IO_SIZE 0x100
 
 #define OXYGEN_EEPROM_ID       0x434d  /* "CM" */
@@ -35,6 +39,7 @@
 #define MIDI_OUTPUT            0x0800
 #define MIDI_INPUT             0x1000
 #define AC97_CD_INPUT          0x2000
+#define AC97_FMIC_SWITCH       0x4000
 
 enum {
        CONTROL_SPDIF_PCM,
@@ -65,6 +70,7 @@ struct snd_pcm_hardware;
 struct snd_pcm_hw_params;
 struct snd_kcontrol_new;
 struct snd_rawmidi;
+struct snd_info_buffer;
 struct oxygen;
 
 struct oxygen_model {
@@ -79,8 +85,6 @@ struct oxygen_model {
        void (*resume)(struct oxygen *chip);
        void (*pcm_hardware_filter)(unsigned int channel,
                                    struct snd_pcm_hardware *hardware);
-       unsigned int (*get_i2s_mclk)(struct oxygen *chip, unsigned int channel,
-                                    struct snd_pcm_hw_params *hw_params);
        void (*set_dac_params)(struct oxygen *chip,
                               struct snd_pcm_hw_params *params);
        void (*set_adc_params)(struct oxygen *chip,
@@ -92,15 +96,19 @@ struct oxygen_model {
        void (*uart_input)(struct oxygen *chip);
        void (*ac97_switch)(struct oxygen *chip,
                            unsigned int reg, unsigned int mute);
+       void (*dump_registers)(struct oxygen *chip,
+                              struct snd_info_buffer *buffer);
        const unsigned int *dac_tlv;
-       unsigned long private_data;
        size_t model_data_size;
        unsigned int device_config;
-       u8 dac_channels;
+       u8 dac_channels_pcm;
+       u8 dac_channels_mixer;
        u8 dac_volume_min;
        u8 dac_volume_max;
        u8 misc_flags;
        u8 function_flags;
+       u8 dac_mclks;
+       u8 adc_mclks;
        u16 dac_i2s_format;
        u16 adc_i2s_format;
 };
@@ -121,7 +129,6 @@ struct oxygen {
        u8 pcm_running;
        u8 dac_routing;
        u8 spdif_playback_enable;
-       u8 revision;
        u8 has_ac97_0;
        u8 has_ac97_1;
        u32 spdif_bits;
@@ -167,8 +174,6 @@ void oxygen_update_spdif_source(struct oxygen *chip);
 /* oxygen_pcm.c */
 
 int oxygen_pcm_init(struct oxygen *chip);
-unsigned int oxygen_default_i2s_mclk(struct oxygen *chip, unsigned int channel,
-                                    struct snd_pcm_hw_params *hw_params);
 
 /* oxygen_io.c */
 
index 09b2b2a..f5164b1 100644 (file)
@@ -197,11 +197,11 @@ void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data)
 {
        unsigned int count;
 
-       /* should not need more than 7.68 us (24 * 320 ns) */
+       /* should not need more than 30.72 us (24 * 1.28 us) */
        count = 10;
        while ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & OXYGEN_SPI_BUSY)
               && count > 0) {
-               udelay(1);
+               udelay(4);
                --count;
        }
 
index e5ebe56..70b7398 100644 (file)
@@ -202,7 +202,13 @@ static void oxygen_proc_read(struct snd_info_entry *entry,
        struct oxygen *chip = entry->private_data;
        int i, j;
 
-       snd_iprintf(buffer, "CMI8788\n\n");
+       switch (oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_PACKAGE_ID_MASK) {
+       case OXYGEN_PACKAGE_ID_8786: i = '6'; break;
+       case OXYGEN_PACKAGE_ID_8787: i = '7'; break;
+       case OXYGEN_PACKAGE_ID_8788: i = '8'; break;
+       default:                     i = '?'; break;
+       }
+       snd_iprintf(buffer, "CMI878%c:\n", i);
        for (i = 0; i < OXYGEN_IO_SIZE; i += 0x10) {
                snd_iprintf(buffer, "%02x:", i);
                for (j = 0; j < 0x10; ++j)
@@ -212,7 +218,7 @@ static void oxygen_proc_read(struct snd_info_entry *entry,
        if (mutex_lock_interruptible(&chip->mutex) < 0)
                return;
        if (chip->has_ac97_0) {
-               snd_iprintf(buffer, "\nAC97\n");
+               snd_iprintf(buffer, "\nAC97:\n");
                for (i = 0; i < 0x80; i += 0x10) {
                        snd_iprintf(buffer, "%02x:", i);
                        for (j = 0; j < 0x10; j += 2)
@@ -222,7 +228,7 @@ static void oxygen_proc_read(struct snd_info_entry *entry,
                }
        }
        if (chip->has_ac97_1) {
-               snd_iprintf(buffer, "\nAC97 2\n");
+               snd_iprintf(buffer, "\nAC97 2:\n");
                for (i = 0; i < 0x80; i += 0x10) {
                        snd_iprintf(buffer, "%02x:", i);
                        for (j = 0; j < 0x10; j += 2)
@@ -232,13 +238,15 @@ static void oxygen_proc_read(struct snd_info_entry *entry,
                }
        }
        mutex_unlock(&chip->mutex);
+       if (chip->model.dump_registers)
+               chip->model.dump_registers(chip, buffer);
 }
 
 static void oxygen_proc_init(struct oxygen *chip)
 {
        struct snd_info_entry *entry;
 
-       if (!snd_card_proc_new(chip->card, "cmi8788", &entry))
+       if (!snd_card_proc_new(chip->card, "oxygen", &entry))
                snd_info_set_text_ops(entry, chip, oxygen_proc_read);
 }
 #else
@@ -262,7 +270,7 @@ oxygen_search_pci_id(struct oxygen *chip, const struct pci_device_id ids[])
         */
        subdevice = oxygen_read_eeprom(chip, 2);
        /* use default ID if EEPROM is missing */
-       if (subdevice == 0xffff)
+       if (subdevice == 0xffff && oxygen_read_eeprom(chip, 1) == 0xffff)
                subdevice = 0x8788;
        /*
         * We use only the subsystem device ID for searching because it is
@@ -364,12 +372,7 @@ static void oxygen_init(struct oxygen *chip)
                (IEC958_AES1_CON_PCM_CODER << OXYGEN_SPDIF_CATEGORY_SHIFT);
        chip->spdif_pcm_bits = chip->spdif_bits;
 
-       if (oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_REVISION_2)
-               chip->revision = 2;
-       else
-               chip->revision = 1;
-
-       if (chip->revision == 1)
+       if (!(oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_REVISION_2))
                oxygen_set_bits8(chip, OXYGEN_MISC,
                                 OXYGEN_MISC_PCI_MEM_W_1_CLOCK);
 
@@ -406,28 +409,40 @@ static void oxygen_init(struct oxygen *chip)
                      (OXYGEN_FORMAT_16 << OXYGEN_MULTICH_FORMAT_SHIFT));
        oxygen_write8(chip, OXYGEN_REC_CHANNELS, OXYGEN_REC_CHANNELS_2_2_2);
        oxygen_write16(chip, OXYGEN_I2S_MULTICH_FORMAT,
-                      OXYGEN_RATE_48000 | chip->model.dac_i2s_format |
-                      OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
-                      OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
+                      OXYGEN_RATE_48000 |
+                      chip->model.dac_i2s_format |
+                      OXYGEN_I2S_MCLK(chip->model.dac_mclks) |
+                      OXYGEN_I2S_BITS_16 |
+                      OXYGEN_I2S_MASTER |
+                      OXYGEN_I2S_BCLK_64);
        if (chip->model.device_config & CAPTURE_0_FROM_I2S_1)
                oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
-                              OXYGEN_RATE_48000 | chip->model.adc_i2s_format |
-                              OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
-                              OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
+                              OXYGEN_RATE_48000 |
+                              chip->model.adc_i2s_format |
+                              OXYGEN_I2S_MCLK(chip->model.adc_mclks) |
+                              OXYGEN_I2S_BITS_16 |
+                              OXYGEN_I2S_MASTER |
+                              OXYGEN_I2S_BCLK_64);
        else
                oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
-                              OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK);
+                              OXYGEN_I2S_MASTER |
+                              OXYGEN_I2S_MUTE_MCLK);
        if (chip->model.device_config & (CAPTURE_0_FROM_I2S_2 |
                                         CAPTURE_2_FROM_I2S_2))
                oxygen_write16(chip, OXYGEN_I2S_B_FORMAT,
-                              OXYGEN_RATE_48000 | chip->model.adc_i2s_format |
-                              OXYGEN_I2S_MCLK_256 | OXYGEN_I2S_BITS_16 |
-                              OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
+                              OXYGEN_RATE_48000 |
+                              chip->model.adc_i2s_format |
+                              OXYGEN_I2S_MCLK(chip->model.adc_mclks) |
+                              OXYGEN_I2S_BITS_16 |
+                              OXYGEN_I2S_MASTER |
+                              OXYGEN_I2S_BCLK_64);
        else
                oxygen_write16(chip, OXYGEN_I2S_B_FORMAT,
-                              OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK);
+                              OXYGEN_I2S_MASTER |
+                              OXYGEN_I2S_MUTE_MCLK);
        oxygen_write16(chip, OXYGEN_I2S_C_FORMAT,
-                      OXYGEN_I2S_MASTER | OXYGEN_I2S_MUTE_MCLK);
+                      OXYGEN_I2S_MASTER |
+                      OXYGEN_I2S_MUTE_MCLK);
        oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL,
                            OXYGEN_SPDIF_OUT_ENABLE |
                            OXYGEN_SPDIF_LOOPBACK);
@@ -557,7 +572,8 @@ static void oxygen_card_free(struct snd_card *card)
        oxygen_shutdown(chip);
        if (chip->irq >= 0)
                free_irq(chip->irq, chip);
-       flush_scheduled_work();
+       flush_work_sync(&chip->spdif_input_bits_work);
+       flush_work_sync(&chip->gpio_work);
        chip->model.cleanup(chip);
        kfree(chip->model_data);
        mutex_destroy(&chip->mutex);
@@ -648,8 +664,8 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
 
        strcpy(card->driver, chip->model.chip);
        strcpy(card->shortname, chip->model.shortname);
-       sprintf(card->longname, "%s (rev %u) at %#lx, irq %i",
-               chip->model.longname, chip->revision, chip->addr, chip->irq);
+       sprintf(card->longname, "%s at %#lx, irq %i",
+               chip->model.longname, chip->addr, chip->irq);
        strcpy(card->mixername, chip->model.chip);
        snd_component_add(card, chip->model.chip);
 
@@ -733,7 +749,8 @@ int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state)
        spin_unlock_irq(&chip->reg_lock);
 
        synchronize_irq(chip->irq);
-       flush_scheduled_work();
+       flush_work_sync(&chip->spdif_input_bits_work);
+       flush_work_sync(&chip->gpio_work);
        chip->interrupt_mask = saved_interrupt_mask;
 
        pci_disable_device(pci);
index 2849b36..9bff14d 100644 (file)
@@ -31,7 +31,7 @@ static int dac_volume_info(struct snd_kcontrol *ctl,
        struct oxygen *chip = ctl->private_data;
 
        info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       info->count = chip->model.dac_channels;
+       info->count = chip->model.dac_channels_mixer;
        info->value.integer.min = chip->model.dac_volume_min;
        info->value.integer.max = chip->model.dac_volume_max;
        return 0;
@@ -44,7 +44,7 @@ static int dac_volume_get(struct snd_kcontrol *ctl,
        unsigned int i;
 
        mutex_lock(&chip->mutex);
-       for (i = 0; i < chip->model.dac_channels; ++i)
+       for (i = 0; i < chip->model.dac_channels_mixer; ++i)
                value->value.integer.value[i] = chip->dac_volume[i];
        mutex_unlock(&chip->mutex);
        return 0;
@@ -59,7 +59,7 @@ static int dac_volume_put(struct snd_kcontrol *ctl,
 
        changed = 0;
        mutex_lock(&chip->mutex);
-       for (i = 0; i < chip->model.dac_channels; ++i)
+       for (i = 0; i < chip->model.dac_channels_mixer; ++i)
                if (value->value.integer.value[i] != chip->dac_volume[i]) {
                        chip->dac_volume[i] = value->value.integer.value[i];
                        changed = 1;
@@ -97,6 +97,16 @@ static int dac_mute_put(struct snd_kcontrol *ctl,
        return changed;
 }
 
+static unsigned int upmix_item_count(struct oxygen *chip)
+{
+       if (chip->model.dac_channels_pcm < 8)
+               return 2;
+       else if (chip->model.update_center_lfe_mix)
+               return 5;
+       else
+               return 3;
+}
+
 static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
 {
        static const char *const names[5] = {
@@ -107,15 +117,9 @@ static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
                "Front+Surround+Center/LFE+Back",
        };
        struct oxygen *chip = ctl->private_data;
-       unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3;
+       unsigned int count = upmix_item_count(chip);
 
-       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       info->count = 1;
-       info->value.enumerated.items = count;
-       if (info->value.enumerated.item >= count)
-               info->value.enumerated.item = count - 1;
-       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
-       return 0;
+       return snd_ctl_enum_info(info, 1, count, names);
 }
 
 static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
@@ -188,7 +192,7 @@ void oxygen_update_dac_routing(struct oxygen *chip)
 static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
 {
        struct oxygen *chip = ctl->private_data;
-       unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3;
+       unsigned int count = upmix_item_count(chip);
        int changed;
 
        if (value->value.enumerated.item[0] >= count)
@@ -430,30 +434,31 @@ static int spdif_input_default_get(struct snd_kcontrol *ctl,
        return 0;
 }
 
-static int spdif_loopback_get(struct snd_kcontrol *ctl,
-                             struct snd_ctl_elem_value *value)
+static int spdif_bit_switch_get(struct snd_kcontrol *ctl,
+                               struct snd_ctl_elem_value *value)
 {
        struct oxygen *chip = ctl->private_data;
+       u32 bit = ctl->private_value;
 
        value->value.integer.value[0] =
-               !!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL)
-                  & OXYGEN_SPDIF_LOOPBACK);
+               !!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL) & bit);
        return 0;
 }
 
-static int spdif_loopback_put(struct snd_kcontrol *ctl,
-                             struct snd_ctl_elem_value *value)
+static int spdif_bit_switch_put(struct snd_kcontrol *ctl,
+                               struct snd_ctl_elem_value *value)
 {
        struct oxygen *chip = ctl->private_data;
+       u32 bit = ctl->private_value;
        u32 oldreg, newreg;
        int changed;
 
        spin_lock_irq(&chip->reg_lock);
        oldreg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
        if (value->value.integer.value[0])
-               newreg = oldreg | OXYGEN_SPDIF_LOOPBACK;
+               newreg = oldreg | bit;
        else
-               newreg = oldreg & ~OXYGEN_SPDIF_LOOPBACK;
+               newreg = oldreg & ~bit;
        changed = newreg != oldreg;
        if (changed)
                oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, newreg);
@@ -644,6 +649,46 @@ static int ac97_volume_put(struct snd_kcontrol *ctl,
        return change;
 }
 
+static int mic_fmic_source_info(struct snd_kcontrol *ctl,
+                          struct snd_ctl_elem_info *info)
+{
+       static const char *const names[] = { "Mic Jack", "Front Panel" };
+
+       return snd_ctl_enum_info(info, 1, 2, names);
+}
+
+static int mic_fmic_source_get(struct snd_kcontrol *ctl,
+                              struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+
+       mutex_lock(&chip->mutex);
+       value->value.enumerated.item[0] =
+               !!(oxygen_read_ac97(chip, 0, CM9780_JACK) & CM9780_FMIC2MIC);
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static int mic_fmic_source_put(struct snd_kcontrol *ctl,
+                              struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u16 oldreg, newreg;
+       int change;
+
+       mutex_lock(&chip->mutex);
+       oldreg = oxygen_read_ac97(chip, 0, CM9780_JACK);
+       if (value->value.enumerated.item[0])
+               newreg = oldreg | CM9780_FMIC2MIC;
+       else
+               newreg = oldreg & ~CM9780_FMIC2MIC;
+       change = newreg != oldreg;
+       if (change)
+               oxygen_write_ac97(chip, 0, CM9780_JACK, newreg);
+       mutex_unlock(&chip->mutex);
+       return change;
+}
+
 static int ac97_fp_rec_volume_info(struct snd_kcontrol *ctl,
                                   struct snd_ctl_elem_info *info)
 {
@@ -791,8 +836,17 @@ static const struct snd_kcontrol_new spdif_input_controls[] = {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = SNDRV_CTL_NAME_IEC958("Loopback ", NONE, SWITCH),
                .info = snd_ctl_boolean_mono_info,
-               .get = spdif_loopback_get,
-               .put = spdif_loopback_put,
+               .get = spdif_bit_switch_get,
+               .put = spdif_bit_switch_put,
+               .private_value = OXYGEN_SPDIF_LOOPBACK,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = SNDRV_CTL_NAME_IEC958("Validity Check ",CAPTURE,SWITCH),
+               .info = snd_ctl_boolean_mono_info,
+               .get = spdif_bit_switch_get,
+               .put = spdif_bit_switch_put,
+               .private_value = OXYGEN_SPDIF_SPDVALID,
        },
 };
 
@@ -908,6 +962,13 @@ static const struct snd_kcontrol_new ac97_controls[] = {
        AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC, 0),
        AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1),
        AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Mic Source Capture Enum",
+               .info = mic_fmic_source_info,
+               .get = mic_fmic_source_get,
+               .put = mic_fmic_source_put,
+       },
        AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1),
        AC97_VOLUME("CD Capture Volume", 0, AC97_CD, 1),
        AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1),
@@ -970,7 +1031,10 @@ static int add_controls(struct oxygen *chip,
                                continue;
                }
                if (!strcmp(template.name, "Stereo Upmixing") &&
-                   chip->model.dac_channels == 2)
+                   chip->model.dac_channels_pcm == 2)
+                       continue;
+               if (!strcmp(template.name, "Mic Source Capture Enum") &&
+                   !(chip->model.device_config & AC97_FMIC_SWITCH))
                        continue;
                if (!strncmp(template.name, "CD Capture ", 11) &&
                    !(chip->model.device_config & AC97_CD_INPUT))
index 8146674..d5533e3 100644 (file)
@@ -39,7 +39,8 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = {
                SNDRV_PCM_INFO_MMAP_VALID |
                SNDRV_PCM_INFO_INTERLEAVED |
                SNDRV_PCM_INFO_PAUSE |
-               SNDRV_PCM_INFO_SYNC_START,
+               SNDRV_PCM_INFO_SYNC_START |
+               SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
        .formats = SNDRV_PCM_FMTBIT_S16_LE |
                   SNDRV_PCM_FMTBIT_S32_LE,
        .rates = SNDRV_PCM_RATE_32000 |
@@ -65,7 +66,8 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
                SNDRV_PCM_INFO_MMAP_VALID |
                SNDRV_PCM_INFO_INTERLEAVED |
                SNDRV_PCM_INFO_PAUSE |
-               SNDRV_PCM_INFO_SYNC_START,
+               SNDRV_PCM_INFO_SYNC_START |
+               SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
        .formats = SNDRV_PCM_FMTBIT_S16_LE |
                   SNDRV_PCM_FMTBIT_S32_LE,
        .rates = SNDRV_PCM_RATE_32000 |
@@ -91,7 +93,8 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = {
                SNDRV_PCM_INFO_MMAP_VALID |
                SNDRV_PCM_INFO_INTERLEAVED |
                SNDRV_PCM_INFO_PAUSE |
-               SNDRV_PCM_INFO_SYNC_START,
+               SNDRV_PCM_INFO_SYNC_START |
+               SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
        .formats = SNDRV_PCM_FMTBIT_S16_LE,
        .rates = SNDRV_PCM_RATE_48000,
        .rate_min = 48000,
@@ -140,7 +143,7 @@ static int oxygen_open(struct snd_pcm_substream *substream,
                runtime->hw.rate_min = 44100;
                break;
        case PCM_MULTICH:
-               runtime->hw.channels_max = chip->model.dac_channels;
+               runtime->hw.channels_max = chip->model.dac_channels_pcm;
                break;
        }
        if (chip->model.pcm_hardware_filter)
@@ -271,17 +274,6 @@ static unsigned int oxygen_rate(struct snd_pcm_hw_params *hw_params)
        }
 }
 
-unsigned int oxygen_default_i2s_mclk(struct oxygen *chip,
-                                    unsigned int channel,
-                                    struct snd_pcm_hw_params *hw_params)
-{
-       if (params_rate(hw_params) <= 96000)
-               return OXYGEN_I2S_MCLK_256;
-       else
-               return OXYGEN_I2S_MCLK_128;
-}
-EXPORT_SYMBOL(oxygen_default_i2s_mclk);
-
 static unsigned int oxygen_i2s_bits(struct snd_pcm_hw_params *hw_params)
 {
        if (params_format(hw_params) == SNDRV_PCM_FORMAT_S32_LE)
@@ -341,6 +333,26 @@ static int oxygen_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
+static u16 get_mclk(struct oxygen *chip, unsigned int channel,
+                   struct snd_pcm_hw_params *params)
+{
+       unsigned int mclks, shift;
+
+       if (channel == PCM_MULTICH)
+               mclks = chip->model.dac_mclks;
+       else
+               mclks = chip->model.adc_mclks;
+
+       if (params_rate(params) <= 48000)
+               shift = 0;
+       else if (params_rate(params) <= 96000)
+               shift = 2;
+       else
+               shift = 4;
+
+       return OXYGEN_I2S_MCLK(mclks >> shift);
+}
+
 static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream,
                                  struct snd_pcm_hw_params *hw_params)
 {
@@ -357,8 +369,8 @@ static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream,
                             OXYGEN_REC_FORMAT_A_MASK);
        oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT,
                              oxygen_rate(hw_params) |
-                             chip->model.get_i2s_mclk(chip, PCM_A, hw_params) |
                              chip->model.adc_i2s_format |
+                             get_mclk(chip, PCM_A, hw_params) |
                              oxygen_i2s_bits(hw_params),
                              OXYGEN_I2S_RATE_MASK |
                              OXYGEN_I2S_FORMAT_MASK |
@@ -393,9 +405,8 @@ static int oxygen_rec_b_hw_params(struct snd_pcm_substream *substream,
        if (!is_ac97)
                oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT,
                                      oxygen_rate(hw_params) |
-                                     chip->model.get_i2s_mclk(chip, PCM_B,
-                                                              hw_params) |
                                      chip->model.adc_i2s_format |
+                                     get_mclk(chip, PCM_B, hw_params) |
                                      oxygen_i2s_bits(hw_params),
                                      OXYGEN_I2S_RATE_MASK |
                                      OXYGEN_I2S_FORMAT_MASK |
@@ -476,8 +487,7 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream,
        oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT,
                              oxygen_rate(hw_params) |
                              chip->model.dac_i2s_format |
-                             chip->model.get_i2s_mclk(chip, PCM_MULTICH,
-                                                      hw_params) |
+                             get_mclk(chip, PCM_MULTICH, hw_params) |
                              oxygen_i2s_bits(hw_params),
                              OXYGEN_I2S_RATE_MASK |
                              OXYGEN_I2S_FORMAT_MASK |
@@ -530,7 +540,10 @@ static int oxygen_prepare(struct snd_pcm_substream *substream)
        oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask);
        oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask);
 
-       chip->interrupt_mask |= channel_mask;
+       if (substream->runtime->no_period_wakeup)
+               chip->interrupt_mask &= ~channel_mask;
+       else
+               chip->interrupt_mask |= channel_mask;
        oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask);
        spin_unlock_irq(&chip->reg_lock);
        return 0;
index 4dcd41b..63dc7a0 100644 (file)
 #define  OXYGEN_I2S_FORMAT_I2S         0x0000
 #define  OXYGEN_I2S_FORMAT_LJUST       0x0008
 #define  OXYGEN_I2S_MCLK_MASK          0x0030  /* MCLK/LRCK */
-#define  OXYGEN_I2S_MCLK_128           0x0000
-#define  OXYGEN_I2S_MCLK_256           0x0010
-#define  OXYGEN_I2S_MCLK_512           0x0020
+#define  OXYGEN_I2S_MCLK_SHIFT         4
+#define  MCLK_128                      0
+#define  MCLK_256                      1
+#define  MCLK_512                      2
+#define  OXYGEN_I2S_MCLK(f)            (((f) & 3) << OXYGEN_I2S_MCLK_SHIFT)
 #define  OXYGEN_I2S_BITS_MASK          0x00c0
 #define  OXYGEN_I2S_BITS_16            0x0000
 #define  OXYGEN_I2S_BITS_20            0x0040
 #define  OXYGEN_SPI_DATA_LENGTH_MASK   0x02
 #define  OXYGEN_SPI_DATA_LENGTH_2      0x00
 #define  OXYGEN_SPI_DATA_LENGTH_3      0x02
-#define  OXYGEN_SPI_CLOCK_MASK         0xc0
+#define  OXYGEN_SPI_CLOCK_MASK         0x0c
 #define  OXYGEN_SPI_CLOCK_160          0x00    /* ns */
-#define  OXYGEN_SPI_CLOCK_320          0x40
-#define  OXYGEN_SPI_CLOCK_640          0x80
-#define  OXYGEN_SPI_CLOCK_1280         0xc0
+#define  OXYGEN_SPI_CLOCK_320          0x04
+#define  OXYGEN_SPI_CLOCK_640          0x08
+#define  OXYGEN_SPI_CLOCK_1280         0x0c
 #define  OXYGEN_SPI_CODEC_MASK         0x70    /* 0..5 */
 #define  OXYGEN_SPI_CODEC_SHIFT                4
 #define  OXYGEN_SPI_CEN_MASK           0x80
index b35343b..0434c20 100644 (file)
@@ -24,6 +24,8 @@ void xonar_init_ext_power(struct oxygen *chip);
 void xonar_init_cs53x1(struct oxygen *chip);
 void xonar_set_cs53x1_params(struct oxygen *chip,
                             struct snd_pcm_hw_params *params);
+
+#define XONAR_GPIO_BIT_INVERT  (1 << 16)
 int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl,
                              struct snd_ctl_elem_value *value);
 int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl,
index aa27c31..9f72d42 100644 (file)
  *
  * CMI8788:
  *
- * I²C <-> CS4398 (front)
- *     <-> CS4362A (surround, center/LFE, back)
+ *   I²C <-> CS4398 (addr 1001111) (front)
+ *       <-> CS4362A (addr 0011000) (surround, center/LFE, back)
  *
- * GPI 0 <- external power present (DX only)
+ *   GPI 0 <- external power present (DX only)
  *
- * GPIO 0 -> enable output to speakers
- * GPIO 1 -> enable front panel I/O
- * GPIO 2 -> M0 of CS5361
- * GPIO 3 -> M1 of CS5361
- * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
+ *   GPIO 0 -> enable output to speakers
+ *   GPIO 1 -> route output to front panel
+ *   GPIO 2 -> M0 of CS5361
+ *   GPIO 3 -> M1 of CS5361
+ *   GPIO 6 -> ?
+ *   GPIO 7 -> ?
+ *   GPIO 8 -> route input jack to line-in (0) or mic-in (1)
  *
- * CS4398:
- *
- * AD0 <- 1
- * AD1 <- 1
+ * CM9780:
  *
- * CS4362A:
+ *   LINE_OUT -> input of ADC
  *
- * AD0 <- 0
+ *   AUX_IN  <- aux
+ *   MIC_IN  <- mic
+ *   FMIC_IN <- front mic
  *
- * CM9780:
- *
- * GPO 0 -> route line-in (0) or AC97 output (1) to CS5361 input
+ *   GPO 0 -> route line-in (0) or AC97 output (1) to CS5361 input
  */
 
 #include <linux/pci.h>
@@ -63,6 +62,7 @@
 #define GPI_EXT_POWER          0x01
 #define GPIO_D1_OUTPUT_ENABLE  0x0001
 #define GPIO_D1_FRONT_PANEL    0x0002
+#define GPIO_D1_MAGIC          0x00c0
 #define GPIO_D1_INPUT_ROUTE    0x0100
 
 #define I2C_DEVICE_CS4398      0x9e    /* 10011, AD1=1, AD0=1, /W=0 */
@@ -169,12 +169,12 @@ static void xonar_d1_init(struct oxygen *chip)
        cs43xx_registers_init(chip);
 
        oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
-                         GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE);
+                         GPIO_D1_FRONT_PANEL |
+                         GPIO_D1_MAGIC |
+                         GPIO_D1_INPUT_ROUTE);
        oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
                            GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE);
 
-       oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC);
-
        xonar_init_cs53x1(chip);
        xonar_enable_output(chip);
 
@@ -284,7 +284,7 @@ static void update_cs43xx_center_lfe_mix(struct oxygen *chip, bool mixed)
 
 static const struct snd_kcontrol_new front_panel_switch = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Front Panel Switch",
+       .name = "Front Panel Playback Switch",
        .info = snd_ctl_boolean_mono_info,
        .get = xonar_gpio_bit_switch_get,
        .put = xonar_gpio_bit_switch_put,
@@ -298,13 +298,7 @@ static int rolloff_info(struct snd_kcontrol *ctl,
                "Fast Roll-off", "Slow Roll-off"
        };
 
-       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       info->count = 1;
-       info->value.enumerated.items = 2;
-       if (info->value.enumerated.item >= 2)
-               info->value.enumerated.item = 1;
-       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
-       return 0;
+       return snd_ctl_enum_info(info, 1, 2, names);
 }
 
 static int rolloff_get(struct snd_kcontrol *ctl,
@@ -380,6 +374,30 @@ static int xonar_d1_mixer_init(struct oxygen *chip)
        return 0;
 }
 
+static void dump_cs4362a_registers(struct xonar_cs43xx *data,
+                                  struct snd_info_buffer *buffer)
+{
+       unsigned int i;
+
+       snd_iprintf(buffer, "\nCS4362A:");
+       for (i = 1; i <= 14; ++i)
+               snd_iprintf(buffer, " %02x", data->cs4362a_regs[i]);
+       snd_iprintf(buffer, "\n");
+}
+
+static void dump_d1_registers(struct oxygen *chip,
+                             struct snd_info_buffer *buffer)
+{
+       struct xonar_cs43xx *data = chip->model_data;
+       unsigned int i;
+
+       snd_iprintf(buffer, "\nCS4398: 7?");
+       for (i = 2; i <= 8; ++i)
+               snd_iprintf(buffer, " %02x", data->cs4398_regs[i]);
+       snd_iprintf(buffer, "\n");
+       dump_cs4362a_registers(data, buffer);
+}
+
 static const struct oxygen_model model_xonar_d1 = {
        .longname = "Asus Virtuoso 100",
        .chip = "AV200",
@@ -388,22 +406,26 @@ static const struct oxygen_model model_xonar_d1 = {
        .cleanup = xonar_d1_cleanup,
        .suspend = xonar_d1_suspend,
        .resume = xonar_d1_resume,
-       .get_i2s_mclk = oxygen_default_i2s_mclk,
        .set_dac_params = set_cs43xx_params,
        .set_adc_params = xonar_set_cs53x1_params,
        .update_dac_volume = update_cs43xx_volume,
        .update_dac_mute = update_cs43xx_mute,
        .update_center_lfe_mix = update_cs43xx_center_lfe_mix,
        .ac97_switch = xonar_d1_line_mic_ac97_switch,
+       .dump_registers = dump_d1_registers,
        .dac_tlv = cs4362a_db_scale,
        .model_data_size = sizeof(struct xonar_cs43xx),
        .device_config = PLAYBACK_0_TO_I2S |
                         PLAYBACK_1_TO_SPDIF |
-                        CAPTURE_0_FROM_I2S_2,
-       .dac_channels = 8,
+                        CAPTURE_0_FROM_I2S_2 |
+                        AC97_FMIC_SWITCH,
+       .dac_channels_pcm = 8,
+       .dac_channels_mixer = 8,
        .dac_volume_min = 127 - 60,
        .dac_volume_max = 127,
        .function_flags = OXYGEN_FUNCTION_2WIRE,
+       .dac_mclks = OXYGEN_MCLKS(256, 128, 128),
+       .adc_mclks = OXYGEN_MCLKS(256, 128, 128),
        .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
        .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
 };
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c
new file mode 100644 (file)
index 0000000..e4de0b8
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+ * card driver for the Xonar DG
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License, version 2.
+ *
+ *  This driver 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 driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Xonar DG
+ * --------
+ *
+ * CMI8788:
+ *
+ *   SPI 0 -> CS4245
+ *
+ *   GPIO 3 <- ?
+ *   GPIO 4 <- headphone detect
+ *   GPIO 5 -> route input jack to line-in (0) or mic-in (1)
+ *   GPIO 6 -> route input jack to line-in (0) or mic-in (1)
+ *   GPIO 7 -> enable rear headphone amp
+ *   GPIO 8 -> enable output to speakers
+ *
+ * CS4245:
+ *
+ *   input 1 <- aux
+ *   input 2 <- front mic
+ *   input 4 <- line/mic
+ *   aux out -> front panel headphones
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+#include "oxygen.h"
+#include "xonar_dg.h"
+#include "cs4245.h"
+
+#define GPIO_MAGIC             0x0008
+#define GPIO_HP_DETECT         0x0010
+#define GPIO_INPUT_ROUTE       0x0060
+#define GPIO_HP_REAR           0x0080
+#define GPIO_OUTPUT_ENABLE     0x0100
+
+struct dg {
+       unsigned int output_sel;
+       s8 input_vol[4][2];
+       unsigned int input_sel;
+       u8 hp_vol_att;
+       u8 cs4245_regs[0x11];
+};
+
+static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value)
+{
+       struct dg *data = chip->model_data;
+
+       oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
+                        OXYGEN_SPI_DATA_LENGTH_3 |
+                        OXYGEN_SPI_CLOCK_1280 |
+                        (0 << OXYGEN_SPI_CODEC_SHIFT) |
+                        OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
+                        CS4245_SPI_ADDRESS |
+                        CS4245_SPI_WRITE |
+                        (value << 8) | reg);
+       data->cs4245_regs[reg] = value;
+}
+
+static void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value)
+{
+       struct dg *data = chip->model_data;
+
+       if (value != data->cs4245_regs[reg])
+               cs4245_write(chip, reg, value);
+}
+
+static void cs4245_registers_init(struct oxygen *chip)
+{
+       struct dg *data = chip->model_data;
+
+       cs4245_write(chip, CS4245_POWER_CTRL, CS4245_PDN);
+       cs4245_write(chip, CS4245_DAC_CTRL_1,
+                    data->cs4245_regs[CS4245_DAC_CTRL_1]);
+       cs4245_write(chip, CS4245_ADC_CTRL,
+                    data->cs4245_regs[CS4245_ADC_CTRL]);
+       cs4245_write(chip, CS4245_SIGNAL_SEL,
+                    data->cs4245_regs[CS4245_SIGNAL_SEL]);
+       cs4245_write(chip, CS4245_PGA_B_CTRL,
+                    data->cs4245_regs[CS4245_PGA_B_CTRL]);
+       cs4245_write(chip, CS4245_PGA_A_CTRL,
+                    data->cs4245_regs[CS4245_PGA_A_CTRL]);
+       cs4245_write(chip, CS4245_ANALOG_IN,
+                    data->cs4245_regs[CS4245_ANALOG_IN]);
+       cs4245_write(chip, CS4245_DAC_A_CTRL,
+                    data->cs4245_regs[CS4245_DAC_A_CTRL]);
+       cs4245_write(chip, CS4245_DAC_B_CTRL,
+                    data->cs4245_regs[CS4245_DAC_B_CTRL]);
+       cs4245_write(chip, CS4245_DAC_CTRL_2,
+                    CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC);
+       cs4245_write(chip, CS4245_INT_MASK, 0);
+       cs4245_write(chip, CS4245_POWER_CTRL, 0);
+}
+
+static void cs4245_init(struct oxygen *chip)
+{
+       struct dg *data = chip->model_data;
+
+       data->cs4245_regs[CS4245_DAC_CTRL_1] =
+               CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST;
+       data->cs4245_regs[CS4245_ADC_CTRL] =
+               CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST;
+       data->cs4245_regs[CS4245_SIGNAL_SEL] =
+               CS4245_A_OUT_SEL_HIZ | CS4245_ASYNCH;
+       data->cs4245_regs[CS4245_PGA_B_CTRL] = 0;
+       data->cs4245_regs[CS4245_PGA_A_CTRL] = 0;
+       data->cs4245_regs[CS4245_ANALOG_IN] =
+               CS4245_PGA_SOFT | CS4245_PGA_ZERO | CS4245_SEL_INPUT_4;
+       data->cs4245_regs[CS4245_DAC_A_CTRL] = 0;
+       data->cs4245_regs[CS4245_DAC_B_CTRL] = 0;
+       cs4245_registers_init(chip);
+       snd_component_add(chip->card, "CS4245");
+}
+
+static void dg_output_enable(struct oxygen *chip)
+{
+       msleep(2500);
+       oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
+}
+
+static void dg_init(struct oxygen *chip)
+{
+       struct dg *data = chip->model_data;
+
+       data->output_sel = 0;
+       data->input_sel = 3;
+       data->hp_vol_att = 2 * 16;
+
+       cs4245_init(chip);
+
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
+                           GPIO_MAGIC | GPIO_HP_DETECT);
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+                         GPIO_INPUT_ROUTE | GPIO_HP_REAR | GPIO_OUTPUT_ENABLE);
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
+                           GPIO_INPUT_ROUTE | GPIO_HP_REAR);
+       dg_output_enable(chip);
+}
+
+static void dg_cleanup(struct oxygen *chip)
+{
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
+}
+
+static void dg_suspend(struct oxygen *chip)
+{
+       dg_cleanup(chip);
+}
+
+static void dg_resume(struct oxygen *chip)
+{
+       cs4245_registers_init(chip);
+       dg_output_enable(chip);
+}
+
+static void set_cs4245_dac_params(struct oxygen *chip,
+                                 struct snd_pcm_hw_params *params)
+{
+       struct dg *data = chip->model_data;
+       u8 value;
+
+       value = data->cs4245_regs[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK;
+       if (params_rate(params) <= 50000)
+               value |= CS4245_DAC_FM_SINGLE;
+       else if (params_rate(params) <= 100000)
+               value |= CS4245_DAC_FM_DOUBLE;
+       else
+               value |= CS4245_DAC_FM_QUAD;
+       cs4245_write_cached(chip, CS4245_DAC_CTRL_1, value);
+}
+
+static void set_cs4245_adc_params(struct oxygen *chip,
+                                 struct snd_pcm_hw_params *params)
+{
+       struct dg *data = chip->model_data;
+       u8 value;
+
+       value = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK;
+       if (params_rate(params) <= 50000)
+               value |= CS4245_ADC_FM_SINGLE;
+       else if (params_rate(params) <= 100000)
+               value |= CS4245_ADC_FM_DOUBLE;
+       else
+               value |= CS4245_ADC_FM_QUAD;
+       cs4245_write_cached(chip, CS4245_ADC_CTRL, value);
+}
+
+static int output_switch_info(struct snd_kcontrol *ctl,
+                             struct snd_ctl_elem_info *info)
+{
+       static const char *const names[3] = {
+               "Speakers", "Headphones", "FP Headphones"
+       };
+
+       return snd_ctl_enum_info(info, 1, 3, names);
+}
+
+static int output_switch_get(struct snd_kcontrol *ctl,
+                            struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+
+       mutex_lock(&chip->mutex);
+       value->value.enumerated.item[0] = data->output_sel;
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static int output_switch_put(struct snd_kcontrol *ctl,
+                            struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+       u8 reg;
+       int changed;
+
+       if (value->value.enumerated.item[0] > 2)
+               return -EINVAL;
+
+       mutex_lock(&chip->mutex);
+       changed = value->value.enumerated.item[0] != data->output_sel;
+       if (changed) {
+               data->output_sel = value->value.enumerated.item[0];
+
+               reg = data->cs4245_regs[CS4245_SIGNAL_SEL] &
+                                               ~CS4245_A_OUT_SEL_MASK;
+               reg |= data->output_sel == 2 ?
+                               CS4245_A_OUT_SEL_DAC : CS4245_A_OUT_SEL_HIZ;
+               cs4245_write_cached(chip, CS4245_SIGNAL_SEL, reg);
+
+               cs4245_write_cached(chip, CS4245_DAC_A_CTRL,
+                                   data->output_sel ? data->hp_vol_att : 0);
+               cs4245_write_cached(chip, CS4245_DAC_B_CTRL,
+                                   data->output_sel ? data->hp_vol_att : 0);
+
+               oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+                                     data->output_sel == 1 ? GPIO_HP_REAR : 0,
+                                     GPIO_HP_REAR);
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static int hp_volume_offset_info(struct snd_kcontrol *ctl,
+                                struct snd_ctl_elem_info *info)
+{
+       static const char *const names[3] = {
+               "< 64 ohms", "64-150 ohms", "150-300 ohms"
+       };
+
+       return snd_ctl_enum_info(info, 1, 3, names);
+}
+
+static int hp_volume_offset_get(struct snd_kcontrol *ctl,
+                               struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+
+       mutex_lock(&chip->mutex);
+       if (data->hp_vol_att > 2 * 7)
+               value->value.enumerated.item[0] = 0;
+       else if (data->hp_vol_att > 0)
+               value->value.enumerated.item[0] = 1;
+       else
+               value->value.enumerated.item[0] = 2;
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static int hp_volume_offset_put(struct snd_kcontrol *ctl,
+                               struct snd_ctl_elem_value *value)
+{
+       static const s8 atts[3] = { 2 * 16, 2 * 7, 0 };
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+       s8 att;
+       int changed;
+
+       if (value->value.enumerated.item[0] > 2)
+               return -EINVAL;
+       att = atts[value->value.enumerated.item[0]];
+       mutex_lock(&chip->mutex);
+       changed = att != data->hp_vol_att;
+       if (changed) {
+               data->hp_vol_att = att;
+               if (data->output_sel) {
+                       cs4245_write_cached(chip, CS4245_DAC_A_CTRL, att);
+                       cs4245_write_cached(chip, CS4245_DAC_B_CTRL, att);
+               }
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static int input_vol_info(struct snd_kcontrol *ctl,
+                         struct snd_ctl_elem_info *info)
+{
+       info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       info->count = 2;
+       info->value.integer.min = 2 * -12;
+       info->value.integer.max = 2 * 12;
+       return 0;
+}
+
+static int input_vol_get(struct snd_kcontrol *ctl,
+                        struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+       unsigned int idx = ctl->private_value;
+
+       mutex_lock(&chip->mutex);
+       value->value.integer.value[0] = data->input_vol[idx][0];
+       value->value.integer.value[1] = data->input_vol[idx][1];
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static int input_vol_put(struct snd_kcontrol *ctl,
+                        struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+       unsigned int idx = ctl->private_value;
+       int changed = 0;
+
+       if (value->value.integer.value[0] < 2 * -12 ||
+           value->value.integer.value[0] > 2 * 12 ||
+           value->value.integer.value[1] < 2 * -12 ||
+           value->value.integer.value[1] > 2 * 12)
+               return -EINVAL;
+       mutex_lock(&chip->mutex);
+       changed = data->input_vol[idx][0] != value->value.integer.value[0] ||
+                 data->input_vol[idx][1] != value->value.integer.value[1];
+       if (changed) {
+               data->input_vol[idx][0] = value->value.integer.value[0];
+               data->input_vol[idx][1] = value->value.integer.value[1];
+               if (idx == data->input_sel) {
+                       cs4245_write_cached(chip, CS4245_PGA_A_CTRL,
+                                           data->input_vol[idx][0]);
+                       cs4245_write_cached(chip, CS4245_PGA_B_CTRL,
+                                           data->input_vol[idx][1]);
+               }
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale, -1200, 50, 0);
+
+static int input_sel_info(struct snd_kcontrol *ctl,
+                         struct snd_ctl_elem_info *info)
+{
+       static const char *const names[4] = {
+               "Mic", "Aux", "Front Mic", "Line"
+       };
+
+       return snd_ctl_enum_info(info, 1, 4, names);
+}
+
+static int input_sel_get(struct snd_kcontrol *ctl,
+                        struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+
+       mutex_lock(&chip->mutex);
+       value->value.enumerated.item[0] = data->input_sel;
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static int input_sel_put(struct snd_kcontrol *ctl,
+                        struct snd_ctl_elem_value *value)
+{
+       static const u8 sel_values[4] = {
+               CS4245_SEL_MIC,
+               CS4245_SEL_INPUT_1,
+               CS4245_SEL_INPUT_2,
+               CS4245_SEL_INPUT_4
+       };
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+       int changed;
+
+       if (value->value.enumerated.item[0] > 3)
+               return -EINVAL;
+
+       mutex_lock(&chip->mutex);
+       changed = value->value.enumerated.item[0] != data->input_sel;
+       if (changed) {
+               data->input_sel = value->value.enumerated.item[0];
+
+               cs4245_write(chip, CS4245_ANALOG_IN,
+                            (data->cs4245_regs[CS4245_ANALOG_IN] &
+                                                       ~CS4245_SEL_MASK) |
+                            sel_values[data->input_sel]);
+
+               cs4245_write_cached(chip, CS4245_PGA_A_CTRL,
+                                   data->input_vol[data->input_sel][0]);
+               cs4245_write_cached(chip, CS4245_PGA_B_CTRL,
+                                   data->input_vol[data->input_sel][1]);
+
+               oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+                                     data->input_sel ? 0 : GPIO_INPUT_ROUTE,
+                                     GPIO_INPUT_ROUTE);
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
+{
+       static const char *const names[2] = { "Active", "Frozen" };
+
+       return snd_ctl_enum_info(info, 1, 2, names);
+}
+
+static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+
+       value->value.enumerated.item[0] =
+               !!(data->cs4245_regs[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE);
+       return 0;
+}
+
+static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+       u8 reg;
+       int changed;
+
+       mutex_lock(&chip->mutex);
+       reg = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE;
+       if (value->value.enumerated.item[0])
+               reg |= CS4245_HPF_FREEZE;
+       changed = reg != data->cs4245_regs[CS4245_ADC_CTRL];
+       if (changed)
+               cs4245_write(chip, CS4245_ADC_CTRL, reg);
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+#define INPUT_VOLUME(xname, index) { \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .info = input_vol_info, \
+       .get = input_vol_get, \
+       .put = input_vol_put, \
+       .tlv = { .p = cs4245_pga_db_scale }, \
+       .private_value = index, \
+}
+static const struct snd_kcontrol_new dg_controls[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Analog Output Playback Enum",
+               .info = output_switch_info,
+               .get = output_switch_get,
+               .put = output_switch_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Headphones Impedance Playback Enum",
+               .info = hp_volume_offset_info,
+               .get = hp_volume_offset_get,
+               .put = hp_volume_offset_put,
+       },
+       INPUT_VOLUME("Mic Capture Volume", 0),
+       INPUT_VOLUME("Aux Capture Volume", 1),
+       INPUT_VOLUME("Front Mic Capture Volume", 2),
+       INPUT_VOLUME("Line Capture Volume", 3),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Capture Source",
+               .info = input_sel_info,
+               .get = input_sel_get,
+               .put = input_sel_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "ADC High-pass Filter Capture Enum",
+               .info = hpf_info,
+               .get = hpf_get,
+               .put = hpf_put,
+       },
+};
+
+static int dg_control_filter(struct snd_kcontrol_new *template)
+{
+       if (!strncmp(template->name, "Master Playback ", 16))
+               return 1;
+       return 0;
+}
+
+static int dg_mixer_init(struct oxygen *chip)
+{
+       unsigned int i;
+       int err;
+
+       for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) {
+               err = snd_ctl_add(chip->card,
+                                 snd_ctl_new1(&dg_controls[i], chip));
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+static void dump_cs4245_registers(struct oxygen *chip,
+                                 struct snd_info_buffer *buffer)
+{
+       struct dg *data = chip->model_data;
+       unsigned int i;
+
+       snd_iprintf(buffer, "\nCS4245:");
+       for (i = 1; i <= 0x10; ++i)
+               snd_iprintf(buffer, " %02x", data->cs4245_regs[i]);
+       snd_iprintf(buffer, "\n");
+}
+
+struct oxygen_model model_xonar_dg = {
+       .shortname = "Xonar DG",
+       .longname = "C-Media Oxygen HD Audio",
+       .chip = "CMI8786",
+       .init = dg_init,
+       .control_filter = dg_control_filter,
+       .mixer_init = dg_mixer_init,
+       .cleanup = dg_cleanup,
+       .suspend = dg_suspend,
+       .resume = dg_resume,
+       .set_dac_params = set_cs4245_dac_params,
+       .set_adc_params = set_cs4245_adc_params,
+       .dump_registers = dump_cs4245_registers,
+       .model_data_size = sizeof(struct dg),
+       .device_config = PLAYBACK_0_TO_I2S |
+                        PLAYBACK_1_TO_SPDIF |
+                        CAPTURE_0_FROM_I2S_2,
+       .dac_channels_pcm = 6,
+       .dac_channels_mixer = 0,
+       .function_flags = OXYGEN_FUNCTION_SPI,
+       .dac_mclks = OXYGEN_MCLKS(256, 128, 128),
+       .adc_mclks = OXYGEN_MCLKS(256, 128, 128),
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
diff --git a/sound/pci/oxygen/xonar_dg.h b/sound/pci/oxygen/xonar_dg.h
new file mode 100644 (file)
index 0000000..5688d78
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef XONAR_DG_H_INCLUDED
+#define XONAR_DG_H_INCLUDED
+
+#include "oxygen.h"
+
+extern struct oxygen_model model_xonar_dg;
+
+#endif
index b12db1f..136dac6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * helper functions for HDMI models (Xonar HDAV1.3)
+ * helper functions for HDMI models (Xonar HDAV1.3/HDAV1.3 Slim)
  *
  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
  *
index b3ff713..0ebe7f5 100644 (file)
@@ -104,9 +104,10 @@ int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl,
 {
        struct oxygen *chip = ctl->private_data;
        u16 bit = ctl->private_value;
+       bool invert = ctl->private_value & XONAR_GPIO_BIT_INVERT;
 
        value->value.integer.value[0] =
-               !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit);
+               !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit) ^ invert;
        return 0;
 }
 
@@ -115,12 +116,13 @@ int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl,
 {
        struct oxygen *chip = ctl->private_data;
        u16 bit = ctl->private_value;
+       bool invert = ctl->private_value & XONAR_GPIO_BIT_INVERT;
        u16 old_bits, new_bits;
        int changed;
 
        spin_lock_irq(&chip->reg_lock);
        old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
-       if (value->value.integer.value[0])
+       if (!!value->value.integer.value[0] ^ invert)
                new_bits = old_bits | bit;
        else
                new_bits = old_bits & ~bit;
index d491fd6..54cad38 100644 (file)
  *
  * CMI8788:
  *
- * SPI 0 -> 1st PCM1796 (front)
- * SPI 1 -> 2nd PCM1796 (surround)
- * SPI 2 -> 3rd PCM1796 (center/LFE)
- * SPI 4 -> 4th PCM1796 (back)
+ *   SPI 0 -> 1st PCM1796 (front)
+ *   SPI 1 -> 2nd PCM1796 (surround)
+ *   SPI 2 -> 3rd PCM1796 (center/LFE)
+ *   SPI 4 -> 4th PCM1796 (back)
  *
- * GPIO 2 -> M0 of CS5381
- * GPIO 3 -> M1 of CS5381
- * GPIO 5 <- external power present (D2X only)
- * GPIO 7 -> ALT
- * GPIO 8 -> enable output to speakers
+ *   GPIO 2 -> M0 of CS5381
+ *   GPIO 3 -> M1 of CS5381
+ *   GPIO 5 <- external power present (D2X only)
+ *   GPIO 7 -> ALT
+ *   GPIO 8 -> enable output to speakers
  *
  * CM9780:
  *
- * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
+ *   LINE_OUT -> input of ADC
+ *
+ *   AUX_IN   <- aux
+ *   VIDEO_IN <- CD
+ *   FMIC_IN  <- mic
+ *
+ *   GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
  */
 
 /*
  *
  * CMI8788:
  *
- * I²C <-> PCM1796 (front)
+ *   I²C <-> PCM1796 (addr 1001100) (front)
  *
- * GPI 0 <- external power present
+ *   GPI 0 <- external power present
  *
- * GPIO 0 -> enable output to speakers
- * GPIO 2 -> M0 of CS5381
- * GPIO 3 -> M1 of CS5381
- * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
+ *   GPIO 0 -> enable HDMI (0) or speaker (1) output
+ *   GPIO 2 -> M0 of CS5381
+ *   GPIO 3 -> M1 of CS5381
+ *   GPIO 4 <- daughterboard detection
+ *   GPIO 5 <- daughterboard detection
+ *   GPIO 6 -> ?
+ *   GPIO 7 -> ?
+ *   GPIO 8 -> route input jack to line-in (0) or mic-in (1)
  *
- * TXD -> HDMI controller
- * RXD <- HDMI controller
- *
- * PCM1796 front: AD1,0 <- 0,0
+ *   UART <-> HDMI controller
  *
  * CM9780:
  *
- * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
+ *   LINE_OUT -> input of ADC
+ *
+ *   AUX_IN <- aux
+ *   CD_IN  <- CD
+ *   MIC_IN <- mic
+ *
+ *   GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
  *
  * no daughterboard
  * ----------------
  *
- * GPIO 4 <- 1
+ *   GPIO 4 <- 1
  *
  * H6 daughterboard
  * ----------------
  *
- * GPIO 4 <- 0
- * GPIO 5 <- 0
- *
- * I²C <-> PCM1796 (surround)
- *     <-> PCM1796 (center/LFE)
- *     <-> PCM1796 (back)
+ *   GPIO 4 <- 0
+ *   GPIO 5 <- 0
  *
- * PCM1796 surround:   AD1,0 <- 0,1
- * PCM1796 center/LFE: AD1,0 <- 1,0
- * PCM1796 back:       AD1,0 <- 1,1
+ *   I²C <-> PCM1796 (addr 1001101) (surround)
+ *       <-> PCM1796 (addr 1001110) (center/LFE)
+ *       <-> PCM1796 (addr 1001111) (back)
  *
  * unknown daughterboard
  * ---------------------
  *
- * GPIO 4 <- 0
- * GPIO 5 <- 1
- *
- * I²C <-> CS4362A (surround, center/LFE, back)
+ *   GPIO 4 <- 0
+ *   GPIO 5 <- 1
  *
- * CS4362A: AD0 <- 0
+ *   I²C <-> CS4362A (addr 0011000) (surround, center/LFE, back)
  */
 
 /*
  *
  * CMI8788:
  *
- * I²C <-> PCM1792A
- *     <-> CS2000 (ST only)
+ *   I²C <-> PCM1792A (addr 1001100)
+ *       <-> CS2000 (addr 1001110) (ST only)
  *
- * ADC1 MCLK -> REF_CLK of CS2000 (ST only)
+ *   ADC1 MCLK -> REF_CLK of CS2000 (ST only)
  *
- * GPI 0 <- external power present (STX only)
+ *   GPI 0 <- external power present (STX only)
  *
- * GPIO 0 -> enable output to speakers
- * GPIO 1 -> route HP to front panel (0) or rear jack (1)
- * GPIO 2 -> M0 of CS5381
- * GPIO 3 -> M1 of CS5381
- * GPIO 7 -> route output to speaker jacks (0) or HP (1)
- * GPIO 8 -> route input jack to line-in (0) or mic-in (1)
+ *   GPIO 0 -> enable output to speakers
+ *   GPIO 1 -> route HP to front panel (0) or rear jack (1)
+ *   GPIO 2 -> M0 of CS5381
+ *   GPIO 3 -> M1 of CS5381
+ *   GPIO 4 <- daughterboard detection
+ *   GPIO 5 <- daughterboard detection
+ *   GPIO 6 -> ?
+ *   GPIO 7 -> route output to speaker jacks (0) or HP (1)
+ *   GPIO 8 -> route input jack to line-in (0) or mic-in (1)
  *
  * PCM1792A:
  *
- * AD1,0 <- 0,0
- * SCK <- CLK_OUT of CS2000 (ST only)
+ *   SCK <- CLK_OUT of CS2000 (ST only)
  *
- * CS2000:
+ * CM9780:
  *
- * AD0 <- 0
+ *   LINE_OUT -> input of ADC
  *
- * CM9780:
+ *   AUX_IN <- aux
+ *   MIC_IN <- mic
  *
- * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
+ *   GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
  *
  * H6 daughterboard
  * ----------------
  */
 
 /*
- * Xonar HDAV1.3 Slim
- * ------------------
+ * Xonar Xense
+ * -----------
  *
  * CMI8788:
  *
- * GPIO 1 -> enable output
+ *   I²C <-> PCM1796 (addr 1001100) (front)
+ *       <-> CS4362A (addr 0011000) (surround, center/LFE, back)
+ *       <-> CS2000 (addr 1001110)
+ *
+ *   ADC1 MCLK -> REF_CLK of CS2000
+ *
+ *   GPI 0 <- external power present
+ *
+ *   GPIO 0 -> enable output
+ *   GPIO 1 -> route HP to front panel (0) or rear jack (1)
+ *   GPIO 2 -> M0 of CS5381
+ *   GPIO 3 -> M1 of CS5381
+ *   GPIO 4 -> enable output
+ *   GPIO 5 -> enable output
+ *   GPIO 6 -> ?
+ *   GPIO 7 -> route output to HP (0) or speaker (1)
+ *   GPIO 8 -> route input jack to mic-in (0) or line-in (1)
  *
- * TXD -> HDMI controller
- * RXD <- HDMI controller
+ * CM9780:
+ *
+ *   LINE_OUT -> input of ADC
+ *
+ *   AUX_IN   <- aux
+ *   VIDEO_IN <- ?
+ *   FMIC_IN  <- mic
+ *
+ *   GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input
+ *   GPO 1 -> route mic-in from input jack (0) or front panel header (1)
  */
 
 #include <linux/pci.h>
 #include <sound/ac97_codec.h>
 #include <sound/control.h>
 #include <sound/core.h>
+#include <sound/info.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/tlv.h>
 #define GPIO_INPUT_ROUTE       0x0100
 
 #define GPIO_HDAV_OUTPUT_ENABLE        0x0001
+#define GPIO_HDAV_MAGIC                0x00c0
 
 #define GPIO_DB_MASK           0x0030
 #define GPIO_DB_H6             0x0000
 
 #define GPIO_ST_OUTPUT_ENABLE  0x0001
 #define GPIO_ST_HP_REAR                0x0002
+#define GPIO_ST_MAGIC          0x0040
 #define GPIO_ST_HP             0x0080
 
 #define I2C_DEVICE_PCM1796(i)  (0x98 + ((i) << 1))     /* 10011, ii, /W=0 */
@@ -186,11 +223,12 @@ struct xonar_pcm179x {
        unsigned int dacs;
        u8 pcm1796_regs[4][5];
        unsigned int current_rate;
-       bool os_128;
+       bool h6;
        bool hp_active;
        s8 hp_gain_offset;
        bool has_cs2000;
-       u8 cs2000_fun_cfg_1;
+       u8 cs2000_regs[0x1f];
+       bool broken_i2c;
 };
 
 struct xonar_hdav {
@@ -249,16 +287,14 @@ static void cs2000_write(struct oxygen *chip, u8 reg, u8 value)
        struct xonar_pcm179x *data = chip->model_data;
 
        oxygen_write_i2c(chip, I2C_DEVICE_CS2000, reg, value);
-       if (reg == CS2000_FUN_CFG_1)
-               data->cs2000_fun_cfg_1 = value;
+       data->cs2000_regs[reg] = value;
 }
 
 static void cs2000_write_cached(struct oxygen *chip, u8 reg, u8 value)
 {
        struct xonar_pcm179x *data = chip->model_data;
 
-       if (reg != CS2000_FUN_CFG_1 ||
-           value != data->cs2000_fun_cfg_1)
+       if (value != data->cs2000_regs[reg])
                cs2000_write(chip, reg, value);
 }
 
@@ -268,6 +304,7 @@ static void pcm1796_registers_init(struct oxygen *chip)
        unsigned int i;
        s8 gain_offset;
 
+       msleep(1);
        gain_offset = data->hp_active ? data->hp_gain_offset : 0;
        for (i = 0; i < data->dacs; ++i) {
                /* set ATLD before ATL/ATR */
@@ -282,6 +319,7 @@ static void pcm1796_registers_init(struct oxygen *chip)
                pcm1796_write(chip, i, 20,
                              data->pcm1796_regs[0][20 - PCM1796_REG_BASE]);
                pcm1796_write(chip, i, 21, 0);
+               gain_offset = 0;
        }
 }
 
@@ -290,10 +328,11 @@ static void pcm1796_init(struct oxygen *chip)
        struct xonar_pcm179x *data = chip->model_data;
 
        data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE |
-               PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD;
+               PCM1796_DMF_DISABLED | PCM1796_FMT_24_I2S | PCM1796_ATLD;
        data->pcm1796_regs[0][19 - PCM1796_REG_BASE] =
                PCM1796_FLT_SHARP | PCM1796_ATS_1;
-       data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = PCM1796_OS_64;
+       data->pcm1796_regs[0][20 - PCM1796_REG_BASE] =
+               data->h6 ? PCM1796_OS_64 : PCM1796_OS_128;
        pcm1796_registers_init(chip);
        data->current_rate = 48000;
 }
@@ -339,18 +378,20 @@ static void xonar_hdav_init(struct oxygen *chip)
        oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
                       OXYGEN_2WIRE_LENGTH_8 |
                       OXYGEN_2WIRE_INTERRUPT_MASK |
-                      OXYGEN_2WIRE_SPEED_FAST);
+                      OXYGEN_2WIRE_SPEED_STANDARD);
 
        data->pcm179x.generic.anti_pop_delay = 100;
        data->pcm179x.generic.output_enable_bit = GPIO_HDAV_OUTPUT_ENABLE;
        data->pcm179x.generic.ext_power_reg = OXYGEN_GPI_DATA;
        data->pcm179x.generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
        data->pcm179x.generic.ext_power_bit = GPI_EXT_POWER;
-       data->pcm179x.dacs = chip->model.private_data ? 4 : 1;
+       data->pcm179x.dacs = chip->model.dac_channels_mixer / 2;
+       data->pcm179x.h6 = chip->model.dac_channels_mixer > 2;
 
        pcm1796_init(chip);
 
-       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_INPUT_ROUTE);
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+                         GPIO_HDAV_MAGIC | GPIO_INPUT_ROUTE);
        oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_INPUT_ROUTE);
 
        xonar_init_cs53x1(chip);
@@ -367,7 +408,7 @@ static void xonar_st_init_i2c(struct oxygen *chip)
        oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS,
                       OXYGEN_2WIRE_LENGTH_8 |
                       OXYGEN_2WIRE_INTERRUPT_MASK |
-                      OXYGEN_2WIRE_SPEED_FAST);
+                      OXYGEN_2WIRE_SPEED_STANDARD);
 }
 
 static void xonar_st_init_common(struct oxygen *chip)
@@ -375,13 +416,14 @@ static void xonar_st_init_common(struct oxygen *chip)
        struct xonar_pcm179x *data = chip->model_data;
 
        data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE;
-       data->dacs = chip->model.private_data ? 4 : 1;
+       data->dacs = chip->model.dac_channels_mixer / 2;
        data->hp_gain_offset = 2*-18;
 
        pcm1796_init(chip);
 
        oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
-                         GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
+                         GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR |
+                         GPIO_ST_MAGIC | GPIO_ST_HP);
        oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
                            GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP);
 
@@ -410,9 +452,11 @@ static void cs2000_registers_init(struct oxygen *chip)
        cs2000_write(chip, CS2000_RATIO_0 + 1, 0x10);
        cs2000_write(chip, CS2000_RATIO_0 + 2, 0x00);
        cs2000_write(chip, CS2000_RATIO_0 + 3, 0x00);
-       cs2000_write(chip, CS2000_FUN_CFG_1, data->cs2000_fun_cfg_1);
+       cs2000_write(chip, CS2000_FUN_CFG_1,
+                    data->cs2000_regs[CS2000_FUN_CFG_1]);
        cs2000_write(chip, CS2000_FUN_CFG_2, 0);
        cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_EN_DEV_CFG_2);
+       msleep(3); /* PLL lock delay */
 }
 
 static void xonar_st_init(struct oxygen *chip)
@@ -420,13 +464,18 @@ static void xonar_st_init(struct oxygen *chip)
        struct xonar_pcm179x *data = chip->model_data;
 
        data->generic.anti_pop_delay = 100;
+       data->h6 = chip->model.dac_channels_mixer > 2;
        data->has_cs2000 = 1;
-       data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1;
+       data->cs2000_regs[CS2000_FUN_CFG_1] = CS2000_REF_CLK_DIV_1;
+       data->broken_i2c = true;
 
        oxygen_write16(chip, OXYGEN_I2S_A_FORMAT,
-                      OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_I2S |
-                      OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 |
-                      OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64);
+                      OXYGEN_RATE_48000 |
+                      OXYGEN_I2S_FORMAT_I2S |
+                      OXYGEN_I2S_MCLK(data->h6 ? MCLK_256 : MCLK_512) |
+                      OXYGEN_I2S_BITS_16 |
+                      OXYGEN_I2S_MASTER |
+                      OXYGEN_I2S_BCLK_64);
 
        xonar_st_init_i2c(chip);
        cs2000_registers_init(chip);
@@ -507,44 +556,16 @@ static void xonar_st_resume(struct oxygen *chip)
        xonar_stx_resume(chip);
 }
 
-static unsigned int mclk_from_rate(struct oxygen *chip, unsigned int rate)
-{
-       struct xonar_pcm179x *data = chip->model_data;
-
-       if (rate <= 32000)
-               return OXYGEN_I2S_MCLK_512;
-       else if (rate <= 48000 && data->os_128)
-               return OXYGEN_I2S_MCLK_512;
-       else if (rate <= 96000)
-               return OXYGEN_I2S_MCLK_256;
-       else
-               return OXYGEN_I2S_MCLK_128;
-}
-
-static unsigned int get_pcm1796_i2s_mclk(struct oxygen *chip,
-                                        unsigned int channel,
-                                        struct snd_pcm_hw_params *params)
-{
-       if (channel == PCM_MULTICH)
-               return mclk_from_rate(chip, params_rate(params));
-       else
-               return oxygen_default_i2s_mclk(chip, channel, params);
-}
-
 static void update_pcm1796_oversampling(struct oxygen *chip)
 {
        struct xonar_pcm179x *data = chip->model_data;
        unsigned int i;
        u8 reg;
 
-       if (data->current_rate <= 32000)
+       if (data->current_rate <= 48000 && !data->h6)
                reg = PCM1796_OS_128;
-       else if (data->current_rate <= 48000 && data->os_128)
-               reg = PCM1796_OS_128;
-       else if (data->current_rate <= 96000 || data->os_128)
-               reg = PCM1796_OS_64;
        else
-               reg = PCM1796_OS_32;
+               reg = PCM1796_OS_64;
        for (i = 0; i < data->dacs; ++i)
                pcm1796_write_cached(chip, i, 20, reg);
 }
@@ -554,6 +575,7 @@ static void set_pcm1796_params(struct oxygen *chip,
 {
        struct xonar_pcm179x *data = chip->model_data;
 
+       msleep(1);
        data->current_rate = params_rate(params);
        update_pcm1796_oversampling(chip);
 }
@@ -570,6 +592,7 @@ static void update_pcm1796_volume(struct oxygen *chip)
                                     + gain_offset);
                pcm1796_write_cached(chip, i, 17, chip->dac_volume[i * 2 + 1]
                                     + gain_offset);
+               gain_offset = 0;
        }
 }
 
@@ -579,7 +602,7 @@ static void update_pcm1796_mute(struct oxygen *chip)
        unsigned int i;
        u8 value;
 
-       value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD;
+       value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_I2S | PCM1796_ATLD;
        if (chip->dac_mute)
                value |= PCM1796_MUTE;
        for (i = 0; i < data->dacs; ++i)
@@ -592,45 +615,35 @@ static void update_cs2000_rate(struct oxygen *chip, unsigned int rate)
        u8 rate_mclk, reg;
 
        switch (rate) {
-               /* XXX Why is the I2S A MCLK half the actual I2S MCLK? */
        case 32000:
-               rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256;
-               break;
-       case 44100:
-               if (data->os_128)
-                       rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256;
-               else
-                       rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_128;
-               break;
-       default: /* 48000 */
-               if (data->os_128)
-                       rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256;
-               else
-                       rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_128;
-               break;
        case 64000:
-               rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256;
+               rate_mclk = OXYGEN_RATE_32000;
                break;
+       case 44100:
        case 88200:
-               rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256;
-               break;
-       case 96000:
-               rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256;
-               break;
        case 176400:
-               rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256;
+               rate_mclk = OXYGEN_RATE_44100;
                break;
+       default:
+       case 48000:
+       case 96000:
        case 192000:
-               rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256;
+               rate_mclk = OXYGEN_RATE_48000;
                break;
        }
-       oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk,
-                             OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK);
-       if ((rate_mclk & OXYGEN_I2S_MCLK_MASK) <= OXYGEN_I2S_MCLK_128)
+
+       if (rate <= 96000 && (rate > 48000 || data->h6)) {
+               rate_mclk |= OXYGEN_I2S_MCLK(MCLK_256);
                reg = CS2000_REF_CLK_DIV_1;
-       else
+       } else {
+               rate_mclk |= OXYGEN_I2S_MCLK(MCLK_512);
                reg = CS2000_REF_CLK_DIV_2;
+       }
+
+       oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk,
+                             OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK);
        cs2000_write_cached(chip, CS2000_FUN_CFG_1, reg);
+       msleep(3); /* PLL lock delay */
 }
 
 static void set_st_params(struct oxygen *chip,
@@ -665,13 +678,7 @@ static int rolloff_info(struct snd_kcontrol *ctl,
                "Sharp Roll-off", "Slow Roll-off"
        };
 
-       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       info->count = 1;
-       info->value.enumerated.items = 2;
-       if (info->value.enumerated.item >= 2)
-               info->value.enumerated.item = 1;
-       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
-       return 0;
+       return snd_ctl_enum_info(info, 1, 2, names);
 }
 
 static int rolloff_get(struct snd_kcontrol *ctl,
@@ -719,57 +726,13 @@ static const struct snd_kcontrol_new rolloff_control = {
        .put = rolloff_put,
 };
 
-static int os_128_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
-{
-       static const char *const names[2] = { "64x", "128x" };
-
-       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       info->count = 1;
-       info->value.enumerated.items = 2;
-       if (info->value.enumerated.item >= 2)
-               info->value.enumerated.item = 1;
-       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
-       return 0;
-}
-
-static int os_128_get(struct snd_kcontrol *ctl,
-                     struct snd_ctl_elem_value *value)
-{
-       struct oxygen *chip = ctl->private_data;
-       struct xonar_pcm179x *data = chip->model_data;
-
-       value->value.enumerated.item[0] = data->os_128;
-       return 0;
-}
-
-static int os_128_put(struct snd_kcontrol *ctl,
-                     struct snd_ctl_elem_value *value)
-{
-       struct oxygen *chip = ctl->private_data;
-       struct xonar_pcm179x *data = chip->model_data;
-       int changed;
-
-       mutex_lock(&chip->mutex);
-       changed = value->value.enumerated.item[0] != data->os_128;
-       if (changed) {
-               data->os_128 = value->value.enumerated.item[0];
-               if (data->has_cs2000)
-                       update_cs2000_rate(chip, data->current_rate);
-               oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT,
-                                     mclk_from_rate(chip, data->current_rate),
-                                     OXYGEN_I2S_MCLK_MASK);
-               update_pcm1796_oversampling(chip);
-       }
-       mutex_unlock(&chip->mutex);
-       return changed;
-}
-
-static const struct snd_kcontrol_new os_128_control = {
+static const struct snd_kcontrol_new hdav_hdmi_control = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "DAC Oversampling Playback Enum",
-       .info = os_128_info,
-       .get = os_128_get,
-       .put = os_128_put,
+       .name = "HDMI Playback Switch",
+       .info = snd_ctl_boolean_mono_info,
+       .get = xonar_gpio_bit_switch_get,
+       .put = xonar_gpio_bit_switch_put,
+       .private_value = GPIO_HDAV_OUTPUT_ENABLE | XONAR_GPIO_BIT_INVERT,
 };
 
 static int st_output_switch_info(struct snd_kcontrol *ctl,
@@ -779,13 +742,7 @@ static int st_output_switch_info(struct snd_kcontrol *ctl,
                "Speakers", "Headphones", "FP Headphones"
        };
 
-       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       info->count = 1;
-       info->value.enumerated.items = 3;
-       if (info->value.enumerated.item >= 3)
-               info->value.enumerated.item = 2;
-       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
-       return 0;
+       return snd_ctl_enum_info(info, 1, 3, names);
 }
 
 static int st_output_switch_get(struct snd_kcontrol *ctl,
@@ -840,13 +797,7 @@ static int st_hp_volume_offset_info(struct snd_kcontrol *ctl,
                "< 64 ohms", "64-300 ohms", "300-600 ohms"
        };
 
-       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       info->count = 1;
-       info->value.enumerated.items = 3;
-       if (info->value.enumerated.item > 2)
-               info->value.enumerated.item = 2;
-       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
-       return 0;
+       return snd_ctl_enum_info(info, 1, 3, names);
 }
 
 static int st_hp_volume_offset_get(struct snd_kcontrol *ctl,
@@ -928,16 +879,25 @@ static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
        return 0;
 }
 
+static int xonar_st_h6_control_filter(struct snd_kcontrol_new *template)
+{
+       if (!strncmp(template->name, "Master Playback ", 16))
+               /* no volume/mute, as I²C to the third DAC does not work */
+               return 1;
+       return 0;
+}
+
 static int add_pcm1796_controls(struct oxygen *chip)
 {
+       struct xonar_pcm179x *data = chip->model_data;
        int err;
 
-       err = snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip));
-       if (err < 0)
-               return err;
-       err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip));
-       if (err < 0)
-               return err;
+       if (!data->broken_i2c) {
+               err = snd_ctl_add(chip->card,
+                                 snd_ctl_new1(&rolloff_control, chip));
+               if (err < 0)
+                       return err;
+       }
        return 0;
 }
 
@@ -956,7 +916,15 @@ static int xonar_d2_mixer_init(struct oxygen *chip)
 
 static int xonar_hdav_mixer_init(struct oxygen *chip)
 {
-       return add_pcm1796_controls(chip);
+       int err;
+
+       err = snd_ctl_add(chip->card, snd_ctl_new1(&hdav_hdmi_control, chip));
+       if (err < 0)
+               return err;
+       err = add_pcm1796_controls(chip);
+       if (err < 0)
+               return err;
+       return 0;
 }
 
 static int xonar_st_mixer_init(struct oxygen *chip)
@@ -976,6 +944,45 @@ static int xonar_st_mixer_init(struct oxygen *chip)
        return 0;
 }
 
+static void dump_pcm1796_registers(struct oxygen *chip,
+                                  struct snd_info_buffer *buffer)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+       unsigned int dac, i;
+
+       for (dac = 0; dac < data->dacs; ++dac) {
+               snd_iprintf(buffer, "\nPCM1796 %u:", dac + 1);
+               for (i = 0; i < 5; ++i)
+                       snd_iprintf(buffer, " %02x",
+                                   data->pcm1796_regs[dac][i]);
+       }
+       snd_iprintf(buffer, "\n");
+}
+
+static void dump_cs2000_registers(struct oxygen *chip,
+                                 struct snd_info_buffer *buffer)
+{
+       struct xonar_pcm179x *data = chip->model_data;
+       unsigned int i;
+
+       if (data->has_cs2000) {
+               snd_iprintf(buffer, "\nCS2000:\n00:   ");
+               for (i = 1; i < 0x10; ++i)
+                       snd_iprintf(buffer, " %02x", data->cs2000_regs[i]);
+               snd_iprintf(buffer, "\n10:");
+               for (i = 0x10; i < 0x1f; ++i)
+                       snd_iprintf(buffer, " %02x", data->cs2000_regs[i]);
+               snd_iprintf(buffer, "\n");
+       }
+}
+
+static void dump_st_registers(struct oxygen *chip,
+                             struct snd_info_buffer *buffer)
+{
+       dump_pcm1796_registers(chip, buffer);
+       dump_cs2000_registers(chip, buffer);
+}
+
 static const struct oxygen_model model_xonar_d2 = {
        .longname = "Asus Virtuoso 200",
        .chip = "AV200",
@@ -985,11 +992,11 @@ static const struct oxygen_model model_xonar_d2 = {
        .cleanup = xonar_d2_cleanup,
        .suspend = xonar_d2_suspend,
        .resume = xonar_d2_resume,
-       .get_i2s_mclk = get_pcm1796_i2s_mclk,
        .set_dac_params = set_pcm1796_params,
        .set_adc_params = xonar_set_cs53x1_params,
        .update_dac_volume = update_pcm1796_volume,
        .update_dac_mute = update_pcm1796_mute,
+       .dump_registers = dump_pcm1796_registers,
        .dac_tlv = pcm1796_db_scale,
        .model_data_size = sizeof(struct xonar_pcm179x),
        .device_config = PLAYBACK_0_TO_I2S |
@@ -999,13 +1006,16 @@ static const struct oxygen_model model_xonar_d2 = {
                         MIDI_OUTPUT |
                         MIDI_INPUT |
                         AC97_CD_INPUT,
-       .dac_channels = 8,
+       .dac_channels_pcm = 8,
+       .dac_channels_mixer = 8,
        .dac_volume_min = 255 - 2*60,
        .dac_volume_max = 255,
        .misc_flags = OXYGEN_MISC_MIDI,
        .function_flags = OXYGEN_FUNCTION_SPI |
                          OXYGEN_FUNCTION_ENABLE_SPI_4_5,
-       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+       .dac_mclks = OXYGEN_MCLKS(512, 128, 128),
+       .adc_mclks = OXYGEN_MCLKS(256, 128, 128),
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S,
        .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
 };
 
@@ -1018,25 +1028,28 @@ static const struct oxygen_model model_xonar_hdav = {
        .suspend = xonar_hdav_suspend,
        .resume = xonar_hdav_resume,
        .pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter,
-       .get_i2s_mclk = get_pcm1796_i2s_mclk,
        .set_dac_params = set_hdav_params,
        .set_adc_params = xonar_set_cs53x1_params,
        .update_dac_volume = update_pcm1796_volume,
        .update_dac_mute = update_pcm1796_mute,
        .uart_input = xonar_hdmi_uart_input,
        .ac97_switch = xonar_line_mic_ac97_switch,
+       .dump_registers = dump_pcm1796_registers,
        .dac_tlv = pcm1796_db_scale,
        .model_data_size = sizeof(struct xonar_hdav),
        .device_config = PLAYBACK_0_TO_I2S |
                         PLAYBACK_1_TO_SPDIF |
                         CAPTURE_0_FROM_I2S_2 |
                         CAPTURE_1_FROM_SPDIF,
-       .dac_channels = 8,
+       .dac_channels_pcm = 8,
+       .dac_channels_mixer = 2,
        .dac_volume_min = 255 - 2*60,
        .dac_volume_max = 255,
        .misc_flags = OXYGEN_MISC_MIDI,
        .function_flags = OXYGEN_FUNCTION_2WIRE,
-       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+       .dac_mclks = OXYGEN_MCLKS(512, 128, 128),
+       .adc_mclks = OXYGEN_MCLKS(256, 128, 128),
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S,
        .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
 };
 
@@ -1048,22 +1061,26 @@ static const struct oxygen_model model_xonar_st = {
        .cleanup = xonar_st_cleanup,
        .suspend = xonar_st_suspend,
        .resume = xonar_st_resume,
-       .get_i2s_mclk = get_pcm1796_i2s_mclk,
        .set_dac_params = set_st_params,
        .set_adc_params = xonar_set_cs53x1_params,
        .update_dac_volume = update_pcm1796_volume,
        .update_dac_mute = update_pcm1796_mute,
        .ac97_switch = xonar_line_mic_ac97_switch,
+       .dump_registers = dump_st_registers,
        .dac_tlv = pcm1796_db_scale,
        .model_data_size = sizeof(struct xonar_pcm179x),
        .device_config = PLAYBACK_0_TO_I2S |
                         PLAYBACK_1_TO_SPDIF |
-                        CAPTURE_0_FROM_I2S_2,
-       .dac_channels = 2,
+                        CAPTURE_0_FROM_I2S_2 |
+                        AC97_FMIC_SWITCH,
+       .dac_channels_pcm = 2,
+       .dac_channels_mixer = 2,
        .dac_volume_min = 255 - 2*60,
        .dac_volume_max = 255,
        .function_flags = OXYGEN_FUNCTION_2WIRE,
-       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+       .dac_mclks = OXYGEN_MCLKS(512, 128, 128),
+       .adc_mclks = OXYGEN_MCLKS(256, 128, 128),
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S,
        .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
 };
 
@@ -1089,7 +1106,8 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip,
                        break;
                case GPIO_DB_H6:
                        chip->model.shortname = "Xonar HDAV1.3+H6";
-                       chip->model.private_data = 1;
+                       chip->model.dac_channels_mixer = 8;
+                       chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128);
                        break;
                }
                break;
@@ -1102,8 +1120,10 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip,
                        break;
                case GPIO_DB_H6:
                        chip->model.shortname = "Xonar ST+H6";
-                       chip->model.dac_channels = 8;
-                       chip->model.private_data = 1;
+                       chip->model.control_filter = xonar_st_h6_control_filter;
+                       chip->model.dac_channels_pcm = 8;
+                       chip->model.dac_channels_mixer = 8;
+                       chip->model.dac_mclks = OXYGEN_MCLKS(256, 128, 128);
                        break;
                }
                break;
@@ -1114,9 +1134,6 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip,
                chip->model.resume = xonar_stx_resume;
                chip->model.set_dac_params = set_pcm1796_params;
                break;
-       case 0x835e:
-               snd_printk(KERN_ERR "the HDAV1.3 Slim is not supported\n");
-               return -ENODEV;
        default:
                return -EINVAL;
        }
index 200f760..42d1ab1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * card driver for models with WM8776/WM8766 DACs (Xonar DS)
+ * card driver for models with WM8776/WM8766 DACs (Xonar DS/HDAV1.3 Slim)
  *
  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
  *
  *
  * CMI8788:
  *
- * SPI 0 -> WM8766 (surround, center/LFE, back)
- * SPI 1 -> WM8776 (front, input)
+ *   SPI 0 -> WM8766 (surround, center/LFE, back)
+ *   SPI 1 -> WM8776 (front, input)
  *
- * GPIO 4 <- headphone detect, 0 = plugged
- * GPIO 6 -> route input jack to mic-in (0) or line-in (1)
- * GPIO 7 -> enable output to front L/R speaker channels
- * GPIO 8 -> enable output to other speaker channels and front panel headphone
+ *   GPIO 4 <- headphone detect, 0 = plugged
+ *   GPIO 6 -> route input jack to mic-in (0) or line-in (1)
+ *   GPIO 7 -> enable output to front L/R speaker channels
+ *   GPIO 8 -> enable output to other speaker channels and front panel headphone
  *
- * WM8766:
+ * WM8776:
  *
- * input 1 <- line
- * input 2 <- mic
- * input 3 <- front mic
- * input 4 <- aux
+ *   input 1 <- line
+ *   input 2 <- mic
+ *   input 3 <- front mic
+ *   input 4 <- aux
+ */
+
+/*
+ * Xonar HDAV1.3 Slim
+ * ------------------
+ *
+ * CMI8788:
+ *
+ *   I²C <-> WM8776 (addr 0011010)
+ *
+ *   GPIO 0  -> disable HDMI output
+ *   GPIO 1  -> enable HP output
+ *   GPIO 6  -> firmware EEPROM I²C clock
+ *   GPIO 7 <-> firmware EEPROM I²C data
+ *
+ *   UART <-> HDMI controller
+ *
+ * WM8776:
+ *
+ *   input 1 <- mic
+ *   input 2 <- aux
  */
 
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <sound/control.h>
 #include <sound/core.h>
+#include <sound/info.h>
 #include <sound/jack.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #define GPIO_DS_OUTPUT_FRONTLR 0x0080
 #define GPIO_DS_OUTPUT_ENABLE  0x0100
 
+#define GPIO_SLIM_HDMI_DISABLE 0x0001
+#define GPIO_SLIM_OUTPUT_ENABLE        0x0002
+#define GPIO_SLIM_FIRMWARE_CLK 0x0040
+#define GPIO_SLIM_FIRMWARE_DATA        0x0080
+
+#define I2C_DEVICE_WM8776      0x34    /* 001101, 0, /W=0 */
+
 #define LC_CONTROL_LIMITER     0x40000000
 #define LC_CONTROL_ALC         0x20000000
 
@@ -66,19 +95,37 @@ struct xonar_wm87x6 {
        struct snd_kcontrol *mic_adcmux_control;
        struct snd_kcontrol *lc_controls[13];
        struct snd_jack *hp_jack;
+       struct xonar_hdmi hdmi;
 };
 
-static void wm8776_write(struct oxygen *chip,
-                        unsigned int reg, unsigned int value)
+static void wm8776_write_spi(struct oxygen *chip,
+                            unsigned int reg, unsigned int value)
 {
-       struct xonar_wm87x6 *data = chip->model_data;
-
        oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
                         OXYGEN_SPI_DATA_LENGTH_2 |
                         OXYGEN_SPI_CLOCK_160 |
                         (1 << OXYGEN_SPI_CODEC_SHIFT) |
                         OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
                         (reg << 9) | value);
+}
+
+static void wm8776_write_i2c(struct oxygen *chip,
+                            unsigned int reg, unsigned int value)
+{
+       oxygen_write_i2c(chip, I2C_DEVICE_WM8776,
+                        (reg << 1) | (value >> 8), value);
+}
+
+static void wm8776_write(struct oxygen *chip,
+                        unsigned int reg, unsigned int value)
+{
+       struct xonar_wm87x6 *data = chip->model_data;
+
+       if ((chip->model.function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK) ==
+           OXYGEN_FUNCTION_SPI)
+               wm8776_write_spi(chip, reg, value);
+       else
+               wm8776_write_i2c(chip, reg, value);
        if (reg < ARRAY_SIZE(data->wm8776_regs)) {
                if (reg >= WM8776_HPLVOL && reg <= WM8776_DACMASTER)
                        value &= ~WM8776_UPDATE;
@@ -245,17 +292,50 @@ static void xonar_ds_init(struct oxygen *chip)
        snd_component_add(chip->card, "WM8766");
 }
 
+static void xonar_hdav_slim_init(struct oxygen *chip)
+{
+       struct xonar_wm87x6 *data = chip->model_data;
+
+       data->generic.anti_pop_delay = 300;
+       data->generic.output_enable_bit = GPIO_SLIM_OUTPUT_ENABLE;
+
+       wm8776_init(chip);
+
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+                         GPIO_SLIM_HDMI_DISABLE |
+                         GPIO_SLIM_FIRMWARE_CLK |
+                         GPIO_SLIM_FIRMWARE_DATA);
+
+       xonar_hdmi_init(chip, &data->hdmi);
+       xonar_enable_output(chip);
+
+       snd_component_add(chip->card, "WM8776");
+}
+
 static void xonar_ds_cleanup(struct oxygen *chip)
 {
        xonar_disable_output(chip);
        wm8776_write(chip, WM8776_RESET, 0);
 }
 
+static void xonar_hdav_slim_cleanup(struct oxygen *chip)
+{
+       xonar_hdmi_cleanup(chip);
+       xonar_disable_output(chip);
+       wm8776_write(chip, WM8776_RESET, 0);
+       msleep(2);
+}
+
 static void xonar_ds_suspend(struct oxygen *chip)
 {
        xonar_ds_cleanup(chip);
 }
 
+static void xonar_hdav_slim_suspend(struct oxygen *chip)
+{
+       xonar_hdav_slim_cleanup(chip);
+}
+
 static void xonar_ds_resume(struct oxygen *chip)
 {
        wm8776_registers_init(chip);
@@ -264,6 +344,15 @@ static void xonar_ds_resume(struct oxygen *chip)
        xonar_ds_handle_hp_jack(chip);
 }
 
+static void xonar_hdav_slim_resume(struct oxygen *chip)
+{
+       struct xonar_wm87x6 *data = chip->model_data;
+
+       wm8776_registers_init(chip);
+       xonar_hdmi_resume(chip, &data->hdmi);
+       xonar_enable_output(chip);
+}
+
 static void wm8776_adc_hardware_filter(unsigned int channel,
                                       struct snd_pcm_hardware *hardware)
 {
@@ -278,6 +367,13 @@ static void wm8776_adc_hardware_filter(unsigned int channel,
        }
 }
 
+static void xonar_hdav_slim_hardware_filter(unsigned int channel,
+                                           struct snd_pcm_hardware *hardware)
+{
+       wm8776_adc_hardware_filter(channel, hardware);
+       xonar_hdmi_pcm_hardware_filter(channel, hardware);
+}
+
 static void set_wm87x6_dac_params(struct oxygen *chip,
                                  struct snd_pcm_hw_params *params)
 {
@@ -294,6 +390,14 @@ static void set_wm8776_adc_params(struct oxygen *chip,
        wm8776_write_cached(chip, WM8776_MSTRCTRL, reg);
 }
 
+static void set_hdav_slim_dac_params(struct oxygen *chip,
+                                    struct snd_pcm_hw_params *params)
+{
+       struct xonar_wm87x6 *data = chip->model_data;
+
+       xonar_set_hdmi_params(chip, &data->hdmi, params);
+}
+
 static void update_wm8776_volume(struct oxygen *chip)
 {
        struct xonar_wm87x6 *data = chip->model_data;
@@ -473,11 +577,6 @@ static int wm8776_field_enum_info(struct snd_kcontrol *ctl,
        const char *const *names;
 
        max = (ctl->private_value >> 12) & 0xf;
-       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       info->count = 1;
-       info->value.enumerated.items = max + 1;
-       if (info->value.enumerated.item > max)
-               info->value.enumerated.item = max;
        switch ((ctl->private_value >> 24) & 0x1f) {
        case WM8776_ALCCTRL2:
                names = hld;
@@ -501,8 +600,7 @@ static int wm8776_field_enum_info(struct snd_kcontrol *ctl,
        default:
                return -ENXIO;
        }
-       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
-       return 0;
+       return snd_ctl_enum_info(info, 1, max + 1, names);
 }
 
 static int wm8776_field_volume_info(struct snd_kcontrol *ctl,
@@ -759,13 +857,8 @@ static int wm8776_level_control_info(struct snd_kcontrol *ctl,
        static const char *const names[3] = {
                "None", "Peak Limiter", "Automatic Level Control"
        };
-       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       info->count = 1;
-       info->value.enumerated.items = 3;
-       if (info->value.enumerated.item >= 3)
-               info->value.enumerated.item = 2;
-       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
-       return 0;
+
+       return snd_ctl_enum_info(info, 1, 3, names);
 }
 
 static int wm8776_level_control_get(struct snd_kcontrol *ctl,
@@ -851,13 +944,7 @@ static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
                "None", "High-pass Filter"
        };
 
-       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       info->count = 1;
-       info->value.enumerated.items = 2;
-       if (info->value.enumerated.item >= 2)
-               info->value.enumerated.item = 1;
-       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
-       return 0;
+       return snd_ctl_enum_info(info, 1, 2, names);
 }
 
 static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
@@ -985,6 +1072,53 @@ static const struct snd_kcontrol_new ds_controls[] = {
                .private_value = 0,
        },
 };
+static const struct snd_kcontrol_new hdav_slim_controls[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "HDMI Playback Switch",
+               .info = snd_ctl_boolean_mono_info,
+               .get = xonar_gpio_bit_switch_get,
+               .put = xonar_gpio_bit_switch_put,
+               .private_value = GPIO_SLIM_HDMI_DISABLE | XONAR_GPIO_BIT_INVERT,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Headphone Playback Volume",
+               .info = wm8776_hp_vol_info,
+               .get = wm8776_hp_vol_get,
+               .put = wm8776_hp_vol_put,
+               .tlv = { .p = wm8776_hp_db_scale },
+       },
+       WM8776_BIT_SWITCH("Headphone Playback Switch",
+                         WM8776_PWRDOWN, WM8776_HPPD, 1, 0),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Input Capture Volume",
+               .info = wm8776_input_vol_info,
+               .get = wm8776_input_vol_get,
+               .put = wm8776_input_vol_put,
+               .tlv = { .p = wm8776_adc_db_scale },
+       },
+       WM8776_BIT_SWITCH("Mic Capture Switch",
+                         WM8776_ADCMUX, 1 << 0, 0, 0),
+       WM8776_BIT_SWITCH("Aux Capture Switch",
+                         WM8776_ADCMUX, 1 << 1, 0, 0),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "ADC Filter Capture Enum",
+               .info = hpf_info,
+               .get = hpf_get,
+               .put = hpf_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Level Control Capture Enum",
+               .info = wm8776_level_control_info,
+               .get = wm8776_level_control_get,
+               .put = wm8776_level_control_put,
+               .private_value = 0,
+       },
+};
 static const struct snd_kcontrol_new lc_controls[] = {
        WM8776_FIELD_CTL_VOLUME("Limiter Threshold",
                                WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf,
@@ -1028,6 +1162,26 @@ static const struct snd_kcontrol_new lc_controls[] = {
                                LC_CONTROL_ALC, wm8776_ngth_db_scale),
 };
 
+static int add_lc_controls(struct oxygen *chip)
+{
+       struct xonar_wm87x6 *data = chip->model_data;
+       unsigned int i;
+       struct snd_kcontrol *ctl;
+       int err;
+
+       BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls));
+       for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) {
+               ctl = snd_ctl_new1(&lc_controls[i], chip);
+               if (!ctl)
+                       return -ENOMEM;
+               err = snd_ctl_add(chip->card, ctl);
+               if (err < 0)
+                       return err;
+               data->lc_controls[i] = ctl;
+       }
+       return 0;
+}
+
 static int xonar_ds_mixer_init(struct oxygen *chip)
 {
        struct xonar_wm87x6 *data = chip->model_data;
@@ -1049,17 +1203,54 @@ static int xonar_ds_mixer_init(struct oxygen *chip)
        }
        if (!data->line_adcmux_control || !data->mic_adcmux_control)
                return -ENXIO;
-       BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls));
-       for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) {
-               ctl = snd_ctl_new1(&lc_controls[i], chip);
+
+       return add_lc_controls(chip);
+}
+
+static int xonar_hdav_slim_mixer_init(struct oxygen *chip)
+{
+       unsigned int i;
+       struct snd_kcontrol *ctl;
+       int err;
+
+       for (i = 0; i < ARRAY_SIZE(hdav_slim_controls); ++i) {
+               ctl = snd_ctl_new1(&hdav_slim_controls[i], chip);
                if (!ctl)
                        return -ENOMEM;
                err = snd_ctl_add(chip->card, ctl);
                if (err < 0)
                        return err;
-               data->lc_controls[i] = ctl;
        }
-       return 0;
+
+       return add_lc_controls(chip);
+}
+
+static void dump_wm8776_registers(struct oxygen *chip,
+                                 struct snd_info_buffer *buffer)
+{
+       struct xonar_wm87x6 *data = chip->model_data;
+       unsigned int i;
+
+       snd_iprintf(buffer, "\nWM8776:\n00:");
+       for (i = 0; i < 0x10; ++i)
+               snd_iprintf(buffer, " %03x", data->wm8776_regs[i]);
+       snd_iprintf(buffer, "\n10:");
+       for (i = 0x10; i < 0x17; ++i)
+               snd_iprintf(buffer, " %03x", data->wm8776_regs[i]);
+       snd_iprintf(buffer, "\n");
+}
+
+static void dump_wm87x6_registers(struct oxygen *chip,
+                                 struct snd_info_buffer *buffer)
+{
+       struct xonar_wm87x6 *data = chip->model_data;
+       unsigned int i;
+
+       dump_wm8776_registers(chip, buffer);
+       snd_iprintf(buffer, "\nWM8766:\n00:");
+       for (i = 0; i < 0x10; ++i)
+               snd_iprintf(buffer, " %03x", data->wm8766_regs[i]);
+       snd_iprintf(buffer, "\n");
 }
 
 static const struct oxygen_model model_xonar_ds = {
@@ -1072,22 +1263,57 @@ static const struct oxygen_model model_xonar_ds = {
        .suspend = xonar_ds_suspend,
        .resume = xonar_ds_resume,
        .pcm_hardware_filter = wm8776_adc_hardware_filter,
-       .get_i2s_mclk = oxygen_default_i2s_mclk,
        .set_dac_params = set_wm87x6_dac_params,
        .set_adc_params = set_wm8776_adc_params,
        .update_dac_volume = update_wm87x6_volume,
        .update_dac_mute = update_wm87x6_mute,
        .update_center_lfe_mix = update_wm8766_center_lfe_mix,
        .gpio_changed = xonar_ds_gpio_changed,
+       .dump_registers = dump_wm87x6_registers,
        .dac_tlv = wm87x6_dac_db_scale,
        .model_data_size = sizeof(struct xonar_wm87x6),
        .device_config = PLAYBACK_0_TO_I2S |
                         PLAYBACK_1_TO_SPDIF |
                         CAPTURE_0_FROM_I2S_1,
-       .dac_channels = 8,
+       .dac_channels_pcm = 8,
+       .dac_channels_mixer = 8,
        .dac_volume_min = 255 - 2*60,
        .dac_volume_max = 255,
        .function_flags = OXYGEN_FUNCTION_SPI,
+       .dac_mclks = OXYGEN_MCLKS(256, 256, 128),
+       .adc_mclks = OXYGEN_MCLKS(256, 256, 128),
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
+
+static const struct oxygen_model model_xonar_hdav_slim = {
+       .shortname = "Xonar HDAV1.3 Slim",
+       .longname = "Asus Virtuoso 200",
+       .chip = "AV200",
+       .init = xonar_hdav_slim_init,
+       .mixer_init = xonar_hdav_slim_mixer_init,
+       .cleanup = xonar_hdav_slim_cleanup,
+       .suspend = xonar_hdav_slim_suspend,
+       .resume = xonar_hdav_slim_resume,
+       .pcm_hardware_filter = xonar_hdav_slim_hardware_filter,
+       .set_dac_params = set_hdav_slim_dac_params,
+       .set_adc_params = set_wm8776_adc_params,
+       .update_dac_volume = update_wm8776_volume,
+       .update_dac_mute = update_wm8776_mute,
+       .uart_input = xonar_hdmi_uart_input,
+       .dump_registers = dump_wm8776_registers,
+       .dac_tlv = wm87x6_dac_db_scale,
+       .model_data_size = sizeof(struct xonar_wm87x6),
+       .device_config = PLAYBACK_0_TO_I2S |
+                        PLAYBACK_1_TO_SPDIF |
+                        CAPTURE_0_FROM_I2S_1,
+       .dac_channels_pcm = 8,
+       .dac_channels_mixer = 2,
+       .dac_volume_min = 255 - 2*60,
+       .dac_volume_max = 255,
+       .function_flags = OXYGEN_FUNCTION_2WIRE,
+       .dac_mclks = OXYGEN_MCLKS(256, 256, 128),
+       .adc_mclks = OXYGEN_MCLKS(256, 256, 128),
        .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
        .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
 };
@@ -1099,6 +1325,9 @@ int __devinit get_xonar_wm87x6_model(struct oxygen *chip,
        case 0x838e:
                chip->model = model_xonar_ds;
                break;
+       case 0x835e:
+               chip->model = model_xonar_hdav_slim;
+               break;
        default:
                return -EINVAL;
        }
index 0b720cf..2d83324 100644 (file)
@@ -60,6 +60,7 @@ MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP},"
                "{RME HDSP-9652},"
                "{RME HDSP-9632}}");
 #ifdef HDSP_FW_LOADER
+MODULE_FIRMWARE("rpm_firmware.bin");
 MODULE_FIRMWARE("multiface_firmware.bin");
 MODULE_FIRMWARE("multiface_firmware_rev11.bin");
 MODULE_FIRMWARE("digiface_firmware.bin");
@@ -81,6 +82,7 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin");
 #define H9632_SS_CHANNELS       12
 #define H9632_DS_CHANNELS       8
 #define H9632_QS_CHANNELS       4
+#define RPM_CHANNELS             6
 
 /* Write registers. These are defined as byte-offsets from the iobase value.
  */
@@ -191,6 +193,25 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin");
 #define HDSP_PhoneGain1                  (1<<30)
 #define HDSP_QuadSpeed           (1<<31)
 
+/* RPM uses some of the registers for special purposes */
+#define HDSP_RPM_Inp12            0x04A00
+#define HDSP_RPM_Inp12_Phon_6dB   0x00800  /* Dolby */
+#define HDSP_RPM_Inp12_Phon_0dB   0x00000  /* .. */
+#define HDSP_RPM_Inp12_Phon_n6dB  0x04000  /* inp_0 */
+#define HDSP_RPM_Inp12_Line_0dB   0x04200  /* Dolby+PRO */
+#define HDSP_RPM_Inp12_Line_n6dB  0x00200  /* PRO */
+
+#define HDSP_RPM_Inp34            0x32000
+#define HDSP_RPM_Inp34_Phon_6dB   0x20000  /* SyncRef1 */
+#define HDSP_RPM_Inp34_Phon_0dB   0x00000  /* .. */
+#define HDSP_RPM_Inp34_Phon_n6dB  0x02000  /* SyncRef2 */
+#define HDSP_RPM_Inp34_Line_0dB   0x30000  /* SyncRef1+SyncRef0 */
+#define HDSP_RPM_Inp34_Line_n6dB  0x10000  /* SyncRef0 */
+
+#define HDSP_RPM_Bypass           0x01000
+
+#define HDSP_RPM_Disconnect       0x00001
+
 #define HDSP_ADGainMask       (HDSP_ADGain0|HDSP_ADGain1)
 #define HDSP_ADGainMinus10dBV  HDSP_ADGainMask
 #define HDSP_ADGainPlus4dBu   (HDSP_ADGain0)
@@ -450,7 +471,7 @@ struct hdsp {
        u32                   creg_spdif;
        u32                   creg_spdif_stream;
        int                   clock_source_locked;
-       char                 *card_name;             /* digiface/multiface */
+       char                 *card_name;         /* digiface/multiface/rpm */
        enum HDSP_IO_Type     io_type;               /* ditto, but for code use */
         unsigned short        firmware_rev;
        unsigned short        state;                 /* stores state bits */
@@ -612,6 +633,7 @@ static int hdsp_playback_to_output_key (struct hdsp *hdsp, int in, int out)
        switch (hdsp->io_type) {
        case Multiface:
        case Digiface:
+       case RPM:
        default:
                if (hdsp->firmware_rev == 0xa)
                        return (64 * out) + (32 + (in));
@@ -629,6 +651,7 @@ static int hdsp_input_to_output_key (struct hdsp *hdsp, int in, int out)
        switch (hdsp->io_type) {
        case Multiface:
        case Digiface:
+       case RPM:
        default:
                if (hdsp->firmware_rev == 0xa)
                        return (64 * out) + in;
@@ -655,7 +678,7 @@ static int hdsp_check_for_iobox (struct hdsp *hdsp)
 {
        if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0;
        if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_ConfigError) {
-               snd_printk ("Hammerfall-DSP: no Digiface or Multiface connected!\n");
+               snd_printk("Hammerfall-DSP: no IO box connected!\n");
                hdsp->state &= ~HDSP_FirmwareLoaded;
                return -EIO;
        }
@@ -680,7 +703,7 @@ static int hdsp_wait_for_iobox(struct hdsp *hdsp, unsigned int loops,
                }
        }
 
-       snd_printk("Hammerfall-DSP: no Digiface or Multiface connected!\n");
+       snd_printk("Hammerfall-DSP: no IO box connected!\n");
        hdsp->state &= ~HDSP_FirmwareLoaded;
        return -EIO;
 }
@@ -752,17 +775,21 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp)
                hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD);
                hdsp_write (hdsp, HDSP_fifoData, 0);
 
-               if (hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT)) {
-                       hdsp->io_type = Multiface;
-                       hdsp_write (hdsp, HDSP_control2Reg, HDSP_VERSION_BIT);
-                       hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD);
-                       hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT);
+               if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT)) {
+                       hdsp_write(hdsp, HDSP_control2Reg, HDSP_VERSION_BIT);
+                       hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD);
+                       if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT))
+                               hdsp->io_type = RPM;
+                       else
+                               hdsp->io_type = Multiface;
                } else {
                        hdsp->io_type = Digiface;
                }
        } else {
                /* firmware was already loaded, get iobox type */
-               if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
+               if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2)
+                       hdsp->io_type = RPM;
+               else if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
                        hdsp->io_type = Multiface;
                else
                        hdsp->io_type = Digiface;
@@ -1184,6 +1211,7 @@ static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally)
                        hdsp->channel_map = channel_map_ds;
        } else {
                switch (hdsp->io_type) {
+               case RPM:
                case Multiface:
                        hdsp->channel_map = channel_map_mf_ss;
                        break;
@@ -3231,6 +3259,318 @@ HDSP_PRECISE_POINTER("Precise Pointer", 0),
 HDSP_USE_MIDI_TASKLET("Use Midi Tasklet", 0),
 };
 
+
+static int hdsp_rpm_input12(struct hdsp *hdsp)
+{
+       switch (hdsp->control_register & HDSP_RPM_Inp12) {
+       case HDSP_RPM_Inp12_Phon_6dB:
+               return 0;
+       case HDSP_RPM_Inp12_Phon_n6dB:
+               return 2;
+       case HDSP_RPM_Inp12_Line_0dB:
+               return 3;
+       case HDSP_RPM_Inp12_Line_n6dB:
+               return 4;
+       }
+       return 1;
+}
+
+
+static int snd_hdsp_get_rpm_input12(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.enumerated.item[0] = hdsp_rpm_input12(hdsp);
+       return 0;
+}
+
+
+static int hdsp_set_rpm_input12(struct hdsp *hdsp, int mode)
+{
+       hdsp->control_register &= ~HDSP_RPM_Inp12;
+       switch (mode) {
+       case 0:
+               hdsp->control_register |= HDSP_RPM_Inp12_Phon_6dB;
+               break;
+       case 1:
+               break;
+       case 2:
+               hdsp->control_register |= HDSP_RPM_Inp12_Phon_n6dB;
+               break;
+       case 3:
+               hdsp->control_register |= HDSP_RPM_Inp12_Line_0dB;
+               break;
+       case 4:
+               hdsp->control_register |= HDSP_RPM_Inp12_Line_n6dB;
+               break;
+       default:
+               return -1;
+       }
+
+       hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
+       return 0;
+}
+
+
+static int snd_hdsp_put_rpm_input12(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
+       int change;
+       int val;
+
+       if (!snd_hdsp_use_is_exclusive(hdsp))
+               return -EBUSY;
+       val = ucontrol->value.enumerated.item[0];
+       if (val < 0)
+               val = 0;
+       if (val > 4)
+               val = 4;
+       spin_lock_irq(&hdsp->lock);
+       if (val != hdsp_rpm_input12(hdsp))
+               change = (hdsp_set_rpm_input12(hdsp, val) == 0) ? 1 : 0;
+       else
+               change = 0;
+       spin_unlock_irq(&hdsp->lock);
+       return change;
+}
+
+
+static int snd_hdsp_info_rpm_input(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[] = {"Phono +6dB", "Phono 0dB", "Phono -6dB", "Line 0dB", "Line -6dB"};
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 5;
+       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+               uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+
+static int hdsp_rpm_input34(struct hdsp *hdsp)
+{
+       switch (hdsp->control_register & HDSP_RPM_Inp34) {
+       case HDSP_RPM_Inp34_Phon_6dB:
+               return 0;
+       case HDSP_RPM_Inp34_Phon_n6dB:
+               return 2;
+       case HDSP_RPM_Inp34_Line_0dB:
+               return 3;
+       case HDSP_RPM_Inp34_Line_n6dB:
+               return 4;
+       }
+       return 1;
+}
+
+
+static int snd_hdsp_get_rpm_input34(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.enumerated.item[0] = hdsp_rpm_input34(hdsp);
+       return 0;
+}
+
+
+static int hdsp_set_rpm_input34(struct hdsp *hdsp, int mode)
+{
+       hdsp->control_register &= ~HDSP_RPM_Inp34;
+       switch (mode) {
+       case 0:
+               hdsp->control_register |= HDSP_RPM_Inp34_Phon_6dB;
+               break;
+       case 1:
+               break;
+       case 2:
+               hdsp->control_register |= HDSP_RPM_Inp34_Phon_n6dB;
+               break;
+       case 3:
+               hdsp->control_register |= HDSP_RPM_Inp34_Line_0dB;
+               break;
+       case 4:
+               hdsp->control_register |= HDSP_RPM_Inp34_Line_n6dB;
+               break;
+       default:
+               return -1;
+       }
+
+       hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
+       return 0;
+}
+
+
+static int snd_hdsp_put_rpm_input34(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
+       int change;
+       int val;
+
+       if (!snd_hdsp_use_is_exclusive(hdsp))
+               return -EBUSY;
+       val = ucontrol->value.enumerated.item[0];
+       if (val < 0)
+               val = 0;
+       if (val > 4)
+               val = 4;
+       spin_lock_irq(&hdsp->lock);
+       if (val != hdsp_rpm_input34(hdsp))
+               change = (hdsp_set_rpm_input34(hdsp, val) == 0) ? 1 : 0;
+       else
+               change = 0;
+       spin_unlock_irq(&hdsp->lock);
+       return change;
+}
+
+
+/* RPM Bypass switch */
+static int hdsp_rpm_bypass(struct hdsp *hdsp)
+{
+       return (hdsp->control_register & HDSP_RPM_Bypass) ? 1 : 0;
+}
+
+
+static int snd_hdsp_get_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = hdsp_rpm_bypass(hdsp);
+       return 0;
+}
+
+
+static int hdsp_set_rpm_bypass(struct hdsp *hdsp, int on)
+{
+       if (on)
+               hdsp->control_register |= HDSP_RPM_Bypass;
+       else
+               hdsp->control_register &= ~HDSP_RPM_Bypass;
+       hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
+       return 0;
+}
+
+
+static int snd_hdsp_put_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
+       int change;
+       unsigned int val;
+
+       if (!snd_hdsp_use_is_exclusive(hdsp))
+               return -EBUSY;
+       val = ucontrol->value.integer.value[0] & 1;
+       spin_lock_irq(&hdsp->lock);
+       change = (int)val != hdsp_rpm_bypass(hdsp);
+       hdsp_set_rpm_bypass(hdsp, val);
+       spin_unlock_irq(&hdsp->lock);
+       return change;
+}
+
+
+static int snd_hdsp_info_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[] = {"On", "Off"};
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 2;
+       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+               uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+
+/* RPM Disconnect switch */
+static int hdsp_rpm_disconnect(struct hdsp *hdsp)
+{
+       return (hdsp->control_register & HDSP_RPM_Disconnect) ? 1 : 0;
+}
+
+
+static int snd_hdsp_get_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = hdsp_rpm_disconnect(hdsp);
+       return 0;
+}
+
+
+static int hdsp_set_rpm_disconnect(struct hdsp *hdsp, int on)
+{
+       if (on)
+               hdsp->control_register |= HDSP_RPM_Disconnect;
+       else
+               hdsp->control_register &= ~HDSP_RPM_Disconnect;
+       hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register);
+       return 0;
+}
+
+
+static int snd_hdsp_put_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
+       int change;
+       unsigned int val;
+
+       if (!snd_hdsp_use_is_exclusive(hdsp))
+               return -EBUSY;
+       val = ucontrol->value.integer.value[0] & 1;
+       spin_lock_irq(&hdsp->lock);
+       change = (int)val != hdsp_rpm_disconnect(hdsp);
+       hdsp_set_rpm_disconnect(hdsp, val);
+       spin_unlock_irq(&hdsp->lock);
+       return change;
+}
+
+static int snd_hdsp_info_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[] = {"On", "Off"};
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 2;
+       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+               uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+       strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static struct snd_kcontrol_new snd_hdsp_rpm_controls[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "RPM Bypass",
+               .get = snd_hdsp_get_rpm_bypass,
+               .put = snd_hdsp_put_rpm_bypass,
+               .info = snd_hdsp_info_rpm_bypass
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "RPM Disconnect",
+               .get = snd_hdsp_get_rpm_disconnect,
+               .put = snd_hdsp_put_rpm_disconnect,
+               .info = snd_hdsp_info_rpm_disconnect
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Input 1/2",
+               .get = snd_hdsp_get_rpm_input12,
+               .put = snd_hdsp_put_rpm_input12,
+               .info = snd_hdsp_info_rpm_input
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Input 3/4",
+               .get = snd_hdsp_get_rpm_input34,
+               .put = snd_hdsp_put_rpm_input34,
+               .info = snd_hdsp_info_rpm_input
+       },
+       HDSP_SYSTEM_SAMPLE_RATE("System Sample Rate", 0),
+       HDSP_MIXER("Mixer", 0)
+};
+
 static struct snd_kcontrol_new snd_hdsp_96xx_aeb = HDSP_AEB("Analog Extension Board", 0);
 static struct snd_kcontrol_new snd_hdsp_adat_sync_check = HDSP_ADAT_SYNC_CHECK;
 
@@ -3240,6 +3580,16 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp)
        int err;
        struct snd_kcontrol *kctl;
 
+       if (hdsp->io_type == RPM) {
+               /* RPM Bypass, Disconnect and Input switches */
+               for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_rpm_controls); idx++) {
+                       err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_rpm_controls[idx], hdsp));
+                       if (err < 0)
+                               return err;
+               }
+               return 0;
+       }
+
        for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_controls); idx++) {
                if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_controls[idx], hdsp))) < 0)
                        return err;
@@ -3459,48 +3809,102 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 
        snd_iprintf(buffer, "\n");
 
-       switch (hdsp_spdif_in(hdsp)) {
-       case HDSP_SPDIFIN_OPTICAL:
-               snd_iprintf(buffer, "IEC958 input: Optical\n");
-               break;
-       case HDSP_SPDIFIN_COAXIAL:
-               snd_iprintf(buffer, "IEC958 input: Coaxial\n");
-               break;
-       case HDSP_SPDIFIN_INTERNAL:
-               snd_iprintf(buffer, "IEC958 input: Internal\n");
-               break;
-       case HDSP_SPDIFIN_AES:
-               snd_iprintf(buffer, "IEC958 input: AES\n");
-               break;
-       default:
-               snd_iprintf(buffer, "IEC958 input: ???\n");
-               break;
+       if (hdsp->io_type != RPM) {
+               switch (hdsp_spdif_in(hdsp)) {
+               case HDSP_SPDIFIN_OPTICAL:
+                       snd_iprintf(buffer, "IEC958 input: Optical\n");
+                       break;
+               case HDSP_SPDIFIN_COAXIAL:
+                       snd_iprintf(buffer, "IEC958 input: Coaxial\n");
+                       break;
+               case HDSP_SPDIFIN_INTERNAL:
+                       snd_iprintf(buffer, "IEC958 input: Internal\n");
+                       break;
+               case HDSP_SPDIFIN_AES:
+                       snd_iprintf(buffer, "IEC958 input: AES\n");
+                       break;
+               default:
+                       snd_iprintf(buffer, "IEC958 input: ???\n");
+                       break;
+               }
        }
 
-       if (hdsp->control_register & HDSP_SPDIFOpticalOut)
-               snd_iprintf(buffer, "IEC958 output: Coaxial & ADAT1\n");
-       else
-               snd_iprintf(buffer, "IEC958 output: Coaxial only\n");
+       if (RPM == hdsp->io_type) {
+               if (hdsp->control_register & HDSP_RPM_Bypass)
+                       snd_iprintf(buffer, "RPM Bypass: disabled\n");
+               else
+                       snd_iprintf(buffer, "RPM Bypass: enabled\n");
+               if (hdsp->control_register & HDSP_RPM_Disconnect)
+                       snd_iprintf(buffer, "RPM disconnected\n");
+               else
+                       snd_iprintf(buffer, "RPM connected\n");
 
-       if (hdsp->control_register & HDSP_SPDIFProfessional)
-               snd_iprintf(buffer, "IEC958 quality: Professional\n");
-       else
-               snd_iprintf(buffer, "IEC958 quality: Consumer\n");
+               switch (hdsp->control_register & HDSP_RPM_Inp12) {
+               case HDSP_RPM_Inp12_Phon_6dB:
+                       snd_iprintf(buffer, "Input 1/2: Phono, 6dB\n");
+                       break;
+               case HDSP_RPM_Inp12_Phon_0dB:
+                       snd_iprintf(buffer, "Input 1/2: Phono, 0dB\n");
+                       break;
+               case HDSP_RPM_Inp12_Phon_n6dB:
+                       snd_iprintf(buffer, "Input 1/2: Phono, -6dB\n");
+                       break;
+               case HDSP_RPM_Inp12_Line_0dB:
+                       snd_iprintf(buffer, "Input 1/2: Line, 0dB\n");
+                       break;
+               case HDSP_RPM_Inp12_Line_n6dB:
+                       snd_iprintf(buffer, "Input 1/2: Line, -6dB\n");
+                       break;
+               default:
+                       snd_iprintf(buffer, "Input 1/2: ???\n");
+               }
 
-       if (hdsp->control_register & HDSP_SPDIFEmphasis)
-               snd_iprintf(buffer, "IEC958 emphasis: on\n");
-       else
-               snd_iprintf(buffer, "IEC958 emphasis: off\n");
+               switch (hdsp->control_register & HDSP_RPM_Inp34) {
+               case HDSP_RPM_Inp34_Phon_6dB:
+                       snd_iprintf(buffer, "Input 3/4: Phono, 6dB\n");
+                       break;
+               case HDSP_RPM_Inp34_Phon_0dB:
+                       snd_iprintf(buffer, "Input 3/4: Phono, 0dB\n");
+                       break;
+               case HDSP_RPM_Inp34_Phon_n6dB:
+                       snd_iprintf(buffer, "Input 3/4: Phono, -6dB\n");
+                       break;
+               case HDSP_RPM_Inp34_Line_0dB:
+                       snd_iprintf(buffer, "Input 3/4: Line, 0dB\n");
+                       break;
+               case HDSP_RPM_Inp34_Line_n6dB:
+                       snd_iprintf(buffer, "Input 3/4: Line, -6dB\n");
+                       break;
+               default:
+                       snd_iprintf(buffer, "Input 3/4: ???\n");
+               }
 
-       if (hdsp->control_register & HDSP_SPDIFNonAudio)
-               snd_iprintf(buffer, "IEC958 NonAudio: on\n");
-       else
-               snd_iprintf(buffer, "IEC958 NonAudio: off\n");
-       if ((x = hdsp_spdif_sample_rate (hdsp)) != 0)
-               snd_iprintf (buffer, "IEC958 sample rate: %d\n", x);
-       else
-               snd_iprintf (buffer, "IEC958 sample rate: Error flag set\n");
+       } else {
+               if (hdsp->control_register & HDSP_SPDIFOpticalOut)
+                       snd_iprintf(buffer, "IEC958 output: Coaxial & ADAT1\n");
+               else
+                       snd_iprintf(buffer, "IEC958 output: Coaxial only\n");
+
+               if (hdsp->control_register & HDSP_SPDIFProfessional)
+                       snd_iprintf(buffer, "IEC958 quality: Professional\n");
+               else
+                       snd_iprintf(buffer, "IEC958 quality: Consumer\n");
+
+               if (hdsp->control_register & HDSP_SPDIFEmphasis)
+                       snd_iprintf(buffer, "IEC958 emphasis: on\n");
+               else
+                       snd_iprintf(buffer, "IEC958 emphasis: off\n");
 
+               if (hdsp->control_register & HDSP_SPDIFNonAudio)
+                       snd_iprintf(buffer, "IEC958 NonAudio: on\n");
+               else
+                       snd_iprintf(buffer, "IEC958 NonAudio: off\n");
+               x = hdsp_spdif_sample_rate(hdsp);
+               if (x != 0)
+                       snd_iprintf(buffer, "IEC958 sample rate: %d\n", x);
+               else
+                       snd_iprintf(buffer, "IEC958 sample rate: Error flag set\n");
+       }
        snd_iprintf(buffer, "\n");
 
        /* Sync Check */
@@ -3765,7 +4169,7 @@ static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id)
                        snd_hdsp_midi_input_read (&hdsp->midi[0]);
                }
        }
-       if (hdsp->io_type != Multiface && hdsp->io_type != H9632 && midi1 && midi1status) {
+       if (hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632 && midi1 && midi1status) {
                if (hdsp->use_midi_tasklet) {
                        /* we disable interrupts for this input until processing is done */
                        hdsp->control_register &= ~HDSP_Midi1InterruptEnable;
@@ -4093,7 +4497,7 @@ static struct snd_pcm_hardware snd_hdsp_playback_subinfo =
                                 SNDRV_PCM_RATE_96000),
        .rate_min =             32000,
        .rate_max =             96000,
-       .channels_min =         14,
+       .channels_min =         6,
        .channels_max =         HDSP_MAX_CHANNELS,
        .buffer_bytes_max =     HDSP_CHANNEL_BUFFER_BYTES * HDSP_MAX_CHANNELS,
        .period_bytes_min =     (64 * 4) * 10,
@@ -4122,7 +4526,7 @@ static struct snd_pcm_hardware snd_hdsp_capture_subinfo =
                                 SNDRV_PCM_RATE_96000),
        .rate_min =             32000,
        .rate_max =             96000,
-       .channels_min =         14,
+       .channels_min =         5,
        .channels_max =         HDSP_MAX_CHANNELS,
        .buffer_bytes_max =     HDSP_CHANNEL_BUFFER_BYTES * HDSP_MAX_CHANNELS,
        .period_bytes_min =     (64 * 4) * 10,
@@ -4357,10 +4761,12 @@ static int snd_hdsp_playback_open(struct snd_pcm_substream *substream)
                             snd_hdsp_hw_rule_rate_out_channels, hdsp,
                             SNDRV_PCM_HW_PARAM_CHANNELS, -1);
 
-       hdsp->creg_spdif_stream = hdsp->creg_spdif;
-       hdsp->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
-       snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE |
-                      SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id);
+       if (RPM != hdsp->io_type) {
+               hdsp->creg_spdif_stream = hdsp->creg_spdif;
+               hdsp->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+               snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE |
+                       SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id);
+       }
        return 0;
 }
 
@@ -4375,9 +4781,11 @@ static int snd_hdsp_playback_release(struct snd_pcm_substream *substream)
 
        spin_unlock_irq(&hdsp->lock);
 
-       hdsp->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
-       snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE |
-                      SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id);
+       if (RPM != hdsp->io_type) {
+               hdsp->spdif_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+               snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE |
+                       SNDRV_CTL_EVENT_MASK_INFO, &hdsp->spdif_ctl->id);
+       }
        return 0;
 }
 
@@ -4616,7 +5024,7 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
                if (hdsp->io_type != H9632)
                    info.adatsync_sync_check = (unsigned char)hdsp_adatsync_sync_check(hdsp);
                info.spdif_sync_check = (unsigned char)hdsp_spdif_sync_check(hdsp);
-               for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != H9632) ? 3 : 1); ++i)
+               for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632) ? 3 : 1); ++i)
                        info.adat_sync_check[i] = (unsigned char)hdsp_adat_sync_check(hdsp, i);
                info.spdif_in = (unsigned char)hdsp_spdif_in(hdsp);
                info.spdif_out = (unsigned char)hdsp_spdif_out(hdsp);
@@ -4636,6 +5044,9 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
                        info.phone_gain = (unsigned char)hdsp_phone_gain(hdsp);
                        info.xlr_breakout_cable = (unsigned char)hdsp_xlr_breakout_cable(hdsp);
 
+               } else if (hdsp->io_type == RPM) {
+                       info.da_gain = (unsigned char) hdsp_rpm_input12(hdsp);
+                       info.ad_gain = (unsigned char) hdsp_rpm_input34(hdsp);
                }
                if (hdsp->io_type == H9632 || hdsp->io_type == H9652)
                        info.analog_extension_board = (unsigned char)hdsp_aeb(hdsp);
@@ -4844,6 +5255,14 @@ static void snd_hdsp_initialize_channels(struct hdsp *hdsp)
                hdsp->ds_in_channels = hdsp->ds_out_channels = MULTIFACE_DS_CHANNELS;
                break;
 
+       case RPM:
+               hdsp->card_name = "RME Hammerfall DSP + RPM";
+               hdsp->ss_in_channels = RPM_CHANNELS-1;
+               hdsp->ss_out_channels = RPM_CHANNELS;
+               hdsp->ds_in_channels = RPM_CHANNELS-1;
+               hdsp->ds_out_channels = RPM_CHANNELS;
+               break;
+
        default:
                /* should never get here */
                break;
@@ -4930,6 +5349,9 @@ static int hdsp_request_fw_loader(struct hdsp *hdsp)
 
        /* caution: max length of firmware filename is 30! */
        switch (hdsp->io_type) {
+       case RPM:
+               fwfile = "rpm_firmware.bin";
+               break;
        case Multiface:
                if (hdsp->firmware_rev == 0xa)
                        fwfile = "multiface_firmware.bin";
@@ -5100,7 +5522,9 @@ static int __devinit snd_hdsp_create(struct snd_card *card,
                        return 0;
                } else {
                        snd_printk(KERN_INFO "Hammerfall-DSP: Firmware already present, initializing card.\n");
-                       if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
+                       if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2)
+                               hdsp->io_type = RPM;
+                       else if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1)
                                hdsp->io_type = Multiface;
                        else
                                hdsp->io_type = Digiface;
index 5518371..c94c051 100644 (file)
@@ -1389,15 +1389,9 @@ static struct snd_kcontrol_new snd_ymfpci_spdif_stream __devinitdata =
 
 static int snd_ymfpci_drec_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info)
 {
-       static char *texts[3] = {"AC'97", "IEC958", "ZV Port"};
-
-       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       info->count = 1;
-       info->value.enumerated.items = 3;
-       if (info->value.enumerated.item > 2)
-               info->value.enumerated.item = 2;
-       strcpy(info->value.enumerated.name, texts[info->value.enumerated.item]);
-       return 0;
+       static const char *const texts[3] = {"AC'97", "IEC958", "ZV Port"};
+
+       return snd_ctl_enum_info(info, 1, 3, texts);
 }
 
 static int snd_ymfpci_drec_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value)
index 3e598e7..a3efc52 100644 (file)
@@ -20,6 +20,21 @@ menuconfig SND_SOC
 
 if SND_SOC
 
+config SND_SOC_CACHE_LZO
+       bool "Support LZO compression for register caches"
+       select LZO_COMPRESS
+       select LZO_DECOMPRESS
+       ---help---
+          Select this to enable LZO compression for register caches.
+          This will allow machine or CODEC drivers to compress register
+          caches in memory, reducing the memory consumption at the
+          expense of performance.  If this is not present and is used
+          the system will fall back to uncompressed caches.
+
+          Usually it is safe to disable this option, where cache
+          compression in used the rbtree option will typically perform
+          better.
+
 config SND_SOC_AC97_BUS
        bool
 
@@ -36,7 +51,7 @@ source "sound/soc/nuc900/Kconfig"
 source "sound/soc/omap/Kconfig"
 source "sound/soc/kirkwood/Kconfig"
 source "sound/soc/pxa/Kconfig"
-source "sound/soc/s3c24xx/Kconfig"
+source "sound/soc/samsung/Kconfig"
 source "sound/soc/s6000/Kconfig"
 source "sound/soc/sh/Kconfig"
 source "sound/soc/txx9/Kconfig"
index eb18344..ce913bf 100644 (file)
@@ -14,7 +14,7 @@ obj-$(CONFIG_SND_SOC) += nuc900/
 obj-$(CONFIG_SND_SOC)  += omap/
 obj-$(CONFIG_SND_SOC)  += kirkwood/
 obj-$(CONFIG_SND_SOC)  += pxa/
-obj-$(CONFIG_SND_SOC)  += s3c24xx/
+obj-$(CONFIG_SND_SOC)  += samsung/
 obj-$(CONFIG_SND_SOC)  += s6000/
 obj-$(CONFIG_SND_SOC)  += sh/
 obj-$(CONFIG_SND_SOC)  += txx9/
index 5f4e59f..1aac2f4 100644 (file)
@@ -33,7 +33,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <mach/at32ap700x.h>
 #include <mach/portmux.h>
@@ -318,27 +317,28 @@ static const struct snd_soc_dapm_route intercon[] = {
 static int playpaq_wm8510_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int i;
 
        /*
         * Add DAPM widgets
         */
        for (i = 0; i < ARRAY_SIZE(playpaq_dapm_widgets); i++)
-               snd_soc_dapm_new_control(codec, &playpaq_dapm_widgets[i]);
+               snd_soc_dapm_new_control(dapm, &playpaq_dapm_widgets[i]);
 
 
 
        /*
         * Setup audio path interconnects
         */
-       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
 
 
 
        /* always connected pins */
-       snd_soc_dapm_enable_pin(codec, "Int Mic");
-       snd_soc_dapm_enable_pin(codec, "Ext Spk");
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_enable_pin(dapm, "Int Mic");
+       snd_soc_dapm_enable_pin(dapm, "Ext Spk");
+       snd_soc_dapm_sync(dapm);
 
 
 
index e521ada..af3c730 100644 (file)
@@ -44,7 +44,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
@@ -140,6 +139,7 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
        printk(KERN_DEBUG
@@ -154,25 +154,25 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
        }
 
        /* Add specific widgets */
-       snd_soc_dapm_new_controls(codec, at91sam9g20ek_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, at91sam9g20ek_dapm_widgets,
                                  ARRAY_SIZE(at91sam9g20ek_dapm_widgets));
        /* Set up specific audio path interconnects */
-       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
 
        /* not connected */
-       snd_soc_dapm_nc_pin(codec, "RLINEIN");
-       snd_soc_dapm_nc_pin(codec, "LLINEIN");
+       snd_soc_dapm_nc_pin(dapm, "RLINEIN");
+       snd_soc_dapm_nc_pin(dapm, "LLINEIN");
 
 #ifdef ENABLE_MIC_INPUT
-       snd_soc_dapm_enable_pin(codec, "Int Mic");
+       snd_soc_dapm_enable_pin(dapm, "Int Mic");
 #else
-       snd_soc_dapm_nc_pin(codec, "Int Mic");
+       snd_soc_dapm_nc_pin(dapm, "Int Mic");
 #endif
 
        /* always connected */
-       snd_soc_dapm_enable_pin(codec, "Ext Spk");
+       snd_soc_dapm_enable_pin(dapm, "Ext Spk");
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
 
        return 0;
 }
index 86e0f85..da2208e 100644 (file)
@@ -30,7 +30,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
@@ -105,19 +104,20 @@ static const struct snd_soc_dapm_route audio_map[] = {
 static int afeb9260_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
        /* Add afeb9260 specific widgets */
-       snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets,
                                  ARRAY_SIZE(tlv320aic23_dapm_widgets));
 
        /* Set up afeb9260 specific audio path audio_map */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_enable_pin(codec, "Headphone Jack");
-       snd_soc_dapm_enable_pin(codec, "Line In");
-       snd_soc_dapm_enable_pin(codec, "Mic Jack");
+       snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+       snd_soc_dapm_enable_pin(dapm, "Line In");
+       snd_soc_dapm_enable_pin(dapm, "Mic Jack");
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
 
        return 0;
 }
index b62fcd3..cb99f04 100644 (file)
@@ -13,7 +13,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-au1x00/au1xxx_psc.h>
 #include <asm/mach-au1x00/au1xxx_dbdma.h>
index 2394bff..83012da 100644 (file)
@@ -20,7 +20,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/pcm_params.h>
 
 #include <asm/blackfin.h>
index e4a6253..d3ccb92 100644 (file)
@@ -29,7 +29,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/pcm_params.h>
 
 #include <asm/blackfin.h>
index 900ced5..732fb8b 100644 (file)
@@ -35,7 +35,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/pcm_params.h>
 
 #include <asm/blackfin.h>
index 36f2769..e902b24 100644 (file)
@@ -33,7 +33,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/pcm_params.h>
 
 #include <asm/dma.h>
index 01d19e9..06b6981 100644 (file)
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/tlv.h>
 #include <sound/initval.h>
 #include <sound/jack.h>
+#include <trace/events/asoc.h>
 
 #include "88pm860x-codec.h"
 
@@ -146,7 +146,6 @@ struct pm860x_priv {
 
        int                     irq[4];
        unsigned char           name[4][MAX_NAME_LEN];
-       unsigned char           reg_cache[REG_CACHE_SIZE];
 };
 
 /* -9450dB to 0dB in 150dB steps ( mute instead of -9450dB) */
@@ -1172,7 +1171,7 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        /* Enable Audio PLL & Audio section */
                        data = AUDIO_PLL | AUDIO_SECTION_RESET
                                | AUDIO_SECTION_ON;
@@ -1185,7 +1184,7 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec,
                pm860x_set_bits(codec->control_data, REG_MISC2, data, 0);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -1263,6 +1262,12 @@ static irqreturn_t pm860x_codec_handler(int irq, void *data)
        mask = pm860x->det.hs_shrt | pm860x->det.hook_det | pm860x->det.lo_shrt
                | pm860x->det.hp_det;
 
+#ifndef CONFIG_SND_SOC_88PM860X_MODULE
+       if (status & (HEADSET_STATUS | MIC_STATUS | SHORT_HS1 | SHORT_HS2 |
+                     SHORT_LO1 | SHORT_LO2))
+               trace_snd_soc_jack_irq(dev_name(pm860x->codec->dev));
+#endif
+
        if ((pm860x->det.hp_det & SND_JACK_HEADPHONE)
                && (status & HEADSET_STATUS))
                report |= SND_JACK_HEADPHONE;
@@ -1346,6 +1351,7 @@ EXPORT_SYMBOL_GPL(pm860x_mic_jack_detect);
 static int pm860x_probe(struct snd_soc_codec *codec)
 {
        struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int i, ret;
 
        pm860x->codec = codec;
@@ -1358,7 +1364,7 @@ static int pm860x_probe(struct snd_soc_codec *codec)
                                           pm860x->name[i], pm860x);
                if (ret < 0) {
                        dev_err(codec->dev, "Failed to request IRQ!\n");
-                       goto out_irq;
+                       goto out;
                }
        }
 
@@ -1369,22 +1375,20 @@ static int pm860x_probe(struct snd_soc_codec *codec)
        if (ret < 0) {
                dev_err(codec->dev, "Failed to fill register cache: %d\n",
                        ret);
-               goto out_codec;
+               goto out;
        }
 
        snd_soc_add_controls(codec, pm860x_snd_controls,
                             ARRAY_SIZE(pm860x_snd_controls));
-       snd_soc_dapm_new_controls(codec, pm860x_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, pm860x_dapm_widgets,
                                  ARRAY_SIZE(pm860x_dapm_widgets));
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
        return 0;
 
-out_codec:
-       i = 3;
-out_irq:
-       for (; i >= 0; i--)
+out:
+       while (--i >= 0)
                free_irq(pm860x->irq[i], pm860x);
-       return -EINVAL;
+       return ret;
 }
 
 static int pm860x_remove(struct snd_soc_codec *codec)
index 3b5690d..883a312 100644 (file)
@@ -22,6 +22,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_AK4535 if I2C
        select SND_SOC_AK4642 if I2C
        select SND_SOC_AK4671 if I2C
+       select SND_SOC_ALC5623 if I2C
        select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
        select SND_SOC_CS42L51 if I2C
        select SND_SOC_CS4270 if I2C
@@ -54,9 +55,11 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8727
        select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI
+       select SND_SOC_WM8737 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8741 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
+       select SND_SOC_WM8770 if SPI_MASTER
        select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8900 if I2C
@@ -75,6 +78,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8990 if I2C
        select SND_SOC_WM8993 if I2C
        select SND_SOC_WM8994 if MFD_WM8994
+       select SND_SOC_WM8995 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM9081 if I2C
        select SND_SOC_WM9090 if I2C
        select SND_SOC_WM9705 if SND_SOC_AC97_BUS
@@ -130,6 +134,9 @@ config SND_SOC_AK4642
 config SND_SOC_AK4671
        tristate
 
+config SND_SOC_ALC5623
+       tristate
+
 config SND_SOC_CQ0093VC
        tristate
 
@@ -160,6 +167,9 @@ config SND_SOC_L3
 config SND_SOC_DA7210
         tristate
 
+config SND_SOC_DMIC
+       tristate
+
 config SND_SOC_MAX98088
        tristate
 
@@ -231,6 +241,9 @@ config SND_SOC_WM8728
 config SND_SOC_WM8731
        tristate
 
+config SND_SOC_WM8737
+       tristate
+
 config SND_SOC_WM8741
        tristate
 
@@ -240,6 +253,9 @@ config SND_SOC_WM8750
 config SND_SOC_WM8753
        tristate
 
+config SND_SOC_WM8770
+       tristate
+
 config SND_SOC_WM8776
        tristate
 
@@ -294,6 +310,9 @@ config SND_SOC_WM8993
 config SND_SOC_WM8994
        tristate
 
+config SND_SOC_WM8995
+       tristate
+
 config SND_SOC_WM9081
        tristate
 
@@ -318,3 +337,4 @@ config SND_SOC_WM2000
 
 config SND_SOC_WM9090
        tristate
+
index f67a2d6..579af9c 100644 (file)
@@ -14,9 +14,11 @@ snd-soc-cs42l51-objs := cs42l51.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-cx20442-objs := cx20442.o
 snd-soc-da7210-objs := da7210.o
+snd-soc-dmic-objs := dmic.o
 snd-soc-l3-objs := l3.o
 snd-soc-max98088-objs := max98088.o
 snd-soc-pcm3008-objs := pcm3008.o
+snd-soc-alc5623-objs := alc5623.o
 snd-soc-spdif-objs := spdif_transciever.o
 snd-soc-ssm2602-objs := ssm2602.o
 snd-soc-stac9766-objs := stac9766.o
@@ -38,9 +40,11 @@ snd-soc-wm8711-objs := wm8711.o
 snd-soc-wm8727-objs := wm8727.o
 snd-soc-wm8728-objs := wm8728.o
 snd-soc-wm8731-objs := wm8731.o
+snd-soc-wm8737-objs := wm8737.o
 snd-soc-wm8741-objs := wm8741.o
 snd-soc-wm8750-objs := wm8750.o
 snd-soc-wm8753-objs := wm8753.o
+snd-soc-wm8770-objs := wm8770.o
 snd-soc-wm8776-objs := wm8776.o
 snd-soc-wm8804-objs := wm8804.o
 snd-soc-wm8900-objs := wm8900.o
@@ -58,7 +62,8 @@ snd-soc-wm8985-objs := wm8985.o
 snd-soc-wm8988-objs := wm8988.o
 snd-soc-wm8990-objs := wm8990.o
 snd-soc-wm8993-objs := wm8993.o
-snd-soc-wm8994-objs := wm8994.o
+snd-soc-wm8994-objs := wm8994.o wm8994-tables.o
+snd-soc-wm8995-objs := wm8995.o
 snd-soc-wm9081-objs := wm9081.o
 snd-soc-wm9705-objs := wm9705.o
 snd-soc-wm9712-objs := wm9712.o
@@ -88,10 +93,12 @@ obj-$(CONFIG_SND_SOC_CS42L51)       += snd-soc-cs42l51.o
 obj-$(CONFIG_SND_SOC_CS4270)   += snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_CX20442)  += snd-soc-cx20442.o
 obj-$(CONFIG_SND_SOC_DA7210)   += snd-soc-da7210.o
+obj-$(CONFIG_SND_SOC_DMIC)     += snd-soc-dmic.o
 obj-$(CONFIG_SND_SOC_L3)       += snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)     += snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
 obj-$(CONFIG_SND_SOC_PCM3008)  += snd-soc-pcm3008.o
+obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
 obj-$(CONFIG_SND_SOC_SPDIF)    += snd-soc-spdif.o
 obj-$(CONFIG_SND_SOC_SSM2602)  += snd-soc-ssm2602.o
 obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
@@ -113,9 +120,11 @@ obj-$(CONFIG_SND_SOC_WM8711)       += snd-soc-wm8711.o
 obj-$(CONFIG_SND_SOC_WM8727)   += snd-soc-wm8727.o
 obj-$(CONFIG_SND_SOC_WM8728)   += snd-soc-wm8728.o
 obj-$(CONFIG_SND_SOC_WM8731)   += snd-soc-wm8731.o
+obj-$(CONFIG_SND_SOC_WM8737)   += snd-soc-wm8737.o
 obj-$(CONFIG_SND_SOC_WM8741)   += snd-soc-wm8741.o
 obj-$(CONFIG_SND_SOC_WM8750)   += snd-soc-wm8750.o
 obj-$(CONFIG_SND_SOC_WM8753)   += snd-soc-wm8753.o
+obj-$(CONFIG_SND_SOC_WM8770)   += snd-soc-wm8770.o
 obj-$(CONFIG_SND_SOC_WM8776)   += snd-soc-wm8776.o
 obj-$(CONFIG_SND_SOC_WM8804)   += snd-soc-wm8804.o
 obj-$(CONFIG_SND_SOC_WM8900)   += snd-soc-wm8900.o
@@ -134,6 +143,7 @@ obj-$(CONFIG_SND_SOC_WM8988)        += snd-soc-wm8988.o
 obj-$(CONFIG_SND_SOC_WM8990)   += snd-soc-wm8990.o
 obj-$(CONFIG_SND_SOC_WM8993)   += snd-soc-wm8993.o
 obj-$(CONFIG_SND_SOC_WM8994)   += snd-soc-wm8994.o
+obj-$(CONFIG_SND_SOC_WM8995)   += snd-soc-wm8995.o
 obj-$(CONFIG_SND_SOC_WM9081)   += snd-soc-wm9081.o
 obj-$(CONFIG_SND_SOC_WM9705)   += snd-soc-wm9705.o
 obj-$(CONFIG_SND_SOC_WM9712)   += snd-soc-wm9712.o
index d272534..ab63d52 100644 (file)
@@ -27,7 +27,6 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 #include <sound/tlv.h>
-#include <sound/soc-dapm.h>
 #include <linux/spi/spi.h>
 #include "ad1836.h"
 
@@ -220,6 +219,7 @@ static struct snd_soc_dai_driver ad1836_dai = {
 static int ad1836_probe(struct snd_soc_codec *codec)
 {
        struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret = 0;
 
        codec->control_data = ad1836->control_data;
@@ -227,7 +227,6 @@ static int ad1836_probe(struct snd_soc_codec *codec)
        if (ret < 0) {
                dev_err(codec->dev, "failed to set cache I/O: %d\n",
                                ret);
-               kfree(ad1836);
                return ret;
        }
 
@@ -252,9 +251,9 @@ static int ad1836_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, ad1836_snd_controls,
                             ARRAY_SIZE(ad1836_snd_controls));
-       snd_soc_dapm_new_controls(codec, ad1836_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, ad1836_dapm_widgets,
                                  ARRAY_SIZE(ad1836_dapm_widgets));
-       snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
+       snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths));
 
        return ret;
 }
index fa2834c..da46479 100644 (file)
 #include <sound/initval.h>
 #include <sound/soc.h>
 #include <sound/tlv.h>
-#include <sound/soc-dapm.h>
 #include "ad193x.h"
 
 /* codec private data */
 struct ad193x_priv {
-       u8 reg_cache[AD193X_NUM_REGS];
        enum snd_soc_control_type bus_type;
        void *control_data;
        int sysclk;
@@ -353,6 +351,7 @@ static struct snd_soc_dai_driver ad193x_dai = {
 static int ad193x_probe(struct snd_soc_codec *codec)
 {
        struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
        codec->control_data = ad193x->control_data;
@@ -363,7 +362,6 @@ static int ad193x_probe(struct snd_soc_codec *codec)
        if (ret < 0) {
                dev_err(codec->dev, "failed to set cache I/O: %d\n",
                                ret);
-               kfree(ad193x);
                return ret;
        }
 
@@ -385,9 +383,9 @@ static int ad193x_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, ad193x_snd_controls,
                             ARRAY_SIZE(ad193x_snd_controls));
-       snd_soc_dapm_new_controls(codec, ad193x_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, ad193x_dapm_widgets,
                                  ARRAY_SIZE(ad193x_dapm_widgets));
-       snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
+       snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths));
 
        return ret;
 }
index 410ccd5..34cb51e 100644 (file)
@@ -29,7 +29,6 @@
 #include <sound/ac97_codec.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include "ad1980.h"
 
index cd88c8f..8b38739 100644 (file)
@@ -24,7 +24,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/initval.h>
 
 #include "ak4535.h"
@@ -290,10 +289,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int ak4535_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, ak4535_dapm_widgets,
-                                 ARRAY_SIZE(ak4535_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_new_controls(dapm, ak4535_dapm_widgets,
+                                 ARRAY_SIZE(ak4535_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
 }
@@ -366,9 +366,9 @@ static int ak4535_set_dai_fmt(struct snd_soc_dai *codec_dai,
 static int ak4535_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
-       u16 mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
+       u16 mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC);
        if (!mute)
-               ak4535_write(codec, AK4535_DAC, mute_reg);
+               ak4535_write(codec, AK4535_DAC, mute_reg & ~0x20);
        else
                ak4535_write(codec, AK4535_DAC, mute_reg | 0x20);
        return 0;
@@ -381,11 +381,11 @@ static int ak4535_set_bias_level(struct snd_soc_codec *codec,
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
-               ak4535_write(codec, AK4535_DAC, mute_reg);
+               mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC);
+               ak4535_write(codec, AK4535_DAC, mute_reg & ~0x20);
                break;
        case SND_SOC_BIAS_PREPARE:
-               mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
+               mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC);
                ak4535_write(codec, AK4535_DAC, mute_reg | 0x20);
                break;
        case SND_SOC_BIAS_STANDBY:
@@ -399,7 +399,7 @@ static int ak4535_set_bias_level(struct snd_soc_codec *codec,
                ak4535_write(codec, AK4535_PM1, i & (~0x80));
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index 90c90b7..f00eba3 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
-#include <sound/soc-dapm.h>
+#include <sound/soc.h>
 #include <sound/initval.h>
 #include <sound/tlv.h>
 
index 24f5f49..2ec75ab 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/initval.h>
 #include <sound/tlv.h>
 
@@ -28,7 +27,6 @@
 struct ak4671_priv {
        enum snd_soc_control_type control_type;
        void *control_data;
-       u8 reg_cache[AK4671_CACHEREGNUM];
 };
 
 /* ak4671 register cache & default register settings */
@@ -437,10 +435,11 @@ static const struct snd_soc_dapm_route intercon[] = {
 
 static int ak4671_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, ak4671_dapm_widgets,
-                                 ARRAY_SIZE(ak4671_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+       snd_soc_dapm_new_controls(dapm, ak4671_dapm_widgets,
+                                 ARRAY_SIZE(ak4671_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
 
        return 0;
 }
@@ -602,7 +601,7 @@ static int ak4671_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, 0x00);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c
new file mode 100644 (file)
index 0000000..4f377c9
--- /dev/null
@@ -0,0 +1,1117 @@
+/*
+ * alc5623.c  --  alc562[123] ALSA Soc Audio driver
+ *
+ * Copyright 2008 Realtek Microelectronics
+ * Author: flove <flove@realtek.com> Ethan <eku@marvell.com>
+ *
+ * Copyright 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ *
+ * Based on WM8753.c
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/tlv.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/alc5623.h>
+
+#include "alc5623.h"
+
+static int caps_charge = 2000;
+module_param(caps_charge, int, 0);
+MODULE_PARM_DESC(caps_charge, "ALC5623 cap charge time (msecs)");
+
+/* codec private data */
+struct alc5623_priv {
+       enum snd_soc_control_type control_type;
+       void *control_data;
+       struct mutex mutex;
+       u8 id;
+       unsigned int sysclk;
+       u16 reg_cache[ALC5623_VENDOR_ID2+2];
+       unsigned int add_ctrl;
+       unsigned int jack_det_ctrl;
+};
+
+static void alc5623_fill_cache(struct snd_soc_codec *codec)
+{
+       int i, step = codec->driver->reg_cache_step;
+       u16 *cache = codec->reg_cache;
+
+       /* not really efficient ... */
+       for (i = 0 ; i < codec->driver->reg_cache_size ; i += step)
+               cache[i] = codec->hw_read(codec, i);
+}
+
+static inline int alc5623_reset(struct snd_soc_codec *codec)
+{
+       return snd_soc_write(codec, ALC5623_RESET, 0);
+}
+
+static int amp_mixer_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       /* to power-on/off class-d amp generators/speaker */
+       /* need to write to 'index-46h' register :        */
+       /* so write index num (here 0x46) to reg 0x6a     */
+       /* and then 0xffff/0 to reg 0x6c                  */
+       snd_soc_write(w->codec, ALC5623_HID_CTRL_INDEX, 0x46);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_write(w->codec, ALC5623_HID_CTRL_DATA, 0xFFFF);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_write(w->codec, ALC5623_HID_CTRL_DATA, 0);
+               break;
+       }
+
+       return 0;
+}
+
+/*
+ * ALC5623 Controls
+ */
+
+static const DECLARE_TLV_DB_SCALE(vol_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(hp_tlv, -4650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(adc_rec_tlv, -1650, 150, 0);
+static const unsigned int boost_tlv[] = {
+       TLV_DB_RANGE_HEAD(3),
+       0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+       1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+       2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
+};
+static const DECLARE_TLV_DB_SCALE(dig_tlv, 0, 600, 0);
+
+static const struct snd_kcontrol_new rt5621_vol_snd_controls[] = {
+       SOC_DOUBLE_TLV("Speaker Playback Volume",
+                       ALC5623_SPK_OUT_VOL, 8, 0, 31, 1, hp_tlv),
+       SOC_DOUBLE("Speaker Playback Switch",
+                       ALC5623_SPK_OUT_VOL, 15, 7, 1, 1),
+       SOC_DOUBLE_TLV("Headphone Playback Volume",
+                       ALC5623_HP_OUT_VOL, 8, 0, 31, 1, hp_tlv),
+       SOC_DOUBLE("Headphone Playback Switch",
+                       ALC5623_HP_OUT_VOL, 15, 7, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5622_vol_snd_controls[] = {
+       SOC_DOUBLE_TLV("Speaker Playback Volume",
+                       ALC5623_SPK_OUT_VOL, 8, 0, 31, 1, hp_tlv),
+       SOC_DOUBLE("Speaker Playback Switch",
+                       ALC5623_SPK_OUT_VOL, 15, 7, 1, 1),
+       SOC_DOUBLE_TLV("Line Playback Volume",
+                       ALC5623_HP_OUT_VOL, 8, 0, 31, 1, hp_tlv),
+       SOC_DOUBLE("Line Playback Switch",
+                       ALC5623_HP_OUT_VOL, 15, 7, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5623_vol_snd_controls[] = {
+       SOC_DOUBLE_TLV("Line Playback Volume",
+                       ALC5623_SPK_OUT_VOL, 8, 0, 31, 1, hp_tlv),
+       SOC_DOUBLE("Line Playback Switch",
+                       ALC5623_SPK_OUT_VOL, 15, 7, 1, 1),
+       SOC_DOUBLE_TLV("Headphone Playback Volume",
+                       ALC5623_HP_OUT_VOL, 8, 0, 31, 1, hp_tlv),
+       SOC_DOUBLE("Headphone Playback Switch",
+                       ALC5623_HP_OUT_VOL, 15, 7, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5623_snd_controls[] = {
+       SOC_DOUBLE_TLV("Auxout Playback Volume",
+                       ALC5623_MONO_AUX_OUT_VOL, 8, 0, 31, 1, hp_tlv),
+       SOC_DOUBLE("Auxout Playback Switch",
+                       ALC5623_MONO_AUX_OUT_VOL, 15, 7, 1, 1),
+       SOC_DOUBLE_TLV("PCM Playback Volume",
+                       ALC5623_STEREO_DAC_VOL, 8, 0, 31, 1, vol_tlv),
+       SOC_DOUBLE_TLV("AuxI Capture Volume",
+                       ALC5623_AUXIN_VOL, 8, 0, 31, 1, vol_tlv),
+       SOC_DOUBLE_TLV("LineIn Capture Volume",
+                       ALC5623_LINE_IN_VOL, 8, 0, 31, 1, vol_tlv),
+       SOC_SINGLE_TLV("Mic1 Capture Volume",
+                       ALC5623_MIC_VOL, 8, 31, 1, vol_tlv),
+       SOC_SINGLE_TLV("Mic2 Capture Volume",
+                       ALC5623_MIC_VOL, 0, 31, 1, vol_tlv),
+       SOC_DOUBLE_TLV("Rec Capture Volume",
+                       ALC5623_ADC_REC_GAIN, 7, 0, 31, 0, adc_rec_tlv),
+       SOC_SINGLE_TLV("Mic 1 Boost Volume",
+                       ALC5623_MIC_CTRL, 10, 2, 0, boost_tlv),
+       SOC_SINGLE_TLV("Mic 2 Boost Volume",
+                       ALC5623_MIC_CTRL, 8, 2, 0, boost_tlv),
+       SOC_SINGLE_TLV("Digital Boost Volume",
+                       ALC5623_ADD_CTRL_REG, 4, 3, 0, dig_tlv),
+};
+
+/*
+ * DAPM Controls
+ */
+static const struct snd_kcontrol_new alc5623_hp_mixer_controls[] = {
+SOC_DAPM_SINGLE("LI2HP Playback Switch", ALC5623_LINE_IN_VOL, 15, 1, 1),
+SOC_DAPM_SINGLE("AUXI2HP Playback Switch", ALC5623_AUXIN_VOL, 15, 1, 1),
+SOC_DAPM_SINGLE("MIC12HP Playback Switch", ALC5623_MIC_ROUTING_CTRL, 15, 1, 1),
+SOC_DAPM_SINGLE("MIC22HP Playback Switch", ALC5623_MIC_ROUTING_CTRL, 7, 1, 1),
+SOC_DAPM_SINGLE("DAC2HP Playback Switch", ALC5623_STEREO_DAC_VOL, 15, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5623_hpl_mixer_controls[] = {
+SOC_DAPM_SINGLE("ADC2HP_L Playback Switch", ALC5623_ADC_REC_GAIN, 15, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5623_hpr_mixer_controls[] = {
+SOC_DAPM_SINGLE("ADC2HP_R Playback Switch", ALC5623_ADC_REC_GAIN, 14, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5623_mono_mixer_controls[] = {
+SOC_DAPM_SINGLE("ADC2MONO_L Playback Switch", ALC5623_ADC_REC_GAIN, 13, 1, 1),
+SOC_DAPM_SINGLE("ADC2MONO_R Playback Switch", ALC5623_ADC_REC_GAIN, 12, 1, 1),
+SOC_DAPM_SINGLE("LI2MONO Playback Switch", ALC5623_LINE_IN_VOL, 13, 1, 1),
+SOC_DAPM_SINGLE("AUXI2MONO Playback Switch", ALC5623_AUXIN_VOL, 13, 1, 1),
+SOC_DAPM_SINGLE("MIC12MONO Playback Switch", ALC5623_MIC_ROUTING_CTRL, 13, 1, 1),
+SOC_DAPM_SINGLE("MIC22MONO Playback Switch", ALC5623_MIC_ROUTING_CTRL, 5, 1, 1),
+SOC_DAPM_SINGLE("DAC2MONO Playback Switch", ALC5623_STEREO_DAC_VOL, 13, 1, 1),
+};
+
+static const struct snd_kcontrol_new alc5623_speaker_mixer_controls[] = {
+SOC_DAPM_SINGLE("LI2SPK Playback Switch", ALC5623_LINE_IN_VOL, 14, 1, 1),
+SOC_DAPM_SINGLE("AUXI2SPK Playback Switch", ALC5623_AUXIN_VOL, 14, 1, 1),
+SOC_DAPM_SINGLE("MIC12SPK Playback Switch", ALC5623_MIC_ROUTING_CTRL, 14, 1, 1),
+SOC_DAPM_SINGLE("MIC22SPK Playback Switch", ALC5623_MIC_ROUTING_CTRL, 6, 1, 1),
+SOC_DAPM_SINGLE("DAC2SPK Playback Switch", ALC5623_STEREO_DAC_VOL, 14, 1, 1),
+};
+
+/* Left Record Mixer */
+static const struct snd_kcontrol_new alc5623_captureL_mixer_controls[] = {
+SOC_DAPM_SINGLE("Mic1 Capture Switch", ALC5623_ADC_REC_MIXER, 14, 1, 1),
+SOC_DAPM_SINGLE("Mic2 Capture Switch", ALC5623_ADC_REC_MIXER, 13, 1, 1),
+SOC_DAPM_SINGLE("LineInL Capture Switch", ALC5623_ADC_REC_MIXER, 12, 1, 1),
+SOC_DAPM_SINGLE("Left AuxI Capture Switch", ALC5623_ADC_REC_MIXER, 11, 1, 1),
+SOC_DAPM_SINGLE("HPMixerL Capture Switch", ALC5623_ADC_REC_MIXER, 10, 1, 1),
+SOC_DAPM_SINGLE("SPKMixer Capture Switch", ALC5623_ADC_REC_MIXER, 9, 1, 1),
+SOC_DAPM_SINGLE("MonoMixer Capture Switch", ALC5623_ADC_REC_MIXER, 8, 1, 1),
+};
+
+/* Right Record Mixer */
+static const struct snd_kcontrol_new alc5623_captureR_mixer_controls[] = {
+SOC_DAPM_SINGLE("Mic1 Capture Switch", ALC5623_ADC_REC_MIXER, 6, 1, 1),
+SOC_DAPM_SINGLE("Mic2 Capture Switch", ALC5623_ADC_REC_MIXER, 5, 1, 1),
+SOC_DAPM_SINGLE("LineInR Capture Switch", ALC5623_ADC_REC_MIXER, 4, 1, 1),
+SOC_DAPM_SINGLE("Right AuxI Capture Switch", ALC5623_ADC_REC_MIXER, 3, 1, 1),
+SOC_DAPM_SINGLE("HPMixerR Capture Switch", ALC5623_ADC_REC_MIXER, 2, 1, 1),
+SOC_DAPM_SINGLE("SPKMixer Capture Switch", ALC5623_ADC_REC_MIXER, 1, 1, 1),
+SOC_DAPM_SINGLE("MonoMixer Capture Switch", ALC5623_ADC_REC_MIXER, 0, 1, 1),
+};
+
+static const char *alc5623_spk_n_sour_sel[] = {
+               "RN/-R", "RP/+R", "LN/-R", "Vmid" };
+static const char *alc5623_hpl_out_input_sel[] = {
+               "Vmid", "HP Left Mix"};
+static const char *alc5623_hpr_out_input_sel[] = {
+               "Vmid", "HP Right Mix"};
+static const char *alc5623_spkout_input_sel[] = {
+               "Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"};
+static const char *alc5623_aux_out_input_sel[] = {
+               "Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"};
+
+/* auxout output mux */
+static const struct soc_enum alc5623_aux_out_input_enum =
+SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 6, 4, alc5623_aux_out_input_sel);
+static const struct snd_kcontrol_new alc5623_auxout_mux_controls =
+SOC_DAPM_ENUM("Route", alc5623_aux_out_input_enum);
+
+/* speaker output mux */
+static const struct soc_enum alc5623_spkout_input_enum =
+SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 10, 4, alc5623_spkout_input_sel);
+static const struct snd_kcontrol_new alc5623_spkout_mux_controls =
+SOC_DAPM_ENUM("Route", alc5623_spkout_input_enum);
+
+/* headphone left output mux */
+static const struct soc_enum alc5623_hpl_out_input_enum =
+SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 9, 2, alc5623_hpl_out_input_sel);
+static const struct snd_kcontrol_new alc5623_hpl_out_mux_controls =
+SOC_DAPM_ENUM("Route", alc5623_hpl_out_input_enum);
+
+/* headphone right output mux */
+static const struct soc_enum alc5623_hpr_out_input_enum =
+SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 8, 2, alc5623_hpr_out_input_sel);
+static const struct snd_kcontrol_new alc5623_hpr_out_mux_controls =
+SOC_DAPM_ENUM("Route", alc5623_hpr_out_input_enum);
+
+/* speaker output N select */
+static const struct soc_enum alc5623_spk_n_sour_enum =
+SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 14, 4, alc5623_spk_n_sour_sel);
+static const struct snd_kcontrol_new alc5623_spkoutn_mux_controls =
+SOC_DAPM_ENUM("Route", alc5623_spk_n_sour_enum);
+
+static const struct snd_soc_dapm_widget alc5623_dapm_widgets[] = {
+/* Muxes */
+SND_SOC_DAPM_MUX("AuxOut Mux", SND_SOC_NOPM, 0, 0,
+       &alc5623_auxout_mux_controls),
+SND_SOC_DAPM_MUX("SpeakerOut Mux", SND_SOC_NOPM, 0, 0,
+       &alc5623_spkout_mux_controls),
+SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0,
+       &alc5623_hpl_out_mux_controls),
+SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0,
+       &alc5623_hpr_out_mux_controls),
+SND_SOC_DAPM_MUX("SpeakerOut N Mux", SND_SOC_NOPM, 0, 0,
+       &alc5623_spkoutn_mux_controls),
+
+/* output mixers */
+SND_SOC_DAPM_MIXER("HP Mix", SND_SOC_NOPM, 0, 0,
+       &alc5623_hp_mixer_controls[0],
+       ARRAY_SIZE(alc5623_hp_mixer_controls)),
+SND_SOC_DAPM_MIXER("HPR Mix", ALC5623_PWR_MANAG_ADD2, 4, 0,
+       &alc5623_hpr_mixer_controls[0],
+       ARRAY_SIZE(alc5623_hpr_mixer_controls)),
+SND_SOC_DAPM_MIXER("HPL Mix", ALC5623_PWR_MANAG_ADD2, 5, 0,
+       &alc5623_hpl_mixer_controls[0],
+       ARRAY_SIZE(alc5623_hpl_mixer_controls)),
+SND_SOC_DAPM_MIXER("HPOut Mix", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Mono Mix", ALC5623_PWR_MANAG_ADD2, 2, 0,
+       &alc5623_mono_mixer_controls[0],
+       ARRAY_SIZE(alc5623_mono_mixer_controls)),
+SND_SOC_DAPM_MIXER("Speaker Mix", ALC5623_PWR_MANAG_ADD2, 3, 0,
+       &alc5623_speaker_mixer_controls[0],
+       ARRAY_SIZE(alc5623_speaker_mixer_controls)),
+
+/* input mixers */
+SND_SOC_DAPM_MIXER("Left Capture Mix", ALC5623_PWR_MANAG_ADD2, 1, 0,
+       &alc5623_captureL_mixer_controls[0],
+       ARRAY_SIZE(alc5623_captureL_mixer_controls)),
+SND_SOC_DAPM_MIXER("Right Capture Mix", ALC5623_PWR_MANAG_ADD2, 0, 0,
+       &alc5623_captureR_mixer_controls[0],
+       ARRAY_SIZE(alc5623_captureR_mixer_controls)),
+
+SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback",
+       ALC5623_PWR_MANAG_ADD2, 9, 0),
+SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback",
+       ALC5623_PWR_MANAG_ADD2, 8, 0),
+SND_SOC_DAPM_MIXER("I2S Mix", ALC5623_PWR_MANAG_ADD1, 15, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("AuxI Mix", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("Line Mix", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture",
+       ALC5623_PWR_MANAG_ADD2, 7, 0),
+SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture",
+       ALC5623_PWR_MANAG_ADD2, 6, 0),
+SND_SOC_DAPM_PGA("Left Headphone", ALC5623_PWR_MANAG_ADD3, 10, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Headphone", ALC5623_PWR_MANAG_ADD3, 9, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SpeakerOut", ALC5623_PWR_MANAG_ADD3, 12, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Left AuxOut", ALC5623_PWR_MANAG_ADD3, 14, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right AuxOut", ALC5623_PWR_MANAG_ADD3, 13, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Left LineIn", ALC5623_PWR_MANAG_ADD3, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right LineIn", ALC5623_PWR_MANAG_ADD3, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Left AuxI", ALC5623_PWR_MANAG_ADD3, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right AuxI", ALC5623_PWR_MANAG_ADD3, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA("MIC1 PGA", ALC5623_PWR_MANAG_ADD3, 3, 0, NULL, 0),
+SND_SOC_DAPM_PGA("MIC2 PGA", ALC5623_PWR_MANAG_ADD3, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA("MIC1 Pre Amp", ALC5623_PWR_MANAG_ADD3, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA("MIC2 Pre Amp", ALC5623_PWR_MANAG_ADD3, 0, 0, NULL, 0),
+SND_SOC_DAPM_MICBIAS("Mic Bias1", ALC5623_PWR_MANAG_ADD1, 11, 0),
+
+SND_SOC_DAPM_OUTPUT("AUXOUTL"),
+SND_SOC_DAPM_OUTPUT("AUXOUTR"),
+SND_SOC_DAPM_OUTPUT("HPL"),
+SND_SOC_DAPM_OUTPUT("HPR"),
+SND_SOC_DAPM_OUTPUT("SPKOUT"),
+SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+SND_SOC_DAPM_INPUT("LINEINL"),
+SND_SOC_DAPM_INPUT("LINEINR"),
+SND_SOC_DAPM_INPUT("AUXINL"),
+SND_SOC_DAPM_INPUT("AUXINR"),
+SND_SOC_DAPM_INPUT("MIC1"),
+SND_SOC_DAPM_INPUT("MIC2"),
+SND_SOC_DAPM_VMID("Vmid"),
+};
+
+static const char *alc5623_amp_names[] = {"AB Amp", "D Amp"};
+static const struct soc_enum alc5623_amp_enum =
+       SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 13, 2, alc5623_amp_names);
+static const struct snd_kcontrol_new alc5623_amp_mux_controls =
+       SOC_DAPM_ENUM("Route", alc5623_amp_enum);
+
+static const struct snd_soc_dapm_widget alc5623_dapm_amp_widgets[] = {
+SND_SOC_DAPM_PGA_E("D Amp", ALC5623_PWR_MANAG_ADD2, 14, 0, NULL, 0,
+       amp_mixer_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_PGA("AB Amp", ALC5623_PWR_MANAG_ADD2, 15, 0, NULL, 0),
+SND_SOC_DAPM_MUX("AB-D Amp Mux", SND_SOC_NOPM, 0, 0,
+       &alc5623_amp_mux_controls),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+       /* virtual mixer - mixes left & right channels */
+       {"I2S Mix", NULL,                               "Left DAC"},
+       {"I2S Mix", NULL,                               "Right DAC"},
+       {"Line Mix", NULL,                              "Right LineIn"},
+       {"Line Mix", NULL,                              "Left LineIn"},
+       {"AuxI Mix", NULL,                              "Left AuxI"},
+       {"AuxI Mix", NULL,                              "Right AuxI"},
+       {"AUXOUTL", NULL,                               "Left AuxOut"},
+       {"AUXOUTR", NULL,                               "Right AuxOut"},
+
+       /* HP mixer */
+       {"HPL Mix", "ADC2HP_L Playback Switch",         "Left Capture Mix"},
+       {"HPL Mix", NULL,                               "HP Mix"},
+       {"HPR Mix", "ADC2HP_R Playback Switch",         "Right Capture Mix"},
+       {"HPR Mix", NULL,                               "HP Mix"},
+       {"HP Mix", "LI2HP Playback Switch",             "Line Mix"},
+       {"HP Mix", "AUXI2HP Playback Switch",           "AuxI Mix"},
+       {"HP Mix", "MIC12HP Playback Switch",           "MIC1 PGA"},
+       {"HP Mix", "MIC22HP Playback Switch",           "MIC2 PGA"},
+       {"HP Mix", "DAC2HP Playback Switch",            "I2S Mix"},
+
+       /* speaker mixer */
+       {"Speaker Mix", "LI2SPK Playback Switch",       "Line Mix"},
+       {"Speaker Mix", "AUXI2SPK Playback Switch",     "AuxI Mix"},
+       {"Speaker Mix", "MIC12SPK Playback Switch",     "MIC1 PGA"},
+       {"Speaker Mix", "MIC22SPK Playback Switch",     "MIC2 PGA"},
+       {"Speaker Mix", "DAC2SPK Playback Switch",      "I2S Mix"},
+
+       /* mono mixer */
+       {"Mono Mix", "ADC2MONO_L Playback Switch",      "Left Capture Mix"},
+       {"Mono Mix", "ADC2MONO_R Playback Switch",      "Right Capture Mix"},
+       {"Mono Mix", "LI2MONO Playback Switch",         "Line Mix"},
+       {"Mono Mix", "AUXI2MONO Playback Switch",       "AuxI Mix"},
+       {"Mono Mix", "MIC12MONO Playback Switch",       "MIC1 PGA"},
+       {"Mono Mix", "MIC22MONO Playback Switch",       "MIC2 PGA"},
+       {"Mono Mix", "DAC2MONO Playback Switch",        "I2S Mix"},
+
+       /* Left record mixer */
+       {"Left Capture Mix", "LineInL Capture Switch",  "LINEINL"},
+       {"Left Capture Mix", "Left AuxI Capture Switch", "AUXINL"},
+       {"Left Capture Mix", "Mic1 Capture Switch",     "MIC1 Pre Amp"},
+       {"Left Capture Mix", "Mic2 Capture Switch",     "MIC2 Pre Amp"},
+       {"Left Capture Mix", "HPMixerL Capture Switch", "HPL Mix"},
+       {"Left Capture Mix", "SPKMixer Capture Switch", "Speaker Mix"},
+       {"Left Capture Mix", "MonoMixer Capture Switch", "Mono Mix"},
+
+       /*Right record mixer */
+       {"Right Capture Mix", "LineInR Capture Switch", "LINEINR"},
+       {"Right Capture Mix", "Right AuxI Capture Switch",      "AUXINR"},
+       {"Right Capture Mix", "Mic1 Capture Switch",    "MIC1 Pre Amp"},
+       {"Right Capture Mix", "Mic2 Capture Switch",    "MIC2 Pre Amp"},
+       {"Right Capture Mix", "HPMixerR Capture Switch", "HPR Mix"},
+       {"Right Capture Mix", "SPKMixer Capture Switch", "Speaker Mix"},
+       {"Right Capture Mix", "MonoMixer Capture Switch", "Mono Mix"},
+
+       /* headphone left mux */
+       {"Left Headphone Mux", "HP Left Mix",           "HPL Mix"},
+       {"Left Headphone Mux", "Vmid",                  "Vmid"},
+
+       /* headphone right mux */
+       {"Right Headphone Mux", "HP Right Mix",         "HPR Mix"},
+       {"Right Headphone Mux", "Vmid",                 "Vmid"},
+
+       /* speaker out mux */
+       {"SpeakerOut Mux", "Vmid",                      "Vmid"},
+       {"SpeakerOut Mux", "HPOut Mix",                 "HPOut Mix"},
+       {"SpeakerOut Mux", "Speaker Mix",               "Speaker Mix"},
+       {"SpeakerOut Mux", "Mono Mix",                  "Mono Mix"},
+
+       /* Mono/Aux Out mux */
+       {"AuxOut Mux", "Vmid",                          "Vmid"},
+       {"AuxOut Mux", "HPOut Mix",                     "HPOut Mix"},
+       {"AuxOut Mux", "Speaker Mix",                   "Speaker Mix"},
+       {"AuxOut Mux", "Mono Mix",                      "Mono Mix"},
+
+       /* output pga */
+       {"HPL", NULL,                                   "Left Headphone"},
+       {"Left Headphone", NULL,                        "Left Headphone Mux"},
+       {"HPR", NULL,                                   "Right Headphone"},
+       {"Right Headphone", NULL,                       "Right Headphone Mux"},
+       {"Left AuxOut", NULL,                           "AuxOut Mux"},
+       {"Right AuxOut", NULL,                          "AuxOut Mux"},
+
+       /* input pga */
+       {"Left LineIn", NULL,                           "LINEINL"},
+       {"Right LineIn", NULL,                          "LINEINR"},
+       {"Left AuxI", NULL,                             "AUXINL"},
+       {"Right AuxI", NULL,                            "AUXINR"},
+       {"MIC1 Pre Amp", NULL,                          "MIC1"},
+       {"MIC2 Pre Amp", NULL,                          "MIC2"},
+       {"MIC1 PGA", NULL,                              "MIC1 Pre Amp"},
+       {"MIC2 PGA", NULL,                              "MIC2 Pre Amp"},
+
+       /* left ADC */
+       {"Left ADC", NULL,                              "Left Capture Mix"},
+
+       /* right ADC */
+       {"Right ADC", NULL,                             "Right Capture Mix"},
+
+       {"SpeakerOut N Mux", "RN/-R",                   "SpeakerOut"},
+       {"SpeakerOut N Mux", "RP/+R",                   "SpeakerOut"},
+       {"SpeakerOut N Mux", "LN/-R",                   "SpeakerOut"},
+       {"SpeakerOut N Mux", "Vmid",                    "Vmid"},
+
+       {"SPKOUT", NULL,                                "SpeakerOut"},
+       {"SPKOUTN", NULL,                               "SpeakerOut N Mux"},
+};
+
+static const struct snd_soc_dapm_route intercon_spk[] = {
+       {"SpeakerOut", NULL,                            "SpeakerOut Mux"},
+};
+
+static const struct snd_soc_dapm_route intercon_amp_spk[] = {
+       {"AB Amp", NULL,                                "SpeakerOut Mux"},
+       {"D Amp", NULL,                                 "SpeakerOut Mux"},
+       {"AB-D Amp Mux", "AB Amp",                      "AB Amp"},
+       {"AB-D Amp Mux", "D Amp",                       "D Amp"},
+       {"SpeakerOut", NULL,                            "AB-D Amp Mux"},
+};
+
+/* PLL divisors */
+struct _pll_div {
+       u32 pll_in;
+       u32 pll_out;
+       u16 regvalue;
+};
+
+/* Note : pll code from original alc5623 driver. Not sure of how good it is */
+/* usefull only for master mode */
+static const struct _pll_div codec_master_pll_div[] = {
+
+       {  2048000,  8192000,   0x0ea0},
+       {  3686400,  8192000,   0x4e27},
+       { 12000000,  8192000,   0x456b},
+       { 13000000,  8192000,   0x495f},
+       { 13100000,  8192000,   0x0320},
+       {  2048000,  11289600,  0xf637},
+       {  3686400,  11289600,  0x2f22},
+       { 12000000,  11289600,  0x3e2f},
+       { 13000000,  11289600,  0x4d5b},
+       { 13100000,  11289600,  0x363b},
+       {  2048000,  16384000,  0x1ea0},
+       {  3686400,  16384000,  0x9e27},
+       { 12000000,  16384000,  0x452b},
+       { 13000000,  16384000,  0x542f},
+       { 13100000,  16384000,  0x03a0},
+       {  2048000,  16934400,  0xe625},
+       {  3686400,  16934400,  0x9126},
+       { 12000000,  16934400,  0x4d2c},
+       { 13000000,  16934400,  0x742f},
+       { 13100000,  16934400,  0x3c27},
+       {  2048000,  22579200,  0x2aa0},
+       {  3686400,  22579200,  0x2f20},
+       { 12000000,  22579200,  0x7e2f},
+       { 13000000,  22579200,  0x742f},
+       { 13100000,  22579200,  0x3c27},
+       {  2048000,  24576000,  0x2ea0},
+       {  3686400,  24576000,  0xee27},
+       { 12000000,  24576000,  0x2915},
+       { 13000000,  24576000,  0x772e},
+       { 13100000,  24576000,  0x0d20},
+};
+
+static const struct _pll_div codec_slave_pll_div[] = {
+
+       {  1024000,  16384000,  0x3ea0},
+       {  1411200,  22579200,  0x3ea0},
+       {  1536000,  24576000,  0x3ea0},
+       {  2048000,  16384000,  0x1ea0},
+       {  2822400,  22579200,  0x1ea0},
+       {  3072000,  24576000,  0x1ea0},
+
+};
+
+static int alc5623_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+               int source, unsigned int freq_in, unsigned int freq_out)
+{
+       int i;
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int gbl_clk = 0, pll_div = 0;
+       u16 reg;
+
+       if (pll_id < ALC5623_PLL_FR_MCLK || pll_id > ALC5623_PLL_FR_BCK)
+               return -ENODEV;
+
+       /* Disable PLL power */
+       snd_soc_update_bits(codec, ALC5623_PWR_MANAG_ADD2,
+                               ALC5623_PWR_ADD2_PLL,
+                               0);
+
+       /* pll is not used in slave mode */
+       reg = snd_soc_read(codec, ALC5623_DAI_CONTROL);
+       if (reg & ALC5623_DAI_SDP_SLAVE_MODE)
+               return 0;
+
+       if (!freq_in || !freq_out)
+               return 0;
+
+       switch (pll_id) {
+       case ALC5623_PLL_FR_MCLK:
+               for (i = 0; i < ARRAY_SIZE(codec_master_pll_div); i++) {
+                       if (codec_master_pll_div[i].pll_in == freq_in
+                          && codec_master_pll_div[i].pll_out == freq_out) {
+                               /* PLL source from MCLK */
+                               pll_div  = codec_master_pll_div[i].regvalue;
+                               break;
+                       }
+               }
+               break;
+       case ALC5623_PLL_FR_BCK:
+               for (i = 0; i < ARRAY_SIZE(codec_slave_pll_div); i++) {
+                       if (codec_slave_pll_div[i].pll_in == freq_in
+                          && codec_slave_pll_div[i].pll_out == freq_out) {
+                               /* PLL source from Bitclk */
+                               gbl_clk = ALC5623_GBL_CLK_PLL_SOUR_SEL_BITCLK;
+                               pll_div = codec_slave_pll_div[i].regvalue;
+                               break;
+                       }
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (!pll_div)
+               return -EINVAL;
+
+       snd_soc_write(codec, ALC5623_GLOBAL_CLK_CTRL_REG, gbl_clk);
+       snd_soc_write(codec, ALC5623_PLL_CTRL, pll_div);
+       snd_soc_update_bits(codec, ALC5623_PWR_MANAG_ADD2,
+                               ALC5623_PWR_ADD2_PLL,
+                               ALC5623_PWR_ADD2_PLL);
+       gbl_clk |= ALC5623_GBL_CLK_SYS_SOUR_SEL_PLL;
+       snd_soc_write(codec, ALC5623_GLOBAL_CLK_CTRL_REG, gbl_clk);
+
+       return 0;
+}
+
+struct _coeff_div {
+       u16 fs;
+       u16 regvalue;
+};
+
+/* codec hifi mclk (after PLL) clock divider coefficients */
+/* values inspired from column BCLK=32Fs of Appendix A table */
+static const struct _coeff_div coeff_div[] = {
+       {256*8, 0x3a69},
+       {384*8, 0x3c6b},
+       {256*4, 0x2a69},
+       {384*4, 0x2c6b},
+       {256*2, 0x1a69},
+       {384*2, 0x1c6b},
+       {256*1, 0x0a69},
+       {384*1, 0x0c6b},
+};
+
+static int get_coeff(struct snd_soc_codec *codec, int rate)
+{
+       struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+               if (coeff_div[i].fs * rate == alc5623->sysclk)
+                       return i;
+       }
+       return -EINVAL;
+}
+
+/*
+ * Clock after PLL and dividers
+ */
+static int alc5623_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
+
+       switch (freq) {
+       case  8192000:
+       case 11289600:
+       case 12288000:
+       case 16384000:
+       case 16934400:
+       case 18432000:
+       case 22579200:
+       case 24576000:
+               alc5623->sysclk = freq;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int alc5623_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 iface = 0;
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               iface = ALC5623_DAI_SDP_MASTER_MODE;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               iface = ALC5623_DAI_SDP_SLAVE_MODE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* interface format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               iface |= ALC5623_DAI_I2S_DF_I2S;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               iface |= ALC5623_DAI_I2S_DF_RIGHT;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iface |= ALC5623_DAI_I2S_DF_LEFT;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               iface |= ALC5623_DAI_I2S_DF_PCM;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               iface |= ALC5623_DAI_I2S_DF_PCM | ALC5623_DAI_I2S_PCM_MODE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               iface |= ALC5623_DAI_MAIN_I2S_BCLK_POL_CTRL;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               iface |= ALC5623_DAI_MAIN_I2S_BCLK_POL_CTRL;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return snd_soc_write(codec, ALC5623_DAI_CONTROL, iface);
+}
+
+static int alc5623_pcm_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 alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
+       int coeff, rate;
+       u16 iface;
+
+       iface = snd_soc_read(codec, ALC5623_DAI_CONTROL);
+       iface &= ~ALC5623_DAI_I2S_DL_MASK;
+
+       /* bit size */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               iface |= ALC5623_DAI_I2S_DL_16;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               iface |= ALC5623_DAI_I2S_DL_20;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               iface |= ALC5623_DAI_I2S_DL_24;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               iface |= ALC5623_DAI_I2S_DL_32;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* set iface & srate */
+       snd_soc_write(codec, ALC5623_DAI_CONTROL, iface);
+       rate = params_rate(params);
+       coeff = get_coeff(codec, rate);
+       if (coeff < 0)
+               return -EINVAL;
+
+       coeff = coeff_div[coeff].regvalue;
+       dev_dbg(codec->dev, "%s: sysclk=%d,rate=%d,coeff=0x%04x\n",
+               __func__, alc5623->sysclk, rate, coeff);
+       snd_soc_write(codec, ALC5623_STEREO_AD_DA_CLK_CTRL, coeff);
+
+       return 0;
+}
+
+static int alc5623_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       u16 hp_mute = ALC5623_MISC_M_DAC_L_INPUT | ALC5623_MISC_M_DAC_R_INPUT;
+       u16 mute_reg = snd_soc_read(codec, ALC5623_MISC_CTRL) & ~hp_mute;
+
+       if (mute)
+               mute_reg |= hp_mute;
+
+       return snd_soc_write(codec, ALC5623_MISC_CTRL, mute_reg);
+}
+
+#define ALC5623_ADD2_POWER_EN (ALC5623_PWR_ADD2_VREF \
+       | ALC5623_PWR_ADD2_DAC_REF_CIR)
+
+#define ALC5623_ADD3_POWER_EN (ALC5623_PWR_ADD3_MAIN_BIAS \
+       | ALC5623_PWR_ADD3_MIC1_BOOST_AD)
+
+#define ALC5623_ADD1_POWER_EN \
+       (ALC5623_PWR_ADD1_SHORT_CURR_DET_EN | ALC5623_PWR_ADD1_SOFTGEN_EN \
+       | ALC5623_PWR_ADD1_DEPOP_BUF_HP | ALC5623_PWR_ADD1_HP_OUT_AMP \
+       | ALC5623_PWR_ADD1_HP_OUT_ENH_AMP)
+
+#define ALC5623_ADD1_POWER_EN_5622 \
+       (ALC5623_PWR_ADD1_SHORT_CURR_DET_EN \
+       | ALC5623_PWR_ADD1_HP_OUT_AMP)
+
+static void enable_power_depop(struct snd_soc_codec *codec)
+{
+       struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
+
+       snd_soc_update_bits(codec, ALC5623_PWR_MANAG_ADD1,
+                               ALC5623_PWR_ADD1_SOFTGEN_EN,
+                               ALC5623_PWR_ADD1_SOFTGEN_EN);
+
+       snd_soc_write(codec, ALC5623_PWR_MANAG_ADD3, ALC5623_ADD3_POWER_EN);
+
+       snd_soc_update_bits(codec, ALC5623_MISC_CTRL,
+                               ALC5623_MISC_HP_DEPOP_MODE2_EN,
+                               ALC5623_MISC_HP_DEPOP_MODE2_EN);
+
+       msleep(500);
+
+       snd_soc_write(codec, ALC5623_PWR_MANAG_ADD2, ALC5623_ADD2_POWER_EN);
+
+       /* avoid writing '1' into 5622 reserved bits */
+       if (alc5623->id == 0x22)
+               snd_soc_write(codec, ALC5623_PWR_MANAG_ADD1,
+                       ALC5623_ADD1_POWER_EN_5622);
+       else
+               snd_soc_write(codec, ALC5623_PWR_MANAG_ADD1,
+                       ALC5623_ADD1_POWER_EN);
+
+       /* disable HP Depop2 */
+       snd_soc_update_bits(codec, ALC5623_MISC_CTRL,
+                               ALC5623_MISC_HP_DEPOP_MODE2_EN,
+                               0);
+
+}
+
+static int alc5623_set_bias_level(struct snd_soc_codec *codec,
+                                     enum snd_soc_bias_level level)
+{
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               enable_power_depop(codec);
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               /* everything off except vref/vmid, */
+               snd_soc_write(codec, ALC5623_PWR_MANAG_ADD2,
+                               ALC5623_PWR_ADD2_VREF);
+               snd_soc_write(codec, ALC5623_PWR_MANAG_ADD3,
+                               ALC5623_PWR_ADD3_MAIN_BIAS);
+               break;
+       case SND_SOC_BIAS_OFF:
+               /* everything off, dac mute, inactive */
+               snd_soc_write(codec, ALC5623_PWR_MANAG_ADD2, 0);
+               snd_soc_write(codec, ALC5623_PWR_MANAG_ADD3, 0);
+               snd_soc_write(codec, ALC5623_PWR_MANAG_ADD1, 0);
+               break;
+       }
+       codec->dapm.bias_level = level;
+       return 0;
+}
+
+#define ALC5623_FORMATS        (SNDRV_PCM_FMTBIT_S16_LE \
+                       | SNDRV_PCM_FMTBIT_S24_LE \
+                       | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops alc5623_dai_ops = {
+               .hw_params = alc5623_pcm_hw_params,
+               .digital_mute = alc5623_mute,
+               .set_fmt = alc5623_set_dai_fmt,
+               .set_sysclk = alc5623_set_dai_sysclk,
+               .set_pll = alc5623_set_dai_pll,
+};
+
+static struct snd_soc_dai_driver alc5623_dai = {
+       .name = "alc5623-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rate_min =     8000,
+               .rate_max =     48000,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = ALC5623_FORMATS,},
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rate_min =     8000,
+               .rate_max =     48000,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = ALC5623_FORMATS,},
+
+       .ops = &alc5623_dai_ops,
+};
+
+static int alc5623_suspend(struct snd_soc_codec *codec, pm_message_t mesg)
+{
+       alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int alc5623_resume(struct snd_soc_codec *codec)
+{
+       int i, step = codec->driver->reg_cache_step;
+       u16 *cache = codec->reg_cache;
+
+       /* Sync reg_cache with the hardware */
+       for (i = 2 ; i < codec->driver->reg_cache_size ; i += step)
+               snd_soc_write(codec, i, cache[i]);
+
+       alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* charge alc5623 caps */
+       if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) {
+               alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+               codec->dapm.bias_level = SND_SOC_BIAS_ON;
+               alc5623_set_bias_level(codec, codec->dapm.bias_level);
+       }
+
+       return 0;
+}
+
+static int alc5623_probe(struct snd_soc_codec *codec)
+{
+       struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       int ret;
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, alc5623->control_type);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       alc5623_reset(codec);
+       alc5623_fill_cache(codec);
+
+       /* power on device */
+       alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       if (alc5623->add_ctrl) {
+               snd_soc_write(codec, ALC5623_ADD_CTRL_REG,
+                               alc5623->add_ctrl);
+       }
+
+       if (alc5623->jack_det_ctrl) {
+               snd_soc_write(codec, ALC5623_JACK_DET_CTRL,
+                               alc5623->jack_det_ctrl);
+       }
+
+       switch (alc5623->id) {
+       case 0x21:
+               snd_soc_add_controls(codec, rt5621_vol_snd_controls,
+                       ARRAY_SIZE(rt5621_vol_snd_controls));
+               break;
+       case 0x22:
+               snd_soc_add_controls(codec, rt5622_vol_snd_controls,
+                       ARRAY_SIZE(rt5622_vol_snd_controls));
+               break;
+       case 0x23:
+               snd_soc_add_controls(codec, alc5623_vol_snd_controls,
+                       ARRAY_SIZE(alc5623_vol_snd_controls));
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_add_controls(codec, alc5623_snd_controls,
+                       ARRAY_SIZE(alc5623_snd_controls));
+
+       snd_soc_dapm_new_controls(dapm, alc5623_dapm_widgets,
+                                       ARRAY_SIZE(alc5623_dapm_widgets));
+
+       /* set up audio path interconnects */
+       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
+
+       switch (alc5623->id) {
+       case 0x21:
+       case 0x22:
+               snd_soc_dapm_new_controls(dapm, alc5623_dapm_amp_widgets,
+                                       ARRAY_SIZE(alc5623_dapm_amp_widgets));
+               snd_soc_dapm_add_routes(dapm, intercon_amp_spk,
+                                       ARRAY_SIZE(intercon_amp_spk));
+               break;
+       case 0x23:
+               snd_soc_dapm_add_routes(dapm, intercon_spk,
+                                       ARRAY_SIZE(intercon_spk));
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
+/* power down chip */
+static int alc5623_remove(struct snd_soc_codec *codec)
+{
+       alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_device_alc5623 = {
+       .probe = alc5623_probe,
+       .remove = alc5623_remove,
+       .suspend = alc5623_suspend,
+       .resume = alc5623_resume,
+       .set_bias_level = alc5623_set_bias_level,
+       .reg_cache_size = ALC5623_VENDOR_ID2+2,
+       .reg_word_size = sizeof(u16),
+       .reg_cache_step = 2,
+};
+
+/*
+ * ALC5623 2 wire address is determined by A1 pin
+ * state during powerup.
+ *    low  = 0x1a
+ *    high = 0x1b
+ */
+static int alc5623_i2c_probe(struct i2c_client *client,
+                               const struct i2c_device_id *id)
+{
+       struct alc5623_platform_data *pdata;
+       struct alc5623_priv *alc5623;
+       int ret, vid1, vid2;
+
+       vid1 = i2c_smbus_read_word_data(client, ALC5623_VENDOR_ID1);
+       if (vid1 < 0) {
+               dev_err(&client->dev, "failed to read I2C\n");
+               return -EIO;
+       }
+       vid1 = ((vid1 & 0xff) << 8) | (vid1 >> 8);
+
+       vid2 = i2c_smbus_read_byte_data(client, ALC5623_VENDOR_ID2);
+       if (vid2 < 0) {
+               dev_err(&client->dev, "failed to read I2C\n");
+               return -EIO;
+       }
+
+       if ((vid1 != 0x10ec) || (vid2 != id->driver_data)) {
+               dev_err(&client->dev, "unknown or wrong codec\n");
+               dev_err(&client->dev, "Expected %x:%lx, got %x:%x\n",
+                               0x10ec, id->driver_data,
+                               vid1, vid2);
+               return -ENODEV;
+       }
+
+       dev_dbg(&client->dev, "Found codec id : alc56%02x\n", vid2);
+
+       alc5623 = kzalloc(sizeof(struct alc5623_priv), GFP_KERNEL);
+       if (alc5623 == NULL)
+               return -ENOMEM;
+
+       pdata = client->dev.platform_data;
+       if (pdata) {
+               alc5623->add_ctrl = pdata->add_ctrl;
+               alc5623->jack_det_ctrl = pdata->jack_det_ctrl;
+       }
+
+       alc5623->id = vid2;
+       switch (alc5623->id) {
+       case 0x21:
+               alc5623_dai.name = "alc5621-hifi";
+               break;
+       case 0x22:
+               alc5623_dai.name = "alc5622-hifi";
+               break;
+       case 0x23:
+               alc5623_dai.name = "alc5623-hifi";
+               break;
+       default:
+               kfree(alc5623);
+               return -EINVAL;
+       }
+
+       i2c_set_clientdata(client, alc5623);
+       alc5623->control_data = client;
+       alc5623->control_type = SND_SOC_I2C;
+       mutex_init(&alc5623->mutex);
+
+       ret =  snd_soc_register_codec(&client->dev,
+               &soc_codec_device_alc5623, &alc5623_dai, 1);
+       if (ret != 0) {
+               dev_err(&client->dev, "Failed to register codec: %d\n", ret);
+               kfree(alc5623);
+       }
+
+       return ret;
+}
+
+static int alc5623_i2c_remove(struct i2c_client *client)
+{
+       struct alc5623_priv *alc5623 = i2c_get_clientdata(client);
+
+       snd_soc_unregister_codec(&client->dev);
+       kfree(alc5623);
+       return 0;
+}
+
+static const struct i2c_device_id alc5623_i2c_table[] = {
+       {"alc5621", 0x21},
+       {"alc5622", 0x22},
+       {"alc5623", 0x23},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, alc5623_i2c_table);
+
+/*  i2c codec control layer */
+static struct i2c_driver alc5623_i2c_driver = {
+       .driver = {
+               .name = "alc562x-codec",
+               .owner = THIS_MODULE,
+       },
+       .probe = alc5623_i2c_probe,
+       .remove =  __devexit_p(alc5623_i2c_remove),
+       .id_table = alc5623_i2c_table,
+};
+
+static int __init alc5623_modinit(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&alc5623_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "%s: can't add i2c driver", __func__);
+               return ret;
+       }
+
+       return ret;
+}
+module_init(alc5623_modinit);
+
+static void __exit alc5623_modexit(void)
+{
+       i2c_del_driver(&alc5623_i2c_driver);
+}
+module_exit(alc5623_modexit);
+
+MODULE_DESCRIPTION("ASoC alc5621/2/3 driver");
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/alc5623.h b/sound/soc/codecs/alc5623.h
new file mode 100644 (file)
index 0000000..f3d6826
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * alc5623.h  --  alc562[123] ALSA Soc Audio driver
+ *
+ * Copyright 2008 Realtek Microelectronics
+ * Copyright 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ * Author: flove <flove@realtek.com>
+ * Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _ALC5623_H
+#define _ALC5623_H
+
+#define ALC5623_RESET                          0x00
+/*                             5621 5622 5623  */
+/* speaker output vol             2    2       */
+/* line output vol                      4    2  */
+/* HP output vol                  4    0    4  */
+#define ALC5623_SPK_OUT_VOL                    0x02
+#define ALC5623_HP_OUT_VOL                     0x04
+#define ALC5623_MONO_AUX_OUT_VOL               0x06
+#define ALC5623_AUXIN_VOL                      0x08
+#define ALC5623_LINE_IN_VOL                    0x0A
+#define ALC5623_STEREO_DAC_VOL                 0x0C
+#define ALC5623_MIC_VOL                                0x0E
+#define ALC5623_MIC_ROUTING_CTRL               0x10
+#define ALC5623_ADC_REC_GAIN                   0x12
+#define ALC5623_ADC_REC_MIXER                  0x14
+#define ALC5623_SOFT_VOL_CTRL_TIME             0x16
+/* ALC5623_OUTPUT_MIXER_CTRL :                 */
+/* same remark as for reg 2 line vs speaker    */
+#define ALC5623_OUTPUT_MIXER_CTRL              0x1C
+#define ALC5623_MIC_CTRL                       0x22
+
+#define        ALC5623_DAI_CONTROL                     0x34
+#define ALC5623_DAI_SDP_MASTER_MODE            (0 << 15)
+#define ALC5623_DAI_SDP_SLAVE_MODE             (1 << 15)
+#define ALC5623_DAI_I2S_PCM_MODE               (1 << 14)
+#define ALC5623_DAI_MAIN_I2S_BCLK_POL_CTRL     (1 <<  7)
+#define ALC5623_DAI_ADC_DATA_L_R_SWAP          (1 <<  5)
+#define ALC5623_DAI_DAC_DATA_L_R_SWAP          (1 <<  4)
+#define ALC5623_DAI_I2S_DL_MASK                        (3 <<  2)
+#define ALC5623_DAI_I2S_DL_32                  (3 <<  2)
+#define        ALC5623_DAI_I2S_DL_24                   (2 <<  2)
+#define ALC5623_DAI_I2S_DL_20                  (1 <<  2)
+#define ALC5623_DAI_I2S_DL_16                  (0 <<  2)
+#define ALC5623_DAI_I2S_DF_PCM                 (3 <<  0)
+#define        ALC5623_DAI_I2S_DF_LEFT                 (2 <<  0)
+#define ALC5623_DAI_I2S_DF_RIGHT               (1 <<  0)
+#define ALC5623_DAI_I2S_DF_I2S                 (0 <<  0)
+
+#define ALC5623_STEREO_AD_DA_CLK_CTRL          0x36
+#define        ALC5623_COMPANDING_CTRL                 0x38
+
+#define        ALC5623_PWR_MANAG_ADD1                  0x3A
+#define ALC5623_PWR_ADD1_MAIN_I2S_EN           (1 << 15)
+#define ALC5623_PWR_ADD1_ZC_DET_PD_EN          (1 << 14)
+#define ALC5623_PWR_ADD1_MIC1_BIAS_EN          (1 << 11)
+#define ALC5623_PWR_ADD1_SHORT_CURR_DET_EN     (1 << 10)
+#define ALC5623_PWR_ADD1_SOFTGEN_EN            (1 <<  8) /* rsvd on 5622 */
+#define        ALC5623_PWR_ADD1_DEPOP_BUF_HP           (1 <<  6) /* rsvd on 5622 */
+#define        ALC5623_PWR_ADD1_HP_OUT_AMP             (1 <<  5)
+#define        ALC5623_PWR_ADD1_HP_OUT_ENH_AMP         (1 <<  4) /* rsvd on 5622 */
+#define ALC5623_PWR_ADD1_DEPOP_BUF_AUX         (1 <<  2)
+#define ALC5623_PWR_ADD1_AUX_OUT_AMP           (1 <<  1)
+#define ALC5623_PWR_ADD1_AUX_OUT_ENH_AMP       (1 <<  0) /* rsvd on 5622 */
+
+#define ALC5623_PWR_MANAG_ADD2                 0x3C
+#define ALC5623_PWR_ADD2_LINEOUT               (1 << 15) /* rt5623 */
+#define ALC5623_PWR_ADD2_CLASS_AB              (1 << 15) /* rt5621 */
+#define ALC5623_PWR_ADD2_CLASS_D               (1 << 14) /* rt5621 */
+#define ALC5623_PWR_ADD2_VREF                  (1 << 13)
+#define ALC5623_PWR_ADD2_PLL                   (1 << 12)
+#define ALC5623_PWR_ADD2_DAC_REF_CIR           (1 << 10)
+#define ALC5623_PWR_ADD2_L_DAC_CLK             (1 <<  9)
+#define ALC5623_PWR_ADD2_R_DAC_CLK             (1 <<  8)
+#define ALC5623_PWR_ADD2_L_ADC_CLK_GAIN                (1 <<  7)
+#define ALC5623_PWR_ADD2_R_ADC_CLK_GAIN                (1 <<  6)
+#define ALC5623_PWR_ADD2_L_HP_MIXER            (1 <<  5)
+#define ALC5623_PWR_ADD2_R_HP_MIXER            (1 <<  4)
+#define ALC5623_PWR_ADD2_SPK_MIXER             (1 <<  3)
+#define ALC5623_PWR_ADD2_MONO_MIXER            (1 <<  2)
+#define ALC5623_PWR_ADD2_L_ADC_REC_MIXER       (1 <<  1)
+#define ALC5623_PWR_ADD2_R_ADC_REC_MIXER       (1 <<  0)
+
+#define ALC5623_PWR_MANAG_ADD3                 0x3E
+#define ALC5623_PWR_ADD3_MAIN_BIAS             (1 << 15)
+#define ALC5623_PWR_ADD3_AUXOUT_L_VOL_AMP      (1 << 14)
+#define ALC5623_PWR_ADD3_AUXOUT_R_VOL_AMP      (1 << 13)
+#define ALC5623_PWR_ADD3_SPK_OUT               (1 << 12)
+#define ALC5623_PWR_ADD3_HP_L_OUT_VOL          (1 << 10)
+#define ALC5623_PWR_ADD3_HP_R_OUT_VOL          (1 <<  9)
+#define ALC5623_PWR_ADD3_LINEIN_L_VOL          (1 <<  7)
+#define ALC5623_PWR_ADD3_LINEIN_R_VOL          (1 <<  6)
+#define ALC5623_PWR_ADD3_AUXIN_L_VOL           (1 <<  5)
+#define ALC5623_PWR_ADD3_AUXIN_R_VOL           (1 <<  4)
+#define ALC5623_PWR_ADD3_MIC1_FUN_CTRL         (1 <<  3)
+#define ALC5623_PWR_ADD3_MIC2_FUN_CTRL         (1 <<  2)
+#define ALC5623_PWR_ADD3_MIC1_BOOST_AD         (1 <<  1)
+#define ALC5623_PWR_ADD3_MIC2_BOOST_AD         (1 <<  0)
+
+#define ALC5623_ADD_CTRL_REG                   0x40
+
+#define        ALC5623_GLOBAL_CLK_CTRL_REG             0x42
+#define ALC5623_GBL_CLK_SYS_SOUR_SEL_PLL       (1 << 15)
+#define ALC5623_GBL_CLK_SYS_SOUR_SEL_MCLK      (0 << 15)
+#define ALC5623_GBL_CLK_PLL_SOUR_SEL_BITCLK    (1 << 14)
+#define ALC5623_GBL_CLK_PLL_SOUR_SEL_MCLK      (0 << 14)
+#define ALC5623_GBL_CLK_PLL_DIV_RATIO_DIV8     (3 <<  1)
+#define ALC5623_GBL_CLK_PLL_DIV_RATIO_DIV4     (2 <<  1)
+#define ALC5623_GBL_CLK_PLL_DIV_RATIO_DIV2     (1 <<  1)
+#define ALC5623_GBL_CLK_PLL_DIV_RATIO_DIV1     (0 <<  1)
+#define ALC5623_GBL_CLK_PLL_PRE_DIV2           (1 <<  0)
+#define ALC5623_GBL_CLK_PLL_PRE_DIV1           (0 <<  0)
+
+#define ALC5623_PLL_CTRL                       0x44
+#define ALC5623_PLL_CTRL_N_VAL(n)              (((n)&0xff) << 8)
+#define ALC5623_PLL_CTRL_K_VAL(k)              (((k)&0x7)  << 4)
+#define ALC5623_PLL_CTRL_M_VAL(m)              ((m)&0xf)
+
+#define ALC5623_GPIO_OUTPUT_PIN_CTRL           0x4A
+#define ALC5623_GPIO_PIN_CONFIG                        0x4C
+#define ALC5623_GPIO_PIN_POLARITY              0x4E
+#define ALC5623_GPIO_PIN_STICKY                        0x50
+#define ALC5623_GPIO_PIN_WAKEUP                        0x52
+#define ALC5623_GPIO_PIN_STATUS                        0x54
+#define ALC5623_GPIO_PIN_SHARING               0x56
+#define        ALC5623_OVER_CURR_STATUS                0x58
+#define ALC5623_JACK_DET_CTRL                  0x5A
+
+#define ALC5623_MISC_CTRL                      0x5E
+#define ALC5623_MISC_DISABLE_FAST_VREG         (1 << 15)
+#define ALC5623_MISC_SPK_CLASS_AB_OC_PD                (1 << 13) /* 5621 */
+#define ALC5623_MISC_SPK_CLASS_AB_OC_DET       (1 << 12) /* 5621 */
+#define ALC5623_MISC_HP_DEPOP_MODE3_EN         (1 << 10)
+#define ALC5623_MISC_HP_DEPOP_MODE2_EN         (1 <<  9)
+#define ALC5623_MISC_HP_DEPOP_MODE1_EN         (1 <<  8)
+#define ALC5623_MISC_AUXOUT_DEPOP_MODE3_EN     (1 <<  6)
+#define ALC5623_MISC_AUXOUT_DEPOP_MODE2_EN     (1 <<  5)
+#define ALC5623_MISC_AUXOUT_DEPOP_MODE1_EN     (1 <<  4)
+#define ALC5623_MISC_M_DAC_L_INPUT             (1 <<  3)
+#define ALC5623_MISC_M_DAC_R_INPUT             (1 <<  2)
+#define ALC5623_MISC_IRQOUT_INV_CTRL           (1 <<  0)
+
+#define        ALC5623_PSEDUEO_SPATIAL_CTRL            0x60
+#define ALC5623_EQ_CTRL                                0x62
+#define ALC5623_EQ_MODE_ENABLE                 0x66
+#define ALC5623_AVC_CTRL                       0x68
+#define ALC5623_HID_CTRL_INDEX                 0x6A
+#define ALC5623_HID_CTRL_DATA                  0x6C
+#define ALC5623_VENDOR_ID1                     0x7C
+#define ALC5623_VENDOR_ID2                     0x7E
+
+#define ALC5623_PLL_FR_MCLK                    0
+#define ALC5623_PLL_FR_BCK                     1
+#endif
index 8236439..46dbfd0 100644 (file)
@@ -36,8 +36,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dai.h>
-#include <sound/soc-dapm.h>
 #include <sound/initval.h>
 
 #include <mach/dm365.h>
@@ -116,7 +114,7 @@ static int cq93vc_set_bias_level(struct snd_soc_codec *codec,
                             DAVINCI_VC_REG12_POWER_ALL_OFF);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
 
        return 0;
 }
index 6d4bdc6..8b51245 100644 (file)
 #define CS4270_MUTE_DAC_A      0x01
 #define CS4270_MUTE_DAC_B      0x02
 
+/* Power-on default values for the registers
+ *
+ * This array contains the power-on default values of the registers, with the
+ * exception of the "CHIPID" register (01h).  The lower four bits of that
+ * register contain the hardware revision, so it is treated as volatile.
+ *
+ * Also note that on the CS4270, the first readable register is 1, but ASoC
+ * assumes the first register is 0.  Therfore, the array must have an entry for
+ * register 0, but we use cs4270_reg_is_readable() to tell ASoC that it can't
+ * be read.
+ */
+static const u8 cs4270_default_reg_cache[CS4270_LASTREG + 1] = {
+       0x00, 0x00, 0x00, 0x30, 0x00, 0x60, 0x20, 0x00, 0x00
+};
+
 static const char *supply_names[] = {
        "va", "vd", "vlc"
 };
@@ -114,7 +129,6 @@ static const char *supply_names[] = {
 struct cs4270_private {
        enum snd_soc_control_type control_type;
        void *control_data;
-       u8 reg_cache[CS4270_NUMREGS];
        unsigned int mclk; /* Input frequency of the MCLK pin */
        unsigned int mode; /* The mode (I2S or left-justified) */
        unsigned int slave_mode;
@@ -179,6 +193,20 @@ static struct cs4270_mode_ratios cs4270_mode_ratios[] = {
 /* The number of MCLK/LRCK ratios supported by the CS4270 */
 #define NUM_MCLK_RATIOS                ARRAY_SIZE(cs4270_mode_ratios)
 
+static int cs4270_reg_is_readable(unsigned int reg)
+{
+       return (reg >= CS4270_FIRSTREG) && (reg <= CS4270_LASTREG);
+}
+
+static int cs4270_reg_is_volatile(unsigned int reg)
+{
+       /* Unreadable registers are considered volatile */
+       if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG))
+               return 1;
+
+       return reg == CS4270_CHIPID;
+}
+
 /**
  * cs4270_set_dai_sysclk - determine the CS4270 samples rates.
  * @codec_dai: the codec DAI
@@ -263,97 +291,6 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,
        return ret;
 }
 
-/**
- * cs4270_fill_cache - pre-fill the CS4270 register cache.
- * @codec: the codec for this CS4270
- *
- * This function fills in the CS4270 register cache by reading the register
- * values from the hardware.
- *
- * This CS4270 registers are cached to avoid excessive I2C I/O operations.
- * After the initial read to pre-fill the cache, the CS4270 never updates
- * the register values, so we won't have a cache coherency problem.
- *
- * We use the auto-increment feature of the CS4270 to read all registers in
- * one shot.
- */
-static int cs4270_fill_cache(struct snd_soc_codec *codec)
-{
-       u8 *cache = codec->reg_cache;
-       struct i2c_client *i2c_client = codec->control_data;
-       s32 length;
-
-       length = i2c_smbus_read_i2c_block_data(i2c_client,
-               CS4270_FIRSTREG | CS4270_I2C_INCR, CS4270_NUMREGS, cache);
-
-       if (length != CS4270_NUMREGS) {
-               dev_err(codec->dev, "i2c read failure, addr=0x%x\n",
-                      i2c_client->addr);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-/**
- * cs4270_read_reg_cache - read from the CS4270 register cache.
- * @codec: the codec for this CS4270
- * @reg: the register to read
- *
- * This function returns the value for a given register.  It reads only from
- * the register cache, not the hardware itself.
- *
- * This CS4270 registers are cached to avoid excessive I2C I/O operations.
- * After the initial read to pre-fill the cache, the CS4270 never updates
- * the register values, so we won't have a cache coherency problem.
- */
-static unsigned int cs4270_read_reg_cache(struct snd_soc_codec *codec,
-       unsigned int reg)
-{
-       u8 *cache = codec->reg_cache;
-
-       if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG))
-               return -EIO;
-
-       return cache[reg - CS4270_FIRSTREG];
-}
-
-/**
- * cs4270_i2c_write - write to a CS4270 register via the I2C bus.
- * @codec: the codec for this CS4270
- * @reg: the register to write
- * @value: the value to write to the register
- *
- * This function writes the given value to the given CS4270 register, and
- * also updates the register cache.
- *
- * Note that we don't use the hw_write function pointer of snd_soc_codec.
- * That's because it's too clunky: the hw_write_t prototype does not match
- * i2c_smbus_write_byte_data(), and it's just another layer of overhead.
- */
-static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg,
-                           unsigned int value)
-{
-       u8 *cache = codec->reg_cache;
-
-       if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG))
-               return -EIO;
-
-       /* Only perform an I2C operation if the new value is different */
-       if (cache[reg - CS4270_FIRSTREG] != value) {
-               struct i2c_client *client = codec->control_data;
-               if (i2c_smbus_write_byte_data(client, reg, value)) {
-                       dev_err(codec->dev, "i2c write failed\n");
-                       return -EIO;
-               }
-
-               /* We've written to the hardware, so update the cache */
-               cache[reg - CS4270_FIRSTREG] = value;
-       }
-
-       return 0;
-}
-
 /**
  * cs4270_hw_params - program the CS4270 with the given hardware parameters.
  * @substream: the audio stream
@@ -551,15 +488,16 @@ static struct snd_soc_dai_driver cs4270_dai = {
 static int cs4270_probe(struct snd_soc_codec *codec)
 {
        struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
-       int i, ret, reg;
+       int i, ret;
 
        codec->control_data = cs4270->control_data;
 
-       /* The I2C interface is set up, so pre-fill our register cache */
-
-       ret = cs4270_fill_cache(codec);
+       /* Tell ASoC what kind of I/O to use to read the registers.  ASoC will
+        * then do the I2C transactions itself.
+        */
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, cs4270->control_type);
        if (ret < 0) {
-               dev_err(codec->dev, "failed to fill register cache\n");
+               dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret);
                return ret;
        }
 
@@ -568,10 +506,7 @@ static int cs4270_probe(struct snd_soc_codec *codec)
         * this feature disabled by default.  An application (e.g. alsactl) can
         * re-enabled it by using the controls.
         */
-
-       reg = cs4270_read_reg_cache(codec, CS4270_MUTE);
-       reg &= ~CS4270_MUTE_AUTO;
-       ret = cs4270_i2c_write(codec, CS4270_MUTE, reg);
+       ret = snd_soc_update_bits(codec, CS4270_MUTE, CS4270_MUTE_AUTO, 0);
        if (ret < 0) {
                dev_err(codec->dev, "i2c write failed\n");
                return ret;
@@ -582,10 +517,8 @@ static int cs4270_probe(struct snd_soc_codec *codec)
         * playback has started.  An application (e.g. alsactl) can
         * re-enabled it by using the controls.
         */
-
-       reg = cs4270_read_reg_cache(codec, CS4270_TRANS);
-       reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO);
-       ret = cs4270_i2c_write(codec, CS4270_TRANS, reg);
+       ret = snd_soc_update_bits(codec, CS4270_TRANS,
+               CS4270_TRANS_SOFT | CS4270_TRANS_ZERO, 0);
        if (ret < 0) {
                dev_err(codec->dev, "i2c write failed\n");
                return ret;
@@ -708,15 +641,16 @@ static int cs4270_soc_resume(struct snd_soc_codec *codec)
  * Assign this variable to the codec_dev field of the machine driver's
  * snd_soc_device structure.
  */
-static struct snd_soc_codec_driver soc_codec_device_cs4270 = {
-       .probe =        cs4270_probe,
-       .remove =       cs4270_remove,
-       .suspend =      cs4270_soc_suspend,
-       .resume =       cs4270_soc_resume,
-       .read = cs4270_read_reg_cache,
-       .write = cs4270_i2c_write,
-       .reg_cache_size = CS4270_NUMREGS,
-       .reg_word_size = sizeof(u8),
+static const struct snd_soc_codec_driver soc_codec_device_cs4270 = {
+       .probe =                cs4270_probe,
+       .remove =               cs4270_remove,
+       .suspend =              cs4270_soc_suspend,
+       .resume =               cs4270_soc_resume,
+       .volatile_register =    cs4270_reg_is_volatile,
+       .readable_register =    cs4270_reg_is_readable,
+       .reg_cache_size =       CS4270_LASTREG + 1,
+       .reg_word_size =        sizeof(u8),
+       .reg_cache_default =    cs4270_default_reg_cache,
 };
 
 /**
index cb086ea..8fb7070 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/tlv.h>
 #include <sound/initval.h>
 #include <sound/pcm_params.h>
@@ -47,7 +46,6 @@ struct cs42l51_private {
        unsigned int mclk;
        unsigned int audio_mode;        /* The mode (I2S or left-justified) */
        enum master_slave_mode func;
-       u8 reg_cache[CS42L51_NUMREGS];
 };
 
 #define CS42L51_FORMATS ( \
@@ -519,6 +517,7 @@ static struct snd_soc_dai_driver cs42l51_dai = {
 static int cs42l51_probe(struct snd_soc_codec *codec)
 {
        struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret, reg;
 
        codec->control_data = cs42l51->control_data;
@@ -550,9 +549,9 @@ static int cs42l51_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, cs42l51_snd_controls,
                ARRAY_SIZE(cs42l51_snd_controls));
-       snd_soc_dapm_new_controls(codec, cs42l51_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, cs42l51_dapm_widgets,
                ARRAY_SIZE(cs42l51_dapm_widgets));
-       snd_soc_dapm_add_routes(codec, cs42l51_routes,
+       snd_soc_dapm_add_routes(dapm, cs42l51_routes,
                ARRAY_SIZE(cs42l51_routes));
 
        return 0;
index e8d27c8..03d1e86 100644 (file)
@@ -18,7 +18,7 @@
 
 #include <sound/core.h>
 #include <sound/initval.h>
-#include <sound/soc-dapm.h>
+#include <sound/soc.h>
 
 #include "cx20442.h"
 
@@ -26,7 +26,6 @@
 struct cx20442_priv {
        enum snd_soc_control_type control_type;
        void *control_data;
-       u8 reg_cache[1];
 };
 
 #define CX20442_PM             0x0
@@ -89,10 +88,11 @@ static const struct snd_soc_dapm_route cx20442_audio_map[] = {
 
 static int cx20442_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, cx20442_dapm_widgets,
-                                 ARRAY_SIZE(cx20442_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, cx20442_audio_map,
+       snd_soc_dapm_new_controls(dapm, cx20442_dapm_widgets,
+                                 ARRAY_SIZE(cx20442_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, cx20442_audio_map,
                                ARRAY_SIZE(cx20442_audio_map));
 
        return 0;
@@ -263,7 +263,7 @@ static void v253_close(struct tty_struct *tty)
        /* Prevent the codec driver from further accessing the modem */
        codec->hw_write = NULL;
        cx20442->control_data = NULL;
-       codec->pop_time = 0;
+       codec->card->pop_time = 0;
 }
 
 /* Line discipline .hangup() */
@@ -291,7 +291,7 @@ static void v253_receive(struct tty_struct *tty,
                /* Set up codec driver access to modem controls */
                cx20442->control_data = tty;
                codec->hw_write = (hw_write_t)tty->ops->write;
-               codec->pop_time = 1;
+               codec->card->pop_time = 1;
        }
 }
 
@@ -348,7 +348,7 @@ static int cx20442_codec_probe(struct snd_soc_codec *codec)
 
        cx20442->control_data = NULL;
        codec->hw_write = NULL;
-       codec->pop_time = 0;
+       codec->card->pop_time = 0;
 
        return 0;
 }
index 58bb9b9..92fd9d7 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/slab.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
-#include <sound/soc-dapm.h>
+#include <sound/soc.h>
 #include <sound/initval.h>
 #include <sound/tlv.h>
 
diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c
new file mode 100644 (file)
index 0000000..57e9dac
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * dmic.c  --  SoC audio for Generic Digital MICs
+ *
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+static struct snd_soc_dai_driver dmic_dai = {
+       .name = "dmic-hifi",
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 8,
+               .rates = SNDRV_PCM_RATE_CONTINUOUS,
+               .formats = SNDRV_PCM_FMTBIT_S32_LE
+                       | SNDRV_PCM_FMTBIT_S24_LE
+                       | SNDRV_PCM_FMTBIT_S16_LE,
+       },
+};
+
+static struct snd_soc_codec_driver soc_dmic = {};
+
+static int __devinit dmic_dev_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_dmic, &dmic_dai, 1);
+}
+
+static int __devexit dmic_dev_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+MODULE_ALIAS("platform:dmic-codec");
+
+static struct platform_driver dmic_driver = {
+       .driver = {
+               .name = "dmic-codec",
+               .owner = THIS_MODULE,
+       },
+       .probe = dmic_dev_probe,
+       .remove = __devexit_p(dmic_dev_remove),
+};
+
+static int __init dmic_init(void)
+{
+       return platform_driver_register(&dmic_driver);
+}
+module_init(dmic_init);
+
+static void __exit dmic_exit(void)
+{
+       platform_driver_unregister(&dmic_driver);
+}
+module_exit(dmic_exit);
+
+MODULE_DESCRIPTION("Generic DMIC driver");
+MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
+MODULE_LICENSE("GPL");
index 16253ec..f7cd346 100644 (file)
@@ -22,7 +22,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
-#include <sound/soc-dapm.h>
 #include <sound/soc.h>
 
 #define JZ4740_REG_CODEC_1 0x0
@@ -266,7 +265,7 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
                break;
        case SND_SOC_BIAS_STANDBY:
                /* The only way to clear the suspend flag is to reset the codec */
-               if (codec->bias_level == SND_SOC_BIAS_OFF)
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
                        jz4740_codec_wakeup(codec);
 
                mask = JZ4740_CODEC_1_VREF_DISABLE |
@@ -288,23 +287,25 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
 
        return 0;
 }
 
 static int jz4740_codec_dev_probe(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
        snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
                        JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
 
        snd_soc_add_controls(codec, jz4740_codec_controls,
                ARRAY_SIZE(jz4740_codec_controls));
 
-       snd_soc_dapm_new_controls(codec, jz4740_codec_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, jz4740_codec_dapm_widgets,
                ARRAY_SIZE(jz4740_codec_dapm_widgets));
 
-       snd_soc_dapm_add_routes(codec, jz4740_codec_dapm_routes,
+       snd_soc_dapm_add_routes(dapm, jz4740_codec_dapm_routes,
                ARRAY_SIZE(jz4740_codec_dapm_routes));
 
        snd_soc_dapm_new_widgets(codec);
index 72f0dbc..89498f9 100644 (file)
@@ -20,7 +20,6 @@
 #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 <linux/slab.h>
@@ -1229,15 +1228,17 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int max98088_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, max98088_dapm_widgets,
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       snd_soc_dapm_new_controls(dapm, max98088_dapm_widgets,
                                  ARRAY_SIZE(max98088_dapm_widgets));
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        snd_soc_add_controls(codec, max98088_snd_controls,
                             ARRAY_SIZE(max98088_snd_controls));
 
-       snd_soc_dapm_new_widgets(codec);
+       snd_soc_dapm_new_widgets(dapm);
        return 0;
 }
 
@@ -1622,7 +1623,7 @@ static int max98088_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF)
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
                        max98088_sync_cache(codec);
 
                snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
@@ -1635,7 +1636,7 @@ static int max98088_set_bias_level(struct snd_soc_codec *codec,
                codec->cache_sync = 1;
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index 6f38d61..2727bef 100644 (file)
@@ -38,7 +38,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/initval.h>
 
 #include "ssm2602.h"
@@ -207,10 +206,11 @@ static const struct snd_soc_dapm_route audio_conn[] = {
 
 static int ssm2602_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, ssm2602_dapm_widgets,
-                                 ARRAY_SIZE(ssm2602_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, audio_conn, ARRAY_SIZE(audio_conn));
+       snd_soc_dapm_new_controls(dapm, ssm2602_dapm_widgets,
+                                 ARRAY_SIZE(ssm2602_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, audio_conn, ARRAY_SIZE(audio_conn));
 
        return 0;
 }
@@ -493,7 +493,7 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index 061f9e5..78b2b50 100644 (file)
@@ -236,7 +236,7 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec,
                stac9766_ac97_write(codec, AC97_POWERDOWN, 0xffff);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index e8652b1..54a30ef 100644 (file)
@@ -30,7 +30,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/tlv.h>
 #include <sound/initval.h>
 
@@ -391,11 +390,12 @@ static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk,
 
 static int tlv320aic23_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
-                                 ARRAY_SIZE(tlv320aic23_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
+       snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets,
+                                 ARRAY_SIZE(tlv320aic23_dapm_widgets));
        /* set up audio path interconnects */
-       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
 
        return 0;
 }
@@ -574,7 +574,7 @@ static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
                tlv320aic23_write(codec, TLV320AIC23_PWR, 0xffff);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index 6b7d71e..e2a7608 100644 (file)
@@ -18,7 +18,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/initval.h>
 
 #include "tlv320aic26.h"
@@ -31,7 +30,6 @@ MODULE_LICENSE("GPL");
 struct aic26 {
        struct spi_device *spi;
        struct snd_soc_codec codec;
-       u16 reg_cache[AIC26_NUM_REGS];  /* shadow registers */
        int master;
        int datfm;
        int mclk;
@@ -355,7 +353,6 @@ static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set);
  */
 static int aic26_probe(struct snd_soc_codec *codec)
 {
-       struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
        int ret, err, i, reg;
 
        dev_info(codec->dev, "Probing AIC26 SoC CODEC driver\n");
@@ -373,7 +370,7 @@ static int aic26_probe(struct snd_soc_codec *codec)
        aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
 
        /* Fill register cache */
-       for (i = 0; i < ARRAY_SIZE(aic26->reg_cache); i++)
+       for (i = 0; i < codec->driver->reg_cache_size; i++)
                aic26_reg_read(codec, i);
 
        /* Register the sysfs files for debugging */
index 77b8f9a..3bedab2 100644 (file)
@@ -46,7 +46,6 @@
 #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 <sound/tlv320aic3x.h>
@@ -61,6 +60,8 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = {
        "DRVDD",        /* ADC Analog and Output Driver Voltage */
 };
 
+static LIST_HEAD(reset_list);
+
 struct aic3x_priv;
 
 struct aic3x_disable_nb {
@@ -77,6 +78,7 @@ struct aic3x_priv {
        struct aic3x_setup_data *setup;
        void *control_data;
        unsigned int sysclk;
+       struct list_head list;
        int master;
        int gpio_reset;
        int power;
@@ -183,7 +185,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
 
        if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) {
                /* find dapm widget path assoc with kcontrol */
-               list_for_each_entry(path, &widget->codec->dapm_paths, list) {
+               list_for_each_entry(path, &widget->dapm->card->paths, list) {
                        if (path->kcontrol != kcontrol)
                                continue;
 
@@ -199,7 +201,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
                }
 
                if (found)
-                       snd_soc_dapm_sync(widget->codec);
+                       snd_soc_dapm_sync(widget->dapm);
        }
 
        ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
@@ -788,17 +790,19 @@ static const struct snd_soc_dapm_route intercon_3007[] = {
 static int aic3x_add_widgets(struct snd_soc_codec *codec)
 {
        struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets,
                                  ARRAY_SIZE(aic3x_dapm_widgets));
 
        /* set up audio path interconnects */
-       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
 
        if (aic3x->model == AIC3X_MODEL_3007) {
-               snd_soc_dapm_new_controls(codec, aic3007_dapm_widgets,
+               snd_soc_dapm_new_controls(dapm, aic3007_dapm_widgets,
                        ARRAY_SIZE(aic3007_dapm_widgets));
-               snd_soc_dapm_add_routes(codec, intercon_3007, ARRAY_SIZE(intercon_3007));
+               snd_soc_dapm_add_routes(dapm, intercon_3007,
+                                       ARRAY_SIZE(intercon_3007));
        }
 
        return 0;
@@ -1075,7 +1079,7 @@ static int aic3x_regulator_event(struct notifier_block *nb,
                 * Put codec to reset and require cache sync as at least one
                 * of the supplies was disabled
                 */
-               if (aic3x->gpio_reset >= 0)
+               if (gpio_is_valid(aic3x->gpio_reset))
                        gpio_set_value(aic3x->gpio_reset, 0);
                aic3x->codec->cache_sync = 1;
        }
@@ -1102,7 +1106,7 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)
                if (!codec->cache_sync)
                        goto out;
 
-               if (aic3x->gpio_reset >= 0) {
+               if (gpio_is_valid(aic3x->gpio_reset)) {
                        udelay(1);
                        gpio_set_value(aic3x->gpio_reset, 1);
                }
@@ -1135,7 +1139,7 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_ON:
                break;
        case SND_SOC_BIAS_PREPARE:
-               if (codec->bias_level == SND_SOC_BIAS_STANDBY &&
+               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY &&
                    aic3x->master) {
                        /* enable pll */
                        reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
@@ -1146,7 +1150,7 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_STANDBY:
                if (!aic3x->power)
                        aic3x_set_power(codec, 1);
-               if (codec->bias_level == SND_SOC_BIAS_PREPARE &&
+               if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE &&
                    aic3x->master) {
                        /* disable pll */
                        reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
@@ -1159,7 +1163,7 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
                        aic3x_set_power(codec, 0);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
 
        return 0;
 }
@@ -1344,14 +1348,28 @@ static int aic3x_init(struct snd_soc_codec *codec)
        return 0;
 }
 
+static bool aic3x_is_shared_reset(struct aic3x_priv *aic3x)
+{
+       struct aic3x_priv *a;
+
+       list_for_each_entry(a, &reset_list, list) {
+               if (gpio_is_valid(aic3x->gpio_reset) &&
+                   aic3x->gpio_reset == a->gpio_reset)
+                       return true;
+       }
+
+       return false;
+}
+
 static int aic3x_probe(struct snd_soc_codec *codec)
 {
        struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
        int ret, i;
 
+       INIT_LIST_HEAD(&aic3x->list);
        codec->control_data = aic3x->control_data;
        aic3x->codec = codec;
-       codec->idle_bias_off = 1;
+       codec->dapm.idle_bias_off = 1;
 
        ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type);
        if (ret != 0) {
@@ -1359,7 +1377,8 @@ static int aic3x_probe(struct snd_soc_codec *codec)
                return ret;
        }
 
-       if (aic3x->gpio_reset >= 0) {
+       if (gpio_is_valid(aic3x->gpio_reset) &&
+           !aic3x_is_shared_reset(aic3x)) {
                ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset");
                if (ret != 0)
                        goto err_gpio;
@@ -1405,6 +1424,7 @@ static int aic3x_probe(struct snd_soc_codec *codec)
                snd_soc_add_controls(codec, &aic3x_classd_amp_gain_ctrl, 1);
 
        aic3x_add_widgets(codec);
+       list_add(&aic3x->list, &reset_list);
 
        return 0;
 
@@ -1414,10 +1434,10 @@ err_notif:
                                              &aic3x->disable_nb[i].nb);
        regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
 err_get:
-       if (aic3x->gpio_reset >= 0)
+       if (gpio_is_valid(aic3x->gpio_reset) &&
+           !aic3x_is_shared_reset(aic3x))
                gpio_free(aic3x->gpio_reset);
 err_gpio:
-       kfree(aic3x);
        return ret;
 }
 
@@ -1427,7 +1447,9 @@ static int aic3x_remove(struct snd_soc_codec *codec)
        int i;
 
        aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       if (aic3x->gpio_reset >= 0) {
+       list_del(&aic3x->list);
+       if (gpio_is_valid(aic3x->gpio_reset) &&
+           !aic3x_is_shared_reset(aic3x)) {
                gpio_set_value(aic3x->gpio_reset, 0);
                gpio_free(aic3x->gpio_reset);
        }
@@ -1523,21 +1545,6 @@ static struct i2c_driver aic3x_i2c_driver = {
        .remove = aic3x_i2c_remove,
        .id_table = aic3x_i2c_id,
 };
-
-static inline void aic3x_i2c_init(void)
-{
-       int ret;
-
-       ret = i2c_add_driver(&aic3x_i2c_driver);
-       if (ret)
-               printk(KERN_ERR "%s: error regsitering i2c driver, %d\n",
-                      __func__, ret);
-}
-
-static inline void aic3x_i2c_exit(void)
-{
-       i2c_del_driver(&aic3x_i2c_driver);
-}
 #endif
 
 static int __init aic3x_modinit(void)
index c5ab8c8..71d7be8 100644 (file)
 #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 <sound/tlv320dac33-plat.h>
 #include "tlv320dac33.h"
 
-#define DAC33_BUFFER_SIZE_BYTES                24576   /* bytes, 12288 16 bit words,
-                                                * 6144 stereo */
-#define DAC33_BUFFER_SIZE_SAMPLES      6144
-
-#define NSAMPLE_MAX            5700
-
-#define MODE7_LTHR             10
-#define MODE7_UTHR             (DAC33_BUFFER_SIZE_SAMPLES - 10)
+/*
+ * The internal FIFO is 24576 bytes long
+ * It can be configured to hold 16bit or 24bit samples
+ * In 16bit configuration the FIFO can hold 6144 stereo samples
+ * In 24bit configuration the FIFO can hold 4096 stereo samples
+ */
+#define DAC33_FIFO_SIZE_16BIT  6144
+#define DAC33_FIFO_SIZE_24BIT  4096
+#define DAC33_MODE7_MARGIN     10      /* Safety margin for FIFO in Mode7 */
 
 #define BURST_BASEFREQ_HZ      49152000
 
@@ -100,16 +100,11 @@ struct tlv320dac33_priv {
        unsigned int refclk;
 
        unsigned int alarm_threshold;   /* set to be half of LATENCY_TIME_MS */
-       unsigned int nsample_min;       /* nsample should not be lower than
-                                        * this */
-       unsigned int nsample_max;       /* nsample should not be higher than
-                                        * this */
        enum dac33_fifo_modes fifo_mode;/* FIFO mode selection */
+       unsigned int fifo_size;         /* Size of the FIFO in samples */
        unsigned int nsample;           /* burst read amount from host */
        int mode1_latency;              /* latency caused by the i2c writes in
                                         * us */
-       int auto_fifo_config;           /* Configure the FIFO based on the
-                                        * period size */
        u8 burst_bclkdiv;               /* BCLK divider value in burst mode */
        unsigned int burst_rate;        /* Interface speed in Burst modes */
 
@@ -303,7 +298,6 @@ static void dac33_init_chip(struct snd_soc_codec *codec)
        if (unlikely(!dac33->chip_power))
                return;
 
-       /* 44-46: DAC Control Registers */
        /* A : DAC sample rate Fsref/1.5 */
        dac33_write(codec, DAC33_DAC_CTRL_A, DAC33_DACRATE(0));
        /* B : DAC src=normal, not muted */
@@ -316,8 +310,6 @@ static void dac33_init_chip(struct snd_soc_codec *codec)
         clock source = internal osc (?) */
        dac33_write(codec, DAC33_ANA_VOL_SOFT_STEP_CTRL, DAC33_VOLCLKEN);
 
-       dac33_write(codec, DAC33_PWR_CTRL, DAC33_PDNALLB);
-
        /* Restore only selected registers (gains mostly) */
        dac33_write(codec, DAC33_LDAC_DIG_VOL_CTRL,
                    dac33_read_reg_cache(codec, DAC33_LDAC_DIG_VOL_CTRL));
@@ -328,6 +320,10 @@ static void dac33_init_chip(struct snd_soc_codec *codec)
                    dac33_read_reg_cache(codec, DAC33_LINEL_TO_LLO_VOL));
        dac33_write(codec, DAC33_LINER_TO_RLO_VOL,
                    dac33_read_reg_cache(codec, DAC33_LINER_TO_RLO_VOL));
+
+       dac33_write(codec, DAC33_OUT_AMP_CTRL,
+                   dac33_read_reg_cache(codec, DAC33_OUT_AMP_CTRL));
+
 }
 
 static inline int dac33_read_id(struct snd_soc_codec *codec)
@@ -357,6 +353,21 @@ static inline void dac33_soft_power(struct snd_soc_codec *codec, int power)
        dac33_write(codec, DAC33_PWR_CTRL, reg);
 }
 
+static inline void dac33_disable_digital(struct snd_soc_codec *codec)
+{
+       u8 reg;
+
+       /* Stop the DAI clock */
+       reg = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B);
+       reg &= ~DAC33_BCLKON;
+       dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_B, reg);
+
+       /* Power down the Oscillator, and DACs */
+       reg = dac33_read_reg_cache(codec, DAC33_PWR_CTRL);
+       reg &= ~(DAC33_OSCPDNB | DAC33_DACRPDNB | DAC33_DACLPDNB);
+       dac33_write(codec, DAC33_PWR_CTRL, reg);
+}
+
 static int dac33_hard_power(struct snd_soc_codec *codec, int power)
 {
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
@@ -405,7 +416,7 @@ exit:
        return ret;
 }
 
-static int playback_event(struct snd_soc_dapm_widget *w,
+static int dac33_playback_event(struct snd_soc_dapm_widget *w,
                struct snd_kcontrol *kcontrol, int event)
 {
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(w->codec);
@@ -417,77 +428,13 @@ static int playback_event(struct snd_soc_dapm_widget *w,
                        dac33_prepare_chip(dac33->substream);
                }
                break;
+       case SND_SOC_DAPM_POST_PMD:
+               dac33_disable_digital(w->codec);
+               break;
        }
        return 0;
 }
 
-static int dac33_get_nsample(struct snd_kcontrol *kcontrol,
-                        struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
-
-       ucontrol->value.integer.value[0] = dac33->nsample;
-
-       return 0;
-}
-
-static int dac33_set_nsample(struct snd_kcontrol *kcontrol,
-                        struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
-       int ret = 0;
-
-       if (dac33->nsample == ucontrol->value.integer.value[0])
-               return 0;
-
-       if (ucontrol->value.integer.value[0] < dac33->nsample_min ||
-           ucontrol->value.integer.value[0] > dac33->nsample_max) {
-               ret = -EINVAL;
-       } else {
-               dac33->nsample = ucontrol->value.integer.value[0];
-               /* Re calculate the burst time */
-               dac33->mode1_us_burst = SAMPLES_TO_US(dac33->burst_rate,
-                                                     dac33->nsample);
-       }
-
-       return ret;
-}
-
-static int dac33_get_uthr(struct snd_kcontrol *kcontrol,
-                        struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
-
-       ucontrol->value.integer.value[0] = dac33->uthr;
-
-       return 0;
-}
-
-static int dac33_set_uthr(struct snd_kcontrol *kcontrol,
-                        struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
-       int ret = 0;
-
-       if (dac33->substream)
-               return -EBUSY;
-
-       if (dac33->uthr == ucontrol->value.integer.value[0])
-               return 0;
-
-       if (ucontrol->value.integer.value[0] < (MODE7_LTHR + 10) ||
-           ucontrol->value.integer.value[0] > MODE7_UTHR)
-               ret = -EINVAL;
-       else
-               dac33->uthr = ucontrol->value.integer.value[0];
-
-       return ret;
-}
-
 static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,
                         struct snd_ctl_elem_value *ucontrol)
 {
@@ -572,13 +519,6 @@ static const struct snd_kcontrol_new dac33_mode_snd_controls[] = {
                 dac33_get_fifo_mode, dac33_set_fifo_mode),
 };
 
-static const struct snd_kcontrol_new dac33_fifo_snd_controls[] = {
-       SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0,
-               dac33_get_nsample, dac33_set_nsample),
-       SOC_SINGLE_EXT("UTHR", 0, 0, MODE7_UTHR, 0,
-                dac33_get_uthr, dac33_set_uthr),
-};
-
 /* Analog bypass */
 static const struct snd_kcontrol_new dac33_dapm_abypassl_control =
        SOC_DAPM_SINGLE("Switch", DAC33_LINEL_TO_LLO_VOL, 7, 1, 1);
@@ -586,6 +526,25 @@ static const struct snd_kcontrol_new dac33_dapm_abypassl_control =
 static const struct snd_kcontrol_new dac33_dapm_abypassr_control =
        SOC_DAPM_SINGLE("Switch", DAC33_LINER_TO_RLO_VOL, 7, 1, 1);
 
+/* LOP L/R invert selection */
+static const char *dac33_lr_lom_texts[] = {"DAC", "LOP"};
+
+static const struct soc_enum dac33_left_lom_enum =
+       SOC_ENUM_SINGLE(DAC33_OUT_AMP_CTRL, 3,
+                       ARRAY_SIZE(dac33_lr_lom_texts),
+                       dac33_lr_lom_texts);
+
+static const struct snd_kcontrol_new dac33_dapm_left_lom_control =
+SOC_DAPM_ENUM("Route", dac33_left_lom_enum);
+
+static const struct soc_enum dac33_right_lom_enum =
+       SOC_ENUM_SINGLE(DAC33_OUT_AMP_CTRL, 2,
+                       ARRAY_SIZE(dac33_lr_lom_texts),
+                       dac33_lr_lom_texts);
+
+static const struct snd_kcontrol_new dac33_dapm_right_lom_control =
+SOC_DAPM_ENUM("Route", dac33_right_lom_enum);
+
 static const struct snd_soc_dapm_widget dac33_dapm_widgets[] = {
        SND_SOC_DAPM_OUTPUT("LEFT_LO"),
        SND_SOC_DAPM_OUTPUT("RIGHT_LO"),
@@ -593,8 +552,8 @@ static const struct snd_soc_dapm_widget dac33_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("LINEL"),
        SND_SOC_DAPM_INPUT("LINER"),
 
-       SND_SOC_DAPM_DAC("DACL", "Left Playback", DAC33_LDAC_PWR_CTRL, 2, 0),
-       SND_SOC_DAPM_DAC("DACR", "Right Playback", DAC33_RDAC_PWR_CTRL, 2, 0),
+       SND_SOC_DAPM_DAC("DACL", "Left Playback", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("DACR", "Right Playback", SND_SOC_NOPM, 0, 0),
 
        /* Analog bypass */
        SND_SOC_DAPM_SWITCH("Analog Left Bypass", SND_SOC_NOPM, 0, 0,
@@ -602,12 +561,30 @@ static const struct snd_soc_dapm_widget dac33_dapm_widgets[] = {
        SND_SOC_DAPM_SWITCH("Analog Right Bypass", SND_SOC_NOPM, 0, 0,
                                &dac33_dapm_abypassr_control),
 
-       SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Left Amp Power",
+       SND_SOC_DAPM_MUX("Left LOM Inverted From", SND_SOC_NOPM, 0, 0,
+               &dac33_dapm_left_lom_control),
+       SND_SOC_DAPM_MUX("Right LOM Inverted From", SND_SOC_NOPM, 0, 0,
+               &dac33_dapm_right_lom_control),
+       /*
+        * For DAPM path, when only the anlog bypass path is enabled, and the
+        * LOP inverted from the corresponding DAC side.
+        * This is needed, so we can attach the DAC power supply in this case.
+        */
+       SND_SOC_DAPM_PGA("Left Bypass PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Bypass PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Left Amplifier",
                         DAC33_OUT_AMP_PWR_CTRL, 6, 3, 3, 0),
-       SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Right Amp Power",
+       SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Right Amplifier",
                         DAC33_OUT_AMP_PWR_CTRL, 4, 3, 3, 0),
 
-       SND_SOC_DAPM_PRE("Prepare Playback", playback_event),
+       SND_SOC_DAPM_SUPPLY("Left DAC Power",
+                           DAC33_LDAC_PWR_CTRL, 2, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Right DAC Power",
+                           DAC33_RDAC_PWR_CTRL, 2, 0, NULL, 0),
+
+       SND_SOC_DAPM_PRE("Pre Playback", dac33_playback_event),
+       SND_SOC_DAPM_POST("Post Playback", dac33_playback_event),
 };
 
 static const struct snd_soc_dapm_route audio_map[] = {
@@ -615,24 +592,39 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Analog Left Bypass", "Switch", "LINEL"},
        {"Analog Right Bypass", "Switch", "LINER"},
 
-       {"Output Left Amp Power", NULL, "DACL"},
-       {"Output Right Amp Power", NULL, "DACR"},
+       {"Output Left Amplifier", NULL, "DACL"},
+       {"Output Right Amplifier", NULL, "DACR"},
 
-       {"Output Left Amp Power", NULL, "Analog Left Bypass"},
-       {"Output Right Amp Power", NULL, "Analog Right Bypass"},
+       {"Left Bypass PGA", NULL, "Analog Left Bypass"},
+       {"Right Bypass PGA", NULL, "Analog Right Bypass"},
+
+       {"Left LOM Inverted From", "DAC", "Left Bypass PGA"},
+       {"Right LOM Inverted From", "DAC", "Right Bypass PGA"},
+       {"Left LOM Inverted From", "LOP", "Analog Left Bypass"},
+       {"Right LOM Inverted From", "LOP", "Analog Right Bypass"},
+
+       {"Output Left Amplifier", NULL, "Left LOM Inverted From"},
+       {"Output Right Amplifier", NULL, "Right LOM Inverted From"},
+
+       {"DACL", NULL, "Left DAC Power"},
+       {"DACR", NULL, "Right DAC Power"},
+
+       {"Left Bypass PGA", NULL, "Left DAC Power"},
+       {"Right Bypass PGA", NULL, "Right DAC Power"},
 
        /* output */
-       {"LEFT_LO", NULL, "Output Left Amp Power"},
-       {"RIGHT_LO", NULL, "Output Right Amp Power"},
+       {"LEFT_LO", NULL, "Output Left Amplifier"},
+       {"RIGHT_LO", NULL, "Output Right Amplifier"},
 };
 
 static int dac33_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, dac33_dapm_widgets,
-                                 ARRAY_SIZE(dac33_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
+       snd_soc_dapm_new_controls(dapm, dac33_dapm_widgets,
+                                 ARRAY_SIZE(dac33_dapm_widgets));
        /* set up audio path interconnects */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
 }
@@ -640,16 +632,18 @@ static int dac33_add_widgets(struct snd_soc_codec *codec)
 static int dac33_set_bias_level(struct snd_soc_codec *codec,
                                enum snd_soc_bias_level level)
 {
+       struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               dac33_soft_power(codec, 1);
+               if (!dac33->substream)
+                       dac33_soft_power(codec, 1);
                break;
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        /* Coming from OFF, switch on the codec */
                        ret = dac33_hard_power(codec, 1);
                        if (ret != 0)
@@ -660,14 +654,14 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
                break;
        case SND_SOC_BIAS_OFF:
                /* Do not power off, when the codec is already off */
-               if (codec->bias_level == SND_SOC_BIAS_OFF)
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
                        return 0;
                ret = dac33_hard_power(codec, 0);
                if (ret != 0)
                        return ret;
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
 
        return 0;
 }
@@ -705,7 +699,7 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
                spin_unlock_irq(&dac33->lock);
 
                dac33_write16(codec, DAC33_PREFILL_MSB,
-                               DAC33_THRREG(MODE7_LTHR));
+                               DAC33_THRREG(DAC33_MODE7_MARGIN));
 
                /* Enable Upper Threshold IRQ */
                dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MUT);
@@ -815,6 +809,8 @@ static int dac33_startup(struct snd_pcm_substream *substream,
        /* Stream started, save the substream pointer */
        dac33->substream = substream;
 
+       snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24);
+
        return 0;
 }
 
@@ -826,18 +822,17 @@ static void dac33_shutdown(struct snd_pcm_substream *substream,
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
        dac33->substream = NULL;
-
-       /* Reset the nSample restrictions */
-       dac33->nsample_min = 0;
-       dac33->nsample_max = NSAMPLE_MAX;
 }
 
+#define CALC_BURST_RATE(bclkdiv, bclk_per_sample) \
+       (BURST_BASEFREQ_HZ / bclkdiv / bclk_per_sample)
 static int dac33_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 tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
        /* Check parameters for validity */
        switch (params_rate(params)) {
@@ -852,6 +847,12 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
 
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
+               dac33->fifo_size = DAC33_FIFO_SIZE_16BIT;
+               dac33->burst_rate = CALC_BURST_RATE(dac33->burst_bclkdiv, 32);
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               dac33->fifo_size = DAC33_FIFO_SIZE_24BIT;
+               dac33->burst_rate = CALC_BURST_RATE(dac33->burst_bclkdiv, 64);
                break;
        default:
                dev_err(codec->dev, "unsupported format %d\n",
@@ -906,6 +907,9 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
                aictrl_a |= (DAC33_NCYCL_16 | DAC33_WLEN_16);
                fifoctrl_a |= DAC33_WIDTH;
                break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               aictrl_a |= (DAC33_NCYCL_32 | DAC33_WLEN_24);
+               break;
        default:
                dev_err(codec->dev, "unsupported format %d\n",
                        substream->runtime->format);
@@ -1040,7 +1044,10 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
                dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C,
                                                        dac33->burst_bclkdiv);
        else
-               dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 32);
+               if (substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE)
+                       dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 32);
+               else
+                       dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 16);
 
        switch (dac33->fifo_mode) {
        case DAC33_FIFO_MODE1:
@@ -1053,7 +1060,8 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
                 * at the bottom, and also at the top of the FIFO
                 */
                dac33_write16(codec, DAC33_UTHR_MSB, DAC33_THRREG(dac33->uthr));
-               dac33_write16(codec, DAC33_LTHR_MSB, DAC33_THRREG(MODE7_LTHR));
+               dac33_write16(codec, DAC33_LTHR_MSB,
+                             DAC33_THRREG(DAC33_MODE7_MARGIN));
                break;
        default:
                break;
@@ -1082,42 +1090,21 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
                /* Number of samples under i2c latency */
                dac33->alarm_threshold = US_TO_SAMPLES(rate,
                                                dac33->mode1_latency);
-               nsample_limit = DAC33_BUFFER_SIZE_SAMPLES -
-                               dac33->alarm_threshold;
-
-               if (dac33->auto_fifo_config) {
-                       if (period_size <= dac33->alarm_threshold)
-                               /*
-                                * Configure nSamaple to number of periods,
-                                * which covers the latency requironment.
-                                */
-                               dac33->nsample = period_size *
-                                      ((dac33->alarm_threshold / period_size) +
-                                      (dac33->alarm_threshold % period_size ?
-                                      1 : 0));
-                       else if (period_size > nsample_limit)
-                               dac33->nsample = nsample_limit;
-                       else
-                               dac33->nsample = period_size;
-               } else {
-                       /* nSample time shall not be shorter than i2c latency */
-                       dac33->nsample_min = dac33->alarm_threshold;
+               nsample_limit = dac33->fifo_size - dac33->alarm_threshold;
+
+               if (period_size <= dac33->alarm_threshold)
                        /*
-                        * nSample should not be bigger than alsa buffer minus
-                        * size of one period to avoid overruns
+                        * Configure nSamaple to number of periods,
+                        * which covers the latency requironment.
                         */
-                       dac33->nsample_max = substream->runtime->buffer_size -
-                                               period_size;
-
-                       if (dac33->nsample_max > nsample_limit)
-                               dac33->nsample_max = nsample_limit;
-
-                       /* Correct the nSample if it is outside of the ranges */
-                       if (dac33->nsample < dac33->nsample_min)
-                               dac33->nsample = dac33->nsample_min;
-                       if (dac33->nsample > dac33->nsample_max)
-                               dac33->nsample = dac33->nsample_max;
-               }
+                       dac33->nsample = period_size *
+                               ((dac33->alarm_threshold / period_size) +
+                               (dac33->alarm_threshold % period_size ?
+                               1 : 0));
+               else if (period_size > nsample_limit)
+                       dac33->nsample = nsample_limit;
+               else
+                       dac33->nsample = period_size;
 
                dac33->mode1_us_burst = SAMPLES_TO_US(dac33->burst_rate,
                                                      dac33->nsample);
@@ -1125,19 +1112,16 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
                dac33->t_stamp2 = 0;
                break;
        case DAC33_FIFO_MODE7:
-               if (dac33->auto_fifo_config) {
-                       dac33->uthr = UTHR_FROM_PERIOD_SIZE(
-                                       period_size,
-                                       rate,
-                                       dac33->burst_rate) + 9;
-                       if (dac33->uthr > MODE7_UTHR)
-                               dac33->uthr = MODE7_UTHR;
-                       if (dac33->uthr < (MODE7_LTHR + 10))
-                               dac33->uthr = (MODE7_LTHR + 10);
-               }
+               dac33->uthr = UTHR_FROM_PERIOD_SIZE(period_size, rate,
+                                                   dac33->burst_rate) + 9;
+               if (dac33->uthr > (dac33->fifo_size - DAC33_MODE7_MARGIN))
+                       dac33->uthr = dac33->fifo_size - DAC33_MODE7_MARGIN;
+               if (dac33->uthr < (DAC33_MODE7_MARGIN + 10))
+                       dac33->uthr = (DAC33_MODE7_MARGIN + 10);
+
                dac33->mode7_us_to_lthr =
                                SAMPLES_TO_US(substream->runtime->rate,
-                                       dac33->uthr - MODE7_LTHR + 1);
+                                       dac33->uthr - DAC33_MODE7_MARGIN + 1);
                dac33->t_stamp1 = 0;
                break;
        default:
@@ -1255,8 +1239,8 @@ static snd_pcm_sframes_t dac33_dai_delay(
                        samples += (samples_in - samples_out);
 
                        if (likely(samples > 0))
-                               delay = samples > DAC33_BUFFER_SIZE_SAMPLES ?
-                                       DAC33_BUFFER_SIZE_SAMPLES : samples;
+                               delay = samples > dac33->fifo_size ?
+                                       dac33->fifo_size : samples;
                        else
                                delay = 0;
                }
@@ -1308,7 +1292,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
                        samples_in = US_TO_SAMPLES(
                                        dac33->burst_rate,
                                        time_delta);
-                       delay = MODE7_LTHR + samples_in - samples_out;
+                       delay = DAC33_MODE7_MARGIN + samples_in - samples_out;
 
                        if (unlikely(delay > uthr))
                                delay = uthr;
@@ -1415,7 +1399,7 @@ static int dac33_soc_probe(struct snd_soc_codec *codec)
 
        codec->control_data = dac33->control_data;
        codec->hw_write = (hw_write_t) i2c_master_send;
-       codec->idle_bias_off = 1;
+       codec->dapm.idle_bias_off = 1;
        dac33->codec = codec;
 
        /* Read the tlv320dac33 ID registers */
@@ -1459,14 +1443,10 @@ static int dac33_soc_probe(struct snd_soc_codec *codec)
        snd_soc_add_controls(codec, dac33_snd_controls,
                             ARRAY_SIZE(dac33_snd_controls));
        /* Only add the FIFO controls, if we have valid IRQ number */
-       if (dac33->irq >= 0) {
+       if (dac33->irq >= 0)
                snd_soc_add_controls(codec, dac33_mode_snd_controls,
                                     ARRAY_SIZE(dac33_mode_snd_controls));
-               /* FIFO usage controls only, if autoio config is not selected */
-               if (!dac33->auto_fifo_config)
-                       snd_soc_add_controls(codec, dac33_fifo_snd_controls,
-                                       ARRAY_SIZE(dac33_fifo_snd_controls));
-       }
+
        dac33_add_widgets(codec);
 
 err_power:
@@ -1515,7 +1495,7 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
 
 #define DAC33_RATES    (SNDRV_PCM_RATE_44100 | \
                         SNDRV_PCM_RATE_48000)
-#define DAC33_FORMATS  SNDRV_PCM_FMTBIT_S16_LE
+#define DAC33_FORMATS  (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
 static struct snd_soc_dai_ops dac33_dai_ops = {
        .startup        = dac33_startup,
@@ -1563,17 +1543,11 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
 
        dac33->power_gpio = pdata->power_gpio;
        dac33->burst_bclkdiv = pdata->burst_bclkdiv;
-       /* Pre calculate the burst rate */
-       dac33->burst_rate = BURST_BASEFREQ_HZ / dac33->burst_bclkdiv / 32;
        dac33->keep_bclk = pdata->keep_bclk;
-       dac33->auto_fifo_config = pdata->auto_fifo_config;
        dac33->mode1_latency = pdata->mode1_latency;
        if (!dac33->mode1_latency)
                dac33->mode1_latency = 10000; /* 10ms */
        dac33->irq = client->irq;
-       dac33->nsample = NSAMPLE_MAX;
-       dac33->nsample_max = NSAMPLE_MAX;
-       dac33->uthr = MODE7_UTHR;
        /* Disable FIFO use by default */
        dac33->fifo_mode = DAC33_FIFO_BYPASS;
 
index d2c2430..1f1ac81 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/slab.h>
 #include <sound/tpa6130a2-plat.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/tlv.h>
 
 #include "tpa6130a2.h"
@@ -42,7 +41,7 @@ struct tpa6130a2_data {
        unsigned char regs[TPA6130A2_CACHEREGNUM];
        struct regulator *supply;
        int power_gpio;
-       unsigned char power_state;
+       u8 power_state:1;
        enum tpa_model id;
 };
 
@@ -117,7 +116,7 @@ static int tpa6130a2_initialize(void)
        return ret;
 }
 
-static int tpa6130a2_power(int power)
+static int tpa6130a2_power(u8 power)
 {
        struct  tpa6130a2_data *data;
        u8      val;
@@ -127,17 +126,19 @@ static int tpa6130a2_power(int power)
        data = i2c_get_clientdata(tpa6130a2_client);
 
        mutex_lock(&data->mutex);
-       if (power && !data->power_state) {
-               /* Power on */
-               if (data->power_gpio >= 0)
-                       gpio_set_value(data->power_gpio, 1);
+       if (power == data->power_state)
+               goto exit;
 
+       if (power) {
                ret = regulator_enable(data->supply);
                if (ret != 0) {
                        dev_err(&tpa6130a2_client->dev,
                                "Failed to enable supply: %d\n", ret);
                        goto exit;
                }
+               /* Power on */
+               if (data->power_gpio >= 0)
+                       gpio_set_value(data->power_gpio, 1);
 
                data->power_state = 1;
                ret = tpa6130a2_initialize();
@@ -150,12 +151,7 @@ static int tpa6130a2_power(int power)
                        data->power_state = 0;
                        goto exit;
                }
-
-               /* Clear SWS */
-               val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
-               val &= ~TPA6130A2_SWS;
-               tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
-       } else if (!power && data->power_state) {
+       } else {
                /* set SWS */
                val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
                val |= TPA6130A2_SWS;
@@ -300,6 +296,7 @@ static void tpa6130a2_channel_enable(u8 channel, int enable)
                /* Enable amplifier */
                val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
                val |= channel;
+               val &= ~TPA6130A2_SWS;
                tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
 
                /* Unmute channel */
@@ -320,72 +317,24 @@ static void tpa6130a2_channel_enable(u8 channel, int enable)
        }
 }
 
-static int tpa6130a2_left_event(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol, int event)
-{
-       switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
-               tpa6130a2_channel_enable(TPA6130A2_HP_EN_L, 1);
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               tpa6130a2_channel_enable(TPA6130A2_HP_EN_L, 0);
-               break;
-       }
-       return 0;
-}
-
-static int tpa6130a2_right_event(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol, int event)
-{
-       switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
-               tpa6130a2_channel_enable(TPA6130A2_HP_EN_R, 1);
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               tpa6130a2_channel_enable(TPA6130A2_HP_EN_R, 0);
-               break;
-       }
-       return 0;
-}
-
-static int tpa6130a2_supply_event(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol, int event)
+int tpa6130a2_stereo_enable(struct snd_soc_codec *codec, int enable)
 {
        int ret = 0;
-
-       switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
+       if (enable) {
                ret = tpa6130a2_power(1);
-               break;
-       case SND_SOC_DAPM_POST_PMD:
+               if (ret < 0)
+                       return ret;
+               tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L,
+                                        1);
+       } else {
+               tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L,
+                                        0);
                ret = tpa6130a2_power(0);
-               break;
        }
+
        return ret;
 }
-
-static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = {
-       SND_SOC_DAPM_PGA_E("TPA6130A2 Left", SND_SOC_NOPM,
-                       0, 0, NULL, 0, tpa6130a2_left_event,
-                       SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_PGA_E("TPA6130A2 Right", SND_SOC_NOPM,
-                       0, 0, NULL, 0, tpa6130a2_right_event,
-                       SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_SUPPLY("TPA6130A2 Enable", SND_SOC_NOPM,
-                       0, 0, tpa6130a2_supply_event,
-                       SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
-       /* Outputs */
-       SND_SOC_DAPM_OUTPUT("TPA6130A2 Headphone Left"),
-       SND_SOC_DAPM_OUTPUT("TPA6130A2 Headphone Right"),
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
-       {"TPA6130A2 Headphone Left", NULL, "TPA6130A2 Left"},
-       {"TPA6130A2 Headphone Right", NULL, "TPA6130A2 Right"},
-
-       {"TPA6130A2 Headphone Left", NULL, "TPA6130A2 Enable"},
-       {"TPA6130A2 Headphone Right", NULL, "TPA6130A2 Enable"},
-};
+EXPORT_SYMBOL_GPL(tpa6130a2_stereo_enable);
 
 int tpa6130a2_add_controls(struct snd_soc_codec *codec)
 {
@@ -396,18 +345,12 @@ int tpa6130a2_add_controls(struct snd_soc_codec *codec)
 
        data = i2c_get_clientdata(tpa6130a2_client);
 
-       snd_soc_dapm_new_controls(codec, tpa6130a2_dapm_widgets,
-                               ARRAY_SIZE(tpa6130a2_dapm_widgets));
-
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
-
        if (data->id == TPA6140A2)
                return snd_soc_add_controls(codec, tpa6140a2_controls,
                                                ARRAY_SIZE(tpa6140a2_controls));
        else
                return snd_soc_add_controls(codec, tpa6130a2_controls,
                                                ARRAY_SIZE(tpa6130a2_controls));
-
 }
 EXPORT_SYMBOL_GPL(tpa6130a2_add_controls);
 
index 57e867f..5df49c8 100644 (file)
@@ -57,5 +57,6 @@
 #define TPA6130A2_VERSION_MASK         (0x0f)
 
 extern int tpa6130a2_add_controls(struct snd_soc_codec *codec);
+extern int tpa6130a2_stereo_enable(struct snd_soc_codec *codec, int enable);
 
 #endif /* __TPA6130A2_H__ */
index cbebec6..e4d464b 100644 (file)
@@ -32,7 +32,6 @@
 #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>
 
@@ -233,6 +232,16 @@ static int twl4030_write(struct snd_soc_codec *codec,
        return 0;
 }
 
+static inline void twl4030_wait_ms(int time)
+{
+       if (time < 60) {
+               time *= 1000;
+               usleep_range(time, time + 500);
+       } else {
+               msleep(time);
+       }
+}
+
 static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
 {
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
@@ -338,10 +347,14 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
        twl4030_write(codec, TWL4030_REG_ANAMICL,
                reg | TWL4030_CNCL_OFFSET_START);
 
-       /* wait for offset cancellation to complete */
+       /*
+        * Wait for offset cancellation to complete.
+        * Since this takes a while, do not slam the i2c.
+        * Start polling the status after ~20ms.
+        */
+       msleep(20);
        do {
-               /* this takes a little while, so don't slam i2c */
-               udelay(2000);
+               usleep_range(1000, 2000);
                twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
                                    TWL4030_REG_ANAMICL);
        } while ((i++ < 100) &&
@@ -725,9 +738,12 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
        /* Base values for ramp delay calculation: 2^19 - 2^26 */
        unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304,
                                    8388608, 16777216, 33554432, 67108864};
+       unsigned int delay;
 
        hs_gain = twl4030_read_reg_cache(codec, TWL4030_REG_HS_GAIN_SET);
        hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
+       delay = (ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] /
+               twl4030->sysclk) + 1;
 
        /* Enable external mute control, this dramatically reduces
         * the pop-noise */
@@ -751,16 +767,14 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
                hs_pop |= TWL4030_RAMP_EN;
                twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
                /* Wait ramp delay time + 1, so the VMID can settle */
-               mdelay((ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] /
-                       twl4030->sysclk) + 1);
+               twl4030_wait_ms(delay);
        } else {
                /* Headset ramp-down _not_ according to
                 * the TRM, but in a way that it is working */
                hs_pop &= ~TWL4030_RAMP_EN;
                twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
                /* Wait ramp delay time + 1, so the VMID can settle */
-               mdelay((ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] /
-                       twl4030->sysclk) + 1);
+               twl4030_wait_ms(delay);
                /* Bypass the reg_cache to mute the headset */
                twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
                                        hs_gain & (~0x0f),
@@ -835,7 +849,7 @@ static int digimic_event(struct snd_soc_dapm_widget *w,
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
 
        if (twl4030->digimic_delay)
-               mdelay(twl4030->digimic_delay);
+               twl4030_wait_ms(twl4030->digimic_delay);
        return 0;
 }
 
@@ -1621,10 +1635,11 @@ static const struct snd_soc_dapm_route intercon[] = {
 
 static int twl4030_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, twl4030_dapm_widgets,
-                                ARRAY_SIZE(twl4030_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+       snd_soc_dapm_new_controls(dapm, twl4030_dapm_widgets,
+                                ARRAY_SIZE(twl4030_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
 
        return 0;
 }
@@ -1638,14 +1653,14 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF)
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
                        twl4030_codec_enable(codec, 1);
                break;
        case SND_SOC_BIAS_OFF:
                twl4030_codec_enable(codec, 0);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
 
        return 0;
 }
@@ -1709,6 +1724,7 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = rtd->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 
+       snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24);
        if (twl4030->master_substream) {
                twl4030->slave_substream = substream;
                /* The DAI has one configuration for playback and capture, so
@@ -1833,7 +1849,7 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
        case SNDRV_PCM_FORMAT_S16_LE:
                format |= TWL4030_DATA_WIDTH_16S_16W;
                break;
-       case SNDRV_PCM_FORMAT_S24_LE:
+       case SNDRV_PCM_FORMAT_S32_LE:
                format |= TWL4030_DATA_WIDTH_32S_24W;
                break;
        default:
@@ -2166,7 +2182,7 @@ static int twl4030_voice_set_tristate(struct snd_soc_dai *dai, int tristate)
 }
 
 #define TWL4030_RATES   (SNDRV_PCM_RATE_8000_48000)
-#define TWL4030_FORMATS         (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE)
+#define TWL4030_FORMATS         (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
 static struct snd_soc_dai_ops twl4030_dai_hifi_ops = {
        .startup        = twl4030_startup,
@@ -2245,7 +2261,7 @@ static int twl4030_soc_probe(struct snd_soc_codec *codec)
        snd_soc_codec_set_drvdata(codec, twl4030);
        /* Set the defaults, and power up the codec */
        twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
-       codec->idle_bias_off = 1;
+       codec->dapm.idle_bias_off = 1;
 
        twl4030_init_chip(codec);
 
@@ -2257,9 +2273,12 @@ static int twl4030_soc_probe(struct snd_soc_codec *codec)
 
 static int twl4030_soc_remove(struct snd_soc_codec *codec)
 {
+       struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+
        /* Reset registers to their chip default before leaving */
        twl4030_reset_registers(codec);
        twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       kfree(twl4030);
        return 0;
 }
 
@@ -2291,10 +2310,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
 
 static int __devexit twl4030_codec_remove(struct platform_device *pdev)
 {
-       struct twl4030_priv *twl4030 = dev_get_drvdata(&pdev->dev);
-
        snd_soc_unregister_codec(&pdev->dev);
-       kfree(twl4030);
        return 0;
 }
 
index 10f6e52..4bbf1b1 100644 (file)
 #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 "twl6040.h"
 
-#define TWL6040_RATES   (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
-#define TWL6040_FORMATS         (SNDRV_PCM_FMTBIT_S32_LE)
+#define TWL6040_RATES          SNDRV_PCM_RATE_8000_96000
+#define TWL6040_FORMATS        (SNDRV_PCM_FMTBIT_S32_LE)
+
+#define TWL6040_OUTHS_0dB 0x00
+#define TWL6040_OUTHS_M30dB 0x0F
+#define TWL6040_OUTHF_0dB 0x03
+#define TWL6040_OUTHF_M52dB 0x1D
+
+#define TWL6040_RAMP_NONE      0
+#define TWL6040_RAMP_UP                1
+#define TWL6040_RAMP_DOWN      2
+
+#define TWL6040_HSL_VOL_MASK   0x0F
+#define TWL6040_HSL_VOL_SHIFT  0
+#define TWL6040_HSR_VOL_MASK   0xF0
+#define TWL6040_HSR_VOL_SHIFT  4
+#define TWL6040_HF_VOL_MASK    0x1F
+#define TWL6040_HF_VOL_SHIFT   0
+
+struct twl6040_output {
+       u16 active;
+       u16 left_vol;
+       u16 right_vol;
+       u16 left_step;
+       u16 right_step;
+       unsigned int step_delay;
+       u16 ramp;
+       u16 mute;
+       struct completion ramp_done;
+};
+
+struct twl6040_jack_data {
+       struct snd_soc_jack *jack;
+       int report;
+};
 
 /* codec private data */
 struct twl6040_data {
@@ -53,6 +85,17 @@ struct twl6040_data {
        unsigned int sysclk;
        struct snd_pcm_hw_constraint_list *sysclk_constraints;
        struct completion ready;
+       struct twl6040_jack_data hs_jack;
+       struct snd_soc_codec *codec;
+       struct workqueue_struct *workqueue;
+       struct delayed_work delayed_work;
+       struct mutex mutex;
+       struct twl6040_output headset;
+       struct twl6040_output handsfree;
+       struct workqueue_struct *hf_workqueue;
+       struct workqueue_struct *hs_workqueue;
+       struct delayed_work hs_delayed_work;
+       struct delayed_work hf_delayed_work;
 };
 
 /*
@@ -201,7 +244,7 @@ static int twl6040_read_reg_volatile(struct snd_soc_codec *codec,
        if (reg >= TWL6040_CACHEREGNUM)
                return -EIO;
 
-       twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &value, reg);
+       twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &value, reg);
        twl6040_write_reg_cache(codec, reg, value);
 
        return value;
@@ -217,7 +260,7 @@ static int twl6040_write(struct snd_soc_codec *codec,
                return -EIO;
 
        twl6040_write_reg_cache(codec, reg, value);
-       return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg);
+       return twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, value, reg);
 }
 
 static void twl6040_init_vio_regs(struct snd_soc_codec *codec)
@@ -254,6 +297,305 @@ static void twl6040_init_vdd_regs(struct snd_soc_codec *codec)
        }
 }
 
+/*
+ * Ramp HS PGA volume to minimise pops at stream startup and shutdown.
+ */
+static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec,
+                       unsigned int left_step, unsigned int right_step)
+{
+
+       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+       struct twl6040_output *headset = &priv->headset;
+       int left_complete = 0, right_complete = 0;
+       u8 reg, val;
+
+       /* left channel */
+       left_step = (left_step > 0xF) ? 0xF : left_step;
+       reg = twl6040_read_reg_cache(codec, TWL6040_REG_HSGAIN);
+       val = (~reg & TWL6040_HSL_VOL_MASK);
+
+       if (headset->ramp == TWL6040_RAMP_UP) {
+               /* ramp step up */
+               if (val < headset->left_vol) {
+                       val += left_step;
+                       reg &= ~TWL6040_HSL_VOL_MASK;
+                       twl6040_write(codec, TWL6040_REG_HSGAIN,
+                                       (reg | (~val & TWL6040_HSL_VOL_MASK)));
+               } else {
+                       left_complete = 1;
+               }
+       } else if (headset->ramp == TWL6040_RAMP_DOWN) {
+               /* ramp step down */
+               if (val > 0x0) {
+                       val -= left_step;
+                       reg &= ~TWL6040_HSL_VOL_MASK;
+                       twl6040_write(codec, TWL6040_REG_HSGAIN, reg |
+                                               (~val & TWL6040_HSL_VOL_MASK));
+               } else {
+                       left_complete = 1;
+               }
+       }
+
+       /* right channel */
+       right_step = (right_step > 0xF) ? 0xF : right_step;
+       reg = twl6040_read_reg_cache(codec, TWL6040_REG_HSGAIN);
+       val = (~reg & TWL6040_HSR_VOL_MASK) >> TWL6040_HSR_VOL_SHIFT;
+
+       if (headset->ramp == TWL6040_RAMP_UP) {
+               /* ramp step up */
+               if (val < headset->right_vol) {
+                       val += right_step;
+                       reg &= ~TWL6040_HSR_VOL_MASK;
+                       twl6040_write(codec, TWL6040_REG_HSGAIN,
+                               (reg | (~val << TWL6040_HSR_VOL_SHIFT)));
+               } else {
+                       right_complete = 1;
+               }
+       } else if (headset->ramp == TWL6040_RAMP_DOWN) {
+               /* ramp step down */
+               if (val > 0x0) {
+                       val -= right_step;
+                       reg &= ~TWL6040_HSR_VOL_MASK;
+                       twl6040_write(codec, TWL6040_REG_HSGAIN,
+                                        reg | (~val << TWL6040_HSR_VOL_SHIFT));
+               } else {
+                       right_complete = 1;
+               }
+       }
+
+       return left_complete & right_complete;
+}
+
+/*
+ * Ramp HF PGA volume to minimise pops at stream startup and shutdown.
+ */
+static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec,
+                       unsigned int left_step, unsigned int right_step)
+{
+       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+       struct twl6040_output *handsfree = &priv->handsfree;
+       int left_complete = 0, right_complete = 0;
+       u16 reg, val;
+
+       /* left channel */
+       left_step = (left_step > 0x1D) ? 0x1D : left_step;
+       reg = twl6040_read_reg_cache(codec, TWL6040_REG_HFLGAIN);
+       reg = 0x1D - reg;
+       val = (reg & TWL6040_HF_VOL_MASK);
+       if (handsfree->ramp == TWL6040_RAMP_UP) {
+               /* ramp step up */
+               if (val < handsfree->left_vol) {
+                       val += left_step;
+                       reg &= ~TWL6040_HF_VOL_MASK;
+                       twl6040_write(codec, TWL6040_REG_HFLGAIN,
+                                               reg | (0x1D - val));
+               } else {
+                       left_complete = 1;
+               }
+       } else if (handsfree->ramp == TWL6040_RAMP_DOWN) {
+               /* ramp step down */
+               if (val > 0) {
+                       val -= left_step;
+                       reg &= ~TWL6040_HF_VOL_MASK;
+                       twl6040_write(codec, TWL6040_REG_HFLGAIN,
+                                               reg | (0x1D - val));
+               } else {
+                       left_complete = 1;
+               }
+       }
+
+       /* right channel */
+       right_step = (right_step > 0x1D) ? 0x1D : right_step;
+       reg = twl6040_read_reg_cache(codec, TWL6040_REG_HFRGAIN);
+       reg = 0x1D - reg;
+       val = (reg & TWL6040_HF_VOL_MASK);
+       if (handsfree->ramp == TWL6040_RAMP_UP) {
+               /* ramp step up */
+               if (val < handsfree->right_vol) {
+                       val += right_step;
+                       reg &= ~TWL6040_HF_VOL_MASK;
+                       twl6040_write(codec, TWL6040_REG_HFRGAIN,
+                                               reg | (0x1D - val));
+               } else {
+                       right_complete = 1;
+               }
+       } else if (handsfree->ramp == TWL6040_RAMP_DOWN) {
+               /* ramp step down */
+               if (val > 0) {
+                       val -= right_step;
+                       reg &= ~TWL6040_HF_VOL_MASK;
+                       twl6040_write(codec, TWL6040_REG_HFRGAIN,
+                                               reg | (0x1D - val));
+               }
+       }
+
+       return left_complete & right_complete;
+}
+
+/*
+ * This work ramps both output PGAs at stream start/stop time to
+ * minimise pop associated with DAPM power switching.
+ */
+static void twl6040_pga_hs_work(struct work_struct *work)
+{
+       struct twl6040_data *priv =
+               container_of(work, struct twl6040_data, hs_delayed_work.work);
+       struct snd_soc_codec *codec = priv->codec;
+       struct twl6040_output *headset = &priv->headset;
+       unsigned int delay = headset->step_delay;
+       int i, headset_complete;
+
+       /* do we need to ramp at all ? */
+       if (headset->ramp == TWL6040_RAMP_NONE)
+               return;
+
+       /* HS PGA volumes have 4 bits of resolution to ramp */
+       for (i = 0; i <= 16; i++) {
+               headset_complete = 1;
+               if (headset->ramp != TWL6040_RAMP_NONE)
+                       headset_complete = twl6040_hs_ramp_step(codec,
+                                                       headset->left_step,
+                                                       headset->right_step);
+
+               /* ramp finished ? */
+               if (headset_complete)
+                       break;
+
+               /*
+                * TODO: tune: delay is longer over 0dB
+                * as increases are larger.
+                */
+               if (i >= 8)
+                       schedule_timeout_interruptible(msecs_to_jiffies(delay +
+                                                       (delay >> 1)));
+               else
+                       schedule_timeout_interruptible(msecs_to_jiffies(delay));
+       }
+
+       if (headset->ramp == TWL6040_RAMP_DOWN) {
+               headset->active = 0;
+               complete(&headset->ramp_done);
+       } else {
+               headset->active = 1;
+       }
+       headset->ramp = TWL6040_RAMP_NONE;
+}
+
+static void twl6040_pga_hf_work(struct work_struct *work)
+{
+       struct twl6040_data *priv =
+               container_of(work, struct twl6040_data, hf_delayed_work.work);
+       struct snd_soc_codec *codec = priv->codec;
+       struct twl6040_output *handsfree = &priv->handsfree;
+       unsigned int delay = handsfree->step_delay;
+       int i, handsfree_complete;
+
+       /* do we need to ramp at all ? */
+       if (handsfree->ramp == TWL6040_RAMP_NONE)
+               return;
+
+       /* HF PGA volumes have 5 bits of resolution to ramp */
+       for (i = 0; i <= 32; i++) {
+               handsfree_complete = 1;
+               if (handsfree->ramp != TWL6040_RAMP_NONE)
+                       handsfree_complete = twl6040_hf_ramp_step(codec,
+                                                       handsfree->left_step,
+                                                       handsfree->right_step);
+
+               /* ramp finished ? */
+               if (handsfree_complete)
+                       break;
+
+               /*
+                * TODO: tune: delay is longer over 0dB
+                * as increases are larger.
+                */
+               if (i >= 16)
+                       schedule_timeout_interruptible(msecs_to_jiffies(delay +
+                                                      (delay >> 1)));
+               else
+                       schedule_timeout_interruptible(msecs_to_jiffies(delay));
+       }
+
+
+       if (handsfree->ramp == TWL6040_RAMP_DOWN) {
+               handsfree->active = 0;
+               complete(&handsfree->ramp_done);
+       } else
+               handsfree->active = 1;
+       handsfree->ramp = TWL6040_RAMP_NONE;
+}
+
+static int pga_event(struct snd_soc_dapm_widget *w,
+                       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+       struct twl6040_output *out;
+       struct delayed_work *work;
+       struct workqueue_struct *queue;
+
+       switch (w->shift) {
+       case 2:
+       case 3:
+               out = &priv->headset;
+               work = &priv->hs_delayed_work;
+               queue = priv->hs_workqueue;
+               out->step_delay = 5;    /* 5 ms between volume ramp steps */
+               break;
+       case 4:
+               out = &priv->handsfree;
+               work = &priv->hf_delayed_work;
+               queue = priv->hf_workqueue;
+               out->step_delay = 5;    /* 5 ms between volume ramp steps */
+               if (SND_SOC_DAPM_EVENT_ON(event))
+                       priv->non_lp++;
+               else
+                       priv->non_lp--;
+               break;
+       default:
+               return -1;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               if (out->active)
+                       break;
+
+               /* don't use volume ramp for power-up */
+               out->left_step = out->left_vol;
+               out->right_step = out->right_vol;
+
+               if (!delayed_work_pending(work)) {
+                       out->ramp = TWL6040_RAMP_UP;
+                       queue_delayed_work(queue, work,
+                                       msecs_to_jiffies(1));
+               }
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               if (!out->active)
+                       break;
+
+               if (!delayed_work_pending(work)) {
+                       /* use volume ramp for power-down */
+                       out->left_step = 1;
+                       out->right_step = 1;
+                       out->ramp = TWL6040_RAMP_DOWN;
+                       INIT_COMPLETION(out->ramp_done);
+
+                       queue_delayed_work(queue, work,
+                                       msecs_to_jiffies(1));
+
+                       wait_for_completion_timeout(&out->ramp_done,
+                                       msecs_to_jiffies(2000));
+               }
+               break;
+       }
+
+       return 0;
+}
+
 /* twl6040 codec manual power-up sequence */
 static void twl6040_power_up(struct snd_soc_codec *codec)
 {
@@ -382,6 +724,47 @@ static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
+void twl6040_hs_jack_report(struct snd_soc_codec *codec,
+                               struct snd_soc_jack *jack, int report)
+{
+       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+       int status;
+
+       mutex_lock(&priv->mutex);
+
+       /* Sync status */
+       status = twl6040_read_reg_volatile(codec, TWL6040_REG_STATUS);
+       if (status & TWL6040_PLUGCOMP)
+               snd_soc_jack_report(jack, report, report);
+       else
+               snd_soc_jack_report(jack, 0, report);
+
+       mutex_unlock(&priv->mutex);
+}
+
+void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
+                               struct snd_soc_jack *jack, int report)
+{
+       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+       struct twl6040_jack_data *hs_jack = &priv->hs_jack;
+
+       hs_jack->jack = jack;
+       hs_jack->report = report;
+
+       twl6040_hs_jack_report(codec, hs_jack->jack, hs_jack->report);
+}
+EXPORT_SYMBOL_GPL(twl6040_hs_jack_detect);
+
+static void twl6040_accessory_work(struct work_struct *work)
+{
+       struct twl6040_data *priv = container_of(work,
+                                       struct twl6040_data, delayed_work.work);
+       struct snd_soc_codec *codec = priv->codec;
+       struct twl6040_jack_data *hs_jack = &priv->hs_jack;
+
+       twl6040_hs_jack_report(codec, hs_jack->jack, hs_jack->report);
+}
+
 /* audio interrupt handler */
 static irqreturn_t twl6040_naudint_handler(int irq, void *data)
 {
@@ -389,33 +772,180 @@ static irqreturn_t twl6040_naudint_handler(int irq, void *data)
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
        u8 intid;
 
-       twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &intid, TWL6040_REG_INTID);
+       twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &intid, TWL6040_REG_INTID);
 
-       switch (intid) {
-       case TWL6040_THINT:
+       if (intid & TWL6040_THINT)
                dev_alert(codec->dev, "die temp over-limit detection\n");
+
+       if ((intid & TWL6040_PLUGINT) || (intid & TWL6040_UNPLUGINT))
+               queue_delayed_work(priv->workqueue, &priv->delayed_work,
+                                                       msecs_to_jiffies(200));
+
+       if (intid & TWL6040_HOOKINT)
+               dev_info(codec->dev, "hook detection\n");
+
+       if (intid & TWL6040_HFINT)
+               dev_alert(codec->dev, "hf drivers over current detection\n");
+
+       if (intid & TWL6040_VIBINT)
+               dev_alert(codec->dev, "vib drivers over current detection\n");
+
+       if (intid & TWL6040_READYINT)
+               complete(&priv->ready);
+
+       return IRQ_HANDLED;
+}
+
+static int twl6040_put_volsw(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct twl6040_data *twl6040_priv = snd_soc_codec_get_drvdata(codec);
+       struct twl6040_output *out = NULL;
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       int ret;
+       unsigned int reg = mc->reg;
+
+       /* For HS and HF we shadow the values and only actually write
+        * them out when active in order to ensure the amplifier comes on
+        * as quietly as possible. */
+       switch (reg) {
+       case TWL6040_REG_HSGAIN:
+               out = &twl6040_priv->headset;
                break;
-       case TWL6040_PLUGINT:
-       case TWL6040_UNPLUGINT:
-       case TWL6040_HOOKINT:
+       default:
                break;
-       case TWL6040_HFINT:
-               dev_alert(codec->dev, "hf drivers over current detection\n");
+       }
+
+       if (out) {
+               out->left_vol = ucontrol->value.integer.value[0];
+               out->right_vol = ucontrol->value.integer.value[1];
+               if (!out->active)
+                       return 1;
+       }
+
+       ret = snd_soc_put_volsw(kcontrol, ucontrol);
+       if (ret < 0)
+               return ret;
+
+       return 1;
+}
+
+static int twl6040_get_volsw(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct twl6040_data *twl6040_priv = snd_soc_codec_get_drvdata(codec);
+       struct twl6040_output *out = &twl6040_priv->headset;
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       unsigned int reg = mc->reg;
+
+       switch (reg) {
+       case TWL6040_REG_HSGAIN:
+               out = &twl6040_priv->headset;
+               ucontrol->value.integer.value[0] = out->left_vol;
+               ucontrol->value.integer.value[1] = out->right_vol;
+               return 0;
+
+       default:
                break;
-       case TWL6040_VIBINT:
-               dev_alert(codec->dev, "vib drivers over current detection\n");
+       }
+
+       return snd_soc_get_volsw(kcontrol, ucontrol);
+}
+
+static int twl6040_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct twl6040_data *twl6040_priv = snd_soc_codec_get_drvdata(codec);
+       struct twl6040_output *out = NULL;
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       int ret;
+       unsigned int reg = mc->reg;
+
+       /* For HS and HF we shadow the values and only actually write
+        * them out when active in order to ensure the amplifier comes on
+        * as quietly as possible. */
+       switch (reg) {
+       case TWL6040_REG_HFLGAIN:
+       case TWL6040_REG_HFRGAIN:
+               out = &twl6040_priv->handsfree;
                break;
-       case TWL6040_READYINT:
-               complete(&priv->ready);
+       default:
                break;
+       }
+
+       if (out) {
+               out->left_vol = ucontrol->value.integer.value[0];
+               out->right_vol = ucontrol->value.integer.value[1];
+               if (!out->active)
+                       return 1;
+       }
+
+       ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
+       if (ret < 0)
+               return ret;
+
+       return 1;
+}
+
+static int twl6040_get_volsw_2r(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct twl6040_data *twl6040_priv = snd_soc_codec_get_drvdata(codec);
+       struct twl6040_output *out = &twl6040_priv->handsfree;
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       unsigned int reg = mc->reg;
+
+       /* If these are cached registers use the cache */
+       switch (reg) {
+       case TWL6040_REG_HFLGAIN:
+       case TWL6040_REG_HFRGAIN:
+               out = &twl6040_priv->handsfree;
+               ucontrol->value.integer.value[0] = out->left_vol;
+               ucontrol->value.integer.value[1] = out->right_vol;
+               return 0;
+
        default:
-               dev_err(codec->dev, "unknown audio interrupt %d\n", intid);
                break;
        }
 
-       return IRQ_HANDLED;
+       return snd_soc_get_volsw_2r(kcontrol, ucontrol);
 }
 
+/* double control with volume update */
+#define SOC_TWL6040_DOUBLE_TLV(xname, xreg, shift_left, shift_right, xmax,\
+                                                       xinvert, tlv_array)\
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+                SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .tlv.p = (tlv_array), \
+       .info = snd_soc_info_volsw, .get = twl6040_get_volsw, \
+       .put = twl6040_put_volsw, \
+       .private_value = (unsigned long)&(struct soc_mixer_control) \
+               {.reg = xreg, .shift = shift_left, .rshift = shift_right,\
+                .max = xmax, .platform_max = xmax, .invert = xinvert} }
+
+/* double control with volume update */
+#define SOC_TWL6040_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax,\
+                               xinvert, tlv_array)\
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+               SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+               SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
+       .tlv.p = (tlv_array), \
+       .info = snd_soc_info_volsw_2r, \
+       .get = twl6040_get_volsw_2r, .put = twl6040_put_volsw_2r_vu, \
+       .private_value = (unsigned long)&(struct soc_mixer_control) \
+               {.reg = reg_left, .rreg = reg_right, .shift = xshift, \
+                .rshift = xshift, .max = xmax, .invert = xinvert}, }
+
 /*
  * MICATT volume control:
  * from -6 to 0 dB in 6 dB steps
@@ -424,9 +954,15 @@ static DECLARE_TLV_DB_SCALE(mic_preamp_tlv, -600, 600, 0);
 
 /*
  * MICGAIN volume control:
- * from 6 to 30 dB in 6 dB steps
+ * from -6 to 30 dB in 6 dB steps
  */
-static DECLARE_TLV_DB_SCALE(mic_amp_tlv, 600, 600, 0);
+static DECLARE_TLV_DB_SCALE(mic_amp_tlv, -600, 600, 0);
+
+/*
+ * AFMGAIN volume control:
+ * from 18 to 24 dB in 6 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(afm_amp_tlv, 1800, 600, 0);
 
 /*
  * HSGAIN volume control:
@@ -455,8 +991,30 @@ static const char *twl6040_amicr_texts[] =
        {"Headset Mic", "Sub Mic", "Aux/FM Right", "Off"};
 
 static const struct soc_enum twl6040_enum[] = {
-       SOC_ENUM_SINGLE(TWL6040_REG_MICLCTL, 3, 3, twl6040_amicl_texts),
-       SOC_ENUM_SINGLE(TWL6040_REG_MICRCTL, 3, 3, twl6040_amicr_texts),
+       SOC_ENUM_SINGLE(TWL6040_REG_MICLCTL, 3, 4, twl6040_amicl_texts),
+       SOC_ENUM_SINGLE(TWL6040_REG_MICRCTL, 3, 4, twl6040_amicr_texts),
+};
+
+static const char *twl6040_hs_texts[] = {
+       "Off", "HS DAC", "Line-In amp"
+};
+
+static const struct soc_enum twl6040_hs_enum[] = {
+       SOC_ENUM_SINGLE(TWL6040_REG_HSLCTL, 5, ARRAY_SIZE(twl6040_hs_texts),
+                       twl6040_hs_texts),
+       SOC_ENUM_SINGLE(TWL6040_REG_HSRCTL, 5, ARRAY_SIZE(twl6040_hs_texts),
+                       twl6040_hs_texts),
+};
+
+static const char *twl6040_hf_texts[] = {
+       "Off", "HF DAC", "Line-In amp"
+};
+
+static const struct soc_enum twl6040_hf_enum[] = {
+       SOC_ENUM_SINGLE(TWL6040_REG_HFLCTL, 2, ARRAY_SIZE(twl6040_hf_texts),
+                       twl6040_hf_texts),
+       SOC_ENUM_SINGLE(TWL6040_REG_HFRCTL, 2, ARRAY_SIZE(twl6040_hf_texts),
+                       twl6040_hf_texts),
 };
 
 static const struct snd_kcontrol_new amicl_control =
@@ -466,18 +1024,18 @@ static const struct snd_kcontrol_new amicr_control =
        SOC_DAPM_ENUM("Route", twl6040_enum[1]);
 
 /* Headset DAC playback switches */
-static const struct snd_kcontrol_new hsdacl_switch_controls =
-       SOC_DAPM_SINGLE("Switch", TWL6040_REG_HSLCTL, 5, 1, 0);
+static const struct snd_kcontrol_new hsl_mux_controls =
+       SOC_DAPM_ENUM("Route", twl6040_hs_enum[0]);
 
-static const struct snd_kcontrol_new hsdacr_switch_controls =
-       SOC_DAPM_SINGLE("Switch", TWL6040_REG_HSRCTL, 5, 1, 0);
+static const struct snd_kcontrol_new hsr_mux_controls =
+       SOC_DAPM_ENUM("Route", twl6040_hs_enum[1]);
 
 /* Handsfree DAC playback switches */
-static const struct snd_kcontrol_new hfdacl_switch_controls =
-       SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFLCTL, 2, 1, 0);
+static const struct snd_kcontrol_new hfl_mux_controls =
+       SOC_DAPM_ENUM("Route", twl6040_hf_enum[0]);
 
-static const struct snd_kcontrol_new hfdacr_switch_controls =
-       SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFRCTL, 2, 1, 0);
+static const struct snd_kcontrol_new hfr_mux_controls =
+       SOC_DAPM_ENUM("Route", twl6040_hf_enum[1]);
 
 static const struct snd_kcontrol_new ep_driver_switch_controls =
        SOC_DAPM_SINGLE("Switch", TWL6040_REG_EARCTL, 0, 1, 0);
@@ -489,10 +1047,14 @@ static const struct snd_kcontrol_new twl6040_snd_controls[] = {
        SOC_DOUBLE_TLV("Capture Volume",
                TWL6040_REG_MICGAIN, 0, 3, 4, 0, mic_amp_tlv),
 
+       /* AFM gains */
+       SOC_DOUBLE_TLV("Aux FM Volume",
+               TWL6040_REG_LINEGAIN, 0, 4, 0xF, 0, afm_amp_tlv),
+
        /* Playback gains */
-       SOC_DOUBLE_TLV("Headset Playback Volume",
+       SOC_TWL6040_DOUBLE_TLV("Headset Playback Volume",
                TWL6040_REG_HSGAIN, 0, 4, 0xF, 1, hs_tlv),
-       SOC_DOUBLE_R_TLV("Handsfree Playback Volume",
+       SOC_TWL6040_DOUBLE_R_TLV("Handsfree Playback Volume",
                TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1, hf_tlv),
        SOC_SINGLE_TLV("Earphone Playback Volume",
                TWL6040_REG_EARCTL, 1, 0xF, 1, ep_tlv),
@@ -525,6 +1087,12 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
        SND_SOC_DAPM_PGA("MicAmpR",
                        TWL6040_REG_MICRCTL, 0, 0, NULL, 0),
 
+       /* Auxiliary FM PGAs */
+       SND_SOC_DAPM_PGA("AFMAmpL",
+                       TWL6040_REG_MICLCTL, 1, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("AFMAmpR",
+                       TWL6040_REG_MICRCTL, 1, 0, NULL, 0),
+
        /* ADCs */
        SND_SOC_DAPM_ADC("ADC Left", "Left Front Capture",
                        TWL6040_REG_MICLCTL, 2, 0),
@@ -559,29 +1127,33 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
                        twl6040_power_mode_event,
                        SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
-       /* Analog playback switches */
-       SND_SOC_DAPM_SWITCH("HSDAC Left Playback",
-                       SND_SOC_NOPM, 0, 0, &hsdacl_switch_controls),
-       SND_SOC_DAPM_SWITCH("HSDAC Right Playback",
-                       SND_SOC_NOPM, 0, 0, &hsdacr_switch_controls),
-       SND_SOC_DAPM_SWITCH("HFDAC Left Playback",
-                       SND_SOC_NOPM, 0, 0, &hfdacl_switch_controls),
-       SND_SOC_DAPM_SWITCH("HFDAC Right Playback",
-                       SND_SOC_NOPM, 0, 0, &hfdacr_switch_controls),
+       SND_SOC_DAPM_MUX("HF Left Playback",
+                       SND_SOC_NOPM, 0, 0, &hfl_mux_controls),
+       SND_SOC_DAPM_MUX("HF Right Playback",
+                       SND_SOC_NOPM, 0, 0, &hfr_mux_controls),
+       /* Analog playback Muxes */
+       SND_SOC_DAPM_MUX("HS Left Playback",
+                       SND_SOC_NOPM, 0, 0, &hsl_mux_controls),
+       SND_SOC_DAPM_MUX("HS Right Playback",
+                       SND_SOC_NOPM, 0, 0, &hsr_mux_controls),
 
        /* Analog playback drivers */
-       SND_SOC_DAPM_PGA_E("Handsfree Left Driver",
+       SND_SOC_DAPM_OUT_DRV_E("Handsfree Left Driver",
                        TWL6040_REG_HFLCTL, 4, 0, NULL, 0,
-                       twl6040_power_mode_event,
-                       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_PGA_E("Handsfree Right Driver",
+                       pga_event,
+                       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_OUT_DRV_E("Handsfree Right Driver",
                        TWL6040_REG_HFRCTL, 4, 0, NULL, 0,
-                       twl6040_power_mode_event,
-                       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
-       SND_SOC_DAPM_PGA("Headset Left Driver",
-                       TWL6040_REG_HSLCTL, 2, 0, NULL, 0),
-       SND_SOC_DAPM_PGA("Headset Right Driver",
-                       TWL6040_REG_HSRCTL, 2, 0, NULL, 0),
+                       pga_event,
+                       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_OUT_DRV_E("Headset Left Driver",
+                       TWL6040_REG_HSLCTL, 2, 0, NULL, 0,
+                       pga_event,
+                       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_OUT_DRV_E("Headset Right Driver",
+                       TWL6040_REG_HSRCTL, 2, 0, NULL, 0,
+                       pga_event,
+                       SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
        SND_SOC_DAPM_SWITCH_E("Earphone Driver",
                        SND_SOC_NOPM, 0, 0, &ep_driver_switch_controls,
                        twl6040_power_mode_event,
@@ -611,12 +1183,18 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"ADC Left", NULL, "MicAmpL"},
        {"ADC Right", NULL, "MicAmpR"},
 
-       /* Headset playback path */
-       {"HSDAC Left Playback", "Switch", "HSDAC Left"},
-       {"HSDAC Right Playback", "Switch", "HSDAC Right"},
+       /* AFM path */
+       {"AFMAmpL", "NULL", "AFML"},
+       {"AFMAmpR", "NULL", "AFMR"},
+
+       {"HS Left Playback", "HS DAC", "HSDAC Left"},
+       {"HS Left Playback", "Line-In amp", "AFMAmpL"},
 
-       {"Headset Left Driver", NULL, "HSDAC Left Playback"},
-       {"Headset Right Driver", NULL, "HSDAC Right Playback"},
+       {"HS Right Playback", "HS DAC", "HSDAC Right"},
+       {"HS Right Playback", "Line-In amp", "AFMAmpR"},
+
+       {"Headset Left Driver", "NULL", "HS Left Playback"},
+       {"Headset Right Driver", "NULL", "HS Right Playback"},
 
        {"HSOL", NULL, "Headset Left Driver"},
        {"HSOR", NULL, "Headset Right Driver"},
@@ -625,12 +1203,14 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Earphone Driver", "Switch", "HSDAC Left"},
        {"EP", NULL, "Earphone Driver"},
 
-       /* Handsfree playback path */
-       {"HFDAC Left Playback", "Switch", "HFDAC Left"},
-       {"HFDAC Right Playback", "Switch", "HFDAC Right"},
+       {"HF Left Playback", "HF DAC", "HFDAC Left"},
+       {"HF Left Playback", "Line-In amp", "AFMAmpL"},
+
+       {"HF Right Playback", "HF DAC", "HFDAC Right"},
+       {"HF Right Playback", "Line-In amp", "AFMAmpR"},
 
-       {"HFDAC Left PGA", NULL, "HFDAC Left Playback"},
-       {"HFDAC Right PGA", NULL, "HFDAC Right Playback"},
+       {"HFDAC Left PGA", NULL, "HF Left Playback"},
+       {"HFDAC Right PGA", NULL, "HF Right Playback"},
 
        {"Handsfree Left Driver", "Switch", "HFDAC Left PGA"},
        {"Handsfree Right Driver", "Switch", "HFDAC Right PGA"},
@@ -641,12 +1221,12 @@ static const struct snd_soc_dapm_route intercon[] = {
 
 static int twl6040_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, twl6040_dapm_widgets,
-                                ARRAY_SIZE(twl6040_dapm_widgets));
-
-       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_new_widgets(codec);
+       snd_soc_dapm_new_controls(dapm, twl6040_dapm_widgets,
+                                ARRAY_SIZE(twl6040_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
+       snd_soc_dapm_new_widgets(dapm);
 
        return 0;
 }
@@ -659,10 +1239,10 @@ static int twl6040_power_up_completion(struct snd_soc_codec *codec,
        u8 intid;
 
        time_left = wait_for_completion_timeout(&priv->ready,
-                               msecs_to_jiffies(48));
+                               msecs_to_jiffies(144));
 
        if (!time_left) {
-               twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &intid,
+               twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &intid,
                                                        TWL6040_REG_INTID);
                if (!(intid & TWL6040_READYINT)) {
                        dev_err(codec->dev, "timeout waiting for READYINT\n");
@@ -713,6 +1293,15 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
 
                /* initialize vdd/vss registers with reg_cache */
                twl6040_init_vdd_regs(codec);
+
+               /* Set external boost GPO */
+               twl6040_write(codec, TWL6040_REG_GPOCTL, 0x02);
+
+               /* Set initial minimal gain values */
+               twl6040_write(codec, TWL6040_REG_HSGAIN, 0xFF);
+               twl6040_write(codec, TWL6040_REG_EARCTL, 0x1E);
+               twl6040_write(codec, TWL6040_REG_HFLGAIN, 0x1D);
+               twl6040_write(codec, TWL6040_REG_HFRGAIN, 0x1D);
                break;
        case SND_SOC_BIAS_OFF:
                if (!priv->codec_powered)
@@ -739,7 +1328,7 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
 
        return 0;
 }
@@ -772,23 +1361,6 @@ static int twl6040_startup(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = rtd->codec;
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 
-       if (!priv->sysclk) {
-               dev_err(codec->dev,
-                       "no mclk configured, call set_sysclk() on init\n");
-               return -EINVAL;
-       }
-
-       /*
-        * capture is not supported at 17.64 MHz,
-        * it's reserved for headset low-power playback scenario
-        */
-       if ((priv->sysclk == 17640000) && substream->stream) {
-               dev_err(codec->dev,
-                       "capture mode is not supported at %dHz\n",
-                       priv->sysclk);
-               return -EINVAL;
-       }
-
        snd_pcm_hw_constraint_list(substream->runtime, 0,
                                SNDRV_PCM_HW_PARAM_RATE,
                                priv->sysclk_constraints);
@@ -814,10 +1386,17 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
 
        rate = params_rate(params);
        switch (rate) {
+       case 11250:
+       case 22500:
+       case 44100:
        case 88200:
                lppllctl |= TWL6040_LPLLFIN;
                priv->sysclk = 17640000;
                break;
+       case 8000:
+       case 16000:
+       case 32000:
+       case 48000:
        case 96000:
                lppllctl &= ~TWL6040_LPLLFIN;
                priv->sysclk = 19200000;
@@ -832,31 +1411,37 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int twl6040_trigger(struct snd_pcm_substream *substream,
-                       int cmd, struct snd_soc_dai *dai)
+static int twl6040_prepare(struct snd_pcm_substream *substream,
+                       struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_codec *codec = rtd->codec;
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-               /*
-                * low-power playback mode is restricted
-                * for headset path only
-                */
-               if ((priv->sysclk == 17640000) && priv->non_lp) {
+       if (!priv->sysclk) {
+               dev_err(codec->dev,
+                       "no mclk configured, call set_sysclk() on init\n");
+               return -EINVAL;
+       }
+
+       /*
+        * capture is not supported at 17.64 MHz,
+        * it's reserved for headset low-power playback scenario
+        */
+       if ((priv->sysclk == 17640000) &&
+                       substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               dev_err(codec->dev,
+                       "capture mode is not supported at %dHz\n",
+                       priv->sysclk);
+               return -EINVAL;
+       }
+
+       if ((priv->sysclk == 17640000) && priv->non_lp) {
                        dev_err(codec->dev,
                                "some enabled paths aren't supported at %dHz\n",
                                priv->sysclk);
                        return -EPERM;
-               }
-               break;
-       default:
-               break;
        }
-
        return 0;
 }
 
@@ -970,7 +1555,7 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static struct snd_soc_dai_ops twl6040_dai_ops = {
        .startup        = twl6040_startup,
        .hw_params      = twl6040_hw_params,
-       .trigger        = twl6040_trigger,
+       .prepare        = twl6040_prepare,
        .set_sysclk     = twl6040_set_dai_sysclk,
 };
 
@@ -1004,6 +1589,7 @@ static int twl6040_suspend(struct snd_soc_codec *codec, pm_message_t state)
 static int twl6040_resume(struct snd_soc_codec *codec)
 {
        twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       twl6040_set_bias_level(codec, codec->dapm.suspend_bias_level);
 
        return 0;
 }
@@ -1018,24 +1604,41 @@ static int twl6040_probe(struct snd_soc_codec *codec)
        struct twl6040_data *priv;
        int audpwron, naudint;
        int ret = 0;
+       u8 icrev, intmr = TWL6040_ALLINT_MSK;
 
        priv = kzalloc(sizeof(struct twl6040_data), GFP_KERNEL);
        if (priv == NULL)
                return -ENOMEM;
        snd_soc_codec_set_drvdata(codec, priv);
 
-       if (twl_codec) {
+       priv->codec = codec;
+
+       twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &icrev, TWL6040_REG_ASICREV);
+
+       if (twl_codec && (icrev > 0))
                audpwron = twl_codec->audpwron_gpio;
-               naudint = twl_codec->naudint_irq;
-       } else {
+       else
                audpwron = -EINVAL;
+
+       if (twl_codec)
+               naudint = twl_codec->naudint_irq;
+       else
                naudint = 0;
-       }
 
        priv->audpwron = audpwron;
        priv->naudint = naudint;
+       priv->workqueue = create_singlethread_workqueue("twl6040-codec");
+
+       if (!priv->workqueue)
+               goto work_err;
+
+       INIT_DELAYED_WORK(&priv->delayed_work, twl6040_accessory_work);
+
+       mutex_init(&priv->mutex);
 
        init_completion(&priv->ready);
+       init_completion(&priv->headset.ramp_done);
+       init_completion(&priv->handsfree.ramp_done);
 
        if (gpio_is_valid(audpwron)) {
                ret = gpio_request(audpwron, "audpwron");
@@ -1047,7 +1650,14 @@ static int twl6040_probe(struct snd_soc_codec *codec)
                        goto gpio2_err;
 
                priv->codec_powered = 0;
+
+               /* enable only codec ready interrupt */
+               intmr &= ~(TWL6040_READYMSK | TWL6040_PLUGMSK);
+
+               /* reset interrupt status to allow correct power up sequence */
+               twl6040_read_reg_volatile(codec, TWL6040_REG_INTID);
        }
+       twl6040_write(codec, TWL6040_REG_INTMR, intmr);
 
        if (naudint) {
                /* audio interrupt */
@@ -1057,25 +1667,29 @@ static int twl6040_probe(struct snd_soc_codec *codec)
                                "twl6040_codec", codec);
                if (ret)
                        goto gpio2_err;
-       } else {
-               if (gpio_is_valid(audpwron)) {
-                       /* enable only codec ready interrupt */
-                       twl6040_write_reg_cache(codec, TWL6040_REG_INTMR,
-                                       ~TWL6040_READYMSK & TWL6040_ALLINT_MSK);
-               } else {
-                       /* no interrupts at all */
-                       twl6040_write_reg_cache(codec, TWL6040_REG_INTMR,
-                                               TWL6040_ALLINT_MSK);
-               }
        }
 
        /* init vio registers */
        twl6040_init_vio_regs(codec);
 
+       priv->hf_workqueue = create_singlethread_workqueue("twl6040-hf");
+       if (priv->hf_workqueue == NULL) {
+               ret = -ENOMEM;
+               goto irq_err;
+       }
+       priv->hs_workqueue = create_singlethread_workqueue("twl6040-hs");
+       if (priv->hs_workqueue == NULL) {
+               ret = -ENOMEM;
+               goto wq_err;
+       }
+
+       INIT_DELAYED_WORK(&priv->hs_delayed_work, twl6040_pga_hs_work);
+       INIT_DELAYED_WORK(&priv->hf_delayed_work, twl6040_pga_hf_work);
+
        /* power on device */
        ret = twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        if (ret)
-               goto irq_err;
+               goto bias_err;
 
        snd_soc_add_controls(codec, twl6040_snd_controls,
                                ARRAY_SIZE(twl6040_snd_controls));
@@ -1083,6 +1697,10 @@ static int twl6040_probe(struct snd_soc_codec *codec)
 
        return 0;
 
+bias_err:
+       destroy_workqueue(priv->hs_workqueue);
+wq_err:
+       destroy_workqueue(priv->hf_workqueue);
 irq_err:
        if (naudint)
                free_irq(naudint, codec);
@@ -1090,6 +1708,8 @@ gpio2_err:
        if (gpio_is_valid(audpwron))
                gpio_free(audpwron);
 gpio1_err:
+       destroy_workqueue(priv->workqueue);
+work_err:
        kfree(priv);
        return ret;
 }
@@ -1108,6 +1728,9 @@ static int twl6040_remove(struct snd_soc_codec *codec)
        if (naudint)
                free_irq(naudint, codec);
 
+       destroy_workqueue(priv->workqueue);
+       destroy_workqueue(priv->hf_workqueue);
+       destroy_workqueue(priv->hs_workqueue);
        kfree(priv);
 
        return 0;
index f7c77fa..23aeed0 100644 (file)
@@ -79,6 +79,7 @@
 
 /* INTMR (0x04) fields */
 
+#define TWL6040_PLUGMSK                        0x02
 #define TWL6040_READYMSK               0x40
 #define TWL6040_ALLINT_MSK             0x7B
 
 #define TWL6040_HPPLL_ID               1
 #define TWL6040_LPPLL_ID               2
 
+/* STATUS (0x2E) fields */
+
+#define TWL6040_PLUGCOMP               0x02
+
+void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
+                           struct snd_soc_jack *jack, int report);
+
 #endif /* End of __TWL6040_H__ */
index 464f0cf..e76847a 100644 (file)
@@ -19,7 +19,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/initval.h>
 
 #include <sound/uda134x.h>
@@ -389,7 +388,7 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec,
                        pd->power(0);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index 0c6c725..c5ca8cf 100644 (file)
@@ -27,7 +27,6 @@
 #include <sound/control.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/tlv.h>
 #include <sound/uda1380.h>
 
@@ -36,7 +35,6 @@
 /* codec private data */
 struct uda1380_priv {
        struct snd_soc_codec *codec;
-       u16 reg_cache[UDA1380_CACHEREGNUM];
        unsigned int dac_clk;
        struct work_struct work;
        void *control_data;
@@ -414,10 +412,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int uda1380_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets,
-                                 ARRAY_SIZE(uda1380_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_new_controls(dapm, uda1380_dapm_widgets,
+                                 ARRAY_SIZE(uda1380_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
 }
@@ -603,7 +602,7 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
        int reg;
        struct uda1380_platform_data *pdata = codec->dev->platform_data;
 
-       if (codec->bias_level == level)
+       if (codec->dapm.bias_level == level)
                return 0;
 
        switch (level) {
@@ -613,7 +612,7 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
                uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm);
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        if (gpio_is_valid(pdata->gpio_power)) {
                                gpio_set_value(pdata->gpio_power, 1);
                                mdelay(1);
@@ -636,7 +635,7 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
                for (reg = UDA1380_MVOL; reg < UDA1380_CACHEREGNUM; reg++)
                        set_bit(reg - 0x10, &uda1380_cache_dirty);
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index 0c47c78..d3ffa2f 100644 (file)
@@ -25,8 +25,7 @@
 #include <linux/slab.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
-#include <sound/soc-dai.h>
-#include <sound/soc-dapm.h>
+#include <sound/soc.h>
 #include <sound/initval.h>
 
 #include "wl1273.h"
index 4bcd168..80ddf4f 100644 (file)
@@ -36,7 +36,6 @@
 #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>
 
@@ -705,6 +704,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
 /* Called from the machine driver */
 int wm2000_add_controls(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
        if (!wm2000_i2c) {
@@ -712,12 +712,12 @@ int wm2000_add_controls(struct snd_soc_codec *codec)
                return -ENODEV;
        }
 
-       ret = snd_soc_dapm_new_controls(codec, wm2000_dapm_widgets,
+       ret = snd_soc_dapm_new_controls(dapm, wm2000_dapm_widgets,
                                        ARRAY_SIZE(wm2000_dapm_widgets));
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       ret = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
        if (ret < 0)
                return ret;
 
index 7611add..6d6dc9e 100644 (file)
@@ -24,9 +24,9 @@
 #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 <trace/events/asoc.h>
 
 #include "wm8350.h"
 
@@ -54,6 +54,7 @@ struct wm8350_output {
 
 struct wm8350_jack_data {
        struct snd_soc_jack *jack;
+       struct delayed_work work;
        int report;
        int short_report;
 };
@@ -230,8 +231,9 @@ static inline int wm8350_out2_ramp_step(struct snd_soc_codec *codec)
  */
 static void wm8350_pga_work(struct work_struct *work)
 {
-       struct snd_soc_codec *codec =
-           container_of(work, struct snd_soc_codec, delayed_work.work);
+       struct snd_soc_dapm_context *dapm =
+           container_of(work, struct snd_soc_dapm_context, delayed_work.work);
+       struct snd_soc_codec *codec = dapm->codec;
        struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
        struct wm8350_output *out1 = &wm8350_data->out1,
            *out2 = &wm8350_data->out2;
@@ -302,8 +304,8 @@ static int pga_event(struct snd_soc_dapm_widget *w,
                out->ramp = WM8350_RAMP_UP;
                out->active = 1;
 
-               if (!delayed_work_pending(&codec->delayed_work))
-                       schedule_delayed_work(&codec->delayed_work,
+               if (!delayed_work_pending(&codec->dapm.delayed_work))
+                       schedule_delayed_work(&codec->dapm.delayed_work,
                                              msecs_to_jiffies(1));
                break;
 
@@ -311,8 +313,8 @@ static int pga_event(struct snd_soc_dapm_widget *w,
                out->ramp = WM8350_RAMP_DOWN;
                out->active = 0;
 
-               if (!delayed_work_pending(&codec->delayed_work))
-                       schedule_delayed_work(&codec->delayed_work,
+               if (!delayed_work_pending(&codec->dapm.delayed_work))
+                       schedule_delayed_work(&codec->dapm.delayed_work,
                                              msecs_to_jiffies(1));
                break;
        }
@@ -786,9 +788,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int wm8350_add_widgets(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
-       ret = snd_soc_dapm_new_controls(codec,
+       ret = snd_soc_dapm_new_controls(dapm,
                                        wm8350_dapm_widgets,
                                        ARRAY_SIZE(wm8350_dapm_widgets));
        if (ret != 0) {
@@ -797,7 +800,7 @@ static int wm8350_add_widgets(struct snd_soc_codec *codec)
        }
 
        /* set up audio paths */
-       ret = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       ret = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
        if (ret != 0) {
                dev_err(codec->dev, "DAPM route register failed\n");
                return ret;
@@ -1184,7 +1187,7 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
                                                    priv->supplies);
                        if (ret != 0)
@@ -1317,7 +1320,7 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec,
                                       priv->supplies);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -1334,45 +1337,69 @@ static int wm8350_resume(struct snd_soc_codec *codec)
        return 0;
 }
 
-static irqreturn_t wm8350_hp_jack_handler(int irq, void *data)
+static void wm8350_hp_work(struct wm8350_data *priv,
+                          struct wm8350_jack_data *jack,
+                          u16 mask)
 {
-       struct wm8350_data *priv = data;
        struct wm8350 *wm8350 = priv->codec.control_data;
        u16 reg;
        int report;
-       int mask;
+
+       reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS);
+       if (reg & mask)
+               report = jack->report;
+       else
+               report = 0;
+
+       snd_soc_jack_report(jack->jack, report, jack->report);
+
+}
+
+static void wm8350_hpl_work(struct work_struct *work)
+{
+       struct wm8350_data *priv =
+           container_of(work, struct wm8350_data, hpl.work.work);
+
+       wm8350_hp_work(priv, &priv->hpl, WM8350_JACK_L_LVL);
+}
+
+static void wm8350_hpr_work(struct work_struct *work)
+{
+       struct wm8350_data *priv =
+           container_of(work, struct wm8350_data, hpr.work.work);
+       
+       wm8350_hp_work(priv, &priv->hpr, WM8350_JACK_R_LVL);
+}
+
+static irqreturn_t wm8350_hp_jack_handler(int irq, void *data)
+{
+       struct wm8350_data *priv = data;
+       struct wm8350 *wm8350 = priv->codec.control_data;
        struct wm8350_jack_data *jack = NULL;
 
        switch (irq - wm8350->irq_base) {
        case WM8350_IRQ_CODEC_JCK_DET_L:
+#ifndef CONFIG_SND_SOC_WM8350_MODULE
+               trace_snd_soc_jack_irq("WM8350 HPL");
+#endif
                jack = &priv->hpl;
-               mask = WM8350_JACK_L_LVL;
                break;
 
        case WM8350_IRQ_CODEC_JCK_DET_R:
+#ifndef CONFIG_SND_SOC_WM8350_MODULE
+               trace_snd_soc_jack_irq("WM8350 HPR");
+#endif
                jack = &priv->hpr;
-               mask = WM8350_JACK_R_LVL;
                break;
 
        default:
                BUG();
        }
 
-       if (!jack->jack) {
-               dev_warn(wm8350->dev, "Jack interrupt called with no jack\n");
-               return IRQ_NONE;
-       }
-
-       /* Debounce */
-       msleep(200);
-
-       reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS);
-       if (reg & mask)
-               report = jack->report;
-       else
-               report = 0;
+       if (device_may_wakeup(wm8350->dev))
+               pm_wakeup_event(wm8350->dev, 250);
 
-       snd_soc_jack_report(jack->jack, report, jack->report);
+       schedule_delayed_work(&jack->work, 200);
 
        return IRQ_HANDLED;
 }
@@ -1436,6 +1463,10 @@ static irqreturn_t wm8350_mic_handler(int irq, void *data)
        u16 reg;
        int report = 0;
 
+#ifndef CONFIG_SND_SOC_WM8350_MODULE
+       trace_snd_soc_jack_irq("WM8350 mic");
+#endif
+
        reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS);
        if (reg & WM8350_JACK_MICSCD_LVL)
                report |= priv->mic.short_report;
@@ -1550,7 +1581,9 @@ static  int wm8350_codec_probe(struct snd_soc_codec *codec)
        /* Put the codec into reset if it wasn't already */
        wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
 
-       INIT_DELAYED_WORK(&codec->delayed_work, wm8350_pga_work);
+       INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8350_pga_work);
+       INIT_DELAYED_WORK(&priv->hpl.work, wm8350_hpl_work);
+       INIT_DELAYED_WORK(&priv->hpr.work, wm8350_hpr_work);
 
        /* Enable the codec */
        wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
@@ -1626,7 +1659,6 @@ static int  wm8350_codec_remove(struct snd_soc_codec *codec)
 {
        struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
        struct wm8350 *wm8350 = dev_get_platdata(codec->dev);
-       int ret;
 
        wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
                          WM8350_JDL_ENA | WM8350_JDR_ENA);
@@ -1641,15 +1673,12 @@ static int  wm8350_codec_remove(struct snd_soc_codec *codec)
        priv->hpr.jack = NULL;
        priv->mic.jack = NULL;
 
-       /* cancel any work waiting to be queued. */
-       ret = cancel_delayed_work(&codec->delayed_work);
+       cancel_delayed_work_sync(&priv->hpl.work);
+       cancel_delayed_work_sync(&priv->hpr.work);
 
        /* if there was any work waiting then we run it now and
         * wait for its completion */
-       if (ret) {
-               schedule_delayed_work(&codec->delayed_work, 0);
-               flush_scheduled_work();
-       }
+       flush_delayed_work_sync(&codec->dapm.delayed_work);
 
        wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
index 8502997..3c3bc07 100644 (file)
@@ -26,7 +26,6 @@
 #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>
 
@@ -911,10 +910,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int wm8400_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, wm8400_dapm_widgets,
-                                 ARRAY_SIZE(wm8400_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_new_controls(dapm, wm8400_dapm_widgets,
+                                 ARRAY_SIZE(wm8400_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
 }
@@ -1219,7 +1219,7 @@ static int wm8400_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(power),
                                                    &power[0]);
                        if (ret != 0) {
@@ -1306,7 +1306,7 @@ static int wm8400_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index 8f10709..db0dced 100644 (file)
@@ -24,7 +24,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/initval.h>
 
 #include "wm8510.h"
@@ -216,10 +215,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int wm8510_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, wm8510_dapm_widgets,
-                                 ARRAY_SIZE(wm8510_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_new_controls(dapm, wm8510_dapm_widgets,
+                                 ARRAY_SIZE(wm8510_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
 }
@@ -478,7 +478,7 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_STANDBY:
                power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;
 
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        /* Initial cap charge at VMID 5k */
                        snd_soc_write(codec, WM8510_POWER1, power1 | 0x3);
                        mdelay(100);
@@ -495,7 +495,7 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index deca79e..5eb2f50 100644 (file)
@@ -24,7 +24,6 @@
 #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>
 
@@ -109,10 +108,11 @@ static const struct snd_soc_dapm_route intercon[] = {
 
 static int wm8523_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, wm8523_dapm_widgets,
-                                 ARRAY_SIZE(wm8523_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+       snd_soc_dapm_new_controls(dapm, wm8523_dapm_widgets,
+                                 ARRAY_SIZE(wm8523_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
 
        return 0;
 }
@@ -327,7 +327,7 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies),
                                                    wm8523->supplies);
                        if (ret != 0) {
@@ -366,7 +366,7 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec,
                                       wm8523->supplies);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index 8725d4e..8f6b5ee 100644 (file)
@@ -31,7 +31,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/tlv.h>
 #include <sound/initval.h>
 #include <asm/div64.h>
@@ -191,7 +190,6 @@ static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = {
 struct wm8580_priv {
        enum snd_soc_control_type control_type;
        struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES];
-       u16 reg_cache[WM8580_MAX_REGISTER + 1];
        struct pll_state a;
        struct pll_state b;
        int sysclk[2];
@@ -302,10 +300,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int wm8580_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets,
-                                 ARRAY_SIZE(wm8580_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_new_controls(dapm, wm8580_dapm_widgets,
+                                 ARRAY_SIZE(wm8580_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
 }
@@ -507,13 +506,13 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
        }
 
        /* Look up the SYSCLK ratio; accept only exact matches */
-       ratio = wm8580->sysclk[dai->id] / params_rate(params);
+       ratio = wm8580->sysclk[dai->driver->id] / params_rate(params);
        for (i = 0; i < ARRAY_SIZE(wm8580_sysclk_ratios); i++)
                if (ratio == wm8580_sysclk_ratios[i])
                        break;
        if (i == ARRAY_SIZE(wm8580_sysclk_ratios)) {
                dev_err(codec->dev, "Invalid clock ratio %d/%d\n",
-                       wm8580->sysclk[dai->id], params_rate(params));
+                       wm8580->sysclk[dai->driver->id], params_rate(params));
                return -EINVAL;
        }
        paifa |= i;
@@ -716,7 +715,7 @@ static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 
        switch (clk_id) {
        case WM8580_CLKSRC_ADCMCLK:
-               if (dai->id != WM8580_DAI_PAIFTX)
+               if (dai->driver->id != WM8580_DAI_PAIFTX)
                        return -EINVAL;
                sel = 0 << sel_shift;
                break;
@@ -735,7 +734,7 @@ static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id,
        }
 
        /* We really should validate PLL settings but not yet */
-       wm8580->sysclk[dai->id] = freq;
+       wm8580->sysclk[dai->driver->id] = freq;
 
        return snd_soc_update_bits(codec, WM8580_CLKSEL, sel_mask, sel);
 }
@@ -767,7 +766,7 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        /* Power up and get individual control of the DACs */
                        reg = snd_soc_read(codec, WM8580_PWRDN1);
                        reg &= ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD);
@@ -785,7 +784,7 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -905,7 +904,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8580 = {
        .set_bias_level = wm8580_set_bias_level,
        .reg_cache_size = ARRAY_SIZE(wm8580_reg),
        .reg_word_size = sizeof(u16),
-       .reg_cache_default = &wm8580_reg,
+       .reg_cache_default = wm8580_reg,
 };
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
index 54fbd76..97c3038 100644 (file)
@@ -25,7 +25,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/tlv.h>
 #include <sound/initval.h>
 
@@ -34,7 +33,6 @@
 /* codec private data */
 struct wm8711_priv {
        enum snd_soc_control_type bus_type;
-       u16 reg_cache[WM8711_CACHEREGNUM];
        unsigned int sysclk;
 };
 
@@ -93,10 +91,11 @@ static const struct snd_soc_dapm_route intercon[] = {
 
 static int wm8711_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, wm8711_dapm_widgets,
-                                 ARRAY_SIZE(wm8711_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+       snd_soc_dapm_new_controls(dapm, wm8711_dapm_widgets,
+                                 ARRAY_SIZE(wm8711_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
 
        return 0;
 }
@@ -318,7 +317,7 @@ static int wm8711_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_write(codec, WM8711_PWR, 0xffff);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index 075f35e..736b035 100644 (file)
@@ -23,7 +23,6 @@
 #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>
 
@@ -73,10 +72,11 @@ static const struct snd_soc_dapm_route intercon[] = {
 
 static int wm8728_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, wm8728_dapm_widgets,
-                                 ARRAY_SIZE(wm8728_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+       snd_soc_dapm_new_controls(dapm, wm8728_dapm_widgets,
+                                 ARRAY_SIZE(wm8728_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
 
        return 0;
 }
@@ -180,7 +180,7 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_ON:
        case SND_SOC_BIAS_PREPARE:
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        /* Power everything up... */
                        reg = snd_soc_read(codec, WM8728_DACCTL);
                        snd_soc_write(codec, WM8728_DACCTL, reg & ~0x4);
@@ -197,7 +197,7 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_write(codec, WM8728_DACCTL, reg | 0x4);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index e725c09..0a67c31 100644 (file)
@@ -26,7 +26,6 @@
 #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>
 
@@ -44,9 +43,10 @@ static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = {
 struct wm8731_priv {
        enum snd_soc_control_type control_type;
        struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES];
-       u16 reg_cache[WM8731_CACHEREGNUM];
        unsigned int sysclk;
        int sysclk_type;
+       int playback_fs;
+       bool deemph;
 };
 
 
@@ -65,16 +65,79 @@ static const u16 wm8731_reg[WM8731_CACHEREGNUM] = {
 #define wm8731_reset(c)        snd_soc_write(c, WM8731_RESET, 0)
 
 static const char *wm8731_input_select[] = {"Line In", "Mic"};
-static const char *wm8731_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
 
-static const struct soc_enum wm8731_enum[] = {
-       SOC_ENUM_SINGLE(WM8731_APANA, 2, 2, wm8731_input_select),
-       SOC_ENUM_SINGLE(WM8731_APDIGI, 1, 4, wm8731_deemph),
-};
+static const struct soc_enum wm8731_insel_enum =
+       SOC_ENUM_SINGLE(WM8731_APANA, 2, 2, wm8731_input_select);
+
+static int wm8731_deemph[] = { 0, 32000, 44100, 48000 };
+
+static int wm8731_set_deemph(struct snd_soc_codec *codec)
+{
+       struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
+       int val, i, best;
+
+       /* If we're using deemphasis select the nearest available sample
+        * rate.
+        */
+       if (wm8731->deemph) {
+               best = 1;
+               for (i = 2; i < ARRAY_SIZE(wm8731_deemph); i++) {
+                       if (abs(wm8731_deemph[i] - wm8731->playback_fs) <
+                           abs(wm8731_deemph[best] - wm8731->playback_fs))
+                               best = i;
+               }
+
+               val = best << 1;
+       } else {
+               best = 0;
+               val = 0;
+       }
+
+       dev_dbg(codec->dev, "Set deemphasis %d (%dHz)\n",
+               best, wm8731_deemph[best]);
+
+       return snd_soc_update_bits(codec, WM8731_APDIGI, 0x6, val);
+}
+
+static int wm8731_get_deemph(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = wm8731->deemph;
+
+       return 0;
+}
+
+static int wm8731_put_deemph(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
+       int deemph = ucontrol->value.enumerated.item[0];
+       int ret = 0;
+
+       if (deemph > 1)
+               return -EINVAL;
+
+       mutex_lock(&codec->mutex);
+       if (wm8731->deemph != deemph) {
+               wm8731->deemph = deemph;
+
+               wm8731_set_deemph(codec);
+
+               ret = 1;
+       }
+       mutex_unlock(&codec->mutex);
+
+       return ret;
+}
 
 static const DECLARE_TLV_DB_SCALE(in_tlv, -3450, 150, 0);
 static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -1500, 300, 0);
 static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 2000, 0);
 
 static const struct snd_kcontrol_new wm8731_snd_controls[] = {
 
@@ -87,7 +150,7 @@ SOC_DOUBLE_R_TLV("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0,
                 in_tlv),
 SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1),
 
-SOC_SINGLE("Mic Boost (+20dB)", WM8731_APANA, 0, 1, 0),
+SOC_SINGLE_TLV("Mic Boost Volume", WM8731_APANA, 0, 1, 0, mic_tlv),
 SOC_SINGLE("Mic Capture Switch", WM8731_APANA, 1, 1, 1),
 
 SOC_SINGLE_TLV("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1,
@@ -96,7 +159,8 @@ SOC_SINGLE_TLV("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1,
 SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1),
 SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0),
 
-SOC_ENUM("Playback De-emphasis", wm8731_enum[1]),
+SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0,
+                   wm8731_get_deemph, wm8731_put_deemph),
 };
 
 /* Output Mixer */
@@ -108,7 +172,7 @@ SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0),
 
 /* Input mux */
 static const struct snd_kcontrol_new wm8731_input_mux_controls =
-SOC_DAPM_ENUM("Input Select", wm8731_enum[0]);
+SOC_DAPM_ENUM("Input Select", wm8731_insel_enum);
 
 static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
 SND_SOC_DAPM_SUPPLY("OSC", WM8731_PWR, 5, 1, NULL, 0),
@@ -165,10 +229,11 @@ static const struct snd_soc_dapm_route intercon[] = {
 
 static int wm8731_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets,
-                                 ARRAY_SIZE(wm8731_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+       snd_soc_dapm_new_controls(dapm, wm8731_dapm_widgets,
+                                 ARRAY_SIZE(wm8731_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
 
        return 0;
 }
@@ -239,6 +304,8 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
        u16 srate = (coeff_div[i].sr << 2) |
                (coeff_div[i].bosr << 1) | coeff_div[i].usb;
 
+       wm8731->playback_fs = params_rate(params);
+
        snd_soc_write(codec, WM8731_SRATE, srate);
 
        /* bit size */
@@ -253,6 +320,8 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
+       wm8731_set_deemph(codec);
+
        snd_soc_write(codec, WM8731_IFACE, iface);
        return 0;
 }
@@ -319,7 +388,7 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                return -EINVAL;
        }
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(&codec->dapm);
 
        return 0;
 }
@@ -399,7 +468,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
                                                    wm8731->supplies);
                        if (ret != 0)
@@ -428,7 +497,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
                                       wm8731->supplies);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -542,7 +611,6 @@ err_regulator_enable:
 err_regulator_get:
        regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
 
-       kfree(wm8731);
        return ret;
 }
 
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c
new file mode 100644 (file)
index 0000000..30c67d0
--- /dev/null
@@ -0,0 +1,754 @@
+/*
+ * wm8737.c  --  WM8737 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.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 "wm8737.h"
+
+#define WM8737_NUM_SUPPLIES 4
+static const char *wm8737_supply_names[WM8737_NUM_SUPPLIES] = {
+       "DCVDD",
+       "DBVDD",
+       "AVDD",
+       "MVDD",
+};
+
+/* codec private data */
+struct wm8737_priv {
+       enum snd_soc_control_type control_type;
+       struct regulator_bulk_data supplies[WM8737_NUM_SUPPLIES];
+       unsigned int mclk;
+};
+
+static const u16 wm8737_reg[WM8737_REGISTER_COUNT] = {
+       0x00C3,     /* R0  - Left PGA volume */
+       0x00C3,     /* R1  - Right PGA volume */
+       0x0007,     /* R2  - AUDIO path L */
+       0x0007,     /* R3  - AUDIO path R */
+       0x0000,     /* R4  - 3D Enhance */
+       0x0000,     /* R5  - ADC Control */
+       0x0000,     /* R6  - Power Management */
+       0x000A,     /* R7  - Audio Format */
+       0x0000,     /* R8  - Clocking */
+       0x000F,     /* R9  - MIC Preamp Control */
+       0x0003,     /* R10 - Misc Bias Control */
+       0x0000,     /* R11 - Noise Gate */
+       0x007C,     /* R12 - ALC1 */
+       0x0000,     /* R13 - ALC2 */
+       0x0032,     /* R14 - ALC3 */
+};
+
+static int wm8737_reset(struct snd_soc_codec *codec)
+{
+       return snd_soc_write(codec, WM8737_RESET, 0);
+}
+
+static const unsigned int micboost_tlv[] = {
+       TLV_DB_RANGE_HEAD(4),
+       0, 0, TLV_DB_SCALE_ITEM(1300, 0, 0),
+       1, 1, TLV_DB_SCALE_ITEM(1800, 0, 0),
+       2, 2, TLV_DB_SCALE_ITEM(2800, 0, 0),
+       3, 3, TLV_DB_SCALE_ITEM(3300, 0, 0),
+};
+static const DECLARE_TLV_DB_SCALE(pga_tlv, -9750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(ng_tlv, -7800, 600, 0);
+static const DECLARE_TLV_DB_SCALE(alc_max_tlv, -1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(alc_target_tlv, -1800, 100, 0);
+
+static const char *micbias_enum_text[] = {
+       "25%",
+       "50%",
+       "75%",
+       "100%",
+};
+
+static const struct soc_enum micbias_enum =
+       SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 0, 4, micbias_enum_text);
+
+static const char *low_cutoff_text[] = {
+       "Low", "High"
+};
+
+static const struct soc_enum low_3d =
+       SOC_ENUM_SINGLE(WM8737_3D_ENHANCE, 6, 2, low_cutoff_text);
+
+static const char *high_cutoff_text[] = {
+       "High", "Low"
+};
+
+static const struct soc_enum high_3d =
+       SOC_ENUM_SINGLE(WM8737_3D_ENHANCE, 5, 2, high_cutoff_text);
+
+static const char *alc_fn_text[] = {
+       "Disabled", "Right", "Left", "Stereo"
+};
+
+static const struct soc_enum alc_fn =
+       SOC_ENUM_SINGLE(WM8737_ALC1, 7, 4, alc_fn_text);
+
+static const char *alc_hold_text[] = {
+       "0", "2.67ms", "5.33ms", "10.66ms", "21.32ms", "42.64ms", "85.28ms",
+       "170.56ms", "341.12ms", "682.24ms", "1.364s", "2.728s", "5.458s",
+       "10.916s", "21.832s", "43.691s"
+};
+
+static const struct soc_enum alc_hold =
+       SOC_ENUM_SINGLE(WM8737_ALC2, 0, 16, alc_hold_text);
+
+static const char *alc_atk_text[] = {
+       "8.4ms", "16.8ms", "33.6ms", "67.2ms", "134.4ms", "268.8ms", "537.6ms",
+       "1.075s", "2.15s", "4.3s", "8.6s"
+};
+
+static const struct soc_enum alc_atk =
+       SOC_ENUM_SINGLE(WM8737_ALC3, 0, 11, alc_atk_text);
+
+static const char *alc_dcy_text[] = {
+       "33.6ms", "67.2ms", "134.4ms", "268.8ms", "537.6ms", "1.075s", "2.15s",
+       "4.3s", "8.6s", "17.2s", "34.41s"
+};
+
+static const struct soc_enum alc_dcy =
+       SOC_ENUM_SINGLE(WM8737_ALC3, 4, 11, alc_dcy_text);
+
+static const struct snd_kcontrol_new wm8737_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Mic Boost Volume", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R,
+                6, 3, 0, micboost_tlv),
+SOC_DOUBLE_R("Mic Boost Switch", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R,
+            4, 1, 0),
+SOC_DOUBLE("Mic ZC Switch", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R,
+          3, 1, 0),
+
+SOC_DOUBLE_R_TLV("Capture Volume", WM8737_LEFT_PGA_VOLUME,
+                WM8737_RIGHT_PGA_VOLUME, 0, 255, 0, pga_tlv),
+SOC_DOUBLE("Capture ZC Switch", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R,
+          2, 1, 0),
+
+SOC_DOUBLE("INPUT1 DC Bias Switch", WM8737_MISC_BIAS_CONTROL, 0, 1, 1, 0),
+
+SOC_ENUM("Mic PGA Bias", micbias_enum),
+SOC_SINGLE("ADC Low Power Switch", WM8737_ADC_CONTROL, 2, 1, 0),
+SOC_SINGLE("High Pass Filter Switch", WM8737_ADC_CONTROL, 0, 1, 1),
+SOC_DOUBLE("Polarity Invert Switch", WM8737_ADC_CONTROL, 5, 6, 1, 0),
+
+SOC_SINGLE("3D Switch", WM8737_3D_ENHANCE, 0, 1, 0),
+SOC_SINGLE("3D Depth", WM8737_3D_ENHANCE, 1, 15, 0),
+SOC_ENUM("3D Low Cut-off", low_3d),
+SOC_ENUM("3D High Cut-off", low_3d),
+SOC_SINGLE_TLV("3D ADC Volume", WM8737_3D_ENHANCE, 7, 1, 1, adc_tlv),
+
+SOC_SINGLE("Noise Gate Switch", WM8737_NOISE_GATE, 0, 1, 0),
+SOC_SINGLE_TLV("Noise Gate Threshold Volume", WM8737_NOISE_GATE, 2, 7, 0,
+              ng_tlv),
+
+SOC_ENUM("ALC", alc_fn),
+SOC_SINGLE_TLV("ALC Max Gain Volume", WM8737_ALC1, 4, 7, 0, alc_max_tlv),
+SOC_SINGLE_TLV("ALC Target Volume", WM8737_ALC1, 0, 15, 0, alc_target_tlv),
+SOC_ENUM("ALC Hold Time", alc_hold),
+SOC_SINGLE("ALC ZC Switch", WM8737_ALC2, 4, 1, 0),
+SOC_ENUM("ALC Attack Time", alc_atk),
+SOC_ENUM("ALC Decay Time", alc_dcy),
+};
+
+static const char *linsel_text[] = {
+       "LINPUT1", "LINPUT2", "LINPUT3", "LINPUT1 DC",
+};
+
+static const struct soc_enum linsel_enum =
+       SOC_ENUM_SINGLE(WM8737_AUDIO_PATH_L, 7, 4, linsel_text);
+
+static const struct snd_kcontrol_new linsel_mux =
+       SOC_DAPM_ENUM("LINSEL", linsel_enum);
+
+
+static const char *rinsel_text[] = {
+       "RINPUT1", "RINPUT2", "RINPUT3", "RINPUT1 DC",
+};
+
+static const struct soc_enum rinsel_enum =
+       SOC_ENUM_SINGLE(WM8737_AUDIO_PATH_R, 7, 4, rinsel_text);
+
+static const struct snd_kcontrol_new rinsel_mux =
+       SOC_DAPM_ENUM("RINSEL", rinsel_enum);
+
+static const char *bypass_text[] = {
+       "Direct", "Preamp"
+};
+
+static const struct soc_enum lbypass_enum =
+       SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 2, 2, bypass_text);
+
+static const struct snd_kcontrol_new lbypass_mux =
+       SOC_DAPM_ENUM("Left Bypass", lbypass_enum);
+
+
+static const struct soc_enum rbypass_enum =
+       SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 3, 2, bypass_text);
+
+static const struct snd_kcontrol_new rbypass_mux =
+       SOC_DAPM_ENUM("Left Bypass", rbypass_enum);
+
+static const struct snd_soc_dapm_widget wm8737_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("LINPUT1"),
+SND_SOC_DAPM_INPUT("LINPUT2"),
+SND_SOC_DAPM_INPUT("LINPUT3"),
+SND_SOC_DAPM_INPUT("RINPUT1"),
+SND_SOC_DAPM_INPUT("RINPUT2"),
+SND_SOC_DAPM_INPUT("RINPUT3"),
+SND_SOC_DAPM_INPUT("LACIN"),
+SND_SOC_DAPM_INPUT("RACIN"),
+
+SND_SOC_DAPM_MUX("LINSEL", SND_SOC_NOPM, 0, 0, &linsel_mux),
+SND_SOC_DAPM_MUX("RINSEL", SND_SOC_NOPM, 0, 0, &rinsel_mux),
+
+SND_SOC_DAPM_MUX("Left Preamp Mux", SND_SOC_NOPM, 0, 0, &lbypass_mux),
+SND_SOC_DAPM_MUX("Right Preamp Mux", SND_SOC_NOPM, 0, 0, &rbypass_mux),
+
+SND_SOC_DAPM_PGA("PGAL", WM8737_POWER_MANAGEMENT, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("PGAR", WM8737_POWER_MANAGEMENT, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_DAC("ADCL", NULL, WM8737_POWER_MANAGEMENT, 3, 0),
+SND_SOC_DAPM_DAC("ADCR", NULL, WM8737_POWER_MANAGEMENT, 2, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF", "Capture", 0, WM8737_POWER_MANAGEMENT, 6, 0),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+       { "LINSEL", "LINPUT1", "LINPUT1" },
+       { "LINSEL", "LINPUT2", "LINPUT2" },
+       { "LINSEL", "LINPUT3", "LINPUT3" },
+       { "LINSEL", "LINPUT1 DC", "LINPUT1" },
+
+       { "RINSEL", "RINPUT1", "RINPUT1" },
+       { "RINSEL", "RINPUT2", "RINPUT2" },
+       { "RINSEL", "RINPUT3", "RINPUT3" },
+       { "RINSEL", "RINPUT1 DC", "RINPUT1" },
+
+       { "Left Preamp Mux", "Preamp", "LINSEL" },
+       { "Left Preamp Mux", "Direct", "LACIN" },
+
+       { "Right Preamp Mux", "Preamp", "RINSEL" },
+       { "Right Preamp Mux", "Direct", "RACIN" },
+
+       { "PGAL", NULL, "Left Preamp Mux" },
+       { "PGAR", NULL, "Right Preamp Mux" },
+
+       { "ADCL", NULL, "PGAL" },
+       { "ADCR", NULL, "PGAR" },
+
+       { "AIF", NULL, "ADCL" },
+       { "AIF", NULL, "ADCR" },
+};
+
+static int wm8737_add_widgets(struct snd_soc_codec *codec)
+{
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       snd_soc_dapm_new_controls(dapm, wm8737_dapm_widgets,
+                                 ARRAY_SIZE(wm8737_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
+
+       return 0;
+}
+
+/* codec mclk clock divider coefficients */
+static const struct {
+       u32 mclk;
+       u32 rate;
+       u8 usb;
+       u8 sr;
+} coeff_div[] = {
+       { 12288000,  8000, 0,  0x4 },
+       { 12288000, 12000, 0,  0x8 },
+       { 12288000, 16000, 0,  0xa },
+       { 12288000, 24000, 0, 0x1c },
+       { 12288000, 32000, 0,  0xc },
+       { 12288000, 48000, 0,    0 },
+       { 12288000, 96000, 0,  0xe },
+
+       { 11289600,  8000, 0, 0x14 },
+       { 11289600, 11025, 0, 0x18 },
+       { 11289600, 22050, 0, 0x1a },
+       { 11289600, 44100, 0, 0x10 },
+       { 11289600, 88200, 0, 0x1e },
+
+       { 18432000,  8000, 0,  0x5 },
+       { 18432000, 12000, 0,  0x9 },
+       { 18432000, 16000, 0,  0xb },
+       { 18432000, 24000, 0, 0x1b },
+       { 18432000, 32000, 0,  0xd },
+       { 18432000, 48000, 0,  0x1 },
+       { 18432000, 96000, 0, 0x1f },
+
+       { 16934400,  8000, 0, 0x15 },
+       { 16934400, 11025, 0, 0x19 },
+       { 16934400, 22050, 0, 0x1b },
+       { 16934400, 44100, 0, 0x11 },
+       { 16934400, 88200, 0, 0x1f },
+
+       { 12000000,  8000, 1,  0x4 },
+       { 12000000, 11025, 1, 0x19 },
+       { 12000000, 12000, 1,  0x8 },
+       { 12000000, 16000, 1,  0xa },
+       { 12000000, 22050, 1, 0x1b },
+       { 12000000, 24000, 1, 0x1c },
+       { 12000000, 32000, 1,  0xc },
+       { 12000000, 44100, 1, 0x11 },
+       { 12000000, 48000, 1,  0x0 },
+       { 12000000, 88200, 1, 0x1f },
+       { 12000000, 96000, 1,  0xe },
+};
+
+static int wm8737_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 wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
+       int i;
+       u16 clocking = 0;
+       u16 af = 0;
+
+       for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+               if (coeff_div[i].rate != params_rate(params))
+                       continue;
+
+               if (coeff_div[i].mclk == wm8737->mclk)
+                       break;
+
+               if (coeff_div[i].mclk == wm8737->mclk * 2) {
+                       clocking |= WM8737_CLKDIV2;
+                       break;
+               }
+       }
+
+       if (i == ARRAY_SIZE(coeff_div)) {
+               dev_err(codec->dev, "%dHz MCLK can't support %dHz\n",
+                       wm8737->mclk, params_rate(params));
+               return -EINVAL;
+       }
+
+       clocking |= coeff_div[i].usb | (coeff_div[i].sr << WM8737_SR_SHIFT);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               af |= 0x8;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               af |= 0x10;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               af |= 0x18;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8737_AUDIO_FORMAT, WM8737_WL_MASK, af);
+       snd_soc_update_bits(codec, WM8737_CLOCKING,
+                           WM8737_USB_MODE | WM8737_CLKDIV2 | WM8737_SR_MASK,
+                           clocking);
+
+       return 0;
+}
+
+static int wm8737_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+                                int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+               if (freq == coeff_div[i].mclk ||
+                   freq == coeff_div[i].mclk * 2) {
+                       wm8737->mclk = freq;
+                       return 0;
+               }
+       }
+
+       dev_err(codec->dev, "MCLK rate %dHz not supported\n", freq);
+
+       return -EINVAL;
+}
+
+
+static int wm8737_set_dai_fmt(struct snd_soc_dai *codec_dai,
+               unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u16 af = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               af |= WM8737_MS;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               af |= 0x2;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               af |= 0x1;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               af |= 0x3;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               af |= 0x13;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               af |= WM8737_LRP;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8737_AUDIO_FORMAT,
+                           WM8737_FORMAT_MASK | WM8737_LRP | WM8737_MS, af);
+
+       return 0;
+}
+
+static int wm8737_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               /* VMID at 2*75k */
+               snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL,
+                                   WM8737_VMIDSEL_MASK, 0);
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies),
+                                                   wm8737->supplies);
+                       if (ret != 0) {
+                               dev_err(codec->dev,
+                                       "Failed to enable supplies: %d\n",
+                                       ret);
+                               return ret;
+                       }
+
+                       snd_soc_cache_sync(codec);
+
+                       /* Fast VMID ramp at 2*2.5k */
+                       snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL,
+                                           WM8737_VMIDSEL_MASK, 0x4);
+
+                       /* Bring VMID up */
+                       snd_soc_update_bits(codec, WM8737_POWER_MANAGEMENT,
+                                           WM8737_VMID_MASK |
+                                           WM8737_VREF_MASK,
+                                           WM8737_VMID_MASK |
+                                           WM8737_VREF_MASK);
+
+                       msleep(500);
+               }
+
+               /* VMID at 2*300k */
+               snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL,
+                                   WM8737_VMIDSEL_MASK, 2);
+
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               snd_soc_update_bits(codec, WM8737_POWER_MANAGEMENT,
+                                   WM8737_VMID_MASK | WM8737_VREF_MASK, 0);
+
+               regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies),
+                                      wm8737->supplies);
+               break;
+       }
+
+       codec->dapm.bias_level = level;
+       return 0;
+}
+
+#define WM8737_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8737_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops wm8737_dai_ops = {
+       .hw_params      = wm8737_hw_params,
+       .set_sysclk     = wm8737_set_dai_sysclk,
+       .set_fmt        = wm8737_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver wm8737_dai = {
+       .name = "wm8737",
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,  /* Mono modes not yet supported */
+               .channels_max = 2,
+               .rates = WM8737_RATES,
+               .formats = WM8737_FORMATS,
+       },
+       .ops = &wm8737_dai_ops,
+};
+
+#ifdef CONFIG_PM
+static int wm8737_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+       wm8737_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int wm8737_resume(struct snd_soc_codec *codec)
+{
+       wm8737_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       return 0;
+}
+#else
+#define wm8737_suspend NULL
+#define wm8737_resume NULL
+#endif
+
+static int wm8737_probe(struct snd_soc_codec *codec)
+{
+       struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
+       int ret, i;
+
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8737->control_type);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(wm8737->supplies); i++)
+               wm8737->supplies[i].supply = wm8737_supply_names[i];
+
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8737->supplies),
+                                wm8737->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies),
+                                   wm8737->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_get;
+       }
+
+       ret = wm8737_reset(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset\n");
+               goto err_enable;
+       }
+
+       snd_soc_update_bits(codec, WM8737_LEFT_PGA_VOLUME, WM8737_LVU,
+                           WM8737_LVU);
+       snd_soc_update_bits(codec, WM8737_RIGHT_PGA_VOLUME, WM8737_RVU,
+                           WM8737_RVU);
+
+       wm8737_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* Bias level configuration will have done an extra enable */
+       regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
+
+       snd_soc_add_controls(codec, wm8737_snd_controls,
+                            ARRAY_SIZE(wm8737_snd_controls));
+       wm8737_add_widgets(codec);
+
+       return 0;
+
+err_enable:
+       regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
+err_get:
+       regulator_bulk_free(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
+
+       return ret;
+}
+
+static int wm8737_remove(struct snd_soc_codec *codec)
+{
+       struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
+
+       wm8737_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       regulator_bulk_free(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8737 = {
+       .probe          = wm8737_probe,
+       .remove         = wm8737_remove,
+       .suspend        = wm8737_suspend,
+       .resume         = wm8737_resume,
+       .set_bias_level = wm8737_set_bias_level,
+
+       .reg_cache_size = WM8737_REGISTER_COUNT - 1, /* Skip reset */
+       .reg_word_size  = sizeof(u16),
+       .reg_cache_default = wm8737_reg,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8737_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8737_priv *wm8737;
+       int ret;
+
+       wm8737 = kzalloc(sizeof(struct wm8737_priv), GFP_KERNEL);
+       if (wm8737 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, wm8737);
+       wm8737->control_type = SND_SOC_I2C;
+
+       ret =  snd_soc_register_codec(&i2c->dev,
+                                     &soc_codec_dev_wm8737, &wm8737_dai, 1);
+       if (ret < 0)
+               kfree(wm8737);
+       return ret;
+
+}
+
+static __devexit int wm8737_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
+       return 0;
+}
+
+static const struct i2c_device_id wm8737_i2c_id[] = {
+       { "wm8737", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8737_i2c_id);
+
+static struct i2c_driver wm8737_i2c_driver = {
+       .driver = {
+               .name = "wm8737",
+               .owner = THIS_MODULE,
+       },
+       .probe =    wm8737_i2c_probe,
+       .remove =   __devexit_p(wm8737_i2c_remove),
+       .id_table = wm8737_i2c_id,
+};
+#endif
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8737_spi_probe(struct spi_device *spi)
+{
+       struct wm8737_priv *wm8737;
+       int ret;
+
+       wm8737 = kzalloc(sizeof(struct wm8737_priv), GFP_KERNEL);
+       if (wm8737 == NULL)
+               return -ENOMEM;
+
+       wm8737->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8737);
+
+       ret = snd_soc_register_codec(&spi->dev,
+                                    &soc_codec_dev_wm8737, &wm8737_dai, 1);
+       if (ret < 0)
+               kfree(wm8737);
+       return ret;
+}
+
+static int __devexit wm8737_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
+       return 0;
+}
+
+static struct spi_driver wm8737_spi_driver = {
+       .driver = {
+               .name   = "wm8737",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = wm8737_spi_probe,
+       .remove         = __devexit_p(wm8737_spi_remove),
+};
+#endif /* CONFIG_SPI_MASTER */
+
+static int __init wm8737_modinit(void)
+{
+       int ret;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8737_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8737 I2C driver: %d\n",
+                      ret);
+       }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       ret = spi_register_driver(&wm8737_spi_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8737 SPI driver: %d\n",
+                      ret);
+       }
+#endif
+       return 0;
+}
+module_init(wm8737_modinit);
+
+static void __exit wm8737_exit(void)
+{
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&wm8737_spi_driver);
+#endif
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8737_i2c_driver);
+#endif
+}
+module_exit(wm8737_exit);
+
+MODULE_DESCRIPTION("ASoC WM8737 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8737.h b/sound/soc/codecs/wm8737.h
new file mode 100644 (file)
index 0000000..23d14c8
--- /dev/null
@@ -0,0 +1,322 @@
+#ifndef _WM8737_H
+#define _WM8737_H
+
+/*
+ * wm8737.c  --  WM8523 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.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.
+ */
+
+/*
+ * Register values.
+ */
+#define WM8737_LEFT_PGA_VOLUME                  0x00
+#define WM8737_RIGHT_PGA_VOLUME                 0x01
+#define WM8737_AUDIO_PATH_L                     0x02
+#define WM8737_AUDIO_PATH_R                     0x03
+#define WM8737_3D_ENHANCE                       0x04
+#define WM8737_ADC_CONTROL                      0x05
+#define WM8737_POWER_MANAGEMENT                 0x06
+#define WM8737_AUDIO_FORMAT                     0x07
+#define WM8737_CLOCKING                         0x08
+#define WM8737_MIC_PREAMP_CONTROL               0x09
+#define WM8737_MISC_BIAS_CONTROL                0x0A
+#define WM8737_NOISE_GATE                       0x0B
+#define WM8737_ALC1                             0x0C
+#define WM8737_ALC2                             0x0D
+#define WM8737_ALC3                             0x0E
+#define WM8737_RESET                            0x0F
+
+#define WM8737_REGISTER_COUNT                   16
+#define WM8737_MAX_REGISTER                     0x0F
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Left PGA volume
+ */
+#define WM8737_LVU                              0x0100  /* LVU */
+#define WM8737_LVU_MASK                         0x0100  /* LVU */
+#define WM8737_LVU_SHIFT                             8  /* LVU */
+#define WM8737_LVU_WIDTH                             1  /* LVU */
+#define WM8737_LINVOL_MASK                      0x00FF  /* LINVOL - [7:0] */
+#define WM8737_LINVOL_SHIFT                          0  /* LINVOL - [7:0] */
+#define WM8737_LINVOL_WIDTH                          8  /* LINVOL - [7:0] */
+
+/*
+ * R1 (0x01) - Right PGA volume
+ */
+#define WM8737_RVU                              0x0100  /* RVU */
+#define WM8737_RVU_MASK                         0x0100  /* RVU */
+#define WM8737_RVU_SHIFT                             8  /* RVU */
+#define WM8737_RVU_WIDTH                             1  /* RVU */
+#define WM8737_RINVOL_MASK                      0x00FF  /* RINVOL - [7:0] */
+#define WM8737_RINVOL_SHIFT                          0  /* RINVOL - [7:0] */
+#define WM8737_RINVOL_WIDTH                          8  /* RINVOL - [7:0] */
+
+/*
+ * R2 (0x02) - AUDIO path L
+ */
+#define WM8737_LINSEL_MASK                      0x0180  /* LINSEL - [8:7] */
+#define WM8737_LINSEL_SHIFT                          7  /* LINSEL - [8:7] */
+#define WM8737_LINSEL_WIDTH                          2  /* LINSEL - [8:7] */
+#define WM8737_LMICBOOST_MASK                   0x0060  /* LMICBOOST - [6:5] */
+#define WM8737_LMICBOOST_SHIFT                       5  /* LMICBOOST - [6:5] */
+#define WM8737_LMICBOOST_WIDTH                       2  /* LMICBOOST - [6:5] */
+#define WM8737_LMBE                             0x0010  /* LMBE */
+#define WM8737_LMBE_MASK                        0x0010  /* LMBE */
+#define WM8737_LMBE_SHIFT                            4  /* LMBE */
+#define WM8737_LMBE_WIDTH                            1  /* LMBE */
+#define WM8737_LMZC                             0x0008  /* LMZC */
+#define WM8737_LMZC_MASK                        0x0008  /* LMZC */
+#define WM8737_LMZC_SHIFT                            3  /* LMZC */
+#define WM8737_LMZC_WIDTH                            1  /* LMZC */
+#define WM8737_LPZC                             0x0004  /* LPZC */
+#define WM8737_LPZC_MASK                        0x0004  /* LPZC */
+#define WM8737_LPZC_SHIFT                            2  /* LPZC */
+#define WM8737_LPZC_WIDTH                            1  /* LPZC */
+#define WM8737_LZCTO_MASK                       0x0003  /* LZCTO - [1:0] */
+#define WM8737_LZCTO_SHIFT                           0  /* LZCTO - [1:0] */
+#define WM8737_LZCTO_WIDTH                           2  /* LZCTO - [1:0] */
+
+/*
+ * R3 (0x03) - AUDIO path R
+ */
+#define WM8737_RINSEL_MASK                      0x0180  /* RINSEL - [8:7] */
+#define WM8737_RINSEL_SHIFT                          7  /* RINSEL - [8:7] */
+#define WM8737_RINSEL_WIDTH                          2  /* RINSEL - [8:7] */
+#define WM8737_RMICBOOST_MASK                   0x0060  /* RMICBOOST - [6:5] */
+#define WM8737_RMICBOOST_SHIFT                       5  /* RMICBOOST - [6:5] */
+#define WM8737_RMICBOOST_WIDTH                       2  /* RMICBOOST - [6:5] */
+#define WM8737_RMBE                             0x0010  /* RMBE */
+#define WM8737_RMBE_MASK                        0x0010  /* RMBE */
+#define WM8737_RMBE_SHIFT                            4  /* RMBE */
+#define WM8737_RMBE_WIDTH                            1  /* RMBE */
+#define WM8737_RMZC                             0x0008  /* RMZC */
+#define WM8737_RMZC_MASK                        0x0008  /* RMZC */
+#define WM8737_RMZC_SHIFT                            3  /* RMZC */
+#define WM8737_RMZC_WIDTH                            1  /* RMZC */
+#define WM8737_RPZC                             0x0004  /* RPZC */
+#define WM8737_RPZC_MASK                        0x0004  /* RPZC */
+#define WM8737_RPZC_SHIFT                            2  /* RPZC */
+#define WM8737_RPZC_WIDTH                            1  /* RPZC */
+#define WM8737_RZCTO_MASK                       0x0003  /* RZCTO - [1:0] */
+#define WM8737_RZCTO_SHIFT                           0  /* RZCTO - [1:0] */
+#define WM8737_RZCTO_WIDTH                           2  /* RZCTO - [1:0] */
+
+/*
+ * R4 (0x04) - 3D Enhance
+ */
+#define WM8737_DIV2                             0x0080  /* DIV2 */
+#define WM8737_DIV2_MASK                        0x0080  /* DIV2 */
+#define WM8737_DIV2_SHIFT                            7  /* DIV2 */
+#define WM8737_DIV2_WIDTH                            1  /* DIV2 */
+#define WM8737_3DLC                             0x0040  /* 3DLC */
+#define WM8737_3DLC_MASK                        0x0040  /* 3DLC */
+#define WM8737_3DLC_SHIFT                            6  /* 3DLC */
+#define WM8737_3DLC_WIDTH                            1  /* 3DLC */
+#define WM8737_3DUC                             0x0020  /* 3DUC */
+#define WM8737_3DUC_MASK                        0x0020  /* 3DUC */
+#define WM8737_3DUC_SHIFT                            5  /* 3DUC */
+#define WM8737_3DUC_WIDTH                            1  /* 3DUC */
+#define WM8737_3DDEPTH_MASK                     0x001E  /* 3DDEPTH - [4:1] */
+#define WM8737_3DDEPTH_SHIFT                         1  /* 3DDEPTH - [4:1] */
+#define WM8737_3DDEPTH_WIDTH                         4  /* 3DDEPTH - [4:1] */
+#define WM8737_3DE                              0x0001  /* 3DE */
+#define WM8737_3DE_MASK                         0x0001  /* 3DE */
+#define WM8737_3DE_SHIFT                             0  /* 3DE */
+#define WM8737_3DE_WIDTH                             1  /* 3DE */
+
+/*
+ * R5 (0x05) - ADC Control
+ */
+#define WM8737_MONOMIX_MASK                     0x0180  /* MONOMIX - [8:7] */
+#define WM8737_MONOMIX_SHIFT                         7  /* MONOMIX - [8:7] */
+#define WM8737_MONOMIX_WIDTH                         2  /* MONOMIX - [8:7] */
+#define WM8737_POLARITY_MASK                    0x0060  /* POLARITY - [6:5] */
+#define WM8737_POLARITY_SHIFT                        5  /* POLARITY - [6:5] */
+#define WM8737_POLARITY_WIDTH                        2  /* POLARITY - [6:5] */
+#define WM8737_HPOR                             0x0010  /* HPOR */
+#define WM8737_HPOR_MASK                        0x0010  /* HPOR */
+#define WM8737_HPOR_SHIFT                            4  /* HPOR */
+#define WM8737_HPOR_WIDTH                            1  /* HPOR */
+#define WM8737_LP                               0x0004  /* LP */
+#define WM8737_LP_MASK                          0x0004  /* LP */
+#define WM8737_LP_SHIFT                              2  /* LP */
+#define WM8737_LP_WIDTH                              1  /* LP */
+#define WM8737_MONOUT                           0x0002  /* MONOUT */
+#define WM8737_MONOUT_MASK                      0x0002  /* MONOUT */
+#define WM8737_MONOUT_SHIFT                          1  /* MONOUT */
+#define WM8737_MONOUT_WIDTH                          1  /* MONOUT */
+#define WM8737_ADCHPD                           0x0001  /* ADCHPD */
+#define WM8737_ADCHPD_MASK                      0x0001  /* ADCHPD */
+#define WM8737_ADCHPD_SHIFT                          0  /* ADCHPD */
+#define WM8737_ADCHPD_WIDTH                          1  /* ADCHPD */
+
+/*
+ * R6 (0x06) - Power Management
+ */
+#define WM8737_VMID                             0x0100  /* VMID */
+#define WM8737_VMID_MASK                        0x0100  /* VMID */
+#define WM8737_VMID_SHIFT                            8  /* VMID */
+#define WM8737_VMID_WIDTH                            1  /* VMID */
+#define WM8737_VREF                             0x0080  /* VREF */
+#define WM8737_VREF_MASK                        0x0080  /* VREF */
+#define WM8737_VREF_SHIFT                            7  /* VREF */
+#define WM8737_VREF_WIDTH                            1  /* VREF */
+#define WM8737_AI                               0x0040  /* AI */
+#define WM8737_AI_MASK                          0x0040  /* AI */
+#define WM8737_AI_SHIFT                              6  /* AI */
+#define WM8737_AI_WIDTH                              1  /* AI */
+#define WM8737_PGL                              0x0020  /* PGL */
+#define WM8737_PGL_MASK                         0x0020  /* PGL */
+#define WM8737_PGL_SHIFT                             5  /* PGL */
+#define WM8737_PGL_WIDTH                             1  /* PGL */
+#define WM8737_PGR                              0x0010  /* PGR */
+#define WM8737_PGR_MASK                         0x0010  /* PGR */
+#define WM8737_PGR_SHIFT                             4  /* PGR */
+#define WM8737_PGR_WIDTH                             1  /* PGR */
+#define WM8737_ADL                              0x0008  /* ADL */
+#define WM8737_ADL_MASK                         0x0008  /* ADL */
+#define WM8737_ADL_SHIFT                             3  /* ADL */
+#define WM8737_ADL_WIDTH                             1  /* ADL */
+#define WM8737_ADR                              0x0004  /* ADR */
+#define WM8737_ADR_MASK                         0x0004  /* ADR */
+#define WM8737_ADR_SHIFT                             2  /* ADR */
+#define WM8737_ADR_WIDTH                             1  /* ADR */
+#define WM8737_MICBIAS_MASK                     0x0003  /* MICBIAS - [1:0] */
+#define WM8737_MICBIAS_SHIFT                         0  /* MICBIAS - [1:0] */
+#define WM8737_MICBIAS_WIDTH                         2  /* MICBIAS - [1:0] */
+
+/*
+ * R7 (0x07) - Audio Format
+ */
+#define WM8737_SDODIS                           0x0080  /* SDODIS */
+#define WM8737_SDODIS_MASK                      0x0080  /* SDODIS */
+#define WM8737_SDODIS_SHIFT                          7  /* SDODIS */
+#define WM8737_SDODIS_WIDTH                          1  /* SDODIS */
+#define WM8737_MS                               0x0040  /* MS */
+#define WM8737_MS_MASK                          0x0040  /* MS */
+#define WM8737_MS_SHIFT                              6  /* MS */
+#define WM8737_MS_WIDTH                              1  /* MS */
+#define WM8737_LRP                              0x0010  /* LRP */
+#define WM8737_LRP_MASK                         0x0010  /* LRP */
+#define WM8737_LRP_SHIFT                             4  /* LRP */
+#define WM8737_LRP_WIDTH                             1  /* LRP */
+#define WM8737_WL_MASK                          0x000C  /* WL - [3:2] */
+#define WM8737_WL_SHIFT                              2  /* WL - [3:2] */
+#define WM8737_WL_WIDTH                              2  /* WL - [3:2] */
+#define WM8737_FORMAT_MASK                      0x0003  /* FORMAT - [1:0] */
+#define WM8737_FORMAT_SHIFT                          0  /* FORMAT - [1:0] */
+#define WM8737_FORMAT_WIDTH                          2  /* FORMAT - [1:0] */
+
+/*
+ * R8 (0x08) - Clocking
+ */
+#define WM8737_AUTODETECT                       0x0080  /* AUTODETECT */
+#define WM8737_AUTODETECT_MASK                  0x0080  /* AUTODETECT */
+#define WM8737_AUTODETECT_SHIFT                      7  /* AUTODETECT */
+#define WM8737_AUTODETECT_WIDTH                      1  /* AUTODETECT */
+#define WM8737_CLKDIV2                          0x0040  /* CLKDIV2 */
+#define WM8737_CLKDIV2_MASK                     0x0040  /* CLKDIV2 */
+#define WM8737_CLKDIV2_SHIFT                         6  /* CLKDIV2 */
+#define WM8737_CLKDIV2_WIDTH                         1  /* CLKDIV2 */
+#define WM8737_SR_MASK                          0x003E  /* SR - [5:1] */
+#define WM8737_SR_SHIFT                              1  /* SR - [5:1] */
+#define WM8737_SR_WIDTH                              5  /* SR - [5:1] */
+#define WM8737_USB_MODE                         0x0001  /* USB MODE */
+#define WM8737_USB_MODE_MASK                    0x0001  /* USB MODE */
+#define WM8737_USB_MODE_SHIFT                        0  /* USB MODE */
+#define WM8737_USB_MODE_WIDTH                        1  /* USB MODE */
+
+/*
+ * R9 (0x09) - MIC Preamp Control
+ */
+#define WM8737_RBYPEN                           0x0008  /* RBYPEN */
+#define WM8737_RBYPEN_MASK                      0x0008  /* RBYPEN */
+#define WM8737_RBYPEN_SHIFT                          3  /* RBYPEN */
+#define WM8737_RBYPEN_WIDTH                          1  /* RBYPEN */
+#define WM8737_LBYPEN                           0x0004  /* LBYPEN */
+#define WM8737_LBYPEN_MASK                      0x0004  /* LBYPEN */
+#define WM8737_LBYPEN_SHIFT                          2  /* LBYPEN */
+#define WM8737_LBYPEN_WIDTH                          1  /* LBYPEN */
+#define WM8737_MBCTRL_MASK                      0x0003  /* MBCTRL - [1:0] */
+#define WM8737_MBCTRL_SHIFT                          0  /* MBCTRL - [1:0] */
+#define WM8737_MBCTRL_WIDTH                          2  /* MBCTRL - [1:0] */
+
+/*
+ * R10 (0x0A) - Misc Bias Control
+ */
+#define WM8737_VMIDSEL_MASK                     0x000C  /* VMIDSEL - [3:2] */
+#define WM8737_VMIDSEL_SHIFT                         2  /* VMIDSEL - [3:2] */
+#define WM8737_VMIDSEL_WIDTH                         2  /* VMIDSEL - [3:2] */
+#define WM8737_LINPUT1_DC_BIAS_ENABLE           0x0002  /* LINPUT1 DC BIAS ENABLE */
+#define WM8737_LINPUT1_DC_BIAS_ENABLE_MASK      0x0002  /* LINPUT1 DC BIAS ENABLE */
+#define WM8737_LINPUT1_DC_BIAS_ENABLE_SHIFT          1  /* LINPUT1 DC BIAS ENABLE */
+#define WM8737_LINPUT1_DC_BIAS_ENABLE_WIDTH          1  /* LINPUT1 DC BIAS ENABLE */
+#define WM8737_RINPUT1_DC_BIAS_ENABLE           0x0001  /* RINPUT1 DC BIAS ENABLE */
+#define WM8737_RINPUT1_DC_BIAS_ENABLE_MASK      0x0001  /* RINPUT1 DC BIAS ENABLE */
+#define WM8737_RINPUT1_DC_BIAS_ENABLE_SHIFT          0  /* RINPUT1 DC BIAS ENABLE */
+#define WM8737_RINPUT1_DC_BIAS_ENABLE_WIDTH          1  /* RINPUT1 DC BIAS ENABLE */
+
+/*
+ * R11 (0x0B) - Noise Gate
+ */
+#define WM8737_NGTH_MASK                        0x001C  /* NGTH - [4:2] */
+#define WM8737_NGTH_SHIFT                            2  /* NGTH - [4:2] */
+#define WM8737_NGTH_WIDTH                            3  /* NGTH - [4:2] */
+#define WM8737_NGAT                             0x0001  /* NGAT */
+#define WM8737_NGAT_MASK                        0x0001  /* NGAT */
+#define WM8737_NGAT_SHIFT                            0  /* NGAT */
+#define WM8737_NGAT_WIDTH                            1  /* NGAT */
+
+/*
+ * R12 (0x0C) - ALC1
+ */
+#define WM8737_ALCSEL_MASK                      0x0180  /* ALCSEL - [8:7] */
+#define WM8737_ALCSEL_SHIFT                          7  /* ALCSEL - [8:7] */
+#define WM8737_ALCSEL_WIDTH                          2  /* ALCSEL - [8:7] */
+#define WM8737_MAX_GAIN_MASK                    0x0070  /* MAX GAIN - [6:4] */
+#define WM8737_MAX_GAIN_SHIFT                        4  /* MAX GAIN - [6:4] */
+#define WM8737_MAX_GAIN_WIDTH                        3  /* MAX GAIN - [6:4] */
+#define WM8737_ALCL_MASK                        0x000F  /* ALCL - [3:0] */
+#define WM8737_ALCL_SHIFT                            0  /* ALCL - [3:0] */
+#define WM8737_ALCL_WIDTH                            4  /* ALCL - [3:0] */
+
+/*
+ * R13 (0x0D) - ALC2
+ */
+#define WM8737_ALCZCE                           0x0010  /* ALCZCE */
+#define WM8737_ALCZCE_MASK                      0x0010  /* ALCZCE */
+#define WM8737_ALCZCE_SHIFT                          4  /* ALCZCE */
+#define WM8737_ALCZCE_WIDTH                          1  /* ALCZCE */
+#define WM8737_HLD_MASK                         0x000F  /* HLD - [3:0] */
+#define WM8737_HLD_SHIFT                             0  /* HLD - [3:0] */
+#define WM8737_HLD_WIDTH                             4  /* HLD - [3:0] */
+
+/*
+ * R14 (0x0E) - ALC3
+ */
+#define WM8737_DCY_MASK                         0x00F0  /* DCY - [7:4] */
+#define WM8737_DCY_SHIFT                             4  /* DCY - [7:4] */
+#define WM8737_DCY_WIDTH                             4  /* DCY - [7:4] */
+#define WM8737_ATK_MASK                         0x000F  /* ATK - [3:0] */
+#define WM8737_ATK_SHIFT                             0  /* ATK - [3:0] */
+#define WM8737_ATK_WIDTH                             4  /* ATK - [3:0] */
+
+/*
+ * R15 (0x0F) - Reset
+ */
+#define WM8737_RESET_MASK                       0x01FF  /* RESET - [8:0] */
+#define WM8737_RESET_SHIFT                           0  /* RESET - [8:0] */
+#define WM8737_RESET_WIDTH                           9  /* RESET - [8:0] */
+
+#endif
index aea60ef..494f2d3 100644 (file)
@@ -24,7 +24,6 @@
 #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>
 
@@ -94,10 +93,11 @@ static const struct snd_soc_dapm_route intercon[] = {
 
 static int wm8741_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, wm8741_dapm_widgets,
-                                 ARRAY_SIZE(wm8741_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+       snd_soc_dapm_new_controls(dapm, wm8741_dapm_widgets,
+                                 ARRAY_SIZE(wm8741_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
 
        return 0;
 }
@@ -455,7 +455,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8741 = {
        .resume =       wm8741_resume,
        .reg_cache_size = ARRAY_SIZE(wm8741_reg_defaults),
        .reg_word_size = sizeof(u16),
-       .reg_cache_default = &wm8741_reg_defaults,
+       .reg_cache_default = wm8741_reg_defaults,
 };
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
index 6c924cd..38f38fd 100644 (file)
@@ -25,7 +25,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/initval.h>
 
 #include "wm8750.h"
@@ -53,7 +52,6 @@ static const u16 wm8750_reg[] = {
 struct wm8750_priv {
        unsigned int sysclk;
        enum snd_soc_control_type control_type;
-       u16 reg_cache[ARRAY_SIZE(wm8750_reg)];
 };
 
 #define wm8750_reset(c)        snd_soc_write(c, WM8750_RESET, 0)
@@ -399,10 +397,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int wm8750_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets,
-                                 ARRAY_SIZE(wm8750_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_new_controls(dapm, wm8750_dapm_widgets,
+                                 ARRAY_SIZE(wm8750_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
 }
@@ -615,7 +614,7 @@ static int wm8750_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        /* Set VMID to 5k */
                        snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x01c1);
 
@@ -630,7 +629,7 @@ static int wm8750_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_write(codec, WM8750_PWR1, 0x0001);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index 87caae5..79b02ae 100644 (file)
@@ -45,7 +45,6 @@
 #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 <asm/div64.h>
@@ -623,10 +622,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int wm8753_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets,
-                                 ARRAY_SIZE(wm8753_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_new_controls(dapm, wm8753_dapm_widgets,
+                                 ARRAY_SIZE(wm8753_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
 }
@@ -1245,7 +1245,7 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_write(codec, WM8753_PWR1, 0x0001);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -1435,9 +1435,11 @@ static void wm8753_set_dai_mode(struct snd_soc_codec *codec,
 
 static void wm8753_work(struct work_struct *work)
 {
-       struct snd_soc_codec *codec =
-               container_of(work, struct snd_soc_codec, delayed_work.work);
-       wm8753_set_bias_level(codec, codec->bias_level);
+       struct snd_soc_dapm_context *dapm =
+               container_of(work, struct snd_soc_dapm_context,
+                            delayed_work.work);
+       struct snd_soc_codec *codec = dapm->codec;
+       wm8753_set_bias_level(codec, dapm->bias_level);
 }
 
 static int wm8753_suspend(struct snd_soc_codec *codec, pm_message_t state)
@@ -1466,41 +1468,22 @@ static int wm8753_resume(struct snd_soc_codec *codec)
        wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* charge wm8753 caps */
-       if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {
+       if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) {
                wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
-               codec->bias_level = SND_SOC_BIAS_ON;
-               schedule_delayed_work(&codec->delayed_work,
+               codec->dapm.bias_level = SND_SOC_BIAS_ON;
+               schedule_delayed_work(&codec->dapm.delayed_work,
                        msecs_to_jiffies(caps_charge));
        }
 
        return 0;
 }
 
-/*
- * This function forces any delayed work to be queued and run.
- */
-static int run_delayed_work(struct delayed_work *dwork)
-{
-       int ret;
-
-       /* cancel any work waiting to be queued. */
-       ret = cancel_delayed_work(dwork);
-
-       /* if there was any work waiting then we run it now and
-        * wait for it's completion */
-       if (ret) {
-               schedule_delayed_work(dwork, 0);
-               flush_scheduled_work();
-       }
-       return ret;
-}
-
 static int wm8753_probe(struct snd_soc_codec *codec)
 {
        struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
+       INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8753_work);
 
        ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8753->control_type);
        if (ret < 0) {
@@ -1519,7 +1502,7 @@ static int wm8753_probe(struct snd_soc_codec *codec)
 
        /* charge output caps */
        wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
-       schedule_delayed_work(&codec->delayed_work,
+       schedule_delayed_work(&codec->dapm.delayed_work,
                              msecs_to_jiffies(caps_charge));
 
        /* set the update bits */
@@ -1544,7 +1527,7 @@ static int wm8753_probe(struct snd_soc_codec *codec)
 /* power down chip */
 static int wm8753_remove(struct snd_soc_codec *codec)
 {
-       run_delayed_work(&codec->delayed_work);
+       flush_delayed_work_sync(&codec->dapm.delayed_work);
        wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c
new file mode 100644 (file)
index 0000000..19b92ba
--- /dev/null
@@ -0,0 +1,749 @@
+/*
+ * wm8770.c  --  WM8770 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.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/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.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 "wm8770.h"
+
+#define WM8770_NUM_SUPPLIES 3
+static const char *wm8770_supply_names[WM8770_NUM_SUPPLIES] = {
+       "AVDD1",
+       "AVDD2",
+       "DVDD"
+};
+
+static const u16 wm8770_reg_defs[WM8770_CACHEREGNUM] = {
+       0x7f, 0x7f, 0x7f, 0x7f,
+       0x7f, 0x7f, 0x7f, 0x7f,
+       0x7f, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0, 0x90, 0,
+       0, 0x22, 0x22, 0x3e,
+       0xc, 0xc, 0x100, 0x189,
+       0x189, 0x8770
+};
+
+struct wm8770_priv {
+       enum snd_soc_control_type control_type;
+       struct regulator_bulk_data supplies[WM8770_NUM_SUPPLIES];
+       struct notifier_block disable_nb[WM8770_NUM_SUPPLIES];
+       struct snd_soc_codec *codec;
+       int sysclk;
+};
+
+static int vout12supply_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event);
+static int vout34supply_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event);
+
+/*
+ * We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define WM8770_REGULATOR_EVENT(n) \
+static int wm8770_regulator_event_##n(struct notifier_block *nb, \
+                                     unsigned long event, void *data)    \
+{ \
+       struct wm8770_priv *wm8770 = container_of(nb, struct wm8770_priv, \
+                                    disable_nb[n]); \
+       if (event & REGULATOR_EVENT_DISABLE) { \
+               wm8770->codec->cache_sync = 1; \
+       } \
+       return 0; \
+}
+
+WM8770_REGULATOR_EVENT(0)
+WM8770_REGULATOR_EVENT(1)
+WM8770_REGULATOR_EVENT(2)
+
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(dac_dig_tlv, -12750, 50, 1);
+static const DECLARE_TLV_DB_SCALE(dac_alg_tlv, -12700, 100, 1);
+
+static const char *dac_phase_text[][2] = {
+       { "DAC1 Normal", "DAC1 Inverted" },
+       { "DAC2 Normal", "DAC2 Inverted" },
+       { "DAC3 Normal", "DAC3 Inverted" },
+       { "DAC4 Normal", "DAC4 Inverted" },
+};
+
+static const struct soc_enum dac_phase[] = {
+       SOC_ENUM_DOUBLE(WM8770_DACPHASE, 0, 1, 2, dac_phase_text[0]),
+       SOC_ENUM_DOUBLE(WM8770_DACPHASE, 2, 3, 2, dac_phase_text[1]),
+       SOC_ENUM_DOUBLE(WM8770_DACPHASE, 4, 5, 2, dac_phase_text[2]),
+       SOC_ENUM_DOUBLE(WM8770_DACPHASE, 6, 7, 2, dac_phase_text[3]),
+};
+
+static const struct snd_kcontrol_new wm8770_snd_controls[] = {
+       /* global DAC playback controls */
+       SOC_SINGLE_TLV("DAC Playback Volume", WM8770_MSDIGVOL, 0, 255, 0,
+               dac_dig_tlv),
+       SOC_SINGLE("DAC Playback Switch", WM8770_DACMUTE, 4, 1, 1),
+       SOC_SINGLE("DAC Playback ZC Switch", WM8770_DACCTRL1, 0, 1, 0),
+
+       /* global VOUT playback controls */
+       SOC_SINGLE_TLV("VOUT Playback Volume", WM8770_MSALGVOL, 0, 127, 0,
+               dac_alg_tlv),
+       SOC_SINGLE("VOUT Playback ZC Switch", WM8770_MSALGVOL, 7, 1, 0),
+
+       /* VOUT1/2/3/4 specific controls */
+       SOC_DOUBLE_R_TLV("VOUT1 Playback Volume", WM8770_VOUT1LVOL,
+               WM8770_VOUT1RVOL, 0, 127, 0, dac_alg_tlv),
+       SOC_DOUBLE_R("VOUT1 Playback ZC Switch", WM8770_VOUT1LVOL,
+               WM8770_VOUT1RVOL, 7, 1, 0),
+       SOC_DOUBLE_R_TLV("VOUT2 Playback Volume", WM8770_VOUT2LVOL,
+               WM8770_VOUT2RVOL, 0, 127, 0, dac_alg_tlv),
+       SOC_DOUBLE_R("VOUT2 Playback ZC Switch", WM8770_VOUT2LVOL,
+               WM8770_VOUT2RVOL, 7, 1, 0),
+       SOC_DOUBLE_R_TLV("VOUT3 Playback Volume", WM8770_VOUT3LVOL,
+               WM8770_VOUT3RVOL, 0, 127, 0, dac_alg_tlv),
+       SOC_DOUBLE_R("VOUT3 Playback ZC Switch", WM8770_VOUT3LVOL,
+               WM8770_VOUT3RVOL, 7, 1, 0),
+       SOC_DOUBLE_R_TLV("VOUT4 Playback Volume", WM8770_VOUT4LVOL,
+               WM8770_VOUT4RVOL, 0, 127, 0, dac_alg_tlv),
+       SOC_DOUBLE_R("VOUT4 Playback ZC Switch", WM8770_VOUT4LVOL,
+               WM8770_VOUT4RVOL, 7, 1, 0),
+
+       /* DAC1/2/3/4 specific controls */
+       SOC_DOUBLE_R_TLV("DAC1 Playback Volume", WM8770_DAC1LVOL,
+               WM8770_DAC1RVOL, 0, 255, 0, dac_dig_tlv),
+       SOC_SINGLE("DAC1 Deemphasis Switch", WM8770_DACCTRL2, 0, 1, 0),
+       SOC_ENUM("DAC1 Phase", dac_phase[0]),
+       SOC_DOUBLE_R_TLV("DAC2 Playback Volume", WM8770_DAC2LVOL,
+               WM8770_DAC2RVOL, 0, 255, 0, dac_dig_tlv),
+       SOC_SINGLE("DAC2 Deemphasis Switch", WM8770_DACCTRL2, 1, 1, 0),
+       SOC_ENUM("DAC2 Phase", dac_phase[1]),
+       SOC_DOUBLE_R_TLV("DAC3 Playback Volume", WM8770_DAC3LVOL,
+               WM8770_DAC3RVOL, 0, 255, 0, dac_dig_tlv),
+       SOC_SINGLE("DAC3 Deemphasis Switch", WM8770_DACCTRL2, 2, 1, 0),
+       SOC_ENUM("DAC3 Phase", dac_phase[2]),
+       SOC_DOUBLE_R_TLV("DAC4 Playback Volume", WM8770_DAC4LVOL,
+               WM8770_DAC4RVOL, 0, 255, 0, dac_dig_tlv),
+       SOC_SINGLE("DAC4 Deemphasis Switch", WM8770_DACCTRL2, 3, 1, 0),
+       SOC_ENUM("DAC4 Phase", dac_phase[3]),
+
+       /* ADC specific controls */
+       SOC_DOUBLE_R_TLV("Capture Volume", WM8770_ADCLCTRL, WM8770_ADCRCTRL,
+               0, 31, 0, adc_tlv),
+       SOC_DOUBLE_R("Capture Switch", WM8770_ADCLCTRL, WM8770_ADCRCTRL,
+               5, 1, 1),
+
+       /* other controls */
+       SOC_SINGLE("ADC 128x Oversampling Switch", WM8770_MSTRCTRL, 3, 1, 0),
+       SOC_SINGLE("ADC Highpass Filter Switch", WM8770_IFACECTRL, 8, 1, 1)
+};
+
+static const char *ain_text[] = {
+       "AIN1", "AIN2", "AIN3", "AIN4",
+       "AIN5", "AIN6", "AIN7", "AIN8"
+};
+
+static const struct soc_enum ain_enum =
+       SOC_ENUM_DOUBLE(WM8770_ADCMUX, 0, 4, 8, ain_text);
+
+static const struct snd_kcontrol_new ain_mux =
+       SOC_DAPM_ENUM("Capture Mux", ain_enum);
+
+static const struct snd_kcontrol_new vout1_mix_controls[] = {
+       SOC_DAPM_SINGLE("DAC1 Switch", WM8770_OUTMUX1, 0, 1, 0),
+       SOC_DAPM_SINGLE("AUX1 Switch", WM8770_OUTMUX1, 1, 1, 0),
+       SOC_DAPM_SINGLE("Bypass Switch", WM8770_OUTMUX1, 2, 1, 0)
+};
+
+static const struct snd_kcontrol_new vout2_mix_controls[] = {
+       SOC_DAPM_SINGLE("DAC2 Switch", WM8770_OUTMUX1, 3, 1, 0),
+       SOC_DAPM_SINGLE("AUX2 Switch", WM8770_OUTMUX1, 4, 1, 0),
+       SOC_DAPM_SINGLE("Bypass Switch", WM8770_OUTMUX1, 5, 1, 0)
+};
+
+static const struct snd_kcontrol_new vout3_mix_controls[] = {
+       SOC_DAPM_SINGLE("DAC3 Switch", WM8770_OUTMUX2, 0, 1, 0),
+       SOC_DAPM_SINGLE("AUX3 Switch", WM8770_OUTMUX2, 1, 1, 0),
+       SOC_DAPM_SINGLE("Bypass Switch", WM8770_OUTMUX2, 2, 1, 0)
+};
+
+static const struct snd_kcontrol_new vout4_mix_controls[] = {
+       SOC_DAPM_SINGLE("DAC4 Switch", WM8770_OUTMUX2, 3, 1, 0),
+       SOC_DAPM_SINGLE("Bypass Switch", WM8770_OUTMUX2, 4, 1, 0)
+};
+
+static const struct snd_soc_dapm_widget wm8770_dapm_widgets[] = {
+       SND_SOC_DAPM_INPUT("AUX1"),
+       SND_SOC_DAPM_INPUT("AUX2"),
+       SND_SOC_DAPM_INPUT("AUX3"),
+
+       SND_SOC_DAPM_INPUT("AIN1"),
+       SND_SOC_DAPM_INPUT("AIN2"),
+       SND_SOC_DAPM_INPUT("AIN3"),
+       SND_SOC_DAPM_INPUT("AIN4"),
+       SND_SOC_DAPM_INPUT("AIN5"),
+       SND_SOC_DAPM_INPUT("AIN6"),
+       SND_SOC_DAPM_INPUT("AIN7"),
+       SND_SOC_DAPM_INPUT("AIN8"),
+
+       SND_SOC_DAPM_MUX("Capture Mux", WM8770_ADCMUX, 8, 1, &ain_mux),
+
+       SND_SOC_DAPM_ADC("ADC", "Capture", WM8770_PWDNCTRL, 1, 1),
+
+       SND_SOC_DAPM_DAC("DAC1", "Playback", WM8770_PWDNCTRL, 2, 1),
+       SND_SOC_DAPM_DAC("DAC2", "Playback", WM8770_PWDNCTRL, 3, 1),
+       SND_SOC_DAPM_DAC("DAC3", "Playback", WM8770_PWDNCTRL, 4, 1),
+       SND_SOC_DAPM_DAC("DAC4", "Playback", WM8770_PWDNCTRL, 5, 1),
+
+       SND_SOC_DAPM_SUPPLY("VOUT12 Supply", SND_SOC_NOPM, 0, 0,
+               vout12supply_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY("VOUT34 Supply", SND_SOC_NOPM, 0, 0,
+               vout34supply_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MIXER("VOUT1 Mixer", SND_SOC_NOPM, 0, 0,
+               vout1_mix_controls, ARRAY_SIZE(vout1_mix_controls)),
+       SND_SOC_DAPM_MIXER("VOUT2 Mixer", SND_SOC_NOPM, 0, 0,
+               vout2_mix_controls, ARRAY_SIZE(vout2_mix_controls)),
+       SND_SOC_DAPM_MIXER("VOUT3 Mixer", SND_SOC_NOPM, 0, 0,
+               vout3_mix_controls, ARRAY_SIZE(vout3_mix_controls)),
+       SND_SOC_DAPM_MIXER("VOUT4 Mixer", SND_SOC_NOPM, 0, 0,
+               vout4_mix_controls, ARRAY_SIZE(vout4_mix_controls)),
+
+       SND_SOC_DAPM_OUTPUT("VOUT1"),
+       SND_SOC_DAPM_OUTPUT("VOUT2"),
+       SND_SOC_DAPM_OUTPUT("VOUT3"),
+       SND_SOC_DAPM_OUTPUT("VOUT4")
+};
+
+static const struct snd_soc_dapm_route wm8770_intercon[] = {
+       { "Capture Mux", "AIN1", "AIN1" },
+       { "Capture Mux", "AIN2", "AIN2" },
+       { "Capture Mux", "AIN3", "AIN3" },
+       { "Capture Mux", "AIN4", "AIN4" },
+       { "Capture Mux", "AIN5", "AIN5" },
+       { "Capture Mux", "AIN6", "AIN6" },
+       { "Capture Mux", "AIN7", "AIN7" },
+       { "Capture Mux", "AIN8", "AIN8" },
+
+       { "ADC", NULL, "Capture Mux" },
+
+       { "VOUT1 Mixer", NULL, "VOUT12 Supply" },
+       { "VOUT1 Mixer", "DAC1 Switch", "DAC1" },
+       { "VOUT1 Mixer", "AUX1 Switch", "AUX1" },
+       { "VOUT1 Mixer", "Bypass Switch", "Capture Mux" },
+
+       { "VOUT2 Mixer", NULL, "VOUT12 Supply" },
+       { "VOUT2 Mixer", "DAC2 Switch", "DAC2" },
+       { "VOUT2 Mixer", "AUX2 Switch", "AUX2" },
+       { "VOUT2 Mixer", "Bypass Switch", "Capture Mux" },
+
+       { "VOUT3 Mixer", NULL, "VOUT34 Supply" },
+       { "VOUT3 Mixer", "DAC3 Switch", "DAC3" },
+       { "VOUT3 Mixer", "AUX3 Switch", "AUX3" },
+       { "VOUT3 Mixer", "Bypass Switch", "Capture Mux" },
+
+       { "VOUT4 Mixer", NULL, "VOUT34 Supply" },
+       { "VOUT4 Mixer", "DAC4 Switch", "DAC4" },
+       { "VOUT4 Mixer", "Bypass Switch", "Capture Mux" },
+
+       { "VOUT1", NULL, "VOUT1 Mixer" },
+       { "VOUT2", NULL, "VOUT2 Mixer" },
+       { "VOUT3", NULL, "VOUT3 Mixer" },
+       { "VOUT4", NULL, "VOUT4 Mixer" }
+};
+
+static int vout12supply_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec;
+
+       codec = w->codec;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec, WM8770_OUTMUX1, 0x180, 0);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, WM8770_OUTMUX1, 0x180, 0x180);
+               break;
+       }
+
+       return 0;
+}
+
+static int vout34supply_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec;
+
+       codec = w->codec;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec, WM8770_OUTMUX2, 0x180, 0);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, WM8770_OUTMUX2, 0x180, 0x180);
+               break;
+       }
+
+       return 0;
+}
+
+static int wm8770_reset(struct snd_soc_codec *codec)
+{
+       return snd_soc_write(codec, WM8770_RESET, 0);
+}
+
+static int wm8770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec;
+       int iface, master;
+
+       codec = dai->codec;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               master = 0x100;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               master = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       iface = 0;
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               iface |= 0x2;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iface |= 0x1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               iface |= 0xc;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               iface |= 0x8;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               iface |= 0x4;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8770_IFACECTRL, 0xf, iface);
+       snd_soc_update_bits(codec, WM8770_MSTRCTRL, 0x100, master);
+
+       return 0;
+}
+
+static const int mclk_ratios[] = {
+       128,
+       192,
+       256,
+       384,
+       512,
+       768
+};
+
+static int wm8770_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec;
+       struct wm8770_priv *wm8770;
+       int i;
+       int iface;
+       int shift;
+       int ratio;
+
+       codec = dai->codec;
+       wm8770 = snd_soc_codec_get_drvdata(codec);
+
+       iface = 0;
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               iface |= 0x10;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               iface |= 0x20;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               iface |= 0x30;
+               break;
+       }
+
+       switch (substream->stream) {
+       case SNDRV_PCM_STREAM_PLAYBACK:
+               i = 0;
+               shift = 4;
+               break;
+       case SNDRV_PCM_STREAM_CAPTURE:
+               i = 2;
+               shift = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Only need to set MCLK/LRCLK ratio if we're master */
+       if (snd_soc_read(codec, WM8770_MSTRCTRL) & 0x100) {
+               for (; i < ARRAY_SIZE(mclk_ratios); ++i) {
+                       ratio = wm8770->sysclk / params_rate(params);
+                       if (ratio == mclk_ratios[i])
+                               break;
+               }
+
+               if (i == ARRAY_SIZE(mclk_ratios)) {
+                       dev_err(codec->dev,
+                               "Unable to configure MCLK ratio %d/%d\n",
+                               wm8770->sysclk, params_rate(params));
+                       return -EINVAL;
+               }
+
+               dev_dbg(codec->dev, "MCLK is %dfs\n", mclk_ratios[i]);
+
+               snd_soc_update_bits(codec, WM8770_MSTRCTRL, 0x7 << shift,
+                                   i << shift);
+       }
+
+       snd_soc_update_bits(codec, WM8770_IFACECTRL, 0x30, iface);
+
+       return 0;
+}
+
+static int wm8770_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec;
+
+       codec = dai->codec;
+       return snd_soc_update_bits(codec, WM8770_DACMUTE, 0x10,
+                                  !!mute << 4);
+}
+
+static int wm8770_set_sysclk(struct snd_soc_dai *dai,
+                            int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec;
+       struct wm8770_priv *wm8770;
+
+       codec = dai->codec;
+       wm8770 = snd_soc_codec_get_drvdata(codec);
+       wm8770->sysclk = freq;
+       return 0;
+}
+
+static void wm8770_sync_cache(struct snd_soc_codec *codec)
+{
+       int i;
+       u16 *cache;
+
+       if (!codec->cache_sync)
+               return;
+
+       codec->cache_only = 0;
+       cache = codec->reg_cache;
+       for (i = 0; i < codec->driver->reg_cache_size; i++) {
+               if (i == WM8770_RESET || cache[i] == wm8770_reg_defs[i])
+                       continue;
+               snd_soc_write(codec, i, cache[i]);
+       }
+       codec->cache_sync = 0;
+}
+
+static int wm8770_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       int ret;
+       struct wm8770_priv *wm8770;
+
+       wm8770 = snd_soc_codec_get_drvdata(codec);
+
+       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 = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies),
+                                                   wm8770->supplies);
+                       if (ret) {
+                               dev_err(codec->dev,
+                                       "Failed to enable supplies: %d\n",
+                                       ret);
+                               return ret;
+                       }
+                       wm8770_sync_cache(codec);
+                       /* global powerup */
+                       snd_soc_write(codec, WM8770_PWDNCTRL, 0);
+               }
+               break;
+       case SND_SOC_BIAS_OFF:
+               /* global powerdown */
+               snd_soc_write(codec, WM8770_PWDNCTRL, 1);
+               regulator_bulk_disable(ARRAY_SIZE(wm8770->supplies),
+                                      wm8770->supplies);
+               break;
+       }
+
+       codec->dapm.bias_level = level;
+       return 0;
+}
+
+#define WM8770_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops wm8770_dai_ops = {
+       .digital_mute = wm8770_mute,
+       .hw_params = wm8770_hw_params,
+       .set_fmt = wm8770_set_fmt,
+       .set_sysclk = wm8770_set_sysclk,
+};
+
+static struct snd_soc_dai_driver wm8770_dai = {
+       .name = "wm8770-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_192000,
+               .formats = WM8770_FORMATS
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = WM8770_FORMATS
+       },
+       .ops = &wm8770_dai_ops,
+       .symmetric_rates = 1
+};
+
+#ifdef CONFIG_PM
+static int wm8770_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+       wm8770_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int wm8770_resume(struct snd_soc_codec *codec)
+{
+       wm8770_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       return 0;
+}
+#else
+#define wm8770_suspend NULL
+#define wm8770_resume NULL
+#endif
+
+static int wm8770_probe(struct snd_soc_codec *codec)
+{
+       struct wm8770_priv *wm8770;
+       int ret;
+       int i;
+
+       wm8770 = snd_soc_codec_get_drvdata(codec);
+       wm8770->codec = codec;
+
+       codec->dapm.idle_bias_off = 1;
+
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8770->control_type);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++)
+               wm8770->supplies[i].supply = wm8770_supply_names[i];
+
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8770->supplies),
+                                wm8770->supplies);
+       if (ret) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       wm8770->disable_nb[0].notifier_call = wm8770_regulator_event_0;
+       wm8770->disable_nb[1].notifier_call = wm8770_regulator_event_1;
+       wm8770->disable_nb[2].notifier_call = wm8770_regulator_event_2;
+
+       /* This should really be moved into the regulator core */
+       for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) {
+               ret = regulator_register_notifier(wm8770->supplies[i].consumer,
+                                                 &wm8770->disable_nb[i]);
+               if (ret) {
+                       dev_err(codec->dev,
+                               "Failed to register regulator notifier: %d\n",
+                               ret);
+               }
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies),
+                                   wm8770->supplies);
+       if (ret) {
+               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_reg_get;
+       }
+
+       ret = wm8770_reset(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+               goto err_reg_enable;
+       }
+
+       wm8770_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* latch the volume update bits */
+       snd_soc_update_bits(codec, WM8770_MSDIGVOL, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8770_MSALGVOL, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8770_VOUT1RVOL, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8770_VOUT2RVOL, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8770_VOUT3RVOL, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8770_VOUT4RVOL, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8770_DAC1RVOL, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8770_DAC2RVOL, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8770_DAC3RVOL, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8770_DAC4RVOL, 0x100, 0x100);
+
+       /* mute all DACs */
+       snd_soc_update_bits(codec, WM8770_DACMUTE, 0x10, 0x10);
+
+       snd_soc_add_controls(codec, wm8770_snd_controls,
+                            ARRAY_SIZE(wm8770_snd_controls));
+       snd_soc_dapm_new_controls(&codec->dapm, wm8770_dapm_widgets,
+                                 ARRAY_SIZE(wm8770_dapm_widgets));
+       snd_soc_dapm_add_routes(&codec->dapm, wm8770_intercon,
+                               ARRAY_SIZE(wm8770_intercon));
+       return 0;
+
+err_reg_enable:
+       regulator_bulk_disable(ARRAY_SIZE(wm8770->supplies), wm8770->supplies);
+err_reg_get:
+       regulator_bulk_free(ARRAY_SIZE(wm8770->supplies), wm8770->supplies);
+       return ret;
+}
+
+static int wm8770_remove(struct snd_soc_codec *codec)
+{
+       struct wm8770_priv *wm8770;
+       int i;
+
+       wm8770 = snd_soc_codec_get_drvdata(codec);
+       wm8770_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       for (i = 0; i < ARRAY_SIZE(wm8770->supplies); ++i)
+               regulator_unregister_notifier(wm8770->supplies[i].consumer,
+                                             &wm8770->disable_nb[i]);
+       regulator_bulk_free(ARRAY_SIZE(wm8770->supplies), wm8770->supplies);
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8770 = {
+       .probe = wm8770_probe,
+       .remove = wm8770_remove,
+       .suspend = wm8770_suspend,
+       .resume = wm8770_resume,
+       .set_bias_level = wm8770_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8770_reg_defs),
+       .reg_word_size = sizeof (u16),
+       .reg_cache_default = wm8770_reg_defs
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8770_spi_probe(struct spi_device *spi)
+{
+       struct wm8770_priv *wm8770;
+       int ret;
+
+       wm8770 = kzalloc(sizeof(struct wm8770_priv), GFP_KERNEL);
+       if (!wm8770)
+               return -ENOMEM;
+
+       wm8770->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8770);
+
+       ret = snd_soc_register_codec(&spi->dev,
+                                    &soc_codec_dev_wm8770, &wm8770_dai, 1);
+       if (ret < 0)
+               kfree(wm8770);
+       return ret;
+}
+
+static int __devexit wm8770_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
+       return 0;
+}
+
+static struct spi_driver wm8770_spi_driver = {
+       .driver = {
+               .name = "wm8770",
+               .owner = THIS_MODULE,
+       },
+       .probe = wm8770_spi_probe,
+       .remove = __devexit_p(wm8770_spi_remove)
+};
+#endif
+
+static int __init wm8770_modinit(void)
+{
+       int ret = 0;
+
+#if defined(CONFIG_SPI_MASTER)
+       ret = spi_register_driver(&wm8770_spi_driver);
+       if (ret) {
+               printk(KERN_ERR "Failed to register wm8770 SPI driver: %d\n",
+                      ret);
+       }
+#endif
+       return ret;
+}
+module_init(wm8770_modinit);
+
+static void __exit wm8770_exit(void)
+{
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&wm8770_spi_driver);
+#endif
+}
+module_exit(wm8770_exit);
+
+MODULE_DESCRIPTION("ASoC WM8770 driver");
+MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8770.h b/sound/soc/codecs/wm8770.h
new file mode 100644 (file)
index 0000000..5f1b3bd
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * wm8770.h  --  WM8770 ASoC driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.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 _WM8770_H
+#define _WM8770_H
+
+/* Registers */
+#define WM8770_VOUT1LVOL                0
+#define WM8770_VOUT1RVOL                0x1
+#define WM8770_VOUT2LVOL                0x2
+#define WM8770_VOUT2RVOL                0x3
+#define WM8770_VOUT3LVOL                0x4
+#define WM8770_VOUT3RVOL                0x5
+#define WM8770_VOUT4LVOL                0x6
+#define WM8770_VOUT4RVOL                0x7
+#define WM8770_MSALGVOL                 0x8
+#define WM8770_DAC1LVOL                 0x9
+#define WM8770_DAC1RVOL                 0xa
+#define WM8770_DAC2LVOL                 0xb
+#define WM8770_DAC2RVOL                 0xc
+#define WM8770_DAC3LVOL                 0xd
+#define WM8770_DAC3RVOL                 0xe
+#define WM8770_DAC4LVOL                 0xf
+#define WM8770_DAC4RVOL                 0x10
+#define WM8770_MSDIGVOL                 0x11
+#define WM8770_DACPHASE                 0x12
+#define WM8770_DACCTRL1                 0x13
+#define WM8770_DACMUTE                  0x14
+#define WM8770_DACCTRL2                 0x15
+#define WM8770_IFACECTRL                0x16
+#define WM8770_MSTRCTRL                 0x17
+#define WM8770_PWDNCTRL                 0x18
+#define WM8770_ADCLCTRL                 0x19
+#define WM8770_ADCRCTRL                 0x1a
+#define WM8770_ADCMUX                   0x1b
+#define WM8770_OUTMUX1                  0x1c
+#define WM8770_OUTMUX2                  0x1d
+#define WM8770_RESET                    0x31
+
+#define WM8770_CACHEREGNUM 0x20
+
+#endif
index 0132a27..8e7953b 100644 (file)
@@ -25,7 +25,6 @@
 #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>
 
@@ -306,7 +305,7 @@ static int wm8776_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_PREPARE:
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        /* Disable the global powerdown; DAPM does the rest */
                        snd_soc_update_bits(codec, WM8776_PWRDOWN, 1, 0);
                }
@@ -317,7 +316,7 @@ static int wm8776_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -404,6 +403,7 @@ static int wm8776_resume(struct snd_soc_codec *codec)
 static int wm8776_probe(struct snd_soc_codec *codec)
 {
        struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret = 0;
 
        ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8776->control_type);
@@ -427,9 +427,9 @@ static int wm8776_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, wm8776_snd_controls,
                             ARRAY_SIZE(wm8776_snd_controls));
-       snd_soc_dapm_new_controls(codec, wm8776_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, wm8776_dapm_widgets,
                                  ARRAY_SIZE(wm8776_dapm_widgets));
-       snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes));
+       snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
 
        return ret;
 }
index 4599e8e..6dae1b4 100644 (file)
@@ -23,7 +23,6 @@
 #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>
 
@@ -515,7 +514,7 @@ static int wm8804_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0);
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
                                                    wm8804->supplies);
                        if (ret) {
@@ -537,7 +536,7 @@ static int wm8804_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -581,7 +580,7 @@ static int wm8804_probe(struct snd_soc_codec *codec)
        wm8804 = snd_soc_codec_get_drvdata(codec);
        wm8804->codec = codec;
 
-       codec->idle_bias_off = 1;
+       codec->dapm.idle_bias_off = 1;
 
        ret = snd_soc_codec_set_cache_io(codec, 8, 8, wm8804->control_type);
        if (ret < 0) {
index aca4b1e..cd09599 100644 (file)
@@ -30,7 +30,6 @@
 #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>
 
 
 struct wm8900_priv {
        enum snd_soc_control_type control_type;
-       u16 reg_cache[WM8900_MAXREG];
 
        u32 fll_in; /* FLL input frequency */
        u32 fll_out; /* FLL output frequency */
@@ -611,10 +609,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int wm8900_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, wm8900_dapm_widgets,
-                                 ARRAY_SIZE(wm8900_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_new_controls(dapm, wm8900_dapm_widgets,
+                                 ARRAY_SIZE(wm8900_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
 }
@@ -1051,7 +1050,7 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec,
 
        case SND_SOC_BIAS_STANDBY:
                /* Charge capacitors if initial power up */
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        /* STARTUP_BIAS_ENA on */
                        snd_soc_write(codec, WM8900_REG_POWER1,
                                     WM8900_REG_POWER1_STARTUP_BIAS_ENA);
@@ -1119,7 +1118,7 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec,
                             WM8900_REG_POWER2_SYSCLK_ENA);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index 622b602..987476a 100644 (file)
@@ -29,9 +29,9 @@
 #include <sound/pcm_params.h>
 #include <sound/tlv.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/initval.h>
 #include <sound/wm8903.h>
+#include <trace/events/asoc.h>
 
 #include "wm8903.h"
 
@@ -214,15 +214,14 @@ static u16 wm8903_reg_defaults[] = {
 
 struct wm8903_priv {
 
-       u16 reg_cache[ARRAY_SIZE(wm8903_reg_defaults)];
-
        int sysclk;
        int irq;
 
-       /* Reference counts */
+       int fs;
+       int deemph;
+
+       /* Reference count */
        int class_w_users;
-       int playback_active;
-       int capture_active;
 
        struct completion wseq;
 
@@ -231,9 +230,6 @@ struct wm8903_priv {
        int mic_short;
        int mic_last_report;
        int mic_delay;
-
-       struct snd_pcm_substream *master_substream;
-       struct snd_pcm_substream *slave_substream;
 };
 
 static int wm8903_volatile_register(unsigned int reg)
@@ -463,6 +459,72 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
        .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
 
 
+static int wm8903_deemph[] = { 0, 32000, 44100, 48000 };
+
+static int wm8903_set_deemph(struct snd_soc_codec *codec)
+{
+       struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
+       int val, i, best;
+
+       /* If we're using deemphasis select the nearest available sample
+        * rate.
+        */
+       if (wm8903->deemph) {
+               best = 1;
+               for (i = 2; i < ARRAY_SIZE(wm8903_deemph); i++) {
+                       if (abs(wm8903_deemph[i] - wm8903->fs) <
+                           abs(wm8903_deemph[best] - wm8903->fs))
+                               best = i;
+               }
+
+               val = best << WM8903_DEEMPH_SHIFT;
+       } else {
+               best = 0;
+               val = 0;
+       }
+
+       dev_dbg(codec->dev, "Set deemphasis %d (%dHz)\n",
+               best, wm8903_deemph[best]);
+
+       return snd_soc_update_bits(codec, WM8903_DAC_DIGITAL_1,
+                                  WM8903_DEEMPH_MASK, val);
+}
+
+static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = wm8903->deemph;
+
+       return 0;
+}
+
+static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
+       int deemph = ucontrol->value.enumerated.item[0];
+       int ret = 0;
+
+       if (deemph > 1)
+               return -EINVAL;
+
+       mutex_lock(&codec->mutex);
+       if (wm8903->deemph != deemph) {
+               wm8903->deemph = deemph;
+
+               wm8903_set_deemph(codec);
+
+               ret = 1;
+       }
+       mutex_unlock(&codec->mutex);
+
+       return ret;
+}
+
 /* ALSA can only do steps of .01dB */
 static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
 
@@ -475,6 +537,23 @@ static const DECLARE_TLV_DB_SCALE(drc_tlv_min, 0, 600, 0);
 static const DECLARE_TLV_DB_SCALE(drc_tlv_max, 1200, 600, 0);
 static const DECLARE_TLV_DB_SCALE(drc_tlv_startup, -300, 50, 0);
 
+static const char *hpf_mode_text[] = {
+       "Hi-fi", "Voice 1", "Voice 2", "Voice 3"
+};
+
+static const struct soc_enum hpf_mode =
+       SOC_ENUM_SINGLE(WM8903_ADC_DIGITAL_0, 5, 4, hpf_mode_text);
+
+static const char *osr_text[] = {
+       "Low power", "High performance"
+};
+
+static const struct soc_enum adc_osr =
+       SOC_ENUM_SINGLE(WM8903_ANALOGUE_ADC_0, 0, 2, osr_text);
+
+static const struct soc_enum dac_osr =
+       SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 0, 2, osr_text);
+
 static const char *drc_slope_text[] = {
        "1", "1/2", "1/4", "1/8", "1/16", "0"
 };
@@ -537,13 +616,6 @@ static const char *mute_mode_text[] = {
 static const struct soc_enum mute_mode =
        SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 9, 2, mute_mode_text);
 
-static const char *dac_deemphasis_text[] = {
-       "Disabled", "32kHz", "44.1kHz", "48kHz"
-};
-
-static const struct soc_enum dac_deemphasis =
-       SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 1, 4, dac_deemphasis_text);
-
 static const char *companding_text[] = {
        "ulaw", "alaw"
 };
@@ -613,6 +685,9 @@ SOC_SINGLE("Right Input PGA Common Mode Switch", WM8903_ANALOGUE_RIGHT_INPUT_1,
           6, 1, 0),
 
 /* ADCs */
+SOC_ENUM("ADC OSR", adc_osr),
+SOC_SINGLE("HPF Switch", WM8903_ADC_DIGITAL_0, 4, 1, 0),
+SOC_ENUM("HPF Mode", hpf_mode),
 SOC_SINGLE("DRC Switch", WM8903_DRC_0, 15, 1, 0),
 SOC_ENUM("DRC Compressor Slope R0", drc_slope_r0),
 SOC_ENUM("DRC Compressor Slope R1", drc_slope_r1),
@@ -642,14 +717,16 @@ SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8903_DAC_DIGITAL_0, 4, 8,
               12, 0, digital_sidetone_tlv),
 
 /* DAC */
+SOC_ENUM("DAC OSR", dac_osr),
 SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8903_DAC_DIGITAL_VOLUME_LEFT,
                 WM8903_DAC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv),
 SOC_ENUM("DAC Soft Mute Rate", soft_mute),
 SOC_ENUM("DAC Mute Mode", mute_mode),
 SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0),
-SOC_ENUM("DAC De-emphasis", dac_deemphasis),
 SOC_ENUM("DAC Companding Mode", dac_companding),
 SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0),
+SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0,
+                   wm8903_get_deemph, wm8903_put_deemph),
 
 /* Headphones */
 SOC_DOUBLE_R("Headphone Switch",
@@ -923,10 +1000,11 @@ static const struct snd_soc_dapm_route intercon[] = {
 
 static int wm8903_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, wm8903_dapm_widgets,
-                                 ARRAY_SIZE(wm8903_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+       snd_soc_dapm_new_controls(dapm, wm8903_dapm_widgets,
+                                 ARRAY_SIZE(wm8903_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
 
        return 0;
 }
@@ -934,7 +1012,7 @@ static int wm8903_add_widgets(struct snd_soc_codec *codec)
 static int wm8903_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
-       u16 reg, reg2;
+       u16 reg;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
@@ -946,7 +1024,7 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        snd_soc_write(codec, WM8903_CLOCK_RATES_2,
                                     WM8903_CLK_SYS_ENA);
 
@@ -958,23 +1036,15 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec,
                        wm8903_run_sequence(codec, 0);
                        wm8903_sync_reg_cache(codec, codec->reg_cache);
 
-                       /* Enable low impedence charge pump output */
-                       reg = snd_soc_read(codec,
-                                         WM8903_CONTROL_INTERFACE_TEST_1);
-                       snd_soc_write(codec, WM8903_CONTROL_INTERFACE_TEST_1,
-                                    reg | WM8903_TEST_KEY);
-                       reg2 = snd_soc_read(codec, WM8903_CHARGE_PUMP_TEST_1);
-                       snd_soc_write(codec, WM8903_CHARGE_PUMP_TEST_1,
-                                    reg2 | WM8903_CP_SW_KELVIN_MODE_MASK);
-                       snd_soc_write(codec, WM8903_CONTROL_INTERFACE_TEST_1,
-                                    reg);
-
                        /* By default no bypass paths are enabled so
                         * enable Class W support.
                         */
                        dev_dbg(codec->dev, "Enabling Class W\n");
-                       snd_soc_write(codec, WM8903_CLASS_W_0, reg |
-                                    WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V);
+                       snd_soc_update_bits(codec, WM8903_CLASS_W_0,
+                                           WM8903_CP_DYN_FREQ |
+                                           WM8903_CP_DYN_V,
+                                           WM8903_CP_DYN_FREQ |
+                                           WM8903_CP_DYN_V);
                }
 
                reg = snd_soc_read(codec, WM8903_VMID_CONTROL_0);
@@ -991,7 +1061,7 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
 
        return 0;
 }
@@ -1222,58 +1292,6 @@ static struct {
        { 0,      0 },
 };
 
-static int wm8903_startup(struct snd_pcm_substream *substream,
-                         struct snd_soc_dai *dai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
-       struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-       struct snd_pcm_runtime *master_runtime;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               wm8903->playback_active++;
-       else
-               wm8903->capture_active++;
-
-       /* The DAI has shared clocks so if we already have a playback or
-        * capture going then constrain this substream to match it.
-        */
-       if (wm8903->master_substream) {
-               master_runtime = wm8903->master_substream->runtime;
-
-               dev_dbg(codec->dev, "Constraining to %d bits\n",
-                       master_runtime->sample_bits);
-
-               snd_pcm_hw_constraint_minmax(substream->runtime,
-                                            SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
-                                            master_runtime->sample_bits,
-                                            master_runtime->sample_bits);
-
-               wm8903->slave_substream = substream;
-       } else
-               wm8903->master_substream = substream;
-
-       return 0;
-}
-
-static void wm8903_shutdown(struct snd_pcm_substream *substream,
-                           struct snd_soc_dai *dai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->codec;
-       struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               wm8903->playback_active--;
-       else
-               wm8903->capture_active--;
-
-       if (wm8903->master_substream == substream)
-               wm8903->master_substream = wm8903->slave_substream;
-
-       wm8903->slave_substream = NULL;
-}
-
 static int wm8903_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params,
                            struct snd_soc_dai *dai)
@@ -1298,11 +1316,6 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
        u16 clock1 = snd_soc_read(codec, WM8903_CLOCK_RATES_1);
        u16 dac_digital1 = snd_soc_read(codec, WM8903_DAC_DIGITAL_1);
 
-       if (substream == wm8903->slave_substream) {
-               dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n");
-               return 0;
-       }
-
        /* Enable sloping stopband filter for low sample rates */
        if (fs <= 24000)
                dac_digital1 |= WM8903_DAC_SB_FILT;
@@ -1320,19 +1333,6 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
                }
        }
 
-       /* Constraints should stop us hitting this but let's make sure */
-       if (wm8903->capture_active)
-               switch (sample_rates[dsp_config].rate) {
-               case 88200:
-               case 96000:
-                       dev_err(codec->dev, "%dHz unsupported by ADC\n",
-                               fs);
-                       return -EINVAL;
-
-               default:
-                       break;
-               }
-
        dev_dbg(codec->dev, "DSP fs = %dHz\n", sample_rates[dsp_config].rate);
        clock1 &= ~WM8903_SAMPLE_RATE_MASK;
        clock1 |= sample_rates[dsp_config].value;
@@ -1428,6 +1428,9 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
        aif2 |= bclk_divs[bclk_div].div;
        aif3 |= bclk / fs;
 
+       wm8903->fs = params_rate(params);
+       wm8903_set_deemph(codec);
+
        snd_soc_write(codec, WM8903_CLOCK_RATES_0, clock0);
        snd_soc_write(codec, WM8903_CLOCK_RATES_1, clock1);
        snd_soc_write(codec, WM8903_AUDIO_INTERFACE_1, aif1);
@@ -1521,6 +1524,11 @@ static irqreturn_t wm8903_irq(int irq, void *data)
        mic_report = wm8903->mic_last_report;
        int_pol = snd_soc_read(codec, WM8903_INTERRUPT_POLARITY_1);
 
+#ifndef CONFIG_SND_SOC_WM8903_MODULE
+       if (int_val & (WM8903_MICSHRT_EINT | WM8903_MICDET_EINT))
+               trace_snd_soc_jack_irq(dev_name(codec->dev));
+#endif
+
        if (int_val & WM8903_MICSHRT_EINT) {
                dev_dbg(codec->dev, "Microphone short (pol=%x)\n", int_pol);
 
@@ -1571,8 +1579,6 @@ static irqreturn_t wm8903_irq(int irq, void *data)
                        SNDRV_PCM_FMTBIT_S24_LE)
 
 static struct snd_soc_dai_ops wm8903_dai_ops = {
-       .startup        = wm8903_startup,
-       .shutdown       = wm8903_shutdown,
        .hw_params      = wm8903_hw_params,
        .digital_mute   = wm8903_digital_mute,
        .set_fmt        = wm8903_set_dai_fmt,
index 996435e..e8490f3 100644 (file)
@@ -19,10 +19,6 @@ extern int wm8903_mic_detect(struct snd_soc_codec *codec,
                             struct snd_soc_jack *jack,
                             int det, int shrt);
 
-#define WM8903_MCLK_DIV_2 1
-#define WM8903_CLK_SYS    2
-#define WM8903_BCLK       3
-#define WM8903_LRCLK      4
 
 /*
  * Register values.
@@ -98,8 +94,6 @@ extern int wm8903_mic_detect(struct snd_soc_codec *codec,
 #define WM8903_INTERRUPT_STATUS_1_MASK          0x7A
 #define WM8903_INTERRUPT_POLARITY_1             0x7B
 #define WM8903_INTERRUPT_CONTROL                0x7E
-#define WM8903_CONTROL_INTERFACE_TEST_1         0x81
-#define WM8903_CHARGE_PUMP_TEST_1               0x95
 #define WM8903_CLOCK_RATE_TEST_4                0xA4
 #define WM8903_ANALOGUE_OUTPUT_BIAS_0           0xAC
 
@@ -1205,25 +1199,6 @@ extern int wm8903_mic_detect(struct snd_soc_codec *codec,
 #define WM8903_IRQ_POL_SHIFT                         0  /* IRQ_POL */
 #define WM8903_IRQ_POL_WIDTH                         1  /* IRQ_POL */
 
-/*
- * R129 (0x81) - Control Interface Test 1
- */
-#define WM8903_USER_KEY                         0x0002  /* USER_KEY */
-#define WM8903_USER_KEY_MASK                    0x0002  /* USER_KEY */
-#define WM8903_USER_KEY_SHIFT                        1  /* USER_KEY */
-#define WM8903_USER_KEY_WIDTH                        1  /* USER_KEY */
-#define WM8903_TEST_KEY                         0x0001  /* TEST_KEY */
-#define WM8903_TEST_KEY_MASK                    0x0001  /* TEST_KEY */
-#define WM8903_TEST_KEY_SHIFT                        0  /* TEST_KEY */
-#define WM8903_TEST_KEY_WIDTH                        1  /* TEST_KEY */
-
-/*
- * R149 (0x95) - Charge Pump Test 1
- */
-#define WM8903_CP_SW_KELVIN_MODE_MASK           0x0006  /* CP_SW_KELVIN_MODE - [2:1] */
-#define WM8903_CP_SW_KELVIN_MODE_SHIFT               1  /* CP_SW_KELVIN_MODE - [2:1] */
-#define WM8903_CP_SW_KELVIN_MODE_WIDTH               2  /* CP_SW_KELVIN_MODE - [2:1] */
-
 /*
  * R164 (0xA4) - Clock Rate Test 4
  */
index 1ec12ef..9de44a4 100644 (file)
@@ -24,7 +24,6 @@
 #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 <sound/wm8904.h>
@@ -1427,10 +1426,11 @@ static const struct snd_soc_dapm_route wm8912_intercon[] = {
 static int wm8904_add_widgets(struct snd_soc_codec *codec)
 {
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_new_controls(codec, wm8904_core_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, wm8904_core_dapm_widgets,
                                  ARRAY_SIZE(wm8904_core_dapm_widgets));
-       snd_soc_dapm_add_routes(codec, core_intercon,
+       snd_soc_dapm_add_routes(dapm, core_intercon,
                                ARRAY_SIZE(core_intercon));
 
        switch (wm8904->devtype) {
@@ -1442,20 +1442,20 @@ static int wm8904_add_widgets(struct snd_soc_codec *codec)
                snd_soc_add_controls(codec, wm8904_snd_controls,
                                     ARRAY_SIZE(wm8904_snd_controls));
 
-               snd_soc_dapm_new_controls(codec, wm8904_adc_dapm_widgets,
+               snd_soc_dapm_new_controls(dapm, wm8904_adc_dapm_widgets,
                                          ARRAY_SIZE(wm8904_adc_dapm_widgets));
-               snd_soc_dapm_new_controls(codec, wm8904_dac_dapm_widgets,
+               snd_soc_dapm_new_controls(dapm, wm8904_dac_dapm_widgets,
                                          ARRAY_SIZE(wm8904_dac_dapm_widgets));
-               snd_soc_dapm_new_controls(codec, wm8904_dapm_widgets,
+               snd_soc_dapm_new_controls(dapm, wm8904_dapm_widgets,
                                          ARRAY_SIZE(wm8904_dapm_widgets));
 
-               snd_soc_dapm_add_routes(codec, core_intercon,
+               snd_soc_dapm_add_routes(dapm, core_intercon,
                                        ARRAY_SIZE(core_intercon));
-               snd_soc_dapm_add_routes(codec, adc_intercon,
+               snd_soc_dapm_add_routes(dapm, adc_intercon,
                                        ARRAY_SIZE(adc_intercon));
-               snd_soc_dapm_add_routes(codec, dac_intercon,
+               snd_soc_dapm_add_routes(dapm, dac_intercon,
                                        ARRAY_SIZE(dac_intercon));
-               snd_soc_dapm_add_routes(codec, wm8904_intercon,
+               snd_soc_dapm_add_routes(dapm, wm8904_intercon,
                                        ARRAY_SIZE(wm8904_intercon));
                break;
 
@@ -1463,17 +1463,17 @@ static int wm8904_add_widgets(struct snd_soc_codec *codec)
                snd_soc_add_controls(codec, wm8904_dac_snd_controls,
                                     ARRAY_SIZE(wm8904_dac_snd_controls));
 
-               snd_soc_dapm_new_controls(codec, wm8904_dac_dapm_widgets,
+               snd_soc_dapm_new_controls(dapm, wm8904_dac_dapm_widgets,
                                          ARRAY_SIZE(wm8904_dac_dapm_widgets));
 
-               snd_soc_dapm_add_routes(codec, dac_intercon,
+               snd_soc_dapm_add_routes(dapm, dac_intercon,
                                        ARRAY_SIZE(dac_intercon));
-               snd_soc_dapm_add_routes(codec, wm8912_intercon,
+               snd_soc_dapm_add_routes(dapm, wm8912_intercon,
                                        ARRAY_SIZE(wm8912_intercon));
                break;
        }
 
-       snd_soc_dapm_new_widgets(codec);
+       snd_soc_dapm_new_widgets(dapm);
        return 0;
 }
 
@@ -1589,7 +1589,7 @@ static int wm8904_hw_params(struct snd_pcm_substream *substream,
                       - wm8904->fs);
        for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) {
                cur_val = abs((wm8904->sysclk_rate /
-                              clk_sys_rates[i].ratio) - wm8904->fs);;
+                              clk_sys_rates[i].ratio) - wm8904->fs);
                if (cur_val < best_val) {
                        best = i;
                        best_val = cur_val;
@@ -2138,7 +2138,7 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies),
                                                    wm8904->supplies);
                        if (ret != 0) {
@@ -2197,7 +2197,7 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec,
                                       wm8904->supplies);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -2373,7 +2373,7 @@ static int wm8904_probe(struct snd_soc_codec *codec)
        int ret, i;
 
        codec->cache_sync = 1;
-       codec->idle_bias_off = 1;
+       codec->dapm.idle_bias_off = 1;
 
        switch (wm8904->devtype) {
        case WM8904:
index 23086e2..25580e3 100644 (file)
@@ -35,7 +35,6 @@
 #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>
 
@@ -43,7 +42,6 @@
 
 struct wm8940_priv {
        unsigned int sysclk;
-       u16 reg_cache[WM8940_CACHEREGNUM];
        enum snd_soc_control_type control_type;
        void *control_data;
 };
@@ -291,13 +289,14 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int wm8940_add_widgets(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
-       ret = snd_soc_dapm_new_controls(codec, wm8940_dapm_widgets,
+       ret = snd_soc_dapm_new_controls(dapm, wm8940_dapm_widgets,
                                        ARRAY_SIZE(wm8940_dapm_widgets));
        if (ret)
                goto error_ret;
-       ret = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       ret = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
        if (ret)
                goto error_ret;
 
@@ -735,7 +734,6 @@ static int wm8940_probe(struct snd_soc_codec *codec)
                return ret;
 
        return ret;
-;
 }
 
 static int wm8940_remove(struct snd_soc_codec *codec)
index 2ac35b0..7167dfc 100644 (file)
@@ -23,7 +23,6 @@
 #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 <sound/wm8955.h>
@@ -576,13 +575,14 @@ static const struct snd_soc_dapm_route wm8955_intercon[] = {
 
 static int wm8955_add_widgets(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
        snd_soc_add_controls(codec, wm8955_snd_controls,
                             ARRAY_SIZE(wm8955_snd_controls));
 
-       snd_soc_dapm_new_controls(codec, wm8955_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, wm8955_dapm_widgets,
                                  ARRAY_SIZE(wm8955_dapm_widgets));
-
-       snd_soc_dapm_add_routes(codec, wm8955_intercon,
+       snd_soc_dapm_add_routes(dapm, wm8955_intercon,
                                ARRAY_SIZE(wm8955_intercon));
 
        return 0;
@@ -786,7 +786,7 @@ static int wm8955_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies),
                                                    wm8955->supplies);
                        if (ret != 0) {
@@ -850,7 +850,7 @@ static int wm8955_set_bias_level(struct snd_soc_codec *codec,
                                       wm8955->supplies);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index ff6ff2f..4393394 100644 (file)
@@ -20,7 +20,6 @@
 #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 <sound/wm8960.h>
@@ -72,7 +71,6 @@ static const u16 wm8960_reg[WM8960_CACHEREGNUM] = {
 };
 
 struct wm8960_priv {
-       u16 reg_cache[WM8960_CACHEREGNUM];
        enum snd_soc_control_type control_type;
        void *control_data;
        int (*set_bias_level)(struct snd_soc_codec *,
@@ -389,27 +387,28 @@ static int wm8960_add_widgets(struct snd_soc_codec *codec)
 {
        struct wm8960_data *pdata = codec->dev->platform_data;
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        struct snd_soc_dapm_widget *w;
 
-       snd_soc_dapm_new_controls(codec, wm8960_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets,
                                  ARRAY_SIZE(wm8960_dapm_widgets));
 
-       snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
+       snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths));
 
        /* In capless mode OUT3 is used to provide VMID for the
         * headphone outputs, otherwise it is used as a mono mixer.
         */
        if (pdata && pdata->capless) {
-               snd_soc_dapm_new_controls(codec, wm8960_dapm_widgets_capless,
+               snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets_capless,
                                          ARRAY_SIZE(wm8960_dapm_widgets_capless));
 
-               snd_soc_dapm_add_routes(codec, audio_paths_capless,
+               snd_soc_dapm_add_routes(dapm, audio_paths_capless,
                                        ARRAY_SIZE(audio_paths_capless));
        } else {
-               snd_soc_dapm_new_controls(codec, wm8960_dapm_widgets_out3,
+               snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets_out3,
                                          ARRAY_SIZE(wm8960_dapm_widgets_out3));
 
-               snd_soc_dapm_add_routes(codec, audio_paths_out3,
+               snd_soc_dapm_add_routes(dapm, audio_paths_out3,
                                        ARRAY_SIZE(audio_paths_out3));
        }
 
@@ -418,7 +417,9 @@ static int wm8960_add_widgets(struct snd_soc_codec *codec)
         * list each time to find the desired power state do so now
         * and save the result.
         */
-       list_for_each_entry(w, &codec->dapm_widgets, list) {
+       list_for_each_entry(w, &codec->card->widgets, list) {
+               if (w->dapm != &codec->dapm)
+                       continue;
                if (strcmp(w->name, "LOUT1 PGA") == 0)
                        wm8960->lout1 = w;
                if (strcmp(w->name, "ROUT1 PGA") == 0)
@@ -573,7 +574,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        /* Enable anti-pop features */
                        snd_soc_write(codec, WM8960_APOP1,
                                      WM8960_POBCTRL | WM8960_SOFT_ST |
@@ -611,7 +612,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
 
        return 0;
 }
@@ -627,7 +628,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_PREPARE:
-               switch (codec->bias_level) {
+               switch (codec->dapm.bias_level) {
                case SND_SOC_BIAS_STANDBY:
                        /* Enable anti pop mode */
                        snd_soc_update_bits(codec, WM8960_APOP1,
@@ -682,7 +683,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               switch (codec->bias_level) {
+               switch (codec->dapm.bias_level) {
                case SND_SOC_BIAS_PREPARE:
                        /* Disable HP discharge */
                        snd_soc_update_bits(codec, WM8960_APOP2,
@@ -706,7 +707,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
 
        return 0;
 }
index 8340485..55252e7 100644 (file)
@@ -23,7 +23,6 @@
 #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>
 
@@ -290,7 +289,6 @@ static u16 wm8961_reg_defaults[] = {
 struct wm8961_priv {
        enum snd_soc_control_type control_type;
        int sysclk;
-       u16 reg_cache[WM8961_MAX_REGISTER];
 };
 
 static int wm8961_volatile_register(unsigned int reg)
@@ -882,7 +880,7 @@ static int wm8961_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_PREPARE:
-               if (codec->bias_level == SND_SOC_BIAS_STANDBY) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
                        /* Enable bias generation */
                        reg = snd_soc_read(codec, WM8961_ANTI_POP);
                        reg |= WM8961_BUFIOEN | WM8961_BUFDCOPEN;
@@ -897,7 +895,7 @@ static int wm8961_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_PREPARE) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) {
                        /* VREF off */
                        reg = snd_soc_read(codec, WM8961_PWR_MGMT_1);
                        reg &= ~WM8961_VREF;
@@ -919,7 +917,7 @@ static int wm8961_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
 
        return 0;
 }
@@ -959,6 +957,7 @@ static struct snd_soc_dai_driver wm8961_dai = {
 
 static int wm8961_probe(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret = 0;
        u16 reg;
 
@@ -1024,9 +1023,9 @@ static int wm8961_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, wm8961_snd_controls,
                                ARRAY_SIZE(wm8961_snd_controls));
-       snd_soc_dapm_new_controls(codec, wm8961_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, wm8961_dapm_widgets,
                                  ARRAY_SIZE(wm8961_dapm_widgets));
-       snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
+       snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths));
 
        return 0;
 }
index 7c421cc..b9cb1fc 100644 (file)
 #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 <sound/wm8962.h>
+#include <trace/events/asoc.h>
 
 #include "wm8962.h"
 
@@ -1956,7 +1956,7 @@ static int wm8962_readable_register(unsigned int reg)
 
 static int wm8962_reset(struct snd_soc_codec *codec)
 {
-       return snd_soc_write(codec, WM8962_SOFTWARE_RESET, 0);
+       return snd_soc_write(codec, WM8962_SOFTWARE_RESET, 0x6243);
 }
 
 static const DECLARE_TLV_DB_SCALE(inpga_tlv, -2325, 75, 0);
@@ -2677,6 +2677,7 @@ 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 snd_soc_dapm_context *dapm = &codec->dapm;
 
        snd_soc_add_controls(codec, wm8962_snd_controls,
                             ARRAY_SIZE(wm8962_snd_controls));
@@ -2688,26 +2689,26 @@ static int wm8962_add_widgets(struct snd_soc_codec *codec)
                                     ARRAY_SIZE(wm8962_spk_stereo_controls));
 
 
-       snd_soc_dapm_new_controls(codec, wm8962_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, wm8962_dapm_widgets,
                                  ARRAY_SIZE(wm8962_dapm_widgets));
        if (pdata && pdata->spk_mono)
-               snd_soc_dapm_new_controls(codec, wm8962_dapm_spk_mono_widgets,
+               snd_soc_dapm_new_controls(dapm, wm8962_dapm_spk_mono_widgets,
                                          ARRAY_SIZE(wm8962_dapm_spk_mono_widgets));
        else
-               snd_soc_dapm_new_controls(codec, wm8962_dapm_spk_stereo_widgets,
+               snd_soc_dapm_new_controls(dapm, wm8962_dapm_spk_stereo_widgets,
                                          ARRAY_SIZE(wm8962_dapm_spk_stereo_widgets));
 
-       snd_soc_dapm_add_routes(codec, wm8962_intercon,
+       snd_soc_dapm_add_routes(dapm, wm8962_intercon,
                                ARRAY_SIZE(wm8962_intercon));
        if (pdata && pdata->spk_mono)
-               snd_soc_dapm_add_routes(codec, wm8962_spk_mono_intercon,
+               snd_soc_dapm_add_routes(dapm, wm8962_spk_mono_intercon,
                                        ARRAY_SIZE(wm8962_spk_mono_intercon));
        else
-               snd_soc_dapm_add_routes(codec, wm8962_spk_stereo_intercon,
+               snd_soc_dapm_add_routes(dapm, wm8962_spk_stereo_intercon,
                                        ARRAY_SIZE(wm8962_spk_stereo_intercon));
 
 
-       snd_soc_dapm_disable_pin(codec, "Beep");
+       snd_soc_dapm_disable_pin(dapm, "Beep");
 
        return 0;
 }
@@ -2814,7 +2815,7 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec,
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       if (level == codec->bias_level)
+       if (level == codec->dapm.bias_level)
                return 0;
 
        switch (level) {
@@ -2828,7 +2829,7 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies),
                                                    wm8962->supplies);
                        if (ret != 0) {
@@ -2878,7 +2879,7 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec,
                                       wm8962->supplies);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -3348,6 +3349,12 @@ static irqreturn_t wm8962_irq(int irq, void *data)
        if (active & (WM8962_MICSCD_EINT | WM8962_MICD_EINT)) {
                dev_dbg(codec->dev, "Microphone event detected\n");
 
+#ifndef CONFIG_SND_SOC_WM8962_MODULE
+               trace_snd_soc_jack_irq(dev_name(codec->dev));
+#endif
+
+               pm_wakeup_event(codec->dev, 300);
+
                schedule_delayed_work(&wm8962->mic_work,
                                      msecs_to_jiffies(250));
        }
@@ -3433,6 +3440,7 @@ static void wm8962_beep_work(struct work_struct *work)
        struct wm8962_priv *wm8962 =
                container_of(work, struct wm8962_priv, beep_work);
        struct snd_soc_codec *codec = wm8962->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int i;
        int reg = 0;
        int best = 0;
@@ -3449,16 +3457,16 @@ static void wm8962_beep_work(struct work_struct *work)
 
                reg = WM8962_BEEP_ENA | (best << WM8962_BEEP_RATE_SHIFT);
 
-               snd_soc_dapm_enable_pin(codec, "Beep");
+               snd_soc_dapm_enable_pin(dapm, "Beep");
        } else {
                dev_dbg(codec->dev, "Disabling beep\n");
-               snd_soc_dapm_disable_pin(codec, "Beep");
+               snd_soc_dapm_disable_pin(dapm, "Beep");
        }
 
        snd_soc_update_bits(codec, WM8962_BEEP_GENERATOR_1,
                            WM8962_BEEP_ENA | WM8962_BEEP_RATE_MASK, reg);
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
 }
 
 /* For usability define a way of injecting beep events for the device -
@@ -3706,7 +3714,7 @@ static int wm8962_probe(struct snd_soc_codec *codec)
        INIT_DELAYED_WORK(&wm8962->mic_work, wm8962_mic_work);
 
        codec->cache_sync = 1;
-       codec->idle_bias_off = 1;
+       codec->dapm.idle_bias_off = 1;
 
        ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
        if (ret != 0) {
@@ -3865,7 +3873,6 @@ err_enable:
 err_get:
        regulator_bulk_free(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
 err:
-       kfree(wm8962);
        return ret;
 }
 
index 9f18db6..572bb80 100644 (file)
@@ -25,7 +25,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/initval.h>
 
 #include "wm8971.h"
@@ -333,10 +332,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int wm8971_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, wm8971_dapm_widgets,
-                                 ARRAY_SIZE(wm8971_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_new_controls(dapm, wm8971_dapm_widgets,
+                                 ARRAY_SIZE(wm8971_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
 }
@@ -553,7 +553,7 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_write(codec, WM8971_PWR1, 0x0001);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -590,9 +590,11 @@ static struct snd_soc_dai_driver wm8971_dai = {
 
 static void wm8971_work(struct work_struct *work)
 {
-       struct snd_soc_codec *codec =
-               container_of(work, struct snd_soc_codec, delayed_work.work);
-       wm8971_set_bias_level(codec, codec->bias_level);
+       struct snd_soc_dapm_context *dapm =
+               container_of(work, struct snd_soc_dapm_context,
+                            delayed_work.work);
+       struct snd_soc_codec *codec = dapm->codec;
+       wm8971_set_bias_level(codec, codec->dapm.bias_level);
 }
 
 static int wm8971_suspend(struct snd_soc_codec *codec, pm_message_t state)
@@ -620,11 +622,11 @@ static int wm8971_resume(struct snd_soc_codec *codec)
        wm8971_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* charge wm8971 caps */
-       if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {
+       if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) {
                reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
                snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0);
-               codec->bias_level = SND_SOC_BIAS_ON;
-               queue_delayed_work(wm8971_workq, &codec->delayed_work,
+               codec->dapm.bias_level = SND_SOC_BIAS_ON;
+               queue_delayed_work(wm8971_workq, &codec->dapm.delayed_work,
                        msecs_to_jiffies(1000));
        }
 
@@ -643,7 +645,7 @@ static int wm8971_probe(struct snd_soc_codec *codec)
                return ret;
        }
 
-       INIT_DELAYED_WORK(&codec->delayed_work, wm8971_work);
+       INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8971_work);
        wm8971_workq = create_workqueue("wm8971");
        if (wm8971_workq == NULL)
                return -ENOMEM;
@@ -653,8 +655,8 @@ static int wm8971_probe(struct snd_soc_codec *codec)
        /* charge output caps - set vmid to 5k for quick power up */
        reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
        snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0);
-       codec->bias_level = SND_SOC_BIAS_STANDBY;
-       queue_delayed_work(wm8971_workq, &codec->delayed_work,
+       codec->dapm.bias_level = SND_SOC_BIAS_STANDBY;
+       queue_delayed_work(wm8971_workq, &codec->dapm.delayed_work,
                msecs_to_jiffies(1000));
 
        /* set the update bits */
index b4363f6..ca646a8 100644 (file)
@@ -23,7 +23,6 @@
 #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>
 
@@ -52,7 +51,6 @@ static const u16 wm8974_reg[WM8974_CACHEREGNUM] = {
 
 struct wm8974_priv {
        enum snd_soc_control_type control_type;
-       u16 reg_cache[WM8974_CACHEREGNUM];
 };
 
 #define wm8974_reset(c)        snd_soc_write(c, WM8974_RESET, 0)
@@ -274,10 +272,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int wm8974_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, wm8974_dapm_widgets,
-                                 ARRAY_SIZE(wm8974_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_new_controls(dapm, wm8974_dapm_widgets,
+                                 ARRAY_SIZE(wm8974_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
 }
@@ -530,7 +529,7 @@ static int wm8974_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_STANDBY:
                power1 |= WM8974_POWER1_BIASEN | WM8974_POWER1_BUFIOEN;
 
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        /* Initial cap charge at VMID 5k */
                        snd_soc_write(codec, WM8974_POWER1, power1 | 0x3);
                        mdelay(100);
@@ -547,7 +546,7 @@ static int wm8974_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index 13b979a..4bbc344 100644 (file)
@@ -24,7 +24,6 @@
 #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 <asm/div64.h>
@@ -60,7 +59,6 @@ struct wm8978_priv {
        unsigned int f_opclk;
        int mclk_idx;
        enum wm8978_sysclk_src sysclk;
-       u16 reg_cache[WM8978_CACHEREGNUM];
 };
 
 static const char *wm8978_companding[] = {"Off", "NC", "u-law", "A-law"};
@@ -355,11 +353,12 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int wm8978_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, wm8978_dapm_widgets,
-                                 ARRAY_SIZE(wm8978_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
+       snd_soc_dapm_new_controls(dapm, wm8978_dapm_widgets,
+                                 ARRAY_SIZE(wm8978_dapm_widgets));
        /* set up the WM8978 audio map */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
 }
@@ -837,7 +836,7 @@ static int wm8978_set_bias_level(struct snd_soc_codec *codec,
                /* bit 3: enable bias, bit 2: enable I/O tie off buffer */
                power1 |= 0xc;
 
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        /* Initial cap charge at VMID 5k */
                        snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1,
                                      power1 | 0x3);
@@ -857,7 +856,7 @@ static int wm8978_set_bias_level(struct snd_soc_codec *codec,
 
        dev_dbg(codec->dev, "%s: %d, %x\n", __func__, level, power1);
 
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index fd2e7cc..bae510a 100644 (file)
@@ -26,7 +26,6 @@
 #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>
 
@@ -533,10 +532,11 @@ static int eqmode_put(struct snd_kcontrol *kcontrol,
 
 static int wm8985_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, wm8985_dapm_widgets,
-                                 ARRAY_SIZE(wm8985_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, audio_map,
+       snd_soc_dapm_new_controls(dapm, wm8985_dapm_widgets,
+                                 ARRAY_SIZE(wm8985_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, audio_map,
                                ARRAY_SIZE(audio_map));
        return 0;
 }
@@ -879,7 +879,7 @@ static int wm8985_set_bias_level(struct snd_soc_codec *codec,
                                    1 << WM8985_VMIDSEL_SHIFT);
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(wm8985->supplies),
                                                    wm8985->supplies);
                        if (ret) {
@@ -939,7 +939,7 @@ static int wm8985_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index d7f2597..d7170f1 100644 (file)
@@ -25,7 +25,6 @@
 #include <sound/pcm_params.h>
 #include <sound/tlv.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/initval.h>
 
 #include "wm8988.h"
@@ -54,7 +53,6 @@ struct wm8988_priv {
        unsigned int sysclk;
        enum snd_soc_control_type control_type;
        struct snd_pcm_hw_constraint_list *sysclk_constraints;
-       u16 reg_cache[WM8988_NUM_REG];
 };
 
 
@@ -677,7 +675,7 @@ static int wm8988_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        /* VREF, VMID=2x5k */
                        snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x1c1);
 
@@ -693,7 +691,7 @@ static int wm8988_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_write(codec, WM8988_PWR1, 0x0000);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
@@ -759,6 +757,7 @@ static int wm8988_resume(struct snd_soc_codec *codec)
 static int wm8988_probe(struct snd_soc_codec *codec)
 {
        struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret = 0;
        u16 reg;
 
@@ -790,9 +789,9 @@ static int wm8988_probe(struct snd_soc_codec *codec)
 
        snd_soc_add_controls(codec, wm8988_snd_controls,
                                ARRAY_SIZE(wm8988_snd_controls));
-       snd_soc_dapm_new_controls(codec, wm8988_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, wm8988_dapm_widgets,
                                  ARRAY_SIZE(wm8988_dapm_widgets));
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
 }
index 264828e..5c87a63 100644 (file)
@@ -23,7 +23,6 @@
 #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 <asm/div64.h>
@@ -914,11 +913,12 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int wm8990_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, wm8990_dapm_widgets,
-                                 ARRAY_SIZE(wm8990_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
+       snd_soc_dapm_new_controls(dapm, wm8990_dapm_widgets,
+                                 ARRAY_SIZE(wm8990_dapm_widgets));
        /* set up the WM8990 audio map */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
 }
@@ -1170,7 +1170,7 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        /* Enable all output discharge bits */
                        snd_soc_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE |
                                WM8990_DIS_RLINE | WM8990_DIS_OUT3 |
@@ -1266,7 +1266,7 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index 589e3fa..18c0d9c 100644 (file)
@@ -24,7 +24,6 @@
 #include <sound/pcm_params.h>
 #include <sound/tlv.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/initval.h>
 #include <sound/wm8993.h>
 
@@ -226,7 +225,6 @@ static struct {
 
 struct wm8993_priv {
        struct wm_hubs_data hubs_data;
-       u16 reg_cache[WM8993_REGISTER_COUNT];
        struct regulator_bulk_data supplies[WM8993_NUM_SUPPLIES];
        struct wm8993_platform_data pdata;
        enum snd_soc_control_type control_type;
@@ -735,6 +733,7 @@ static int class_w_put(struct snd_kcontrol *kcontrol,
                                            0);
                }
                wm8993->class_w_users++;
+               wm8993->hubs_data.class_w = true;
        }
 
        /* Implement the change */
@@ -751,6 +750,7 @@ static int class_w_put(struct snd_kcontrol *kcontrol,
                                            WM8993_CP_DYN_V);
                }
                wm8993->class_w_users--;
+               wm8993->hubs_data.class_w = false;
        }
 
        dev_dbg(codec->dev, "Indirect DAC use count now %d\n",
@@ -968,7 +968,7 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies),
                                                    wm8993->supplies);
                        if (ret != 0)
@@ -1029,6 +1029,12 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec,
                                    WM8993_VMID_SEL_MASK | WM8993_BIAS_ENA,
                                    0);
 
+               snd_soc_update_bits(codec, WM8993_ANTIPOP2,
+                                   WM8993_STARTUP_BIAS_ENA |
+                                   WM8993_VMID_BUF_ENA |
+                                   WM8993_VMID_RAMP_MASK |
+                                   WM8993_BIAS_SRC, 0);
+
 #ifdef CONFIG_REGULATOR
                /* Post 2.6.34 we will be able to get a callback when
                 * the regulators are disabled which we can use but
@@ -1043,7 +1049,7 @@ static int wm8993_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
 
        return 0;
 }
@@ -1225,7 +1231,7 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream,
                       - wm8993->fs);
        for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) {
                cur_val = abs((wm8993->sysclk_rate /
-                              clk_sys_rates[i].ratio) - wm8993->fs);;
+                              clk_sys_rates[i].ratio) - wm8993->fs);
                if (cur_val < best_val) {
                        best = i;
                        best_val = cur_val;
@@ -1422,6 +1428,7 @@ static struct snd_soc_dai_driver wm8993_dai = {
 static int wm8993_probe(struct snd_soc_codec *codec)
 {
        struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret, i, val;
 
        wm8993->hubs_data.hp_startup_mode = 1;
@@ -1503,11 +1510,11 @@ static int wm8993_probe(struct snd_soc_codec *codec)
                                     ARRAY_SIZE(wm8993_eq_controls));
        }
 
-       snd_soc_dapm_new_controls(codec, wm8993_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, wm8993_dapm_widgets,
                                  ARRAY_SIZE(wm8993_dapm_widgets));
        wm_hubs_add_analogue_controls(codec);
 
-       snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes));
+       snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
        wm_hubs_add_analogue_routes(codec, wm8993->pdata.lineout1_diff,
                                    wm8993->pdata.lineout2_diff);
 
diff --git a/sound/soc/codecs/wm8994-tables.c b/sound/soc/codecs/wm8994-tables.c
new file mode 100644 (file)
index 0000000..68e9b02
--- /dev/null
@@ -0,0 +1,3147 @@
+#include "wm8994.h"
+
+const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE] = {
+       { 0xFFFF, 0xFFFF }, /* R0     - Software Reset */
+       { 0x3B37, 0x3B37 }, /* R1     - Power Management (1) */
+       { 0x6BF0, 0x6BF0 }, /* R2     - Power Management (2) */
+       { 0x3FF0, 0x3FF0 }, /* R3     - Power Management (3) */
+       { 0x3F3F, 0x3F3F }, /* R4     - Power Management (4) */
+       { 0x3F0F, 0x3F0F }, /* R5     - Power Management (5) */
+       { 0x003F, 0x003F }, /* R6     - Power Management (6) */
+       { 0x0000, 0x0000 }, /* R7 */
+       { 0x0000, 0x0000 }, /* R8 */
+       { 0x0000, 0x0000 }, /* R9 */
+       { 0x0000, 0x0000 }, /* R10 */
+       { 0x0000, 0x0000 }, /* R11 */
+       { 0x0000, 0x0000 }, /* R12 */
+       { 0x0000, 0x0000 }, /* R13 */
+       { 0x0000, 0x0000 }, /* R14 */
+       { 0x0000, 0x0000 }, /* R15 */
+       { 0x0000, 0x0000 }, /* R16 */
+       { 0x0000, 0x0000 }, /* R17 */
+       { 0x0000, 0x0000 }, /* R18 */
+       { 0x0000, 0x0000 }, /* R19 */
+       { 0x0000, 0x0000 }, /* R20 */
+       { 0x01C0, 0x01C0 }, /* R21    - Input Mixer (1) */
+       { 0x0000, 0x0000 }, /* R22 */
+       { 0x0000, 0x0000 }, /* R23 */
+       { 0x00DF, 0x01DF }, /* R24    - Left Line Input 1&2 Volume */
+       { 0x00DF, 0x01DF }, /* R25    - Left Line Input 3&4 Volume */
+       { 0x00DF, 0x01DF }, /* R26    - Right Line Input 1&2 Volume */
+       { 0x00DF, 0x01DF }, /* R27    - Right Line Input 3&4 Volume */
+       { 0x00FF, 0x01FF }, /* R28    - Left Output Volume */
+       { 0x00FF, 0x01FF }, /* R29    - Right Output Volume */
+       { 0x0077, 0x0077 }, /* R30    - Line Outputs Volume */
+       { 0x0030, 0x0030 }, /* R31    - HPOUT2 Volume */
+       { 0x00FF, 0x01FF }, /* R32    - Left OPGA Volume */
+       { 0x00FF, 0x01FF }, /* R33    - Right OPGA Volume */
+       { 0x007F, 0x007F }, /* R34    - SPKMIXL Attenuation */
+       { 0x017F, 0x017F }, /* R35    - SPKMIXR Attenuation */
+       { 0x003F, 0x003F }, /* R36    - SPKOUT Mixers */
+       { 0x003F, 0x003F }, /* R37    - ClassD */
+       { 0x00FF, 0x01FF }, /* R38    - Speaker Volume Left */
+       { 0x00FF, 0x01FF }, /* R39    - Speaker Volume Right */
+       { 0x00FF, 0x00FF }, /* R40    - Input Mixer (2) */
+       { 0x01B7, 0x01B7 }, /* R41    - Input Mixer (3) */
+       { 0x01B7, 0x01B7 }, /* R42    - Input Mixer (4) */
+       { 0x01C7, 0x01C7 }, /* R43    - Input Mixer (5) */
+       { 0x01C7, 0x01C7 }, /* R44    - Input Mixer (6) */
+       { 0x01FF, 0x01FF }, /* R45    - Output Mixer (1) */
+       { 0x01FF, 0x01FF }, /* R46    - Output Mixer (2) */
+       { 0x0FFF, 0x0FFF }, /* R47    - Output Mixer (3) */
+       { 0x0FFF, 0x0FFF }, /* R48    - Output Mixer (4) */
+       { 0x0FFF, 0x0FFF }, /* R49    - Output Mixer (5) */
+       { 0x0FFF, 0x0FFF }, /* R50    - Output Mixer (6) */
+       { 0x0038, 0x0038 }, /* R51    - HPOUT2 Mixer */
+       { 0x0077, 0x0077 }, /* R52    - Line Mixer (1) */
+       { 0x0077, 0x0077 }, /* R53    - Line Mixer (2) */
+       { 0x03FF, 0x03FF }, /* R54    - Speaker Mixer */
+       { 0x00C1, 0x00C1 }, /* R55    - Additional Control */
+       { 0x00F0, 0x00F0 }, /* R56    - AntiPOP (1) */
+       { 0x01EF, 0x01EF }, /* R57    - AntiPOP (2) */
+       { 0x00FF, 0x00FF }, /* R58    - MICBIAS */
+       { 0x000F, 0x000F }, /* R59    - LDO 1 */
+       { 0x0007, 0x0007 }, /* R60    - LDO 2 */
+       { 0x0000, 0x0000 }, /* R61 */
+       { 0x0000, 0x0000 }, /* R62 */
+       { 0x0000, 0x0000 }, /* R63 */
+       { 0x0000, 0x0000 }, /* R64 */
+       { 0x0000, 0x0000 }, /* R65 */
+       { 0x0000, 0x0000 }, /* R66 */
+       { 0x0000, 0x0000 }, /* R67 */
+       { 0x0000, 0x0000 }, /* R68 */
+       { 0x0000, 0x0000 }, /* R69 */
+       { 0x0000, 0x0000 }, /* R70 */
+       { 0x0000, 0x0000 }, /* R71 */
+       { 0x0000, 0x0000 }, /* R72 */
+       { 0x0000, 0x0000 }, /* R73 */
+       { 0x0000, 0x0000 }, /* R74 */
+       { 0x0000, 0x0000 }, /* R75 */
+       { 0x8000, 0x8000 }, /* R76    - Charge Pump (1) */
+       { 0x0000, 0x0000 }, /* R77 */
+       { 0x0000, 0x0000 }, /* R78 */
+       { 0x0000, 0x0000 }, /* R79 */
+       { 0x0000, 0x0000 }, /* R80 */
+       { 0x0301, 0x0301 }, /* R81    - Class W (1) */
+       { 0x0000, 0x0000 }, /* R82 */
+       { 0x0000, 0x0000 }, /* R83 */
+       { 0x333F, 0x333F }, /* R84    - DC Servo (1) */
+       { 0x0FEF, 0x0FEF }, /* R85    - DC Servo (2) */
+       { 0x0000, 0x0000 }, /* R86 */
+       { 0xFFFF, 0xFFFF }, /* R87    - DC Servo (4) */
+       { 0x0333, 0x0000 }, /* R88    - DC Servo Readback */
+       { 0x0000, 0x0000 }, /* R89 */
+       { 0x0000, 0x0000 }, /* R90 */
+       { 0x0000, 0x0000 }, /* R91 */
+       { 0x0000, 0x0000 }, /* R92 */
+       { 0x0000, 0x0000 }, /* R93 */
+       { 0x0000, 0x0000 }, /* R94 */
+       { 0x0000, 0x0000 }, /* R95 */
+       { 0x00EE, 0x00EE }, /* R96    - Analogue HP (1) */
+       { 0x0000, 0x0000 }, /* R97 */
+       { 0x0000, 0x0000 }, /* R98 */
+       { 0x0000, 0x0000 }, /* R99 */
+       { 0x0000, 0x0000 }, /* R100 */
+       { 0x0000, 0x0000 }, /* R101 */
+       { 0x0000, 0x0000 }, /* R102 */
+       { 0x0000, 0x0000 }, /* R103 */
+       { 0x0000, 0x0000 }, /* R104 */
+       { 0x0000, 0x0000 }, /* R105 */
+       { 0x0000, 0x0000 }, /* R106 */
+       { 0x0000, 0x0000 }, /* R107 */
+       { 0x0000, 0x0000 }, /* R108 */
+       { 0x0000, 0x0000 }, /* R109 */
+       { 0x0000, 0x0000 }, /* R110 */
+       { 0x0000, 0x0000 }, /* R111 */
+       { 0x0000, 0x0000 }, /* R112 */
+       { 0x0000, 0x0000 }, /* R113 */
+       { 0x0000, 0x0000 }, /* R114 */
+       { 0x0000, 0x0000 }, /* R115 */
+       { 0x0000, 0x0000 }, /* R116 */
+       { 0x0000, 0x0000 }, /* R117 */
+       { 0x0000, 0x0000 }, /* R118 */
+       { 0x0000, 0x0000 }, /* R119 */
+       { 0x0000, 0x0000 }, /* R120 */
+       { 0x0000, 0x0000 }, /* R121 */
+       { 0x0000, 0x0000 }, /* R122 */
+       { 0x0000, 0x0000 }, /* R123 */
+       { 0x0000, 0x0000 }, /* R124 */
+       { 0x0000, 0x0000 }, /* R125 */
+       { 0x0000, 0x0000 }, /* R126 */
+       { 0x0000, 0x0000 }, /* R127 */
+       { 0x0000, 0x0000 }, /* R128 */
+       { 0x0000, 0x0000 }, /* R129 */
+       { 0x0000, 0x0000 }, /* R130 */
+       { 0x0000, 0x0000 }, /* R131 */
+       { 0x0000, 0x0000 }, /* R132 */
+       { 0x0000, 0x0000 }, /* R133 */
+       { 0x0000, 0x0000 }, /* R134 */
+       { 0x0000, 0x0000 }, /* R135 */
+       { 0x0000, 0x0000 }, /* R136 */
+       { 0x0000, 0x0000 }, /* R137 */
+       { 0x0000, 0x0000 }, /* R138 */
+       { 0x0000, 0x0000 }, /* R139 */
+       { 0x0000, 0x0000 }, /* R140 */
+       { 0x0000, 0x0000 }, /* R141 */
+       { 0x0000, 0x0000 }, /* R142 */
+       { 0x0000, 0x0000 }, /* R143 */
+       { 0x0000, 0x0000 }, /* R144 */
+       { 0x0000, 0x0000 }, /* R145 */
+       { 0x0000, 0x0000 }, /* R146 */
+       { 0x0000, 0x0000 }, /* R147 */
+       { 0x0000, 0x0000 }, /* R148 */
+       { 0x0000, 0x0000 }, /* R149 */
+       { 0x0000, 0x0000 }, /* R150 */
+       { 0x0000, 0x0000 }, /* R151 */
+       { 0x0000, 0x0000 }, /* R152 */
+       { 0x0000, 0x0000 }, /* R153 */
+       { 0x0000, 0x0000 }, /* R154 */
+       { 0x0000, 0x0000 }, /* R155 */
+       { 0x0000, 0x0000 }, /* R156 */
+       { 0x0000, 0x0000 }, /* R157 */
+       { 0x0000, 0x0000 }, /* R158 */
+       { 0x0000, 0x0000 }, /* R159 */
+       { 0x0000, 0x0000 }, /* R160 */
+       { 0x0000, 0x0000 }, /* R161 */
+       { 0x0000, 0x0000 }, /* R162 */
+       { 0x0000, 0x0000 }, /* R163 */
+       { 0x0000, 0x0000 }, /* R164 */
+       { 0x0000, 0x0000 }, /* R165 */
+       { 0x0000, 0x0000 }, /* R166 */
+       { 0x0000, 0x0000 }, /* R167 */
+       { 0x0000, 0x0000 }, /* R168 */
+       { 0x0000, 0x0000 }, /* R169 */
+       { 0x0000, 0x0000 }, /* R170 */
+       { 0x0000, 0x0000 }, /* R171 */
+       { 0x0000, 0x0000 }, /* R172 */
+       { 0x0000, 0x0000 }, /* R173 */
+       { 0x0000, 0x0000 }, /* R174 */
+       { 0x0000, 0x0000 }, /* R175 */
+       { 0x0000, 0x0000 }, /* R176 */
+       { 0x0000, 0x0000 }, /* R177 */
+       { 0x0000, 0x0000 }, /* R178 */
+       { 0x0000, 0x0000 }, /* R179 */
+       { 0x0000, 0x0000 }, /* R180 */
+       { 0x0000, 0x0000 }, /* R181 */
+       { 0x0000, 0x0000 }, /* R182 */
+       { 0x0000, 0x0000 }, /* R183 */
+       { 0x0000, 0x0000 }, /* R184 */
+       { 0x0000, 0x0000 }, /* R185 */
+       { 0x0000, 0x0000 }, /* R186 */
+       { 0x0000, 0x0000 }, /* R187 */
+       { 0x0000, 0x0000 }, /* R188 */
+       { 0x0000, 0x0000 }, /* R189 */
+       { 0x0000, 0x0000 }, /* R190 */
+       { 0x0000, 0x0000 }, /* R191 */
+       { 0x0000, 0x0000 }, /* R192 */
+       { 0x0000, 0x0000 }, /* R193 */
+       { 0x0000, 0x0000 }, /* R194 */
+       { 0x0000, 0x0000 }, /* R195 */
+       { 0x0000, 0x0000 }, /* R196 */
+       { 0x0000, 0x0000 }, /* R197 */
+       { 0x0000, 0x0000 }, /* R198 */
+       { 0x0000, 0x0000 }, /* R199 */
+       { 0x0000, 0x0000 }, /* R200 */
+       { 0x0000, 0x0000 }, /* R201 */
+       { 0x0000, 0x0000 }, /* R202 */
+       { 0x0000, 0x0000 }, /* R203 */
+       { 0x0000, 0x0000 }, /* R204 */
+       { 0x0000, 0x0000 }, /* R205 */
+       { 0x0000, 0x0000 }, /* R206 */
+       { 0x0000, 0x0000 }, /* R207 */
+       { 0x0000, 0x0000 }, /* R208 */
+       { 0x0000, 0x0000 }, /* R209 */
+       { 0x0000, 0x0000 }, /* R210 */
+       { 0x0000, 0x0000 }, /* R211 */
+       { 0x0000, 0x0000 }, /* R212 */
+       { 0x0000, 0x0000 }, /* R213 */
+       { 0x0000, 0x0000 }, /* R214 */
+       { 0x0000, 0x0000 }, /* R215 */
+       { 0x0000, 0x0000 }, /* R216 */
+       { 0x0000, 0x0000 }, /* R217 */
+       { 0x0000, 0x0000 }, /* R218 */
+       { 0x0000, 0x0000 }, /* R219 */
+       { 0x0000, 0x0000 }, /* R220 */
+       { 0x0000, 0x0000 }, /* R221 */
+       { 0x0000, 0x0000 }, /* R222 */
+       { 0x0000, 0x0000 }, /* R223 */
+       { 0x0000, 0x0000 }, /* R224 */
+       { 0x0000, 0x0000 }, /* R225 */
+       { 0x0000, 0x0000 }, /* R226 */
+       { 0x0000, 0x0000 }, /* R227 */
+       { 0x0000, 0x0000 }, /* R228 */
+       { 0x0000, 0x0000 }, /* R229 */
+       { 0x0000, 0x0000 }, /* R230 */
+       { 0x0000, 0x0000 }, /* R231 */
+       { 0x0000, 0x0000 }, /* R232 */
+       { 0x0000, 0x0000 }, /* R233 */
+       { 0x0000, 0x0000 }, /* R234 */
+       { 0x0000, 0x0000 }, /* R235 */
+       { 0x0000, 0x0000 }, /* R236 */
+       { 0x0000, 0x0000 }, /* R237 */
+       { 0x0000, 0x0000 }, /* R238 */
+       { 0x0000, 0x0000 }, /* R239 */
+       { 0x0000, 0x0000 }, /* R240 */
+       { 0x0000, 0x0000 }, /* R241 */
+       { 0x0000, 0x0000 }, /* R242 */
+       { 0x0000, 0x0000 }, /* R243 */
+       { 0x0000, 0x0000 }, /* R244 */
+       { 0x0000, 0x0000 }, /* R245 */
+       { 0x0000, 0x0000 }, /* R246 */
+       { 0x0000, 0x0000 }, /* R247 */
+       { 0x0000, 0x0000 }, /* R248 */
+       { 0x0000, 0x0000 }, /* R249 */
+       { 0x0000, 0x0000 }, /* R250 */
+       { 0x0000, 0x0000 }, /* R251 */
+       { 0x0000, 0x0000 }, /* R252 */
+       { 0x0000, 0x0000 }, /* R253 */
+       { 0x0000, 0x0000 }, /* R254 */
+       { 0x0000, 0x0000 }, /* R255 */
+       { 0x000F, 0x0000 }, /* R256   - Chip Revision */
+       { 0x0074, 0x0074 }, /* R257   - Control Interface */
+       { 0x0000, 0x0000 }, /* R258 */
+       { 0x0000, 0x0000 }, /* R259 */
+       { 0x0000, 0x0000 }, /* R260 */
+       { 0x0000, 0x0000 }, /* R261 */
+       { 0x0000, 0x0000 }, /* R262 */
+       { 0x0000, 0x0000 }, /* R263 */
+       { 0x0000, 0x0000 }, /* R264 */
+       { 0x0000, 0x0000 }, /* R265 */
+       { 0x0000, 0x0000 }, /* R266 */
+       { 0x0000, 0x0000 }, /* R267 */
+       { 0x0000, 0x0000 }, /* R268 */
+       { 0x0000, 0x0000 }, /* R269 */
+       { 0x0000, 0x0000 }, /* R270 */
+       { 0x0000, 0x0000 }, /* R271 */
+       { 0x807F, 0x837F }, /* R272   - Write Sequencer Ctrl (1) */
+       { 0x017F, 0x0000 }, /* R273   - Write Sequencer Ctrl (2) */
+       { 0x0000, 0x0000 }, /* R274 */
+       { 0x0000, 0x0000 }, /* R275 */
+       { 0x0000, 0x0000 }, /* R276 */
+       { 0x0000, 0x0000 }, /* R277 */
+       { 0x0000, 0x0000 }, /* R278 */
+       { 0x0000, 0x0000 }, /* R279 */
+       { 0x0000, 0x0000 }, /* R280 */
+       { 0x0000, 0x0000 }, /* R281 */
+       { 0x0000, 0x0000 }, /* R282 */
+       { 0x0000, 0x0000 }, /* R283 */
+       { 0x0000, 0x0000 }, /* R284 */
+       { 0x0000, 0x0000 }, /* R285 */
+       { 0x0000, 0x0000 }, /* R286 */
+       { 0x0000, 0x0000 }, /* R287 */
+       { 0x0000, 0x0000 }, /* R288 */
+       { 0x0000, 0x0000 }, /* R289 */
+       { 0x0000, 0x0000 }, /* R290 */
+       { 0x0000, 0x0000 }, /* R291 */
+       { 0x0000, 0x0000 }, /* R292 */
+       { 0x0000, 0x0000 }, /* R293 */
+       { 0x0000, 0x0000 }, /* R294 */
+       { 0x0000, 0x0000 }, /* R295 */
+       { 0x0000, 0x0000 }, /* R296 */
+       { 0x0000, 0x0000 }, /* R297 */
+       { 0x0000, 0x0000 }, /* R298 */
+       { 0x0000, 0x0000 }, /* R299 */
+       { 0x0000, 0x0000 }, /* R300 */
+       { 0x0000, 0x0000 }, /* R301 */
+       { 0x0000, 0x0000 }, /* R302 */
+       { 0x0000, 0x0000 }, /* R303 */
+       { 0x0000, 0x0000 }, /* R304 */
+       { 0x0000, 0x0000 }, /* R305 */
+       { 0x0000, 0x0000 }, /* R306 */
+       { 0x0000, 0x0000 }, /* R307 */
+       { 0x0000, 0x0000 }, /* R308 */
+       { 0x0000, 0x0000 }, /* R309 */
+       { 0x0000, 0x0000 }, /* R310 */
+       { 0x0000, 0x0000 }, /* R311 */
+       { 0x0000, 0x0000 }, /* R312 */
+       { 0x0000, 0x0000 }, /* R313 */
+       { 0x0000, 0x0000 }, /* R314 */
+       { 0x0000, 0x0000 }, /* R315 */
+       { 0x0000, 0x0000 }, /* R316 */
+       { 0x0000, 0x0000 }, /* R317 */
+       { 0x0000, 0x0000 }, /* R318 */
+       { 0x0000, 0x0000 }, /* R319 */
+       { 0x0000, 0x0000 }, /* R320 */
+       { 0x0000, 0x0000 }, /* R321 */
+       { 0x0000, 0x0000 }, /* R322 */
+       { 0x0000, 0x0000 }, /* R323 */
+       { 0x0000, 0x0000 }, /* R324 */
+       { 0x0000, 0x0000 }, /* R325 */
+       { 0x0000, 0x0000 }, /* R326 */
+       { 0x0000, 0x0000 }, /* R327 */
+       { 0x0000, 0x0000 }, /* R328 */
+       { 0x0000, 0x0000 }, /* R329 */
+       { 0x0000, 0x0000 }, /* R330 */
+       { 0x0000, 0x0000 }, /* R331 */
+       { 0x0000, 0x0000 }, /* R332 */
+       { 0x0000, 0x0000 }, /* R333 */
+       { 0x0000, 0x0000 }, /* R334 */
+       { 0x0000, 0x0000 }, /* R335 */
+       { 0x0000, 0x0000 }, /* R336 */
+       { 0x0000, 0x0000 }, /* R337 */
+       { 0x0000, 0x0000 }, /* R338 */
+       { 0x0000, 0x0000 }, /* R339 */
+       { 0x0000, 0x0000 }, /* R340 */
+       { 0x0000, 0x0000 }, /* R341 */
+       { 0x0000, 0x0000 }, /* R342 */
+       { 0x0000, 0x0000 }, /* R343 */
+       { 0x0000, 0x0000 }, /* R344 */
+       { 0x0000, 0x0000 }, /* R345 */
+       { 0x0000, 0x0000 }, /* R346 */
+       { 0x0000, 0x0000 }, /* R347 */
+       { 0x0000, 0x0000 }, /* R348 */
+       { 0x0000, 0x0000 }, /* R349 */
+       { 0x0000, 0x0000 }, /* R350 */
+       { 0x0000, 0x0000 }, /* R351 */
+       { 0x0000, 0x0000 }, /* R352 */
+       { 0x0000, 0x0000 }, /* R353 */
+       { 0x0000, 0x0000 }, /* R354 */
+       { 0x0000, 0x0000 }, /* R355 */
+       { 0x0000, 0x0000 }, /* R356 */
+       { 0x0000, 0x0000 }, /* R357 */
+       { 0x0000, 0x0000 }, /* R358 */
+       { 0x0000, 0x0000 }, /* R359 */
+       { 0x0000, 0x0000 }, /* R360 */
+       { 0x0000, 0x0000 }, /* R361 */
+       { 0x0000, 0x0000 }, /* R362 */
+       { 0x0000, 0x0000 }, /* R363 */
+       { 0x0000, 0x0000 }, /* R364 */
+       { 0x0000, 0x0000 }, /* R365 */
+       { 0x0000, 0x0000 }, /* R366 */
+       { 0x0000, 0x0000 }, /* R367 */
+       { 0x0000, 0x0000 }, /* R368 */
+       { 0x0000, 0x0000 }, /* R369 */
+       { 0x0000, 0x0000 }, /* R370 */
+       { 0x0000, 0x0000 }, /* R371 */
+       { 0x0000, 0x0000 }, /* R372 */
+       { 0x0000, 0x0000 }, /* R373 */
+       { 0x0000, 0x0000 }, /* R374 */
+       { 0x0000, 0x0000 }, /* R375 */
+       { 0x0000, 0x0000 }, /* R376 */
+       { 0x0000, 0x0000 }, /* R377 */
+       { 0x0000, 0x0000 }, /* R378 */
+       { 0x0000, 0x0000 }, /* R379 */
+       { 0x0000, 0x0000 }, /* R380 */
+       { 0x0000, 0x0000 }, /* R381 */
+       { 0x0000, 0x0000 }, /* R382 */
+       { 0x0000, 0x0000 }, /* R383 */
+       { 0x0000, 0x0000 }, /* R384 */
+       { 0x0000, 0x0000 }, /* R385 */
+       { 0x0000, 0x0000 }, /* R386 */
+       { 0x0000, 0x0000 }, /* R387 */
+       { 0x0000, 0x0000 }, /* R388 */
+       { 0x0000, 0x0000 }, /* R389 */
+       { 0x0000, 0x0000 }, /* R390 */
+       { 0x0000, 0x0000 }, /* R391 */
+       { 0x0000, 0x0000 }, /* R392 */
+       { 0x0000, 0x0000 }, /* R393 */
+       { 0x0000, 0x0000 }, /* R394 */
+       { 0x0000, 0x0000 }, /* R395 */
+       { 0x0000, 0x0000 }, /* R396 */
+       { 0x0000, 0x0000 }, /* R397 */
+       { 0x0000, 0x0000 }, /* R398 */
+       { 0x0000, 0x0000 }, /* R399 */
+       { 0x0000, 0x0000 }, /* R400 */
+       { 0x0000, 0x0000 }, /* R401 */
+       { 0x0000, 0x0000 }, /* R402 */
+       { 0x0000, 0x0000 }, /* R403 */
+       { 0x0000, 0x0000 }, /* R404 */
+       { 0x0000, 0x0000 }, /* R405 */
+       { 0x0000, 0x0000 }, /* R406 */
+       { 0x0000, 0x0000 }, /* R407 */
+       { 0x0000, 0x0000 }, /* R408 */
+       { 0x0000, 0x0000 }, /* R409 */
+       { 0x0000, 0x0000 }, /* R410 */
+       { 0x0000, 0x0000 }, /* R411 */
+       { 0x0000, 0x0000 }, /* R412 */
+       { 0x0000, 0x0000 }, /* R413 */
+       { 0x0000, 0x0000 }, /* R414 */
+       { 0x0000, 0x0000 }, /* R415 */
+       { 0x0000, 0x0000 }, /* R416 */
+       { 0x0000, 0x0000 }, /* R417 */
+       { 0x0000, 0x0000 }, /* R418 */
+       { 0x0000, 0x0000 }, /* R419 */
+       { 0x0000, 0x0000 }, /* R420 */
+       { 0x0000, 0x0000 }, /* R421 */
+       { 0x0000, 0x0000 }, /* R422 */
+       { 0x0000, 0x0000 }, /* R423 */
+       { 0x0000, 0x0000 }, /* R424 */
+       { 0x0000, 0x0000 }, /* R425 */
+       { 0x0000, 0x0000 }, /* R426 */
+       { 0x0000, 0x0000 }, /* R427 */
+       { 0x0000, 0x0000 }, /* R428 */
+       { 0x0000, 0x0000 }, /* R429 */
+       { 0x0000, 0x0000 }, /* R430 */
+       { 0x0000, 0x0000 }, /* R431 */
+       { 0x0000, 0x0000 }, /* R432 */
+       { 0x0000, 0x0000 }, /* R433 */
+       { 0x0000, 0x0000 }, /* R434 */
+       { 0x0000, 0x0000 }, /* R435 */
+       { 0x0000, 0x0000 }, /* R436 */
+       { 0x0000, 0x0000 }, /* R437 */
+       { 0x0000, 0x0000 }, /* R438 */
+       { 0x0000, 0x0000 }, /* R439 */
+       { 0x0000, 0x0000 }, /* R440 */
+       { 0x0000, 0x0000 }, /* R441 */
+       { 0x0000, 0x0000 }, /* R442 */
+       { 0x0000, 0x0000 }, /* R443 */
+       { 0x0000, 0x0000 }, /* R444 */
+       { 0x0000, 0x0000 }, /* R445 */
+       { 0x0000, 0x0000 }, /* R446 */
+       { 0x0000, 0x0000 }, /* R447 */
+       { 0x0000, 0x0000 }, /* R448 */
+       { 0x0000, 0x0000 }, /* R449 */
+       { 0x0000, 0x0000 }, /* R450 */
+       { 0x0000, 0x0000 }, /* R451 */
+       { 0x0000, 0x0000 }, /* R452 */
+       { 0x0000, 0x0000 }, /* R453 */
+       { 0x0000, 0x0000 }, /* R454 */
+       { 0x0000, 0x0000 }, /* R455 */
+       { 0x0000, 0x0000 }, /* R456 */
+       { 0x0000, 0x0000 }, /* R457 */
+       { 0x0000, 0x0000 }, /* R458 */
+       { 0x0000, 0x0000 }, /* R459 */
+       { 0x0000, 0x0000 }, /* R460 */
+       { 0x0000, 0x0000 }, /* R461 */
+       { 0x0000, 0x0000 }, /* R462 */
+       { 0x0000, 0x0000 }, /* R463 */
+       { 0x0000, 0x0000 }, /* R464 */
+       { 0x0000, 0x0000 }, /* R465 */
+       { 0x0000, 0x0000 }, /* R466 */
+       { 0x0000, 0x0000 }, /* R467 */
+       { 0x0000, 0x0000 }, /* R468 */
+       { 0x0000, 0x0000 }, /* R469 */
+       { 0x0000, 0x0000 }, /* R470 */
+       { 0x0000, 0x0000 }, /* R471 */
+       { 0x0000, 0x0000 }, /* R472 */
+       { 0x0000, 0x0000 }, /* R473 */
+       { 0x0000, 0x0000 }, /* R474 */
+       { 0x0000, 0x0000 }, /* R475 */
+       { 0x0000, 0x0000 }, /* R476 */
+       { 0x0000, 0x0000 }, /* R477 */
+       { 0x0000, 0x0000 }, /* R478 */
+       { 0x0000, 0x0000 }, /* R479 */
+       { 0x0000, 0x0000 }, /* R480 */
+       { 0x0000, 0x0000 }, /* R481 */
+       { 0x0000, 0x0000 }, /* R482 */
+       { 0x0000, 0x0000 }, /* R483 */
+       { 0x0000, 0x0000 }, /* R484 */
+       { 0x0000, 0x0000 }, /* R485 */
+       { 0x0000, 0x0000 }, /* R486 */
+       { 0x0000, 0x0000 }, /* R487 */
+       { 0x0000, 0x0000 }, /* R488 */
+       { 0x0000, 0x0000 }, /* R489 */
+       { 0x0000, 0x0000 }, /* R490 */
+       { 0x0000, 0x0000 }, /* R491 */
+       { 0x0000, 0x0000 }, /* R492 */
+       { 0x0000, 0x0000 }, /* R493 */
+       { 0x0000, 0x0000 }, /* R494 */
+       { 0x0000, 0x0000 }, /* R495 */
+       { 0x0000, 0x0000 }, /* R496 */
+       { 0x0000, 0x0000 }, /* R497 */
+       { 0x0000, 0x0000 }, /* R498 */
+       { 0x0000, 0x0000 }, /* R499 */
+       { 0x0000, 0x0000 }, /* R500 */
+       { 0x0000, 0x0000 }, /* R501 */
+       { 0x0000, 0x0000 }, /* R502 */
+       { 0x0000, 0x0000 }, /* R503 */
+       { 0x0000, 0x0000 }, /* R504 */
+       { 0x0000, 0x0000 }, /* R505 */
+       { 0x0000, 0x0000 }, /* R506 */
+       { 0x0000, 0x0000 }, /* R507 */
+       { 0x0000, 0x0000 }, /* R508 */
+       { 0x0000, 0x0000 }, /* R509 */
+       { 0x0000, 0x0000 }, /* R510 */
+       { 0x0000, 0x0000 }, /* R511 */
+       { 0x001F, 0x001F }, /* R512   - AIF1 Clocking (1) */
+       { 0x003F, 0x003F }, /* R513   - AIF1 Clocking (2) */
+       { 0x0000, 0x0000 }, /* R514 */
+       { 0x0000, 0x0000 }, /* R515 */
+       { 0x001F, 0x001F }, /* R516   - AIF2 Clocking (1) */
+       { 0x003F, 0x003F }, /* R517   - AIF2 Clocking (2) */
+       { 0x0000, 0x0000 }, /* R518 */
+       { 0x0000, 0x0000 }, /* R519 */
+       { 0x001F, 0x001F }, /* R520   - Clocking (1) */
+       { 0x0777, 0x0777 }, /* R521   - Clocking (2) */
+       { 0x0000, 0x0000 }, /* R522 */
+       { 0x0000, 0x0000 }, /* R523 */
+       { 0x0000, 0x0000 }, /* R524 */
+       { 0x0000, 0x0000 }, /* R525 */
+       { 0x0000, 0x0000 }, /* R526 */
+       { 0x0000, 0x0000 }, /* R527 */
+       { 0x00FF, 0x00FF }, /* R528   - AIF1 Rate */
+       { 0x00FF, 0x00FF }, /* R529   - AIF2 Rate */
+       { 0x000F, 0x0000 }, /* R530   - Rate Status */
+       { 0x0000, 0x0000 }, /* R531 */
+       { 0x0000, 0x0000 }, /* R532 */
+       { 0x0000, 0x0000 }, /* R533 */
+       { 0x0000, 0x0000 }, /* R534 */
+       { 0x0000, 0x0000 }, /* R535 */
+       { 0x0000, 0x0000 }, /* R536 */
+       { 0x0000, 0x0000 }, /* R537 */
+       { 0x0000, 0x0000 }, /* R538 */
+       { 0x0000, 0x0000 }, /* R539 */
+       { 0x0000, 0x0000 }, /* R540 */
+       { 0x0000, 0x0000 }, /* R541 */
+       { 0x0000, 0x0000 }, /* R542 */
+       { 0x0000, 0x0000 }, /* R543 */
+       { 0x0007, 0x0007 }, /* R544   - FLL1 Control (1) */
+       { 0x3F77, 0x3F77 }, /* R545   - FLL1 Control (2) */
+       { 0xFFFF, 0xFFFF }, /* R546   - FLL1 Control (3) */
+       { 0x7FEF, 0x7FEF }, /* R547   - FLL1 Control (4) */
+       { 0x1FDB, 0x1FDB }, /* R548   - FLL1 Control (5) */
+       { 0x0000, 0x0000 }, /* R549 */
+       { 0x0000, 0x0000 }, /* R550 */
+       { 0x0000, 0x0000 }, /* R551 */
+       { 0x0000, 0x0000 }, /* R552 */
+       { 0x0000, 0x0000 }, /* R553 */
+       { 0x0000, 0x0000 }, /* R554 */
+       { 0x0000, 0x0000 }, /* R555 */
+       { 0x0000, 0x0000 }, /* R556 */
+       { 0x0000, 0x0000 }, /* R557 */
+       { 0x0000, 0x0000 }, /* R558 */
+       { 0x0000, 0x0000 }, /* R559 */
+       { 0x0000, 0x0000 }, /* R560 */
+       { 0x0000, 0x0000 }, /* R561 */
+       { 0x0000, 0x0000 }, /* R562 */
+       { 0x0000, 0x0000 }, /* R563 */
+       { 0x0000, 0x0000 }, /* R564 */
+       { 0x0000, 0x0000 }, /* R565 */
+       { 0x0000, 0x0000 }, /* R566 */
+       { 0x0000, 0x0000 }, /* R567 */
+       { 0x0000, 0x0000 }, /* R568 */
+       { 0x0000, 0x0000 }, /* R569 */
+       { 0x0000, 0x0000 }, /* R570 */
+       { 0x0000, 0x0000 }, /* R571 */
+       { 0x0000, 0x0000 }, /* R572 */
+       { 0x0000, 0x0000 }, /* R573 */
+       { 0x0000, 0x0000 }, /* R574 */
+       { 0x0000, 0x0000 }, /* R575 */
+       { 0x0007, 0x0007 }, /* R576   - FLL2 Control (1) */
+       { 0x3F77, 0x3F77 }, /* R577   - FLL2 Control (2) */
+       { 0xFFFF, 0xFFFF }, /* R578   - FLL2 Control (3) */
+       { 0x7FEF, 0x7FEF }, /* R579   - FLL2 Control (4) */
+       { 0x1FDB, 0x1FDB }, /* R580   - FLL2 Control (5) */
+       { 0x0000, 0x0000 }, /* R581 */
+       { 0x0000, 0x0000 }, /* R582 */
+       { 0x0000, 0x0000 }, /* R583 */
+       { 0x0000, 0x0000 }, /* R584 */
+       { 0x0000, 0x0000 }, /* R585 */
+       { 0x0000, 0x0000 }, /* R586 */
+       { 0x0000, 0x0000 }, /* R587 */
+       { 0x0000, 0x0000 }, /* R588 */
+       { 0x0000, 0x0000 }, /* R589 */
+       { 0x0000, 0x0000 }, /* R590 */
+       { 0x0000, 0x0000 }, /* R591 */
+       { 0x0000, 0x0000 }, /* R592 */
+       { 0x0000, 0x0000 }, /* R593 */
+       { 0x0000, 0x0000 }, /* R594 */
+       { 0x0000, 0x0000 }, /* R595 */
+       { 0x0000, 0x0000 }, /* R596 */
+       { 0x0000, 0x0000 }, /* R597 */
+       { 0x0000, 0x0000 }, /* R598 */
+       { 0x0000, 0x0000 }, /* R599 */
+       { 0x0000, 0x0000 }, /* R600 */
+       { 0x0000, 0x0000 }, /* R601 */
+       { 0x0000, 0x0000 }, /* R602 */
+       { 0x0000, 0x0000 }, /* R603 */
+       { 0x0000, 0x0000 }, /* R604 */
+       { 0x0000, 0x0000 }, /* R605 */
+       { 0x0000, 0x0000 }, /* R606 */
+       { 0x0000, 0x0000 }, /* R607 */
+       { 0x0000, 0x0000 }, /* R608 */
+       { 0x0000, 0x0000 }, /* R609 */
+       { 0x0000, 0x0000 }, /* R610 */
+       { 0x0000, 0x0000 }, /* R611 */
+       { 0x0000, 0x0000 }, /* R612 */
+       { 0x0000, 0x0000 }, /* R613 */
+       { 0x0000, 0x0000 }, /* R614 */
+       { 0x0000, 0x0000 }, /* R615 */
+       { 0x0000, 0x0000 }, /* R616 */
+       { 0x0000, 0x0000 }, /* R617 */
+       { 0x0000, 0x0000 }, /* R618 */
+       { 0x0000, 0x0000 }, /* R619 */
+       { 0x0000, 0x0000 }, /* R620 */
+       { 0x0000, 0x0000 }, /* R621 */
+       { 0x0000, 0x0000 }, /* R622 */
+       { 0x0000, 0x0000 }, /* R623 */
+       { 0x0000, 0x0000 }, /* R624 */
+       { 0x0000, 0x0000 }, /* R625 */
+       { 0x0000, 0x0000 }, /* R626 */
+       { 0x0000, 0x0000 }, /* R627 */
+       { 0x0000, 0x0000 }, /* R628 */
+       { 0x0000, 0x0000 }, /* R629 */
+       { 0x0000, 0x0000 }, /* R630 */
+       { 0x0000, 0x0000 }, /* R631 */
+       { 0x0000, 0x0000 }, /* R632 */
+       { 0x0000, 0x0000 }, /* R633 */
+       { 0x0000, 0x0000 }, /* R634 */
+       { 0x0000, 0x0000 }, /* R635 */
+       { 0x0000, 0x0000 }, /* R636 */
+       { 0x0000, 0x0000 }, /* R637 */
+       { 0x0000, 0x0000 }, /* R638 */
+       { 0x0000, 0x0000 }, /* R639 */
+       { 0x0000, 0x0000 }, /* R640 */
+       { 0x0000, 0x0000 }, /* R641 */
+       { 0x0000, 0x0000 }, /* R642 */
+       { 0x0000, 0x0000 }, /* R643 */
+       { 0x0000, 0x0000 }, /* R644 */
+       { 0x0000, 0x0000 }, /* R645 */
+       { 0x0000, 0x0000 }, /* R646 */
+       { 0x0000, 0x0000 }, /* R647 */
+       { 0x0000, 0x0000 }, /* R648 */
+       { 0x0000, 0x0000 }, /* R649 */
+       { 0x0000, 0x0000 }, /* R650 */
+       { 0x0000, 0x0000 }, /* R651 */
+       { 0x0000, 0x0000 }, /* R652 */
+       { 0x0000, 0x0000 }, /* R653 */
+       { 0x0000, 0x0000 }, /* R654 */
+       { 0x0000, 0x0000 }, /* R655 */
+       { 0x0000, 0x0000 }, /* R656 */
+       { 0x0000, 0x0000 }, /* R657 */
+       { 0x0000, 0x0000 }, /* R658 */
+       { 0x0000, 0x0000 }, /* R659 */
+       { 0x0000, 0x0000 }, /* R660 */
+       { 0x0000, 0x0000 }, /* R661 */
+       { 0x0000, 0x0000 }, /* R662 */
+       { 0x0000, 0x0000 }, /* R663 */
+       { 0x0000, 0x0000 }, /* R664 */
+       { 0x0000, 0x0000 }, /* R665 */
+       { 0x0000, 0x0000 }, /* R666 */
+       { 0x0000, 0x0000 }, /* R667 */
+       { 0x0000, 0x0000 }, /* R668 */
+       { 0x0000, 0x0000 }, /* R669 */
+       { 0x0000, 0x0000 }, /* R670 */
+       { 0x0000, 0x0000 }, /* R671 */
+       { 0x0000, 0x0000 }, /* R672 */
+       { 0x0000, 0x0000 }, /* R673 */
+       { 0x0000, 0x0000 }, /* R674 */
+       { 0x0000, 0x0000 }, /* R675 */
+       { 0x0000, 0x0000 }, /* R676 */
+       { 0x0000, 0x0000 }, /* R677 */
+       { 0x0000, 0x0000 }, /* R678 */
+       { 0x0000, 0x0000 }, /* R679 */
+       { 0x0000, 0x0000 }, /* R680 */
+       { 0x0000, 0x0000 }, /* R681 */
+       { 0x0000, 0x0000 }, /* R682 */
+       { 0x0000, 0x0000 }, /* R683 */
+       { 0x0000, 0x0000 }, /* R684 */
+       { 0x0000, 0x0000 }, /* R685 */
+       { 0x0000, 0x0000 }, /* R686 */
+       { 0x0000, 0x0000 }, /* R687 */
+       { 0x0000, 0x0000 }, /* R688 */
+       { 0x0000, 0x0000 }, /* R689 */
+       { 0x0000, 0x0000 }, /* R690 */
+       { 0x0000, 0x0000 }, /* R691 */
+       { 0x0000, 0x0000 }, /* R692 */
+       { 0x0000, 0x0000 }, /* R693 */
+       { 0x0000, 0x0000 }, /* R694 */
+       { 0x0000, 0x0000 }, /* R695 */
+       { 0x0000, 0x0000 }, /* R696 */
+       { 0x0000, 0x0000 }, /* R697 */
+       { 0x0000, 0x0000 }, /* R698 */
+       { 0x0000, 0x0000 }, /* R699 */
+       { 0x0000, 0x0000 }, /* R700 */
+       { 0x0000, 0x0000 }, /* R701 */
+       { 0x0000, 0x0000 }, /* R702 */
+       { 0x0000, 0x0000 }, /* R703 */
+       { 0x0000, 0x0000 }, /* R704 */
+       { 0x0000, 0x0000 }, /* R705 */
+       { 0x0000, 0x0000 }, /* R706 */
+       { 0x0000, 0x0000 }, /* R707 */
+       { 0x0000, 0x0000 }, /* R708 */
+       { 0x0000, 0x0000 }, /* R709 */
+       { 0x0000, 0x0000 }, /* R710 */
+       { 0x0000, 0x0000 }, /* R711 */
+       { 0x0000, 0x0000 }, /* R712 */
+       { 0x0000, 0x0000 }, /* R713 */
+       { 0x0000, 0x0000 }, /* R714 */
+       { 0x0000, 0x0000 }, /* R715 */
+       { 0x0000, 0x0000 }, /* R716 */
+       { 0x0000, 0x0000 }, /* R717 */
+       { 0x0000, 0x0000 }, /* R718 */
+       { 0x0000, 0x0000 }, /* R719 */
+       { 0x0000, 0x0000 }, /* R720 */
+       { 0x0000, 0x0000 }, /* R721 */
+       { 0x0000, 0x0000 }, /* R722 */
+       { 0x0000, 0x0000 }, /* R723 */
+       { 0x0000, 0x0000 }, /* R724 */
+       { 0x0000, 0x0000 }, /* R725 */
+       { 0x0000, 0x0000 }, /* R726 */
+       { 0x0000, 0x0000 }, /* R727 */
+       { 0x0000, 0x0000 }, /* R728 */
+       { 0x0000, 0x0000 }, /* R729 */
+       { 0x0000, 0x0000 }, /* R730 */
+       { 0x0000, 0x0000 }, /* R731 */
+       { 0x0000, 0x0000 }, /* R732 */
+       { 0x0000, 0x0000 }, /* R733 */
+       { 0x0000, 0x0000 }, /* R734 */
+       { 0x0000, 0x0000 }, /* R735 */
+       { 0x0000, 0x0000 }, /* R736 */
+       { 0x0000, 0x0000 }, /* R737 */
+       { 0x0000, 0x0000 }, /* R738 */
+       { 0x0000, 0x0000 }, /* R739 */
+       { 0x0000, 0x0000 }, /* R740 */
+       { 0x0000, 0x0000 }, /* R741 */
+       { 0x0000, 0x0000 }, /* R742 */
+       { 0x0000, 0x0000 }, /* R743 */
+       { 0x0000, 0x0000 }, /* R744 */
+       { 0x0000, 0x0000 }, /* R745 */
+       { 0x0000, 0x0000 }, /* R746 */
+       { 0x0000, 0x0000 }, /* R747 */
+       { 0x0000, 0x0000 }, /* R748 */
+       { 0x0000, 0x0000 }, /* R749 */
+       { 0x0000, 0x0000 }, /* R750 */
+       { 0x0000, 0x0000 }, /* R751 */
+       { 0x0000, 0x0000 }, /* R752 */
+       { 0x0000, 0x0000 }, /* R753 */
+       { 0x0000, 0x0000 }, /* R754 */
+       { 0x0000, 0x0000 }, /* R755 */
+       { 0x0000, 0x0000 }, /* R756 */
+       { 0x0000, 0x0000 }, /* R757 */
+       { 0x0000, 0x0000 }, /* R758 */
+       { 0x0000, 0x0000 }, /* R759 */
+       { 0x0000, 0x0000 }, /* R760 */
+       { 0x0000, 0x0000 }, /* R761 */
+       { 0x0000, 0x0000 }, /* R762 */
+       { 0x0000, 0x0000 }, /* R763 */
+       { 0x0000, 0x0000 }, /* R764 */
+       { 0x0000, 0x0000 }, /* R765 */
+       { 0x0000, 0x0000 }, /* R766 */
+       { 0x0000, 0x0000 }, /* R767 */
+       { 0xE1F8, 0xE1F8 }, /* R768   - AIF1 Control (1) */
+       { 0xCD1F, 0xCD1F }, /* R769   - AIF1 Control (2) */
+       { 0xF000, 0xF000 }, /* R770   - AIF1 Master/Slave */
+       { 0x01F0, 0x01F0 }, /* R771   - AIF1 BCLK */
+       { 0x0FFF, 0x0FFF }, /* R772   - AIF1ADC LRCLK */
+       { 0x0FFF, 0x0FFF }, /* R773   - AIF1DAC LRCLK */
+       { 0x0003, 0x0003 }, /* R774   - AIF1DAC Data */
+       { 0x0003, 0x0003 }, /* R775   - AIF1ADC Data */
+       { 0x0000, 0x0000 }, /* R776 */
+       { 0x0000, 0x0000 }, /* R777 */
+       { 0x0000, 0x0000 }, /* R778 */
+       { 0x0000, 0x0000 }, /* R779 */
+       { 0x0000, 0x0000 }, /* R780 */
+       { 0x0000, 0x0000 }, /* R781 */
+       { 0x0000, 0x0000 }, /* R782 */
+       { 0x0000, 0x0000 }, /* R783 */
+       { 0xF1F8, 0xF1F8 }, /* R784   - AIF2 Control (1) */
+       { 0xFD1F, 0xFD1F }, /* R785   - AIF2 Control (2) */
+       { 0xF000, 0xF000 }, /* R786   - AIF2 Master/Slave */
+       { 0x01F0, 0x01F0 }, /* R787   - AIF2 BCLK */
+       { 0x0FFF, 0x0FFF }, /* R788   - AIF2ADC LRCLK */
+       { 0x0FFF, 0x0FFF }, /* R789   - AIF2DAC LRCLK */
+       { 0x0003, 0x0003 }, /* R790   - AIF2DAC Data */
+       { 0x0003, 0x0003 }, /* R791   - AIF2ADC Data */
+       { 0x0000, 0x0000 }, /* R792 */
+       { 0x0000, 0x0000 }, /* R793 */
+       { 0x0000, 0x0000 }, /* R794 */
+       { 0x0000, 0x0000 }, /* R795 */
+       { 0x0000, 0x0000 }, /* R796 */
+       { 0x0000, 0x0000 }, /* R797 */
+       { 0x0000, 0x0000 }, /* R798 */
+       { 0x0000, 0x0000 }, /* R799 */
+       { 0x0000, 0x0000 }, /* R800 */
+       { 0x0000, 0x0000 }, /* R801 */
+       { 0x0000, 0x0000 }, /* R802 */
+       { 0x0000, 0x0000 }, /* R803 */
+       { 0x0000, 0x0000 }, /* R804 */
+       { 0x0000, 0x0000 }, /* R805 */
+       { 0x0000, 0x0000 }, /* R806 */
+       { 0x0000, 0x0000 }, /* R807 */
+       { 0x0000, 0x0000 }, /* R808 */
+       { 0x0000, 0x0000 }, /* R809 */
+       { 0x0000, 0x0000 }, /* R810 */
+       { 0x0000, 0x0000 }, /* R811 */
+       { 0x0000, 0x0000 }, /* R812 */
+       { 0x0000, 0x0000 }, /* R813 */
+       { 0x0000, 0x0000 }, /* R814 */
+       { 0x0000, 0x0000 }, /* R815 */
+       { 0x0000, 0x0000 }, /* R816 */
+       { 0x0000, 0x0000 }, /* R817 */
+       { 0x0000, 0x0000 }, /* R818 */
+       { 0x0000, 0x0000 }, /* R819 */
+       { 0x0000, 0x0000 }, /* R820 */
+       { 0x0000, 0x0000 }, /* R821 */
+       { 0x0000, 0x0000 }, /* R822 */
+       { 0x0000, 0x0000 }, /* R823 */
+       { 0x0000, 0x0000 }, /* R824 */
+       { 0x0000, 0x0000 }, /* R825 */
+       { 0x0000, 0x0000 }, /* R826 */
+       { 0x0000, 0x0000 }, /* R827 */
+       { 0x0000, 0x0000 }, /* R828 */
+       { 0x0000, 0x0000 }, /* R829 */
+       { 0x0000, 0x0000 }, /* R830 */
+       { 0x0000, 0x0000 }, /* R831 */
+       { 0x0000, 0x0000 }, /* R832 */
+       { 0x0000, 0x0000 }, /* R833 */
+       { 0x0000, 0x0000 }, /* R834 */
+       { 0x0000, 0x0000 }, /* R835 */
+       { 0x0000, 0x0000 }, /* R836 */
+       { 0x0000, 0x0000 }, /* R837 */
+       { 0x0000, 0x0000 }, /* R838 */
+       { 0x0000, 0x0000 }, /* R839 */
+       { 0x0000, 0x0000 }, /* R840 */
+       { 0x0000, 0x0000 }, /* R841 */
+       { 0x0000, 0x0000 }, /* R842 */
+       { 0x0000, 0x0000 }, /* R843 */
+       { 0x0000, 0x0000 }, /* R844 */
+       { 0x0000, 0x0000 }, /* R845 */
+       { 0x0000, 0x0000 }, /* R846 */
+       { 0x0000, 0x0000 }, /* R847 */
+       { 0x0000, 0x0000 }, /* R848 */
+       { 0x0000, 0x0000 }, /* R849 */
+       { 0x0000, 0x0000 }, /* R850 */
+       { 0x0000, 0x0000 }, /* R851 */
+       { 0x0000, 0x0000 }, /* R852 */
+       { 0x0000, 0x0000 }, /* R853 */
+       { 0x0000, 0x0000 }, /* R854 */
+       { 0x0000, 0x0000 }, /* R855 */
+       { 0x0000, 0x0000 }, /* R856 */
+       { 0x0000, 0x0000 }, /* R857 */
+       { 0x0000, 0x0000 }, /* R858 */
+       { 0x0000, 0x0000 }, /* R859 */
+       { 0x0000, 0x0000 }, /* R860 */
+       { 0x0000, 0x0000 }, /* R861 */
+       { 0x0000, 0x0000 }, /* R862 */
+       { 0x0000, 0x0000 }, /* R863 */
+       { 0x0000, 0x0000 }, /* R864 */
+       { 0x0000, 0x0000 }, /* R865 */
+       { 0x0000, 0x0000 }, /* R866 */
+       { 0x0000, 0x0000 }, /* R867 */
+       { 0x0000, 0x0000 }, /* R868 */
+       { 0x0000, 0x0000 }, /* R869 */
+       { 0x0000, 0x0000 }, /* R870 */
+       { 0x0000, 0x0000 }, /* R871 */
+       { 0x0000, 0x0000 }, /* R872 */
+       { 0x0000, 0x0000 }, /* R873 */
+       { 0x0000, 0x0000 }, /* R874 */
+       { 0x0000, 0x0000 }, /* R875 */
+       { 0x0000, 0x0000 }, /* R876 */
+       { 0x0000, 0x0000 }, /* R877 */
+       { 0x0000, 0x0000 }, /* R878 */
+       { 0x0000, 0x0000 }, /* R879 */
+       { 0x0000, 0x0000 }, /* R880 */
+       { 0x0000, 0x0000 }, /* R881 */
+       { 0x0000, 0x0000 }, /* R882 */
+       { 0x0000, 0x0000 }, /* R883 */
+       { 0x0000, 0x0000 }, /* R884 */
+       { 0x0000, 0x0000 }, /* R885 */
+       { 0x0000, 0x0000 }, /* R886 */
+       { 0x0000, 0x0000 }, /* R887 */
+       { 0x0000, 0x0000 }, /* R888 */
+       { 0x0000, 0x0000 }, /* R889 */
+       { 0x0000, 0x0000 }, /* R890 */
+       { 0x0000, 0x0000 }, /* R891 */
+       { 0x0000, 0x0000 }, /* R892 */
+       { 0x0000, 0x0000 }, /* R893 */
+       { 0x0000, 0x0000 }, /* R894 */
+       { 0x0000, 0x0000 }, /* R895 */
+       { 0x0000, 0x0000 }, /* R896 */
+       { 0x0000, 0x0000 }, /* R897 */
+       { 0x0000, 0x0000 }, /* R898 */
+       { 0x0000, 0x0000 }, /* R899 */
+       { 0x0000, 0x0000 }, /* R900 */
+       { 0x0000, 0x0000 }, /* R901 */
+       { 0x0000, 0x0000 }, /* R902 */
+       { 0x0000, 0x0000 }, /* R903 */
+       { 0x0000, 0x0000 }, /* R904 */
+       { 0x0000, 0x0000 }, /* R905 */
+       { 0x0000, 0x0000 }, /* R906 */
+       { 0x0000, 0x0000 }, /* R907 */
+       { 0x0000, 0x0000 }, /* R908 */
+       { 0x0000, 0x0000 }, /* R909 */
+       { 0x0000, 0x0000 }, /* R910 */
+       { 0x0000, 0x0000 }, /* R911 */
+       { 0x0000, 0x0000 }, /* R912 */
+       { 0x0000, 0x0000 }, /* R913 */
+       { 0x0000, 0x0000 }, /* R914 */
+       { 0x0000, 0x0000 }, /* R915 */
+       { 0x0000, 0x0000 }, /* R916 */
+       { 0x0000, 0x0000 }, /* R917 */
+       { 0x0000, 0x0000 }, /* R918 */
+       { 0x0000, 0x0000 }, /* R919 */
+       { 0x0000, 0x0000 }, /* R920 */
+       { 0x0000, 0x0000 }, /* R921 */
+       { 0x0000, 0x0000 }, /* R922 */
+       { 0x0000, 0x0000 }, /* R923 */
+       { 0x0000, 0x0000 }, /* R924 */
+       { 0x0000, 0x0000 }, /* R925 */
+       { 0x0000, 0x0000 }, /* R926 */
+       { 0x0000, 0x0000 }, /* R927 */
+       { 0x0000, 0x0000 }, /* R928 */
+       { 0x0000, 0x0000 }, /* R929 */
+       { 0x0000, 0x0000 }, /* R930 */
+       { 0x0000, 0x0000 }, /* R931 */
+       { 0x0000, 0x0000 }, /* R932 */
+       { 0x0000, 0x0000 }, /* R933 */
+       { 0x0000, 0x0000 }, /* R934 */
+       { 0x0000, 0x0000 }, /* R935 */
+       { 0x0000, 0x0000 }, /* R936 */
+       { 0x0000, 0x0000 }, /* R937 */
+       { 0x0000, 0x0000 }, /* R938 */
+       { 0x0000, 0x0000 }, /* R939 */
+       { 0x0000, 0x0000 }, /* R940 */
+       { 0x0000, 0x0000 }, /* R941 */
+       { 0x0000, 0x0000 }, /* R942 */
+       { 0x0000, 0x0000 }, /* R943 */
+       { 0x0000, 0x0000 }, /* R944 */
+       { 0x0000, 0x0000 }, /* R945 */
+       { 0x0000, 0x0000 }, /* R946 */
+       { 0x0000, 0x0000 }, /* R947 */
+       { 0x0000, 0x0000 }, /* R948 */
+       { 0x0000, 0x0000 }, /* R949 */
+       { 0x0000, 0x0000 }, /* R950 */
+       { 0x0000, 0x0000 }, /* R951 */
+       { 0x0000, 0x0000 }, /* R952 */
+       { 0x0000, 0x0000 }, /* R953 */
+       { 0x0000, 0x0000 }, /* R954 */
+       { 0x0000, 0x0000 }, /* R955 */
+       { 0x0000, 0x0000 }, /* R956 */
+       { 0x0000, 0x0000 }, /* R957 */
+       { 0x0000, 0x0000 }, /* R958 */
+       { 0x0000, 0x0000 }, /* R959 */
+       { 0x0000, 0x0000 }, /* R960 */
+       { 0x0000, 0x0000 }, /* R961 */
+       { 0x0000, 0x0000 }, /* R962 */
+       { 0x0000, 0x0000 }, /* R963 */
+       { 0x0000, 0x0000 }, /* R964 */
+       { 0x0000, 0x0000 }, /* R965 */
+       { 0x0000, 0x0000 }, /* R966 */
+       { 0x0000, 0x0000 }, /* R967 */
+       { 0x0000, 0x0000 }, /* R968 */
+       { 0x0000, 0x0000 }, /* R969 */
+       { 0x0000, 0x0000 }, /* R970 */
+       { 0x0000, 0x0000 }, /* R971 */
+       { 0x0000, 0x0000 }, /* R972 */
+       { 0x0000, 0x0000 }, /* R973 */
+       { 0x0000, 0x0000 }, /* R974 */
+       { 0x0000, 0x0000 }, /* R975 */
+       { 0x0000, 0x0000 }, /* R976 */
+       { 0x0000, 0x0000 }, /* R977 */
+       { 0x0000, 0x0000 }, /* R978 */
+       { 0x0000, 0x0000 }, /* R979 */
+       { 0x0000, 0x0000 }, /* R980 */
+       { 0x0000, 0x0000 }, /* R981 */
+       { 0x0000, 0x0000 }, /* R982 */
+       { 0x0000, 0x0000 }, /* R983 */
+       { 0x0000, 0x0000 }, /* R984 */
+       { 0x0000, 0x0000 }, /* R985 */
+       { 0x0000, 0x0000 }, /* R986 */
+       { 0x0000, 0x0000 }, /* R987 */
+       { 0x0000, 0x0000 }, /* R988 */
+       { 0x0000, 0x0000 }, /* R989 */
+       { 0x0000, 0x0000 }, /* R990 */
+       { 0x0000, 0x0000 }, /* R991 */
+       { 0x0000, 0x0000 }, /* R992 */
+       { 0x0000, 0x0000 }, /* R993 */
+       { 0x0000, 0x0000 }, /* R994 */
+       { 0x0000, 0x0000 }, /* R995 */
+       { 0x0000, 0x0000 }, /* R996 */
+       { 0x0000, 0x0000 }, /* R997 */
+       { 0x0000, 0x0000 }, /* R998 */
+       { 0x0000, 0x0000 }, /* R999 */
+       { 0x0000, 0x0000 }, /* R1000 */
+       { 0x0000, 0x0000 }, /* R1001 */
+       { 0x0000, 0x0000 }, /* R1002 */
+       { 0x0000, 0x0000 }, /* R1003 */
+       { 0x0000, 0x0000 }, /* R1004 */
+       { 0x0000, 0x0000 }, /* R1005 */
+       { 0x0000, 0x0000 }, /* R1006 */
+       { 0x0000, 0x0000 }, /* R1007 */
+       { 0x0000, 0x0000 }, /* R1008 */
+       { 0x0000, 0x0000 }, /* R1009 */
+       { 0x0000, 0x0000 }, /* R1010 */
+       { 0x0000, 0x0000 }, /* R1011 */
+       { 0x0000, 0x0000 }, /* R1012 */
+       { 0x0000, 0x0000 }, /* R1013 */
+       { 0x0000, 0x0000 }, /* R1014 */
+       { 0x0000, 0x0000 }, /* R1015 */
+       { 0x0000, 0x0000 }, /* R1016 */
+       { 0x0000, 0x0000 }, /* R1017 */
+       { 0x0000, 0x0000 }, /* R1018 */
+       { 0x0000, 0x0000 }, /* R1019 */
+       { 0x0000, 0x0000 }, /* R1020 */
+       { 0x0000, 0x0000 }, /* R1021 */
+       { 0x0000, 0x0000 }, /* R1022 */
+       { 0x0000, 0x0000 }, /* R1023 */
+       { 0x00FF, 0x01FF }, /* R1024  - AIF1 ADC1 Left Volume */
+       { 0x00FF, 0x01FF }, /* R1025  - AIF1 ADC1 Right Volume */
+       { 0x00FF, 0x01FF }, /* R1026  - AIF1 DAC1 Left Volume */
+       { 0x00FF, 0x01FF }, /* R1027  - AIF1 DAC1 Right Volume */
+       { 0x00FF, 0x01FF }, /* R1028  - AIF1 ADC2 Left Volume */
+       { 0x00FF, 0x01FF }, /* R1029  - AIF1 ADC2 Right Volume */
+       { 0x00FF, 0x01FF }, /* R1030  - AIF1 DAC2 Left Volume */
+       { 0x00FF, 0x01FF }, /* R1031  - AIF1 DAC2 Right Volume */
+       { 0x0000, 0x0000 }, /* R1032 */
+       { 0x0000, 0x0000 }, /* R1033 */
+       { 0x0000, 0x0000 }, /* R1034 */
+       { 0x0000, 0x0000 }, /* R1035 */
+       { 0x0000, 0x0000 }, /* R1036 */
+       { 0x0000, 0x0000 }, /* R1037 */
+       { 0x0000, 0x0000 }, /* R1038 */
+       { 0x0000, 0x0000 }, /* R1039 */
+       { 0xF800, 0xF800 }, /* R1040  - AIF1 ADC1 Filters */
+       { 0x7800, 0x7800 }, /* R1041  - AIF1 ADC2 Filters */
+       { 0x0000, 0x0000 }, /* R1042 */
+       { 0x0000, 0x0000 }, /* R1043 */
+       { 0x0000, 0x0000 }, /* R1044 */
+       { 0x0000, 0x0000 }, /* R1045 */
+       { 0x0000, 0x0000 }, /* R1046 */
+       { 0x0000, 0x0000 }, /* R1047 */
+       { 0x0000, 0x0000 }, /* R1048 */
+       { 0x0000, 0x0000 }, /* R1049 */
+       { 0x0000, 0x0000 }, /* R1050 */
+       { 0x0000, 0x0000 }, /* R1051 */
+       { 0x0000, 0x0000 }, /* R1052 */
+       { 0x0000, 0x0000 }, /* R1053 */
+       { 0x0000, 0x0000 }, /* R1054 */
+       { 0x0000, 0x0000 }, /* R1055 */
+       { 0x02B6, 0x02B6 }, /* R1056  - AIF1 DAC1 Filters (1) */
+       { 0x3F00, 0x3F00 }, /* R1057  - AIF1 DAC1 Filters (2) */
+       { 0x02B6, 0x02B6 }, /* R1058  - AIF1 DAC2 Filters (1) */
+       { 0x3F00, 0x3F00 }, /* R1059  - AIF1 DAC2 Filters (2) */
+       { 0x0000, 0x0000 }, /* R1060 */
+       { 0x0000, 0x0000 }, /* R1061 */
+       { 0x0000, 0x0000 }, /* R1062 */
+       { 0x0000, 0x0000 }, /* R1063 */
+       { 0x0000, 0x0000 }, /* R1064 */
+       { 0x0000, 0x0000 }, /* R1065 */
+       { 0x0000, 0x0000 }, /* R1066 */
+       { 0x0000, 0x0000 }, /* R1067 */
+       { 0x0000, 0x0000 }, /* R1068 */
+       { 0x0000, 0x0000 }, /* R1069 */
+       { 0x0000, 0x0000 }, /* R1070 */
+       { 0x0000, 0x0000 }, /* R1071 */
+       { 0x0000, 0x0000 }, /* R1072 */
+       { 0x0000, 0x0000 }, /* R1073 */
+       { 0x0000, 0x0000 }, /* R1074 */
+       { 0x0000, 0x0000 }, /* R1075 */
+       { 0x0000, 0x0000 }, /* R1076 */
+       { 0x0000, 0x0000 }, /* R1077 */
+       { 0x0000, 0x0000 }, /* R1078 */
+       { 0x0000, 0x0000 }, /* R1079 */
+       { 0x0000, 0x0000 }, /* R1080 */
+       { 0x0000, 0x0000 }, /* R1081 */
+       { 0x0000, 0x0000 }, /* R1082 */
+       { 0x0000, 0x0000 }, /* R1083 */
+       { 0x0000, 0x0000 }, /* R1084 */
+       { 0x0000, 0x0000 }, /* R1085 */
+       { 0x0000, 0x0000 }, /* R1086 */
+       { 0x0000, 0x0000 }, /* R1087 */
+       { 0xFFFF, 0xFFFF }, /* R1088  - AIF1 DRC1 (1) */
+       { 0x1FFF, 0x1FFF }, /* R1089  - AIF1 DRC1 (2) */
+       { 0xFFFF, 0xFFFF }, /* R1090  - AIF1 DRC1 (3) */
+       { 0x07FF, 0x07FF }, /* R1091  - AIF1 DRC1 (4) */
+       { 0x03FF, 0x03FF }, /* R1092  - AIF1 DRC1 (5) */
+       { 0x0000, 0x0000 }, /* R1093 */
+       { 0x0000, 0x0000 }, /* R1094 */
+       { 0x0000, 0x0000 }, /* R1095 */
+       { 0x0000, 0x0000 }, /* R1096 */
+       { 0x0000, 0x0000 }, /* R1097 */
+       { 0x0000, 0x0000 }, /* R1098 */
+       { 0x0000, 0x0000 }, /* R1099 */
+       { 0x0000, 0x0000 }, /* R1100 */
+       { 0x0000, 0x0000 }, /* R1101 */
+       { 0x0000, 0x0000 }, /* R1102 */
+       { 0x0000, 0x0000 }, /* R1103 */
+       { 0xFFFF, 0xFFFF }, /* R1104  - AIF1 DRC2 (1) */
+       { 0x1FFF, 0x1FFF }, /* R1105  - AIF1 DRC2 (2) */
+       { 0xFFFF, 0xFFFF }, /* R1106  - AIF1 DRC2 (3) */
+       { 0x07FF, 0x07FF }, /* R1107  - AIF1 DRC2 (4) */
+       { 0x03FF, 0x03FF }, /* R1108  - AIF1 DRC2 (5) */
+       { 0x0000, 0x0000 }, /* R1109 */
+       { 0x0000, 0x0000 }, /* R1110 */
+       { 0x0000, 0x0000 }, /* R1111 */
+       { 0x0000, 0x0000 }, /* R1112 */
+       { 0x0000, 0x0000 }, /* R1113 */
+       { 0x0000, 0x0000 }, /* R1114 */
+       { 0x0000, 0x0000 }, /* R1115 */
+       { 0x0000, 0x0000 }, /* R1116 */
+       { 0x0000, 0x0000 }, /* R1117 */
+       { 0x0000, 0x0000 }, /* R1118 */
+       { 0x0000, 0x0000 }, /* R1119 */
+       { 0x0000, 0x0000 }, /* R1120 */
+       { 0x0000, 0x0000 }, /* R1121 */
+       { 0x0000, 0x0000 }, /* R1122 */
+       { 0x0000, 0x0000 }, /* R1123 */
+       { 0x0000, 0x0000 }, /* R1124 */
+       { 0x0000, 0x0000 }, /* R1125 */
+       { 0x0000, 0x0000 }, /* R1126 */
+       { 0x0000, 0x0000 }, /* R1127 */
+       { 0x0000, 0x0000 }, /* R1128 */
+       { 0x0000, 0x0000 }, /* R1129 */
+       { 0x0000, 0x0000 }, /* R1130 */
+       { 0x0000, 0x0000 }, /* R1131 */
+       { 0x0000, 0x0000 }, /* R1132 */
+       { 0x0000, 0x0000 }, /* R1133 */
+       { 0x0000, 0x0000 }, /* R1134 */
+       { 0x0000, 0x0000 }, /* R1135 */
+       { 0x0000, 0x0000 }, /* R1136 */
+       { 0x0000, 0x0000 }, /* R1137 */
+       { 0x0000, 0x0000 }, /* R1138 */
+       { 0x0000, 0x0000 }, /* R1139 */
+       { 0x0000, 0x0000 }, /* R1140 */
+       { 0x0000, 0x0000 }, /* R1141 */
+       { 0x0000, 0x0000 }, /* R1142 */
+       { 0x0000, 0x0000 }, /* R1143 */
+       { 0x0000, 0x0000 }, /* R1144 */
+       { 0x0000, 0x0000 }, /* R1145 */
+       { 0x0000, 0x0000 }, /* R1146 */
+       { 0x0000, 0x0000 }, /* R1147 */
+       { 0x0000, 0x0000 }, /* R1148 */
+       { 0x0000, 0x0000 }, /* R1149 */
+       { 0x0000, 0x0000 }, /* R1150 */
+       { 0x0000, 0x0000 }, /* R1151 */
+       { 0xFFFF, 0xFFFF }, /* R1152  - AIF1 DAC1 EQ Gains (1) */
+       { 0xFFC0, 0xFFC0 }, /* R1153  - AIF1 DAC1 EQ Gains (2) */
+       { 0xFFFF, 0xFFFF }, /* R1154  - AIF1 DAC1 EQ Band 1 A */
+       { 0xFFFF, 0xFFFF }, /* R1155  - AIF1 DAC1 EQ Band 1 B */
+       { 0xFFFF, 0xFFFF }, /* R1156  - AIF1 DAC1 EQ Band 1 PG */
+       { 0xFFFF, 0xFFFF }, /* R1157  - AIF1 DAC1 EQ Band 2 A */
+       { 0xFFFF, 0xFFFF }, /* R1158  - AIF1 DAC1 EQ Band 2 B */
+       { 0xFFFF, 0xFFFF }, /* R1159  - AIF1 DAC1 EQ Band 2 C */
+       { 0xFFFF, 0xFFFF }, /* R1160  - AIF1 DAC1 EQ Band 2 PG */
+       { 0xFFFF, 0xFFFF }, /* R1161  - AIF1 DAC1 EQ Band 3 A */
+       { 0xFFFF, 0xFFFF }, /* R1162  - AIF1 DAC1 EQ Band 3 B */
+       { 0xFFFF, 0xFFFF }, /* R1163  - AIF1 DAC1 EQ Band 3 C */
+       { 0xFFFF, 0xFFFF }, /* R1164  - AIF1 DAC1 EQ Band 3 PG */
+       { 0xFFFF, 0xFFFF }, /* R1165  - AIF1 DAC1 EQ Band 4 A */
+       { 0xFFFF, 0xFFFF }, /* R1166  - AIF1 DAC1 EQ Band 4 B */
+       { 0xFFFF, 0xFFFF }, /* R1167  - AIF1 DAC1 EQ Band 4 C */
+       { 0xFFFF, 0xFFFF }, /* R1168  - AIF1 DAC1 EQ Band 4 PG */
+       { 0xFFFF, 0xFFFF }, /* R1169  - AIF1 DAC1 EQ Band 5 A */
+       { 0xFFFF, 0xFFFF }, /* R1170  - AIF1 DAC1 EQ Band 5 B */
+       { 0xFFFF, 0xFFFF }, /* R1171  - AIF1 DAC1 EQ Band 5 PG */
+       { 0x0000, 0x0000 }, /* R1172 */
+       { 0x0000, 0x0000 }, /* R1173 */
+       { 0x0000, 0x0000 }, /* R1174 */
+       { 0x0000, 0x0000 }, /* R1175 */
+       { 0x0000, 0x0000 }, /* R1176 */
+       { 0x0000, 0x0000 }, /* R1177 */
+       { 0x0000, 0x0000 }, /* R1178 */
+       { 0x0000, 0x0000 }, /* R1179 */
+       { 0x0000, 0x0000 }, /* R1180 */
+       { 0x0000, 0x0000 }, /* R1181 */
+       { 0x0000, 0x0000 }, /* R1182 */
+       { 0x0000, 0x0000 }, /* R1183 */
+       { 0xFFFF, 0xFFFF }, /* R1184  - AIF1 DAC2 EQ Gains (1) */
+       { 0xFFC0, 0xFFC0 }, /* R1185  - AIF1 DAC2 EQ Gains (2) */
+       { 0xFFFF, 0xFFFF }, /* R1186  - AIF1 DAC2 EQ Band 1 A */
+       { 0xFFFF, 0xFFFF }, /* R1187  - AIF1 DAC2 EQ Band 1 B */
+       { 0xFFFF, 0xFFFF }, /* R1188  - AIF1 DAC2 EQ Band 1 PG */
+       { 0xFFFF, 0xFFFF }, /* R1189  - AIF1 DAC2 EQ Band 2 A */
+       { 0xFFFF, 0xFFFF }, /* R1190  - AIF1 DAC2 EQ Band 2 B */
+       { 0xFFFF, 0xFFFF }, /* R1191  - AIF1 DAC2 EQ Band 2 C */
+       { 0xFFFF, 0xFFFF }, /* R1192  - AIF1 DAC2 EQ Band 2 PG */
+       { 0xFFFF, 0xFFFF }, /* R1193  - AIF1 DAC2 EQ Band 3 A */
+       { 0xFFFF, 0xFFFF }, /* R1194  - AIF1 DAC2 EQ Band 3 B */
+       { 0xFFFF, 0xFFFF }, /* R1195  - AIF1 DAC2 EQ Band 3 C */
+       { 0xFFFF, 0xFFFF }, /* R1196  - AIF1 DAC2 EQ Band 3 PG */
+       { 0xFFFF, 0xFFFF }, /* R1197  - AIF1 DAC2 EQ Band 4 A */
+       { 0xFFFF, 0xFFFF }, /* R1198  - AIF1 DAC2 EQ Band 4 B */
+       { 0xFFFF, 0xFFFF }, /* R1199  - AIF1 DAC2 EQ Band 4 C */
+       { 0xFFFF, 0xFFFF }, /* R1200  - AIF1 DAC2 EQ Band 4 PG */
+       { 0xFFFF, 0xFFFF }, /* R1201  - AIF1 DAC2 EQ Band 5 A */
+       { 0xFFFF, 0xFFFF }, /* R1202  - AIF1 DAC2 EQ Band 5 B */
+       { 0xFFFF, 0xFFFF }, /* R1203  - AIF1 DAC2 EQ Band 5 PG */
+       { 0x0000, 0x0000 }, /* R1204 */
+       { 0x0000, 0x0000 }, /* R1205 */
+       { 0x0000, 0x0000 }, /* R1206 */
+       { 0x0000, 0x0000 }, /* R1207 */
+       { 0x0000, 0x0000 }, /* R1208 */
+       { 0x0000, 0x0000 }, /* R1209 */
+       { 0x0000, 0x0000 }, /* R1210 */
+       { 0x0000, 0x0000 }, /* R1211 */
+       { 0x0000, 0x0000 }, /* R1212 */
+       { 0x0000, 0x0000 }, /* R1213 */
+       { 0x0000, 0x0000 }, /* R1214 */
+       { 0x0000, 0x0000 }, /* R1215 */
+       { 0x0000, 0x0000 }, /* R1216 */
+       { 0x0000, 0x0000 }, /* R1217 */
+       { 0x0000, 0x0000 }, /* R1218 */
+       { 0x0000, 0x0000 }, /* R1219 */
+       { 0x0000, 0x0000 }, /* R1220 */
+       { 0x0000, 0x0000 }, /* R1221 */
+       { 0x0000, 0x0000 }, /* R1222 */
+       { 0x0000, 0x0000 }, /* R1223 */
+       { 0x0000, 0x0000 }, /* R1224 */
+       { 0x0000, 0x0000 }, /* R1225 */
+       { 0x0000, 0x0000 }, /* R1226 */
+       { 0x0000, 0x0000 }, /* R1227 */
+       { 0x0000, 0x0000 }, /* R1228 */
+       { 0x0000, 0x0000 }, /* R1229 */
+       { 0x0000, 0x0000 }, /* R1230 */
+       { 0x0000, 0x0000 }, /* R1231 */
+       { 0x0000, 0x0000 }, /* R1232 */
+       { 0x0000, 0x0000 }, /* R1233 */
+       { 0x0000, 0x0000 }, /* R1234 */
+       { 0x0000, 0x0000 }, /* R1235 */
+       { 0x0000, 0x0000 }, /* R1236 */
+       { 0x0000, 0x0000 }, /* R1237 */
+       { 0x0000, 0x0000 }, /* R1238 */
+       { 0x0000, 0x0000 }, /* R1239 */
+       { 0x0000, 0x0000 }, /* R1240 */
+       { 0x0000, 0x0000 }, /* R1241 */
+       { 0x0000, 0x0000 }, /* R1242 */
+       { 0x0000, 0x0000 }, /* R1243 */
+       { 0x0000, 0x0000 }, /* R1244 */
+       { 0x0000, 0x0000 }, /* R1245 */
+       { 0x0000, 0x0000 }, /* R1246 */
+       { 0x0000, 0x0000 }, /* R1247 */
+       { 0x0000, 0x0000 }, /* R1248 */
+       { 0x0000, 0x0000 }, /* R1249 */
+       { 0x0000, 0x0000 }, /* R1250 */
+       { 0x0000, 0x0000 }, /* R1251 */
+       { 0x0000, 0x0000 }, /* R1252 */
+       { 0x0000, 0x0000 }, /* R1253 */
+       { 0x0000, 0x0000 }, /* R1254 */
+       { 0x0000, 0x0000 }, /* R1255 */
+       { 0x0000, 0x0000 }, /* R1256 */
+       { 0x0000, 0x0000 }, /* R1257 */
+       { 0x0000, 0x0000 }, /* R1258 */
+       { 0x0000, 0x0000 }, /* R1259 */
+       { 0x0000, 0x0000 }, /* R1260 */
+       { 0x0000, 0x0000 }, /* R1261 */
+       { 0x0000, 0x0000 }, /* R1262 */
+       { 0x0000, 0x0000 }, /* R1263 */
+       { 0x0000, 0x0000 }, /* R1264 */
+       { 0x0000, 0x0000 }, /* R1265 */
+       { 0x0000, 0x0000 }, /* R1266 */
+       { 0x0000, 0x0000 }, /* R1267 */
+       { 0x0000, 0x0000 }, /* R1268 */
+       { 0x0000, 0x0000 }, /* R1269 */
+       { 0x0000, 0x0000 }, /* R1270 */
+       { 0x0000, 0x0000 }, /* R1271 */
+       { 0x0000, 0x0000 }, /* R1272 */
+       { 0x0000, 0x0000 }, /* R1273 */
+       { 0x0000, 0x0000 }, /* R1274 */
+       { 0x0000, 0x0000 }, /* R1275 */
+       { 0x0000, 0x0000 }, /* R1276 */
+       { 0x0000, 0x0000 }, /* R1277 */
+       { 0x0000, 0x0000 }, /* R1278 */
+       { 0x0000, 0x0000 }, /* R1279 */
+       { 0x00FF, 0x01FF }, /* R1280  - AIF2 ADC Left Volume */
+       { 0x00FF, 0x01FF }, /* R1281  - AIF2 ADC Right Volume */
+       { 0x00FF, 0x01FF }, /* R1282  - AIF2 DAC Left Volume */
+       { 0x00FF, 0x01FF }, /* R1283  - AIF2 DAC Right Volume */
+       { 0x0000, 0x0000 }, /* R1284 */
+       { 0x0000, 0x0000 }, /* R1285 */
+       { 0x0000, 0x0000 }, /* R1286 */
+       { 0x0000, 0x0000 }, /* R1287 */
+       { 0x0000, 0x0000 }, /* R1288 */
+       { 0x0000, 0x0000 }, /* R1289 */
+       { 0x0000, 0x0000 }, /* R1290 */
+       { 0x0000, 0x0000 }, /* R1291 */
+       { 0x0000, 0x0000 }, /* R1292 */
+       { 0x0000, 0x0000 }, /* R1293 */
+       { 0x0000, 0x0000 }, /* R1294 */
+       { 0x0000, 0x0000 }, /* R1295 */
+       { 0xF800, 0xF800 }, /* R1296  - AIF2 ADC Filters */
+       { 0x0000, 0x0000 }, /* R1297 */
+       { 0x0000, 0x0000 }, /* R1298 */
+       { 0x0000, 0x0000 }, /* R1299 */
+       { 0x0000, 0x0000 }, /* R1300 */
+       { 0x0000, 0x0000 }, /* R1301 */
+       { 0x0000, 0x0000 }, /* R1302 */
+       { 0x0000, 0x0000 }, /* R1303 */
+       { 0x0000, 0x0000 }, /* R1304 */
+       { 0x0000, 0x0000 }, /* R1305 */
+       { 0x0000, 0x0000 }, /* R1306 */
+       { 0x0000, 0x0000 }, /* R1307 */
+       { 0x0000, 0x0000 }, /* R1308 */
+       { 0x0000, 0x0000 }, /* R1309 */
+       { 0x0000, 0x0000 }, /* R1310 */
+       { 0x0000, 0x0000 }, /* R1311 */
+       { 0x02B6, 0x02B6 }, /* R1312  - AIF2 DAC Filters (1) */
+       { 0x3F00, 0x3F00 }, /* R1313  - AIF2 DAC Filters (2) */
+       { 0x0000, 0x0000 }, /* R1314 */
+       { 0x0000, 0x0000 }, /* R1315 */
+       { 0x0000, 0x0000 }, /* R1316 */
+       { 0x0000, 0x0000 }, /* R1317 */
+       { 0x0000, 0x0000 }, /* R1318 */
+       { 0x0000, 0x0000 }, /* R1319 */
+       { 0x0000, 0x0000 }, /* R1320 */
+       { 0x0000, 0x0000 }, /* R1321 */
+       { 0x0000, 0x0000 }, /* R1322 */
+       { 0x0000, 0x0000 }, /* R1323 */
+       { 0x0000, 0x0000 }, /* R1324 */
+       { 0x0000, 0x0000 }, /* R1325 */
+       { 0x0000, 0x0000 }, /* R1326 */
+       { 0x0000, 0x0000 }, /* R1327 */
+       { 0x0000, 0x0000 }, /* R1328 */
+       { 0x0000, 0x0000 }, /* R1329 */
+       { 0x0000, 0x0000 }, /* R1330 */
+       { 0x0000, 0x0000 }, /* R1331 */
+       { 0x0000, 0x0000 }, /* R1332 */
+       { 0x0000, 0x0000 }, /* R1333 */
+       { 0x0000, 0x0000 }, /* R1334 */
+       { 0x0000, 0x0000 }, /* R1335 */
+       { 0x0000, 0x0000 }, /* R1336 */
+       { 0x0000, 0x0000 }, /* R1337 */
+       { 0x0000, 0x0000 }, /* R1338 */
+       { 0x0000, 0x0000 }, /* R1339 */
+       { 0x0000, 0x0000 }, /* R1340 */
+       { 0x0000, 0x0000 }, /* R1341 */
+       { 0x0000, 0x0000 }, /* R1342 */
+       { 0x0000, 0x0000 }, /* R1343 */
+       { 0xFFFF, 0xFFFF }, /* R1344  - AIF2 DRC (1) */
+       { 0x1FFF, 0x1FFF }, /* R1345  - AIF2 DRC (2) */
+       { 0xFFFF, 0xFFFF }, /* R1346  - AIF2 DRC (3) */
+       { 0x07FF, 0x07FF }, /* R1347  - AIF2 DRC (4) */
+       { 0x03FF, 0x03FF }, /* R1348  - AIF2 DRC (5) */
+       { 0x0000, 0x0000 }, /* R1349 */
+       { 0x0000, 0x0000 }, /* R1350 */
+       { 0x0000, 0x0000 }, /* R1351 */
+       { 0x0000, 0x0000 }, /* R1352 */
+       { 0x0000, 0x0000 }, /* R1353 */
+       { 0x0000, 0x0000 }, /* R1354 */
+       { 0x0000, 0x0000 }, /* R1355 */
+       { 0x0000, 0x0000 }, /* R1356 */
+       { 0x0000, 0x0000 }, /* R1357 */
+       { 0x0000, 0x0000 }, /* R1358 */
+       { 0x0000, 0x0000 }, /* R1359 */
+       { 0x0000, 0x0000 }, /* R1360 */
+       { 0x0000, 0x0000 }, /* R1361 */
+       { 0x0000, 0x0000 }, /* R1362 */
+       { 0x0000, 0x0000 }, /* R1363 */
+       { 0x0000, 0x0000 }, /* R1364 */
+       { 0x0000, 0x0000 }, /* R1365 */
+       { 0x0000, 0x0000 }, /* R1366 */
+       { 0x0000, 0x0000 }, /* R1367 */
+       { 0x0000, 0x0000 }, /* R1368 */
+       { 0x0000, 0x0000 }, /* R1369 */
+       { 0x0000, 0x0000 }, /* R1370 */
+       { 0x0000, 0x0000 }, /* R1371 */
+       { 0x0000, 0x0000 }, /* R1372 */
+       { 0x0000, 0x0000 }, /* R1373 */
+       { 0x0000, 0x0000 }, /* R1374 */
+       { 0x0000, 0x0000 }, /* R1375 */
+       { 0x0000, 0x0000 }, /* R1376 */
+       { 0x0000, 0x0000 }, /* R1377 */
+       { 0x0000, 0x0000 }, /* R1378 */
+       { 0x0000, 0x0000 }, /* R1379 */
+       { 0x0000, 0x0000 }, /* R1380 */
+       { 0x0000, 0x0000 }, /* R1381 */
+       { 0x0000, 0x0000 }, /* R1382 */
+       { 0x0000, 0x0000 }, /* R1383 */
+       { 0x0000, 0x0000 }, /* R1384 */
+       { 0x0000, 0x0000 }, /* R1385 */
+       { 0x0000, 0x0000 }, /* R1386 */
+       { 0x0000, 0x0000 }, /* R1387 */
+       { 0x0000, 0x0000 }, /* R1388 */
+       { 0x0000, 0x0000 }, /* R1389 */
+       { 0x0000, 0x0000 }, /* R1390 */
+       { 0x0000, 0x0000 }, /* R1391 */
+       { 0x0000, 0x0000 }, /* R1392 */
+       { 0x0000, 0x0000 }, /* R1393 */
+       { 0x0000, 0x0000 }, /* R1394 */
+       { 0x0000, 0x0000 }, /* R1395 */
+       { 0x0000, 0x0000 }, /* R1396 */
+       { 0x0000, 0x0000 }, /* R1397 */
+       { 0x0000, 0x0000 }, /* R1398 */
+       { 0x0000, 0x0000 }, /* R1399 */
+       { 0x0000, 0x0000 }, /* R1400 */
+       { 0x0000, 0x0000 }, /* R1401 */
+       { 0x0000, 0x0000 }, /* R1402 */
+       { 0x0000, 0x0000 }, /* R1403 */
+       { 0x0000, 0x0000 }, /* R1404 */
+       { 0x0000, 0x0000 }, /* R1405 */
+       { 0x0000, 0x0000 }, /* R1406 */
+       { 0x0000, 0x0000 }, /* R1407 */
+       { 0xFFFF, 0xFFFF }, /* R1408  - AIF2 EQ Gains (1) */
+       { 0xFFC0, 0xFFC0 }, /* R1409  - AIF2 EQ Gains (2) */
+       { 0xFFFF, 0xFFFF }, /* R1410  - AIF2 EQ Band 1 A */
+       { 0xFFFF, 0xFFFF }, /* R1411  - AIF2 EQ Band 1 B */
+       { 0xFFFF, 0xFFFF }, /* R1412  - AIF2 EQ Band 1 PG */
+       { 0xFFFF, 0xFFFF }, /* R1413  - AIF2 EQ Band 2 A */
+       { 0xFFFF, 0xFFFF }, /* R1414  - AIF2 EQ Band 2 B */
+       { 0xFFFF, 0xFFFF }, /* R1415  - AIF2 EQ Band 2 C */
+       { 0xFFFF, 0xFFFF }, /* R1416  - AIF2 EQ Band 2 PG */
+       { 0xFFFF, 0xFFFF }, /* R1417  - AIF2 EQ Band 3 A */
+       { 0xFFFF, 0xFFFF }, /* R1418  - AIF2 EQ Band 3 B */
+       { 0xFFFF, 0xFFFF }, /* R1419  - AIF2 EQ Band 3 C */
+       { 0xFFFF, 0xFFFF }, /* R1420  - AIF2 EQ Band 3 PG */
+       { 0xFFFF, 0xFFFF }, /* R1421  - AIF2 EQ Band 4 A */
+       { 0xFFFF, 0xFFFF }, /* R1422  - AIF2 EQ Band 4 B */
+       { 0xFFFF, 0xFFFF }, /* R1423  - AIF2 EQ Band 4 C */
+       { 0xFFFF, 0xFFFF }, /* R1424  - AIF2 EQ Band 4 PG */
+       { 0xFFFF, 0xFFFF }, /* R1425  - AIF2 EQ Band 5 A */
+       { 0xFFFF, 0xFFFF }, /* R1426  - AIF2 EQ Band 5 B */
+       { 0xFFFF, 0xFFFF }, /* R1427  - AIF2 EQ Band 5 PG */
+       { 0x0000, 0x0000 }, /* R1428 */
+       { 0x0000, 0x0000 }, /* R1429 */
+       { 0x0000, 0x0000 }, /* R1430 */
+       { 0x0000, 0x0000 }, /* R1431 */
+       { 0x0000, 0x0000 }, /* R1432 */
+       { 0x0000, 0x0000 }, /* R1433 */
+       { 0x0000, 0x0000 }, /* R1434 */
+       { 0x0000, 0x0000 }, /* R1435 */
+       { 0x0000, 0x0000 }, /* R1436 */
+       { 0x0000, 0x0000 }, /* R1437 */
+       { 0x0000, 0x0000 }, /* R1438 */
+       { 0x0000, 0x0000 }, /* R1439 */
+       { 0x0000, 0x0000 }, /* R1440 */
+       { 0x0000, 0x0000 }, /* R1441 */
+       { 0x0000, 0x0000 }, /* R1442 */
+       { 0x0000, 0x0000 }, /* R1443 */
+       { 0x0000, 0x0000 }, /* R1444 */
+       { 0x0000, 0x0000 }, /* R1445 */
+       { 0x0000, 0x0000 }, /* R1446 */
+       { 0x0000, 0x0000 }, /* R1447 */
+       { 0x0000, 0x0000 }, /* R1448 */
+       { 0x0000, 0x0000 }, /* R1449 */
+       { 0x0000, 0x0000 }, /* R1450 */
+       { 0x0000, 0x0000 }, /* R1451 */
+       { 0x0000, 0x0000 }, /* R1452 */
+       { 0x0000, 0x0000 }, /* R1453 */
+       { 0x0000, 0x0000 }, /* R1454 */
+       { 0x0000, 0x0000 }, /* R1455 */
+       { 0x0000, 0x0000 }, /* R1456 */
+       { 0x0000, 0x0000 }, /* R1457 */
+       { 0x0000, 0x0000 }, /* R1458 */
+       { 0x0000, 0x0000 }, /* R1459 */
+       { 0x0000, 0x0000 }, /* R1460 */
+       { 0x0000, 0x0000 }, /* R1461 */
+       { 0x0000, 0x0000 }, /* R1462 */
+       { 0x0000, 0x0000 }, /* R1463 */
+       { 0x0000, 0x0000 }, /* R1464 */
+       { 0x0000, 0x0000 }, /* R1465 */
+       { 0x0000, 0x0000 }, /* R1466 */
+       { 0x0000, 0x0000 }, /* R1467 */
+       { 0x0000, 0x0000 }, /* R1468 */
+       { 0x0000, 0x0000 }, /* R1469 */
+       { 0x0000, 0x0000 }, /* R1470 */
+       { 0x0000, 0x0000 }, /* R1471 */
+       { 0x0000, 0x0000 }, /* R1472 */
+       { 0x0000, 0x0000 }, /* R1473 */
+       { 0x0000, 0x0000 }, /* R1474 */
+       { 0x0000, 0x0000 }, /* R1475 */
+       { 0x0000, 0x0000 }, /* R1476 */
+       { 0x0000, 0x0000 }, /* R1477 */
+       { 0x0000, 0x0000 }, /* R1478 */
+       { 0x0000, 0x0000 }, /* R1479 */
+       { 0x0000, 0x0000 }, /* R1480 */
+       { 0x0000, 0x0000 }, /* R1481 */
+       { 0x0000, 0x0000 }, /* R1482 */
+       { 0x0000, 0x0000 }, /* R1483 */
+       { 0x0000, 0x0000 }, /* R1484 */
+       { 0x0000, 0x0000 }, /* R1485 */
+       { 0x0000, 0x0000 }, /* R1486 */
+       { 0x0000, 0x0000 }, /* R1487 */
+       { 0x0000, 0x0000 }, /* R1488 */
+       { 0x0000, 0x0000 }, /* R1489 */
+       { 0x0000, 0x0000 }, /* R1490 */
+       { 0x0000, 0x0000 }, /* R1491 */
+       { 0x0000, 0x0000 }, /* R1492 */
+       { 0x0000, 0x0000 }, /* R1493 */
+       { 0x0000, 0x0000 }, /* R1494 */
+       { 0x0000, 0x0000 }, /* R1495 */
+       { 0x0000, 0x0000 }, /* R1496 */
+       { 0x0000, 0x0000 }, /* R1497 */
+       { 0x0000, 0x0000 }, /* R1498 */
+       { 0x0000, 0x0000 }, /* R1499 */
+       { 0x0000, 0x0000 }, /* R1500 */
+       { 0x0000, 0x0000 }, /* R1501 */
+       { 0x0000, 0x0000 }, /* R1502 */
+       { 0x0000, 0x0000 }, /* R1503 */
+       { 0x0000, 0x0000 }, /* R1504 */
+       { 0x0000, 0x0000 }, /* R1505 */
+       { 0x0000, 0x0000 }, /* R1506 */
+       { 0x0000, 0x0000 }, /* R1507 */
+       { 0x0000, 0x0000 }, /* R1508 */
+       { 0x0000, 0x0000 }, /* R1509 */
+       { 0x0000, 0x0000 }, /* R1510 */
+       { 0x0000, 0x0000 }, /* R1511 */
+       { 0x0000, 0x0000 }, /* R1512 */
+       { 0x0000, 0x0000 }, /* R1513 */
+       { 0x0000, 0x0000 }, /* R1514 */
+       { 0x0000, 0x0000 }, /* R1515 */
+       { 0x0000, 0x0000 }, /* R1516 */
+       { 0x0000, 0x0000 }, /* R1517 */
+       { 0x0000, 0x0000 }, /* R1518 */
+       { 0x0000, 0x0000 }, /* R1519 */
+       { 0x0000, 0x0000 }, /* R1520 */
+       { 0x0000, 0x0000 }, /* R1521 */
+       { 0x0000, 0x0000 }, /* R1522 */
+       { 0x0000, 0x0000 }, /* R1523 */
+       { 0x0000, 0x0000 }, /* R1524 */
+       { 0x0000, 0x0000 }, /* R1525 */
+       { 0x0000, 0x0000 }, /* R1526 */
+       { 0x0000, 0x0000 }, /* R1527 */
+       { 0x0000, 0x0000 }, /* R1528 */
+       { 0x0000, 0x0000 }, /* R1529 */
+       { 0x0000, 0x0000 }, /* R1530 */
+       { 0x0000, 0x0000 }, /* R1531 */
+       { 0x0000, 0x0000 }, /* R1532 */
+       { 0x0000, 0x0000 }, /* R1533 */
+       { 0x0000, 0x0000 }, /* R1534 */
+       { 0x0000, 0x0000 }, /* R1535 */
+       { 0x01EF, 0x01EF }, /* R1536  - DAC1 Mixer Volumes */
+       { 0x0037, 0x0037 }, /* R1537  - DAC1 Left Mixer Routing */
+       { 0x0037, 0x0037 }, /* R1538  - DAC1 Right Mixer Routing */
+       { 0x01EF, 0x01EF }, /* R1539  - DAC2 Mixer Volumes */
+       { 0x0037, 0x0037 }, /* R1540  - DAC2 Left Mixer Routing */
+       { 0x0037, 0x0037 }, /* R1541  - DAC2 Right Mixer Routing */
+       { 0x0003, 0x0003 }, /* R1542  - AIF1 ADC1 Left Mixer Routing */
+       { 0x0003, 0x0003 }, /* R1543  - AIF1 ADC1 Right Mixer Routing */
+       { 0x0003, 0x0003 }, /* R1544  - AIF1 ADC2 Left Mixer Routing */
+       { 0x0003, 0x0003 }, /* R1545  - AIF1 ADC2 Right mixer Routing */
+       { 0x0000, 0x0000 }, /* R1546 */
+       { 0x0000, 0x0000 }, /* R1547 */
+       { 0x0000, 0x0000 }, /* R1548 */
+       { 0x0000, 0x0000 }, /* R1549 */
+       { 0x0000, 0x0000 }, /* R1550 */
+       { 0x0000, 0x0000 }, /* R1551 */
+       { 0x02FF, 0x03FF }, /* R1552  - DAC1 Left Volume */
+       { 0x02FF, 0x03FF }, /* R1553  - DAC1 Right Volume */
+       { 0x02FF, 0x03FF }, /* R1554  - DAC2 Left Volume */
+       { 0x02FF, 0x03FF }, /* R1555  - DAC2 Right Volume */
+       { 0x0003, 0x0003 }, /* R1556  - DAC Softmute */
+       { 0x0000, 0x0000 }, /* R1557 */
+       { 0x0000, 0x0000 }, /* R1558 */
+       { 0x0000, 0x0000 }, /* R1559 */
+       { 0x0000, 0x0000 }, /* R1560 */
+       { 0x0000, 0x0000 }, /* R1561 */
+       { 0x0000, 0x0000 }, /* R1562 */
+       { 0x0000, 0x0000 }, /* R1563 */
+       { 0x0000, 0x0000 }, /* R1564 */
+       { 0x0000, 0x0000 }, /* R1565 */
+       { 0x0000, 0x0000 }, /* R1566 */
+       { 0x0000, 0x0000 }, /* R1567 */
+       { 0x0003, 0x0003 }, /* R1568  - Oversampling */
+       { 0x03C3, 0x03C3 }, /* R1569  - Sidetone */
+};
+
+const __devinitdata u16 wm8994_reg_defaults[WM8994_CACHE_SIZE] = {
+       0x8994,     /* R0     - Software Reset */
+       0x0000,     /* R1     - Power Management (1) */
+       0x6000,     /* R2     - Power Management (2) */
+       0x0000,     /* R3     - Power Management (3) */
+       0x0000,     /* R4     - Power Management (4) */
+       0x0000,     /* R5     - Power Management (5) */
+       0x0000,     /* R6     - Power Management (6) */
+       0x0000,     /* R7 */
+       0x0000,     /* R8 */
+       0x0000,     /* R9 */
+       0x0000,     /* R10 */
+       0x0000,     /* R11 */
+       0x0000,     /* R12 */
+       0x0000,     /* R13 */
+       0x0000,     /* R14 */
+       0x0000,     /* R15 */
+       0x0000,     /* R16 */
+       0x0000,     /* R17 */
+       0x0000,     /* R18 */
+       0x0000,     /* R19 */
+       0x0000,     /* R20 */
+       0x0000,     /* R21    - Input Mixer (1) */
+       0x0000,     /* R22 */
+       0x0000,     /* R23 */
+       0x008B,     /* R24    - Left Line Input 1&2 Volume */
+       0x008B,     /* R25    - Left Line Input 3&4 Volume */
+       0x008B,     /* R26    - Right Line Input 1&2 Volume */
+       0x008B,     /* R27    - Right Line Input 3&4 Volume */
+       0x006D,     /* R28    - Left Output Volume */
+       0x006D,     /* R29    - Right Output Volume */
+       0x0066,     /* R30    - Line Outputs Volume */
+       0x0020,     /* R31    - HPOUT2 Volume */
+       0x0079,     /* R32    - Left OPGA Volume */
+       0x0079,     /* R33    - Right OPGA Volume */
+       0x0003,     /* R34    - SPKMIXL Attenuation */
+       0x0003,     /* R35    - SPKMIXR Attenuation */
+       0x0011,     /* R36    - SPKOUT Mixers */
+       0x0140,     /* R37    - ClassD */
+       0x0079,     /* R38    - Speaker Volume Left */
+       0x0079,     /* R39    - Speaker Volume Right */
+       0x0000,     /* R40    - Input Mixer (2) */
+       0x0000,     /* R41    - Input Mixer (3) */
+       0x0000,     /* R42    - Input Mixer (4) */
+       0x0000,     /* R43    - Input Mixer (5) */
+       0x0000,     /* R44    - Input Mixer (6) */
+       0x0000,     /* R45    - Output Mixer (1) */
+       0x0000,     /* R46    - Output Mixer (2) */
+       0x0000,     /* R47    - Output Mixer (3) */
+       0x0000,     /* R48    - Output Mixer (4) */
+       0x0000,     /* R49    - Output Mixer (5) */
+       0x0000,     /* R50    - Output Mixer (6) */
+       0x0000,     /* R51    - HPOUT2 Mixer */
+       0x0000,     /* R52    - Line Mixer (1) */
+       0x0000,     /* R53    - Line Mixer (2) */
+       0x0000,     /* R54    - Speaker Mixer */
+       0x0000,     /* R55    - Additional Control */
+       0x0000,     /* R56    - AntiPOP (1) */
+       0x0000,     /* R57    - AntiPOP (2) */
+       0x0000,     /* R58    - MICBIAS */
+       0x000D,     /* R59    - LDO 1 */
+       0x0003,     /* R60    - LDO 2 */
+       0x0000,     /* R61 */
+       0x0000,     /* R62 */
+       0x0000,     /* R63 */
+       0x0000,     /* R64 */
+       0x0000,     /* R65 */
+       0x0000,     /* R66 */
+       0x0000,     /* R67 */
+       0x0000,     /* R68 */
+       0x0000,     /* R69 */
+       0x0000,     /* R70 */
+       0x0000,     /* R71 */
+       0x0000,     /* R72 */
+       0x0000,     /* R73 */
+       0x0000,     /* R74 */
+       0x0000,     /* R75 */
+       0x1F25,     /* R76    - Charge Pump (1) */
+       0x0000,     /* R77 */
+       0x0000,     /* R78 */
+       0x0000,     /* R79 */
+       0x0000,     /* R80 */
+       0x0004,     /* R81    - Class W (1) */
+       0x0000,     /* R82 */
+       0x0000,     /* R83 */
+       0x0000,     /* R84    - DC Servo (1) */
+       0x054A,     /* R85    - DC Servo (2) */
+       0x0000,     /* R86 */
+       0x0000,     /* R87    - DC Servo (4) */
+       0x0000,     /* R88    - DC Servo Readback */
+       0x0000,     /* R89 */
+       0x0000,     /* R90 */
+       0x0000,     /* R91 */
+       0x0000,     /* R92 */
+       0x0000,     /* R93 */
+       0x0000,     /* R94 */
+       0x0000,     /* R95 */
+       0x0000,     /* R96    - Analogue HP (1) */
+       0x0000,     /* R97 */
+       0x0000,     /* R98 */
+       0x0000,     /* R99 */
+       0x0000,     /* R100 */
+       0x0000,     /* R101 */
+       0x0000,     /* R102 */
+       0x0000,     /* R103 */
+       0x0000,     /* R104 */
+       0x0000,     /* R105 */
+       0x0000,     /* R106 */
+       0x0000,     /* R107 */
+       0x0000,     /* R108 */
+       0x0000,     /* R109 */
+       0x0000,     /* R110 */
+       0x0000,     /* R111 */
+       0x0000,     /* R112 */
+       0x0000,     /* R113 */
+       0x0000,     /* R114 */
+       0x0000,     /* R115 */
+       0x0000,     /* R116 */
+       0x0000,     /* R117 */
+       0x0000,     /* R118 */
+       0x0000,     /* R119 */
+       0x0000,     /* R120 */
+       0x0000,     /* R121 */
+       0x0000,     /* R122 */
+       0x0000,     /* R123 */
+       0x0000,     /* R124 */
+       0x0000,     /* R125 */
+       0x0000,     /* R126 */
+       0x0000,     /* R127 */
+       0x0000,     /* R128 */
+       0x0000,     /* R129 */
+       0x0000,     /* R130 */
+       0x0000,     /* R131 */
+       0x0000,     /* R132 */
+       0x0000,     /* R133 */
+       0x0000,     /* R134 */
+       0x0000,     /* R135 */
+       0x0000,     /* R136 */
+       0x0000,     /* R137 */
+       0x0000,     /* R138 */
+       0x0000,     /* R139 */
+       0x0000,     /* R140 */
+       0x0000,     /* R141 */
+       0x0000,     /* R142 */
+       0x0000,     /* R143 */
+       0x0000,     /* R144 */
+       0x0000,     /* R145 */
+       0x0000,     /* R146 */
+       0x0000,     /* R147 */
+       0x0000,     /* R148 */
+       0x0000,     /* R149 */
+       0x0000,     /* R150 */
+       0x0000,     /* R151 */
+       0x0000,     /* R152 */
+       0x0000,     /* R153 */
+       0x0000,     /* R154 */
+       0x0000,     /* R155 */
+       0x0000,     /* R156 */
+       0x0000,     /* R157 */
+       0x0000,     /* R158 */
+       0x0000,     /* R159 */
+       0x0000,     /* R160 */
+       0x0000,     /* R161 */
+       0x0000,     /* R162 */
+       0x0000,     /* R163 */
+       0x0000,     /* R164 */
+       0x0000,     /* R165 */
+       0x0000,     /* R166 */
+       0x0000,     /* R167 */
+       0x0000,     /* R168 */
+       0x0000,     /* R169 */
+       0x0000,     /* R170 */
+       0x0000,     /* R171 */
+       0x0000,     /* R172 */
+       0x0000,     /* R173 */
+       0x0000,     /* R174 */
+       0x0000,     /* R175 */
+       0x0000,     /* R176 */
+       0x0000,     /* R177 */
+       0x0000,     /* R178 */
+       0x0000,     /* R179 */
+       0x0000,     /* R180 */
+       0x0000,     /* R181 */
+       0x0000,     /* R182 */
+       0x0000,     /* R183 */
+       0x0000,     /* R184 */
+       0x0000,     /* R185 */
+       0x0000,     /* R186 */
+       0x0000,     /* R187 */
+       0x0000,     /* R188 */
+       0x0000,     /* R189 */
+       0x0000,     /* R190 */
+       0x0000,     /* R191 */
+       0x0000,     /* R192 */
+       0x0000,     /* R193 */
+       0x0000,     /* R194 */
+       0x0000,     /* R195 */
+       0x0000,     /* R196 */
+       0x0000,     /* R197 */
+       0x0000,     /* R198 */
+       0x0000,     /* R199 */
+       0x0000,     /* R200 */
+       0x0000,     /* R201 */
+       0x0000,     /* R202 */
+       0x0000,     /* R203 */
+       0x0000,     /* R204 */
+       0x0000,     /* R205 */
+       0x0000,     /* R206 */
+       0x0000,     /* R207 */
+       0x0000,     /* R208 */
+       0x0000,     /* R209 */
+       0x0000,     /* R210 */
+       0x0000,     /* R211 */
+       0x0000,     /* R212 */
+       0x0000,     /* R213 */
+       0x0000,     /* R214 */
+       0x0000,     /* R215 */
+       0x0000,     /* R216 */
+       0x0000,     /* R217 */
+       0x0000,     /* R218 */
+       0x0000,     /* R219 */
+       0x0000,     /* R220 */
+       0x0000,     /* R221 */
+       0x0000,     /* R222 */
+       0x0000,     /* R223 */
+       0x0000,     /* R224 */
+       0x0000,     /* R225 */
+       0x0000,     /* R226 */
+       0x0000,     /* R227 */
+       0x0000,     /* R228 */
+       0x0000,     /* R229 */
+       0x0000,     /* R230 */
+       0x0000,     /* R231 */
+       0x0000,     /* R232 */
+       0x0000,     /* R233 */
+       0x0000,     /* R234 */
+       0x0000,     /* R235 */
+       0x0000,     /* R236 */
+       0x0000,     /* R237 */
+       0x0000,     /* R238 */
+       0x0000,     /* R239 */
+       0x0000,     /* R240 */
+       0x0000,     /* R241 */
+       0x0000,     /* R242 */
+       0x0000,     /* R243 */
+       0x0000,     /* R244 */
+       0x0000,     /* R245 */
+       0x0000,     /* R246 */
+       0x0000,     /* R247 */
+       0x0000,     /* R248 */
+       0x0000,     /* R249 */
+       0x0000,     /* R250 */
+       0x0000,     /* R251 */
+       0x0000,     /* R252 */
+       0x0000,     /* R253 */
+       0x0000,     /* R254 */
+       0x0000,     /* R255 */
+       0x0003,     /* R256   - Chip Revision */
+       0x8004,     /* R257   - Control Interface */
+       0x0000,     /* R258 */
+       0x0000,     /* R259 */
+       0x0000,     /* R260 */
+       0x0000,     /* R261 */
+       0x0000,     /* R262 */
+       0x0000,     /* R263 */
+       0x0000,     /* R264 */
+       0x0000,     /* R265 */
+       0x0000,     /* R266 */
+       0x0000,     /* R267 */
+       0x0000,     /* R268 */
+       0x0000,     /* R269 */
+       0x0000,     /* R270 */
+       0x0000,     /* R271 */
+       0x0000,     /* R272   - Write Sequencer Ctrl (1) */
+       0x0000,     /* R273   - Write Sequencer Ctrl (2) */
+       0x0000,     /* R274 */
+       0x0000,     /* R275 */
+       0x0000,     /* R276 */
+       0x0000,     /* R277 */
+       0x0000,     /* R278 */
+       0x0000,     /* R279 */
+       0x0000,     /* R280 */
+       0x0000,     /* R281 */
+       0x0000,     /* R282 */
+       0x0000,     /* R283 */
+       0x0000,     /* R284 */
+       0x0000,     /* R285 */
+       0x0000,     /* R286 */
+       0x0000,     /* R287 */
+       0x0000,     /* R288 */
+       0x0000,     /* R289 */
+       0x0000,     /* R290 */
+       0x0000,     /* R291 */
+       0x0000,     /* R292 */
+       0x0000,     /* R293 */
+       0x0000,     /* R294 */
+       0x0000,     /* R295 */
+       0x0000,     /* R296 */
+       0x0000,     /* R297 */
+       0x0000,     /* R298 */
+       0x0000,     /* R299 */
+       0x0000,     /* R300 */
+       0x0000,     /* R301 */
+       0x0000,     /* R302 */
+       0x0000,     /* R303 */
+       0x0000,     /* R304 */
+       0x0000,     /* R305 */
+       0x0000,     /* R306 */
+       0x0000,     /* R307 */
+       0x0000,     /* R308 */
+       0x0000,     /* R309 */
+       0x0000,     /* R310 */
+       0x0000,     /* R311 */
+       0x0000,     /* R312 */
+       0x0000,     /* R313 */
+       0x0000,     /* R314 */
+       0x0000,     /* R315 */
+       0x0000,     /* R316 */
+       0x0000,     /* R317 */
+       0x0000,     /* R318 */
+       0x0000,     /* R319 */
+       0x0000,     /* R320 */
+       0x0000,     /* R321 */
+       0x0000,     /* R322 */
+       0x0000,     /* R323 */
+       0x0000,     /* R324 */
+       0x0000,     /* R325 */
+       0x0000,     /* R326 */
+       0x0000,     /* R327 */
+       0x0000,     /* R328 */
+       0x0000,     /* R329 */
+       0x0000,     /* R330 */
+       0x0000,     /* R331 */
+       0x0000,     /* R332 */
+       0x0000,     /* R333 */
+       0x0000,     /* R334 */
+       0x0000,     /* R335 */
+       0x0000,     /* R336 */
+       0x0000,     /* R337 */
+       0x0000,     /* R338 */
+       0x0000,     /* R339 */
+       0x0000,     /* R340 */
+       0x0000,     /* R341 */
+       0x0000,     /* R342 */
+       0x0000,     /* R343 */
+       0x0000,     /* R344 */
+       0x0000,     /* R345 */
+       0x0000,     /* R346 */
+       0x0000,     /* R347 */
+       0x0000,     /* R348 */
+       0x0000,     /* R349 */
+       0x0000,     /* R350 */
+       0x0000,     /* R351 */
+       0x0000,     /* R352 */
+       0x0000,     /* R353 */
+       0x0000,     /* R354 */
+       0x0000,     /* R355 */
+       0x0000,     /* R356 */
+       0x0000,     /* R357 */
+       0x0000,     /* R358 */
+       0x0000,     /* R359 */
+       0x0000,     /* R360 */
+       0x0000,     /* R361 */
+       0x0000,     /* R362 */
+       0x0000,     /* R363 */
+       0x0000,     /* R364 */
+       0x0000,     /* R365 */
+       0x0000,     /* R366 */
+       0x0000,     /* R367 */
+       0x0000,     /* R368 */
+       0x0000,     /* R369 */
+       0x0000,     /* R370 */
+       0x0000,     /* R371 */
+       0x0000,     /* R372 */
+       0x0000,     /* R373 */
+       0x0000,     /* R374 */
+       0x0000,     /* R375 */
+       0x0000,     /* R376 */
+       0x0000,     /* R377 */
+       0x0000,     /* R378 */
+       0x0000,     /* R379 */
+       0x0000,     /* R380 */
+       0x0000,     /* R381 */
+       0x0000,     /* R382 */
+       0x0000,     /* R383 */
+       0x0000,     /* R384 */
+       0x0000,     /* R385 */
+       0x0000,     /* R386 */
+       0x0000,     /* R387 */
+       0x0000,     /* R388 */
+       0x0000,     /* R389 */
+       0x0000,     /* R390 */
+       0x0000,     /* R391 */
+       0x0000,     /* R392 */
+       0x0000,     /* R393 */
+       0x0000,     /* R394 */
+       0x0000,     /* R395 */
+       0x0000,     /* R396 */
+       0x0000,     /* R397 */
+       0x0000,     /* R398 */
+       0x0000,     /* R399 */
+       0x0000,     /* R400 */
+       0x0000,     /* R401 */
+       0x0000,     /* R402 */
+       0x0000,     /* R403 */
+       0x0000,     /* R404 */
+       0x0000,     /* R405 */
+       0x0000,     /* R406 */
+       0x0000,     /* R407 */
+       0x0000,     /* R408 */
+       0x0000,     /* R409 */
+       0x0000,     /* R410 */
+       0x0000,     /* R411 */
+       0x0000,     /* R412 */
+       0x0000,     /* R413 */
+       0x0000,     /* R414 */
+       0x0000,     /* R415 */
+       0x0000,     /* R416 */
+       0x0000,     /* R417 */
+       0x0000,     /* R418 */
+       0x0000,     /* R419 */
+       0x0000,     /* R420 */
+       0x0000,     /* R421 */
+       0x0000,     /* R422 */
+       0x0000,     /* R423 */
+       0x0000,     /* R424 */
+       0x0000,     /* R425 */
+       0x0000,     /* R426 */
+       0x0000,     /* R427 */
+       0x0000,     /* R428 */
+       0x0000,     /* R429 */
+       0x0000,     /* R430 */
+       0x0000,     /* R431 */
+       0x0000,     /* R432 */
+       0x0000,     /* R433 */
+       0x0000,     /* R434 */
+       0x0000,     /* R435 */
+       0x0000,     /* R436 */
+       0x0000,     /* R437 */
+       0x0000,     /* R438 */
+       0x0000,     /* R439 */
+       0x0000,     /* R440 */
+       0x0000,     /* R441 */
+       0x0000,     /* R442 */
+       0x0000,     /* R443 */
+       0x0000,     /* R444 */
+       0x0000,     /* R445 */
+       0x0000,     /* R446 */
+       0x0000,     /* R447 */
+       0x0000,     /* R448 */
+       0x0000,     /* R449 */
+       0x0000,     /* R450 */
+       0x0000,     /* R451 */
+       0x0000,     /* R452 */
+       0x0000,     /* R453 */
+       0x0000,     /* R454 */
+       0x0000,     /* R455 */
+       0x0000,     /* R456 */
+       0x0000,     /* R457 */
+       0x0000,     /* R458 */
+       0x0000,     /* R459 */
+       0x0000,     /* R460 */
+       0x0000,     /* R461 */
+       0x0000,     /* R462 */
+       0x0000,     /* R463 */
+       0x0000,     /* R464 */
+       0x0000,     /* R465 */
+       0x0000,     /* R466 */
+       0x0000,     /* R467 */
+       0x0000,     /* R468 */
+       0x0000,     /* R469 */
+       0x0000,     /* R470 */
+       0x0000,     /* R471 */
+       0x0000,     /* R472 */
+       0x0000,     /* R473 */
+       0x0000,     /* R474 */
+       0x0000,     /* R475 */
+       0x0000,     /* R476 */
+       0x0000,     /* R477 */
+       0x0000,     /* R478 */
+       0x0000,     /* R479 */
+       0x0000,     /* R480 */
+       0x0000,     /* R481 */
+       0x0000,     /* R482 */
+       0x0000,     /* R483 */
+       0x0000,     /* R484 */
+       0x0000,     /* R485 */
+       0x0000,     /* R486 */
+       0x0000,     /* R487 */
+       0x0000,     /* R488 */
+       0x0000,     /* R489 */
+       0x0000,     /* R490 */
+       0x0000,     /* R491 */
+       0x0000,     /* R492 */
+       0x0000,     /* R493 */
+       0x0000,     /* R494 */
+       0x0000,     /* R495 */
+       0x0000,     /* R496 */
+       0x0000,     /* R497 */
+       0x0000,     /* R498 */
+       0x0000,     /* R499 */
+       0x0000,     /* R500 */
+       0x0000,     /* R501 */
+       0x0000,     /* R502 */
+       0x0000,     /* R503 */
+       0x0000,     /* R504 */
+       0x0000,     /* R505 */
+       0x0000,     /* R506 */
+       0x0000,     /* R507 */
+       0x0000,     /* R508 */
+       0x0000,     /* R509 */
+       0x0000,     /* R510 */
+       0x0000,     /* R511 */
+       0x0000,     /* R512   - AIF1 Clocking (1) */
+       0x0000,     /* R513   - AIF1 Clocking (2) */
+       0x0000,     /* R514 */
+       0x0000,     /* R515 */
+       0x0000,     /* R516   - AIF2 Clocking (1) */
+       0x0000,     /* R517   - AIF2 Clocking (2) */
+       0x0000,     /* R518 */
+       0x0000,     /* R519 */
+       0x0000,     /* R520   - Clocking (1) */
+       0x0000,     /* R521   - Clocking (2) */
+       0x0000,     /* R522 */
+       0x0000,     /* R523 */
+       0x0000,     /* R524 */
+       0x0000,     /* R525 */
+       0x0000,     /* R526 */
+       0x0000,     /* R527 */
+       0x0083,     /* R528   - AIF1 Rate */
+       0x0083,     /* R529   - AIF2 Rate */
+       0x0000,     /* R530   - Rate Status */
+       0x0000,     /* R531 */
+       0x0000,     /* R532 */
+       0x0000,     /* R533 */
+       0x0000,     /* R534 */
+       0x0000,     /* R535 */
+       0x0000,     /* R536 */
+       0x0000,     /* R537 */
+       0x0000,     /* R538 */
+       0x0000,     /* R539 */
+       0x0000,     /* R540 */
+       0x0000,     /* R541 */
+       0x0000,     /* R542 */
+       0x0000,     /* R543 */
+       0x0000,     /* R544   - FLL1 Control (1) */
+       0x0000,     /* R545   - FLL1 Control (2) */
+       0x0000,     /* R546   - FLL1 Control (3) */
+       0x0000,     /* R547   - FLL1 Control (4) */
+       0x0C80,     /* R548   - FLL1 Control (5) */
+       0x0000,     /* R549 */
+       0x0000,     /* R550 */
+       0x0000,     /* R551 */
+       0x0000,     /* R552 */
+       0x0000,     /* R553 */
+       0x0000,     /* R554 */
+       0x0000,     /* R555 */
+       0x0000,     /* R556 */
+       0x0000,     /* R557 */
+       0x0000,     /* R558 */
+       0x0000,     /* R559 */
+       0x0000,     /* R560 */
+       0x0000,     /* R561 */
+       0x0000,     /* R562 */
+       0x0000,     /* R563 */
+       0x0000,     /* R564 */
+       0x0000,     /* R565 */
+       0x0000,     /* R566 */
+       0x0000,     /* R567 */
+       0x0000,     /* R568 */
+       0x0000,     /* R569 */
+       0x0000,     /* R570 */
+       0x0000,     /* R571 */
+       0x0000,     /* R572 */
+       0x0000,     /* R573 */
+       0x0000,     /* R574 */
+       0x0000,     /* R575 */
+       0x0000,     /* R576   - FLL2 Control (1) */
+       0x0000,     /* R577   - FLL2 Control (2) */
+       0x0000,     /* R578   - FLL2 Control (3) */
+       0x0000,     /* R579   - FLL2 Control (4) */
+       0x0C80,     /* R580   - FLL2 Control (5) */
+       0x0000,     /* R581 */
+       0x0000,     /* R582 */
+       0x0000,     /* R583 */
+       0x0000,     /* R584 */
+       0x0000,     /* R585 */
+       0x0000,     /* R586 */
+       0x0000,     /* R587 */
+       0x0000,     /* R588 */
+       0x0000,     /* R589 */
+       0x0000,     /* R590 */
+       0x0000,     /* R591 */
+       0x0000,     /* R592 */
+       0x0000,     /* R593 */
+       0x0000,     /* R594 */
+       0x0000,     /* R595 */
+       0x0000,     /* R596 */
+       0x0000,     /* R597 */
+       0x0000,     /* R598 */
+       0x0000,     /* R599 */
+       0x0000,     /* R600 */
+       0x0000,     /* R601 */
+       0x0000,     /* R602 */
+       0x0000,     /* R603 */
+       0x0000,     /* R604 */
+       0x0000,     /* R605 */
+       0x0000,     /* R606 */
+       0x0000,     /* R607 */
+       0x0000,     /* R608 */
+       0x0000,     /* R609 */
+       0x0000,     /* R610 */
+       0x0000,     /* R611 */
+       0x0000,     /* R612 */
+       0x0000,     /* R613 */
+       0x0000,     /* R614 */
+       0x0000,     /* R615 */
+       0x0000,     /* R616 */
+       0x0000,     /* R617 */
+       0x0000,     /* R618 */
+       0x0000,     /* R619 */
+       0x0000,     /* R620 */
+       0x0000,     /* R621 */
+       0x0000,     /* R622 */
+       0x0000,     /* R623 */
+       0x0000,     /* R624 */
+       0x0000,     /* R625 */
+       0x0000,     /* R626 */
+       0x0000,     /* R627 */
+       0x0000,     /* R628 */
+       0x0000,     /* R629 */
+       0x0000,     /* R630 */
+       0x0000,     /* R631 */
+       0x0000,     /* R632 */
+       0x0000,     /* R633 */
+       0x0000,     /* R634 */
+       0x0000,     /* R635 */
+       0x0000,     /* R636 */
+       0x0000,     /* R637 */
+       0x0000,     /* R638 */
+       0x0000,     /* R639 */
+       0x0000,     /* R640 */
+       0x0000,     /* R641 */
+       0x0000,     /* R642 */
+       0x0000,     /* R643 */
+       0x0000,     /* R644 */
+       0x0000,     /* R645 */
+       0x0000,     /* R646 */
+       0x0000,     /* R647 */
+       0x0000,     /* R648 */
+       0x0000,     /* R649 */
+       0x0000,     /* R650 */
+       0x0000,     /* R651 */
+       0x0000,     /* R652 */
+       0x0000,     /* R653 */
+       0x0000,     /* R654 */
+       0x0000,     /* R655 */
+       0x0000,     /* R656 */
+       0x0000,     /* R657 */
+       0x0000,     /* R658 */
+       0x0000,     /* R659 */
+       0x0000,     /* R660 */
+       0x0000,     /* R661 */
+       0x0000,     /* R662 */
+       0x0000,     /* R663 */
+       0x0000,     /* R664 */
+       0x0000,     /* R665 */
+       0x0000,     /* R666 */
+       0x0000,     /* R667 */
+       0x0000,     /* R668 */
+       0x0000,     /* R669 */
+       0x0000,     /* R670 */
+       0x0000,     /* R671 */
+       0x0000,     /* R672 */
+       0x0000,     /* R673 */
+       0x0000,     /* R674 */
+       0x0000,     /* R675 */
+       0x0000,     /* R676 */
+       0x0000,     /* R677 */
+       0x0000,     /* R678 */
+       0x0000,     /* R679 */
+       0x0000,     /* R680 */
+       0x0000,     /* R681 */
+       0x0000,     /* R682 */
+       0x0000,     /* R683 */
+       0x0000,     /* R684 */
+       0x0000,     /* R685 */
+       0x0000,     /* R686 */
+       0x0000,     /* R687 */
+       0x0000,     /* R688 */
+       0x0000,     /* R689 */
+       0x0000,     /* R690 */
+       0x0000,     /* R691 */
+       0x0000,     /* R692 */
+       0x0000,     /* R693 */
+       0x0000,     /* R694 */
+       0x0000,     /* R695 */
+       0x0000,     /* R696 */
+       0x0000,     /* R697 */
+       0x0000,     /* R698 */
+       0x0000,     /* R699 */
+       0x0000,     /* R700 */
+       0x0000,     /* R701 */
+       0x0000,     /* R702 */
+       0x0000,     /* R703 */
+       0x0000,     /* R704 */
+       0x0000,     /* R705 */
+       0x0000,     /* R706 */
+       0x0000,     /* R707 */
+       0x0000,     /* R708 */
+       0x0000,     /* R709 */
+       0x0000,     /* R710 */
+       0x0000,     /* R711 */
+       0x0000,     /* R712 */
+       0x0000,     /* R713 */
+       0x0000,     /* R714 */
+       0x0000,     /* R715 */
+       0x0000,     /* R716 */
+       0x0000,     /* R717 */
+       0x0000,     /* R718 */
+       0x0000,     /* R719 */
+       0x0000,     /* R720 */
+       0x0000,     /* R721 */
+       0x0000,     /* R722 */
+       0x0000,     /* R723 */
+       0x0000,     /* R724 */
+       0x0000,     /* R725 */
+       0x0000,     /* R726 */
+       0x0000,     /* R727 */
+       0x0000,     /* R728 */
+       0x0000,     /* R729 */
+       0x0000,     /* R730 */
+       0x0000,     /* R731 */
+       0x0000,     /* R732 */
+       0x0000,     /* R733 */
+       0x0000,     /* R734 */
+       0x0000,     /* R735 */
+       0x0000,     /* R736 */
+       0x0000,     /* R737 */
+       0x0000,     /* R738 */
+       0x0000,     /* R739 */
+       0x0000,     /* R740 */
+       0x0000,     /* R741 */
+       0x0000,     /* R742 */
+       0x0000,     /* R743 */
+       0x0000,     /* R744 */
+       0x0000,     /* R745 */
+       0x0000,     /* R746 */
+       0x0000,     /* R747 */
+       0x0000,     /* R748 */
+       0x0000,     /* R749 */
+       0x0000,     /* R750 */
+       0x0000,     /* R751 */
+       0x0000,     /* R752 */
+       0x0000,     /* R753 */
+       0x0000,     /* R754 */
+       0x0000,     /* R755 */
+       0x0000,     /* R756 */
+       0x0000,     /* R757 */
+       0x0000,     /* R758 */
+       0x0000,     /* R759 */
+       0x0000,     /* R760 */
+       0x0000,     /* R761 */
+       0x0000,     /* R762 */
+       0x0000,     /* R763 */
+       0x0000,     /* R764 */
+       0x0000,     /* R765 */
+       0x0000,     /* R766 */
+       0x0000,     /* R767 */
+       0x4050,     /* R768   - AIF1 Control (1) */
+       0x4000,     /* R769   - AIF1 Control (2) */
+       0x0000,     /* R770   - AIF1 Master/Slave */
+       0x0040,     /* R771   - AIF1 BCLK */
+       0x0040,     /* R772   - AIF1ADC LRCLK */
+       0x0040,     /* R773   - AIF1DAC LRCLK */
+       0x0004,     /* R774   - AIF1DAC Data */
+       0x0100,     /* R775   - AIF1ADC Data */
+       0x0000,     /* R776 */
+       0x0000,     /* R777 */
+       0x0000,     /* R778 */
+       0x0000,     /* R779 */
+       0x0000,     /* R780 */
+       0x0000,     /* R781 */
+       0x0000,     /* R782 */
+       0x0000,     /* R783 */
+       0x4050,     /* R784   - AIF2 Control (1) */
+       0x4000,     /* R785   - AIF2 Control (2) */
+       0x0000,     /* R786   - AIF2 Master/Slave */
+       0x0040,     /* R787   - AIF2 BCLK */
+       0x0040,     /* R788   - AIF2ADC LRCLK */
+       0x0040,     /* R789   - AIF2DAC LRCLK */
+       0x0000,     /* R790   - AIF2DAC Data */
+       0x0000,     /* R791   - AIF2ADC Data */
+       0x0000,     /* R792 */
+       0x0000,     /* R793 */
+       0x0000,     /* R794 */
+       0x0000,     /* R795 */
+       0x0000,     /* R796 */
+       0x0000,     /* R797 */
+       0x0000,     /* R798 */
+       0x0000,     /* R799 */
+       0x0000,     /* R800 */
+       0x0000,     /* R801 */
+       0x0000,     /* R802 */
+       0x0000,     /* R803 */
+       0x0000,     /* R804 */
+       0x0000,     /* R805 */
+       0x0000,     /* R806 */
+       0x0000,     /* R807 */
+       0x0000,     /* R808 */
+       0x0000,     /* R809 */
+       0x0000,     /* R810 */
+       0x0000,     /* R811 */
+       0x0000,     /* R812 */
+       0x0000,     /* R813 */
+       0x0000,     /* R814 */
+       0x0000,     /* R815 */
+       0x0000,     /* R816 */
+       0x0000,     /* R817 */
+       0x0000,     /* R818 */
+       0x0000,     /* R819 */
+       0x0000,     /* R820 */
+       0x0000,     /* R821 */
+       0x0000,     /* R822 */
+       0x0000,     /* R823 */
+       0x0000,     /* R824 */
+       0x0000,     /* R825 */
+       0x0000,     /* R826 */
+       0x0000,     /* R827 */
+       0x0000,     /* R828 */
+       0x0000,     /* R829 */
+       0x0000,     /* R830 */
+       0x0000,     /* R831 */
+       0x0000,     /* R832 */
+       0x0000,     /* R833 */
+       0x0000,     /* R834 */
+       0x0000,     /* R835 */
+       0x0000,     /* R836 */
+       0x0000,     /* R837 */
+       0x0000,     /* R838 */
+       0x0000,     /* R839 */
+       0x0000,     /* R840 */
+       0x0000,     /* R841 */
+       0x0000,     /* R842 */
+       0x0000,     /* R843 */
+       0x0000,     /* R844 */
+       0x0000,     /* R845 */
+       0x0000,     /* R846 */
+       0x0000,     /* R847 */
+       0x0000,     /* R848 */
+       0x0000,     /* R849 */
+       0x0000,     /* R850 */
+       0x0000,     /* R851 */
+       0x0000,     /* R852 */
+       0x0000,     /* R853 */
+       0x0000,     /* R854 */
+       0x0000,     /* R855 */
+       0x0000,     /* R856 */
+       0x0000,     /* R857 */
+       0x0000,     /* R858 */
+       0x0000,     /* R859 */
+       0x0000,     /* R860 */
+       0x0000,     /* R861 */
+       0x0000,     /* R862 */
+       0x0000,     /* R863 */
+       0x0000,     /* R864 */
+       0x0000,     /* R865 */
+       0x0000,     /* R866 */
+       0x0000,     /* R867 */
+       0x0000,     /* R868 */
+       0x0000,     /* R869 */
+       0x0000,     /* R870 */
+       0x0000,     /* R871 */
+       0x0000,     /* R872 */
+       0x0000,     /* R873 */
+       0x0000,     /* R874 */
+       0x0000,     /* R875 */
+       0x0000,     /* R876 */
+       0x0000,     /* R877 */
+       0x0000,     /* R878 */
+       0x0000,     /* R879 */
+       0x0000,     /* R880 */
+       0x0000,     /* R881 */
+       0x0000,     /* R882 */
+       0x0000,     /* R883 */
+       0x0000,     /* R884 */
+       0x0000,     /* R885 */
+       0x0000,     /* R886 */
+       0x0000,     /* R887 */
+       0x0000,     /* R888 */
+       0x0000,     /* R889 */
+       0x0000,     /* R890 */
+       0x0000,     /* R891 */
+       0x0000,     /* R892 */
+       0x0000,     /* R893 */
+       0x0000,     /* R894 */
+       0x0000,     /* R895 */
+       0x0000,     /* R896 */
+       0x0000,     /* R897 */
+       0x0000,     /* R898 */
+       0x0000,     /* R899 */
+       0x0000,     /* R900 */
+       0x0000,     /* R901 */
+       0x0000,     /* R902 */
+       0x0000,     /* R903 */
+       0x0000,     /* R904 */
+       0x0000,     /* R905 */
+       0x0000,     /* R906 */
+       0x0000,     /* R907 */
+       0x0000,     /* R908 */
+       0x0000,     /* R909 */
+       0x0000,     /* R910 */
+       0x0000,     /* R911 */
+       0x0000,     /* R912 */
+       0x0000,     /* R913 */
+       0x0000,     /* R914 */
+       0x0000,     /* R915 */
+       0x0000,     /* R916 */
+       0x0000,     /* R917 */
+       0x0000,     /* R918 */
+       0x0000,     /* R919 */
+       0x0000,     /* R920 */
+       0x0000,     /* R921 */
+       0x0000,     /* R922 */
+       0x0000,     /* R923 */
+       0x0000,     /* R924 */
+       0x0000,     /* R925 */
+       0x0000,     /* R926 */
+       0x0000,     /* R927 */
+       0x0000,     /* R928 */
+       0x0000,     /* R929 */
+       0x0000,     /* R930 */
+       0x0000,     /* R931 */
+       0x0000,     /* R932 */
+       0x0000,     /* R933 */
+       0x0000,     /* R934 */
+       0x0000,     /* R935 */
+       0x0000,     /* R936 */
+       0x0000,     /* R937 */
+       0x0000,     /* R938 */
+       0x0000,     /* R939 */
+       0x0000,     /* R940 */
+       0x0000,     /* R941 */
+       0x0000,     /* R942 */
+       0x0000,     /* R943 */
+       0x0000,     /* R944 */
+       0x0000,     /* R945 */
+       0x0000,     /* R946 */
+       0x0000,     /* R947 */
+       0x0000,     /* R948 */
+       0x0000,     /* R949 */
+       0x0000,     /* R950 */
+       0x0000,     /* R951 */
+       0x0000,     /* R952 */
+       0x0000,     /* R953 */
+       0x0000,     /* R954 */
+       0x0000,     /* R955 */
+       0x0000,     /* R956 */
+       0x0000,     /* R957 */
+       0x0000,     /* R958 */
+       0x0000,     /* R959 */
+       0x0000,     /* R960 */
+       0x0000,     /* R961 */
+       0x0000,     /* R962 */
+       0x0000,     /* R963 */
+       0x0000,     /* R964 */
+       0x0000,     /* R965 */
+       0x0000,     /* R966 */
+       0x0000,     /* R967 */
+       0x0000,     /* R968 */
+       0x0000,     /* R969 */
+       0x0000,     /* R970 */
+       0x0000,     /* R971 */
+       0x0000,     /* R972 */
+       0x0000,     /* R973 */
+       0x0000,     /* R974 */
+       0x0000,     /* R975 */
+       0x0000,     /* R976 */
+       0x0000,     /* R977 */
+       0x0000,     /* R978 */
+       0x0000,     /* R979 */
+       0x0000,     /* R980 */
+       0x0000,     /* R981 */
+       0x0000,     /* R982 */
+       0x0000,     /* R983 */
+       0x0000,     /* R984 */
+       0x0000,     /* R985 */
+       0x0000,     /* R986 */
+       0x0000,     /* R987 */
+       0x0000,     /* R988 */
+       0x0000,     /* R989 */
+       0x0000,     /* R990 */
+       0x0000,     /* R991 */
+       0x0000,     /* R992 */
+       0x0000,     /* R993 */
+       0x0000,     /* R994 */
+       0x0000,     /* R995 */
+       0x0000,     /* R996 */
+       0x0000,     /* R997 */
+       0x0000,     /* R998 */
+       0x0000,     /* R999 */
+       0x0000,     /* R1000 */
+       0x0000,     /* R1001 */
+       0x0000,     /* R1002 */
+       0x0000,     /* R1003 */
+       0x0000,     /* R1004 */
+       0x0000,     /* R1005 */
+       0x0000,     /* R1006 */
+       0x0000,     /* R1007 */
+       0x0000,     /* R1008 */
+       0x0000,     /* R1009 */
+       0x0000,     /* R1010 */
+       0x0000,     /* R1011 */
+       0x0000,     /* R1012 */
+       0x0000,     /* R1013 */
+       0x0000,     /* R1014 */
+       0x0000,     /* R1015 */
+       0x0000,     /* R1016 */
+       0x0000,     /* R1017 */
+       0x0000,     /* R1018 */
+       0x0000,     /* R1019 */
+       0x0000,     /* R1020 */
+       0x0000,     /* R1021 */
+       0x0000,     /* R1022 */
+       0x0000,     /* R1023 */
+       0x00C0,     /* R1024  - AIF1 ADC1 Left Volume */
+       0x00C0,     /* R1025  - AIF1 ADC1 Right Volume */
+       0x00C0,     /* R1026  - AIF1 DAC1 Left Volume */
+       0x00C0,     /* R1027  - AIF1 DAC1 Right Volume */
+       0x00C0,     /* R1028  - AIF1 ADC2 Left Volume */
+       0x00C0,     /* R1029  - AIF1 ADC2 Right Volume */
+       0x00C0,     /* R1030  - AIF1 DAC2 Left Volume */
+       0x00C0,     /* R1031  - AIF1 DAC2 Right Volume */
+       0x0000,     /* R1032 */
+       0x0000,     /* R1033 */
+       0x0000,     /* R1034 */
+       0x0000,     /* R1035 */
+       0x0000,     /* R1036 */
+       0x0000,     /* R1037 */
+       0x0000,     /* R1038 */
+       0x0000,     /* R1039 */
+       0x0000,     /* R1040  - AIF1 ADC1 Filters */
+       0x0000,     /* R1041  - AIF1 ADC2 Filters */
+       0x0000,     /* R1042 */
+       0x0000,     /* R1043 */
+       0x0000,     /* R1044 */
+       0x0000,     /* R1045 */
+       0x0000,     /* R1046 */
+       0x0000,     /* R1047 */
+       0x0000,     /* R1048 */
+       0x0000,     /* R1049 */
+       0x0000,     /* R1050 */
+       0x0000,     /* R1051 */
+       0x0000,     /* R1052 */
+       0x0000,     /* R1053 */
+       0x0000,     /* R1054 */
+       0x0000,     /* R1055 */
+       0x0200,     /* R1056  - AIF1 DAC1 Filters (1) */
+       0x0010,     /* R1057  - AIF1 DAC1 Filters (2) */
+       0x0200,     /* R1058  - AIF1 DAC2 Filters (1) */
+       0x0010,     /* R1059  - AIF1 DAC2 Filters (2) */
+       0x0000,     /* R1060 */
+       0x0000,     /* R1061 */
+       0x0000,     /* R1062 */
+       0x0000,     /* R1063 */
+       0x0000,     /* R1064 */
+       0x0000,     /* R1065 */
+       0x0000,     /* R1066 */
+       0x0000,     /* R1067 */
+       0x0000,     /* R1068 */
+       0x0000,     /* R1069 */
+       0x0000,     /* R1070 */
+       0x0000,     /* R1071 */
+       0x0000,     /* R1072 */
+       0x0000,     /* R1073 */
+       0x0000,     /* R1074 */
+       0x0000,     /* R1075 */
+       0x0000,     /* R1076 */
+       0x0000,     /* R1077 */
+       0x0000,     /* R1078 */
+       0x0000,     /* R1079 */
+       0x0000,     /* R1080 */
+       0x0000,     /* R1081 */
+       0x0000,     /* R1082 */
+       0x0000,     /* R1083 */
+       0x0000,     /* R1084 */
+       0x0000,     /* R1085 */
+       0x0000,     /* R1086 */
+       0x0000,     /* R1087 */
+       0x0098,     /* R1088  - AIF1 DRC1 (1) */
+       0x0845,     /* R1089  - AIF1 DRC1 (2) */
+       0x0000,     /* R1090  - AIF1 DRC1 (3) */
+       0x0000,     /* R1091  - AIF1 DRC1 (4) */
+       0x0000,     /* R1092  - AIF1 DRC1 (5) */
+       0x0000,     /* R1093 */
+       0x0000,     /* R1094 */
+       0x0000,     /* R1095 */
+       0x0000,     /* R1096 */
+       0x0000,     /* R1097 */
+       0x0000,     /* R1098 */
+       0x0000,     /* R1099 */
+       0x0000,     /* R1100 */
+       0x0000,     /* R1101 */
+       0x0000,     /* R1102 */
+       0x0000,     /* R1103 */
+       0x0098,     /* R1104  - AIF1 DRC2 (1) */
+       0x0845,     /* R1105  - AIF1 DRC2 (2) */
+       0x0000,     /* R1106  - AIF1 DRC2 (3) */
+       0x0000,     /* R1107  - AIF1 DRC2 (4) */
+       0x0000,     /* R1108  - AIF1 DRC2 (5) */
+       0x0000,     /* R1109 */
+       0x0000,     /* R1110 */
+       0x0000,     /* R1111 */
+       0x0000,     /* R1112 */
+       0x0000,     /* R1113 */
+       0x0000,     /* R1114 */
+       0x0000,     /* R1115 */
+       0x0000,     /* R1116 */
+       0x0000,     /* R1117 */
+       0x0000,     /* R1118 */
+       0x0000,     /* R1119 */
+       0x0000,     /* R1120 */
+       0x0000,     /* R1121 */
+       0x0000,     /* R1122 */
+       0x0000,     /* R1123 */
+       0x0000,     /* R1124 */
+       0x0000,     /* R1125 */
+       0x0000,     /* R1126 */
+       0x0000,     /* R1127 */
+       0x0000,     /* R1128 */
+       0x0000,     /* R1129 */
+       0x0000,     /* R1130 */
+       0x0000,     /* R1131 */
+       0x0000,     /* R1132 */
+       0x0000,     /* R1133 */
+       0x0000,     /* R1134 */
+       0x0000,     /* R1135 */
+       0x0000,     /* R1136 */
+       0x0000,     /* R1137 */
+       0x0000,     /* R1138 */
+       0x0000,     /* R1139 */
+       0x0000,     /* R1140 */
+       0x0000,     /* R1141 */
+       0x0000,     /* R1142 */
+       0x0000,     /* R1143 */
+       0x0000,     /* R1144 */
+       0x0000,     /* R1145 */
+       0x0000,     /* R1146 */
+       0x0000,     /* R1147 */
+       0x0000,     /* R1148 */
+       0x0000,     /* R1149 */
+       0x0000,     /* R1150 */
+       0x0000,     /* R1151 */
+       0x6318,     /* R1152  - AIF1 DAC1 EQ Gains (1) */
+       0x6300,     /* R1153  - AIF1 DAC1 EQ Gains (2) */
+       0x0FCA,     /* R1154  - AIF1 DAC1 EQ Band 1 A */
+       0x0400,     /* R1155  - AIF1 DAC1 EQ Band 1 B */
+       0x00D8,     /* R1156  - AIF1 DAC1 EQ Band 1 PG */
+       0x1EB5,     /* R1157  - AIF1 DAC1 EQ Band 2 A */
+       0xF145,     /* R1158  - AIF1 DAC1 EQ Band 2 B */
+       0x0B75,     /* R1159  - AIF1 DAC1 EQ Band 2 C */
+       0x01C5,     /* R1160  - AIF1 DAC1 EQ Band 2 PG */
+       0x1C58,     /* R1161  - AIF1 DAC1 EQ Band 3 A */
+       0xF373,     /* R1162  - AIF1 DAC1 EQ Band 3 B */
+       0x0A54,     /* R1163  - AIF1 DAC1 EQ Band 3 C */
+       0x0558,     /* R1164  - AIF1 DAC1 EQ Band 3 PG */
+       0x168E,     /* R1165  - AIF1 DAC1 EQ Band 4 A */
+       0xF829,     /* R1166  - AIF1 DAC1 EQ Band 4 B */
+       0x07AD,     /* R1167  - AIF1 DAC1 EQ Band 4 C */
+       0x1103,     /* R1168  - AIF1 DAC1 EQ Band 4 PG */
+       0x0564,     /* R1169  - AIF1 DAC1 EQ Band 5 A */
+       0x0559,     /* R1170  - AIF1 DAC1 EQ Band 5 B */
+       0x4000,     /* R1171  - AIF1 DAC1 EQ Band 5 PG */
+       0x0000,     /* R1172 */
+       0x0000,     /* R1173 */
+       0x0000,     /* R1174 */
+       0x0000,     /* R1175 */
+       0x0000,     /* R1176 */
+       0x0000,     /* R1177 */
+       0x0000,     /* R1178 */
+       0x0000,     /* R1179 */
+       0x0000,     /* R1180 */
+       0x0000,     /* R1181 */
+       0x0000,     /* R1182 */
+       0x0000,     /* R1183 */
+       0x6318,     /* R1184  - AIF1 DAC2 EQ Gains (1) */
+       0x6300,     /* R1185  - AIF1 DAC2 EQ Gains (2) */
+       0x0FCA,     /* R1186  - AIF1 DAC2 EQ Band 1 A */
+       0x0400,     /* R1187  - AIF1 DAC2 EQ Band 1 B */
+       0x00D8,     /* R1188  - AIF1 DAC2 EQ Band 1 PG */
+       0x1EB5,     /* R1189  - AIF1 DAC2 EQ Band 2 A */
+       0xF145,     /* R1190  - AIF1 DAC2 EQ Band 2 B */
+       0x0B75,     /* R1191  - AIF1 DAC2 EQ Band 2 C */
+       0x01C5,     /* R1192  - AIF1 DAC2 EQ Band 2 PG */
+       0x1C58,     /* R1193  - AIF1 DAC2 EQ Band 3 A */
+       0xF373,     /* R1194  - AIF1 DAC2 EQ Band 3 B */
+       0x0A54,     /* R1195  - AIF1 DAC2 EQ Band 3 C */
+       0x0558,     /* R1196  - AIF1 DAC2 EQ Band 3 PG */
+       0x168E,     /* R1197  - AIF1 DAC2 EQ Band 4 A */
+       0xF829,     /* R1198  - AIF1 DAC2 EQ Band 4 B */
+       0x07AD,     /* R1199  - AIF1 DAC2 EQ Band 4 C */
+       0x1103,     /* R1200  - AIF1 DAC2 EQ Band 4 PG */
+       0x0564,     /* R1201  - AIF1 DAC2 EQ Band 5 A */
+       0x0559,     /* R1202  - AIF1 DAC2 EQ Band 5 B */
+       0x4000,     /* R1203  - AIF1 DAC2 EQ Band 5 PG */
+       0x0000,     /* R1204 */
+       0x0000,     /* R1205 */
+       0x0000,     /* R1206 */
+       0x0000,     /* R1207 */
+       0x0000,     /* R1208 */
+       0x0000,     /* R1209 */
+       0x0000,     /* R1210 */
+       0x0000,     /* R1211 */
+       0x0000,     /* R1212 */
+       0x0000,     /* R1213 */
+       0x0000,     /* R1214 */
+       0x0000,     /* R1215 */
+       0x0000,     /* R1216 */
+       0x0000,     /* R1217 */
+       0x0000,     /* R1218 */
+       0x0000,     /* R1219 */
+       0x0000,     /* R1220 */
+       0x0000,     /* R1221 */
+       0x0000,     /* R1222 */
+       0x0000,     /* R1223 */
+       0x0000,     /* R1224 */
+       0x0000,     /* R1225 */
+       0x0000,     /* R1226 */
+       0x0000,     /* R1227 */
+       0x0000,     /* R1228 */
+       0x0000,     /* R1229 */
+       0x0000,     /* R1230 */
+       0x0000,     /* R1231 */
+       0x0000,     /* R1232 */
+       0x0000,     /* R1233 */
+       0x0000,     /* R1234 */
+       0x0000,     /* R1235 */
+       0x0000,     /* R1236 */
+       0x0000,     /* R1237 */
+       0x0000,     /* R1238 */
+       0x0000,     /* R1239 */
+       0x0000,     /* R1240 */
+       0x0000,     /* R1241 */
+       0x0000,     /* R1242 */
+       0x0000,     /* R1243 */
+       0x0000,     /* R1244 */
+       0x0000,     /* R1245 */
+       0x0000,     /* R1246 */
+       0x0000,     /* R1247 */
+       0x0000,     /* R1248 */
+       0x0000,     /* R1249 */
+       0x0000,     /* R1250 */
+       0x0000,     /* R1251 */
+       0x0000,     /* R1252 */
+       0x0000,     /* R1253 */
+       0x0000,     /* R1254 */
+       0x0000,     /* R1255 */
+       0x0000,     /* R1256 */
+       0x0000,     /* R1257 */
+       0x0000,     /* R1258 */
+       0x0000,     /* R1259 */
+       0x0000,     /* R1260 */
+       0x0000,     /* R1261 */
+       0x0000,     /* R1262 */
+       0x0000,     /* R1263 */
+       0x0000,     /* R1264 */
+       0x0000,     /* R1265 */
+       0x0000,     /* R1266 */
+       0x0000,     /* R1267 */
+       0x0000,     /* R1268 */
+       0x0000,     /* R1269 */
+       0x0000,     /* R1270 */
+       0x0000,     /* R1271 */
+       0x0000,     /* R1272 */
+       0x0000,     /* R1273 */
+       0x0000,     /* R1274 */
+       0x0000,     /* R1275 */
+       0x0000,     /* R1276 */
+       0x0000,     /* R1277 */
+       0x0000,     /* R1278 */
+       0x0000,     /* R1279 */
+       0x00C0,     /* R1280  - AIF2 ADC Left Volume */
+       0x00C0,     /* R1281  - AIF2 ADC Right Volume */
+       0x00C0,     /* R1282  - AIF2 DAC Left Volume */
+       0x00C0,     /* R1283  - AIF2 DAC Right Volume */
+       0x0000,     /* R1284 */
+       0x0000,     /* R1285 */
+       0x0000,     /* R1286 */
+       0x0000,     /* R1287 */
+       0x0000,     /* R1288 */
+       0x0000,     /* R1289 */
+       0x0000,     /* R1290 */
+       0x0000,     /* R1291 */
+       0x0000,     /* R1292 */
+       0x0000,     /* R1293 */
+       0x0000,     /* R1294 */
+       0x0000,     /* R1295 */
+       0x0000,     /* R1296  - AIF2 ADC Filters */
+       0x0000,     /* R1297 */
+       0x0000,     /* R1298 */
+       0x0000,     /* R1299 */
+       0x0000,     /* R1300 */
+       0x0000,     /* R1301 */
+       0x0000,     /* R1302 */
+       0x0000,     /* R1303 */
+       0x0000,     /* R1304 */
+       0x0000,     /* R1305 */
+       0x0000,     /* R1306 */
+       0x0000,     /* R1307 */
+       0x0000,     /* R1308 */
+       0x0000,     /* R1309 */
+       0x0000,     /* R1310 */
+       0x0000,     /* R1311 */
+       0x0200,     /* R1312  - AIF2 DAC Filters (1) */
+       0x0010,     /* R1313  - AIF2 DAC Filters (2) */
+       0x0000,     /* R1314 */
+       0x0000,     /* R1315 */
+       0x0000,     /* R1316 */
+       0x0000,     /* R1317 */
+       0x0000,     /* R1318 */
+       0x0000,     /* R1319 */
+       0x0000,     /* R1320 */
+       0x0000,     /* R1321 */
+       0x0000,     /* R1322 */
+       0x0000,     /* R1323 */
+       0x0000,     /* R1324 */
+       0x0000,     /* R1325 */
+       0x0000,     /* R1326 */
+       0x0000,     /* R1327 */
+       0x0000,     /* R1328 */
+       0x0000,     /* R1329 */
+       0x0000,     /* R1330 */
+       0x0000,     /* R1331 */
+       0x0000,     /* R1332 */
+       0x0000,     /* R1333 */
+       0x0000,     /* R1334 */
+       0x0000,     /* R1335 */
+       0x0000,     /* R1336 */
+       0x0000,     /* R1337 */
+       0x0000,     /* R1338 */
+       0x0000,     /* R1339 */
+       0x0000,     /* R1340 */
+       0x0000,     /* R1341 */
+       0x0000,     /* R1342 */
+       0x0000,     /* R1343 */
+       0x0098,     /* R1344  - AIF2 DRC (1) */
+       0x0845,     /* R1345  - AIF2 DRC (2) */
+       0x0000,     /* R1346  - AIF2 DRC (3) */
+       0x0000,     /* R1347  - AIF2 DRC (4) */
+       0x0000,     /* R1348  - AIF2 DRC (5) */
+       0x0000,     /* R1349 */
+       0x0000,     /* R1350 */
+       0x0000,     /* R1351 */
+       0x0000,     /* R1352 */
+       0x0000,     /* R1353 */
+       0x0000,     /* R1354 */
+       0x0000,     /* R1355 */
+       0x0000,     /* R1356 */
+       0x0000,     /* R1357 */
+       0x0000,     /* R1358 */
+       0x0000,     /* R1359 */
+       0x0000,     /* R1360 */
+       0x0000,     /* R1361 */
+       0x0000,     /* R1362 */
+       0x0000,     /* R1363 */
+       0x0000,     /* R1364 */
+       0x0000,     /* R1365 */
+       0x0000,     /* R1366 */
+       0x0000,     /* R1367 */
+       0x0000,     /* R1368 */
+       0x0000,     /* R1369 */
+       0x0000,     /* R1370 */
+       0x0000,     /* R1371 */
+       0x0000,     /* R1372 */
+       0x0000,     /* R1373 */
+       0x0000,     /* R1374 */
+       0x0000,     /* R1375 */
+       0x0000,     /* R1376 */
+       0x0000,     /* R1377 */
+       0x0000,     /* R1378 */
+       0x0000,     /* R1379 */
+       0x0000,     /* R1380 */
+       0x0000,     /* R1381 */
+       0x0000,     /* R1382 */
+       0x0000,     /* R1383 */
+       0x0000,     /* R1384 */
+       0x0000,     /* R1385 */
+       0x0000,     /* R1386 */
+       0x0000,     /* R1387 */
+       0x0000,     /* R1388 */
+       0x0000,     /* R1389 */
+       0x0000,     /* R1390 */
+       0x0000,     /* R1391 */
+       0x0000,     /* R1392 */
+       0x0000,     /* R1393 */
+       0x0000,     /* R1394 */
+       0x0000,     /* R1395 */
+       0x0000,     /* R1396 */
+       0x0000,     /* R1397 */
+       0x0000,     /* R1398 */
+       0x0000,     /* R1399 */
+       0x0000,     /* R1400 */
+       0x0000,     /* R1401 */
+       0x0000,     /* R1402 */
+       0x0000,     /* R1403 */
+       0x0000,     /* R1404 */
+       0x0000,     /* R1405 */
+       0x0000,     /* R1406 */
+       0x0000,     /* R1407 */
+       0x6318,     /* R1408  - AIF2 EQ Gains (1) */
+       0x6300,     /* R1409  - AIF2 EQ Gains (2) */
+       0x0FCA,     /* R1410  - AIF2 EQ Band 1 A */
+       0x0400,     /* R1411  - AIF2 EQ Band 1 B */
+       0x00D8,     /* R1412  - AIF2 EQ Band 1 PG */
+       0x1EB5,     /* R1413  - AIF2 EQ Band 2 A */
+       0xF145,     /* R1414  - AIF2 EQ Band 2 B */
+       0x0B75,     /* R1415  - AIF2 EQ Band 2 C */
+       0x01C5,     /* R1416  - AIF2 EQ Band 2 PG */
+       0x1C58,     /* R1417  - AIF2 EQ Band 3 A */
+       0xF373,     /* R1418  - AIF2 EQ Band 3 B */
+       0x0A54,     /* R1419  - AIF2 EQ Band 3 C */
+       0x0558,     /* R1420  - AIF2 EQ Band 3 PG */
+       0x168E,     /* R1421  - AIF2 EQ Band 4 A */
+       0xF829,     /* R1422  - AIF2 EQ Band 4 B */
+       0x07AD,     /* R1423  - AIF2 EQ Band 4 C */
+       0x1103,     /* R1424  - AIF2 EQ Band 4 PG */
+       0x0564,     /* R1425  - AIF2 EQ Band 5 A */
+       0x0559,     /* R1426  - AIF2 EQ Band 5 B */
+       0x4000,     /* R1427  - AIF2 EQ Band 5 PG */
+       0x0000,     /* R1428 */
+       0x0000,     /* R1429 */
+       0x0000,     /* R1430 */
+       0x0000,     /* R1431 */
+       0x0000,     /* R1432 */
+       0x0000,     /* R1433 */
+       0x0000,     /* R1434 */
+       0x0000,     /* R1435 */
+       0x0000,     /* R1436 */
+       0x0000,     /* R1437 */
+       0x0000,     /* R1438 */
+       0x0000,     /* R1439 */
+       0x0000,     /* R1440 */
+       0x0000,     /* R1441 */
+       0x0000,     /* R1442 */
+       0x0000,     /* R1443 */
+       0x0000,     /* R1444 */
+       0x0000,     /* R1445 */
+       0x0000,     /* R1446 */
+       0x0000,     /* R1447 */
+       0x0000,     /* R1448 */
+       0x0000,     /* R1449 */
+       0x0000,     /* R1450 */
+       0x0000,     /* R1451 */
+       0x0000,     /* R1452 */
+       0x0000,     /* R1453 */
+       0x0000,     /* R1454 */
+       0x0000,     /* R1455 */
+       0x0000,     /* R1456 */
+       0x0000,     /* R1457 */
+       0x0000,     /* R1458 */
+       0x0000,     /* R1459 */
+       0x0000,     /* R1460 */
+       0x0000,     /* R1461 */
+       0x0000,     /* R1462 */
+       0x0000,     /* R1463 */
+       0x0000,     /* R1464 */
+       0x0000,     /* R1465 */
+       0x0000,     /* R1466 */
+       0x0000,     /* R1467 */
+       0x0000,     /* R1468 */
+       0x0000,     /* R1469 */
+       0x0000,     /* R1470 */
+       0x0000,     /* R1471 */
+       0x0000,     /* R1472 */
+       0x0000,     /* R1473 */
+       0x0000,     /* R1474 */
+       0x0000,     /* R1475 */
+       0x0000,     /* R1476 */
+       0x0000,     /* R1477 */
+       0x0000,     /* R1478 */
+       0x0000,     /* R1479 */
+       0x0000,     /* R1480 */
+       0x0000,     /* R1481 */
+       0x0000,     /* R1482 */
+       0x0000,     /* R1483 */
+       0x0000,     /* R1484 */
+       0x0000,     /* R1485 */
+       0x0000,     /* R1486 */
+       0x0000,     /* R1487 */
+       0x0000,     /* R1488 */
+       0x0000,     /* R1489 */
+       0x0000,     /* R1490 */
+       0x0000,     /* R1491 */
+       0x0000,     /* R1492 */
+       0x0000,     /* R1493 */
+       0x0000,     /* R1494 */
+       0x0000,     /* R1495 */
+       0x0000,     /* R1496 */
+       0x0000,     /* R1497 */
+       0x0000,     /* R1498 */
+       0x0000,     /* R1499 */
+       0x0000,     /* R1500 */
+       0x0000,     /* R1501 */
+       0x0000,     /* R1502 */
+       0x0000,     /* R1503 */
+       0x0000,     /* R1504 */
+       0x0000,     /* R1505 */
+       0x0000,     /* R1506 */
+       0x0000,     /* R1507 */
+       0x0000,     /* R1508 */
+       0x0000,     /* R1509 */
+       0x0000,     /* R1510 */
+       0x0000,     /* R1511 */
+       0x0000,     /* R1512 */
+       0x0000,     /* R1513 */
+       0x0000,     /* R1514 */
+       0x0000,     /* R1515 */
+       0x0000,     /* R1516 */
+       0x0000,     /* R1517 */
+       0x0000,     /* R1518 */
+       0x0000,     /* R1519 */
+       0x0000,     /* R1520 */
+       0x0000,     /* R1521 */
+       0x0000,     /* R1522 */
+       0x0000,     /* R1523 */
+       0x0000,     /* R1524 */
+       0x0000,     /* R1525 */
+       0x0000,     /* R1526 */
+       0x0000,     /* R1527 */
+       0x0000,     /* R1528 */
+       0x0000,     /* R1529 */
+       0x0000,     /* R1530 */
+       0x0000,     /* R1531 */
+       0x0000,     /* R1532 */
+       0x0000,     /* R1533 */
+       0x0000,     /* R1534 */
+       0x0000,     /* R1535 */
+       0x0000,     /* R1536  - DAC1 Mixer Volumes */
+       0x0000,     /* R1537  - DAC1 Left Mixer Routing */
+       0x0000,     /* R1538  - DAC1 Right Mixer Routing */
+       0x0000,     /* R1539  - DAC2 Mixer Volumes */
+       0x0000,     /* R1540  - DAC2 Left Mixer Routing */
+       0x0000,     /* R1541  - DAC2 Right Mixer Routing */
+       0x0000,     /* R1542  - AIF1 ADC1 Left Mixer Routing */
+       0x0000,     /* R1543  - AIF1 ADC1 Right Mixer Routing */
+       0x0000,     /* R1544  - AIF1 ADC2 Left Mixer Routing */
+       0x0000,     /* R1545  - AIF1 ADC2 Right mixer Routing */
+       0x0000,     /* R1546 */
+       0x0000,     /* R1547 */
+       0x0000,     /* R1548 */
+       0x0000,     /* R1549 */
+       0x0000,     /* R1550 */
+       0x0000,     /* R1551 */
+       0x02C0,     /* R1552  - DAC1 Left Volume */
+       0x02C0,     /* R1553  - DAC1 Right Volume */
+       0x02C0,     /* R1554  - DAC2 Left Volume */
+       0x02C0,     /* R1555  - DAC2 Right Volume */
+       0x0000,     /* R1556  - DAC Softmute */
+       0x0000,     /* R1557 */
+       0x0000,     /* R1558 */
+       0x0000,     /* R1559 */
+       0x0000,     /* R1560 */
+       0x0000,     /* R1561 */
+       0x0000,     /* R1562 */
+       0x0000,     /* R1563 */
+       0x0000,     /* R1564 */
+       0x0000,     /* R1565 */
+       0x0000,     /* R1566 */
+       0x0000,     /* R1567 */
+       0x0002,     /* R1568  - Oversampling */
+       0x0000,     /* R1569  - Sidetone */
+};
index 4d3e6f1..247a6a9 100644 (file)
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <sound/core.h>
+#include <sound/jack.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 <trace/events/asoc.h>
 
 #include <linux/mfd/wm8994/core.h>
 #include <linux/mfd/wm8994/registers.h>
@@ -57,8 +59,6 @@ static int wm8994_retune_mobile_base[] = {
        WM8994_AIF2_EQ_GAINS_1,
 };
 
-#define WM8994_REG_CACHE_SIZE  0x621
-
 struct wm8994_micdet {
        struct snd_soc_jack *jack;
        int det;
@@ -71,7 +71,6 @@ struct wm8994_priv {
        enum snd_soc_control_type control_type;
        void *control_data;
        struct snd_soc_codec *codec;
-       u16 reg_cache[WM8994_REG_CACHE_SIZE + 1];
        int sysclk[2];
        int sysclk_rate[2];
        int mclk[2];
@@ -81,6 +80,8 @@ struct wm8994_priv {
        int dac_rates[2];
        int lrclk_shared[2];
 
+       int mbc_ena[3];
+
        /* Platform dependant DRC configuration */
        const char **drc_texts;
        int drc_cfg[WM8994_NUM_DRC];
@@ -92,1588 +93,22 @@ struct wm8994_priv {
        int retune_mobile_cfg[WM8994_NUM_EQ];
        struct soc_enum retune_mobile_enum;
 
+       /* Platform dependant MBC configuration */
+       int mbc_cfg;
+       const char **mbc_texts;
+       struct soc_enum mbc_enum;
+
        struct wm8994_micdet micdet[2];
 
+       wm8958_micdet_cb jack_cb;
+       void *jack_cb_data;
+       bool jack_is_mic;
+       bool jack_is_video;
+
        int revision;
        struct wm8994_pdata *pdata;
 };
 
-static const struct {
-       unsigned short readable;   /* Mask of readable bits */
-       unsigned short writable;   /* Mask of writable bits */
-} access_masks[] = {
-       { 0xFFFF, 0xFFFF }, /* R0     - Software Reset */
-       { 0x3B37, 0x3B37 }, /* R1     - Power Management (1) */
-       { 0x6BF0, 0x6BF0 }, /* R2     - Power Management (2) */
-       { 0x3FF0, 0x3FF0 }, /* R3     - Power Management (3) */
-       { 0x3F3F, 0x3F3F }, /* R4     - Power Management (4) */
-       { 0x3F0F, 0x3F0F }, /* R5     - Power Management (5) */
-       { 0x003F, 0x003F }, /* R6     - Power Management (6) */
-       { 0x0000, 0x0000 }, /* R7 */
-       { 0x0000, 0x0000 }, /* R8 */
-       { 0x0000, 0x0000 }, /* R9 */
-       { 0x0000, 0x0000 }, /* R10 */
-       { 0x0000, 0x0000 }, /* R11 */
-       { 0x0000, 0x0000 }, /* R12 */
-       { 0x0000, 0x0000 }, /* R13 */
-       { 0x0000, 0x0000 }, /* R14 */
-       { 0x0000, 0x0000 }, /* R15 */
-       { 0x0000, 0x0000 }, /* R16 */
-       { 0x0000, 0x0000 }, /* R17 */
-       { 0x0000, 0x0000 }, /* R18 */
-       { 0x0000, 0x0000 }, /* R19 */
-       { 0x0000, 0x0000 }, /* R20 */
-       { 0x01C0, 0x01C0 }, /* R21    - Input Mixer (1) */
-       { 0x0000, 0x0000 }, /* R22 */
-       { 0x0000, 0x0000 }, /* R23 */
-       { 0x00DF, 0x01DF }, /* R24    - Left Line Input 1&2 Volume */
-       { 0x00DF, 0x01DF }, /* R25    - Left Line Input 3&4 Volume */
-       { 0x00DF, 0x01DF }, /* R26    - Right Line Input 1&2 Volume */
-       { 0x00DF, 0x01DF }, /* R27    - Right Line Input 3&4 Volume */
-       { 0x00FF, 0x01FF }, /* R28    - Left Output Volume */
-       { 0x00FF, 0x01FF }, /* R29    - Right Output Volume */
-       { 0x0077, 0x0077 }, /* R30    - Line Outputs Volume */
-       { 0x0030, 0x0030 }, /* R31    - HPOUT2 Volume */
-       { 0x00FF, 0x01FF }, /* R32    - Left OPGA Volume */
-       { 0x00FF, 0x01FF }, /* R33    - Right OPGA Volume */
-       { 0x007F, 0x007F }, /* R34    - SPKMIXL Attenuation */
-       { 0x017F, 0x017F }, /* R35    - SPKMIXR Attenuation */
-       { 0x003F, 0x003F }, /* R36    - SPKOUT Mixers */
-       { 0x003F, 0x003F }, /* R37    - ClassD */
-       { 0x00FF, 0x01FF }, /* R38    - Speaker Volume Left */
-       { 0x00FF, 0x01FF }, /* R39    - Speaker Volume Right */
-       { 0x00FF, 0x00FF }, /* R40    - Input Mixer (2) */
-       { 0x01B7, 0x01B7 }, /* R41    - Input Mixer (3) */
-       { 0x01B7, 0x01B7 }, /* R42    - Input Mixer (4) */
-       { 0x01C7, 0x01C7 }, /* R43    - Input Mixer (5) */
-       { 0x01C7, 0x01C7 }, /* R44    - Input Mixer (6) */
-       { 0x01FF, 0x01FF }, /* R45    - Output Mixer (1) */
-       { 0x01FF, 0x01FF }, /* R46    - Output Mixer (2) */
-       { 0x0FFF, 0x0FFF }, /* R47    - Output Mixer (3) */
-       { 0x0FFF, 0x0FFF }, /* R48    - Output Mixer (4) */
-       { 0x0FFF, 0x0FFF }, /* R49    - Output Mixer (5) */
-       { 0x0FFF, 0x0FFF }, /* R50    - Output Mixer (6) */
-       { 0x0038, 0x0038 }, /* R51    - HPOUT2 Mixer */
-       { 0x0077, 0x0077 }, /* R52    - Line Mixer (1) */
-       { 0x0077, 0x0077 }, /* R53    - Line Mixer (2) */
-       { 0x03FF, 0x03FF }, /* R54    - Speaker Mixer */
-       { 0x00C1, 0x00C1 }, /* R55    - Additional Control */
-       { 0x00F0, 0x00F0 }, /* R56    - AntiPOP (1) */
-       { 0x01EF, 0x01EF }, /* R57    - AntiPOP (2) */
-       { 0x00FF, 0x00FF }, /* R58    - MICBIAS */
-       { 0x000F, 0x000F }, /* R59    - LDO 1 */
-       { 0x0007, 0x0007 }, /* R60    - LDO 2 */
-       { 0x0000, 0x0000 }, /* R61 */
-       { 0x0000, 0x0000 }, /* R62 */
-       { 0x0000, 0x0000 }, /* R63 */
-       { 0x0000, 0x0000 }, /* R64 */
-       { 0x0000, 0x0000 }, /* R65 */
-       { 0x0000, 0x0000 }, /* R66 */
-       { 0x0000, 0x0000 }, /* R67 */
-       { 0x0000, 0x0000 }, /* R68 */
-       { 0x0000, 0x0000 }, /* R69 */
-       { 0x0000, 0x0000 }, /* R70 */
-       { 0x0000, 0x0000 }, /* R71 */
-       { 0x0000, 0x0000 }, /* R72 */
-       { 0x0000, 0x0000 }, /* R73 */
-       { 0x0000, 0x0000 }, /* R74 */
-       { 0x0000, 0x0000 }, /* R75 */
-       { 0x8000, 0x8000 }, /* R76    - Charge Pump (1) */
-       { 0x0000, 0x0000 }, /* R77 */
-       { 0x0000, 0x0000 }, /* R78 */
-       { 0x0000, 0x0000 }, /* R79 */
-       { 0x0000, 0x0000 }, /* R80 */
-       { 0x0301, 0x0301 }, /* R81    - Class W (1) */
-       { 0x0000, 0x0000 }, /* R82 */
-       { 0x0000, 0x0000 }, /* R83 */
-       { 0x333F, 0x333F }, /* R84    - DC Servo (1) */
-       { 0x0FEF, 0x0FEF }, /* R85    - DC Servo (2) */
-       { 0x0000, 0x0000 }, /* R86 */
-       { 0xFFFF, 0xFFFF }, /* R87    - DC Servo (4) */
-       { 0x0333, 0x0000 }, /* R88    - DC Servo Readback */
-       { 0x0000, 0x0000 }, /* R89 */
-       { 0x0000, 0x0000 }, /* R90 */
-       { 0x0000, 0x0000 }, /* R91 */
-       { 0x0000, 0x0000 }, /* R92 */
-       { 0x0000, 0x0000 }, /* R93 */
-       { 0x0000, 0x0000 }, /* R94 */
-       { 0x0000, 0x0000 }, /* R95 */
-       { 0x00EE, 0x00EE }, /* R96    - Analogue HP (1) */
-       { 0x0000, 0x0000 }, /* R97 */
-       { 0x0000, 0x0000 }, /* R98 */
-       { 0x0000, 0x0000 }, /* R99 */
-       { 0x0000, 0x0000 }, /* R100 */
-       { 0x0000, 0x0000 }, /* R101 */
-       { 0x0000, 0x0000 }, /* R102 */
-       { 0x0000, 0x0000 }, /* R103 */
-       { 0x0000, 0x0000 }, /* R104 */
-       { 0x0000, 0x0000 }, /* R105 */
-       { 0x0000, 0x0000 }, /* R106 */
-       { 0x0000, 0x0000 }, /* R107 */
-       { 0x0000, 0x0000 }, /* R108 */
-       { 0x0000, 0x0000 }, /* R109 */
-       { 0x0000, 0x0000 }, /* R110 */
-       { 0x0000, 0x0000 }, /* R111 */
-       { 0x0000, 0x0000 }, /* R112 */
-       { 0x0000, 0x0000 }, /* R113 */
-       { 0x0000, 0x0000 }, /* R114 */
-       { 0x0000, 0x0000 }, /* R115 */
-       { 0x0000, 0x0000 }, /* R116 */
-       { 0x0000, 0x0000 }, /* R117 */
-       { 0x0000, 0x0000 }, /* R118 */
-       { 0x0000, 0x0000 }, /* R119 */
-       { 0x0000, 0x0000 }, /* R120 */
-       { 0x0000, 0x0000 }, /* R121 */
-       { 0x0000, 0x0000 }, /* R122 */
-       { 0x0000, 0x0000 }, /* R123 */
-       { 0x0000, 0x0000 }, /* R124 */
-       { 0x0000, 0x0000 }, /* R125 */
-       { 0x0000, 0x0000 }, /* R126 */
-       { 0x0000, 0x0000 }, /* R127 */
-       { 0x0000, 0x0000 }, /* R128 */
-       { 0x0000, 0x0000 }, /* R129 */
-       { 0x0000, 0x0000 }, /* R130 */
-       { 0x0000, 0x0000 }, /* R131 */
-       { 0x0000, 0x0000 }, /* R132 */
-       { 0x0000, 0x0000 }, /* R133 */
-       { 0x0000, 0x0000 }, /* R134 */
-       { 0x0000, 0x0000 }, /* R135 */
-       { 0x0000, 0x0000 }, /* R136 */
-       { 0x0000, 0x0000 }, /* R137 */
-       { 0x0000, 0x0000 }, /* R138 */
-       { 0x0000, 0x0000 }, /* R139 */
-       { 0x0000, 0x0000 }, /* R140 */
-       { 0x0000, 0x0000 }, /* R141 */
-       { 0x0000, 0x0000 }, /* R142 */
-       { 0x0000, 0x0000 }, /* R143 */
-       { 0x0000, 0x0000 }, /* R144 */
-       { 0x0000, 0x0000 }, /* R145 */
-       { 0x0000, 0x0000 }, /* R146 */
-       { 0x0000, 0x0000 }, /* R147 */
-       { 0x0000, 0x0000 }, /* R148 */
-       { 0x0000, 0x0000 }, /* R149 */
-       { 0x0000, 0x0000 }, /* R150 */
-       { 0x0000, 0x0000 }, /* R151 */
-       { 0x0000, 0x0000 }, /* R152 */
-       { 0x0000, 0x0000 }, /* R153 */
-       { 0x0000, 0x0000 }, /* R154 */
-       { 0x0000, 0x0000 }, /* R155 */
-       { 0x0000, 0x0000 }, /* R156 */
-       { 0x0000, 0x0000 }, /* R157 */
-       { 0x0000, 0x0000 }, /* R158 */
-       { 0x0000, 0x0000 }, /* R159 */
-       { 0x0000, 0x0000 }, /* R160 */
-       { 0x0000, 0x0000 }, /* R161 */
-       { 0x0000, 0x0000 }, /* R162 */
-       { 0x0000, 0x0000 }, /* R163 */
-       { 0x0000, 0x0000 }, /* R164 */
-       { 0x0000, 0x0000 }, /* R165 */
-       { 0x0000, 0x0000 }, /* R166 */
-       { 0x0000, 0x0000 }, /* R167 */
-       { 0x0000, 0x0000 }, /* R168 */
-       { 0x0000, 0x0000 }, /* R169 */
-       { 0x0000, 0x0000 }, /* R170 */
-       { 0x0000, 0x0000 }, /* R171 */
-       { 0x0000, 0x0000 }, /* R172 */
-       { 0x0000, 0x0000 }, /* R173 */
-       { 0x0000, 0x0000 }, /* R174 */
-       { 0x0000, 0x0000 }, /* R175 */
-       { 0x0000, 0x0000 }, /* R176 */
-       { 0x0000, 0x0000 }, /* R177 */
-       { 0x0000, 0x0000 }, /* R178 */
-       { 0x0000, 0x0000 }, /* R179 */
-       { 0x0000, 0x0000 }, /* R180 */
-       { 0x0000, 0x0000 }, /* R181 */
-       { 0x0000, 0x0000 }, /* R182 */
-       { 0x0000, 0x0000 }, /* R183 */
-       { 0x0000, 0x0000 }, /* R184 */
-       { 0x0000, 0x0000 }, /* R185 */
-       { 0x0000, 0x0000 }, /* R186 */
-       { 0x0000, 0x0000 }, /* R187 */
-       { 0x0000, 0x0000 }, /* R188 */
-       { 0x0000, 0x0000 }, /* R189 */
-       { 0x0000, 0x0000 }, /* R190 */
-       { 0x0000, 0x0000 }, /* R191 */
-       { 0x0000, 0x0000 }, /* R192 */
-       { 0x0000, 0x0000 }, /* R193 */
-       { 0x0000, 0x0000 }, /* R194 */
-       { 0x0000, 0x0000 }, /* R195 */
-       { 0x0000, 0x0000 }, /* R196 */
-       { 0x0000, 0x0000 }, /* R197 */
-       { 0x0000, 0x0000 }, /* R198 */
-       { 0x0000, 0x0000 }, /* R199 */
-       { 0x0000, 0x0000 }, /* R200 */
-       { 0x0000, 0x0000 }, /* R201 */
-       { 0x0000, 0x0000 }, /* R202 */
-       { 0x0000, 0x0000 }, /* R203 */
-       { 0x0000, 0x0000 }, /* R204 */
-       { 0x0000, 0x0000 }, /* R205 */
-       { 0x0000, 0x0000 }, /* R206 */
-       { 0x0000, 0x0000 }, /* R207 */
-       { 0x0000, 0x0000 }, /* R208 */
-       { 0x0000, 0x0000 }, /* R209 */
-       { 0x0000, 0x0000 }, /* R210 */
-       { 0x0000, 0x0000 }, /* R211 */
-       { 0x0000, 0x0000 }, /* R212 */
-       { 0x0000, 0x0000 }, /* R213 */
-       { 0x0000, 0x0000 }, /* R214 */
-       { 0x0000, 0x0000 }, /* R215 */
-       { 0x0000, 0x0000 }, /* R216 */
-       { 0x0000, 0x0000 }, /* R217 */
-       { 0x0000, 0x0000 }, /* R218 */
-       { 0x0000, 0x0000 }, /* R219 */
-       { 0x0000, 0x0000 }, /* R220 */
-       { 0x0000, 0x0000 }, /* R221 */
-       { 0x0000, 0x0000 }, /* R222 */
-       { 0x0000, 0x0000 }, /* R223 */
-       { 0x0000, 0x0000 }, /* R224 */
-       { 0x0000, 0x0000 }, /* R225 */
-       { 0x0000, 0x0000 }, /* R226 */
-       { 0x0000, 0x0000 }, /* R227 */
-       { 0x0000, 0x0000 }, /* R228 */
-       { 0x0000, 0x0000 }, /* R229 */
-       { 0x0000, 0x0000 }, /* R230 */
-       { 0x0000, 0x0000 }, /* R231 */
-       { 0x0000, 0x0000 }, /* R232 */
-       { 0x0000, 0x0000 }, /* R233 */
-       { 0x0000, 0x0000 }, /* R234 */
-       { 0x0000, 0x0000 }, /* R235 */
-       { 0x0000, 0x0000 }, /* R236 */
-       { 0x0000, 0x0000 }, /* R237 */
-       { 0x0000, 0x0000 }, /* R238 */
-       { 0x0000, 0x0000 }, /* R239 */
-       { 0x0000, 0x0000 }, /* R240 */
-       { 0x0000, 0x0000 }, /* R241 */
-       { 0x0000, 0x0000 }, /* R242 */
-       { 0x0000, 0x0000 }, /* R243 */
-       { 0x0000, 0x0000 }, /* R244 */
-       { 0x0000, 0x0000 }, /* R245 */
-       { 0x0000, 0x0000 }, /* R246 */
-       { 0x0000, 0x0000 }, /* R247 */
-       { 0x0000, 0x0000 }, /* R248 */
-       { 0x0000, 0x0000 }, /* R249 */
-       { 0x0000, 0x0000 }, /* R250 */
-       { 0x0000, 0x0000 }, /* R251 */
-       { 0x0000, 0x0000 }, /* R252 */
-       { 0x0000, 0x0000 }, /* R253 */
-       { 0x0000, 0x0000 }, /* R254 */
-       { 0x0000, 0x0000 }, /* R255 */
-       { 0x000F, 0x0000 }, /* R256   - Chip Revision */
-       { 0x0074, 0x0074 }, /* R257   - Control Interface */
-       { 0x0000, 0x0000 }, /* R258 */
-       { 0x0000, 0x0000 }, /* R259 */
-       { 0x0000, 0x0000 }, /* R260 */
-       { 0x0000, 0x0000 }, /* R261 */
-       { 0x0000, 0x0000 }, /* R262 */
-       { 0x0000, 0x0000 }, /* R263 */
-       { 0x0000, 0x0000 }, /* R264 */
-       { 0x0000, 0x0000 }, /* R265 */
-       { 0x0000, 0x0000 }, /* R266 */
-       { 0x0000, 0x0000 }, /* R267 */
-       { 0x0000, 0x0000 }, /* R268 */
-       { 0x0000, 0x0000 }, /* R269 */
-       { 0x0000, 0x0000 }, /* R270 */
-       { 0x0000, 0x0000 }, /* R271 */
-       { 0x807F, 0x837F }, /* R272   - Write Sequencer Ctrl (1) */
-       { 0x017F, 0x0000 }, /* R273   - Write Sequencer Ctrl (2) */
-       { 0x0000, 0x0000 }, /* R274 */
-       { 0x0000, 0x0000 }, /* R275 */
-       { 0x0000, 0x0000 }, /* R276 */
-       { 0x0000, 0x0000 }, /* R277 */
-       { 0x0000, 0x0000 }, /* R278 */
-       { 0x0000, 0x0000 }, /* R279 */
-       { 0x0000, 0x0000 }, /* R280 */
-       { 0x0000, 0x0000 }, /* R281 */
-       { 0x0000, 0x0000 }, /* R282 */
-       { 0x0000, 0x0000 }, /* R283 */
-       { 0x0000, 0x0000 }, /* R284 */
-       { 0x0000, 0x0000 }, /* R285 */
-       { 0x0000, 0x0000 }, /* R286 */
-       { 0x0000, 0x0000 }, /* R287 */
-       { 0x0000, 0x0000 }, /* R288 */
-       { 0x0000, 0x0000 }, /* R289 */
-       { 0x0000, 0x0000 }, /* R290 */
-       { 0x0000, 0x0000 }, /* R291 */
-       { 0x0000, 0x0000 }, /* R292 */
-       { 0x0000, 0x0000 }, /* R293 */
-       { 0x0000, 0x0000 }, /* R294 */
-       { 0x0000, 0x0000 }, /* R295 */
-       { 0x0000, 0x0000 }, /* R296 */
-       { 0x0000, 0x0000 }, /* R297 */
-       { 0x0000, 0x0000 }, /* R298 */
-       { 0x0000, 0x0000 }, /* R299 */
-       { 0x0000, 0x0000 }, /* R300 */
-       { 0x0000, 0x0000 }, /* R301 */
-       { 0x0000, 0x0000 }, /* R302 */
-       { 0x0000, 0x0000 }, /* R303 */
-       { 0x0000, 0x0000 }, /* R304 */
-       { 0x0000, 0x0000 }, /* R305 */
-       { 0x0000, 0x0000 }, /* R306 */
-       { 0x0000, 0x0000 }, /* R307 */
-       { 0x0000, 0x0000 }, /* R308 */
-       { 0x0000, 0x0000 }, /* R309 */
-       { 0x0000, 0x0000 }, /* R310 */
-       { 0x0000, 0x0000 }, /* R311 */
-       { 0x0000, 0x0000 }, /* R312 */
-       { 0x0000, 0x0000 }, /* R313 */
-       { 0x0000, 0x0000 }, /* R314 */
-       { 0x0000, 0x0000 }, /* R315 */
-       { 0x0000, 0x0000 }, /* R316 */
-       { 0x0000, 0x0000 }, /* R317 */
-       { 0x0000, 0x0000 }, /* R318 */
-       { 0x0000, 0x0000 }, /* R319 */
-       { 0x0000, 0x0000 }, /* R320 */
-       { 0x0000, 0x0000 }, /* R321 */
-       { 0x0000, 0x0000 }, /* R322 */
-       { 0x0000, 0x0000 }, /* R323 */
-       { 0x0000, 0x0000 }, /* R324 */
-       { 0x0000, 0x0000 }, /* R325 */
-       { 0x0000, 0x0000 }, /* R326 */
-       { 0x0000, 0x0000 }, /* R327 */
-       { 0x0000, 0x0000 }, /* R328 */
-       { 0x0000, 0x0000 }, /* R329 */
-       { 0x0000, 0x0000 }, /* R330 */
-       { 0x0000, 0x0000 }, /* R331 */
-       { 0x0000, 0x0000 }, /* R332 */
-       { 0x0000, 0x0000 }, /* R333 */
-       { 0x0000, 0x0000 }, /* R334 */
-       { 0x0000, 0x0000 }, /* R335 */
-       { 0x0000, 0x0000 }, /* R336 */
-       { 0x0000, 0x0000 }, /* R337 */
-       { 0x0000, 0x0000 }, /* R338 */
-       { 0x0000, 0x0000 }, /* R339 */
-       { 0x0000, 0x0000 }, /* R340 */
-       { 0x0000, 0x0000 }, /* R341 */
-       { 0x0000, 0x0000 }, /* R342 */
-       { 0x0000, 0x0000 }, /* R343 */
-       { 0x0000, 0x0000 }, /* R344 */
-       { 0x0000, 0x0000 }, /* R345 */
-       { 0x0000, 0x0000 }, /* R346 */
-       { 0x0000, 0x0000 }, /* R347 */
-       { 0x0000, 0x0000 }, /* R348 */
-       { 0x0000, 0x0000 }, /* R349 */
-       { 0x0000, 0x0000 }, /* R350 */
-       { 0x0000, 0x0000 }, /* R351 */
-       { 0x0000, 0x0000 }, /* R352 */
-       { 0x0000, 0x0000 }, /* R353 */
-       { 0x0000, 0x0000 }, /* R354 */
-       { 0x0000, 0x0000 }, /* R355 */
-       { 0x0000, 0x0000 }, /* R356 */
-       { 0x0000, 0x0000 }, /* R357 */
-       { 0x0000, 0x0000 }, /* R358 */
-       { 0x0000, 0x0000 }, /* R359 */
-       { 0x0000, 0x0000 }, /* R360 */
-       { 0x0000, 0x0000 }, /* R361 */
-       { 0x0000, 0x0000 }, /* R362 */
-       { 0x0000, 0x0000 }, /* R363 */
-       { 0x0000, 0x0000 }, /* R364 */
-       { 0x0000, 0x0000 }, /* R365 */
-       { 0x0000, 0x0000 }, /* R366 */
-       { 0x0000, 0x0000 }, /* R367 */
-       { 0x0000, 0x0000 }, /* R368 */
-       { 0x0000, 0x0000 }, /* R369 */
-       { 0x0000, 0x0000 }, /* R370 */
-       { 0x0000, 0x0000 }, /* R371 */
-       { 0x0000, 0x0000 }, /* R372 */
-       { 0x0000, 0x0000 }, /* R373 */
-       { 0x0000, 0x0000 }, /* R374 */
-       { 0x0000, 0x0000 }, /* R375 */
-       { 0x0000, 0x0000 }, /* R376 */
-       { 0x0000, 0x0000 }, /* R377 */
-       { 0x0000, 0x0000 }, /* R378 */
-       { 0x0000, 0x0000 }, /* R379 */
-       { 0x0000, 0x0000 }, /* R380 */
-       { 0x0000, 0x0000 }, /* R381 */
-       { 0x0000, 0x0000 }, /* R382 */
-       { 0x0000, 0x0000 }, /* R383 */
-       { 0x0000, 0x0000 }, /* R384 */
-       { 0x0000, 0x0000 }, /* R385 */
-       { 0x0000, 0x0000 }, /* R386 */
-       { 0x0000, 0x0000 }, /* R387 */
-       { 0x0000, 0x0000 }, /* R388 */
-       { 0x0000, 0x0000 }, /* R389 */
-       { 0x0000, 0x0000 }, /* R390 */
-       { 0x0000, 0x0000 }, /* R391 */
-       { 0x0000, 0x0000 }, /* R392 */
-       { 0x0000, 0x0000 }, /* R393 */
-       { 0x0000, 0x0000 }, /* R394 */
-       { 0x0000, 0x0000 }, /* R395 */
-       { 0x0000, 0x0000 }, /* R396 */
-       { 0x0000, 0x0000 }, /* R397 */
-       { 0x0000, 0x0000 }, /* R398 */
-       { 0x0000, 0x0000 }, /* R399 */
-       { 0x0000, 0x0000 }, /* R400 */
-       { 0x0000, 0x0000 }, /* R401 */
-       { 0x0000, 0x0000 }, /* R402 */
-       { 0x0000, 0x0000 }, /* R403 */
-       { 0x0000, 0x0000 }, /* R404 */
-       { 0x0000, 0x0000 }, /* R405 */
-       { 0x0000, 0x0000 }, /* R406 */
-       { 0x0000, 0x0000 }, /* R407 */
-       { 0x0000, 0x0000 }, /* R408 */
-       { 0x0000, 0x0000 }, /* R409 */
-       { 0x0000, 0x0000 }, /* R410 */
-       { 0x0000, 0x0000 }, /* R411 */
-       { 0x0000, 0x0000 }, /* R412 */
-       { 0x0000, 0x0000 }, /* R413 */
-       { 0x0000, 0x0000 }, /* R414 */
-       { 0x0000, 0x0000 }, /* R415 */
-       { 0x0000, 0x0000 }, /* R416 */
-       { 0x0000, 0x0000 }, /* R417 */
-       { 0x0000, 0x0000 }, /* R418 */
-       { 0x0000, 0x0000 }, /* R419 */
-       { 0x0000, 0x0000 }, /* R420 */
-       { 0x0000, 0x0000 }, /* R421 */
-       { 0x0000, 0x0000 }, /* R422 */
-       { 0x0000, 0x0000 }, /* R423 */
-       { 0x0000, 0x0000 }, /* R424 */
-       { 0x0000, 0x0000 }, /* R425 */
-       { 0x0000, 0x0000 }, /* R426 */
-       { 0x0000, 0x0000 }, /* R427 */
-       { 0x0000, 0x0000 }, /* R428 */
-       { 0x0000, 0x0000 }, /* R429 */
-       { 0x0000, 0x0000 }, /* R430 */
-       { 0x0000, 0x0000 }, /* R431 */
-       { 0x0000, 0x0000 }, /* R432 */
-       { 0x0000, 0x0000 }, /* R433 */
-       { 0x0000, 0x0000 }, /* R434 */
-       { 0x0000, 0x0000 }, /* R435 */
-       { 0x0000, 0x0000 }, /* R436 */
-       { 0x0000, 0x0000 }, /* R437 */
-       { 0x0000, 0x0000 }, /* R438 */
-       { 0x0000, 0x0000 }, /* R439 */
-       { 0x0000, 0x0000 }, /* R440 */
-       { 0x0000, 0x0000 }, /* R441 */
-       { 0x0000, 0x0000 }, /* R442 */
-       { 0x0000, 0x0000 }, /* R443 */
-       { 0x0000, 0x0000 }, /* R444 */
-       { 0x0000, 0x0000 }, /* R445 */
-       { 0x0000, 0x0000 }, /* R446 */
-       { 0x0000, 0x0000 }, /* R447 */
-       { 0x0000, 0x0000 }, /* R448 */
-       { 0x0000, 0x0000 }, /* R449 */
-       { 0x0000, 0x0000 }, /* R450 */
-       { 0x0000, 0x0000 }, /* R451 */
-       { 0x0000, 0x0000 }, /* R452 */
-       { 0x0000, 0x0000 }, /* R453 */
-       { 0x0000, 0x0000 }, /* R454 */
-       { 0x0000, 0x0000 }, /* R455 */
-       { 0x0000, 0x0000 }, /* R456 */
-       { 0x0000, 0x0000 }, /* R457 */
-       { 0x0000, 0x0000 }, /* R458 */
-       { 0x0000, 0x0000 }, /* R459 */
-       { 0x0000, 0x0000 }, /* R460 */
-       { 0x0000, 0x0000 }, /* R461 */
-       { 0x0000, 0x0000 }, /* R462 */
-       { 0x0000, 0x0000 }, /* R463 */
-       { 0x0000, 0x0000 }, /* R464 */
-       { 0x0000, 0x0000 }, /* R465 */
-       { 0x0000, 0x0000 }, /* R466 */
-       { 0x0000, 0x0000 }, /* R467 */
-       { 0x0000, 0x0000 }, /* R468 */
-       { 0x0000, 0x0000 }, /* R469 */
-       { 0x0000, 0x0000 }, /* R470 */
-       { 0x0000, 0x0000 }, /* R471 */
-       { 0x0000, 0x0000 }, /* R472 */
-       { 0x0000, 0x0000 }, /* R473 */
-       { 0x0000, 0x0000 }, /* R474 */
-       { 0x0000, 0x0000 }, /* R475 */
-       { 0x0000, 0x0000 }, /* R476 */
-       { 0x0000, 0x0000 }, /* R477 */
-       { 0x0000, 0x0000 }, /* R478 */
-       { 0x0000, 0x0000 }, /* R479 */
-       { 0x0000, 0x0000 }, /* R480 */
-       { 0x0000, 0x0000 }, /* R481 */
-       { 0x0000, 0x0000 }, /* R482 */
-       { 0x0000, 0x0000 }, /* R483 */
-       { 0x0000, 0x0000 }, /* R484 */
-       { 0x0000, 0x0000 }, /* R485 */
-       { 0x0000, 0x0000 }, /* R486 */
-       { 0x0000, 0x0000 }, /* R487 */
-       { 0x0000, 0x0000 }, /* R488 */
-       { 0x0000, 0x0000 }, /* R489 */
-       { 0x0000, 0x0000 }, /* R490 */
-       { 0x0000, 0x0000 }, /* R491 */
-       { 0x0000, 0x0000 }, /* R492 */
-       { 0x0000, 0x0000 }, /* R493 */
-       { 0x0000, 0x0000 }, /* R494 */
-       { 0x0000, 0x0000 }, /* R495 */
-       { 0x0000, 0x0000 }, /* R496 */
-       { 0x0000, 0x0000 }, /* R497 */
-       { 0x0000, 0x0000 }, /* R498 */
-       { 0x0000, 0x0000 }, /* R499 */
-       { 0x0000, 0x0000 }, /* R500 */
-       { 0x0000, 0x0000 }, /* R501 */
-       { 0x0000, 0x0000 }, /* R502 */
-       { 0x0000, 0x0000 }, /* R503 */
-       { 0x0000, 0x0000 }, /* R504 */
-       { 0x0000, 0x0000 }, /* R505 */
-       { 0x0000, 0x0000 }, /* R506 */
-       { 0x0000, 0x0000 }, /* R507 */
-       { 0x0000, 0x0000 }, /* R508 */
-       { 0x0000, 0x0000 }, /* R509 */
-       { 0x0000, 0x0000 }, /* R510 */
-       { 0x0000, 0x0000 }, /* R511 */
-       { 0x001F, 0x001F }, /* R512   - AIF1 Clocking (1) */
-       { 0x003F, 0x003F }, /* R513   - AIF1 Clocking (2) */
-       { 0x0000, 0x0000 }, /* R514 */
-       { 0x0000, 0x0000 }, /* R515 */
-       { 0x001F, 0x001F }, /* R516   - AIF2 Clocking (1) */
-       { 0x003F, 0x003F }, /* R517   - AIF2 Clocking (2) */
-       { 0x0000, 0x0000 }, /* R518 */
-       { 0x0000, 0x0000 }, /* R519 */
-       { 0x001F, 0x001F }, /* R520   - Clocking (1) */
-       { 0x0777, 0x0777 }, /* R521   - Clocking (2) */
-       { 0x0000, 0x0000 }, /* R522 */
-       { 0x0000, 0x0000 }, /* R523 */
-       { 0x0000, 0x0000 }, /* R524 */
-       { 0x0000, 0x0000 }, /* R525 */
-       { 0x0000, 0x0000 }, /* R526 */
-       { 0x0000, 0x0000 }, /* R527 */
-       { 0x00FF, 0x00FF }, /* R528   - AIF1 Rate */
-       { 0x00FF, 0x00FF }, /* R529   - AIF2 Rate */
-       { 0x000F, 0x0000 }, /* R530   - Rate Status */
-       { 0x0000, 0x0000 }, /* R531 */
-       { 0x0000, 0x0000 }, /* R532 */
-       { 0x0000, 0x0000 }, /* R533 */
-       { 0x0000, 0x0000 }, /* R534 */
-       { 0x0000, 0x0000 }, /* R535 */
-       { 0x0000, 0x0000 }, /* R536 */
-       { 0x0000, 0x0000 }, /* R537 */
-       { 0x0000, 0x0000 }, /* R538 */
-       { 0x0000, 0x0000 }, /* R539 */
-       { 0x0000, 0x0000 }, /* R540 */
-       { 0x0000, 0x0000 }, /* R541 */
-       { 0x0000, 0x0000 }, /* R542 */
-       { 0x0000, 0x0000 }, /* R543 */
-       { 0x0007, 0x0007 }, /* R544   - FLL1 Control (1) */
-       { 0x3F77, 0x3F77 }, /* R545   - FLL1 Control (2) */
-       { 0xFFFF, 0xFFFF }, /* R546   - FLL1 Control (3) */
-       { 0x7FEF, 0x7FEF }, /* R547   - FLL1 Control (4) */
-       { 0x1FDB, 0x1FDB }, /* R548   - FLL1 Control (5) */
-       { 0x0000, 0x0000 }, /* R549 */
-       { 0x0000, 0x0000 }, /* R550 */
-       { 0x0000, 0x0000 }, /* R551 */
-       { 0x0000, 0x0000 }, /* R552 */
-       { 0x0000, 0x0000 }, /* R553 */
-       { 0x0000, 0x0000 }, /* R554 */
-       { 0x0000, 0x0000 }, /* R555 */
-       { 0x0000, 0x0000 }, /* R556 */
-       { 0x0000, 0x0000 }, /* R557 */
-       { 0x0000, 0x0000 }, /* R558 */
-       { 0x0000, 0x0000 }, /* R559 */
-       { 0x0000, 0x0000 }, /* R560 */
-       { 0x0000, 0x0000 }, /* R561 */
-       { 0x0000, 0x0000 }, /* R562 */
-       { 0x0000, 0x0000 }, /* R563 */
-       { 0x0000, 0x0000 }, /* R564 */
-       { 0x0000, 0x0000 }, /* R565 */
-       { 0x0000, 0x0000 }, /* R566 */
-       { 0x0000, 0x0000 }, /* R567 */
-       { 0x0000, 0x0000 }, /* R568 */
-       { 0x0000, 0x0000 }, /* R569 */
-       { 0x0000, 0x0000 }, /* R570 */
-       { 0x0000, 0x0000 }, /* R571 */
-       { 0x0000, 0x0000 }, /* R572 */
-       { 0x0000, 0x0000 }, /* R573 */
-       { 0x0000, 0x0000 }, /* R574 */
-       { 0x0000, 0x0000 }, /* R575 */
-       { 0x0007, 0x0007 }, /* R576   - FLL2 Control (1) */
-       { 0x3F77, 0x3F77 }, /* R577   - FLL2 Control (2) */
-       { 0xFFFF, 0xFFFF }, /* R578   - FLL2 Control (3) */
-       { 0x7FEF, 0x7FEF }, /* R579   - FLL2 Control (4) */
-       { 0x1FDB, 0x1FDB }, /* R580   - FLL2 Control (5) */
-       { 0x0000, 0x0000 }, /* R581 */
-       { 0x0000, 0x0000 }, /* R582 */
-       { 0x0000, 0x0000 }, /* R583 */
-       { 0x0000, 0x0000 }, /* R584 */
-       { 0x0000, 0x0000 }, /* R585 */
-       { 0x0000, 0x0000 }, /* R586 */
-       { 0x0000, 0x0000 }, /* R587 */
-       { 0x0000, 0x0000 }, /* R588 */
-       { 0x0000, 0x0000 }, /* R589 */
-       { 0x0000, 0x0000 }, /* R590 */
-       { 0x0000, 0x0000 }, /* R591 */
-       { 0x0000, 0x0000 }, /* R592 */
-       { 0x0000, 0x0000 }, /* R593 */
-       { 0x0000, 0x0000 }, /* R594 */
-       { 0x0000, 0x0000 }, /* R595 */
-       { 0x0000, 0x0000 }, /* R596 */
-       { 0x0000, 0x0000 }, /* R597 */
-       { 0x0000, 0x0000 }, /* R598 */
-       { 0x0000, 0x0000 }, /* R599 */
-       { 0x0000, 0x0000 }, /* R600 */
-       { 0x0000, 0x0000 }, /* R601 */
-       { 0x0000, 0x0000 }, /* R602 */
-       { 0x0000, 0x0000 }, /* R603 */
-       { 0x0000, 0x0000 }, /* R604 */
-       { 0x0000, 0x0000 }, /* R605 */
-       { 0x0000, 0x0000 }, /* R606 */
-       { 0x0000, 0x0000 }, /* R607 */
-       { 0x0000, 0x0000 }, /* R608 */
-       { 0x0000, 0x0000 }, /* R609 */
-       { 0x0000, 0x0000 }, /* R610 */
-       { 0x0000, 0x0000 }, /* R611 */
-       { 0x0000, 0x0000 }, /* R612 */
-       { 0x0000, 0x0000 }, /* R613 */
-       { 0x0000, 0x0000 }, /* R614 */
-       { 0x0000, 0x0000 }, /* R615 */
-       { 0x0000, 0x0000 }, /* R616 */
-       { 0x0000, 0x0000 }, /* R617 */
-       { 0x0000, 0x0000 }, /* R618 */
-       { 0x0000, 0x0000 }, /* R619 */
-       { 0x0000, 0x0000 }, /* R620 */
-       { 0x0000, 0x0000 }, /* R621 */
-       { 0x0000, 0x0000 }, /* R622 */
-       { 0x0000, 0x0000 }, /* R623 */
-       { 0x0000, 0x0000 }, /* R624 */
-       { 0x0000, 0x0000 }, /* R625 */
-       { 0x0000, 0x0000 }, /* R626 */
-       { 0x0000, 0x0000 }, /* R627 */
-       { 0x0000, 0x0000 }, /* R628 */
-       { 0x0000, 0x0000 }, /* R629 */
-       { 0x0000, 0x0000 }, /* R630 */
-       { 0x0000, 0x0000 }, /* R631 */
-       { 0x0000, 0x0000 }, /* R632 */
-       { 0x0000, 0x0000 }, /* R633 */
-       { 0x0000, 0x0000 }, /* R634 */
-       { 0x0000, 0x0000 }, /* R635 */
-       { 0x0000, 0x0000 }, /* R636 */
-       { 0x0000, 0x0000 }, /* R637 */
-       { 0x0000, 0x0000 }, /* R638 */
-       { 0x0000, 0x0000 }, /* R639 */
-       { 0x0000, 0x0000 }, /* R640 */
-       { 0x0000, 0x0000 }, /* R641 */
-       { 0x0000, 0x0000 }, /* R642 */
-       { 0x0000, 0x0000 }, /* R643 */
-       { 0x0000, 0x0000 }, /* R644 */
-       { 0x0000, 0x0000 }, /* R645 */
-       { 0x0000, 0x0000 }, /* R646 */
-       { 0x0000, 0x0000 }, /* R647 */
-       { 0x0000, 0x0000 }, /* R648 */
-       { 0x0000, 0x0000 }, /* R649 */
-       { 0x0000, 0x0000 }, /* R650 */
-       { 0x0000, 0x0000 }, /* R651 */
-       { 0x0000, 0x0000 }, /* R652 */
-       { 0x0000, 0x0000 }, /* R653 */
-       { 0x0000, 0x0000 }, /* R654 */
-       { 0x0000, 0x0000 }, /* R655 */
-       { 0x0000, 0x0000 }, /* R656 */
-       { 0x0000, 0x0000 }, /* R657 */
-       { 0x0000, 0x0000 }, /* R658 */
-       { 0x0000, 0x0000 }, /* R659 */
-       { 0x0000, 0x0000 }, /* R660 */
-       { 0x0000, 0x0000 }, /* R661 */
-       { 0x0000, 0x0000 }, /* R662 */
-       { 0x0000, 0x0000 }, /* R663 */
-       { 0x0000, 0x0000 }, /* R664 */
-       { 0x0000, 0x0000 }, /* R665 */
-       { 0x0000, 0x0000 }, /* R666 */
-       { 0x0000, 0x0000 }, /* R667 */
-       { 0x0000, 0x0000 }, /* R668 */
-       { 0x0000, 0x0000 }, /* R669 */
-       { 0x0000, 0x0000 }, /* R670 */
-       { 0x0000, 0x0000 }, /* R671 */
-       { 0x0000, 0x0000 }, /* R672 */
-       { 0x0000, 0x0000 }, /* R673 */
-       { 0x0000, 0x0000 }, /* R674 */
-       { 0x0000, 0x0000 }, /* R675 */
-       { 0x0000, 0x0000 }, /* R676 */
-       { 0x0000, 0x0000 }, /* R677 */
-       { 0x0000, 0x0000 }, /* R678 */
-       { 0x0000, 0x0000 }, /* R679 */
-       { 0x0000, 0x0000 }, /* R680 */
-       { 0x0000, 0x0000 }, /* R681 */
-       { 0x0000, 0x0000 }, /* R682 */
-       { 0x0000, 0x0000 }, /* R683 */
-       { 0x0000, 0x0000 }, /* R684 */
-       { 0x0000, 0x0000 }, /* R685 */
-       { 0x0000, 0x0000 }, /* R686 */
-       { 0x0000, 0x0000 }, /* R687 */
-       { 0x0000, 0x0000 }, /* R688 */
-       { 0x0000, 0x0000 }, /* R689 */
-       { 0x0000, 0x0000 }, /* R690 */
-       { 0x0000, 0x0000 }, /* R691 */
-       { 0x0000, 0x0000 }, /* R692 */
-       { 0x0000, 0x0000 }, /* R693 */
-       { 0x0000, 0x0000 }, /* R694 */
-       { 0x0000, 0x0000 }, /* R695 */
-       { 0x0000, 0x0000 }, /* R696 */
-       { 0x0000, 0x0000 }, /* R697 */
-       { 0x0000, 0x0000 }, /* R698 */
-       { 0x0000, 0x0000 }, /* R699 */
-       { 0x0000, 0x0000 }, /* R700 */
-       { 0x0000, 0x0000 }, /* R701 */
-       { 0x0000, 0x0000 }, /* R702 */
-       { 0x0000, 0x0000 }, /* R703 */
-       { 0x0000, 0x0000 }, /* R704 */
-       { 0x0000, 0x0000 }, /* R705 */
-       { 0x0000, 0x0000 }, /* R706 */
-       { 0x0000, 0x0000 }, /* R707 */
-       { 0x0000, 0x0000 }, /* R708 */
-       { 0x0000, 0x0000 }, /* R709 */
-       { 0x0000, 0x0000 }, /* R710 */
-       { 0x0000, 0x0000 }, /* R711 */
-       { 0x0000, 0x0000 }, /* R712 */
-       { 0x0000, 0x0000 }, /* R713 */
-       { 0x0000, 0x0000 }, /* R714 */
-       { 0x0000, 0x0000 }, /* R715 */
-       { 0x0000, 0x0000 }, /* R716 */
-       { 0x0000, 0x0000 }, /* R717 */
-       { 0x0000, 0x0000 }, /* R718 */
-       { 0x0000, 0x0000 }, /* R719 */
-       { 0x0000, 0x0000 }, /* R720 */
-       { 0x0000, 0x0000 }, /* R721 */
-       { 0x0000, 0x0000 }, /* R722 */
-       { 0x0000, 0x0000 }, /* R723 */
-       { 0x0000, 0x0000 }, /* R724 */
-       { 0x0000, 0x0000 }, /* R725 */
-       { 0x0000, 0x0000 }, /* R726 */
-       { 0x0000, 0x0000 }, /* R727 */
-       { 0x0000, 0x0000 }, /* R728 */
-       { 0x0000, 0x0000 }, /* R729 */
-       { 0x0000, 0x0000 }, /* R730 */
-       { 0x0000, 0x0000 }, /* R731 */
-       { 0x0000, 0x0000 }, /* R732 */
-       { 0x0000, 0x0000 }, /* R733 */
-       { 0x0000, 0x0000 }, /* R734 */
-       { 0x0000, 0x0000 }, /* R735 */
-       { 0x0000, 0x0000 }, /* R736 */
-       { 0x0000, 0x0000 }, /* R737 */
-       { 0x0000, 0x0000 }, /* R738 */
-       { 0x0000, 0x0000 }, /* R739 */
-       { 0x0000, 0x0000 }, /* R740 */
-       { 0x0000, 0x0000 }, /* R741 */
-       { 0x0000, 0x0000 }, /* R742 */
-       { 0x0000, 0x0000 }, /* R743 */
-       { 0x0000, 0x0000 }, /* R744 */
-       { 0x0000, 0x0000 }, /* R745 */
-       { 0x0000, 0x0000 }, /* R746 */
-       { 0x0000, 0x0000 }, /* R747 */
-       { 0x0000, 0x0000 }, /* R748 */
-       { 0x0000, 0x0000 }, /* R749 */
-       { 0x0000, 0x0000 }, /* R750 */
-       { 0x0000, 0x0000 }, /* R751 */
-       { 0x0000, 0x0000 }, /* R752 */
-       { 0x0000, 0x0000 }, /* R753 */
-       { 0x0000, 0x0000 }, /* R754 */
-       { 0x0000, 0x0000 }, /* R755 */
-       { 0x0000, 0x0000 }, /* R756 */
-       { 0x0000, 0x0000 }, /* R757 */
-       { 0x0000, 0x0000 }, /* R758 */
-       { 0x0000, 0x0000 }, /* R759 */
-       { 0x0000, 0x0000 }, /* R760 */
-       { 0x0000, 0x0000 }, /* R761 */
-       { 0x0000, 0x0000 }, /* R762 */
-       { 0x0000, 0x0000 }, /* R763 */
-       { 0x0000, 0x0000 }, /* R764 */
-       { 0x0000, 0x0000 }, /* R765 */
-       { 0x0000, 0x0000 }, /* R766 */
-       { 0x0000, 0x0000 }, /* R767 */
-       { 0xE1F8, 0xE1F8 }, /* R768   - AIF1 Control (1) */
-       { 0xCD1F, 0xCD1F }, /* R769   - AIF1 Control (2) */
-       { 0xF000, 0xF000 }, /* R770   - AIF1 Master/Slave */
-       { 0x01F0, 0x01F0 }, /* R771   - AIF1 BCLK */
-       { 0x0FFF, 0x0FFF }, /* R772   - AIF1ADC LRCLK */
-       { 0x0FFF, 0x0FFF }, /* R773   - AIF1DAC LRCLK */
-       { 0x0003, 0x0003 }, /* R774   - AIF1DAC Data */
-       { 0x0003, 0x0003 }, /* R775   - AIF1ADC Data */
-       { 0x0000, 0x0000 }, /* R776 */
-       { 0x0000, 0x0000 }, /* R777 */
-       { 0x0000, 0x0000 }, /* R778 */
-       { 0x0000, 0x0000 }, /* R779 */
-       { 0x0000, 0x0000 }, /* R780 */
-       { 0x0000, 0x0000 }, /* R781 */
-       { 0x0000, 0x0000 }, /* R782 */
-       { 0x0000, 0x0000 }, /* R783 */
-       { 0xF1F8, 0xF1F8 }, /* R784   - AIF2 Control (1) */
-       { 0xFD1F, 0xFD1F }, /* R785   - AIF2 Control (2) */
-       { 0xF000, 0xF000 }, /* R786   - AIF2 Master/Slave */
-       { 0x01F0, 0x01F0 }, /* R787   - AIF2 BCLK */
-       { 0x0FFF, 0x0FFF }, /* R788   - AIF2ADC LRCLK */
-       { 0x0FFF, 0x0FFF }, /* R789   - AIF2DAC LRCLK */
-       { 0x0003, 0x0003 }, /* R790   - AIF2DAC Data */
-       { 0x0003, 0x0003 }, /* R791   - AIF2ADC Data */
-       { 0x0000, 0x0000 }, /* R792 */
-       { 0x0000, 0x0000 }, /* R793 */
-       { 0x0000, 0x0000 }, /* R794 */
-       { 0x0000, 0x0000 }, /* R795 */
-       { 0x0000, 0x0000 }, /* R796 */
-       { 0x0000, 0x0000 }, /* R797 */
-       { 0x0000, 0x0000 }, /* R798 */
-       { 0x0000, 0x0000 }, /* R799 */
-       { 0x0000, 0x0000 }, /* R800 */
-       { 0x0000, 0x0000 }, /* R801 */
-       { 0x0000, 0x0000 }, /* R802 */
-       { 0x0000, 0x0000 }, /* R803 */
-       { 0x0000, 0x0000 }, /* R804 */
-       { 0x0000, 0x0000 }, /* R805 */
-       { 0x0000, 0x0000 }, /* R806 */
-       { 0x0000, 0x0000 }, /* R807 */
-       { 0x0000, 0x0000 }, /* R808 */
-       { 0x0000, 0x0000 }, /* R809 */
-       { 0x0000, 0x0000 }, /* R810 */
-       { 0x0000, 0x0000 }, /* R811 */
-       { 0x0000, 0x0000 }, /* R812 */
-       { 0x0000, 0x0000 }, /* R813 */
-       { 0x0000, 0x0000 }, /* R814 */
-       { 0x0000, 0x0000 }, /* R815 */
-       { 0x0000, 0x0000 }, /* R816 */
-       { 0x0000, 0x0000 }, /* R817 */
-       { 0x0000, 0x0000 }, /* R818 */
-       { 0x0000, 0x0000 }, /* R819 */
-       { 0x0000, 0x0000 }, /* R820 */
-       { 0x0000, 0x0000 }, /* R821 */
-       { 0x0000, 0x0000 }, /* R822 */
-       { 0x0000, 0x0000 }, /* R823 */
-       { 0x0000, 0x0000 }, /* R824 */
-       { 0x0000, 0x0000 }, /* R825 */
-       { 0x0000, 0x0000 }, /* R826 */
-       { 0x0000, 0x0000 }, /* R827 */
-       { 0x0000, 0x0000 }, /* R828 */
-       { 0x0000, 0x0000 }, /* R829 */
-       { 0x0000, 0x0000 }, /* R830 */
-       { 0x0000, 0x0000 }, /* R831 */
-       { 0x0000, 0x0000 }, /* R832 */
-       { 0x0000, 0x0000 }, /* R833 */
-       { 0x0000, 0x0000 }, /* R834 */
-       { 0x0000, 0x0000 }, /* R835 */
-       { 0x0000, 0x0000 }, /* R836 */
-       { 0x0000, 0x0000 }, /* R837 */
-       { 0x0000, 0x0000 }, /* R838 */
-       { 0x0000, 0x0000 }, /* R839 */
-       { 0x0000, 0x0000 }, /* R840 */
-       { 0x0000, 0x0000 }, /* R841 */
-       { 0x0000, 0x0000 }, /* R842 */
-       { 0x0000, 0x0000 }, /* R843 */
-       { 0x0000, 0x0000 }, /* R844 */
-       { 0x0000, 0x0000 }, /* R845 */
-       { 0x0000, 0x0000 }, /* R846 */
-       { 0x0000, 0x0000 }, /* R847 */
-       { 0x0000, 0x0000 }, /* R848 */
-       { 0x0000, 0x0000 }, /* R849 */
-       { 0x0000, 0x0000 }, /* R850 */
-       { 0x0000, 0x0000 }, /* R851 */
-       { 0x0000, 0x0000 }, /* R852 */
-       { 0x0000, 0x0000 }, /* R853 */
-       { 0x0000, 0x0000 }, /* R854 */
-       { 0x0000, 0x0000 }, /* R855 */
-       { 0x0000, 0x0000 }, /* R856 */
-       { 0x0000, 0x0000 }, /* R857 */
-       { 0x0000, 0x0000 }, /* R858 */
-       { 0x0000, 0x0000 }, /* R859 */
-       { 0x0000, 0x0000 }, /* R860 */
-       { 0x0000, 0x0000 }, /* R861 */
-       { 0x0000, 0x0000 }, /* R862 */
-       { 0x0000, 0x0000 }, /* R863 */
-       { 0x0000, 0x0000 }, /* R864 */
-       { 0x0000, 0x0000 }, /* R865 */
-       { 0x0000, 0x0000 }, /* R866 */
-       { 0x0000, 0x0000 }, /* R867 */
-       { 0x0000, 0x0000 }, /* R868 */
-       { 0x0000, 0x0000 }, /* R869 */
-       { 0x0000, 0x0000 }, /* R870 */
-       { 0x0000, 0x0000 }, /* R871 */
-       { 0x0000, 0x0000 }, /* R872 */
-       { 0x0000, 0x0000 }, /* R873 */
-       { 0x0000, 0x0000 }, /* R874 */
-       { 0x0000, 0x0000 }, /* R875 */
-       { 0x0000, 0x0000 }, /* R876 */
-       { 0x0000, 0x0000 }, /* R877 */
-       { 0x0000, 0x0000 }, /* R878 */
-       { 0x0000, 0x0000 }, /* R879 */
-       { 0x0000, 0x0000 }, /* R880 */
-       { 0x0000, 0x0000 }, /* R881 */
-       { 0x0000, 0x0000 }, /* R882 */
-       { 0x0000, 0x0000 }, /* R883 */
-       { 0x0000, 0x0000 }, /* R884 */
-       { 0x0000, 0x0000 }, /* R885 */
-       { 0x0000, 0x0000 }, /* R886 */
-       { 0x0000, 0x0000 }, /* R887 */
-       { 0x0000, 0x0000 }, /* R888 */
-       { 0x0000, 0x0000 }, /* R889 */
-       { 0x0000, 0x0000 }, /* R890 */
-       { 0x0000, 0x0000 }, /* R891 */
-       { 0x0000, 0x0000 }, /* R892 */
-       { 0x0000, 0x0000 }, /* R893 */
-       { 0x0000, 0x0000 }, /* R894 */
-       { 0x0000, 0x0000 }, /* R895 */
-       { 0x0000, 0x0000 }, /* R896 */
-       { 0x0000, 0x0000 }, /* R897 */
-       { 0x0000, 0x0000 }, /* R898 */
-       { 0x0000, 0x0000 }, /* R899 */
-       { 0x0000, 0x0000 }, /* R900 */
-       { 0x0000, 0x0000 }, /* R901 */
-       { 0x0000, 0x0000 }, /* R902 */
-       { 0x0000, 0x0000 }, /* R903 */
-       { 0x0000, 0x0000 }, /* R904 */
-       { 0x0000, 0x0000 }, /* R905 */
-       { 0x0000, 0x0000 }, /* R906 */
-       { 0x0000, 0x0000 }, /* R907 */
-       { 0x0000, 0x0000 }, /* R908 */
-       { 0x0000, 0x0000 }, /* R909 */
-       { 0x0000, 0x0000 }, /* R910 */
-       { 0x0000, 0x0000 }, /* R911 */
-       { 0x0000, 0x0000 }, /* R912 */
-       { 0x0000, 0x0000 }, /* R913 */
-       { 0x0000, 0x0000 }, /* R914 */
-       { 0x0000, 0x0000 }, /* R915 */
-       { 0x0000, 0x0000 }, /* R916 */
-       { 0x0000, 0x0000 }, /* R917 */
-       { 0x0000, 0x0000 }, /* R918 */
-       { 0x0000, 0x0000 }, /* R919 */
-       { 0x0000, 0x0000 }, /* R920 */
-       { 0x0000, 0x0000 }, /* R921 */
-       { 0x0000, 0x0000 }, /* R922 */
-       { 0x0000, 0x0000 }, /* R923 */
-       { 0x0000, 0x0000 }, /* R924 */
-       { 0x0000, 0x0000 }, /* R925 */
-       { 0x0000, 0x0000 }, /* R926 */
-       { 0x0000, 0x0000 }, /* R927 */
-       { 0x0000, 0x0000 }, /* R928 */
-       { 0x0000, 0x0000 }, /* R929 */
-       { 0x0000, 0x0000 }, /* R930 */
-       { 0x0000, 0x0000 }, /* R931 */
-       { 0x0000, 0x0000 }, /* R932 */
-       { 0x0000, 0x0000 }, /* R933 */
-       { 0x0000, 0x0000 }, /* R934 */
-       { 0x0000, 0x0000 }, /* R935 */
-       { 0x0000, 0x0000 }, /* R936 */
-       { 0x0000, 0x0000 }, /* R937 */
-       { 0x0000, 0x0000 }, /* R938 */
-       { 0x0000, 0x0000 }, /* R939 */
-       { 0x0000, 0x0000 }, /* R940 */
-       { 0x0000, 0x0000 }, /* R941 */
-       { 0x0000, 0x0000 }, /* R942 */
-       { 0x0000, 0x0000 }, /* R943 */
-       { 0x0000, 0x0000 }, /* R944 */
-       { 0x0000, 0x0000 }, /* R945 */
-       { 0x0000, 0x0000 }, /* R946 */
-       { 0x0000, 0x0000 }, /* R947 */
-       { 0x0000, 0x0000 }, /* R948 */
-       { 0x0000, 0x0000 }, /* R949 */
-       { 0x0000, 0x0000 }, /* R950 */
-       { 0x0000, 0x0000 }, /* R951 */
-       { 0x0000, 0x0000 }, /* R952 */
-       { 0x0000, 0x0000 }, /* R953 */
-       { 0x0000, 0x0000 }, /* R954 */
-       { 0x0000, 0x0000 }, /* R955 */
-       { 0x0000, 0x0000 }, /* R956 */
-       { 0x0000, 0x0000 }, /* R957 */
-       { 0x0000, 0x0000 }, /* R958 */
-       { 0x0000, 0x0000 }, /* R959 */
-       { 0x0000, 0x0000 }, /* R960 */
-       { 0x0000, 0x0000 }, /* R961 */
-       { 0x0000, 0x0000 }, /* R962 */
-       { 0x0000, 0x0000 }, /* R963 */
-       { 0x0000, 0x0000 }, /* R964 */
-       { 0x0000, 0x0000 }, /* R965 */
-       { 0x0000, 0x0000 }, /* R966 */
-       { 0x0000, 0x0000 }, /* R967 */
-       { 0x0000, 0x0000 }, /* R968 */
-       { 0x0000, 0x0000 }, /* R969 */
-       { 0x0000, 0x0000 }, /* R970 */
-       { 0x0000, 0x0000 }, /* R971 */
-       { 0x0000, 0x0000 }, /* R972 */
-       { 0x0000, 0x0000 }, /* R973 */
-       { 0x0000, 0x0000 }, /* R974 */
-       { 0x0000, 0x0000 }, /* R975 */
-       { 0x0000, 0x0000 }, /* R976 */
-       { 0x0000, 0x0000 }, /* R977 */
-       { 0x0000, 0x0000 }, /* R978 */
-       { 0x0000, 0x0000 }, /* R979 */
-       { 0x0000, 0x0000 }, /* R980 */
-       { 0x0000, 0x0000 }, /* R981 */
-       { 0x0000, 0x0000 }, /* R982 */
-       { 0x0000, 0x0000 }, /* R983 */
-       { 0x0000, 0x0000 }, /* R984 */
-       { 0x0000, 0x0000 }, /* R985 */
-       { 0x0000, 0x0000 }, /* R986 */
-       { 0x0000, 0x0000 }, /* R987 */
-       { 0x0000, 0x0000 }, /* R988 */
-       { 0x0000, 0x0000 }, /* R989 */
-       { 0x0000, 0x0000 }, /* R990 */
-       { 0x0000, 0x0000 }, /* R991 */
-       { 0x0000, 0x0000 }, /* R992 */
-       { 0x0000, 0x0000 }, /* R993 */
-       { 0x0000, 0x0000 }, /* R994 */
-       { 0x0000, 0x0000 }, /* R995 */
-       { 0x0000, 0x0000 }, /* R996 */
-       { 0x0000, 0x0000 }, /* R997 */
-       { 0x0000, 0x0000 }, /* R998 */
-       { 0x0000, 0x0000 }, /* R999 */
-       { 0x0000, 0x0000 }, /* R1000 */
-       { 0x0000, 0x0000 }, /* R1001 */
-       { 0x0000, 0x0000 }, /* R1002 */
-       { 0x0000, 0x0000 }, /* R1003 */
-       { 0x0000, 0x0000 }, /* R1004 */
-       { 0x0000, 0x0000 }, /* R1005 */
-       { 0x0000, 0x0000 }, /* R1006 */
-       { 0x0000, 0x0000 }, /* R1007 */
-       { 0x0000, 0x0000 }, /* R1008 */
-       { 0x0000, 0x0000 }, /* R1009 */
-       { 0x0000, 0x0000 }, /* R1010 */
-       { 0x0000, 0x0000 }, /* R1011 */
-       { 0x0000, 0x0000 }, /* R1012 */
-       { 0x0000, 0x0000 }, /* R1013 */
-       { 0x0000, 0x0000 }, /* R1014 */
-       { 0x0000, 0x0000 }, /* R1015 */
-       { 0x0000, 0x0000 }, /* R1016 */
-       { 0x0000, 0x0000 }, /* R1017 */
-       { 0x0000, 0x0000 }, /* R1018 */
-       { 0x0000, 0x0000 }, /* R1019 */
-       { 0x0000, 0x0000 }, /* R1020 */
-       { 0x0000, 0x0000 }, /* R1021 */
-       { 0x0000, 0x0000 }, /* R1022 */
-       { 0x0000, 0x0000 }, /* R1023 */
-       { 0x00FF, 0x01FF }, /* R1024  - AIF1 ADC1 Left Volume */
-       { 0x00FF, 0x01FF }, /* R1025  - AIF1 ADC1 Right Volume */
-       { 0x00FF, 0x01FF }, /* R1026  - AIF1 DAC1 Left Volume */
-       { 0x00FF, 0x01FF }, /* R1027  - AIF1 DAC1 Right Volume */
-       { 0x00FF, 0x01FF }, /* R1028  - AIF1 ADC2 Left Volume */
-       { 0x00FF, 0x01FF }, /* R1029  - AIF1 ADC2 Right Volume */
-       { 0x00FF, 0x01FF }, /* R1030  - AIF1 DAC2 Left Volume */
-       { 0x00FF, 0x01FF }, /* R1031  - AIF1 DAC2 Right Volume */
-       { 0x0000, 0x0000 }, /* R1032 */
-       { 0x0000, 0x0000 }, /* R1033 */
-       { 0x0000, 0x0000 }, /* R1034 */
-       { 0x0000, 0x0000 }, /* R1035 */
-       { 0x0000, 0x0000 }, /* R1036 */
-       { 0x0000, 0x0000 }, /* R1037 */
-       { 0x0000, 0x0000 }, /* R1038 */
-       { 0x0000, 0x0000 }, /* R1039 */
-       { 0xF800, 0xF800 }, /* R1040  - AIF1 ADC1 Filters */
-       { 0x7800, 0x7800 }, /* R1041  - AIF1 ADC2 Filters */
-       { 0x0000, 0x0000 }, /* R1042 */
-       { 0x0000, 0x0000 }, /* R1043 */
-       { 0x0000, 0x0000 }, /* R1044 */
-       { 0x0000, 0x0000 }, /* R1045 */
-       { 0x0000, 0x0000 }, /* R1046 */
-       { 0x0000, 0x0000 }, /* R1047 */
-       { 0x0000, 0x0000 }, /* R1048 */
-       { 0x0000, 0x0000 }, /* R1049 */
-       { 0x0000, 0x0000 }, /* R1050 */
-       { 0x0000, 0x0000 }, /* R1051 */
-       { 0x0000, 0x0000 }, /* R1052 */
-       { 0x0000, 0x0000 }, /* R1053 */
-       { 0x0000, 0x0000 }, /* R1054 */
-       { 0x0000, 0x0000 }, /* R1055 */
-       { 0x02B6, 0x02B6 }, /* R1056  - AIF1 DAC1 Filters (1) */
-       { 0x3F00, 0x3F00 }, /* R1057  - AIF1 DAC1 Filters (2) */
-       { 0x02B6, 0x02B6 }, /* R1058  - AIF1 DAC2 Filters (1) */
-       { 0x3F00, 0x3F00 }, /* R1059  - AIF1 DAC2 Filters (2) */
-       { 0x0000, 0x0000 }, /* R1060 */
-       { 0x0000, 0x0000 }, /* R1061 */
-       { 0x0000, 0x0000 }, /* R1062 */
-       { 0x0000, 0x0000 }, /* R1063 */
-       { 0x0000, 0x0000 }, /* R1064 */
-       { 0x0000, 0x0000 }, /* R1065 */
-       { 0x0000, 0x0000 }, /* R1066 */
-       { 0x0000, 0x0000 }, /* R1067 */
-       { 0x0000, 0x0000 }, /* R1068 */
-       { 0x0000, 0x0000 }, /* R1069 */
-       { 0x0000, 0x0000 }, /* R1070 */
-       { 0x0000, 0x0000 }, /* R1071 */
-       { 0x0000, 0x0000 }, /* R1072 */
-       { 0x0000, 0x0000 }, /* R1073 */
-       { 0x0000, 0x0000 }, /* R1074 */
-       { 0x0000, 0x0000 }, /* R1075 */
-       { 0x0000, 0x0000 }, /* R1076 */
-       { 0x0000, 0x0000 }, /* R1077 */
-       { 0x0000, 0x0000 }, /* R1078 */
-       { 0x0000, 0x0000 }, /* R1079 */
-       { 0x0000, 0x0000 }, /* R1080 */
-       { 0x0000, 0x0000 }, /* R1081 */
-       { 0x0000, 0x0000 }, /* R1082 */
-       { 0x0000, 0x0000 }, /* R1083 */
-       { 0x0000, 0x0000 }, /* R1084 */
-       { 0x0000, 0x0000 }, /* R1085 */
-       { 0x0000, 0x0000 }, /* R1086 */
-       { 0x0000, 0x0000 }, /* R1087 */
-       { 0xFFFF, 0xFFFF }, /* R1088  - AIF1 DRC1 (1) */
-       { 0x1FFF, 0x1FFF }, /* R1089  - AIF1 DRC1 (2) */
-       { 0xFFFF, 0xFFFF }, /* R1090  - AIF1 DRC1 (3) */
-       { 0x07FF, 0x07FF }, /* R1091  - AIF1 DRC1 (4) */
-       { 0x03FF, 0x03FF }, /* R1092  - AIF1 DRC1 (5) */
-       { 0x0000, 0x0000 }, /* R1093 */
-       { 0x0000, 0x0000 }, /* R1094 */
-       { 0x0000, 0x0000 }, /* R1095 */
-       { 0x0000, 0x0000 }, /* R1096 */
-       { 0x0000, 0x0000 }, /* R1097 */
-       { 0x0000, 0x0000 }, /* R1098 */
-       { 0x0000, 0x0000 }, /* R1099 */
-       { 0x0000, 0x0000 }, /* R1100 */
-       { 0x0000, 0x0000 }, /* R1101 */
-       { 0x0000, 0x0000 }, /* R1102 */
-       { 0x0000, 0x0000 }, /* R1103 */
-       { 0xFFFF, 0xFFFF }, /* R1104  - AIF1 DRC2 (1) */
-       { 0x1FFF, 0x1FFF }, /* R1105  - AIF1 DRC2 (2) */
-       { 0xFFFF, 0xFFFF }, /* R1106  - AIF1 DRC2 (3) */
-       { 0x07FF, 0x07FF }, /* R1107  - AIF1 DRC2 (4) */
-       { 0x03FF, 0x03FF }, /* R1108  - AIF1 DRC2 (5) */
-       { 0x0000, 0x0000 }, /* R1109 */
-       { 0x0000, 0x0000 }, /* R1110 */
-       { 0x0000, 0x0000 }, /* R1111 */
-       { 0x0000, 0x0000 }, /* R1112 */
-       { 0x0000, 0x0000 }, /* R1113 */
-       { 0x0000, 0x0000 }, /* R1114 */
-       { 0x0000, 0x0000 }, /* R1115 */
-       { 0x0000, 0x0000 }, /* R1116 */
-       { 0x0000, 0x0000 }, /* R1117 */
-       { 0x0000, 0x0000 }, /* R1118 */
-       { 0x0000, 0x0000 }, /* R1119 */
-       { 0x0000, 0x0000 }, /* R1120 */
-       { 0x0000, 0x0000 }, /* R1121 */
-       { 0x0000, 0x0000 }, /* R1122 */
-       { 0x0000, 0x0000 }, /* R1123 */
-       { 0x0000, 0x0000 }, /* R1124 */
-       { 0x0000, 0x0000 }, /* R1125 */
-       { 0x0000, 0x0000 }, /* R1126 */
-       { 0x0000, 0x0000 }, /* R1127 */
-       { 0x0000, 0x0000 }, /* R1128 */
-       { 0x0000, 0x0000 }, /* R1129 */
-       { 0x0000, 0x0000 }, /* R1130 */
-       { 0x0000, 0x0000 }, /* R1131 */
-       { 0x0000, 0x0000 }, /* R1132 */
-       { 0x0000, 0x0000 }, /* R1133 */
-       { 0x0000, 0x0000 }, /* R1134 */
-       { 0x0000, 0x0000 }, /* R1135 */
-       { 0x0000, 0x0000 }, /* R1136 */
-       { 0x0000, 0x0000 }, /* R1137 */
-       { 0x0000, 0x0000 }, /* R1138 */
-       { 0x0000, 0x0000 }, /* R1139 */
-       { 0x0000, 0x0000 }, /* R1140 */
-       { 0x0000, 0x0000 }, /* R1141 */
-       { 0x0000, 0x0000 }, /* R1142 */
-       { 0x0000, 0x0000 }, /* R1143 */
-       { 0x0000, 0x0000 }, /* R1144 */
-       { 0x0000, 0x0000 }, /* R1145 */
-       { 0x0000, 0x0000 }, /* R1146 */
-       { 0x0000, 0x0000 }, /* R1147 */
-       { 0x0000, 0x0000 }, /* R1148 */
-       { 0x0000, 0x0000 }, /* R1149 */
-       { 0x0000, 0x0000 }, /* R1150 */
-       { 0x0000, 0x0000 }, /* R1151 */
-       { 0xFFFF, 0xFFFF }, /* R1152  - AIF1 DAC1 EQ Gains (1) */
-       { 0xFFC0, 0xFFC0 }, /* R1153  - AIF1 DAC1 EQ Gains (2) */
-       { 0xFFFF, 0xFFFF }, /* R1154  - AIF1 DAC1 EQ Band 1 A */
-       { 0xFFFF, 0xFFFF }, /* R1155  - AIF1 DAC1 EQ Band 1 B */
-       { 0xFFFF, 0xFFFF }, /* R1156  - AIF1 DAC1 EQ Band 1 PG */
-       { 0xFFFF, 0xFFFF }, /* R1157  - AIF1 DAC1 EQ Band 2 A */
-       { 0xFFFF, 0xFFFF }, /* R1158  - AIF1 DAC1 EQ Band 2 B */
-       { 0xFFFF, 0xFFFF }, /* R1159  - AIF1 DAC1 EQ Band 2 C */
-       { 0xFFFF, 0xFFFF }, /* R1160  - AIF1 DAC1 EQ Band 2 PG */
-       { 0xFFFF, 0xFFFF }, /* R1161  - AIF1 DAC1 EQ Band 3 A */
-       { 0xFFFF, 0xFFFF }, /* R1162  - AIF1 DAC1 EQ Band 3 B */
-       { 0xFFFF, 0xFFFF }, /* R1163  - AIF1 DAC1 EQ Band 3 C */
-       { 0xFFFF, 0xFFFF }, /* R1164  - AIF1 DAC1 EQ Band 3 PG */
-       { 0xFFFF, 0xFFFF }, /* R1165  - AIF1 DAC1 EQ Band 4 A */
-       { 0xFFFF, 0xFFFF }, /* R1166  - AIF1 DAC1 EQ Band 4 B */
-       { 0xFFFF, 0xFFFF }, /* R1167  - AIF1 DAC1 EQ Band 4 C */
-       { 0xFFFF, 0xFFFF }, /* R1168  - AIF1 DAC1 EQ Band 4 PG */
-       { 0xFFFF, 0xFFFF }, /* R1169  - AIF1 DAC1 EQ Band 5 A */
-       { 0xFFFF, 0xFFFF }, /* R1170  - AIF1 DAC1 EQ Band 5 B */
-       { 0xFFFF, 0xFFFF }, /* R1171  - AIF1 DAC1 EQ Band 5 PG */
-       { 0x0000, 0x0000 }, /* R1172 */
-       { 0x0000, 0x0000 }, /* R1173 */
-       { 0x0000, 0x0000 }, /* R1174 */
-       { 0x0000, 0x0000 }, /* R1175 */
-       { 0x0000, 0x0000 }, /* R1176 */
-       { 0x0000, 0x0000 }, /* R1177 */
-       { 0x0000, 0x0000 }, /* R1178 */
-       { 0x0000, 0x0000 }, /* R1179 */
-       { 0x0000, 0x0000 }, /* R1180 */
-       { 0x0000, 0x0000 }, /* R1181 */
-       { 0x0000, 0x0000 }, /* R1182 */
-       { 0x0000, 0x0000 }, /* R1183 */
-       { 0xFFFF, 0xFFFF }, /* R1184  - AIF1 DAC2 EQ Gains (1) */
-       { 0xFFC0, 0xFFC0 }, /* R1185  - AIF1 DAC2 EQ Gains (2) */
-       { 0xFFFF, 0xFFFF }, /* R1186  - AIF1 DAC2 EQ Band 1 A */
-       { 0xFFFF, 0xFFFF }, /* R1187  - AIF1 DAC2 EQ Band 1 B */
-       { 0xFFFF, 0xFFFF }, /* R1188  - AIF1 DAC2 EQ Band 1 PG */
-       { 0xFFFF, 0xFFFF }, /* R1189  - AIF1 DAC2 EQ Band 2 A */
-       { 0xFFFF, 0xFFFF }, /* R1190  - AIF1 DAC2 EQ Band 2 B */
-       { 0xFFFF, 0xFFFF }, /* R1191  - AIF1 DAC2 EQ Band 2 C */
-       { 0xFFFF, 0xFFFF }, /* R1192  - AIF1 DAC2 EQ Band 2 PG */
-       { 0xFFFF, 0xFFFF }, /* R1193  - AIF1 DAC2 EQ Band 3 A */
-       { 0xFFFF, 0xFFFF }, /* R1194  - AIF1 DAC2 EQ Band 3 B */
-       { 0xFFFF, 0xFFFF }, /* R1195  - AIF1 DAC2 EQ Band 3 C */
-       { 0xFFFF, 0xFFFF }, /* R1196  - AIF1 DAC2 EQ Band 3 PG */
-       { 0xFFFF, 0xFFFF }, /* R1197  - AIF1 DAC2 EQ Band 4 A */
-       { 0xFFFF, 0xFFFF }, /* R1198  - AIF1 DAC2 EQ Band 4 B */
-       { 0xFFFF, 0xFFFF }, /* R1199  - AIF1 DAC2 EQ Band 4 C */
-       { 0xFFFF, 0xFFFF }, /* R1200  - AIF1 DAC2 EQ Band 4 PG */
-       { 0xFFFF, 0xFFFF }, /* R1201  - AIF1 DAC2 EQ Band 5 A */
-       { 0xFFFF, 0xFFFF }, /* R1202  - AIF1 DAC2 EQ Band 5 B */
-       { 0xFFFF, 0xFFFF }, /* R1203  - AIF1 DAC2 EQ Band 5 PG */
-       { 0x0000, 0x0000 }, /* R1204 */
-       { 0x0000, 0x0000 }, /* R1205 */
-       { 0x0000, 0x0000 }, /* R1206 */
-       { 0x0000, 0x0000 }, /* R1207 */
-       { 0x0000, 0x0000 }, /* R1208 */
-       { 0x0000, 0x0000 }, /* R1209 */
-       { 0x0000, 0x0000 }, /* R1210 */
-       { 0x0000, 0x0000 }, /* R1211 */
-       { 0x0000, 0x0000 }, /* R1212 */
-       { 0x0000, 0x0000 }, /* R1213 */
-       { 0x0000, 0x0000 }, /* R1214 */
-       { 0x0000, 0x0000 }, /* R1215 */
-       { 0x0000, 0x0000 }, /* R1216 */
-       { 0x0000, 0x0000 }, /* R1217 */
-       { 0x0000, 0x0000 }, /* R1218 */
-       { 0x0000, 0x0000 }, /* R1219 */
-       { 0x0000, 0x0000 }, /* R1220 */
-       { 0x0000, 0x0000 }, /* R1221 */
-       { 0x0000, 0x0000 }, /* R1222 */
-       { 0x0000, 0x0000 }, /* R1223 */
-       { 0x0000, 0x0000 }, /* R1224 */
-       { 0x0000, 0x0000 }, /* R1225 */
-       { 0x0000, 0x0000 }, /* R1226 */
-       { 0x0000, 0x0000 }, /* R1227 */
-       { 0x0000, 0x0000 }, /* R1228 */
-       { 0x0000, 0x0000 }, /* R1229 */
-       { 0x0000, 0x0000 }, /* R1230 */
-       { 0x0000, 0x0000 }, /* R1231 */
-       { 0x0000, 0x0000 }, /* R1232 */
-       { 0x0000, 0x0000 }, /* R1233 */
-       { 0x0000, 0x0000 }, /* R1234 */
-       { 0x0000, 0x0000 }, /* R1235 */
-       { 0x0000, 0x0000 }, /* R1236 */
-       { 0x0000, 0x0000 }, /* R1237 */
-       { 0x0000, 0x0000 }, /* R1238 */
-       { 0x0000, 0x0000 }, /* R1239 */
-       { 0x0000, 0x0000 }, /* R1240 */
-       { 0x0000, 0x0000 }, /* R1241 */
-       { 0x0000, 0x0000 }, /* R1242 */
-       { 0x0000, 0x0000 }, /* R1243 */
-       { 0x0000, 0x0000 }, /* R1244 */
-       { 0x0000, 0x0000 }, /* R1245 */
-       { 0x0000, 0x0000 }, /* R1246 */
-       { 0x0000, 0x0000 }, /* R1247 */
-       { 0x0000, 0x0000 }, /* R1248 */
-       { 0x0000, 0x0000 }, /* R1249 */
-       { 0x0000, 0x0000 }, /* R1250 */
-       { 0x0000, 0x0000 }, /* R1251 */
-       { 0x0000, 0x0000 }, /* R1252 */
-       { 0x0000, 0x0000 }, /* R1253 */
-       { 0x0000, 0x0000 }, /* R1254 */
-       { 0x0000, 0x0000 }, /* R1255 */
-       { 0x0000, 0x0000 }, /* R1256 */
-       { 0x0000, 0x0000 }, /* R1257 */
-       { 0x0000, 0x0000 }, /* R1258 */
-       { 0x0000, 0x0000 }, /* R1259 */
-       { 0x0000, 0x0000 }, /* R1260 */
-       { 0x0000, 0x0000 }, /* R1261 */
-       { 0x0000, 0x0000 }, /* R1262 */
-       { 0x0000, 0x0000 }, /* R1263 */
-       { 0x0000, 0x0000 }, /* R1264 */
-       { 0x0000, 0x0000 }, /* R1265 */
-       { 0x0000, 0x0000 }, /* R1266 */
-       { 0x0000, 0x0000 }, /* R1267 */
-       { 0x0000, 0x0000 }, /* R1268 */
-       { 0x0000, 0x0000 }, /* R1269 */
-       { 0x0000, 0x0000 }, /* R1270 */
-       { 0x0000, 0x0000 }, /* R1271 */
-       { 0x0000, 0x0000 }, /* R1272 */
-       { 0x0000, 0x0000 }, /* R1273 */
-       { 0x0000, 0x0000 }, /* R1274 */
-       { 0x0000, 0x0000 }, /* R1275 */
-       { 0x0000, 0x0000 }, /* R1276 */
-       { 0x0000, 0x0000 }, /* R1277 */
-       { 0x0000, 0x0000 }, /* R1278 */
-       { 0x0000, 0x0000 }, /* R1279 */
-       { 0x00FF, 0x01FF }, /* R1280  - AIF2 ADC Left Volume */
-       { 0x00FF, 0x01FF }, /* R1281  - AIF2 ADC Right Volume */
-       { 0x00FF, 0x01FF }, /* R1282  - AIF2 DAC Left Volume */
-       { 0x00FF, 0x01FF }, /* R1283  - AIF2 DAC Right Volume */
-       { 0x0000, 0x0000 }, /* R1284 */
-       { 0x0000, 0x0000 }, /* R1285 */
-       { 0x0000, 0x0000 }, /* R1286 */
-       { 0x0000, 0x0000 }, /* R1287 */
-       { 0x0000, 0x0000 }, /* R1288 */
-       { 0x0000, 0x0000 }, /* R1289 */
-       { 0x0000, 0x0000 }, /* R1290 */
-       { 0x0000, 0x0000 }, /* R1291 */
-       { 0x0000, 0x0000 }, /* R1292 */
-       { 0x0000, 0x0000 }, /* R1293 */
-       { 0x0000, 0x0000 }, /* R1294 */
-       { 0x0000, 0x0000 }, /* R1295 */
-       { 0xF800, 0xF800 }, /* R1296  - AIF2 ADC Filters */
-       { 0x0000, 0x0000 }, /* R1297 */
-       { 0x0000, 0x0000 }, /* R1298 */
-       { 0x0000, 0x0000 }, /* R1299 */
-       { 0x0000, 0x0000 }, /* R1300 */
-       { 0x0000, 0x0000 }, /* R1301 */
-       { 0x0000, 0x0000 }, /* R1302 */
-       { 0x0000, 0x0000 }, /* R1303 */
-       { 0x0000, 0x0000 }, /* R1304 */
-       { 0x0000, 0x0000 }, /* R1305 */
-       { 0x0000, 0x0000 }, /* R1306 */
-       { 0x0000, 0x0000 }, /* R1307 */
-       { 0x0000, 0x0000 }, /* R1308 */
-       { 0x0000, 0x0000 }, /* R1309 */
-       { 0x0000, 0x0000 }, /* R1310 */
-       { 0x0000, 0x0000 }, /* R1311 */
-       { 0x02B6, 0x02B6 }, /* R1312  - AIF2 DAC Filters (1) */
-       { 0x3F00, 0x3F00 }, /* R1313  - AIF2 DAC Filters (2) */
-       { 0x0000, 0x0000 }, /* R1314 */
-       { 0x0000, 0x0000 }, /* R1315 */
-       { 0x0000, 0x0000 }, /* R1316 */
-       { 0x0000, 0x0000 }, /* R1317 */
-       { 0x0000, 0x0000 }, /* R1318 */
-       { 0x0000, 0x0000 }, /* R1319 */
-       { 0x0000, 0x0000 }, /* R1320 */
-       { 0x0000, 0x0000 }, /* R1321 */
-       { 0x0000, 0x0000 }, /* R1322 */
-       { 0x0000, 0x0000 }, /* R1323 */
-       { 0x0000, 0x0000 }, /* R1324 */
-       { 0x0000, 0x0000 }, /* R1325 */
-       { 0x0000, 0x0000 }, /* R1326 */
-       { 0x0000, 0x0000 }, /* R1327 */
-       { 0x0000, 0x0000 }, /* R1328 */
-       { 0x0000, 0x0000 }, /* R1329 */
-       { 0x0000, 0x0000 }, /* R1330 */
-       { 0x0000, 0x0000 }, /* R1331 */
-       { 0x0000, 0x0000 }, /* R1332 */
-       { 0x0000, 0x0000 }, /* R1333 */
-       { 0x0000, 0x0000 }, /* R1334 */
-       { 0x0000, 0x0000 }, /* R1335 */
-       { 0x0000, 0x0000 }, /* R1336 */
-       { 0x0000, 0x0000 }, /* R1337 */
-       { 0x0000, 0x0000 }, /* R1338 */
-       { 0x0000, 0x0000 }, /* R1339 */
-       { 0x0000, 0x0000 }, /* R1340 */
-       { 0x0000, 0x0000 }, /* R1341 */
-       { 0x0000, 0x0000 }, /* R1342 */
-       { 0x0000, 0x0000 }, /* R1343 */
-       { 0xFFFF, 0xFFFF }, /* R1344  - AIF2 DRC (1) */
-       { 0x1FFF, 0x1FFF }, /* R1345  - AIF2 DRC (2) */
-       { 0xFFFF, 0xFFFF }, /* R1346  - AIF2 DRC (3) */
-       { 0x07FF, 0x07FF }, /* R1347  - AIF2 DRC (4) */
-       { 0x03FF, 0x03FF }, /* R1348  - AIF2 DRC (5) */
-       { 0x0000, 0x0000 }, /* R1349 */
-       { 0x0000, 0x0000 }, /* R1350 */
-       { 0x0000, 0x0000 }, /* R1351 */
-       { 0x0000, 0x0000 }, /* R1352 */
-       { 0x0000, 0x0000 }, /* R1353 */
-       { 0x0000, 0x0000 }, /* R1354 */
-       { 0x0000, 0x0000 }, /* R1355 */
-       { 0x0000, 0x0000 }, /* R1356 */
-       { 0x0000, 0x0000 }, /* R1357 */
-       { 0x0000, 0x0000 }, /* R1358 */
-       { 0x0000, 0x0000 }, /* R1359 */
-       { 0x0000, 0x0000 }, /* R1360 */
-       { 0x0000, 0x0000 }, /* R1361 */
-       { 0x0000, 0x0000 }, /* R1362 */
-       { 0x0000, 0x0000 }, /* R1363 */
-       { 0x0000, 0x0000 }, /* R1364 */
-       { 0x0000, 0x0000 }, /* R1365 */
-       { 0x0000, 0x0000 }, /* R1366 */
-       { 0x0000, 0x0000 }, /* R1367 */
-       { 0x0000, 0x0000 }, /* R1368 */
-       { 0x0000, 0x0000 }, /* R1369 */
-       { 0x0000, 0x0000 }, /* R1370 */
-       { 0x0000, 0x0000 }, /* R1371 */
-       { 0x0000, 0x0000 }, /* R1372 */
-       { 0x0000, 0x0000 }, /* R1373 */
-       { 0x0000, 0x0000 }, /* R1374 */
-       { 0x0000, 0x0000 }, /* R1375 */
-       { 0x0000, 0x0000 }, /* R1376 */
-       { 0x0000, 0x0000 }, /* R1377 */
-       { 0x0000, 0x0000 }, /* R1378 */
-       { 0x0000, 0x0000 }, /* R1379 */
-       { 0x0000, 0x0000 }, /* R1380 */
-       { 0x0000, 0x0000 }, /* R1381 */
-       { 0x0000, 0x0000 }, /* R1382 */
-       { 0x0000, 0x0000 }, /* R1383 */
-       { 0x0000, 0x0000 }, /* R1384 */
-       { 0x0000, 0x0000 }, /* R1385 */
-       { 0x0000, 0x0000 }, /* R1386 */
-       { 0x0000, 0x0000 }, /* R1387 */
-       { 0x0000, 0x0000 }, /* R1388 */
-       { 0x0000, 0x0000 }, /* R1389 */
-       { 0x0000, 0x0000 }, /* R1390 */
-       { 0x0000, 0x0000 }, /* R1391 */
-       { 0x0000, 0x0000 }, /* R1392 */
-       { 0x0000, 0x0000 }, /* R1393 */
-       { 0x0000, 0x0000 }, /* R1394 */
-       { 0x0000, 0x0000 }, /* R1395 */
-       { 0x0000, 0x0000 }, /* R1396 */
-       { 0x0000, 0x0000 }, /* R1397 */
-       { 0x0000, 0x0000 }, /* R1398 */
-       { 0x0000, 0x0000 }, /* R1399 */
-       { 0x0000, 0x0000 }, /* R1400 */
-       { 0x0000, 0x0000 }, /* R1401 */
-       { 0x0000, 0x0000 }, /* R1402 */
-       { 0x0000, 0x0000 }, /* R1403 */
-       { 0x0000, 0x0000 }, /* R1404 */
-       { 0x0000, 0x0000 }, /* R1405 */
-       { 0x0000, 0x0000 }, /* R1406 */
-       { 0x0000, 0x0000 }, /* R1407 */
-       { 0xFFFF, 0xFFFF }, /* R1408  - AIF2 EQ Gains (1) */
-       { 0xFFC0, 0xFFC0 }, /* R1409  - AIF2 EQ Gains (2) */
-       { 0xFFFF, 0xFFFF }, /* R1410  - AIF2 EQ Band 1 A */
-       { 0xFFFF, 0xFFFF }, /* R1411  - AIF2 EQ Band 1 B */
-       { 0xFFFF, 0xFFFF }, /* R1412  - AIF2 EQ Band 1 PG */
-       { 0xFFFF, 0xFFFF }, /* R1413  - AIF2 EQ Band 2 A */
-       { 0xFFFF, 0xFFFF }, /* R1414  - AIF2 EQ Band 2 B */
-       { 0xFFFF, 0xFFFF }, /* R1415  - AIF2 EQ Band 2 C */
-       { 0xFFFF, 0xFFFF }, /* R1416  - AIF2 EQ Band 2 PG */
-       { 0xFFFF, 0xFFFF }, /* R1417  - AIF2 EQ Band 3 A */
-       { 0xFFFF, 0xFFFF }, /* R1418  - AIF2 EQ Band 3 B */
-       { 0xFFFF, 0xFFFF }, /* R1419  - AIF2 EQ Band 3 C */
-       { 0xFFFF, 0xFFFF }, /* R1420  - AIF2 EQ Band 3 PG */
-       { 0xFFFF, 0xFFFF }, /* R1421  - AIF2 EQ Band 4 A */
-       { 0xFFFF, 0xFFFF }, /* R1422  - AIF2 EQ Band 4 B */
-       { 0xFFFF, 0xFFFF }, /* R1423  - AIF2 EQ Band 4 C */
-       { 0xFFFF, 0xFFFF }, /* R1424  - AIF2 EQ Band 4 PG */
-       { 0xFFFF, 0xFFFF }, /* R1425  - AIF2 EQ Band 5 A */
-       { 0xFFFF, 0xFFFF }, /* R1426  - AIF2 EQ Band 5 B */
-       { 0xFFFF, 0xFFFF }, /* R1427  - AIF2 EQ Band 5 PG */
-       { 0x0000, 0x0000 }, /* R1428 */
-       { 0x0000, 0x0000 }, /* R1429 */
-       { 0x0000, 0x0000 }, /* R1430 */
-       { 0x0000, 0x0000 }, /* R1431 */
-       { 0x0000, 0x0000 }, /* R1432 */
-       { 0x0000, 0x0000 }, /* R1433 */
-       { 0x0000, 0x0000 }, /* R1434 */
-       { 0x0000, 0x0000 }, /* R1435 */
-       { 0x0000, 0x0000 }, /* R1436 */
-       { 0x0000, 0x0000 }, /* R1437 */
-       { 0x0000, 0x0000 }, /* R1438 */
-       { 0x0000, 0x0000 }, /* R1439 */
-       { 0x0000, 0x0000 }, /* R1440 */
-       { 0x0000, 0x0000 }, /* R1441 */
-       { 0x0000, 0x0000 }, /* R1442 */
-       { 0x0000, 0x0000 }, /* R1443 */
-       { 0x0000, 0x0000 }, /* R1444 */
-       { 0x0000, 0x0000 }, /* R1445 */
-       { 0x0000, 0x0000 }, /* R1446 */
-       { 0x0000, 0x0000 }, /* R1447 */
-       { 0x0000, 0x0000 }, /* R1448 */
-       { 0x0000, 0x0000 }, /* R1449 */
-       { 0x0000, 0x0000 }, /* R1450 */
-       { 0x0000, 0x0000 }, /* R1451 */
-       { 0x0000, 0x0000 }, /* R1452 */
-       { 0x0000, 0x0000 }, /* R1453 */
-       { 0x0000, 0x0000 }, /* R1454 */
-       { 0x0000, 0x0000 }, /* R1455 */
-       { 0x0000, 0x0000 }, /* R1456 */
-       { 0x0000, 0x0000 }, /* R1457 */
-       { 0x0000, 0x0000 }, /* R1458 */
-       { 0x0000, 0x0000 }, /* R1459 */
-       { 0x0000, 0x0000 }, /* R1460 */
-       { 0x0000, 0x0000 }, /* R1461 */
-       { 0x0000, 0x0000 }, /* R1462 */
-       { 0x0000, 0x0000 }, /* R1463 */
-       { 0x0000, 0x0000 }, /* R1464 */
-       { 0x0000, 0x0000 }, /* R1465 */
-       { 0x0000, 0x0000 }, /* R1466 */
-       { 0x0000, 0x0000 }, /* R1467 */
-       { 0x0000, 0x0000 }, /* R1468 */
-       { 0x0000, 0x0000 }, /* R1469 */
-       { 0x0000, 0x0000 }, /* R1470 */
-       { 0x0000, 0x0000 }, /* R1471 */
-       { 0x0000, 0x0000 }, /* R1472 */
-       { 0x0000, 0x0000 }, /* R1473 */
-       { 0x0000, 0x0000 }, /* R1474 */
-       { 0x0000, 0x0000 }, /* R1475 */
-       { 0x0000, 0x0000 }, /* R1476 */
-       { 0x0000, 0x0000 }, /* R1477 */
-       { 0x0000, 0x0000 }, /* R1478 */
-       { 0x0000, 0x0000 }, /* R1479 */
-       { 0x0000, 0x0000 }, /* R1480 */
-       { 0x0000, 0x0000 }, /* R1481 */
-       { 0x0000, 0x0000 }, /* R1482 */
-       { 0x0000, 0x0000 }, /* R1483 */
-       { 0x0000, 0x0000 }, /* R1484 */
-       { 0x0000, 0x0000 }, /* R1485 */
-       { 0x0000, 0x0000 }, /* R1486 */
-       { 0x0000, 0x0000 }, /* R1487 */
-       { 0x0000, 0x0000 }, /* R1488 */
-       { 0x0000, 0x0000 }, /* R1489 */
-       { 0x0000, 0x0000 }, /* R1490 */
-       { 0x0000, 0x0000 }, /* R1491 */
-       { 0x0000, 0x0000 }, /* R1492 */
-       { 0x0000, 0x0000 }, /* R1493 */
-       { 0x0000, 0x0000 }, /* R1494 */
-       { 0x0000, 0x0000 }, /* R1495 */
-       { 0x0000, 0x0000 }, /* R1496 */
-       { 0x0000, 0x0000 }, /* R1497 */
-       { 0x0000, 0x0000 }, /* R1498 */
-       { 0x0000, 0x0000 }, /* R1499 */
-       { 0x0000, 0x0000 }, /* R1500 */
-       { 0x0000, 0x0000 }, /* R1501 */
-       { 0x0000, 0x0000 }, /* R1502 */
-       { 0x0000, 0x0000 }, /* R1503 */
-       { 0x0000, 0x0000 }, /* R1504 */
-       { 0x0000, 0x0000 }, /* R1505 */
-       { 0x0000, 0x0000 }, /* R1506 */
-       { 0x0000, 0x0000 }, /* R1507 */
-       { 0x0000, 0x0000 }, /* R1508 */
-       { 0x0000, 0x0000 }, /* R1509 */
-       { 0x0000, 0x0000 }, /* R1510 */
-       { 0x0000, 0x0000 }, /* R1511 */
-       { 0x0000, 0x0000 }, /* R1512 */
-       { 0x0000, 0x0000 }, /* R1513 */
-       { 0x0000, 0x0000 }, /* R1514 */
-       { 0x0000, 0x0000 }, /* R1515 */
-       { 0x0000, 0x0000 }, /* R1516 */
-       { 0x0000, 0x0000 }, /* R1517 */
-       { 0x0000, 0x0000 }, /* R1518 */
-       { 0x0000, 0x0000 }, /* R1519 */
-       { 0x0000, 0x0000 }, /* R1520 */
-       { 0x0000, 0x0000 }, /* R1521 */
-       { 0x0000, 0x0000 }, /* R1522 */
-       { 0x0000, 0x0000 }, /* R1523 */
-       { 0x0000, 0x0000 }, /* R1524 */
-       { 0x0000, 0x0000 }, /* R1525 */
-       { 0x0000, 0x0000 }, /* R1526 */
-       { 0x0000, 0x0000 }, /* R1527 */
-       { 0x0000, 0x0000 }, /* R1528 */
-       { 0x0000, 0x0000 }, /* R1529 */
-       { 0x0000, 0x0000 }, /* R1530 */
-       { 0x0000, 0x0000 }, /* R1531 */
-       { 0x0000, 0x0000 }, /* R1532 */
-       { 0x0000, 0x0000 }, /* R1533 */
-       { 0x0000, 0x0000 }, /* R1534 */
-       { 0x0000, 0x0000 }, /* R1535 */
-       { 0x01EF, 0x01EF }, /* R1536  - DAC1 Mixer Volumes */
-       { 0x0037, 0x0037 }, /* R1537  - DAC1 Left Mixer Routing */
-       { 0x0037, 0x0037 }, /* R1538  - DAC1 Right Mixer Routing */
-       { 0x01EF, 0x01EF }, /* R1539  - DAC2 Mixer Volumes */
-       { 0x0037, 0x0037 }, /* R1540  - DAC2 Left Mixer Routing */
-       { 0x0037, 0x0037 }, /* R1541  - DAC2 Right Mixer Routing */
-       { 0x0003, 0x0003 }, /* R1542  - AIF1 ADC1 Left Mixer Routing */
-       { 0x0003, 0x0003 }, /* R1543  - AIF1 ADC1 Right Mixer Routing */
-       { 0x0003, 0x0003 }, /* R1544  - AIF1 ADC2 Left Mixer Routing */
-       { 0x0003, 0x0003 }, /* R1545  - AIF1 ADC2 Right mixer Routing */
-       { 0x0000, 0x0000 }, /* R1546 */
-       { 0x0000, 0x0000 }, /* R1547 */
-       { 0x0000, 0x0000 }, /* R1548 */
-       { 0x0000, 0x0000 }, /* R1549 */
-       { 0x0000, 0x0000 }, /* R1550 */
-       { 0x0000, 0x0000 }, /* R1551 */
-       { 0x02FF, 0x03FF }, /* R1552  - DAC1 Left Volume */
-       { 0x02FF, 0x03FF }, /* R1553  - DAC1 Right Volume */
-       { 0x02FF, 0x03FF }, /* R1554  - DAC2 Left Volume */
-       { 0x02FF, 0x03FF }, /* R1555  - DAC2 Right Volume */
-       { 0x0003, 0x0003 }, /* R1556  - DAC Softmute */
-       { 0x0000, 0x0000 }, /* R1557 */
-       { 0x0000, 0x0000 }, /* R1558 */
-       { 0x0000, 0x0000 }, /* R1559 */
-       { 0x0000, 0x0000 }, /* R1560 */
-       { 0x0000, 0x0000 }, /* R1561 */
-       { 0x0000, 0x0000 }, /* R1562 */
-       { 0x0000, 0x0000 }, /* R1563 */
-       { 0x0000, 0x0000 }, /* R1564 */
-       { 0x0000, 0x0000 }, /* R1565 */
-       { 0x0000, 0x0000 }, /* R1566 */
-       { 0x0000, 0x0000 }, /* R1567 */
-       { 0x0003, 0x0003 }, /* R1568  - Oversampling */
-       { 0x03C3, 0x03C3 }, /* R1569  - Sidetone */
-};
-
 static int wm8994_readable(unsigned int reg)
 {
        switch (reg) {
@@ -1696,14 +131,14 @@ static int wm8994_readable(unsigned int reg)
                break;
        }
 
-       if (reg >= ARRAY_SIZE(access_masks))
+       if (reg >= WM8994_CACHE_SIZE)
                return 0;
-       return access_masks[reg].readable != 0;
+       return wm8994_access_masks[reg].readable != 0;
 }
 
 static int wm8994_volatile(unsigned int reg)
 {
-       if (reg >= WM8994_REG_CACHE_SIZE)
+       if (reg >= WM8994_CACHE_SIZE)
                return 1;
 
        switch (reg) {
@@ -1714,6 +149,8 @@ static int wm8994_volatile(unsigned int reg)
        case WM8994_RATE_STATUS:
        case WM8994_LDO_1:
        case WM8994_LDO_2:
+       case WM8958_DSP2_EXECCONTROL:
+       case WM8958_MIC_DETECT_3:
                return 1;
        default:
                return 0;
@@ -1723,14 +160,16 @@ static int wm8994_volatile(unsigned int reg)
 static int wm8994_write(struct snd_soc_codec *codec, unsigned int reg,
        unsigned int value)
 {
-       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       int ret;
 
        BUG_ON(reg > WM8994_MAX_REGISTER);
 
-       if (!wm8994_volatile(reg))
-               wm8994->reg_cache[reg] = value;
-
-       dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value);
+       if (!wm8994_volatile(reg)) {
+               ret = snd_soc_cache_write(codec, reg, value);
+               if (ret != 0)
+                       dev_err(codec->dev, "Cache write to %x failed: %d\n",
+                               reg, ret);
+       }
 
        return wm8994_reg_write(codec->control_data, reg, value);
 }
@@ -1738,14 +177,22 @@ static int wm8994_write(struct snd_soc_codec *codec, unsigned int reg,
 static unsigned int wm8994_read(struct snd_soc_codec *codec,
                                unsigned int reg)
 {
-       u16 *reg_cache = codec->reg_cache;
+       unsigned int val;
+       int ret;
 
        BUG_ON(reg > WM8994_MAX_REGISTER);
 
-       if (wm8994_volatile(reg))
-               return wm8994_reg_read(codec->control_data, reg);
-       else
-               return reg_cache[reg];
+       if (!wm8994_volatile(reg) && wm8994_readable(reg) &&
+           reg < codec->driver->reg_cache_size) {
+               ret = snd_soc_cache_read(codec, reg, &val);
+               if (ret >= 0)
+                       return val;
+               else
+                       dev_err(codec->dev, "Cache read from %x failed: %d\n",
+                               reg, ret);
+       }
+
+       return wm8994_reg_read(codec->control_data, reg);
 }
 
 static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
@@ -1837,7 +284,7 @@ static int configure_clock(struct snd_soc_codec *codec)
 
        snd_soc_update_bits(codec, WM8994_CLOCKING_1, WM8994_SYSCLK_SRC, new);
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(&codec->dapm);
 
        return 0;
 }
@@ -1864,6 +311,19 @@ static const char *sidetone_hpf_text[] = {
 static const struct soc_enum sidetone_hpf =
        SOC_ENUM_SINGLE(WM8994_SIDETONE, 7, 7, sidetone_hpf_text);
 
+static const char *adc_hpf_text[] = {
+       "HiFi", "Voice 1", "Voice 2", "Voice 3"
+};
+
+static const struct soc_enum aif1adc1_hpf =
+       SOC_ENUM_SINGLE(WM8994_AIF1_ADC1_FILTERS, 13, 4, adc_hpf_text);
+
+static const struct soc_enum aif1adc2_hpf =
+       SOC_ENUM_SINGLE(WM8994_AIF1_ADC2_FILTERS, 13, 4, adc_hpf_text);
+
+static const struct soc_enum aif2adc_hpf =
+       SOC_ENUM_SINGLE(WM8994_AIF2_ADC_FILTERS, 13, 4, adc_hpf_text);
+
 static const DECLARE_TLV_DB_SCALE(aif_tlv, 0, 600, 0);
 static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
 static const DECLARE_TLV_DB_SCALE(st_tlv, -3600, 300, 0);
@@ -2071,21 +531,252 @@ static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static const char *aifdac_src_text[] = {
+static const char *aif_chan_src_text[] = {
        "Left", "Right"
 };
 
+static const struct soc_enum aif1adcl_src =
+       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_1, 15, 2, aif_chan_src_text);
+
+static const struct soc_enum aif1adcr_src =
+       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_1, 14, 2, aif_chan_src_text);
+
+static const struct soc_enum aif2adcl_src =
+       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_1, 15, 2, aif_chan_src_text);
+
+static const struct soc_enum aif2adcr_src =
+       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_1, 14, 2, aif_chan_src_text);
+
 static const struct soc_enum aif1dacl_src =
-       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 15, 2, aifdac_src_text);
+       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 15, 2, aif_chan_src_text);
 
 static const struct soc_enum aif1dacr_src =
-       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 14, 2, aifdac_src_text);
+       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 14, 2, aif_chan_src_text);
 
 static const struct soc_enum aif2dacl_src =
-       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 15, 2, aifdac_src_text);
+       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 15, 2, aif_chan_src_text);
 
 static const struct soc_enum aif2dacr_src =
-       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 14, 2, aifdac_src_text);
+       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 14, 2, aif_chan_src_text);
+
+static const char *osr_text[] = {
+       "Low Power", "High Performance",
+};
+
+static const struct soc_enum dac_osr =
+       SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 0, 2, osr_text);
+
+static const struct soc_enum adc_osr =
+       SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 1, 2, osr_text);
+
+static void wm8958_mbc_apply(struct snd_soc_codec *codec, int mbc, int start)
+{
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int pwr_reg = snd_soc_read(codec, WM8994_POWER_MANAGEMENT_5);
+       int ena, reg, aif, i;
+
+       switch (mbc) {
+       case 0:
+               pwr_reg &= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA);
+               aif = 0;
+               break;
+       case 1:
+               pwr_reg &= (WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA);
+               aif = 0;
+               break;
+       case 2:
+               pwr_reg &= (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA);
+               aif = 1;
+               break;
+       default:
+               BUG();
+               return;
+       }
+
+       /* We can only enable the MBC if the AIF is enabled and we
+        * want it to be enabled. */
+       ena = pwr_reg && wm8994->mbc_ena[mbc];
+
+       reg = snd_soc_read(codec, WM8958_DSP2_PROGRAM);
+
+       dev_dbg(codec->dev, "MBC %d startup: %d, power: %x, DSP: %x\n",
+               mbc, start, pwr_reg, reg);
+
+       if (start && ena) {
+               /* If the DSP is already running then noop */
+               if (reg & WM8958_DSP2_ENA)
+                       return;
+
+               /* Switch the clock over to the appropriate AIF */
+               snd_soc_update_bits(codec, WM8994_CLOCKING_1,
+                                   WM8958_DSP2CLK_SRC | WM8958_DSP2CLK_ENA,
+                                   aif << WM8958_DSP2CLK_SRC_SHIFT |
+                                   WM8958_DSP2CLK_ENA);
+
+               snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+                                   WM8958_DSP2_ENA, WM8958_DSP2_ENA);
+
+               /* If we've got user supplied MBC settings use them */
+               if (pdata && pdata->num_mbc_cfgs) {
+                       struct wm8958_mbc_cfg *cfg
+                               = &pdata->mbc_cfgs[wm8994->mbc_cfg];
+
+                       for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++)
+                               snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1,
+                                             cfg->coeff_regs[i]);
+
+                       for (i = 0; i < ARRAY_SIZE(cfg->cutoff_regs); i++)
+                               snd_soc_write(codec,
+                                             i + WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1,
+                                             cfg->cutoff_regs[i]);
+               }
+
+               /* Run the DSP */
+               snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+                             WM8958_DSP2_RUNR);
+
+               /* And we're off! */
+               snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+                                   WM8958_MBC_ENA | WM8958_MBC_SEL_MASK,
+                                   mbc << WM8958_MBC_SEL_SHIFT |
+                                   WM8958_MBC_ENA);
+       } else {
+               /* If the DSP is already stopped then noop */
+               if (!(reg & WM8958_DSP2_ENA))
+                       return;
+
+               snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+                                   WM8958_MBC_ENA, 0); 
+               snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+                                   WM8958_DSP2_ENA, 0);
+               snd_soc_update_bits(codec, WM8994_CLOCKING_1,
+                                   WM8958_DSP2CLK_ENA, 0);
+       }
+}
+
+static int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
+                   struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       int mbc;
+
+       switch (w->shift) {
+       case 13:
+       case 12:
+               mbc = 2;
+               break;
+       case 11:
+       case 10:
+               mbc = 1;
+               break;
+       case 9:
+       case 8:
+               mbc = 0;
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               wm8958_mbc_apply(codec, mbc, 1);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               wm8958_mbc_apply(codec, mbc, 0);
+               break;
+       }
+
+       return 0;
+}
+
+static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       int value = ucontrol->value.integer.value[0];
+       int reg;
+
+       /* Don't allow on the fly reconfiguration */
+       reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+       if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+               return -EBUSY;
+
+       if (value >= pdata->num_mbc_cfgs)
+               return -EINVAL;
+
+       wm8994->mbc_cfg = value;
+
+       return 0;
+}
+
+static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg;
+
+       return 0;
+}
+
+static int wm8958_mbc_info(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int wm8958_mbc_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       int mbc = kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc];
+
+       return 0;
+}
+
+static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       int mbc = kcontrol->private_value;
+       int i;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+       if (ucontrol->value.integer.value[0] > 1)
+               return -EINVAL;
+
+       for (i = 0; i < ARRAY_SIZE(wm8994->mbc_ena); i++) {
+               if (mbc != i && wm8994->mbc_ena[i]) {
+                       dev_dbg(codec->dev, "MBC %d active already\n", mbc);
+                       return -EBUSY;
+               }
+       }
+
+       wm8994->mbc_ena[mbc] = ucontrol->value.integer.value[0];
+
+       wm8958_mbc_apply(codec, mbc, wm8994->mbc_ena[mbc]);
+
+       return 0;
+}
+
+#define WM8958_MBC_SWITCH(xname, xval) {\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .info = wm8958_mbc_info, \
+       .get = wm8958_mbc_get, .put = wm8958_mbc_put, \
+       .private_value = xval }
 
 static const struct snd_kcontrol_new wm8994_snd_controls[] = {
 SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME,
@@ -2098,10 +789,15 @@ SOC_DOUBLE_R_TLV("AIF2ADC Volume", WM8994_AIF2_ADC_LEFT_VOLUME,
                 WM8994_AIF2_ADC_RIGHT_VOLUME,
                 1, 119, 0, digital_tlv),
 
+SOC_ENUM("AIF1ADCL Source", aif1adcl_src),
+SOC_ENUM("AIF1ADCR Source", aif1adcr_src),
+SOC_ENUM("AIF2ADCL Source", aif2adcl_src),
+SOC_ENUM("AIF2ADCR Source", aif2adcr_src),
+
 SOC_ENUM("AIF1DACL Source", aif1dacl_src),
 SOC_ENUM("AIF1DACR Source", aif1dacr_src),
-SOC_ENUM("AIF2DACL Source", aif1dacl_src),
-SOC_ENUM("AIF2DACR Source", aif1dacr_src),
+SOC_ENUM("AIF2DACL Source", aif2dacl_src),
+SOC_ENUM("AIF2DACR Source", aif2dacr_src),
 
 SOC_DOUBLE_R_TLV("AIF1DAC1 Volume", WM8994_AIF1_DAC1_LEFT_VOLUME,
                 WM8994_AIF1_DAC1_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
@@ -2140,6 +836,18 @@ SOC_SINGLE_TLV("DAC2 Left Sidetone Volume", WM8994_DAC2_MIXER_VOLUMES,
 SOC_ENUM("Sidetone HPF Mux", sidetone_hpf),
 SOC_SINGLE("Sidetone HPF Switch", WM8994_SIDETONE, 6, 1, 0),
 
+SOC_ENUM("AIF1ADC1 HPF Mode", aif1adc1_hpf),
+SOC_DOUBLE("AIF1ADC1 HPF Switch", WM8994_AIF1_ADC1_FILTERS, 12, 11, 1, 0),
+
+SOC_ENUM("AIF1ADC2 HPF Mode", aif1adc2_hpf),
+SOC_DOUBLE("AIF1ADC2 HPF Switch", WM8994_AIF1_ADC2_FILTERS, 12, 11, 1, 0),
+
+SOC_ENUM("AIF2ADC HPF Mode", aif2adc_hpf),
+SOC_DOUBLE("AIF2ADC HPF Switch", WM8994_AIF2_ADC_FILTERS, 12, 11, 1, 0),
+
+SOC_ENUM("ADC OSR", adc_osr),
+SOC_ENUM("DAC OSR", dac_osr),
+
 SOC_DOUBLE_R_TLV("DAC1 Volume", WM8994_DAC1_LEFT_VOLUME,
                 WM8994_DAC1_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
 SOC_DOUBLE_R("DAC1 Switch", WM8994_DAC1_LEFT_VOLUME,
@@ -2162,15 +870,15 @@ SOC_SINGLE_TLV("SPKR DAC1 Volume", WM8994_SPKMIXR_ATTENUATION,
 
 SOC_SINGLE_TLV("AIF1DAC1 3D Stereo Volume", WM8994_AIF1_DAC1_FILTERS_2,
               10, 15, 0, wm8994_3d_tlv),
-SOC_SINGLE("AIF1DAC1 3D Stereo Switch", WM8994_AIF1_DAC2_FILTERS_2,
+SOC_SINGLE("AIF1DAC1 3D Stereo Switch", WM8994_AIF1_DAC1_FILTERS_2,
           8, 1, 0),
 SOC_SINGLE_TLV("AIF1DAC2 3D Stereo Volume", WM8994_AIF1_DAC2_FILTERS_2,
               10, 15, 0, wm8994_3d_tlv),
 SOC_SINGLE("AIF1DAC2 3D Stereo Switch", WM8994_AIF1_DAC2_FILTERS_2,
           8, 1, 0),
-SOC_SINGLE_TLV("AIF2DAC 3D Stereo Volume", WM8994_AIF1_DAC1_FILTERS_2,
+SOC_SINGLE_TLV("AIF2DAC 3D Stereo Volume", WM8994_AIF2_DAC_FILTERS_2,
               10, 15, 0, wm8994_3d_tlv),
-SOC_SINGLE("AIF2DAC 3D Stereo Switch", WM8994_AIF1_DAC2_FILTERS_2,
+SOC_SINGLE("AIF2DAC 3D Stereo Switch", WM8994_AIF2_DAC_FILTERS_2,
           8, 1, 0),
 };
 
@@ -2209,6 +917,13 @@ SOC_SINGLE_TLV("AIF2 EQ5 Volume", WM8994_AIF2_EQ_GAINS_2, 6, 31, 0,
               eq_tlv),
 };
 
+static const struct snd_kcontrol_new wm8958_snd_controls[] = {
+SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv),
+WM8958_MBC_SWITCH("AIF1DAC1 MBC Switch", 0),
+WM8958_MBC_SWITCH("AIF1DAC2 MBC Switch", 1),
+WM8958_MBC_SWITCH("AIF2DAC MBC Switch", 2),
+};
+
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
@@ -2228,6 +943,7 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w,
 
 static void wm8994_update_class_w(struct snd_soc_codec *codec)
 {
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        int enable = 1;
        int source = 0;  /* GCC flow analysis can't track enable */
        int reg, reg_r;
@@ -2278,11 +994,13 @@ static void wm8994_update_class_w(struct snd_soc_codec *codec)
                                    WM8994_CP_DYN_PWR |
                                    WM8994_CP_DYN_SRC_SEL_MASK,
                                    source | WM8994_CP_DYN_PWR);
+               wm8994->hubs.class_w = true;
                
        } else {
                dev_dbg(codec->dev, "Class W disabled\n");
                snd_soc_update_bits(codec, WM8994_CLASS_W_1,
                                    WM8994_CP_DYN_PWR, 0);
+               wm8994->hubs.class_w = false;
        }
 }
 
@@ -2512,14 +1230,47 @@ static const struct snd_kcontrol_new aif2adc_mux =
        SOC_DAPM_ENUM("AIF2ADC Mux", aif2adc_enum);
 
 static const char *aif3adc_text[] = {
-       "AIF1ADCDAT", "AIF2ADCDAT", "AIF2DACDAT",
+       "AIF1ADCDAT", "AIF2ADCDAT", "AIF2DACDAT", "Mono PCM",
 };
 
-static const struct soc_enum aif3adc_enum =
+static const struct soc_enum wm8994_aif3adc_enum =
        SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 3, 3, aif3adc_text);
 
-static const struct snd_kcontrol_new aif3adc_mux =
-       SOC_DAPM_ENUM("AIF3ADC Mux", aif3adc_enum);
+static const struct snd_kcontrol_new wm8994_aif3adc_mux =
+       SOC_DAPM_ENUM("AIF3ADC Mux", wm8994_aif3adc_enum);
+
+static const struct soc_enum wm8958_aif3adc_enum =
+       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 3, 4, aif3adc_text);
+
+static const struct snd_kcontrol_new wm8958_aif3adc_mux =
+       SOC_DAPM_ENUM("AIF3ADC Mux", wm8958_aif3adc_enum);
+
+static const char *mono_pcm_out_text[] = {
+       "None", "AIF2ADCL", "AIF2ADCR", 
+};
+
+static const struct soc_enum mono_pcm_out_enum =
+       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 9, 3, mono_pcm_out_text);
+
+static const struct snd_kcontrol_new mono_pcm_out_mux =
+       SOC_DAPM_ENUM("Mono PCM Out Mux", mono_pcm_out_enum);
+
+static const char *aif2dac_src_text[] = {
+       "AIF2", "AIF3",
+};
+
+/* Note that these two control shouldn't be simultaneously switched to AIF3 */
+static const struct soc_enum aif2dacl_src_enum =
+       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 7, 2, aif2dac_src_text);
+
+static const struct snd_kcontrol_new aif2dacl_src_mux =
+       SOC_DAPM_ENUM("AIF2DACL Mux", aif2dacl_src_enum);
+
+static const struct soc_enum aif2dacr_src_enum =
+       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 8, 2, aif2dac_src_text);
+
+static const struct snd_kcontrol_new aif2dacr_src_mux =
+       SOC_DAPM_ENUM("AIF2DACR Mux", aif2dacr_src_enum);
 
 static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = {
 SND_SOC_DAPM_INPUT("DMIC1DAT"),
@@ -2540,19 +1291,23 @@ SND_SOC_DAPM_AIF_OUT("AIF1ADC1L", "AIF1 Capture",
                     0, WM8994_POWER_MANAGEMENT_4, 9, 0),
 SND_SOC_DAPM_AIF_OUT("AIF1ADC1R", "AIF1 Capture",
                     0, WM8994_POWER_MANAGEMENT_4, 8, 0),
-SND_SOC_DAPM_AIF_IN("AIF1DAC1L", NULL, 0,
-                   WM8994_POWER_MANAGEMENT_5, 9, 0),
-SND_SOC_DAPM_AIF_IN("AIF1DAC1R", NULL, 0,
-                   WM8994_POWER_MANAGEMENT_5, 8, 0),
+SND_SOC_DAPM_AIF_IN_E("AIF1DAC1L", NULL, 0,
+                     WM8994_POWER_MANAGEMENT_5, 9, 0, wm8958_aif_ev,
+                     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_AIF_IN_E("AIF1DAC1R", NULL, 0,
+                     WM8994_POWER_MANAGEMENT_5, 8, 0, wm8958_aif_ev,
+                     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
 SND_SOC_DAPM_AIF_OUT("AIF1ADC2L", "AIF1 Capture",
                     0, WM8994_POWER_MANAGEMENT_4, 11, 0),
 SND_SOC_DAPM_AIF_OUT("AIF1ADC2R", "AIF1 Capture",
                     0, WM8994_POWER_MANAGEMENT_4, 10, 0),
-SND_SOC_DAPM_AIF_IN("AIF1DAC2L", NULL, 0,
-                   WM8994_POWER_MANAGEMENT_5, 11, 0),
-SND_SOC_DAPM_AIF_IN("AIF1DAC2R", NULL, 0,
-                   WM8994_POWER_MANAGEMENT_5, 10, 0),
+SND_SOC_DAPM_AIF_IN_E("AIF1DAC2L", NULL, 0,
+                     WM8994_POWER_MANAGEMENT_5, 11, 0, wm8958_aif_ev,
+                     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_AIF_IN_E("AIF1DAC2R", NULL, 0,
+                     WM8994_POWER_MANAGEMENT_5, 10, 0, wm8958_aif_ev,
+                     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
 
 SND_SOC_DAPM_MIXER("AIF1ADC1L Mixer", SND_SOC_NOPM, 0, 0,
                   aif1adc1l_mix, ARRAY_SIZE(aif1adc1l_mix)),
@@ -2581,10 +1336,12 @@ SND_SOC_DAPM_AIF_OUT("AIF2ADCL", NULL, 0,
                     WM8994_POWER_MANAGEMENT_4, 13, 0),
 SND_SOC_DAPM_AIF_OUT("AIF2ADCR", NULL, 0,
                     WM8994_POWER_MANAGEMENT_4, 12, 0),
-SND_SOC_DAPM_AIF_IN("AIF2DACL", NULL, 0,
-                   WM8994_POWER_MANAGEMENT_5, 13, 0),
-SND_SOC_DAPM_AIF_IN("AIF2DACR", NULL, 0,
-                   WM8994_POWER_MANAGEMENT_5, 12, 0),
+SND_SOC_DAPM_AIF_IN_E("AIF2DACL", NULL, 0,
+                     WM8994_POWER_MANAGEMENT_5, 13, 0, wm8958_aif_ev,
+                     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_AIF_IN_E("AIF2DACR", NULL, 0,
+                     WM8994_POWER_MANAGEMENT_5, 12, 0, wm8958_aif_ev,
+                     SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 
 SND_SOC_DAPM_AIF_IN("AIF1DACDAT", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
 SND_SOC_DAPM_AIF_IN("AIF2DACDAT", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0),
@@ -2593,7 +1350,6 @@ SND_SOC_DAPM_AIF_OUT("AIF2ADCDAT", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0),
 SND_SOC_DAPM_MUX("AIF1DAC Mux", SND_SOC_NOPM, 0, 0, &aif1dac_mux),
 SND_SOC_DAPM_MUX("AIF2DAC Mux", SND_SOC_NOPM, 0, 0, &aif2dac_mux),
 SND_SOC_DAPM_MUX("AIF2ADC Mux", SND_SOC_NOPM, 0, 0, &aif2adc_mux),
-SND_SOC_DAPM_MUX("AIF3ADC Mux", SND_SOC_NOPM, 0, 0, &aif3adc_mux),
 
 SND_SOC_DAPM_AIF_IN("AIF3DACDAT", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0),
 SND_SOC_DAPM_AIF_IN("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0),
@@ -2631,8 +1387,18 @@ SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0,
 SND_SOC_DAPM_POST("Debug log", post_ev),
 };
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_widget wm8994_specific_dapm_widgets[] = {
+SND_SOC_DAPM_MUX("AIF3ADC Mux", SND_SOC_NOPM, 0, 0, &wm8994_aif3adc_mux),
+};
+
+static const struct snd_soc_dapm_widget wm8958_dapm_widgets[] = {
+SND_SOC_DAPM_MUX("Mono PCM Out Mux", SND_SOC_NOPM, 0, 0, &mono_pcm_out_mux),
+SND_SOC_DAPM_MUX("AIF2DACL Mux", SND_SOC_NOPM, 0, 0, &aif2dacl_src_mux),
+SND_SOC_DAPM_MUX("AIF2DACR Mux", SND_SOC_NOPM, 0, 0, &aif2dacr_src_mux),
+SND_SOC_DAPM_MUX("AIF3ADC Mux", SND_SOC_NOPM, 0, 0, &wm8958_aif3adc_mux),
+};
 
+static const struct snd_soc_dapm_route intercon[] = {
        { "CLK_SYS", NULL, "AIF1CLK", check_clk_sys },
        { "CLK_SYS", NULL, "AIF2CLK", check_clk_sys },
 
@@ -2740,9 +1506,6 @@ static const struct snd_soc_dapm_route intercon[] = {
        { "AIF1DAC2L", NULL, "AIF1DAC Mux" },
        { "AIF1DAC2R", NULL, "AIF1DAC Mux" },
 
-       { "AIF2DACL", NULL, "AIF2DAC Mux" },
-       { "AIF2DACR", NULL, "AIF2DAC Mux" },
-
        { "AIF1DAC Mux", "AIF1DACDAT", "AIF1DACDAT" },
        { "AIF1DAC Mux", "AIF3DACDAT", "AIF3DACDAT" },
        { "AIF2DAC Mux", "AIF2DACDAT", "AIF2DACDAT" },
@@ -2815,6 +1578,26 @@ static const struct snd_soc_dapm_route intercon[] = {
        { "Right Headphone Mux", "DAC", "DAC1R" },
 };
 
+static const struct snd_soc_dapm_route wm8994_intercon[] = {
+       { "AIF2DACL", NULL, "AIF2DAC Mux" },
+       { "AIF2DACR", NULL, "AIF2DAC Mux" },
+};
+
+static const struct snd_soc_dapm_route wm8958_intercon[] = {
+       { "AIF2DACL", NULL, "AIF2DACL Mux" },
+       { "AIF2DACR", NULL, "AIF2DACR Mux" },
+
+       { "AIF2DACL Mux", "AIF2", "AIF2DAC Mux" },
+       { "AIF2DACL Mux", "AIF3", "AIF3DACDAT" },
+       { "AIF2DACR Mux", "AIF2", "AIF2DAC Mux" },
+       { "AIF2DACR Mux", "AIF3", "AIF3DACDAT" },
+
+       { "Mono PCM Out Mux", "AIF2ADCL", "AIF2ADCL" },
+       { "Mono PCM Out Mux", "AIF2ADCR", "AIF2ADCR" },
+
+       { "AIF3ADC Mux", "Mono PCM", "Mono PCM Out Mux" },
+};
+
 /* The size in bits of the FLL divide multiplied by 10
  * to allow rounding later */
 #define FIXED_FLL_SIZE ((1 << 16) * 10)
@@ -2930,6 +1713,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                /* Allow no source specification when stopping */
                if (freq_out)
                        return -EINVAL;
+               src = wm8994->fll[id].src;
                break;
        case WM8994_FLL_SRC_MCLK1:
        case WM8994_FLL_SRC_MCLK2:
@@ -3094,6 +1878,7 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
 static int wm8994_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
+       struct wm8994 *control = codec->control_data;
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        switch (level) {
@@ -3107,16 +1892,36 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
-                       /* Tweak DC servo and DSP configuration for
-                        * improved performance. */
-                       if (wm8994->revision < 4) {
-                               /* Tweak DC servo and DSP configuration for
-                                * improved performance. */
-                               snd_soc_write(codec, 0x102, 0x3);
-                               snd_soc_write(codec, 0x56, 0x3);
-                               snd_soc_write(codec, 0x817, 0);
-                               snd_soc_write(codec, 0x102, 0);
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       pm_runtime_get_sync(codec->dev);
+
+                       switch (control->type) {
+                       case WM8994:
+                               if (wm8994->revision < 4) {
+                                       /* Tweak DC servo and DSP
+                                        * configuration for improved
+                                        * performance. */
+                                       snd_soc_write(codec, 0x102, 0x3);
+                                       snd_soc_write(codec, 0x56, 0x3);
+                                       snd_soc_write(codec, 0x817, 0);
+                                       snd_soc_write(codec, 0x102, 0);
+                               }
+                               break;
+
+                       case WM8958:
+                               if (wm8994->revision == 0) {
+                                       /* Optimise performance for rev A */
+                                       snd_soc_write(codec, 0x102, 0x3);
+                                       snd_soc_write(codec, 0xcb, 0x81);
+                                       snd_soc_write(codec, 0x817, 0);
+                                       snd_soc_write(codec, 0x102, 0);
+
+                                       snd_soc_update_bits(codec,
+                                                           WM8958_CHARGE_PUMP_2,
+                                                           WM8958_CP_DISCH,
+                                                           WM8958_CP_DISCH);
+                               }
+                               break;
                        }
 
                        /* Discharge LINEOUT1 & 2 */
@@ -3151,7 +1956,7 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_OFF:
-               if (codec->bias_level == SND_SOC_BIAS_STANDBY) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
                        /* Switch over to startup biases */
                        snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
                                            WM8994_BIAS_SRC |
@@ -3183,16 +1988,19 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
                                            WM8994_STARTUP_BIAS_ENA |
                                            WM8994_VMID_BUF_ENA |
                                            WM8994_VMID_RAMP_MASK, 0);
+
+                       pm_runtime_put(codec->dev);
                }
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
 static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
        struct snd_soc_codec *codec = dai->codec;
+       struct wm8994 *control = codec->control_data;
        int ms_reg;
        int aif1_reg;
        int ms = 0;
@@ -3277,6 +2085,13 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                return -EINVAL;
        }
 
+       /* The AIF2 format configuration needs to be mirrored to AIF3
+        * on WM8958 if it's in use so just do it all the time. */
+       if (control->type == WM8958 && dai->id == 2)
+               snd_soc_update_bits(codec, WM8958_AIF3_CONTROL_1,
+                                   WM8994_AIF1_LRCLK_INV |
+                                   WM8958_AIF3_FMT_MASK, aif1);
+
        snd_soc_update_bits(codec, aif1_reg,
                            WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV |
                            WM8994_AIF1_FMT_MASK,
@@ -3317,12 +2132,15 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_codec *codec = dai->codec;
+       struct wm8994 *control = codec->control_data;
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        int aif1_reg;
+       int aif2_reg;
        int bclk_reg;
        int lrclk_reg;
        int rate_reg;
        int aif1 = 0;
+       int aif2 = 0;
        int bclk = 0;
        int lrclk = 0;
        int rate_val = 0;
@@ -3333,6 +2151,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
        switch (dai->id) {
        case 1:
                aif1_reg = WM8994_AIF1_CONTROL_1;
+               aif2_reg = WM8994_AIF1_CONTROL_2;
                bclk_reg = WM8994_AIF1_BCLK;
                rate_reg = WM8994_AIF1_RATE;
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
@@ -3345,6 +2164,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
                break;
        case 2:
                aif1_reg = WM8994_AIF2_CONTROL_1;
+               aif2_reg = WM8994_AIF2_CONTROL_2;
                bclk_reg = WM8994_AIF2_BCLK;
                rate_reg = WM8994_AIF2_RATE;
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
@@ -3355,6 +2175,14 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
                        dev_dbg(codec->dev, "AIF2 using split LRCLK\n");
                }
                break;
+       case 3:
+               switch (control->type) {
+               case WM8958:
+                       aif1_reg = WM8958_AIF3_CONTROL_1;
+                       break;
+               default:
+                       return 0;
+               }
        default:
                return -EINVAL;
        }
@@ -3392,6 +2220,10 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
        dev_dbg(dai->dev, "AIF%dCLK is %dHz, target BCLK %dHz\n",
                dai->id, wm8994->aifclk[id], bclk_rate);
 
+       if (params_channels(params) == 1 &&
+           (snd_soc_read(codec, aif1_reg) & 0x18) == 0x18)
+               aif2 |= WM8994_AIF1_MONO;
+
        if (wm8994->aifclk[id] == 0) {
                dev_err(dai->dev, "AIF%dCLK not configured\n", dai->id);
                return -EINVAL;
@@ -3435,6 +2267,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
                lrclk, bclk_rate / lrclk);
 
        snd_soc_update_bits(codec, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
+       snd_soc_update_bits(codec, aif2_reg, WM8994_AIF1_MONO, aif2);
        snd_soc_update_bits(codec, bclk_reg, WM8994_AIF1_BCLK_DIV_MASK, bclk);
        snd_soc_update_bits(codec, lrclk_reg, WM8994_AIF1DAC_RATE_MASK,
                            lrclk);
@@ -3458,6 +2291,47 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
+static int wm8994_aif3_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 wm8994 *control = codec->control_data;
+       int aif1_reg;
+       int aif1 = 0;
+
+       switch (dai->id) {
+       case 3:
+               switch (control->type) {
+               case WM8958:
+                       aif1_reg = WM8958_AIF3_CONTROL_1;
+                       break;
+               default:
+                       return 0;
+               }
+       default:
+               return 0;
+       }
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               aif1 |= 0x20;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               aif1 |= 0x40;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               aif1 |= 0x60;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return snd_soc_update_bits(codec, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
+}
+
 static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -3539,6 +2413,7 @@ static struct snd_soc_dai_ops wm8994_aif2_dai_ops = {
 };
 
 static struct snd_soc_dai_ops wm8994_aif3_dai_ops = {
+       .hw_params      = wm8994_aif3_hw_params,
        .set_tristate   = wm8994_set_tristate,
 };
 
@@ -3548,14 +2423,14 @@ static struct snd_soc_dai_driver wm8994_dai[] = {
                .id = 1,
                .playback = {
                        .stream_name = "AIF1 Playback",
-                       .channels_min = 2,
+                       .channels_min = 1,
                        .channels_max = 2,
                        .rates = WM8994_RATES,
                        .formats = WM8994_FORMATS,
                },
                .capture = {
                        .stream_name = "AIF1 Capture",
-                       .channels_min = 2,
+                       .channels_min = 1,
                        .channels_max = 2,
                        .rates = WM8994_RATES,
                        .formats = WM8994_FORMATS,
@@ -3567,14 +2442,14 @@ static struct snd_soc_dai_driver wm8994_dai[] = {
                .id = 2,
                .playback = {
                        .stream_name = "AIF2 Playback",
-                       .channels_min = 2,
+                       .channels_min = 1,
                        .channels_max = 2,
                        .rates = WM8994_RATES,
                        .formats = WM8994_FORMATS,
                },
                .capture = {
                        .stream_name = "AIF2 Capture",
-                       .channels_min = 2,
+                       .channels_min = 1,
                        .channels_max = 2,
                        .rates = WM8994_RATES,
                        .formats = WM8994_FORMATS,
@@ -3586,14 +2461,14 @@ static struct snd_soc_dai_driver wm8994_dai[] = {
                .id = 3,
                .playback = {
                        .stream_name = "AIF3 Playback",
-                       .channels_min = 2,
+                       .channels_min = 1,
                        .channels_max = 2,
                        .rates = WM8994_RATES,
                        .formats = WM8994_FORMATS,
                },
                .capture = {
                        .stream_name = "AIF3 Capture",
-                       .channels_min = 2,
+                       .channels_min = 1,
                        .channels_max = 2,
                        .rates = WM8994_RATES,
                        .formats = WM8994_FORMATS,
@@ -3625,26 +2500,12 @@ static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
 static int wm8994_resume(struct snd_soc_codec *codec)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       u16 *reg_cache = codec->reg_cache;
        int i, ret;
 
        /* Restore the registers */
-       for (i = 1; i < ARRAY_SIZE(wm8994->reg_cache); i++) {
-               switch (i) {
-               case WM8994_LDO_1:
-               case WM8994_LDO_2:
-               case WM8994_SOFTWARE_RESET:
-                       /* Handled by other MFD drivers */
-                       continue;
-               default:
-                       break;
-               }
-
-               if (!access_masks[i].writable)
-                       continue;
-
-               wm8994_reg_write(codec->control_data, i, reg_cache[i]);
-       }
+       ret = snd_soc_cache_sync(codec);
+       if (ret != 0)
+               dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
 
        wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
@@ -3794,6 +2655,34 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
        dev_dbg(codec->dev, "%d ReTune Mobile configurations\n",
                pdata->num_retune_mobile_cfgs);
 
+       if (pdata->num_mbc_cfgs) {
+               struct snd_kcontrol_new control[] = {
+                       SOC_ENUM_EXT("MBC Mode", wm8994->mbc_enum,
+                                    wm8958_get_mbc_enum, wm8958_put_mbc_enum),
+               };
+
+               /* We need an array of texts for the enum API */
+               wm8994->mbc_texts = kmalloc(sizeof(char *)
+                                           * pdata->num_mbc_cfgs, GFP_KERNEL);
+               if (!wm8994->mbc_texts) {
+                       dev_err(wm8994->codec->dev,
+                               "Failed to allocate %d MBC config texts\n",
+                               pdata->num_mbc_cfgs);
+                       return;
+               }
+
+               for (i = 0; i < pdata->num_mbc_cfgs; i++)
+                       wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name;
+
+               wm8994->mbc_enum.max = pdata->num_mbc_cfgs;
+               wm8994->mbc_enum.texts = wm8994->mbc_texts;
+
+               ret = snd_soc_add_controls(wm8994->codec, control, 1);
+               if (ret != 0)
+                       dev_err(wm8994->codec->dev,
+                               "Failed to add MBC mode controls: %d\n", ret);
+       }
+
        if (pdata->num_retune_mobile_cfgs)
                wm8994_handle_retune_mobile_pdata(wm8994);
        else
@@ -3823,8 +2712,12 @@ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994_micdet *micdet;
+       struct wm8994 *control = codec->control_data;
        int reg;
 
+       if (control->type != WM8994)
+               return -EINVAL;
+
        switch (micbias) {
        case 1:
                micdet = &wm8994->micdet[0];
@@ -3863,6 +2756,10 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data)
        int reg;
        int report;
 
+#ifndef CONFIG_SND_SOC_WM8994_MODULE
+       trace_snd_soc_jack_irq(dev_name(codec->dev));
+#endif
+
        reg = snd_soc_read(codec, WM8994_INTERRUPT_RAW_STATUS_2);
        if (reg < 0) {
                dev_err(codec->dev, "Failed to read microphone status: %d\n",
@@ -3891,77 +2788,251 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+/* Default microphone detection handler for WM8958 - the user can
+ * override this if they wish.
+ */
+static void wm8958_default_micdet(u16 status, void *data)
+{
+       struct snd_soc_codec *codec = data;
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       int report = 0;
+
+       /* If nothing present then clear our statuses */
+       if (!(status & WM8958_MICD_STS)) {
+               wm8994->jack_is_video = false;
+               wm8994->jack_is_mic = false;
+               goto done;
+       }
+
+       /* Assume anything over 475 ohms is a microphone and remember
+        * that we've seen one (since buttons override it) */
+       if (status & 0x600)
+               wm8994->jack_is_mic = true;
+       if (wm8994->jack_is_mic)
+               report |= SND_JACK_MICROPHONE;
+
+       /* Video has an impedence of approximately 75 ohms; assume
+        * this isn't used as a button and remember it since buttons
+        * override it. */
+       if (status & 0x40)
+               wm8994->jack_is_video = true;
+       if (wm8994->jack_is_video)
+               report |= SND_JACK_VIDEOOUT;
+
+       /* Everything else is buttons; just assign slots */
+       if (status & 0x4)
+               report |= SND_JACK_BTN_0;
+       if (status & 0x8)
+               report |= SND_JACK_BTN_1;
+       if (status & 0x10)
+               report |= SND_JACK_BTN_2;
+       if (status & 0x20)
+               report |= SND_JACK_BTN_3;
+       if (status & 0x80)
+               report |= SND_JACK_BTN_4;
+       if (status & 0x100)
+               report |= SND_JACK_BTN_5;
+
+done:
+       snd_soc_jack_report(wm8994->micdet[0].jack,
+                           SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+                           SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5 |
+                           SND_JACK_MICROPHONE | SND_JACK_VIDEOOUT,
+                           report);
+}
+
+/**
+ * wm8958_mic_detect - Enable microphone detection via the WM8958 IRQ
+ *
+ * @codec:   WM8958 codec
+ * @jack:    jack to report detection events on
+ *
+ * Enable microphone detection functionality for the WM8958.  By
+ * default simple detection which supports the detection of up to 6
+ * buttons plus video and microphone functionality is supported.
+ *
+ * The WM8958 has an advanced jack detection facility which is able to
+ * support complex accessory detection, especially when used in
+ * conjunction with external circuitry.  In order to provide maximum
+ * flexiblity a callback is provided which allows a completely custom
+ * detection algorithm.
+ */
+int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
+                     wm8958_micdet_cb cb, void *cb_data)
+{
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994 *control = codec->control_data;
+
+       if (control->type != WM8958)
+               return -EINVAL;
+
+       if (jack) {
+               if (!cb) {
+                       dev_dbg(codec->dev, "Using default micdet callback\n");
+                       cb = wm8958_default_micdet;
+                       cb_data = codec;
+               }
+
+               wm8994->micdet[0].jack = jack;
+               wm8994->jack_cb = cb;
+               wm8994->jack_cb_data = cb_data;
+
+               snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+                                   WM8958_MICD_ENA, WM8958_MICD_ENA);
+       } else {
+               snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+                                   WM8958_MICD_ENA, 0);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm8958_mic_detect);
+
+static irqreturn_t wm8958_mic_irq(int irq, void *data)
+{
+       struct wm8994_priv *wm8994 = data;
+       struct snd_soc_codec *codec = wm8994->codec;
+       int reg;
+
+       reg = snd_soc_read(codec, WM8958_MIC_DETECT_3);
+       if (reg < 0) {
+               dev_err(codec->dev, "Failed to read mic detect status: %d\n",
+                       reg);
+               return IRQ_NONE;
+       }
+
+       if (!(reg & WM8958_MICD_VALID)) {
+               dev_dbg(codec->dev, "Mic detect data not valid\n");
+               goto out;
+       }
+
+#ifndef CONFIG_SND_SOC_WM8994_MODULE
+       trace_snd_soc_jack_irq(dev_name(codec->dev));
+#endif
+
+       if (wm8994->jack_cb)
+               wm8994->jack_cb(reg, wm8994->jack_cb_data);
+       else
+               dev_warn(codec->dev, "Accessory detection with no callback\n");
+
+out:
+       return IRQ_HANDLED;
+}
+
 static int wm8994_codec_probe(struct snd_soc_codec *codec)
 {
+       struct wm8994 *control;
        struct wm8994_priv *wm8994;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret, i;
 
        codec->control_data = dev_get_drvdata(codec->dev->parent);
+       control = codec->control_data;
 
        wm8994 = kzalloc(sizeof(struct wm8994_priv), GFP_KERNEL);
        if (wm8994 == NULL)
                return -ENOMEM;
        snd_soc_codec_set_drvdata(codec, wm8994);
 
-       codec->reg_cache = &wm8994->reg_cache;
-
        wm8994->pdata = dev_get_platdata(codec->dev->parent);
        wm8994->codec = codec;
 
-       /* Fill the cache with physical values we inherited; don't reset */
-       ret = wm8994_bulk_read(codec->control_data, 0,
-                              ARRAY_SIZE(wm8994->reg_cache) - 1,
-                              codec->reg_cache);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to fill register cache: %d\n",
-                       ret);
-               goto err;
-       }
+       pm_runtime_enable(codec->dev);
+       pm_runtime_resume(codec->dev);
 
-       /* Clear the cached values for unreadable/volatile registers to
-        * avoid potential confusion.
-        */
-       for (i = 0; i < ARRAY_SIZE(wm8994->reg_cache); i++)
-               if (wm8994_volatile(i) || !wm8994_readable(i))
-                       wm8994->reg_cache[i] = 0;
+       /* Read our current status back from the chip - we don't want to
+        * reset as this may interfere with the GPIO or LDO operation. */
+       for (i = 0; i < WM8994_CACHE_SIZE; i++) {
+               if (!wm8994_readable(i) || wm8994_volatile(i))
+                       continue;
+
+               ret = wm8994_reg_read(codec->control_data, i);
+               if (ret <= 0)
+                       continue;
+
+               ret = snd_soc_cache_write(codec, i, ret);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to initialise cache for 0x%x: %d\n",
+                               i, ret);
+                       goto err;
+               }
+       }
 
        /* Set revision-specific configuration */
        wm8994->revision = snd_soc_read(codec, WM8994_CHIP_REVISION);
-       switch (wm8994->revision) {
-       case 2:
-       case 3:
-               wm8994->hubs.dcs_codes = -5;
-               wm8994->hubs.hp_startup_mode = 1;
+       switch (control->type) {
+       case WM8994:
+               switch (wm8994->revision) {
+               case 2:
+               case 3:
+                       wm8994->hubs.dcs_codes = -5;
+                       wm8994->hubs.hp_startup_mode = 1;
+                       wm8994->hubs.dcs_readback_mode = 1;
+                       break;
+               default:
+                       wm8994->hubs.dcs_readback_mode = 1;
+                       break;
+               }
+
+       case WM8958:
                wm8994->hubs.dcs_readback_mode = 1;
                break;
+
        default:
-               wm8994->hubs.dcs_readback_mode = 1;
                break;
        }
 
-       ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC1_DET,
-                                wm8994_mic_irq, "Mic 1 detect", wm8994);
-       if (ret != 0)
-               dev_warn(codec->dev,
-                        "Failed to request Mic1 detect IRQ: %d\n", ret);
-
-       ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT,
-                                wm8994_mic_irq, "Mic 1 short", wm8994);
-       if (ret != 0)
-               dev_warn(codec->dev,
-                        "Failed to request Mic1 short IRQ: %d\n", ret);
-
-       ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC2_DET,
-                                wm8994_mic_irq, "Mic 2 detect", wm8994);
-       if (ret != 0)
-               dev_warn(codec->dev,
-                        "Failed to request Mic2 detect IRQ: %d\n", ret);
+       switch (control->type) {
+       case WM8994:
+               ret = wm8994_request_irq(codec->control_data,
+                                        WM8994_IRQ_MIC1_DET,
+                                        wm8994_mic_irq, "Mic 1 detect",
+                                        wm8994);
+               if (ret != 0)
+                       dev_warn(codec->dev,
+                                "Failed to request Mic1 detect IRQ: %d\n",
+                                ret);
+
+               ret = wm8994_request_irq(codec->control_data,
+                                        WM8994_IRQ_MIC1_SHRT,
+                                        wm8994_mic_irq, "Mic 1 short",
+                                        wm8994);
+               if (ret != 0)
+                       dev_warn(codec->dev,
+                                "Failed to request Mic1 short IRQ: %d\n",
+                                ret);
+
+               ret = wm8994_request_irq(codec->control_data,
+                                        WM8994_IRQ_MIC2_DET,
+                                        wm8994_mic_irq, "Mic 2 detect",
+                                        wm8994);
+               if (ret != 0)
+                       dev_warn(codec->dev,
+                                "Failed to request Mic2 detect IRQ: %d\n",
+                                ret);
+
+               ret = wm8994_request_irq(codec->control_data,
+                                        WM8994_IRQ_MIC2_SHRT,
+                                        wm8994_mic_irq, "Mic 2 short",
+                                        wm8994);
+               if (ret != 0)
+                       dev_warn(codec->dev,
+                                "Failed to request Mic2 short IRQ: %d\n",
+                                ret);
+               break;
 
-       ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT,
-                                wm8994_mic_irq, "Mic 2 short", wm8994);
-       if (ret != 0)
-               dev_warn(codec->dev,
-                        "Failed to request Mic2 short IRQ: %d\n", ret);
+       case WM8958:
+               ret = wm8994_request_irq(codec->control_data,
+                                        WM8994_IRQ_MIC1_DET,
+                                        wm8958_mic_irq, "Mic detect",
+                                        wm8994);
+               if (ret != 0)
+                       dev_warn(codec->dev,
+                                "Failed to request Mic detect IRQ: %d\n",
+                                ret);
+               break;
+       }
 
        /* Remember if AIFnLRCLK is configured as a GPIO.  This should be
         * configured on init - if a system wants to do this dynamically
@@ -4034,10 +3105,36 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        wm_hubs_add_analogue_controls(codec);
        snd_soc_add_controls(codec, wm8994_snd_controls,
                             ARRAY_SIZE(wm8994_snd_controls));
-       snd_soc_dapm_new_controls(codec, wm8994_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, wm8994_dapm_widgets,
                                  ARRAY_SIZE(wm8994_dapm_widgets));
+
+       switch (control->type) {
+       case WM8994:
+               snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets,
+                                         ARRAY_SIZE(wm8994_specific_dapm_widgets));
+               break;
+       case WM8958:
+               snd_soc_add_controls(codec, wm8958_snd_controls,
+                                    ARRAY_SIZE(wm8958_snd_controls));
+               snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
+                                         ARRAY_SIZE(wm8958_dapm_widgets));
+               break;
+       }
+               
+
        wm_hubs_add_analogue_routes(codec, 0, 0);
-       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+       snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
+
+       switch (control->type) {
+       case WM8994:
+               snd_soc_dapm_add_routes(dapm, wm8994_intercon,
+                                       ARRAY_SIZE(wm8994_intercon));
+               break;
+       case WM8958:
+               snd_soc_dapm_add_routes(dapm, wm8958_intercon,
+                                       ARRAY_SIZE(wm8958_intercon));
+               break;
+       }
 
        return 0;
 
@@ -4054,13 +3151,29 @@ err:
 static int  wm8994_codec_remove(struct snd_soc_codec *codec)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994 *control = codec->control_data;
 
        wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
-       wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994);
-       wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994);
-       wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994);
-       wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET, wm8994);
+       pm_runtime_disable(codec->dev);
+
+       switch (control->type) {
+       case WM8994:
+               wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT,
+                               wm8994);
+               wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET,
+                               wm8994);
+               wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT,
+                               wm8994);
+               wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET,
+                               wm8994);
+               break;
+
+       case WM8958:
+               wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET,
+                               wm8994);
+               break;
+       }
        kfree(wm8994->retune_mobile_texts);
        kfree(wm8994->drc_texts);
        kfree(wm8994);
@@ -4073,11 +3186,16 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8994 = {
        .remove =       wm8994_codec_remove,
        .suspend =      wm8994_suspend,
        .resume =       wm8994_resume,
-       .read = wm8994_read,
-       .write = wm8994_write,
+       .read =         wm8994_read,
+       .write =        wm8994_write,
        .readable_register = wm8994_readable,
        .volatile_register = wm8994_volatile,
        .set_bias_level = wm8994_set_bias_level,
+
+       .reg_cache_size = WM8994_CACHE_SIZE,
+       .reg_cache_default = wm8994_reg_defaults,
+       .reg_word_size = 2,
+       .compress_type = SND_SOC_RBTREE_COMPRESSION,
 };
 
 static int __devinit wm8994_probe(struct platform_device *pdev)
index d8dce26..0c355bf 100644 (file)
 #define WM8994_FLL_SRC_LRCLK  3
 #define WM8994_FLL_SRC_BCLK   4
 
+typedef void (*wm8958_micdet_cb)(u16 status, void *data);
+
 int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
                      int micbias, int det, int shrt);
+int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
+                     wm8958_micdet_cb cb, void *cb_data);
+
+#define WM8994_CACHE_SIZE 1570
+
+struct wm8994_access_mask {
+       unsigned short readable;   /* Mask of readable bits */
+       unsigned short writable;   /* Mask of writable bits */
+};
+
+extern const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE];
+extern const __devinitdata  u16 wm8994_reg_defaults[WM8994_CACHE_SIZE];
 
 #endif
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
new file mode 100644 (file)
index 0000000..6045cbd
--- /dev/null
@@ -0,0 +1,1818 @@
+/*
+ * wm8995.c  --  WM8995 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * Based on wm8994.c and wm_hubs.c by Mark Brown
+ *
+ * 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/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.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 "wm8995.h"
+
+static const u16 wm8995_reg_defs[WM8995_MAX_REGISTER + 1] = {
+       [0]     = 0x8995, [5]     = 0x0100, [16]    = 0x000b, [17]    = 0x000b,
+       [24]    = 0x02c0, [25]    = 0x02c0, [26]    = 0x02c0, [27]    = 0x02c0,
+       [28]    = 0x000f, [32]    = 0x0005, [33]    = 0x0005, [40]    = 0x0003,
+       [41]    = 0x0013, [48]    = 0x0004, [56]    = 0x09f8, [64]    = 0x1f25,
+       [69]    = 0x0004, [82]    = 0xaaaa, [84]    = 0x2a2a, [146]   = 0x0060,
+       [256]   = 0x0002, [257]   = 0x8004, [520]   = 0x0010, [528]   = 0x0083,
+       [529]   = 0x0083, [548]   = 0x0c80, [580]   = 0x0c80, [768]   = 0x4050,
+       [769]   = 0x4000, [771]   = 0x0040, [772]   = 0x0040, [773]   = 0x0040,
+       [774]   = 0x0004, [775]   = 0x0100, [784]   = 0x4050, [785]   = 0x4000,
+       [787]   = 0x0040, [788]   = 0x0040, [789]   = 0x0040, [1024]  = 0x00c0,
+       [1025]  = 0x00c0, [1026]  = 0x00c0, [1027]  = 0x00c0, [1028]  = 0x00c0,
+       [1029]  = 0x00c0, [1030]  = 0x00c0, [1031]  = 0x00c0, [1056]  = 0x0200,
+       [1057]  = 0x0010, [1058]  = 0x0200, [1059]  = 0x0010, [1088]  = 0x0098,
+       [1089]  = 0x0845, [1104]  = 0x0098, [1105]  = 0x0845, [1152]  = 0x6318,
+       [1153]  = 0x6300, [1154]  = 0x0fca, [1155]  = 0x0400, [1156]  = 0x00d8,
+       [1157]  = 0x1eb5, [1158]  = 0xf145, [1159]  = 0x0b75, [1160]  = 0x01c5,
+       [1161]  = 0x1c58, [1162]  = 0xf373, [1163]  = 0x0a54, [1164]  = 0x0558,
+       [1165]  = 0x168e, [1166]  = 0xf829, [1167]  = 0x07ad, [1168]  = 0x1103,
+       [1169]  = 0x0564, [1170]  = 0x0559, [1171]  = 0x4000, [1184]  = 0x6318,
+       [1185]  = 0x6300, [1186]  = 0x0fca, [1187]  = 0x0400, [1188]  = 0x00d8,
+       [1189]  = 0x1eb5, [1190]  = 0xf145, [1191]  = 0x0b75, [1192]  = 0x01c5,
+       [1193]  = 0x1c58, [1194]  = 0xf373, [1195]  = 0x0a54, [1196]  = 0x0558,
+       [1197]  = 0x168e, [1198]  = 0xf829, [1199]  = 0x07ad, [1200]  = 0x1103,
+       [1201]  = 0x0564, [1202]  = 0x0559, [1203]  = 0x4000, [1280]  = 0x00c0,
+       [1281]  = 0x00c0, [1282]  = 0x00c0, [1283]  = 0x00c0, [1312]  = 0x0200,
+       [1313]  = 0x0010, [1344]  = 0x0098, [1345]  = 0x0845, [1408]  = 0x6318,
+       [1409]  = 0x6300, [1410]  = 0x0fca, [1411]  = 0x0400, [1412]  = 0x00d8,
+       [1413]  = 0x1eb5, [1414]  = 0xf145, [1415]  = 0x0b75, [1416]  = 0x01c5,
+       [1417]  = 0x1c58, [1418]  = 0xf373, [1419]  = 0x0a54, [1420]  = 0x0558,
+       [1421]  = 0x168e, [1422]  = 0xf829, [1423]  = 0x07ad, [1424]  = 0x1103,
+       [1425]  = 0x0564, [1426]  = 0x0559, [1427]  = 0x4000, [1568]  = 0x0002,
+       [1792]  = 0xa100, [1793]  = 0xa101, [1794]  = 0xa101, [1795]  = 0xa101,
+       [1796]  = 0xa101, [1797]  = 0xa101, [1798]  = 0xa101, [1799]  = 0xa101,
+       [1800]  = 0xa101, [1801]  = 0xa101, [1802]  = 0xa101, [1803]  = 0xa101,
+       [1804]  = 0xa101, [1805]  = 0xa101, [1825]  = 0x0055, [1848]  = 0x3fff,
+       [1849]  = 0x1fff, [2049]  = 0x0001, [2050]  = 0x0069, [2056]  = 0x0002,
+       [2057]  = 0x0003, [2058]  = 0x0069, [12288] = 0x0001, [12289] = 0x0001,
+       [12291] = 0x0006, [12292] = 0x0040, [12293] = 0x0001, [12294] = 0x000f,
+       [12295] = 0x0006, [12296] = 0x0001, [12297] = 0x0003, [12298] = 0x0104,
+       [12300] = 0x0060, [12301] = 0x0011, [12302] = 0x0401, [12304] = 0x0050,
+       [12305] = 0x0003, [12306] = 0x0100, [12308] = 0x0051, [12309] = 0x0003,
+       [12310] = 0x0104, [12311] = 0x000a, [12312] = 0x0060, [12313] = 0x003b,
+       [12314] = 0x0502, [12315] = 0x0100, [12316] = 0x2fff, [12320] = 0x2fff,
+       [12324] = 0x2fff, [12328] = 0x2fff, [12332] = 0x2fff, [12336] = 0x2fff,
+       [12340] = 0x2fff, [12344] = 0x2fff, [12348] = 0x2fff, [12352] = 0x0001,
+       [12353] = 0x0001, [12355] = 0x0006, [12356] = 0x0040, [12357] = 0x0001,
+       [12358] = 0x000f, [12359] = 0x0006, [12360] = 0x0001, [12361] = 0x0003,
+       [12362] = 0x0104, [12364] = 0x0060, [12365] = 0x0011, [12366] = 0x0401,
+       [12368] = 0x0050, [12369] = 0x0003, [12370] = 0x0100, [12372] = 0x0060,
+       [12373] = 0x003b, [12374] = 0x0502, [12375] = 0x0100, [12376] = 0x2fff,
+       [12380] = 0x2fff, [12384] = 0x2fff, [12388] = 0x2fff, [12392] = 0x2fff,
+       [12396] = 0x2fff, [12400] = 0x2fff, [12404] = 0x2fff, [12408] = 0x2fff,
+       [12412] = 0x2fff, [12416] = 0x0001, [12417] = 0x0001, [12419] = 0x0006,
+       [12420] = 0x0040, [12421] = 0x0001, [12422] = 0x000f, [12423] = 0x0006,
+       [12424] = 0x0001, [12425] = 0x0003, [12426] = 0x0106, [12428] = 0x0061,
+       [12429] = 0x0011, [12430] = 0x0401, [12432] = 0x0050, [12433] = 0x0003,
+       [12434] = 0x0102, [12436] = 0x0051, [12437] = 0x0003, [12438] = 0x0106,
+       [12439] = 0x000a, [12440] = 0x0061, [12441] = 0x003b, [12442] = 0x0502,
+       [12443] = 0x0100, [12444] = 0x2fff, [12448] = 0x2fff, [12452] = 0x2fff,
+       [12456] = 0x2fff, [12460] = 0x2fff, [12464] = 0x2fff, [12468] = 0x2fff,
+       [12472] = 0x2fff, [12476] = 0x2fff, [12480] = 0x0001, [12481] = 0x0001,
+       [12483] = 0x0006, [12484] = 0x0040, [12485] = 0x0001, [12486] = 0x000f,
+       [12487] = 0x0006, [12488] = 0x0001, [12489] = 0x0003, [12490] = 0x0106,
+       [12492] = 0x0061, [12493] = 0x0011, [12494] = 0x0401, [12496] = 0x0050,
+       [12497] = 0x0003, [12498] = 0x0102, [12500] = 0x0061, [12501] = 0x003b,
+       [12502] = 0x0502, [12503] = 0x0100, [12504] = 0x2fff, [12508] = 0x2fff,
+       [12512] = 0x2fff, [12516] = 0x2fff, [12520] = 0x2fff, [12524] = 0x2fff,
+       [12528] = 0x2fff, [12532] = 0x2fff, [12536] = 0x2fff, [12540] = 0x2fff,
+       [12544] = 0x0060, [12546] = 0x0601, [12548] = 0x0050, [12550] = 0x0100,
+       [12552] = 0x0001, [12554] = 0x0104, [12555] = 0x0100, [12556] = 0x2fff,
+       [12560] = 0x2fff, [12564] = 0x2fff, [12568] = 0x2fff, [12572] = 0x2fff,
+       [12576] = 0x2fff, [12580] = 0x2fff, [12584] = 0x2fff, [12588] = 0x2fff,
+       [12592] = 0x2fff, [12596] = 0x2fff, [12600] = 0x2fff, [12604] = 0x2fff,
+       [12608] = 0x0061, [12610] = 0x0601, [12612] = 0x0050, [12614] = 0x0102,
+       [12616] = 0x0001, [12618] = 0x0106, [12619] = 0x0100, [12620] = 0x2fff,
+       [12624] = 0x2fff, [12628] = 0x2fff, [12632] = 0x2fff, [12636] = 0x2fff,
+       [12640] = 0x2fff, [12644] = 0x2fff, [12648] = 0x2fff, [12652] = 0x2fff,
+       [12656] = 0x2fff, [12660] = 0x2fff, [12664] = 0x2fff, [12668] = 0x2fff,
+       [12672] = 0x0060, [12674] = 0x0601, [12676] = 0x0061, [12678] = 0x0601,
+       [12680] = 0x0050, [12682] = 0x0300, [12684] = 0x0001, [12686] = 0x0304,
+       [12688] = 0x0040, [12690] = 0x000f, [12692] = 0x0001, [12695] = 0x0100
+};
+
+struct fll_config {
+       int src;
+       int in;
+       int out;
+};
+
+struct wm8995_priv {
+       enum snd_soc_control_type control_type;
+       int sysclk[2];
+       int mclk[2];
+       int aifclk[2];
+       struct fll_config fll[2], fll_suspend[2];
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(in1lr_pga_tlv, -1650, 150, 0);
+static const DECLARE_TLV_DB_SCALE(in1l_boost_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 150, 0);
+
+static const char *in1l_text[] = {
+       "Differential", "Single-ended IN1LN", "Single-ended IN1LP"
+};
+
+static const SOC_ENUM_SINGLE_DECL(in1l_enum, WM8995_LEFT_LINE_INPUT_CONTROL,
+                                 2, in1l_text);
+
+static const char *in1r_text[] = {
+       "Differential", "Single-ended IN1RN", "Single-ended IN1RP"
+};
+
+static const SOC_ENUM_SINGLE_DECL(in1r_enum, WM8995_LEFT_LINE_INPUT_CONTROL,
+                                 0, in1r_text);
+
+static const char *dmic_src_text[] = {
+       "DMICDAT1", "DMICDAT2", "DMICDAT3"
+};
+
+static const SOC_ENUM_SINGLE_DECL(dmic_src1_enum, WM8995_POWER_MANAGEMENT_5,
+                                 8, dmic_src_text);
+static const SOC_ENUM_SINGLE_DECL(dmic_src2_enum, WM8995_POWER_MANAGEMENT_5,
+                                 6, dmic_src_text);
+
+static const struct snd_kcontrol_new wm8995_snd_controls[] = {
+       SOC_DOUBLE_R_TLV("DAC1 Volume", WM8995_DAC1_LEFT_VOLUME,
+               WM8995_DAC1_RIGHT_VOLUME, 0, 96, 0, digital_tlv),
+       SOC_DOUBLE_R("DAC1 Switch", WM8995_DAC1_LEFT_VOLUME,
+               WM8995_DAC1_RIGHT_VOLUME, 9, 1, 1),
+
+       SOC_DOUBLE_R_TLV("DAC2 Volume", WM8995_DAC2_LEFT_VOLUME,
+               WM8995_DAC2_RIGHT_VOLUME, 0, 96, 0, digital_tlv),
+       SOC_DOUBLE_R("DAC2 Switch", WM8995_DAC2_LEFT_VOLUME,
+               WM8995_DAC2_RIGHT_VOLUME, 9, 1, 1),
+
+       SOC_DOUBLE_R_TLV("AIF1DAC1 Volume", WM8995_AIF1_DAC1_LEFT_VOLUME,
+               WM8995_AIF1_DAC1_RIGHT_VOLUME, 0, 96, 0, digital_tlv),
+       SOC_DOUBLE_R_TLV("AIF1DAC2 Volume", WM8995_AIF1_DAC2_LEFT_VOLUME,
+               WM8995_AIF1_DAC2_RIGHT_VOLUME, 0, 96, 0, digital_tlv),
+       SOC_DOUBLE_R_TLV("AIF2DAC Volume", WM8995_AIF2_DAC_LEFT_VOLUME,
+               WM8995_AIF2_DAC_RIGHT_VOLUME, 0, 96, 0, digital_tlv),
+
+       SOC_DOUBLE_R_TLV("IN1LR Volume", WM8995_LEFT_LINE_INPUT_1_VOLUME,
+               WM8995_RIGHT_LINE_INPUT_1_VOLUME, 0, 31, 0, in1lr_pga_tlv),
+
+       SOC_SINGLE_TLV("IN1L Boost", WM8995_LEFT_LINE_INPUT_CONTROL,
+               4, 3, 0, in1l_boost_tlv),
+
+       SOC_ENUM("IN1L Mode", in1l_enum),
+       SOC_ENUM("IN1R Mode", in1r_enum),
+
+       SOC_ENUM("DMIC1 SRC", dmic_src1_enum),
+       SOC_ENUM("DMIC2 SRC", dmic_src2_enum),
+
+       SOC_DOUBLE_TLV("DAC1 Sidetone Volume", WM8995_DAC1_MIXER_VOLUMES, 0, 5,
+               24, 0, sidetone_tlv),
+       SOC_DOUBLE_TLV("DAC2 Sidetone Volume", WM8995_DAC2_MIXER_VOLUMES, 0, 5,
+               24, 0, sidetone_tlv),
+
+       SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8995_AIF1_ADC1_LEFT_VOLUME,
+               WM8995_AIF1_ADC1_RIGHT_VOLUME, 0, 96, 0, digital_tlv),
+       SOC_DOUBLE_R_TLV("AIF1ADC2 Volume", WM8995_AIF1_ADC2_LEFT_VOLUME,
+               WM8995_AIF1_ADC2_RIGHT_VOLUME, 0, 96, 0, digital_tlv),
+       SOC_DOUBLE_R_TLV("AIF2ADC Volume", WM8995_AIF2_ADC_LEFT_VOLUME,
+               WM8995_AIF2_ADC_RIGHT_VOLUME, 0, 96, 0, digital_tlv)
+};
+
+static void wm8995_update_class_w(struct snd_soc_codec *codec)
+{
+       int enable = 1;
+       int source = 0;  /* GCC flow analysis can't track enable */
+       int reg, reg_r;
+
+       /* We also need the same setting for L/R and only one path */
+       reg = snd_soc_read(codec, WM8995_DAC1_LEFT_MIXER_ROUTING);
+       switch (reg) {
+       case WM8995_AIF2DACL_TO_DAC1L:
+               dev_dbg(codec->dev, "Class W source AIF2DAC\n");
+               source = 2 << WM8995_CP_DYN_SRC_SEL_SHIFT;
+               break;
+       case WM8995_AIF1DAC2L_TO_DAC1L:
+               dev_dbg(codec->dev, "Class W source AIF1DAC2\n");
+               source = 1 << WM8995_CP_DYN_SRC_SEL_SHIFT;
+               break;
+       case WM8995_AIF1DAC1L_TO_DAC1L:
+               dev_dbg(codec->dev, "Class W source AIF1DAC1\n");
+               source = 0 << WM8995_CP_DYN_SRC_SEL_SHIFT;
+               break;
+       default:
+               dev_dbg(codec->dev, "DAC mixer setting: %x\n", reg);
+               enable = 0;
+               break;
+       }
+
+       reg_r = snd_soc_read(codec, WM8995_DAC1_RIGHT_MIXER_ROUTING);
+       if (reg_r != reg) {
+               dev_dbg(codec->dev, "Left and right DAC mixers different\n");
+               enable = 0;
+       }
+
+       if (enable) {
+               dev_dbg(codec->dev, "Class W enabled\n");
+               snd_soc_update_bits(codec, WM8995_CLASS_W_1,
+                                   WM8995_CP_DYN_PWR_MASK |
+                                   WM8995_CP_DYN_SRC_SEL_MASK,
+                                   source | WM8995_CP_DYN_PWR);
+       } else {
+               dev_dbg(codec->dev, "Class W disabled\n");
+               snd_soc_update_bits(codec, WM8995_CLASS_W_1,
+                                   WM8995_CP_DYN_PWR_MASK, 0);
+       }
+}
+
+static int check_clk_sys(struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink)
+{
+       unsigned int reg;
+       const char *clk;
+
+       reg = snd_soc_read(source->codec, WM8995_CLOCKING_1);
+       /* Check what we're currently using for CLK_SYS */
+       if (reg & WM8995_SYSCLK_SRC)
+               clk = "AIF2CLK";
+       else
+               clk = "AIF1CLK";
+       return !strcmp(source->name, clk);
+}
+
+static int wm8995_put_class_w(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dapm_widget *w;
+       struct snd_soc_codec *codec;
+       int ret;
+
+       w = snd_kcontrol_chip(kcontrol);
+       codec = w->codec;
+       ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
+       wm8995_update_class_w(codec);
+       return ret;
+}
+
+static int hp_supply_event(struct snd_soc_dapm_widget *w,
+                          struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec;
+       struct wm8995_priv *wm8995;
+
+       codec = w->codec;
+       wm8995 = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               /* Enable the headphone amp */
+               snd_soc_update_bits(codec, WM8995_POWER_MANAGEMENT_1,
+                                   WM8995_HPOUT1L_ENA_MASK |
+                                   WM8995_HPOUT1R_ENA_MASK,
+                                   WM8995_HPOUT1L_ENA |
+                                   WM8995_HPOUT1R_ENA);
+
+               /* Enable the second stage */
+               snd_soc_update_bits(codec, WM8995_ANALOGUE_HP_1,
+                                   WM8995_HPOUT1L_DLY_MASK |
+                                   WM8995_HPOUT1R_DLY_MASK,
+                                   WM8995_HPOUT1L_DLY |
+                                   WM8995_HPOUT1R_DLY);
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_update_bits(codec, WM8995_CHARGE_PUMP_1,
+                                   WM8995_CP_ENA_MASK, 0);
+               break;
+       }
+
+       return 0;
+}
+
+static void dc_servo_cmd(struct snd_soc_codec *codec,
+                        unsigned int reg, unsigned int val, unsigned int mask)
+{
+       int timeout = 10;
+
+       dev_dbg(codec->dev, "%s: reg = %#x, val = %#x, mask = %#x\n",
+               __func__, reg, val, mask);
+
+       snd_soc_write(codec, reg, val);
+       while (timeout--) {
+               msleep(10);
+               val = snd_soc_read(codec, WM8995_DC_SERVO_READBACK_0);
+               if ((val & mask) == mask)
+                       return;
+       }
+
+       dev_err(codec->dev, "Timed out waiting for DC Servo\n");
+}
+
+static int hp_event(struct snd_soc_dapm_widget *w,
+                   struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec;
+       unsigned int reg;
+
+       codec = w->codec;
+       reg = snd_soc_read(codec, WM8995_ANALOGUE_HP_1);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_update_bits(codec, WM8995_CHARGE_PUMP_1,
+                                   WM8995_CP_ENA_MASK, WM8995_CP_ENA);
+
+               msleep(5);
+
+               snd_soc_update_bits(codec, WM8995_POWER_MANAGEMENT_1,
+                                   WM8995_HPOUT1L_ENA_MASK |
+                                   WM8995_HPOUT1R_ENA_MASK,
+                                   WM8995_HPOUT1L_ENA | WM8995_HPOUT1R_ENA);
+
+               udelay(20);
+
+               reg |= WM8995_HPOUT1L_DLY | WM8995_HPOUT1R_DLY;
+               snd_soc_write(codec, WM8995_ANALOGUE_HP_1, reg);
+
+               snd_soc_write(codec, WM8995_DC_SERVO_1, WM8995_DCS_ENA_CHAN_0 |
+                             WM8995_DCS_ENA_CHAN_1);
+
+               dc_servo_cmd(codec, WM8995_DC_SERVO_2,
+                            WM8995_DCS_TRIG_STARTUP_0 |
+                            WM8995_DCS_TRIG_STARTUP_1,
+                            WM8995_DCS_TRIG_DAC_WR_0 |
+                            WM8995_DCS_TRIG_DAC_WR_1);
+
+               reg |= WM8995_HPOUT1R_OUTP | WM8995_HPOUT1R_RMV_SHORT |
+                      WM8995_HPOUT1L_OUTP | WM8995_HPOUT1L_RMV_SHORT;
+               snd_soc_write(codec, WM8995_ANALOGUE_HP_1, reg);
+
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_update_bits(codec, WM8995_ANALOGUE_HP_1,
+                                   WM8995_HPOUT1L_OUTP_MASK |
+                                   WM8995_HPOUT1R_OUTP_MASK |
+                                   WM8995_HPOUT1L_RMV_SHORT_MASK |
+                                   WM8995_HPOUT1R_RMV_SHORT_MASK, 0);
+
+               snd_soc_update_bits(codec, WM8995_ANALOGUE_HP_1,
+                                   WM8995_HPOUT1L_DLY_MASK |
+                                   WM8995_HPOUT1R_DLY_MASK, 0);
+
+               snd_soc_write(codec, WM8995_DC_SERVO_1, 0);
+
+               snd_soc_update_bits(codec, WM8995_POWER_MANAGEMENT_1,
+                                   WM8995_HPOUT1L_ENA_MASK |
+                                   WM8995_HPOUT1R_ENA_MASK,
+                                   0);
+               break;
+       }
+
+       return 0;
+}
+
+static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
+{
+       struct wm8995_priv *wm8995;
+       int rate;
+       int reg1 = 0;
+       int offset;
+
+       wm8995 = snd_soc_codec_get_drvdata(codec);
+
+       if (aif)
+               offset = 4;
+       else
+               offset = 0;
+
+       switch (wm8995->sysclk[aif]) {
+       case WM8995_SYSCLK_MCLK1:
+               rate = wm8995->mclk[0];
+               break;
+       case WM8995_SYSCLK_MCLK2:
+               reg1 |= 0x8;
+               rate = wm8995->mclk[1];
+               break;
+       case WM8995_SYSCLK_FLL1:
+               reg1 |= 0x10;
+               rate = wm8995->fll[0].out;
+               break;
+       case WM8995_SYSCLK_FLL2:
+               reg1 |= 0x18;
+               rate = wm8995->fll[1].out;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (rate >= 13500000) {
+               rate /= 2;
+               reg1 |= WM8995_AIF1CLK_DIV;
+
+               dev_dbg(codec->dev, "Dividing AIF%d clock to %dHz\n",
+                       aif + 1, rate);
+       }
+
+       wm8995->aifclk[aif] = rate;
+
+       snd_soc_update_bits(codec, WM8995_AIF1_CLOCKING_1 + offset,
+                           WM8995_AIF1CLK_SRC_MASK | WM8995_AIF1CLK_DIV_MASK,
+                           reg1);
+       return 0;
+}
+
+static int configure_clock(struct snd_soc_codec *codec)
+{
+       struct wm8995_priv *wm8995;
+       int old, new;
+
+       wm8995 = snd_soc_codec_get_drvdata(codec);
+
+       /* Bring up the AIF clocks first */
+       configure_aif_clock(codec, 0);
+       configure_aif_clock(codec, 1);
+
+       /*
+        * Then switch CLK_SYS over to the higher of them; a change
+        * can only happen as a result of a clocking change which can
+        * only be made outside of DAPM so we can safely redo the
+        * clocking.
+        */
+
+       /* If they're equal it doesn't matter which is used */
+       if (wm8995->aifclk[0] == wm8995->aifclk[1])
+               return 0;
+
+       if (wm8995->aifclk[0] < wm8995->aifclk[1])
+               new = WM8995_SYSCLK_SRC;
+       else
+               new = 0;
+
+       old = snd_soc_read(codec, WM8995_CLOCKING_1) & WM8995_SYSCLK_SRC;
+
+       /* If there's no change then we're done. */
+       if (old == new)
+               return 0;
+
+       snd_soc_update_bits(codec, WM8995_CLOCKING_1,
+                           WM8995_SYSCLK_SRC_MASK, new);
+
+       snd_soc_dapm_sync(&codec->dapm);
+
+       return 0;
+}
+
+static int clk_sys_event(struct snd_soc_dapm_widget *w,
+                        struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec;
+
+       codec = w->codec;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               return configure_clock(codec);
+
+       case SND_SOC_DAPM_POST_PMD:
+               configure_clock(codec);
+               break;
+       }
+
+       return 0;
+}
+
+static const char *sidetone_text[] = {
+       "ADC/DMIC1", "DMIC2",
+};
+
+static const struct soc_enum sidetone1_enum =
+       SOC_ENUM_SINGLE(WM8995_SIDETONE, 0, 2, sidetone_text);
+
+static const struct snd_kcontrol_new sidetone1_mux =
+       SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum);
+
+static const struct soc_enum sidetone2_enum =
+       SOC_ENUM_SINGLE(WM8995_SIDETONE, 1, 2, sidetone_text);
+
+static const struct snd_kcontrol_new sidetone2_mux =
+       SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum);
+
+static const struct snd_kcontrol_new aif1adc1l_mix[] = {
+       SOC_DAPM_SINGLE("ADC/DMIC Switch", WM8995_AIF1_ADC1_LEFT_MIXER_ROUTING,
+               1, 1, 0),
+       SOC_DAPM_SINGLE("AIF2 Switch", WM8995_AIF1_ADC1_LEFT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+static const struct snd_kcontrol_new aif1adc1r_mix[] = {
+       SOC_DAPM_SINGLE("ADC/DMIC Switch", WM8995_AIF1_ADC1_RIGHT_MIXER_ROUTING,
+               1, 1, 0),
+       SOC_DAPM_SINGLE("AIF2 Switch", WM8995_AIF1_ADC1_RIGHT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+static const struct snd_kcontrol_new aif1adc2l_mix[] = {
+       SOC_DAPM_SINGLE("DMIC Switch", WM8995_AIF1_ADC2_LEFT_MIXER_ROUTING,
+               1, 1, 0),
+       SOC_DAPM_SINGLE("AIF2 Switch", WM8995_AIF1_ADC2_LEFT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+static const struct snd_kcontrol_new aif1adc2r_mix[] = {
+       SOC_DAPM_SINGLE("DMIC Switch", WM8995_AIF1_ADC2_RIGHT_MIXER_ROUTING,
+               1, 1, 0),
+       SOC_DAPM_SINGLE("AIF2 Switch", WM8995_AIF1_ADC2_RIGHT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac1l_mix[] = {
+       WM8995_CLASS_W_SWITCH("Right Sidetone Switch", WM8995_DAC1_LEFT_MIXER_ROUTING,
+               5, 1, 0),
+       WM8995_CLASS_W_SWITCH("Left Sidetone Switch", WM8995_DAC1_LEFT_MIXER_ROUTING,
+               4, 1, 0),
+       WM8995_CLASS_W_SWITCH("AIF2 Switch", WM8995_DAC1_LEFT_MIXER_ROUTING,
+               2, 1, 0),
+       WM8995_CLASS_W_SWITCH("AIF1.2 Switch", WM8995_DAC1_LEFT_MIXER_ROUTING,
+               1, 1, 0),
+       WM8995_CLASS_W_SWITCH("AIF1.1 Switch", WM8995_DAC1_LEFT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac1r_mix[] = {
+       WM8995_CLASS_W_SWITCH("Right Sidetone Switch", WM8995_DAC1_RIGHT_MIXER_ROUTING,
+               5, 1, 0),
+       WM8995_CLASS_W_SWITCH("Left Sidetone Switch", WM8995_DAC1_RIGHT_MIXER_ROUTING,
+               4, 1, 0),
+       WM8995_CLASS_W_SWITCH("AIF2 Switch", WM8995_DAC1_RIGHT_MIXER_ROUTING,
+               2, 1, 0),
+       WM8995_CLASS_W_SWITCH("AIF1.2 Switch", WM8995_DAC1_RIGHT_MIXER_ROUTING,
+               1, 1, 0),
+       WM8995_CLASS_W_SWITCH("AIF1.1 Switch", WM8995_DAC1_RIGHT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+static const struct snd_kcontrol_new aif2dac2l_mix[] = {
+       SOC_DAPM_SINGLE("Right Sidetone Switch", WM8995_DAC2_LEFT_MIXER_ROUTING,
+               5, 1, 0),
+       SOC_DAPM_SINGLE("Left Sidetone Switch", WM8995_DAC2_LEFT_MIXER_ROUTING,
+               4, 1, 0),
+       SOC_DAPM_SINGLE("AIF2 Switch", WM8995_DAC2_LEFT_MIXER_ROUTING,
+               2, 1, 0),
+       SOC_DAPM_SINGLE("AIF1.2 Switch", WM8995_DAC2_LEFT_MIXER_ROUTING,
+               1, 1, 0),
+       SOC_DAPM_SINGLE("AIF1.1 Switch", WM8995_DAC2_LEFT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+static const struct snd_kcontrol_new aif2dac2r_mix[] = {
+       SOC_DAPM_SINGLE("Right Sidetone Switch", WM8995_DAC2_RIGHT_MIXER_ROUTING,
+               5, 1, 0),
+       SOC_DAPM_SINGLE("Left Sidetone Switch", WM8995_DAC2_RIGHT_MIXER_ROUTING,
+               4, 1, 0),
+       SOC_DAPM_SINGLE("AIF2 Switch", WM8995_DAC2_RIGHT_MIXER_ROUTING,
+               2, 1, 0),
+       SOC_DAPM_SINGLE("AIF1.2 Switch", WM8995_DAC2_RIGHT_MIXER_ROUTING,
+               1, 1, 0),
+       SOC_DAPM_SINGLE("AIF1.1 Switch", WM8995_DAC2_RIGHT_MIXER_ROUTING,
+               0, 1, 0),
+};
+
+static const struct snd_kcontrol_new in1l_pga =
+       SOC_DAPM_SINGLE("IN1L Switch", WM8995_POWER_MANAGEMENT_2, 5, 1, 0);
+
+static const struct snd_kcontrol_new in1r_pga =
+       SOC_DAPM_SINGLE("IN1R Switch", WM8995_POWER_MANAGEMENT_2, 4, 1, 0);
+
+static const char *adc_mux_text[] = {
+       "ADC",
+       "DMIC",
+};
+
+static const struct soc_enum adc_enum =
+       SOC_ENUM_SINGLE(0, 0, 2, adc_mux_text);
+
+static const struct snd_kcontrol_new adcl_mux =
+       SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum);
+
+static const struct snd_kcontrol_new adcr_mux =
+       SOC_DAPM_ENUM_VIRT("ADCR Mux", adc_enum);
+
+static const char *spk_src_text[] = {
+       "DAC1L", "DAC1R", "DAC2L", "DAC2R"
+};
+
+static const SOC_ENUM_SINGLE_DECL(spk1l_src_enum, WM8995_LEFT_PDM_SPEAKER_1,
+                                 0, spk_src_text);
+static const SOC_ENUM_SINGLE_DECL(spk1r_src_enum, WM8995_RIGHT_PDM_SPEAKER_1,
+                                 0, spk_src_text);
+static const SOC_ENUM_SINGLE_DECL(spk2l_src_enum, WM8995_LEFT_PDM_SPEAKER_2,
+                                 0, spk_src_text);
+static const SOC_ENUM_SINGLE_DECL(spk2r_src_enum, WM8995_RIGHT_PDM_SPEAKER_2,
+                                 0, spk_src_text);
+
+static const struct snd_kcontrol_new spk1l_mux =
+       SOC_DAPM_ENUM("SPK1L SRC", spk1l_src_enum);
+static const struct snd_kcontrol_new spk1r_mux =
+       SOC_DAPM_ENUM("SPK1R SRC", spk1r_src_enum);
+static const struct snd_kcontrol_new spk2l_mux =
+       SOC_DAPM_ENUM("SPK2L SRC", spk2l_src_enum);
+static const struct snd_kcontrol_new spk2r_mux =
+       SOC_DAPM_ENUM("SPK2R SRC", spk2r_src_enum);
+
+static const struct snd_soc_dapm_widget wm8995_dapm_widgets[] = {
+       SND_SOC_DAPM_INPUT("DMIC1DAT"),
+       SND_SOC_DAPM_INPUT("DMIC2DAT"),
+
+       SND_SOC_DAPM_INPUT("IN1L"),
+       SND_SOC_DAPM_INPUT("IN1R"),
+
+       SND_SOC_DAPM_MIXER("IN1L PGA", SND_SOC_NOPM, 0, 0,
+               &in1l_pga, 1),
+       SND_SOC_DAPM_MIXER("IN1R PGA", SND_SOC_NOPM, 0, 0,
+               &in1r_pga, 1),
+
+       SND_SOC_DAPM_MICBIAS("MICBIAS1", WM8995_POWER_MANAGEMENT_1, 8, 0),
+       SND_SOC_DAPM_MICBIAS("MICBIAS2", WM8995_POWER_MANAGEMENT_1, 9, 0),
+
+       SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8995_AIF1_CLOCKING_1, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8995_AIF2_CLOCKING_1, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DSP1CLK", WM8995_CLOCKING_1, 3, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DSP2CLK", WM8995_CLOCKING_1, 2, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("SYSDSPCLK", WM8995_CLOCKING_1, 1, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+       SND_SOC_DAPM_AIF_OUT("AIF1ADC1L", "AIF1 Capture", 0,
+               WM8995_POWER_MANAGEMENT_3, 9, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1ADC1R", "AIF1 Capture", 0,
+               WM8995_POWER_MANAGEMENT_3, 8, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1ADCDAT", "AIF1 Capture", 0,
+       SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1ADC2L", "AIF1 Capture",
+               0, WM8995_POWER_MANAGEMENT_3, 11, 0),
+       SND_SOC_DAPM_AIF_OUT("AIF1ADC2R", "AIF1 Capture",
+               0, WM8995_POWER_MANAGEMENT_3, 10, 0),
+
+       SND_SOC_DAPM_VIRT_MUX("ADCL Mux", SND_SOC_NOPM, 1, 0,
+               &adcl_mux),
+       SND_SOC_DAPM_VIRT_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0,
+               &adcr_mux),
+
+       SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8995_POWER_MANAGEMENT_3, 5, 0),
+       SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8995_POWER_MANAGEMENT_3, 4, 0),
+       SND_SOC_DAPM_ADC("DMIC1L", NULL, WM8995_POWER_MANAGEMENT_3, 3, 0),
+       SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8995_POWER_MANAGEMENT_3, 2, 0),
+
+       SND_SOC_DAPM_ADC("ADCL", NULL, WM8995_POWER_MANAGEMENT_3, 1, 0),
+       SND_SOC_DAPM_ADC("ADCR", NULL, WM8995_POWER_MANAGEMENT_3, 0, 0),
+
+       SND_SOC_DAPM_MIXER("AIF1ADC1L Mixer", SND_SOC_NOPM, 0, 0,
+               aif1adc1l_mix, ARRAY_SIZE(aif1adc1l_mix)),
+       SND_SOC_DAPM_MIXER("AIF1ADC1R Mixer", SND_SOC_NOPM, 0, 0,
+               aif1adc1r_mix, ARRAY_SIZE(aif1adc1r_mix)),
+       SND_SOC_DAPM_MIXER("AIF1ADC2L Mixer", SND_SOC_NOPM, 0, 0,
+               aif1adc2l_mix, ARRAY_SIZE(aif1adc2l_mix)),
+       SND_SOC_DAPM_MIXER("AIF1ADC2R Mixer", SND_SOC_NOPM, 0, 0,
+               aif1adc2r_mix, ARRAY_SIZE(aif1adc2r_mix)),
+
+       SND_SOC_DAPM_AIF_IN("AIF1DAC1L", NULL, 0, WM8995_POWER_MANAGEMENT_4,
+               9, 0),
+       SND_SOC_DAPM_AIF_IN("AIF1DAC1R", NULL, 0, WM8995_POWER_MANAGEMENT_4,
+               8, 0),
+       SND_SOC_DAPM_AIF_IN("AIF1DACDAT", "AIF1 Playback", 0, SND_SOC_NOPM,
+               0, 0),
+
+       SND_SOC_DAPM_AIF_IN("AIF1DAC2L", NULL, 0, WM8995_POWER_MANAGEMENT_4,
+               11, 0),
+       SND_SOC_DAPM_AIF_IN("AIF1DAC2R", NULL, 0, WM8995_POWER_MANAGEMENT_4,
+               10, 0),
+
+       SND_SOC_DAPM_MIXER("AIF2DAC2L Mixer", SND_SOC_NOPM, 0, 0,
+               aif2dac2l_mix, ARRAY_SIZE(aif2dac2l_mix)),
+       SND_SOC_DAPM_MIXER("AIF2DAC2R Mixer", SND_SOC_NOPM, 0, 0,
+               aif2dac2r_mix, ARRAY_SIZE(aif2dac2r_mix)),
+
+       SND_SOC_DAPM_DAC("DAC2L", NULL, WM8995_POWER_MANAGEMENT_4, 3, 0),
+       SND_SOC_DAPM_DAC("DAC2R", NULL, WM8995_POWER_MANAGEMENT_4, 2, 0),
+       SND_SOC_DAPM_DAC("DAC1L", NULL, WM8995_POWER_MANAGEMENT_4, 1, 0),
+       SND_SOC_DAPM_DAC("DAC1R", NULL, WM8995_POWER_MANAGEMENT_4, 0, 0),
+
+       SND_SOC_DAPM_MIXER("DAC1L Mixer", SND_SOC_NOPM, 0, 0, dac1l_mix,
+               ARRAY_SIZE(dac1l_mix)),
+       SND_SOC_DAPM_MIXER("DAC1R Mixer", SND_SOC_NOPM, 0, 0, dac1r_mix,
+               ARRAY_SIZE(dac1r_mix)),
+
+       SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &sidetone1_mux),
+       SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &sidetone2_mux),
+
+       SND_SOC_DAPM_PGA_E("Headphone PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
+               hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+       SND_SOC_DAPM_SUPPLY("Headphone Supply", SND_SOC_NOPM, 0, 0,
+               hp_supply_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+       SND_SOC_DAPM_MUX("SPK1L Driver", WM8995_LEFT_PDM_SPEAKER_1,
+               4, 0, &spk1l_mux),
+       SND_SOC_DAPM_MUX("SPK1R Driver", WM8995_RIGHT_PDM_SPEAKER_1,
+               4, 0, &spk1r_mux),
+       SND_SOC_DAPM_MUX("SPK2L Driver", WM8995_LEFT_PDM_SPEAKER_2,
+               4, 0, &spk2l_mux),
+       SND_SOC_DAPM_MUX("SPK2R Driver", WM8995_RIGHT_PDM_SPEAKER_2,
+               4, 0, &spk2r_mux),
+
+       SND_SOC_DAPM_SUPPLY("LDO2", WM8995_POWER_MANAGEMENT_2, 1, 0, NULL, 0),
+
+       SND_SOC_DAPM_OUTPUT("HP1L"),
+       SND_SOC_DAPM_OUTPUT("HP1R"),
+       SND_SOC_DAPM_OUTPUT("SPK1L"),
+       SND_SOC_DAPM_OUTPUT("SPK1R"),
+       SND_SOC_DAPM_OUTPUT("SPK2L"),
+       SND_SOC_DAPM_OUTPUT("SPK2R")
+};
+
+static const struct snd_soc_dapm_route wm8995_intercon[] = {
+       { "CLK_SYS", NULL, "AIF1CLK", check_clk_sys },
+       { "CLK_SYS", NULL, "AIF2CLK", check_clk_sys },
+
+       { "DSP1CLK", NULL, "CLK_SYS" },
+       { "DSP2CLK", NULL, "CLK_SYS" },
+       { "SYSDSPCLK", NULL, "CLK_SYS" },
+
+       { "AIF1ADC1L", NULL, "AIF1CLK" },
+       { "AIF1ADC1L", NULL, "DSP1CLK" },
+       { "AIF1ADC1R", NULL, "AIF1CLK" },
+       { "AIF1ADC1R", NULL, "DSP1CLK" },
+       { "AIF1ADC1R", NULL, "SYSDSPCLK" },
+
+       { "AIF1ADC2L", NULL, "AIF1CLK" },
+       { "AIF1ADC2L", NULL, "DSP1CLK" },
+       { "AIF1ADC2R", NULL, "AIF1CLK" },
+       { "AIF1ADC2R", NULL, "DSP1CLK" },
+       { "AIF1ADC2R", NULL, "SYSDSPCLK" },
+
+       { "DMIC1L", NULL, "DMIC1DAT" },
+       { "DMIC1L", NULL, "CLK_SYS" },
+       { "DMIC1R", NULL, "DMIC1DAT" },
+       { "DMIC1R", NULL, "CLK_SYS" },
+       { "DMIC2L", NULL, "DMIC2DAT" },
+       { "DMIC2L", NULL, "CLK_SYS" },
+       { "DMIC2R", NULL, "DMIC2DAT" },
+       { "DMIC2R", NULL, "CLK_SYS" },
+
+       { "ADCL", NULL, "AIF1CLK" },
+       { "ADCL", NULL, "DSP1CLK" },
+       { "ADCL", NULL, "SYSDSPCLK" },
+
+       { "ADCR", NULL, "AIF1CLK" },
+       { "ADCR", NULL, "DSP1CLK" },
+       { "ADCR", NULL, "SYSDSPCLK" },
+
+       { "IN1L PGA", "IN1L Switch", "IN1L" },
+       { "IN1R PGA", "IN1R Switch", "IN1R" },
+       { "IN1L PGA", NULL, "LDO2" },
+       { "IN1R PGA", NULL, "LDO2" },
+
+       { "ADCL", NULL, "IN1L PGA" },
+       { "ADCR", NULL, "IN1R PGA" },
+
+       { "ADCL Mux", "ADC", "ADCL" },
+       { "ADCL Mux", "DMIC", "DMIC1L" },
+       { "ADCR Mux", "ADC", "ADCR" },
+       { "ADCR Mux", "DMIC", "DMIC1R" },
+
+       /* AIF1 outputs */
+       { "AIF1ADC1L", NULL, "AIF1ADC1L Mixer" },
+       { "AIF1ADC1L Mixer", "ADC/DMIC Switch", "ADCL Mux" },
+
+       { "AIF1ADC1R", NULL, "AIF1ADC1R Mixer" },
+       { "AIF1ADC1R Mixer", "ADC/DMIC Switch", "ADCR Mux" },
+
+       { "AIF1ADC2L", NULL, "AIF1ADC2L Mixer" },
+       { "AIF1ADC2L Mixer", "DMIC Switch", "DMIC2L" },
+
+       { "AIF1ADC2R", NULL, "AIF1ADC2R Mixer" },
+       { "AIF1ADC2R Mixer", "DMIC Switch", "DMIC2R" },
+
+       /* Sidetone */
+       { "Left Sidetone", "ADC/DMIC1", "AIF1ADC1L" },
+       { "Left Sidetone", "DMIC2", "AIF1ADC2L" },
+       { "Right Sidetone", "ADC/DMIC1", "AIF1ADC1R" },
+       { "Right Sidetone", "DMIC2", "AIF1ADC2R" },
+
+       { "AIF1DAC1L", NULL, "AIF1CLK" },
+       { "AIF1DAC1L", NULL, "DSP1CLK" },
+       { "AIF1DAC1R", NULL, "AIF1CLK" },
+       { "AIF1DAC1R", NULL, "DSP1CLK" },
+       { "AIF1DAC1R", NULL, "SYSDSPCLK" },
+
+       { "AIF1DAC2L", NULL, "AIF1CLK" },
+       { "AIF1DAC2L", NULL, "DSP1CLK" },
+       { "AIF1DAC2R", NULL, "AIF1CLK" },
+       { "AIF1DAC2R", NULL, "DSP1CLK" },
+       { "AIF1DAC2R", NULL, "SYSDSPCLK" },
+
+       { "DAC1L", NULL, "AIF1CLK" },
+       { "DAC1L", NULL, "DSP1CLK" },
+       { "DAC1L", NULL, "SYSDSPCLK" },
+
+       { "DAC1R", NULL, "AIF1CLK" },
+       { "DAC1R", NULL, "DSP1CLK" },
+       { "DAC1R", NULL, "SYSDSPCLK" },
+
+       { "AIF1DAC1L", NULL, "AIF1DACDAT" },
+       { "AIF1DAC1R", NULL, "AIF1DACDAT" },
+       { "AIF1DAC2L", NULL, "AIF1DACDAT" },
+       { "AIF1DAC2R", NULL, "AIF1DACDAT" },
+
+       /* DAC1 inputs */
+       { "DAC1L", NULL, "DAC1L Mixer" },
+       { "DAC1L Mixer", "AIF1.1 Switch", "AIF1DAC1L" },
+       { "DAC1L Mixer", "AIF1.2 Switch", "AIF1DAC2L" },
+       { "DAC1L Mixer", "Left Sidetone Switch", "Left Sidetone" },
+       { "DAC1L Mixer", "Right Sidetone Switch", "Right Sidetone" },
+
+       { "DAC1R", NULL, "DAC1R Mixer" },
+       { "DAC1R Mixer", "AIF1.1 Switch", "AIF1DAC1R" },
+       { "DAC1R Mixer", "AIF1.2 Switch", "AIF1DAC2R" },
+       { "DAC1R Mixer", "Left Sidetone Switch", "Left Sidetone" },
+       { "DAC1R Mixer", "Right Sidetone Switch", "Right Sidetone" },
+
+       /* DAC2/AIF2 outputs */
+       { "DAC2L", NULL, "AIF2DAC2L Mixer" },
+       { "AIF2DAC2L Mixer", "AIF1.2 Switch", "AIF1DAC2L" },
+       { "AIF2DAC2L Mixer", "AIF1.1 Switch", "AIF1DAC1L" },
+
+       { "DAC2R", NULL, "AIF2DAC2R Mixer" },
+       { "AIF2DAC2R Mixer", "AIF1.2 Switch", "AIF1DAC2R" },
+       { "AIF2DAC2R Mixer", "AIF1.1 Switch", "AIF1DAC1R" },
+
+       /* Output stages */
+       { "Headphone PGA", NULL, "DAC1L" },
+       { "Headphone PGA", NULL, "DAC1R" },
+
+       { "Headphone PGA", NULL, "DAC2L" },
+       { "Headphone PGA", NULL, "DAC2R" },
+
+       { "Headphone PGA", NULL, "Headphone Supply" },
+       { "Headphone PGA", NULL, "CLK_SYS" },
+       { "Headphone PGA", NULL, "LDO2" },
+
+       { "HP1L", NULL, "Headphone PGA" },
+       { "HP1R", NULL, "Headphone PGA" },
+
+       { "SPK1L Driver", "DAC1L", "DAC1L" },
+       { "SPK1L Driver", "DAC1R", "DAC1R" },
+       { "SPK1L Driver", "DAC2L", "DAC2L" },
+       { "SPK1L Driver", "DAC2R", "DAC2R" },
+       { "SPK1L Driver", NULL, "CLK_SYS" },
+
+       { "SPK1R Driver", "DAC1L", "DAC1L" },
+       { "SPK1R Driver", "DAC1R", "DAC1R" },
+       { "SPK1R Driver", "DAC2L", "DAC2L" },
+       { "SPK1R Driver", "DAC2R", "DAC2R" },
+       { "SPK1R Driver", NULL, "CLK_SYS" },
+
+       { "SPK2L Driver", "DAC1L", "DAC1L" },
+       { "SPK2L Driver", "DAC1R", "DAC1R" },
+       { "SPK2L Driver", "DAC2L", "DAC2L" },
+       { "SPK2L Driver", "DAC2R", "DAC2R" },
+       { "SPK2L Driver", NULL, "CLK_SYS" },
+
+       { "SPK2R Driver", "DAC1L", "DAC1L" },
+       { "SPK2R Driver", "DAC1R", "DAC1R" },
+       { "SPK2R Driver", "DAC2L", "DAC2L" },
+       { "SPK2R Driver", "DAC2R", "DAC2R" },
+       { "SPK2R Driver", NULL, "CLK_SYS" },
+
+       { "SPK1L", NULL, "SPK1L Driver" },
+       { "SPK1R", NULL, "SPK1R Driver" },
+       { "SPK2L", NULL, "SPK2L Driver" },
+       { "SPK2R", NULL, "SPK2R Driver" }
+};
+
+static int wm8995_volatile(unsigned int reg)
+{
+       /* out of bounds registers are generally considered
+        * volatile to support register banks that are partially
+        * owned by something else for e.g. a DSP
+        */
+       if (reg > WM8995_MAX_CACHED_REGISTER)
+               return 1;
+
+       switch (reg) {
+       case WM8995_SOFTWARE_RESET:
+       case WM8995_DC_SERVO_READBACK_0:
+       case WM8995_INTERRUPT_STATUS_1:
+       case WM8995_INTERRUPT_STATUS_2:
+       case WM8995_INTERRUPT_STATUS_1_MASK:
+       case WM8995_INTERRUPT_STATUS_2_MASK:
+       case WM8995_INTERRUPT_CONTROL:
+       case WM8995_ACCESSORY_DETECT_MODE1:
+       case WM8995_ACCESSORY_DETECT_MODE2:
+       case WM8995_HEADPHONE_DETECT1:
+       case WM8995_HEADPHONE_DETECT2:
+               return 1;
+       }
+
+       return 0;
+}
+
+static int wm8995_aif_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       int mute_reg;
+
+       switch (dai->id) {
+       case 0:
+               mute_reg = WM8995_AIF1_DAC1_FILTERS_1;
+               break;
+       case 1:
+               mute_reg = WM8995_AIF2_DAC_FILTERS_1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, mute_reg, WM8995_AIF1DAC1_MUTE_MASK,
+                           !!mute << WM8995_AIF1DAC1_MUTE_SHIFT);
+       return 0;
+}
+
+static int wm8995_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec;
+       int master;
+       int aif;
+
+       codec = dai->codec;
+
+       master = 0;
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               master = WM8995_AIF1_MSTR;
+               break;
+       default:
+               dev_err(dai->dev, "Unknown master/slave configuration\n");
+               return -EINVAL;
+       }
+
+       aif = 0;
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_B:
+               aif |= WM8995_AIF1_LRCLK_INV;
+       case SND_SOC_DAIFMT_DSP_A:
+               aif |= (0x3 << WM8995_AIF1_FMT_SHIFT);
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               aif |= (0x2 << WM8995_AIF1_FMT_SHIFT);
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               aif |= (0x1 << WM8995_AIF1_FMT_SHIFT);
+               break;
+       default:
+               dev_err(dai->dev, "Unknown dai format\n");
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               /* frame inversion not valid for DSP modes */
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       aif |= WM8995_AIF1_BCLK_INV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       case SND_SOC_DAIFMT_I2S:
+       case SND_SOC_DAIFMT_RIGHT_J:
+       case SND_SOC_DAIFMT_LEFT_J:
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       aif |= WM8995_AIF1_BCLK_INV | WM8995_AIF1_LRCLK_INV;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       aif |= WM8995_AIF1_BCLK_INV;
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       aif |= WM8995_AIF1_LRCLK_INV;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8995_AIF1_CONTROL_1,
+                           WM8995_AIF1_BCLK_INV_MASK |
+                           WM8995_AIF1_LRCLK_INV_MASK |
+                           WM8995_AIF1_FMT_MASK, aif);
+       snd_soc_update_bits(codec, WM8995_AIF1_MASTER_SLAVE,
+                           WM8995_AIF1_MSTR_MASK, master);
+       return 0;
+}
+
+static const int srs[] = {
+       8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100,
+       48000, 88200, 96000
+};
+
+static const int fs_ratios[] = {
+       -1 /* reserved */,
+       128, 192, 256, 384, 512, 768, 1024, 1408, 1536
+};
+
+static const int bclk_divs[] = {
+       10, 15, 20, 30, 40, 55, 60, 80, 110, 120, 160, 220, 240, 320, 440, 480
+};
+
+static int wm8995_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec;
+       struct wm8995_priv *wm8995;
+       int aif1_reg;
+       int bclk_reg;
+       int lrclk_reg;
+       int rate_reg;
+       int bclk_rate;
+       int aif1;
+       int lrclk, bclk;
+       int i, rate_val, best, best_val, cur_val;
+
+       codec = dai->codec;
+       wm8995 = snd_soc_codec_get_drvdata(codec);
+
+       switch (dai->id) {
+       case 0:
+               aif1_reg = WM8995_AIF1_CONTROL_1;
+               bclk_reg = WM8995_AIF1_BCLK;
+               rate_reg = WM8995_AIF1_RATE;
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK /* ||
+                       wm8995->lrclk_shared[0] */) {
+                       lrclk_reg = WM8995_AIF1DAC_LRCLK;
+               } else {
+                       lrclk_reg = WM8995_AIF1ADC_LRCLK;
+                       dev_dbg(codec->dev, "AIF1 using split LRCLK\n");
+               }
+               break;
+       case 1:
+               aif1_reg = WM8995_AIF2_CONTROL_1;
+               bclk_reg = WM8995_AIF2_BCLK;
+               rate_reg = WM8995_AIF2_RATE;
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK /* ||
+                   wm8995->lrclk_shared[1] */) {
+                       lrclk_reg = WM8995_AIF2DAC_LRCLK;
+               } else {
+                       lrclk_reg = WM8995_AIF2ADC_LRCLK;
+                       dev_dbg(codec->dev, "AIF2 using split LRCLK\n");
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       bclk_rate = snd_soc_params_to_bclk(params);
+       if (bclk_rate < 0)
+               return bclk_rate;
+
+       aif1 = 0;
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               aif1 |= (0x1 << WM8995_AIF1_WL_SHIFT);
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               aif1 |= (0x2 << WM8995_AIF1_WL_SHIFT);
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               aif1 |= (0x3 << WM8995_AIF1_WL_SHIFT);
+               break;
+       default:
+               dev_err(dai->dev, "Unsupported word length %u\n",
+                       params_format(params));
+               return -EINVAL;
+       }
+
+       /* try to find a suitable sample rate */
+       for (i = 0; i < ARRAY_SIZE(srs); ++i)
+               if (srs[i] == params_rate(params))
+                       break;
+       if (i == ARRAY_SIZE(srs)) {
+               dev_err(dai->dev, "Sample rate %d is not supported\n",
+                       params_rate(params));
+               return -EINVAL;
+       }
+       rate_val = i << WM8995_AIF1_SR_SHIFT;
+
+       dev_dbg(dai->dev, "Sample rate is %dHz\n", srs[i]);
+       dev_dbg(dai->dev, "AIF%dCLK is %dHz, target BCLK %dHz\n",
+               dai->id + 1, wm8995->aifclk[dai->id], bclk_rate);
+
+       /* AIFCLK/fs ratio; look for a close match in either direction */
+       best = 1;
+       best_val = abs((fs_ratios[1] * params_rate(params))
+                      - wm8995->aifclk[dai->id]);
+       for (i = 2; i < ARRAY_SIZE(fs_ratios); i++) {
+               cur_val = abs((fs_ratios[i] * params_rate(params))
+                             - wm8995->aifclk[dai->id]);
+               if (cur_val >= best_val)
+                       continue;
+               best = i;
+               best_val = cur_val;
+       }
+       rate_val |= best;
+
+       dev_dbg(dai->dev, "Selected AIF%dCLK/fs = %d\n",
+               dai->id + 1, fs_ratios[best]);
+
+       /*
+        * We may not get quite the right frequency if using
+        * approximate clocks so look for the closest match that is
+        * higher than the target (we need to ensure that there enough
+        * BCLKs to clock out the samples).
+        */
+       best = 0;
+       bclk = 0;
+       for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+               cur_val = (wm8995->aifclk[dai->id] * 10 / bclk_divs[i]) - bclk_rate;
+               if (cur_val < 0) /* BCLK table is sorted */
+                       break;
+               best = i;
+       }
+       bclk |= best << WM8995_AIF1_BCLK_DIV_SHIFT;
+
+       bclk_rate = wm8995->aifclk[dai->id] * 10 / bclk_divs[best];
+       dev_dbg(dai->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n",
+               bclk_divs[best], bclk_rate);
+
+       lrclk = bclk_rate / params_rate(params);
+       dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n",
+               lrclk, bclk_rate / lrclk);
+
+       snd_soc_update_bits(codec, aif1_reg,
+                           WM8995_AIF1_WL_MASK, aif1);
+       snd_soc_update_bits(codec, bclk_reg,
+                           WM8995_AIF1_BCLK_DIV_MASK, bclk);
+       snd_soc_update_bits(codec, lrclk_reg,
+                           WM8995_AIF1DAC_RATE_MASK, lrclk);
+       snd_soc_update_bits(codec, rate_reg,
+                           WM8995_AIF1_SR_MASK |
+                           WM8995_AIF1CLK_RATE_MASK, rate_val);
+       return 0;
+}
+
+static int wm8995_set_tristate(struct snd_soc_dai *codec_dai, int tristate)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int reg, val, mask;
+
+       switch (codec_dai->id) {
+       case 0:
+               reg = WM8995_AIF1_MASTER_SLAVE;
+               mask = WM8995_AIF1_TRI;
+               break;
+       case 1:
+               reg = WM8995_AIF2_MASTER_SLAVE;
+               mask = WM8995_AIF2_TRI;
+               break;
+       case 2:
+               reg = WM8995_POWER_MANAGEMENT_5;
+               mask = WM8995_AIF3_TRI;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (tristate)
+               val = mask;
+       else
+               val = 0;
+
+       return snd_soc_update_bits(codec, reg, mask, reg);
+}
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+struct fll_div {
+       u16 outdiv;
+       u16 n;
+       u16 k;
+       u16 clk_ref_div;
+       u16 fll_fratio;
+};
+
+static int wm8995_get_fll_config(struct fll_div *fll,
+                                int freq_in, int freq_out)
+{
+       u64 Kpart;
+       unsigned int K, Ndiv, Nmod;
+
+       pr_debug("FLL input=%dHz, output=%dHz\n", freq_in, freq_out);
+
+       /* Scale the input frequency down to <= 13.5MHz */
+       fll->clk_ref_div = 0;
+       while (freq_in > 13500000) {
+               fll->clk_ref_div++;
+               freq_in /= 2;
+
+               if (fll->clk_ref_div > 3)
+                       return -EINVAL;
+       }
+       pr_debug("CLK_REF_DIV=%d, Fref=%dHz\n", fll->clk_ref_div, freq_in);
+
+       /* Scale the output to give 90MHz<=Fvco<=100MHz */
+       fll->outdiv = 3;
+       while (freq_out * (fll->outdiv + 1) < 90000000) {
+               fll->outdiv++;
+               if (fll->outdiv > 63)
+                       return -EINVAL;
+       }
+       freq_out *= fll->outdiv + 1;
+       pr_debug("OUTDIV=%d, Fvco=%dHz\n", fll->outdiv, freq_out);
+
+       if (freq_in > 1000000) {
+               fll->fll_fratio = 0;
+       } else if (freq_in > 256000) {
+               fll->fll_fratio = 1;
+               freq_in *= 2;
+       } else if (freq_in > 128000) {
+               fll->fll_fratio = 2;
+               freq_in *= 4;
+       } else if (freq_in > 64000) {
+               fll->fll_fratio = 3;
+               freq_in *= 8;
+       } else {
+               fll->fll_fratio = 4;
+               freq_in *= 16;
+       }
+       pr_debug("FLL_FRATIO=%d, Fref=%dHz\n", fll->fll_fratio, freq_in);
+
+       /* Now, calculate N.K */
+       Ndiv = freq_out / freq_in;
+
+       fll->n = Ndiv;
+       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;
+
+       do_div(Kpart, freq_in);
+
+       K = Kpart & 0xFFFFFFFF;
+
+       if ((K % 10) >= 5)
+               K += 5;
+
+       /* Move down to proper range now rounding is done */
+       fll->k = K / 10;
+
+       pr_debug("N=%x K=%x\n", fll->n, fll->k);
+
+       return 0;
+}
+
+static int wm8995_set_fll(struct snd_soc_dai *dai, int id,
+                         int src, unsigned int freq_in,
+                         unsigned int freq_out)
+{
+       struct snd_soc_codec *codec;
+       struct wm8995_priv *wm8995;
+       int reg_offset, ret;
+       struct fll_div fll;
+       u16 reg, aif1, aif2;
+
+       codec = dai->codec;
+       wm8995 = snd_soc_codec_get_drvdata(codec);
+
+       aif1 = snd_soc_read(codec, WM8995_AIF1_CLOCKING_1)
+              & WM8995_AIF1CLK_ENA;
+
+       aif2 = snd_soc_read(codec, WM8995_AIF2_CLOCKING_1)
+              & WM8995_AIF2CLK_ENA;
+
+       switch (id) {
+       case WM8995_FLL1:
+               reg_offset = 0;
+               id = 0;
+               break;
+       case WM8995_FLL2:
+               reg_offset = 0x20;
+               id = 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (src) {
+       case 0:
+               /* Allow no source specification when stopping */
+               if (freq_out)
+                       return -EINVAL;
+               break;
+       case WM8995_FLL_SRC_MCLK1:
+       case WM8995_FLL_SRC_MCLK2:
+       case WM8995_FLL_SRC_LRCLK:
+       case WM8995_FLL_SRC_BCLK:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Are we changing anything? */
+       if (wm8995->fll[id].src == src &&
+           wm8995->fll[id].in == freq_in && wm8995->fll[id].out == freq_out)
+               return 0;
+
+       /* If we're stopping the FLL redo the old config - no
+        * registers will actually be written but we avoid GCC flow
+        * analysis bugs spewing warnings.
+        */
+       if (freq_out)
+               ret = wm8995_get_fll_config(&fll, freq_in, freq_out);
+       else
+               ret = wm8995_get_fll_config(&fll, wm8995->fll[id].in,
+                                           wm8995->fll[id].out);
+       if (ret < 0)
+               return ret;
+
+       /* Gate the AIF clocks while we reclock */
+       snd_soc_update_bits(codec, WM8995_AIF1_CLOCKING_1,
+                           WM8995_AIF1CLK_ENA_MASK, 0);
+       snd_soc_update_bits(codec, WM8995_AIF2_CLOCKING_1,
+                           WM8995_AIF2CLK_ENA_MASK, 0);
+
+       /* We always need to disable the FLL while reconfiguring */
+       snd_soc_update_bits(codec, WM8995_FLL1_CONTROL_1 + reg_offset,
+                           WM8995_FLL1_ENA_MASK, 0);
+
+       reg = (fll.outdiv << WM8995_FLL1_OUTDIV_SHIFT) |
+             (fll.fll_fratio << WM8995_FLL1_FRATIO_SHIFT);
+       snd_soc_update_bits(codec, WM8995_FLL1_CONTROL_2 + reg_offset,
+                           WM8995_FLL1_OUTDIV_MASK |
+                           WM8995_FLL1_FRATIO_MASK, reg);
+
+       snd_soc_write(codec, WM8995_FLL1_CONTROL_3 + reg_offset, fll.k);
+
+       snd_soc_update_bits(codec, WM8995_FLL1_CONTROL_4 + reg_offset,
+                           WM8995_FLL1_N_MASK,
+                           fll.n << WM8995_FLL1_N_SHIFT);
+
+       snd_soc_update_bits(codec, WM8995_FLL1_CONTROL_5 + reg_offset,
+                           WM8995_FLL1_REFCLK_DIV_MASK |
+                           WM8995_FLL1_REFCLK_SRC_MASK,
+                           (fll.clk_ref_div << WM8995_FLL1_REFCLK_DIV_SHIFT) |
+                           (src - 1));
+
+       if (freq_out)
+               snd_soc_update_bits(codec, WM8995_FLL1_CONTROL_1 + reg_offset,
+                                   WM8995_FLL1_ENA_MASK, WM8995_FLL1_ENA);
+
+       wm8995->fll[id].in = freq_in;
+       wm8995->fll[id].out = freq_out;
+       wm8995->fll[id].src = src;
+
+       /* Enable any gated AIF clocks */
+       snd_soc_update_bits(codec, WM8995_AIF1_CLOCKING_1,
+                           WM8995_AIF1CLK_ENA_MASK, aif1);
+       snd_soc_update_bits(codec, WM8995_AIF2_CLOCKING_1,
+                           WM8995_AIF2CLK_ENA_MASK, aif2);
+
+       configure_clock(codec);
+
+       return 0;
+}
+
+static int wm8995_set_dai_sysclk(struct snd_soc_dai *dai,
+                                int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec;
+       struct wm8995_priv *wm8995;
+
+       codec = dai->codec;
+       wm8995 = snd_soc_codec_get_drvdata(codec);
+
+       switch (dai->id) {
+       case 0:
+       case 1:
+               break;
+       default:
+               /* AIF3 shares clocking with AIF1/2 */
+               return -EINVAL;
+       }
+
+       switch (clk_id) {
+       case WM8995_SYSCLK_MCLK1:
+               wm8995->sysclk[dai->id] = WM8995_SYSCLK_MCLK1;
+               wm8995->mclk[0] = freq;
+               dev_dbg(dai->dev, "AIF%d using MCLK1 at %uHz\n",
+                       dai->id + 1, freq);
+               break;
+       case WM8995_SYSCLK_MCLK2:
+               wm8995->sysclk[dai->id] = WM8995_SYSCLK_MCLK1;
+               wm8995->mclk[1] = freq;
+               dev_dbg(dai->dev, "AIF%d using MCLK2 at %uHz\n",
+                       dai->id + 1, freq);
+               break;
+       case WM8995_SYSCLK_FLL1:
+               wm8995->sysclk[dai->id] = WM8995_SYSCLK_FLL1;
+               dev_dbg(dai->dev, "AIF%d using FLL1\n", dai->id + 1);
+               break;
+       case WM8995_SYSCLK_FLL2:
+               wm8995->sysclk[dai->id] = WM8995_SYSCLK_FLL2;
+               dev_dbg(dai->dev, "AIF%d using FLL2\n", dai->id + 1);
+               break;
+       case WM8995_SYSCLK_OPCLK:
+       default:
+               dev_err(dai->dev, "Unknown clock source %d\n", clk_id);
+               return -EINVAL;
+       }
+
+       configure_clock(codec);
+
+       return 0;
+}
+
+static int wm8995_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       struct wm8995_priv *wm8995;
+       int ret;
+
+       wm8995 = snd_soc_codec_get_drvdata(codec);
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       ret = snd_soc_cache_sync(codec);
+                       if (ret) {
+                               dev_err(codec->dev,
+                                       "Failed to sync cache: %d\n", ret);
+                               return ret;
+                       }
+
+                       snd_soc_update_bits(codec, WM8995_POWER_MANAGEMENT_1,
+                                           WM8995_BG_ENA_MASK, WM8995_BG_ENA);
+
+               }
+               break;
+       case SND_SOC_BIAS_OFF:
+               snd_soc_update_bits(codec, WM8995_POWER_MANAGEMENT_1,
+                                   WM8995_BG_ENA_MASK, 0);
+               break;
+       }
+
+       codec->dapm.bias_level = level;
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm8995_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+       wm8995_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int wm8995_resume(struct snd_soc_codec *codec)
+{
+       wm8995_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       return 0;
+}
+#else
+#define wm8995_suspend NULL
+#define wm8995_resume NULL
+#endif
+
+static int wm8995_remove(struct snd_soc_codec *codec)
+{
+       struct wm8995_priv *wm8995;
+       struct i2c_client *i2c;
+
+       i2c = container_of(codec->dev, struct i2c_client, dev);
+       wm8995 = snd_soc_codec_get_drvdata(codec);
+       wm8995_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int wm8995_probe(struct snd_soc_codec *codec)
+{
+       struct wm8995_priv *wm8995;
+       int ret;
+
+       codec->dapm.idle_bias_off = 1;
+       wm8995 = snd_soc_codec_get_drvdata(codec);
+
+       ret = snd_soc_codec_set_cache_io(codec, 16, 16, wm8995->control_type);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_read(codec, WM8995_SOFTWARE_RESET);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read device ID: %d\n", ret);
+               return ret;
+       }
+
+       if (ret != 0x8995) {
+               dev_err(codec->dev, "Invalid device ID: %#x\n", ret);
+               return -EINVAL;
+       }
+
+       ret = snd_soc_write(codec, WM8995_SOFTWARE_RESET, 0);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+               return ret;
+       }
+
+       wm8995_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* Latch volume updates (right only; we always do left then right). */
+       snd_soc_update_bits(codec, WM8995_AIF1_DAC1_RIGHT_VOLUME,
+                           WM8995_AIF1DAC1_VU_MASK, WM8995_AIF1DAC1_VU);
+       snd_soc_update_bits(codec, WM8995_AIF1_DAC2_RIGHT_VOLUME,
+                           WM8995_AIF1DAC2_VU_MASK, WM8995_AIF1DAC2_VU);
+       snd_soc_update_bits(codec, WM8995_AIF2_DAC_RIGHT_VOLUME,
+                           WM8995_AIF2DAC_VU_MASK, WM8995_AIF2DAC_VU);
+       snd_soc_update_bits(codec, WM8995_AIF1_ADC1_RIGHT_VOLUME,
+                           WM8995_AIF1ADC1_VU_MASK, WM8995_AIF1ADC1_VU);
+       snd_soc_update_bits(codec, WM8995_AIF1_ADC2_RIGHT_VOLUME,
+                           WM8995_AIF1ADC2_VU_MASK, WM8995_AIF1ADC2_VU);
+       snd_soc_update_bits(codec, WM8995_AIF2_ADC_RIGHT_VOLUME,
+                           WM8995_AIF2ADC_VU_MASK, WM8995_AIF1ADC2_VU);
+       snd_soc_update_bits(codec, WM8995_DAC1_RIGHT_VOLUME,
+                           WM8995_DAC1_VU_MASK, WM8995_DAC1_VU);
+       snd_soc_update_bits(codec, WM8995_DAC2_RIGHT_VOLUME,
+                           WM8995_DAC2_VU_MASK, WM8995_DAC2_VU);
+       snd_soc_update_bits(codec, WM8995_RIGHT_LINE_INPUT_1_VOLUME,
+                           WM8995_IN1_VU_MASK, WM8995_IN1_VU);
+
+       wm8995_update_class_w(codec);
+
+       snd_soc_add_controls(codec, wm8995_snd_controls,
+                            ARRAY_SIZE(wm8995_snd_controls));
+       snd_soc_dapm_new_controls(&codec->dapm, wm8995_dapm_widgets,
+                                 ARRAY_SIZE(wm8995_dapm_widgets));
+       snd_soc_dapm_add_routes(&codec->dapm, wm8995_intercon,
+                               ARRAY_SIZE(wm8995_intercon));
+
+       return 0;
+}
+
+#define WM8995_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops wm8995_aif1_dai_ops = {
+       .set_sysclk = wm8995_set_dai_sysclk,
+       .set_fmt = wm8995_set_dai_fmt,
+       .hw_params = wm8995_hw_params,
+       .digital_mute = wm8995_aif_mute,
+       .set_pll = wm8995_set_fll,
+       .set_tristate = wm8995_set_tristate,
+};
+
+static struct snd_soc_dai_ops wm8995_aif2_dai_ops = {
+       .set_sysclk = wm8995_set_dai_sysclk,
+       .set_fmt = wm8995_set_dai_fmt,
+       .hw_params = wm8995_hw_params,
+       .digital_mute = wm8995_aif_mute,
+       .set_pll = wm8995_set_fll,
+       .set_tristate = wm8995_set_tristate,
+};
+
+static struct snd_soc_dai_ops wm8995_aif3_dai_ops = {
+       .set_tristate = wm8995_set_tristate,
+};
+
+static struct snd_soc_dai_driver wm8995_dai[] = {
+       {
+               .name = "wm8995-aif1",
+               .playback = {
+                       .stream_name = "AIF1 Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_96000,
+                       .formats = WM8995_FORMATS
+               },
+               .capture = {
+                       .stream_name = "AIF1 Capture",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_48000,
+                       .formats = WM8995_FORMATS
+               },
+               .ops = &wm8995_aif1_dai_ops
+       },
+       {
+               .name = "wm8995-aif2",
+               .playback = {
+                       .stream_name = "AIF2 Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_96000,
+                       .formats = WM8995_FORMATS
+               },
+               .capture = {
+                       .stream_name = "AIF2 Capture",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_48000,
+                       .formats = WM8995_FORMATS
+               },
+               .ops = &wm8995_aif2_dai_ops
+       },
+       {
+               .name = "wm8995-aif3",
+               .playback = {
+                       .stream_name = "AIF3 Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_96000,
+                       .formats = WM8995_FORMATS
+               },
+               .capture = {
+                       .stream_name = "AIF3 Capture",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_48000,
+                       .formats = WM8995_FORMATS
+               },
+               .ops = &wm8995_aif3_dai_ops
+       }
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8995 = {
+       .probe = wm8995_probe,
+       .remove = wm8995_remove,
+       .suspend = wm8995_suspend,
+       .resume = wm8995_resume,
+       .set_bias_level = wm8995_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8995_reg_defs),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8995_reg_defs,
+       .volatile_register = wm8995_volatile,
+       .compress_type = SND_SOC_RBTREE_COMPRESSION
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8995_spi_probe(struct spi_device *spi)
+{
+       struct wm8995_priv *wm8995;
+       int ret;
+
+       wm8995 = kzalloc(sizeof *wm8995, GFP_KERNEL);
+       if (!wm8995)
+               return -ENOMEM;
+
+       wm8995->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8995);
+
+       ret = snd_soc_register_codec(&spi->dev,
+                                    &soc_codec_dev_wm8995, wm8995_dai,
+                                    ARRAY_SIZE(wm8995_dai));
+       if (ret < 0)
+               kfree(wm8995);
+       return ret;
+}
+
+static int __devexit wm8995_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
+       return 0;
+}
+
+static struct spi_driver wm8995_spi_driver = {
+       .driver = {
+               .name = "wm8995",
+               .owner = THIS_MODULE,
+       },
+       .probe = wm8995_spi_probe,
+       .remove = __devexit_p(wm8995_spi_remove)
+};
+#endif
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8995_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8995_priv *wm8995;
+       int ret;
+
+       wm8995 = kzalloc(sizeof *wm8995, GFP_KERNEL);
+       if (!wm8995)
+               return -ENOMEM;
+
+       wm8995->control_type = SND_SOC_I2C;
+       i2c_set_clientdata(i2c, wm8995);
+
+       ret = snd_soc_register_codec(&i2c->dev,
+                                    &soc_codec_dev_wm8995, wm8995_dai,
+                                    ARRAY_SIZE(wm8995_dai));
+       if (ret < 0)
+               kfree(wm8995);
+       return ret;
+}
+
+static __devexit int wm8995_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
+       return 0;
+}
+
+static const struct i2c_device_id wm8995_i2c_id[] = {
+       {"wm8995", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, wm8995_i2c_id);
+
+static struct i2c_driver wm8995_i2c_driver = {
+       .driver = {
+               .name = "wm8995",
+               .owner = THIS_MODULE,
+       },
+       .probe = wm8995_i2c_probe,
+       .remove = __devexit_p(wm8995_i2c_remove),
+       .id_table = wm8995_i2c_id
+};
+#endif
+
+static int __init wm8995_modinit(void)
+{
+       int ret = 0;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8995_i2c_driver);
+       if (ret) {
+               printk(KERN_ERR "Failed to register wm8995 I2C driver: %d\n",
+                      ret);
+       }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       ret = spi_register_driver(&wm8995_spi_driver);
+       if (ret) {
+               printk(KERN_ERR "Failed to register wm8995 SPI driver: %d\n",
+                      ret);
+       }
+#endif
+       return ret;
+}
+
+module_init(wm8995_modinit);
+
+static void __exit wm8995_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8995_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&wm8995_spi_driver);
+#endif
+}
+
+module_exit(wm8995_exit);
+
+MODULE_DESCRIPTION("ASoC WM8995 driver");
+MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8995.h b/sound/soc/codecs/wm8995.h
new file mode 100644 (file)
index 0000000..5642121
--- /dev/null
@@ -0,0 +1,4269 @@
+/*
+ * wm8995.h  --  WM8995 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Wolfson Microelectronics plc
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.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 _WM8995_H
+#define _WM8995_H
+
+#include <asm/types.h>
+
+/*
+ * Register values.
+ */
+#define WM8995_SOFTWARE_RESET                   0x00
+#define WM8995_POWER_MANAGEMENT_1               0x01
+#define WM8995_POWER_MANAGEMENT_2               0x02
+#define WM8995_POWER_MANAGEMENT_3               0x03
+#define WM8995_POWER_MANAGEMENT_4               0x04
+#define WM8995_POWER_MANAGEMENT_5               0x05
+#define WM8995_LEFT_LINE_INPUT_1_VOLUME         0x10
+#define WM8995_RIGHT_LINE_INPUT_1_VOLUME        0x11
+#define WM8995_LEFT_LINE_INPUT_CONTROL          0x12
+#define WM8995_DAC1_LEFT_VOLUME                 0x18
+#define WM8995_DAC1_RIGHT_VOLUME                0x19
+#define WM8995_DAC2_LEFT_VOLUME                 0x1A
+#define WM8995_DAC2_RIGHT_VOLUME                0x1B
+#define WM8995_OUTPUT_VOLUME_ZC_1               0x1C
+#define WM8995_MICBIAS_1                        0x20
+#define WM8995_MICBIAS_2                        0x21
+#define WM8995_LDO_1                            0x28
+#define WM8995_LDO_2                            0x29
+#define WM8995_ACCESSORY_DETECT_MODE1           0x30
+#define WM8995_ACCESSORY_DETECT_MODE2           0x31
+#define WM8995_HEADPHONE_DETECT1                0x34
+#define WM8995_HEADPHONE_DETECT2                0x35
+#define WM8995_MIC_DETECT_1                     0x38
+#define WM8995_MIC_DETECT_2                     0x39
+#define WM8995_CHARGE_PUMP_1                    0x40
+#define WM8995_CLASS_W_1                        0x45
+#define WM8995_DC_SERVO_1                       0x50
+#define WM8995_DC_SERVO_2                       0x51
+#define WM8995_DC_SERVO_3                       0x52
+#define WM8995_DC_SERVO_5                       0x54
+#define WM8995_DC_SERVO_6                       0x55
+#define WM8995_DC_SERVO_7                       0x56
+#define WM8995_DC_SERVO_READBACK_0              0x57
+#define WM8995_ANALOGUE_HP_1                    0x60
+#define WM8995_ANALOGUE_HP_2                    0x61
+#define WM8995_CHIP_REVISION                    0x100
+#define WM8995_CONTROL_INTERFACE_1              0x101
+#define WM8995_CONTROL_INTERFACE_2              0x102
+#define WM8995_WRITE_SEQUENCER_CTRL_1           0x110
+#define WM8995_WRITE_SEQUENCER_CTRL_2           0x111
+#define WM8995_AIF1_CLOCKING_1                  0x200
+#define WM8995_AIF1_CLOCKING_2                  0x201
+#define WM8995_AIF2_CLOCKING_1                  0x204
+#define WM8995_AIF2_CLOCKING_2                  0x205
+#define WM8995_CLOCKING_1                       0x208
+#define WM8995_CLOCKING_2                       0x209
+#define WM8995_AIF1_RATE                        0x210
+#define WM8995_AIF2_RATE                        0x211
+#define WM8995_RATE_STATUS                      0x212
+#define WM8995_FLL1_CONTROL_1                   0x220
+#define WM8995_FLL1_CONTROL_2                   0x221
+#define WM8995_FLL1_CONTROL_3                   0x222
+#define WM8995_FLL1_CONTROL_4                   0x223
+#define WM8995_FLL1_CONTROL_5                   0x224
+#define WM8995_FLL2_CONTROL_1                   0x240
+#define WM8995_FLL2_CONTROL_2                   0x241
+#define WM8995_FLL2_CONTROL_3                   0x242
+#define WM8995_FLL2_CONTROL_4                   0x243
+#define WM8995_FLL2_CONTROL_5                   0x244
+#define WM8995_AIF1_CONTROL_1                   0x300
+#define WM8995_AIF1_CONTROL_2                   0x301
+#define WM8995_AIF1_MASTER_SLAVE                0x302
+#define WM8995_AIF1_BCLK                        0x303
+#define WM8995_AIF1ADC_LRCLK                    0x304
+#define WM8995_AIF1DAC_LRCLK                    0x305
+#define WM8995_AIF1DAC_DATA                     0x306
+#define WM8995_AIF1ADC_DATA                     0x307
+#define WM8995_AIF2_CONTROL_1                   0x310
+#define WM8995_AIF2_CONTROL_2                   0x311
+#define WM8995_AIF2_MASTER_SLAVE                0x312
+#define WM8995_AIF2_BCLK                        0x313
+#define WM8995_AIF2ADC_LRCLK                    0x314
+#define WM8995_AIF2DAC_LRCLK                    0x315
+#define WM8995_AIF2DAC_DATA                     0x316
+#define WM8995_AIF2ADC_DATA                     0x317
+#define WM8995_AIF1_ADC1_LEFT_VOLUME            0x400
+#define WM8995_AIF1_ADC1_RIGHT_VOLUME           0x401
+#define WM8995_AIF1_DAC1_LEFT_VOLUME            0x402
+#define WM8995_AIF1_DAC1_RIGHT_VOLUME           0x403
+#define WM8995_AIF1_ADC2_LEFT_VOLUME            0x404
+#define WM8995_AIF1_ADC2_RIGHT_VOLUME           0x405
+#define WM8995_AIF1_DAC2_LEFT_VOLUME            0x406
+#define WM8995_AIF1_DAC2_RIGHT_VOLUME           0x407
+#define WM8995_AIF1_ADC1_FILTERS                0x410
+#define WM8995_AIF1_ADC2_FILTERS                0x411
+#define WM8995_AIF1_DAC1_FILTERS_1              0x420
+#define WM8995_AIF1_DAC1_FILTERS_2              0x421
+#define WM8995_AIF1_DAC2_FILTERS_1              0x422
+#define WM8995_AIF1_DAC2_FILTERS_2              0x423
+#define WM8995_AIF1_DRC1_1                      0x440
+#define WM8995_AIF1_DRC1_2                      0x441
+#define WM8995_AIF1_DRC1_3                      0x442
+#define WM8995_AIF1_DRC1_4                      0x443
+#define WM8995_AIF1_DRC1_5                      0x444
+#define WM8995_AIF1_DRC2_1                      0x450
+#define WM8995_AIF1_DRC2_2                      0x451
+#define WM8995_AIF1_DRC2_3                      0x452
+#define WM8995_AIF1_DRC2_4                      0x453
+#define WM8995_AIF1_DRC2_5                      0x454
+#define WM8995_AIF1_DAC1_EQ_GAINS_1             0x480
+#define WM8995_AIF1_DAC1_EQ_GAINS_2             0x481
+#define WM8995_AIF1_DAC1_EQ_BAND_1_A            0x482
+#define WM8995_AIF1_DAC1_EQ_BAND_1_B            0x483
+#define WM8995_AIF1_DAC1_EQ_BAND_1_PG           0x484
+#define WM8995_AIF1_DAC1_EQ_BAND_2_A            0x485
+#define WM8995_AIF1_DAC1_EQ_BAND_2_B            0x486
+#define WM8995_AIF1_DAC1_EQ_BAND_2_C            0x487
+#define WM8995_AIF1_DAC1_EQ_BAND_2_PG           0x488
+#define WM8995_AIF1_DAC1_EQ_BAND_3_A            0x489
+#define WM8995_AIF1_DAC1_EQ_BAND_3_B            0x48A
+#define WM8995_AIF1_DAC1_EQ_BAND_3_C            0x48B
+#define WM8995_AIF1_DAC1_EQ_BAND_3_PG           0x48C
+#define WM8995_AIF1_DAC1_EQ_BAND_4_A            0x48D
+#define WM8995_AIF1_DAC1_EQ_BAND_4_B            0x48E
+#define WM8995_AIF1_DAC1_EQ_BAND_4_C            0x48F
+#define WM8995_AIF1_DAC1_EQ_BAND_4_PG           0x490
+#define WM8995_AIF1_DAC1_EQ_BAND_5_A            0x491
+#define WM8995_AIF1_DAC1_EQ_BAND_5_B            0x492
+#define WM8995_AIF1_DAC1_EQ_BAND_5_PG           0x493
+#define WM8995_AIF1_DAC2_EQ_GAINS_1             0x4A0
+#define WM8995_AIF1_DAC2_EQ_GAINS_2             0x4A1
+#define WM8995_AIF1_DAC2_EQ_BAND_1_A            0x4A2
+#define WM8995_AIF1_DAC2_EQ_BAND_1_B            0x4A3
+#define WM8995_AIF1_DAC2_EQ_BAND_1_PG           0x4A4
+#define WM8995_AIF1_DAC2_EQ_BAND_2_A            0x4A5
+#define WM8995_AIF1_DAC2_EQ_BAND_2_B            0x4A6
+#define WM8995_AIF1_DAC2_EQ_BAND_2_C            0x4A7
+#define WM8995_AIF1_DAC2_EQ_BAND_2_PG           0x4A8
+#define WM8995_AIF1_DAC2_EQ_BAND_3_A            0x4A9
+#define WM8995_AIF1_DAC2_EQ_BAND_3_B            0x4AA
+#define WM8995_AIF1_DAC2_EQ_BAND_3_C            0x4AB
+#define WM8995_AIF1_DAC2_EQ_BAND_3_PG           0x4AC
+#define WM8995_AIF1_DAC2_EQ_BAND_4_A            0x4AD
+#define WM8995_AIF1_DAC2_EQ_BAND_4_B            0x4AE
+#define WM8995_AIF1_DAC2_EQ_BAND_4_C            0x4AF
+#define WM8995_AIF1_DAC2_EQ_BAND_4_PG           0x4B0
+#define WM8995_AIF1_DAC2_EQ_BAND_5_A            0x4B1
+#define WM8995_AIF1_DAC2_EQ_BAND_5_B            0x4B2
+#define WM8995_AIF1_DAC2_EQ_BAND_5_PG           0x4B3
+#define WM8995_AIF2_ADC_LEFT_VOLUME             0x500
+#define WM8995_AIF2_ADC_RIGHT_VOLUME            0x501
+#define WM8995_AIF2_DAC_LEFT_VOLUME             0x502
+#define WM8995_AIF2_DAC_RIGHT_VOLUME            0x503
+#define WM8995_AIF2_ADC_FILTERS                 0x510
+#define WM8995_AIF2_DAC_FILTERS_1               0x520
+#define WM8995_AIF2_DAC_FILTERS_2               0x521
+#define WM8995_AIF2_DRC_1                       0x540
+#define WM8995_AIF2_DRC_2                       0x541
+#define WM8995_AIF2_DRC_3                       0x542
+#define WM8995_AIF2_DRC_4                       0x543
+#define WM8995_AIF2_DRC_5                       0x544
+#define WM8995_AIF2_EQ_GAINS_1                  0x580
+#define WM8995_AIF2_EQ_GAINS_2                  0x581
+#define WM8995_AIF2_EQ_BAND_1_A                 0x582
+#define WM8995_AIF2_EQ_BAND_1_B                 0x583
+#define WM8995_AIF2_EQ_BAND_1_PG                0x584
+#define WM8995_AIF2_EQ_BAND_2_A                 0x585
+#define WM8995_AIF2_EQ_BAND_2_B                 0x586
+#define WM8995_AIF2_EQ_BAND_2_C                 0x587
+#define WM8995_AIF2_EQ_BAND_2_PG                0x588
+#define WM8995_AIF2_EQ_BAND_3_A                 0x589
+#define WM8995_AIF2_EQ_BAND_3_B                 0x58A
+#define WM8995_AIF2_EQ_BAND_3_C                 0x58B
+#define WM8995_AIF2_EQ_BAND_3_PG                0x58C
+#define WM8995_AIF2_EQ_BAND_4_A                 0x58D
+#define WM8995_AIF2_EQ_BAND_4_B                 0x58E
+#define WM8995_AIF2_EQ_BAND_4_C                 0x58F
+#define WM8995_AIF2_EQ_BAND_4_PG                0x590
+#define WM8995_AIF2_EQ_BAND_5_A                 0x591
+#define WM8995_AIF2_EQ_BAND_5_B                 0x592
+#define WM8995_AIF2_EQ_BAND_5_PG                0x593
+#define WM8995_DAC1_MIXER_VOLUMES               0x600
+#define WM8995_DAC1_LEFT_MIXER_ROUTING          0x601
+#define WM8995_DAC1_RIGHT_MIXER_ROUTING         0x602
+#define WM8995_DAC2_MIXER_VOLUMES               0x603
+#define WM8995_DAC2_LEFT_MIXER_ROUTING          0x604
+#define WM8995_DAC2_RIGHT_MIXER_ROUTING         0x605
+#define WM8995_AIF1_ADC1_LEFT_MIXER_ROUTING     0x606
+#define WM8995_AIF1_ADC1_RIGHT_MIXER_ROUTING    0x607
+#define WM8995_AIF1_ADC2_LEFT_MIXER_ROUTING     0x608
+#define WM8995_AIF1_ADC2_RIGHT_MIXER_ROUTING    0x609
+#define WM8995_DAC_SOFTMUTE                     0x610
+#define WM8995_OVERSAMPLING                     0x620
+#define WM8995_SIDETONE                         0x621
+#define WM8995_GPIO_1                           0x700
+#define WM8995_GPIO_2                           0x701
+#define WM8995_GPIO_3                           0x702
+#define WM8995_GPIO_4                           0x703
+#define WM8995_GPIO_5                           0x704
+#define WM8995_GPIO_6                           0x705
+#define WM8995_GPIO_7                           0x706
+#define WM8995_GPIO_8                           0x707
+#define WM8995_GPIO_9                           0x708
+#define WM8995_GPIO_10                          0x709
+#define WM8995_GPIO_11                          0x70A
+#define WM8995_GPIO_12                          0x70B
+#define WM8995_GPIO_13                          0x70C
+#define WM8995_GPIO_14                          0x70D
+#define WM8995_PULL_CONTROL_1                   0x720
+#define WM8995_PULL_CONTROL_2                   0x721
+#define WM8995_INTERRUPT_STATUS_1               0x730
+#define WM8995_INTERRUPT_STATUS_2               0x731
+#define WM8995_INTERRUPT_RAW_STATUS_2           0x732
+#define WM8995_INTERRUPT_STATUS_1_MASK          0x738
+#define WM8995_INTERRUPT_STATUS_2_MASK          0x739
+#define WM8995_INTERRUPT_CONTROL                0x740
+#define WM8995_LEFT_PDM_SPEAKER_1               0x800
+#define WM8995_RIGHT_PDM_SPEAKER_1              0x801
+#define WM8995_PDM_SPEAKER_1_MUTE_SEQUENCE      0x802
+#define WM8995_LEFT_PDM_SPEAKER_2               0x808
+#define WM8995_RIGHT_PDM_SPEAKER_2              0x809
+#define WM8995_PDM_SPEAKER_2_MUTE_SEQUENCE      0x80A
+#define WM8995_WRITE_SEQUENCER_0                0x3000
+#define WM8995_WRITE_SEQUENCER_1                0x3001
+#define WM8995_WRITE_SEQUENCER_2                0x3002
+#define WM8995_WRITE_SEQUENCER_3                0x3003
+#define WM8995_WRITE_SEQUENCER_4                0x3004
+#define WM8995_WRITE_SEQUENCER_5                0x3005
+#define WM8995_WRITE_SEQUENCER_6                0x3006
+#define WM8995_WRITE_SEQUENCER_7                0x3007
+#define WM8995_WRITE_SEQUENCER_8                0x3008
+#define WM8995_WRITE_SEQUENCER_9                0x3009
+#define WM8995_WRITE_SEQUENCER_10               0x300A
+#define WM8995_WRITE_SEQUENCER_11               0x300B
+#define WM8995_WRITE_SEQUENCER_12               0x300C
+#define WM8995_WRITE_SEQUENCER_13               0x300D
+#define WM8995_WRITE_SEQUENCER_14               0x300E
+#define WM8995_WRITE_SEQUENCER_15               0x300F
+#define WM8995_WRITE_SEQUENCER_16               0x3010
+#define WM8995_WRITE_SEQUENCER_17               0x3011
+#define WM8995_WRITE_SEQUENCER_18               0x3012
+#define WM8995_WRITE_SEQUENCER_19               0x3013
+#define WM8995_WRITE_SEQUENCER_20               0x3014
+#define WM8995_WRITE_SEQUENCER_21               0x3015
+#define WM8995_WRITE_SEQUENCER_22               0x3016
+#define WM8995_WRITE_SEQUENCER_23               0x3017
+#define WM8995_WRITE_SEQUENCER_24               0x3018
+#define WM8995_WRITE_SEQUENCER_25               0x3019
+#define WM8995_WRITE_SEQUENCER_26               0x301A
+#define WM8995_WRITE_SEQUENCER_27               0x301B
+#define WM8995_WRITE_SEQUENCER_28               0x301C
+#define WM8995_WRITE_SEQUENCER_29               0x301D
+#define WM8995_WRITE_SEQUENCER_30               0x301E
+#define WM8995_WRITE_SEQUENCER_31               0x301F
+#define WM8995_WRITE_SEQUENCER_32               0x3020
+#define WM8995_WRITE_SEQUENCER_33               0x3021
+#define WM8995_WRITE_SEQUENCER_34               0x3022
+#define WM8995_WRITE_SEQUENCER_35               0x3023
+#define WM8995_WRITE_SEQUENCER_36               0x3024
+#define WM8995_WRITE_SEQUENCER_37               0x3025
+#define WM8995_WRITE_SEQUENCER_38               0x3026
+#define WM8995_WRITE_SEQUENCER_39               0x3027
+#define WM8995_WRITE_SEQUENCER_40               0x3028
+#define WM8995_WRITE_SEQUENCER_41               0x3029
+#define WM8995_WRITE_SEQUENCER_42               0x302A
+#define WM8995_WRITE_SEQUENCER_43               0x302B
+#define WM8995_WRITE_SEQUENCER_44               0x302C
+#define WM8995_WRITE_SEQUENCER_45               0x302D
+#define WM8995_WRITE_SEQUENCER_46               0x302E
+#define WM8995_WRITE_SEQUENCER_47               0x302F
+#define WM8995_WRITE_SEQUENCER_48               0x3030
+#define WM8995_WRITE_SEQUENCER_49               0x3031
+#define WM8995_WRITE_SEQUENCER_50               0x3032
+#define WM8995_WRITE_SEQUENCER_51               0x3033
+#define WM8995_WRITE_SEQUENCER_52               0x3034
+#define WM8995_WRITE_SEQUENCER_53               0x3035
+#define WM8995_WRITE_SEQUENCER_54               0x3036
+#define WM8995_WRITE_SEQUENCER_55               0x3037
+#define WM8995_WRITE_SEQUENCER_56               0x3038
+#define WM8995_WRITE_SEQUENCER_57               0x3039
+#define WM8995_WRITE_SEQUENCER_58               0x303A
+#define WM8995_WRITE_SEQUENCER_59               0x303B
+#define WM8995_WRITE_SEQUENCER_60               0x303C
+#define WM8995_WRITE_SEQUENCER_61               0x303D
+#define WM8995_WRITE_SEQUENCER_62               0x303E
+#define WM8995_WRITE_SEQUENCER_63               0x303F
+#define WM8995_WRITE_SEQUENCER_64               0x3040
+#define WM8995_WRITE_SEQUENCER_65               0x3041
+#define WM8995_WRITE_SEQUENCER_66               0x3042
+#define WM8995_WRITE_SEQUENCER_67               0x3043
+#define WM8995_WRITE_SEQUENCER_68               0x3044
+#define WM8995_WRITE_SEQUENCER_69               0x3045
+#define WM8995_WRITE_SEQUENCER_70               0x3046
+#define WM8995_WRITE_SEQUENCER_71               0x3047
+#define WM8995_WRITE_SEQUENCER_72               0x3048
+#define WM8995_WRITE_SEQUENCER_73               0x3049
+#define WM8995_WRITE_SEQUENCER_74               0x304A
+#define WM8995_WRITE_SEQUENCER_75               0x304B
+#define WM8995_WRITE_SEQUENCER_76               0x304C
+#define WM8995_WRITE_SEQUENCER_77               0x304D
+#define WM8995_WRITE_SEQUENCER_78               0x304E
+#define WM8995_WRITE_SEQUENCER_79               0x304F
+#define WM8995_WRITE_SEQUENCER_80               0x3050
+#define WM8995_WRITE_SEQUENCER_81               0x3051
+#define WM8995_WRITE_SEQUENCER_82               0x3052
+#define WM8995_WRITE_SEQUENCER_83               0x3053
+#define WM8995_WRITE_SEQUENCER_84               0x3054
+#define WM8995_WRITE_SEQUENCER_85               0x3055
+#define WM8995_WRITE_SEQUENCER_86               0x3056
+#define WM8995_WRITE_SEQUENCER_87               0x3057
+#define WM8995_WRITE_SEQUENCER_88               0x3058
+#define WM8995_WRITE_SEQUENCER_89               0x3059
+#define WM8995_WRITE_SEQUENCER_90               0x305A
+#define WM8995_WRITE_SEQUENCER_91               0x305B
+#define WM8995_WRITE_SEQUENCER_92               0x305C
+#define WM8995_WRITE_SEQUENCER_93               0x305D
+#define WM8995_WRITE_SEQUENCER_94               0x305E
+#define WM8995_WRITE_SEQUENCER_95               0x305F
+#define WM8995_WRITE_SEQUENCER_96               0x3060
+#define WM8995_WRITE_SEQUENCER_97               0x3061
+#define WM8995_WRITE_SEQUENCER_98               0x3062
+#define WM8995_WRITE_SEQUENCER_99               0x3063
+#define WM8995_WRITE_SEQUENCER_100              0x3064
+#define WM8995_WRITE_SEQUENCER_101              0x3065
+#define WM8995_WRITE_SEQUENCER_102              0x3066
+#define WM8995_WRITE_SEQUENCER_103              0x3067
+#define WM8995_WRITE_SEQUENCER_104              0x3068
+#define WM8995_WRITE_SEQUENCER_105              0x3069
+#define WM8995_WRITE_SEQUENCER_106              0x306A
+#define WM8995_WRITE_SEQUENCER_107              0x306B
+#define WM8995_WRITE_SEQUENCER_108              0x306C
+#define WM8995_WRITE_SEQUENCER_109              0x306D
+#define WM8995_WRITE_SEQUENCER_110              0x306E
+#define WM8995_WRITE_SEQUENCER_111              0x306F
+#define WM8995_WRITE_SEQUENCER_112              0x3070
+#define WM8995_WRITE_SEQUENCER_113              0x3071
+#define WM8995_WRITE_SEQUENCER_114              0x3072
+#define WM8995_WRITE_SEQUENCER_115              0x3073
+#define WM8995_WRITE_SEQUENCER_116              0x3074
+#define WM8995_WRITE_SEQUENCER_117              0x3075
+#define WM8995_WRITE_SEQUENCER_118              0x3076
+#define WM8995_WRITE_SEQUENCER_119              0x3077
+#define WM8995_WRITE_SEQUENCER_120              0x3078
+#define WM8995_WRITE_SEQUENCER_121              0x3079
+#define WM8995_WRITE_SEQUENCER_122              0x307A
+#define WM8995_WRITE_SEQUENCER_123              0x307B
+#define WM8995_WRITE_SEQUENCER_124              0x307C
+#define WM8995_WRITE_SEQUENCER_125              0x307D
+#define WM8995_WRITE_SEQUENCER_126              0x307E
+#define WM8995_WRITE_SEQUENCER_127              0x307F
+#define WM8995_WRITE_SEQUENCER_128              0x3080
+#define WM8995_WRITE_SEQUENCER_129              0x3081
+#define WM8995_WRITE_SEQUENCER_130              0x3082
+#define WM8995_WRITE_SEQUENCER_131              0x3083
+#define WM8995_WRITE_SEQUENCER_132              0x3084
+#define WM8995_WRITE_SEQUENCER_133              0x3085
+#define WM8995_WRITE_SEQUENCER_134              0x3086
+#define WM8995_WRITE_SEQUENCER_135              0x3087
+#define WM8995_WRITE_SEQUENCER_136              0x3088
+#define WM8995_WRITE_SEQUENCER_137              0x3089
+#define WM8995_WRITE_SEQUENCER_138              0x308A
+#define WM8995_WRITE_SEQUENCER_139              0x308B
+#define WM8995_WRITE_SEQUENCER_140              0x308C
+#define WM8995_WRITE_SEQUENCER_141              0x308D
+#define WM8995_WRITE_SEQUENCER_142              0x308E
+#define WM8995_WRITE_SEQUENCER_143              0x308F
+#define WM8995_WRITE_SEQUENCER_144              0x3090
+#define WM8995_WRITE_SEQUENCER_145              0x3091
+#define WM8995_WRITE_SEQUENCER_146              0x3092
+#define WM8995_WRITE_SEQUENCER_147              0x3093
+#define WM8995_WRITE_SEQUENCER_148              0x3094
+#define WM8995_WRITE_SEQUENCER_149              0x3095
+#define WM8995_WRITE_SEQUENCER_150              0x3096
+#define WM8995_WRITE_SEQUENCER_151              0x3097
+#define WM8995_WRITE_SEQUENCER_152              0x3098
+#define WM8995_WRITE_SEQUENCER_153              0x3099
+#define WM8995_WRITE_SEQUENCER_154              0x309A
+#define WM8995_WRITE_SEQUENCER_155              0x309B
+#define WM8995_WRITE_SEQUENCER_156              0x309C
+#define WM8995_WRITE_SEQUENCER_157              0x309D
+#define WM8995_WRITE_SEQUENCER_158              0x309E
+#define WM8995_WRITE_SEQUENCER_159              0x309F
+#define WM8995_WRITE_SEQUENCER_160              0x30A0
+#define WM8995_WRITE_SEQUENCER_161              0x30A1
+#define WM8995_WRITE_SEQUENCER_162              0x30A2
+#define WM8995_WRITE_SEQUENCER_163              0x30A3
+#define WM8995_WRITE_SEQUENCER_164              0x30A4
+#define WM8995_WRITE_SEQUENCER_165              0x30A5
+#define WM8995_WRITE_SEQUENCER_166              0x30A6
+#define WM8995_WRITE_SEQUENCER_167              0x30A7
+#define WM8995_WRITE_SEQUENCER_168              0x30A8
+#define WM8995_WRITE_SEQUENCER_169              0x30A9
+#define WM8995_WRITE_SEQUENCER_170              0x30AA
+#define WM8995_WRITE_SEQUENCER_171              0x30AB
+#define WM8995_WRITE_SEQUENCER_172              0x30AC
+#define WM8995_WRITE_SEQUENCER_173              0x30AD
+#define WM8995_WRITE_SEQUENCER_174              0x30AE
+#define WM8995_WRITE_SEQUENCER_175              0x30AF
+#define WM8995_WRITE_SEQUENCER_176              0x30B0
+#define WM8995_WRITE_SEQUENCER_177              0x30B1
+#define WM8995_WRITE_SEQUENCER_178              0x30B2
+#define WM8995_WRITE_SEQUENCER_179              0x30B3
+#define WM8995_WRITE_SEQUENCER_180              0x30B4
+#define WM8995_WRITE_SEQUENCER_181              0x30B5
+#define WM8995_WRITE_SEQUENCER_182              0x30B6
+#define WM8995_WRITE_SEQUENCER_183              0x30B7
+#define WM8995_WRITE_SEQUENCER_184              0x30B8
+#define WM8995_WRITE_SEQUENCER_185              0x30B9
+#define WM8995_WRITE_SEQUENCER_186              0x30BA
+#define WM8995_WRITE_SEQUENCER_187              0x30BB
+#define WM8995_WRITE_SEQUENCER_188              0x30BC
+#define WM8995_WRITE_SEQUENCER_189              0x30BD
+#define WM8995_WRITE_SEQUENCER_190              0x30BE
+#define WM8995_WRITE_SEQUENCER_191              0x30BF
+#define WM8995_WRITE_SEQUENCER_192              0x30C0
+#define WM8995_WRITE_SEQUENCER_193              0x30C1
+#define WM8995_WRITE_SEQUENCER_194              0x30C2
+#define WM8995_WRITE_SEQUENCER_195              0x30C3
+#define WM8995_WRITE_SEQUENCER_196              0x30C4
+#define WM8995_WRITE_SEQUENCER_197              0x30C5
+#define WM8995_WRITE_SEQUENCER_198              0x30C6
+#define WM8995_WRITE_SEQUENCER_199              0x30C7
+#define WM8995_WRITE_SEQUENCER_200              0x30C8
+#define WM8995_WRITE_SEQUENCER_201              0x30C9
+#define WM8995_WRITE_SEQUENCER_202              0x30CA
+#define WM8995_WRITE_SEQUENCER_203              0x30CB
+#define WM8995_WRITE_SEQUENCER_204              0x30CC
+#define WM8995_WRITE_SEQUENCER_205              0x30CD
+#define WM8995_WRITE_SEQUENCER_206              0x30CE
+#define WM8995_WRITE_SEQUENCER_207              0x30CF
+#define WM8995_WRITE_SEQUENCER_208              0x30D0
+#define WM8995_WRITE_SEQUENCER_209              0x30D1
+#define WM8995_WRITE_SEQUENCER_210              0x30D2
+#define WM8995_WRITE_SEQUENCER_211              0x30D3
+#define WM8995_WRITE_SEQUENCER_212              0x30D4
+#define WM8995_WRITE_SEQUENCER_213              0x30D5
+#define WM8995_WRITE_SEQUENCER_214              0x30D6
+#define WM8995_WRITE_SEQUENCER_215              0x30D7
+#define WM8995_WRITE_SEQUENCER_216              0x30D8
+#define WM8995_WRITE_SEQUENCER_217              0x30D9
+#define WM8995_WRITE_SEQUENCER_218              0x30DA
+#define WM8995_WRITE_SEQUENCER_219              0x30DB
+#define WM8995_WRITE_SEQUENCER_220              0x30DC
+#define WM8995_WRITE_SEQUENCER_221              0x30DD
+#define WM8995_WRITE_SEQUENCER_222              0x30DE
+#define WM8995_WRITE_SEQUENCER_223              0x30DF
+#define WM8995_WRITE_SEQUENCER_224              0x30E0
+#define WM8995_WRITE_SEQUENCER_225              0x30E1
+#define WM8995_WRITE_SEQUENCER_226              0x30E2
+#define WM8995_WRITE_SEQUENCER_227              0x30E3
+#define WM8995_WRITE_SEQUENCER_228              0x30E4
+#define WM8995_WRITE_SEQUENCER_229              0x30E5
+#define WM8995_WRITE_SEQUENCER_230              0x30E6
+#define WM8995_WRITE_SEQUENCER_231              0x30E7
+#define WM8995_WRITE_SEQUENCER_232              0x30E8
+#define WM8995_WRITE_SEQUENCER_233              0x30E9
+#define WM8995_WRITE_SEQUENCER_234              0x30EA
+#define WM8995_WRITE_SEQUENCER_235              0x30EB
+#define WM8995_WRITE_SEQUENCER_236              0x30EC
+#define WM8995_WRITE_SEQUENCER_237              0x30ED
+#define WM8995_WRITE_SEQUENCER_238              0x30EE
+#define WM8995_WRITE_SEQUENCER_239              0x30EF
+#define WM8995_WRITE_SEQUENCER_240              0x30F0
+#define WM8995_WRITE_SEQUENCER_241              0x30F1
+#define WM8995_WRITE_SEQUENCER_242              0x30F2
+#define WM8995_WRITE_SEQUENCER_243              0x30F3
+#define WM8995_WRITE_SEQUENCER_244              0x30F4
+#define WM8995_WRITE_SEQUENCER_245              0x30F5
+#define WM8995_WRITE_SEQUENCER_246              0x30F6
+#define WM8995_WRITE_SEQUENCER_247              0x30F7
+#define WM8995_WRITE_SEQUENCER_248              0x30F8
+#define WM8995_WRITE_SEQUENCER_249              0x30F9
+#define WM8995_WRITE_SEQUENCER_250              0x30FA
+#define WM8995_WRITE_SEQUENCER_251              0x30FB
+#define WM8995_WRITE_SEQUENCER_252              0x30FC
+#define WM8995_WRITE_SEQUENCER_253              0x30FD
+#define WM8995_WRITE_SEQUENCER_254              0x30FE
+#define WM8995_WRITE_SEQUENCER_255              0x30FF
+#define WM8995_WRITE_SEQUENCER_256              0x3100
+#define WM8995_WRITE_SEQUENCER_257              0x3101
+#define WM8995_WRITE_SEQUENCER_258              0x3102
+#define WM8995_WRITE_SEQUENCER_259              0x3103
+#define WM8995_WRITE_SEQUENCER_260              0x3104
+#define WM8995_WRITE_SEQUENCER_261              0x3105
+#define WM8995_WRITE_SEQUENCER_262              0x3106
+#define WM8995_WRITE_SEQUENCER_263              0x3107
+#define WM8995_WRITE_SEQUENCER_264              0x3108
+#define WM8995_WRITE_SEQUENCER_265              0x3109
+#define WM8995_WRITE_SEQUENCER_266              0x310A
+#define WM8995_WRITE_SEQUENCER_267              0x310B
+#define WM8995_WRITE_SEQUENCER_268              0x310C
+#define WM8995_WRITE_SEQUENCER_269              0x310D
+#define WM8995_WRITE_SEQUENCER_270              0x310E
+#define WM8995_WRITE_SEQUENCER_271              0x310F
+#define WM8995_WRITE_SEQUENCER_272              0x3110
+#define WM8995_WRITE_SEQUENCER_273              0x3111
+#define WM8995_WRITE_SEQUENCER_274              0x3112
+#define WM8995_WRITE_SEQUENCER_275              0x3113
+#define WM8995_WRITE_SEQUENCER_276              0x3114
+#define WM8995_WRITE_SEQUENCER_277              0x3115
+#define WM8995_WRITE_SEQUENCER_278              0x3116
+#define WM8995_WRITE_SEQUENCER_279              0x3117
+#define WM8995_WRITE_SEQUENCER_280              0x3118
+#define WM8995_WRITE_SEQUENCER_281              0x3119
+#define WM8995_WRITE_SEQUENCER_282              0x311A
+#define WM8995_WRITE_SEQUENCER_283              0x311B
+#define WM8995_WRITE_SEQUENCER_284              0x311C
+#define WM8995_WRITE_SEQUENCER_285              0x311D
+#define WM8995_WRITE_SEQUENCER_286              0x311E
+#define WM8995_WRITE_SEQUENCER_287              0x311F
+#define WM8995_WRITE_SEQUENCER_288              0x3120
+#define WM8995_WRITE_SEQUENCER_289              0x3121
+#define WM8995_WRITE_SEQUENCER_290              0x3122
+#define WM8995_WRITE_SEQUENCER_291              0x3123
+#define WM8995_WRITE_SEQUENCER_292              0x3124
+#define WM8995_WRITE_SEQUENCER_293              0x3125
+#define WM8995_WRITE_SEQUENCER_294              0x3126
+#define WM8995_WRITE_SEQUENCER_295              0x3127
+#define WM8995_WRITE_SEQUENCER_296              0x3128
+#define WM8995_WRITE_SEQUENCER_297              0x3129
+#define WM8995_WRITE_SEQUENCER_298              0x312A
+#define WM8995_WRITE_SEQUENCER_299              0x312B
+#define WM8995_WRITE_SEQUENCER_300              0x312C
+#define WM8995_WRITE_SEQUENCER_301              0x312D
+#define WM8995_WRITE_SEQUENCER_302              0x312E
+#define WM8995_WRITE_SEQUENCER_303              0x312F
+#define WM8995_WRITE_SEQUENCER_304              0x3130
+#define WM8995_WRITE_SEQUENCER_305              0x3131
+#define WM8995_WRITE_SEQUENCER_306              0x3132
+#define WM8995_WRITE_SEQUENCER_307              0x3133
+#define WM8995_WRITE_SEQUENCER_308              0x3134
+#define WM8995_WRITE_SEQUENCER_309              0x3135
+#define WM8995_WRITE_SEQUENCER_310              0x3136
+#define WM8995_WRITE_SEQUENCER_311              0x3137
+#define WM8995_WRITE_SEQUENCER_312              0x3138
+#define WM8995_WRITE_SEQUENCER_313              0x3139
+#define WM8995_WRITE_SEQUENCER_314              0x313A
+#define WM8995_WRITE_SEQUENCER_315              0x313B
+#define WM8995_WRITE_SEQUENCER_316              0x313C
+#define WM8995_WRITE_SEQUENCER_317              0x313D
+#define WM8995_WRITE_SEQUENCER_318              0x313E
+#define WM8995_WRITE_SEQUENCER_319              0x313F
+#define WM8995_WRITE_SEQUENCER_320              0x3140
+#define WM8995_WRITE_SEQUENCER_321              0x3141
+#define WM8995_WRITE_SEQUENCER_322              0x3142
+#define WM8995_WRITE_SEQUENCER_323              0x3143
+#define WM8995_WRITE_SEQUENCER_324              0x3144
+#define WM8995_WRITE_SEQUENCER_325              0x3145
+#define WM8995_WRITE_SEQUENCER_326              0x3146
+#define WM8995_WRITE_SEQUENCER_327              0x3147
+#define WM8995_WRITE_SEQUENCER_328              0x3148
+#define WM8995_WRITE_SEQUENCER_329              0x3149
+#define WM8995_WRITE_SEQUENCER_330              0x314A
+#define WM8995_WRITE_SEQUENCER_331              0x314B
+#define WM8995_WRITE_SEQUENCER_332              0x314C
+#define WM8995_WRITE_SEQUENCER_333              0x314D
+#define WM8995_WRITE_SEQUENCER_334              0x314E
+#define WM8995_WRITE_SEQUENCER_335              0x314F
+#define WM8995_WRITE_SEQUENCER_336              0x3150
+#define WM8995_WRITE_SEQUENCER_337              0x3151
+#define WM8995_WRITE_SEQUENCER_338              0x3152
+#define WM8995_WRITE_SEQUENCER_339              0x3153
+#define WM8995_WRITE_SEQUENCER_340              0x3154
+#define WM8995_WRITE_SEQUENCER_341              0x3155
+#define WM8995_WRITE_SEQUENCER_342              0x3156
+#define WM8995_WRITE_SEQUENCER_343              0x3157
+#define WM8995_WRITE_SEQUENCER_344              0x3158
+#define WM8995_WRITE_SEQUENCER_345              0x3159
+#define WM8995_WRITE_SEQUENCER_346              0x315A
+#define WM8995_WRITE_SEQUENCER_347              0x315B
+#define WM8995_WRITE_SEQUENCER_348              0x315C
+#define WM8995_WRITE_SEQUENCER_349              0x315D
+#define WM8995_WRITE_SEQUENCER_350              0x315E
+#define WM8995_WRITE_SEQUENCER_351              0x315F
+#define WM8995_WRITE_SEQUENCER_352              0x3160
+#define WM8995_WRITE_SEQUENCER_353              0x3161
+#define WM8995_WRITE_SEQUENCER_354              0x3162
+#define WM8995_WRITE_SEQUENCER_355              0x3163
+#define WM8995_WRITE_SEQUENCER_356              0x3164
+#define WM8995_WRITE_SEQUENCER_357              0x3165
+#define WM8995_WRITE_SEQUENCER_358              0x3166
+#define WM8995_WRITE_SEQUENCER_359              0x3167
+#define WM8995_WRITE_SEQUENCER_360              0x3168
+#define WM8995_WRITE_SEQUENCER_361              0x3169
+#define WM8995_WRITE_SEQUENCER_362              0x316A
+#define WM8995_WRITE_SEQUENCER_363              0x316B
+#define WM8995_WRITE_SEQUENCER_364              0x316C
+#define WM8995_WRITE_SEQUENCER_365              0x316D
+#define WM8995_WRITE_SEQUENCER_366              0x316E
+#define WM8995_WRITE_SEQUENCER_367              0x316F
+#define WM8995_WRITE_SEQUENCER_368              0x3170
+#define WM8995_WRITE_SEQUENCER_369              0x3171
+#define WM8995_WRITE_SEQUENCER_370              0x3172
+#define WM8995_WRITE_SEQUENCER_371              0x3173
+#define WM8995_WRITE_SEQUENCER_372              0x3174
+#define WM8995_WRITE_SEQUENCER_373              0x3175
+#define WM8995_WRITE_SEQUENCER_374              0x3176
+#define WM8995_WRITE_SEQUENCER_375              0x3177
+#define WM8995_WRITE_SEQUENCER_376              0x3178
+#define WM8995_WRITE_SEQUENCER_377              0x3179
+#define WM8995_WRITE_SEQUENCER_378              0x317A
+#define WM8995_WRITE_SEQUENCER_379              0x317B
+#define WM8995_WRITE_SEQUENCER_380              0x317C
+#define WM8995_WRITE_SEQUENCER_381              0x317D
+#define WM8995_WRITE_SEQUENCER_382              0x317E
+#define WM8995_WRITE_SEQUENCER_383              0x317F
+#define WM8995_WRITE_SEQUENCER_384              0x3180
+#define WM8995_WRITE_SEQUENCER_385              0x3181
+#define WM8995_WRITE_SEQUENCER_386              0x3182
+#define WM8995_WRITE_SEQUENCER_387              0x3183
+#define WM8995_WRITE_SEQUENCER_388              0x3184
+#define WM8995_WRITE_SEQUENCER_389              0x3185
+#define WM8995_WRITE_SEQUENCER_390              0x3186
+#define WM8995_WRITE_SEQUENCER_391              0x3187
+#define WM8995_WRITE_SEQUENCER_392              0x3188
+#define WM8995_WRITE_SEQUENCER_393              0x3189
+#define WM8995_WRITE_SEQUENCER_394              0x318A
+#define WM8995_WRITE_SEQUENCER_395              0x318B
+#define WM8995_WRITE_SEQUENCER_396              0x318C
+#define WM8995_WRITE_SEQUENCER_397              0x318D
+#define WM8995_WRITE_SEQUENCER_398              0x318E
+#define WM8995_WRITE_SEQUENCER_399              0x318F
+#define WM8995_WRITE_SEQUENCER_400              0x3190
+#define WM8995_WRITE_SEQUENCER_401              0x3191
+#define WM8995_WRITE_SEQUENCER_402              0x3192
+#define WM8995_WRITE_SEQUENCER_403              0x3193
+#define WM8995_WRITE_SEQUENCER_404              0x3194
+#define WM8995_WRITE_SEQUENCER_405              0x3195
+#define WM8995_WRITE_SEQUENCER_406              0x3196
+#define WM8995_WRITE_SEQUENCER_407              0x3197
+#define WM8995_WRITE_SEQUENCER_408              0x3198
+#define WM8995_WRITE_SEQUENCER_409              0x3199
+#define WM8995_WRITE_SEQUENCER_410              0x319A
+#define WM8995_WRITE_SEQUENCER_411              0x319B
+#define WM8995_WRITE_SEQUENCER_412              0x319C
+#define WM8995_WRITE_SEQUENCER_413              0x319D
+#define WM8995_WRITE_SEQUENCER_414              0x319E
+#define WM8995_WRITE_SEQUENCER_415              0x319F
+#define WM8995_WRITE_SEQUENCER_416              0x31A0
+#define WM8995_WRITE_SEQUENCER_417              0x31A1
+#define WM8995_WRITE_SEQUENCER_418              0x31A2
+#define WM8995_WRITE_SEQUENCER_419              0x31A3
+#define WM8995_WRITE_SEQUENCER_420              0x31A4
+#define WM8995_WRITE_SEQUENCER_421              0x31A5
+#define WM8995_WRITE_SEQUENCER_422              0x31A6
+#define WM8995_WRITE_SEQUENCER_423              0x31A7
+#define WM8995_WRITE_SEQUENCER_424              0x31A8
+#define WM8995_WRITE_SEQUENCER_425              0x31A9
+#define WM8995_WRITE_SEQUENCER_426              0x31AA
+#define WM8995_WRITE_SEQUENCER_427              0x31AB
+#define WM8995_WRITE_SEQUENCER_428              0x31AC
+#define WM8995_WRITE_SEQUENCER_429              0x31AD
+#define WM8995_WRITE_SEQUENCER_430              0x31AE
+#define WM8995_WRITE_SEQUENCER_431              0x31AF
+#define WM8995_WRITE_SEQUENCER_432              0x31B0
+#define WM8995_WRITE_SEQUENCER_433              0x31B1
+#define WM8995_WRITE_SEQUENCER_434              0x31B2
+#define WM8995_WRITE_SEQUENCER_435              0x31B3
+#define WM8995_WRITE_SEQUENCER_436              0x31B4
+#define WM8995_WRITE_SEQUENCER_437              0x31B5
+#define WM8995_WRITE_SEQUENCER_438              0x31B6
+#define WM8995_WRITE_SEQUENCER_439              0x31B7
+#define WM8995_WRITE_SEQUENCER_440              0x31B8
+#define WM8995_WRITE_SEQUENCER_441              0x31B9
+#define WM8995_WRITE_SEQUENCER_442              0x31BA
+#define WM8995_WRITE_SEQUENCER_443              0x31BB
+#define WM8995_WRITE_SEQUENCER_444              0x31BC
+#define WM8995_WRITE_SEQUENCER_445              0x31BD
+#define WM8995_WRITE_SEQUENCER_446              0x31BE
+#define WM8995_WRITE_SEQUENCER_447              0x31BF
+#define WM8995_WRITE_SEQUENCER_448              0x31C0
+#define WM8995_WRITE_SEQUENCER_449              0x31C1
+#define WM8995_WRITE_SEQUENCER_450              0x31C2
+#define WM8995_WRITE_SEQUENCER_451              0x31C3
+#define WM8995_WRITE_SEQUENCER_452              0x31C4
+#define WM8995_WRITE_SEQUENCER_453              0x31C5
+#define WM8995_WRITE_SEQUENCER_454              0x31C6
+#define WM8995_WRITE_SEQUENCER_455              0x31C7
+#define WM8995_WRITE_SEQUENCER_456              0x31C8
+#define WM8995_WRITE_SEQUENCER_457              0x31C9
+#define WM8995_WRITE_SEQUENCER_458              0x31CA
+#define WM8995_WRITE_SEQUENCER_459              0x31CB
+#define WM8995_WRITE_SEQUENCER_460              0x31CC
+#define WM8995_WRITE_SEQUENCER_461              0x31CD
+#define WM8995_WRITE_SEQUENCER_462              0x31CE
+#define WM8995_WRITE_SEQUENCER_463              0x31CF
+#define WM8995_WRITE_SEQUENCER_464              0x31D0
+#define WM8995_WRITE_SEQUENCER_465              0x31D1
+#define WM8995_WRITE_SEQUENCER_466              0x31D2
+#define WM8995_WRITE_SEQUENCER_467              0x31D3
+#define WM8995_WRITE_SEQUENCER_468              0x31D4
+#define WM8995_WRITE_SEQUENCER_469              0x31D5
+#define WM8995_WRITE_SEQUENCER_470              0x31D6
+#define WM8995_WRITE_SEQUENCER_471              0x31D7
+#define WM8995_WRITE_SEQUENCER_472              0x31D8
+#define WM8995_WRITE_SEQUENCER_473              0x31D9
+#define WM8995_WRITE_SEQUENCER_474              0x31DA
+#define WM8995_WRITE_SEQUENCER_475              0x31DB
+#define WM8995_WRITE_SEQUENCER_476              0x31DC
+#define WM8995_WRITE_SEQUENCER_477              0x31DD
+#define WM8995_WRITE_SEQUENCER_478              0x31DE
+#define WM8995_WRITE_SEQUENCER_479              0x31DF
+#define WM8995_WRITE_SEQUENCER_480              0x31E0
+#define WM8995_WRITE_SEQUENCER_481              0x31E1
+#define WM8995_WRITE_SEQUENCER_482              0x31E2
+#define WM8995_WRITE_SEQUENCER_483              0x31E3
+#define WM8995_WRITE_SEQUENCER_484              0x31E4
+#define WM8995_WRITE_SEQUENCER_485              0x31E5
+#define WM8995_WRITE_SEQUENCER_486              0x31E6
+#define WM8995_WRITE_SEQUENCER_487              0x31E7
+#define WM8995_WRITE_SEQUENCER_488              0x31E8
+#define WM8995_WRITE_SEQUENCER_489              0x31E9
+#define WM8995_WRITE_SEQUENCER_490              0x31EA
+#define WM8995_WRITE_SEQUENCER_491              0x31EB
+#define WM8995_WRITE_SEQUENCER_492              0x31EC
+#define WM8995_WRITE_SEQUENCER_493              0x31ED
+#define WM8995_WRITE_SEQUENCER_494              0x31EE
+#define WM8995_WRITE_SEQUENCER_495              0x31EF
+#define WM8995_WRITE_SEQUENCER_496              0x31F0
+#define WM8995_WRITE_SEQUENCER_497              0x31F1
+#define WM8995_WRITE_SEQUENCER_498              0x31F2
+#define WM8995_WRITE_SEQUENCER_499              0x31F3
+#define WM8995_WRITE_SEQUENCER_500              0x31F4
+#define WM8995_WRITE_SEQUENCER_501              0x31F5
+#define WM8995_WRITE_SEQUENCER_502              0x31F6
+#define WM8995_WRITE_SEQUENCER_503              0x31F7
+#define WM8995_WRITE_SEQUENCER_504              0x31F8
+#define WM8995_WRITE_SEQUENCER_505              0x31F9
+#define WM8995_WRITE_SEQUENCER_506              0x31FA
+#define WM8995_WRITE_SEQUENCER_507              0x31FB
+#define WM8995_WRITE_SEQUENCER_508              0x31FC
+#define WM8995_WRITE_SEQUENCER_509              0x31FD
+#define WM8995_WRITE_SEQUENCER_510              0x31FE
+#define WM8995_WRITE_SEQUENCER_511              0x31FF
+
+#define WM8995_REGISTER_COUNT                   725
+#define WM8995_MAX_REGISTER                     0x31FF
+
+#define WM8995_MAX_CACHED_REGISTER             WM8995_MAX_REGISTER
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM8995_SW_RESET_MASK                    0xFFFF /* SW_RESET - [15:0] */
+#define WM8995_SW_RESET_SHIFT                        0 /* SW_RESET - [15:0] */
+#define WM8995_SW_RESET_WIDTH                       16 /* SW_RESET - [15:0] */
+
+/*
+ * R1 (0x01) - Power Management (1)
+ */
+#define WM8995_MICB2_ENA                        0x0200 /* MICB2_ENA */
+#define WM8995_MICB2_ENA_MASK                   0x0200 /* MICB2_ENA */
+#define WM8995_MICB2_ENA_SHIFT                       9 /* MICB2_ENA */
+#define WM8995_MICB2_ENA_WIDTH                       1 /* MICB2_ENA */
+#define WM8995_MICB1_ENA                        0x0100 /* MICB1_ENA */
+#define WM8995_MICB1_ENA_MASK                   0x0100 /* MICB1_ENA */
+#define WM8995_MICB1_ENA_SHIFT                       8 /* MICB1_ENA */
+#define WM8995_MICB1_ENA_WIDTH                       1 /* MICB1_ENA */
+#define WM8995_HPOUT2L_ENA                      0x0080 /* HPOUT2L_ENA */
+#define WM8995_HPOUT2L_ENA_MASK                 0x0080 /* HPOUT2L_ENA */
+#define WM8995_HPOUT2L_ENA_SHIFT                     7 /* HPOUT2L_ENA */
+#define WM8995_HPOUT2L_ENA_WIDTH                     1 /* HPOUT2L_ENA */
+#define WM8995_HPOUT2R_ENA                      0x0040 /* HPOUT2R_ENA */
+#define WM8995_HPOUT2R_ENA_MASK                 0x0040 /* HPOUT2R_ENA */
+#define WM8995_HPOUT2R_ENA_SHIFT                     6 /* HPOUT2R_ENA */
+#define WM8995_HPOUT2R_ENA_WIDTH                     1 /* HPOUT2R_ENA */
+#define WM8995_HPOUT1L_ENA                      0x0020 /* HPOUT1L_ENA */
+#define WM8995_HPOUT1L_ENA_MASK                 0x0020 /* HPOUT1L_ENA */
+#define WM8995_HPOUT1L_ENA_SHIFT                     5 /* HPOUT1L_ENA */
+#define WM8995_HPOUT1L_ENA_WIDTH                     1 /* HPOUT1L_ENA */
+#define WM8995_HPOUT1R_ENA                      0x0010 /* HPOUT1R_ENA */
+#define WM8995_HPOUT1R_ENA_MASK                 0x0010 /* HPOUT1R_ENA */
+#define WM8995_HPOUT1R_ENA_SHIFT                     4 /* HPOUT1R_ENA */
+#define WM8995_HPOUT1R_ENA_WIDTH                     1 /* HPOUT1R_ENA */
+#define WM8995_BG_ENA                           0x0001 /* BG_ENA */
+#define WM8995_BG_ENA_MASK                      0x0001 /* BG_ENA */
+#define WM8995_BG_ENA_SHIFT                          0 /* BG_ENA */
+#define WM8995_BG_ENA_WIDTH                          1 /* BG_ENA */
+
+/*
+ * R2 (0x02) - Power Management (2)
+ */
+#define WM8995_OPCLK_ENA                        0x0800 /* OPCLK_ENA */
+#define WM8995_OPCLK_ENA_MASK                   0x0800 /* OPCLK_ENA */
+#define WM8995_OPCLK_ENA_SHIFT                      11 /* OPCLK_ENA */
+#define WM8995_OPCLK_ENA_WIDTH                       1 /* OPCLK_ENA */
+#define WM8995_IN1L_ENA                         0x0020 /* IN1L_ENA */
+#define WM8995_IN1L_ENA_MASK                    0x0020 /* IN1L_ENA */
+#define WM8995_IN1L_ENA_SHIFT                        5 /* IN1L_ENA */
+#define WM8995_IN1L_ENA_WIDTH                        1 /* IN1L_ENA */
+#define WM8995_IN1R_ENA                         0x0010 /* IN1R_ENA */
+#define WM8995_IN1R_ENA_MASK                    0x0010 /* IN1R_ENA */
+#define WM8995_IN1R_ENA_SHIFT                        4 /* IN1R_ENA */
+#define WM8995_IN1R_ENA_WIDTH                        1 /* IN1R_ENA */
+#define WM8995_LDO2_ENA                         0x0002 /* LDO2_ENA */
+#define WM8995_LDO2_ENA_MASK                    0x0002 /* LDO2_ENA */
+#define WM8995_LDO2_ENA_SHIFT                        1 /* LDO2_ENA */
+#define WM8995_LDO2_ENA_WIDTH                        1 /* LDO2_ENA */
+
+/*
+ * R3 (0x03) - Power Management (3)
+ */
+#define WM8995_AIF2ADCL_ENA                     0x2000 /* AIF2ADCL_ENA */
+#define WM8995_AIF2ADCL_ENA_MASK                0x2000 /* AIF2ADCL_ENA */
+#define WM8995_AIF2ADCL_ENA_SHIFT                   13 /* AIF2ADCL_ENA */
+#define WM8995_AIF2ADCL_ENA_WIDTH                    1 /* AIF2ADCL_ENA */
+#define WM8995_AIF2ADCR_ENA                     0x1000 /* AIF2ADCR_ENA */
+#define WM8995_AIF2ADCR_ENA_MASK                0x1000 /* AIF2ADCR_ENA */
+#define WM8995_AIF2ADCR_ENA_SHIFT                   12 /* AIF2ADCR_ENA */
+#define WM8995_AIF2ADCR_ENA_WIDTH                    1 /* AIF2ADCR_ENA */
+#define WM8995_AIF1ADC2L_ENA                    0x0800 /* AIF1ADC2L_ENA */
+#define WM8995_AIF1ADC2L_ENA_MASK               0x0800 /* AIF1ADC2L_ENA */
+#define WM8995_AIF1ADC2L_ENA_SHIFT                  11 /* AIF1ADC2L_ENA */
+#define WM8995_AIF1ADC2L_ENA_WIDTH                   1 /* AIF1ADC2L_ENA */
+#define WM8995_AIF1ADC2R_ENA                    0x0400 /* AIF1ADC2R_ENA */
+#define WM8995_AIF1ADC2R_ENA_MASK               0x0400 /* AIF1ADC2R_ENA */
+#define WM8995_AIF1ADC2R_ENA_SHIFT                  10 /* AIF1ADC2R_ENA */
+#define WM8995_AIF1ADC2R_ENA_WIDTH                   1 /* AIF1ADC2R_ENA */
+#define WM8995_AIF1ADC1L_ENA                    0x0200 /* AIF1ADC1L_ENA */
+#define WM8995_AIF1ADC1L_ENA_MASK               0x0200 /* AIF1ADC1L_ENA */
+#define WM8995_AIF1ADC1L_ENA_SHIFT                   9 /* AIF1ADC1L_ENA */
+#define WM8995_AIF1ADC1L_ENA_WIDTH                   1 /* AIF1ADC1L_ENA */
+#define WM8995_AIF1ADC1R_ENA                    0x0100 /* AIF1ADC1R_ENA */
+#define WM8995_AIF1ADC1R_ENA_MASK               0x0100 /* AIF1ADC1R_ENA */
+#define WM8995_AIF1ADC1R_ENA_SHIFT                   8 /* AIF1ADC1R_ENA */
+#define WM8995_AIF1ADC1R_ENA_WIDTH                   1 /* AIF1ADC1R_ENA */
+#define WM8995_DMIC3L_ENA                       0x0080 /* DMIC3L_ENA */
+#define WM8995_DMIC3L_ENA_MASK                  0x0080 /* DMIC3L_ENA */
+#define WM8995_DMIC3L_ENA_SHIFT                      7 /* DMIC3L_ENA */
+#define WM8995_DMIC3L_ENA_WIDTH                      1 /* DMIC3L_ENA */
+#define WM8995_DMIC3R_ENA                       0x0040 /* DMIC3R_ENA */
+#define WM8995_DMIC3R_ENA_MASK                  0x0040 /* DMIC3R_ENA */
+#define WM8995_DMIC3R_ENA_SHIFT                      6 /* DMIC3R_ENA */
+#define WM8995_DMIC3R_ENA_WIDTH                      1 /* DMIC3R_ENA */
+#define WM8995_DMIC2L_ENA                       0x0020 /* DMIC2L_ENA */
+#define WM8995_DMIC2L_ENA_MASK                  0x0020 /* DMIC2L_ENA */
+#define WM8995_DMIC2L_ENA_SHIFT                      5 /* DMIC2L_ENA */
+#define WM8995_DMIC2L_ENA_WIDTH                      1 /* DMIC2L_ENA */
+#define WM8995_DMIC2R_ENA                       0x0010 /* DMIC2R_ENA */
+#define WM8995_DMIC2R_ENA_MASK                  0x0010 /* DMIC2R_ENA */
+#define WM8995_DMIC2R_ENA_SHIFT                      4 /* DMIC2R_ENA */
+#define WM8995_DMIC2R_ENA_WIDTH                      1 /* DMIC2R_ENA */
+#define WM8995_DMIC1L_ENA                       0x0008 /* DMIC1L_ENA */
+#define WM8995_DMIC1L_ENA_MASK                  0x0008 /* DMIC1L_ENA */
+#define WM8995_DMIC1L_ENA_SHIFT                      3 /* DMIC1L_ENA */
+#define WM8995_DMIC1L_ENA_WIDTH                      1 /* DMIC1L_ENA */
+#define WM8995_DMIC1R_ENA                       0x0004 /* DMIC1R_ENA */
+#define WM8995_DMIC1R_ENA_MASK                  0x0004 /* DMIC1R_ENA */
+#define WM8995_DMIC1R_ENA_SHIFT                      2 /* DMIC1R_ENA */
+#define WM8995_DMIC1R_ENA_WIDTH                      1 /* DMIC1R_ENA */
+#define WM8995_ADCL_ENA                         0x0002 /* ADCL_ENA */
+#define WM8995_ADCL_ENA_MASK                    0x0002 /* ADCL_ENA */
+#define WM8995_ADCL_ENA_SHIFT                        1 /* ADCL_ENA */
+#define WM8995_ADCL_ENA_WIDTH                        1 /* ADCL_ENA */
+#define WM8995_ADCR_ENA                         0x0001 /* ADCR_ENA */
+#define WM8995_ADCR_ENA_MASK                    0x0001 /* ADCR_ENA */
+#define WM8995_ADCR_ENA_SHIFT                        0 /* ADCR_ENA */
+#define WM8995_ADCR_ENA_WIDTH                        1 /* ADCR_ENA */
+
+/*
+ * R4 (0x04) - Power Management (4)
+ */
+#define WM8995_AIF2DACL_ENA                     0x2000 /* AIF2DACL_ENA */
+#define WM8995_AIF2DACL_ENA_MASK                0x2000 /* AIF2DACL_ENA */
+#define WM8995_AIF2DACL_ENA_SHIFT                   13 /* AIF2DACL_ENA */
+#define WM8995_AIF2DACL_ENA_WIDTH                    1 /* AIF2DACL_ENA */
+#define WM8995_AIF2DACR_ENA                     0x1000 /* AIF2DACR_ENA */
+#define WM8995_AIF2DACR_ENA_MASK                0x1000 /* AIF2DACR_ENA */
+#define WM8995_AIF2DACR_ENA_SHIFT                   12 /* AIF2DACR_ENA */
+#define WM8995_AIF2DACR_ENA_WIDTH                    1 /* AIF2DACR_ENA */
+#define WM8995_AIF1DAC2L_ENA                    0x0800 /* AIF1DAC2L_ENA */
+#define WM8995_AIF1DAC2L_ENA_MASK               0x0800 /* AIF1DAC2L_ENA */
+#define WM8995_AIF1DAC2L_ENA_SHIFT                  11 /* AIF1DAC2L_ENA */
+#define WM8995_AIF1DAC2L_ENA_WIDTH                   1 /* AIF1DAC2L_ENA */
+#define WM8995_AIF1DAC2R_ENA                    0x0400 /* AIF1DAC2R_ENA */
+#define WM8995_AIF1DAC2R_ENA_MASK               0x0400 /* AIF1DAC2R_ENA */
+#define WM8995_AIF1DAC2R_ENA_SHIFT                  10 /* AIF1DAC2R_ENA */
+#define WM8995_AIF1DAC2R_ENA_WIDTH                   1 /* AIF1DAC2R_ENA */
+#define WM8995_AIF1DAC1L_ENA                    0x0200 /* AIF1DAC1L_ENA */
+#define WM8995_AIF1DAC1L_ENA_MASK               0x0200 /* AIF1DAC1L_ENA */
+#define WM8995_AIF1DAC1L_ENA_SHIFT                   9 /* AIF1DAC1L_ENA */
+#define WM8995_AIF1DAC1L_ENA_WIDTH                   1 /* AIF1DAC1L_ENA */
+#define WM8995_AIF1DAC1R_ENA                    0x0100 /* AIF1DAC1R_ENA */
+#define WM8995_AIF1DAC1R_ENA_MASK               0x0100 /* AIF1DAC1R_ENA */
+#define WM8995_AIF1DAC1R_ENA_SHIFT                   8 /* AIF1DAC1R_ENA */
+#define WM8995_AIF1DAC1R_ENA_WIDTH                   1 /* AIF1DAC1R_ENA */
+#define WM8995_DAC2L_ENA                        0x0008 /* DAC2L_ENA */
+#define WM8995_DAC2L_ENA_MASK                   0x0008 /* DAC2L_ENA */
+#define WM8995_DAC2L_ENA_SHIFT                       3 /* DAC2L_ENA */
+#define WM8995_DAC2L_ENA_WIDTH                       1 /* DAC2L_ENA */
+#define WM8995_DAC2R_ENA                        0x0004 /* DAC2R_ENA */
+#define WM8995_DAC2R_ENA_MASK                   0x0004 /* DAC2R_ENA */
+#define WM8995_DAC2R_ENA_SHIFT                       2 /* DAC2R_ENA */
+#define WM8995_DAC2R_ENA_WIDTH                       1 /* DAC2R_ENA */
+#define WM8995_DAC1L_ENA                        0x0002 /* DAC1L_ENA */
+#define WM8995_DAC1L_ENA_MASK                   0x0002 /* DAC1L_ENA */
+#define WM8995_DAC1L_ENA_SHIFT                       1 /* DAC1L_ENA */
+#define WM8995_DAC1L_ENA_WIDTH                       1 /* DAC1L_ENA */
+#define WM8995_DAC1R_ENA                        0x0001 /* DAC1R_ENA */
+#define WM8995_DAC1R_ENA_MASK                   0x0001 /* DAC1R_ENA */
+#define WM8995_DAC1R_ENA_SHIFT                       0 /* DAC1R_ENA */
+#define WM8995_DAC1R_ENA_WIDTH                       1 /* DAC1R_ENA */
+
+/*
+ * R5 (0x05) - Power Management (5)
+ */
+#define WM8995_DMIC_SRC2_MASK                   0x0300 /* DMIC_SRC2 - [9:8] */
+#define WM8995_DMIC_SRC2_SHIFT                       8 /* DMIC_SRC2 - [9:8] */
+#define WM8995_DMIC_SRC2_WIDTH                       2 /* DMIC_SRC2 - [9:8] */
+#define WM8995_DMIC_SRC1_MASK                   0x00C0 /* DMIC_SRC1 - [7:6] */
+#define WM8995_DMIC_SRC1_SHIFT                       6 /* DMIC_SRC1 - [7:6] */
+#define WM8995_DMIC_SRC1_WIDTH                       2 /* DMIC_SRC1 - [7:6] */
+#define WM8995_AIF3_TRI                         0x0020 /* AIF3_TRI */
+#define WM8995_AIF3_TRI_MASK                    0x0020 /* AIF3_TRI */
+#define WM8995_AIF3_TRI_SHIFT                        5 /* AIF3_TRI */
+#define WM8995_AIF3_TRI_WIDTH                        1 /* AIF3_TRI */
+#define WM8995_AIF3_ADCDAT_SRC_MASK             0x0018 /* AIF3_ADCDAT_SRC - [4:3] */
+#define WM8995_AIF3_ADCDAT_SRC_SHIFT                 3 /* AIF3_ADCDAT_SRC - [4:3] */
+#define WM8995_AIF3_ADCDAT_SRC_WIDTH                 2 /* AIF3_ADCDAT_SRC - [4:3] */
+#define WM8995_AIF2_ADCDAT_SRC                  0x0004 /* AIF2_ADCDAT_SRC */
+#define WM8995_AIF2_ADCDAT_SRC_MASK             0x0004 /* AIF2_ADCDAT_SRC */
+#define WM8995_AIF2_ADCDAT_SRC_SHIFT                 2 /* AIF2_ADCDAT_SRC */
+#define WM8995_AIF2_ADCDAT_SRC_WIDTH                 1 /* AIF2_ADCDAT_SRC */
+#define WM8995_AIF2_DACDAT_SRC                  0x0002 /* AIF2_DACDAT_SRC */
+#define WM8995_AIF2_DACDAT_SRC_MASK             0x0002 /* AIF2_DACDAT_SRC */
+#define WM8995_AIF2_DACDAT_SRC_SHIFT                 1 /* AIF2_DACDAT_SRC */
+#define WM8995_AIF2_DACDAT_SRC_WIDTH                 1 /* AIF2_DACDAT_SRC */
+#define WM8995_AIF1_DACDAT_SRC                  0x0001 /* AIF1_DACDAT_SRC */
+#define WM8995_AIF1_DACDAT_SRC_MASK             0x0001 /* AIF1_DACDAT_SRC */
+#define WM8995_AIF1_DACDAT_SRC_SHIFT                 0 /* AIF1_DACDAT_SRC */
+#define WM8995_AIF1_DACDAT_SRC_WIDTH                 1 /* AIF1_DACDAT_SRC */
+
+/*
+ * R16 (0x10) - Left Line Input 1 Volume
+ */
+#define WM8995_IN1_VU                           0x0080 /* IN1_VU */
+#define WM8995_IN1_VU_MASK                      0x0080 /* IN1_VU */
+#define WM8995_IN1_VU_SHIFT                          7 /* IN1_VU */
+#define WM8995_IN1_VU_WIDTH                          1 /* IN1_VU */
+#define WM8995_IN1L_ZC                          0x0020 /* IN1L_ZC */
+#define WM8995_IN1L_ZC_MASK                     0x0020 /* IN1L_ZC */
+#define WM8995_IN1L_ZC_SHIFT                         5 /* IN1L_ZC */
+#define WM8995_IN1L_ZC_WIDTH                         1 /* IN1L_ZC */
+#define WM8995_IN1L_VOL_MASK                    0x001F /* IN1L_VOL - [4:0] */
+#define WM8995_IN1L_VOL_SHIFT                        0 /* IN1L_VOL - [4:0] */
+#define WM8995_IN1L_VOL_WIDTH                        5 /* IN1L_VOL - [4:0] */
+
+/*
+ * R17 (0x11) - Right Line Input 1 Volume
+ */
+#define WM8995_IN1_VU                           0x0080 /* IN1_VU */
+#define WM8995_IN1_VU_MASK                      0x0080 /* IN1_VU */
+#define WM8995_IN1_VU_SHIFT                          7 /* IN1_VU */
+#define WM8995_IN1_VU_WIDTH                          1 /* IN1_VU */
+#define WM8995_IN1R_ZC                          0x0020 /* IN1R_ZC */
+#define WM8995_IN1R_ZC_MASK                     0x0020 /* IN1R_ZC */
+#define WM8995_IN1R_ZC_SHIFT                         5 /* IN1R_ZC */
+#define WM8995_IN1R_ZC_WIDTH                         1 /* IN1R_ZC */
+#define WM8995_IN1R_VOL_MASK                    0x001F /* IN1R_VOL - [4:0] */
+#define WM8995_IN1R_VOL_SHIFT                        0 /* IN1R_VOL - [4:0] */
+#define WM8995_IN1R_VOL_WIDTH                        5 /* IN1R_VOL - [4:0] */
+
+/*
+ * R18 (0x12) - Left Line Input Control
+ */
+#define WM8995_IN1L_BOOST_MASK                  0x0030 /* IN1L_BOOST - [5:4] */
+#define WM8995_IN1L_BOOST_SHIFT                      4 /* IN1L_BOOST - [5:4] */
+#define WM8995_IN1L_BOOST_WIDTH                      2 /* IN1L_BOOST - [5:4] */
+#define WM8995_IN1L_MODE_MASK                   0x000C /* IN1L_MODE - [3:2] */
+#define WM8995_IN1L_MODE_SHIFT                       2 /* IN1L_MODE - [3:2] */
+#define WM8995_IN1L_MODE_WIDTH                       2 /* IN1L_MODE - [3:2] */
+#define WM8995_IN1R_MODE_MASK                   0x0003 /* IN1R_MODE - [1:0] */
+#define WM8995_IN1R_MODE_SHIFT                       0 /* IN1R_MODE - [1:0] */
+#define WM8995_IN1R_MODE_WIDTH                       2 /* IN1R_MODE - [1:0] */
+
+/*
+ * R24 (0x18) - DAC1 Left Volume
+ */
+#define WM8995_DAC1L_MUTE                       0x0200 /* DAC1L_MUTE */
+#define WM8995_DAC1L_MUTE_MASK                  0x0200 /* DAC1L_MUTE */
+#define WM8995_DAC1L_MUTE_SHIFT                      9 /* DAC1L_MUTE */
+#define WM8995_DAC1L_MUTE_WIDTH                      1 /* DAC1L_MUTE */
+#define WM8995_DAC1_VU                          0x0100 /* DAC1_VU */
+#define WM8995_DAC1_VU_MASK                     0x0100 /* DAC1_VU */
+#define WM8995_DAC1_VU_SHIFT                         8 /* DAC1_VU */
+#define WM8995_DAC1_VU_WIDTH                         1 /* DAC1_VU */
+#define WM8995_DAC1L_VOL_MASK                   0x00FF /* DAC1L_VOL - [7:0] */
+#define WM8995_DAC1L_VOL_SHIFT                       0 /* DAC1L_VOL - [7:0] */
+#define WM8995_DAC1L_VOL_WIDTH                       8 /* DAC1L_VOL - [7:0] */
+
+/*
+ * R25 (0x19) - DAC1 Right Volume
+ */
+#define WM8995_DAC1R_MUTE                       0x0200 /* DAC1R_MUTE */
+#define WM8995_DAC1R_MUTE_MASK                  0x0200 /* DAC1R_MUTE */
+#define WM8995_DAC1R_MUTE_SHIFT                      9 /* DAC1R_MUTE */
+#define WM8995_DAC1R_MUTE_WIDTH                      1 /* DAC1R_MUTE */
+#define WM8995_DAC1_VU                          0x0100 /* DAC1_VU */
+#define WM8995_DAC1_VU_MASK                     0x0100 /* DAC1_VU */
+#define WM8995_DAC1_VU_SHIFT                         8 /* DAC1_VU */
+#define WM8995_DAC1_VU_WIDTH                         1 /* DAC1_VU */
+#define WM8995_DAC1R_VOL_MASK                   0x00FF /* DAC1R_VOL - [7:0] */
+#define WM8995_DAC1R_VOL_SHIFT                       0 /* DAC1R_VOL - [7:0] */
+#define WM8995_DAC1R_VOL_WIDTH                       8 /* DAC1R_VOL - [7:0] */
+
+/*
+ * R26 (0x1A) - DAC2 Left Volume
+ */
+#define WM8995_DAC2L_MUTE                       0x0200 /* DAC2L_MUTE */
+#define WM8995_DAC2L_MUTE_MASK                  0x0200 /* DAC2L_MUTE */
+#define WM8995_DAC2L_MUTE_SHIFT                      9 /* DAC2L_MUTE */
+#define WM8995_DAC2L_MUTE_WIDTH                      1 /* DAC2L_MUTE */
+#define WM8995_DAC2_VU                          0x0100 /* DAC2_VU */
+#define WM8995_DAC2_VU_MASK                     0x0100 /* DAC2_VU */
+#define WM8995_DAC2_VU_SHIFT                         8 /* DAC2_VU */
+#define WM8995_DAC2_VU_WIDTH                         1 /* DAC2_VU */
+#define WM8995_DAC2L_VOL_MASK                   0x00FF /* DAC2L_VOL - [7:0] */
+#define WM8995_DAC2L_VOL_SHIFT                       0 /* DAC2L_VOL - [7:0] */
+#define WM8995_DAC2L_VOL_WIDTH                       8 /* DAC2L_VOL - [7:0] */
+
+/*
+ * R27 (0x1B) - DAC2 Right Volume
+ */
+#define WM8995_DAC2R_MUTE                       0x0200 /* DAC2R_MUTE */
+#define WM8995_DAC2R_MUTE_MASK                  0x0200 /* DAC2R_MUTE */
+#define WM8995_DAC2R_MUTE_SHIFT                      9 /* DAC2R_MUTE */
+#define WM8995_DAC2R_MUTE_WIDTH                      1 /* DAC2R_MUTE */
+#define WM8995_DAC2_VU                          0x0100 /* DAC2_VU */
+#define WM8995_DAC2_VU_MASK                     0x0100 /* DAC2_VU */
+#define WM8995_DAC2_VU_SHIFT                         8 /* DAC2_VU */
+#define WM8995_DAC2_VU_WIDTH                         1 /* DAC2_VU */
+#define WM8995_DAC2R_VOL_MASK                   0x00FF /* DAC2R_VOL - [7:0] */
+#define WM8995_DAC2R_VOL_SHIFT                       0 /* DAC2R_VOL - [7:0] */
+#define WM8995_DAC2R_VOL_WIDTH                       8 /* DAC2R_VOL - [7:0] */
+
+/*
+ * R28 (0x1C) - Output Volume ZC (1)
+ */
+#define WM8995_HPOUT2L_ZC                       0x0008 /* HPOUT2L_ZC */
+#define WM8995_HPOUT2L_ZC_MASK                  0x0008 /* HPOUT2L_ZC */
+#define WM8995_HPOUT2L_ZC_SHIFT                      3 /* HPOUT2L_ZC */
+#define WM8995_HPOUT2L_ZC_WIDTH                      1 /* HPOUT2L_ZC */
+#define WM8995_HPOUT2R_ZC                       0x0004 /* HPOUT2R_ZC */
+#define WM8995_HPOUT2R_ZC_MASK                  0x0004 /* HPOUT2R_ZC */
+#define WM8995_HPOUT2R_ZC_SHIFT                      2 /* HPOUT2R_ZC */
+#define WM8995_HPOUT2R_ZC_WIDTH                      1 /* HPOUT2R_ZC */
+#define WM8995_HPOUT1L_ZC                       0x0002 /* HPOUT1L_ZC */
+#define WM8995_HPOUT1L_ZC_MASK                  0x0002 /* HPOUT1L_ZC */
+#define WM8995_HPOUT1L_ZC_SHIFT                      1 /* HPOUT1L_ZC */
+#define WM8995_HPOUT1L_ZC_WIDTH                      1 /* HPOUT1L_ZC */
+#define WM8995_HPOUT1R_ZC                       0x0001 /* HPOUT1R_ZC */
+#define WM8995_HPOUT1R_ZC_MASK                  0x0001 /* HPOUT1R_ZC */
+#define WM8995_HPOUT1R_ZC_SHIFT                      0 /* HPOUT1R_ZC */
+#define WM8995_HPOUT1R_ZC_WIDTH                      1 /* HPOUT1R_ZC */
+
+/*
+ * R32 (0x20) - MICBIAS (1)
+ */
+#define WM8995_MICB1_MODE                       0x0008 /* MICB1_MODE */
+#define WM8995_MICB1_MODE_MASK                  0x0008 /* MICB1_MODE */
+#define WM8995_MICB1_MODE_SHIFT                      3 /* MICB1_MODE */
+#define WM8995_MICB1_MODE_WIDTH                      1 /* MICB1_MODE */
+#define WM8995_MICB1_LVL_MASK                   0x0006 /* MICB1_LVL - [2:1] */
+#define WM8995_MICB1_LVL_SHIFT                       1 /* MICB1_LVL - [2:1] */
+#define WM8995_MICB1_LVL_WIDTH                       2 /* MICB1_LVL - [2:1] */
+#define WM8995_MICB1_DISCH                      0x0001 /* MICB1_DISCH */
+#define WM8995_MICB1_DISCH_MASK                 0x0001 /* MICB1_DISCH */
+#define WM8995_MICB1_DISCH_SHIFT                     0 /* MICB1_DISCH */
+#define WM8995_MICB1_DISCH_WIDTH                     1 /* MICB1_DISCH */
+
+/*
+ * R33 (0x21) - MICBIAS (2)
+ */
+#define WM8995_MICB2_MODE                       0x0008 /* MICB2_MODE */
+#define WM8995_MICB2_MODE_MASK                  0x0008 /* MICB2_MODE */
+#define WM8995_MICB2_MODE_SHIFT                      3 /* MICB2_MODE */
+#define WM8995_MICB2_MODE_WIDTH                      1 /* MICB2_MODE */
+#define WM8995_MICB2_LVL_MASK                   0x0006 /* MICB2_LVL - [2:1] */
+#define WM8995_MICB2_LVL_SHIFT                       1 /* MICB2_LVL - [2:1] */
+#define WM8995_MICB2_LVL_WIDTH                       2 /* MICB2_LVL - [2:1] */
+#define WM8995_MICB2_DISCH                      0x0001 /* MICB2_DISCH */
+#define WM8995_MICB2_DISCH_MASK                 0x0001 /* MICB2_DISCH */
+#define WM8995_MICB2_DISCH_SHIFT                     0 /* MICB2_DISCH */
+#define WM8995_MICB2_DISCH_WIDTH                     1 /* MICB2_DISCH */
+
+/*
+ * R40 (0x28) - LDO 1
+ */
+#define WM8995_LDO1_MODE                        0x0020 /* LDO1_MODE */
+#define WM8995_LDO1_MODE_MASK                   0x0020 /* LDO1_MODE */
+#define WM8995_LDO1_MODE_SHIFT                       5 /* LDO1_MODE */
+#define WM8995_LDO1_MODE_WIDTH                       1 /* LDO1_MODE */
+#define WM8995_LDO1_VSEL_MASK                   0x0006 /* LDO1_VSEL - [2:1] */
+#define WM8995_LDO1_VSEL_SHIFT                       1 /* LDO1_VSEL - [2:1] */
+#define WM8995_LDO1_VSEL_WIDTH                       2 /* LDO1_VSEL - [2:1] */
+#define WM8995_LDO1_DISCH                       0x0001 /* LDO1_DISCH */
+#define WM8995_LDO1_DISCH_MASK                  0x0001 /* LDO1_DISCH */
+#define WM8995_LDO1_DISCH_SHIFT                      0 /* LDO1_DISCH */
+#define WM8995_LDO1_DISCH_WIDTH                      1 /* LDO1_DISCH */
+
+/*
+ * R41 (0x29) - LDO 2
+ */
+#define WM8995_LDO2_MODE                        0x0020 /* LDO2_MODE */
+#define WM8995_LDO2_MODE_MASK                   0x0020 /* LDO2_MODE */
+#define WM8995_LDO2_MODE_SHIFT                       5 /* LDO2_MODE */
+#define WM8995_LDO2_MODE_WIDTH                       1 /* LDO2_MODE */
+#define WM8995_LDO2_VSEL_MASK                   0x001E /* LDO2_VSEL - [4:1] */
+#define WM8995_LDO2_VSEL_SHIFT                       1 /* LDO2_VSEL - [4:1] */
+#define WM8995_LDO2_VSEL_WIDTH                       4 /* LDO2_VSEL - [4:1] */
+#define WM8995_LDO2_DISCH                       0x0001 /* LDO2_DISCH */
+#define WM8995_LDO2_DISCH_MASK                  0x0001 /* LDO2_DISCH */
+#define WM8995_LDO2_DISCH_SHIFT                      0 /* LDO2_DISCH */
+#define WM8995_LDO2_DISCH_WIDTH                      1 /* LDO2_DISCH */
+
+/*
+ * R48 (0x30) - Accessory Detect Mode1
+ */
+#define WM8995_JD_MODE_MASK                     0x0003 /* JD_MODE - [1:0] */
+#define WM8995_JD_MODE_SHIFT                         0 /* JD_MODE - [1:0] */
+#define WM8995_JD_MODE_WIDTH                         2 /* JD_MODE - [1:0] */
+
+/*
+ * R49 (0x31) - Accessory Detect Mode2
+ */
+#define WM8995_VID_ENA                          0x0001 /* VID_ENA */
+#define WM8995_VID_ENA_MASK                     0x0001 /* VID_ENA */
+#define WM8995_VID_ENA_SHIFT                         0 /* VID_ENA */
+#define WM8995_VID_ENA_WIDTH                         1 /* VID_ENA */
+
+/*
+ * R52 (0x34) - Headphone Detect1
+ */
+#define WM8995_HP_RAMPRATE                      0x0002 /* HP_RAMPRATE */
+#define WM8995_HP_RAMPRATE_MASK                 0x0002 /* HP_RAMPRATE */
+#define WM8995_HP_RAMPRATE_SHIFT                     1 /* HP_RAMPRATE */
+#define WM8995_HP_RAMPRATE_WIDTH                     1 /* HP_RAMPRATE */
+#define WM8995_HP_POLL                          0x0001 /* HP_POLL */
+#define WM8995_HP_POLL_MASK                     0x0001 /* HP_POLL */
+#define WM8995_HP_POLL_SHIFT                         0 /* HP_POLL */
+#define WM8995_HP_POLL_WIDTH                         1 /* HP_POLL */
+
+/*
+ * R53 (0x35) - Headphone Detect2
+ */
+#define WM8995_HP_DONE                          0x0080 /* HP_DONE */
+#define WM8995_HP_DONE_MASK                     0x0080 /* HP_DONE */
+#define WM8995_HP_DONE_SHIFT                         7 /* HP_DONE */
+#define WM8995_HP_DONE_WIDTH                         1 /* HP_DONE */
+#define WM8995_HP_LVL_MASK                      0x007F /* HP_LVL - [6:0] */
+#define WM8995_HP_LVL_SHIFT                          0 /* HP_LVL - [6:0] */
+#define WM8995_HP_LVL_WIDTH                          7 /* HP_LVL - [6:0] */
+
+/*
+ * R56 (0x38) - Mic Detect (1)
+ */
+#define WM8995_MICD_RATE_MASK                   0x7800 /* MICD_RATE - [14:11] */
+#define WM8995_MICD_RATE_SHIFT                      11 /* MICD_RATE - [14:11] */
+#define WM8995_MICD_RATE_WIDTH                       4 /* MICD_RATE - [14:11] */
+#define WM8995_MICD_LVL_SEL_MASK                0x01F8 /* MICD_LVL_SEL - [8:3] */
+#define WM8995_MICD_LVL_SEL_SHIFT                    3 /* MICD_LVL_SEL - [8:3] */
+#define WM8995_MICD_LVL_SEL_WIDTH                    6 /* MICD_LVL_SEL - [8:3] */
+#define WM8995_MICD_DBTIME                      0x0002 /* MICD_DBTIME */
+#define WM8995_MICD_DBTIME_MASK                 0x0002 /* MICD_DBTIME */
+#define WM8995_MICD_DBTIME_SHIFT                     1 /* MICD_DBTIME */
+#define WM8995_MICD_DBTIME_WIDTH                     1 /* MICD_DBTIME */
+#define WM8995_MICD_ENA                         0x0001 /* MICD_ENA */
+#define WM8995_MICD_ENA_MASK                    0x0001 /* MICD_ENA */
+#define WM8995_MICD_ENA_SHIFT                        0 /* MICD_ENA */
+#define WM8995_MICD_ENA_WIDTH                        1 /* MICD_ENA */
+
+/*
+ * R57 (0x39) - Mic Detect (2)
+ */
+#define WM8995_MICD_LVL_MASK                    0x01FC /* MICD_LVL - [8:2] */
+#define WM8995_MICD_LVL_SHIFT                        2 /* MICD_LVL - [8:2] */
+#define WM8995_MICD_LVL_WIDTH                        7 /* MICD_LVL - [8:2] */
+#define WM8995_MICD_VALID                       0x0002 /* MICD_VALID */
+#define WM8995_MICD_VALID_MASK                  0x0002 /* MICD_VALID */
+#define WM8995_MICD_VALID_SHIFT                      1 /* MICD_VALID */
+#define WM8995_MICD_VALID_WIDTH                      1 /* MICD_VALID */
+#define WM8995_MICD_STS                         0x0001 /* MICD_STS */
+#define WM8995_MICD_STS_MASK                    0x0001 /* MICD_STS */
+#define WM8995_MICD_STS_SHIFT                        0 /* MICD_STS */
+#define WM8995_MICD_STS_WIDTH                        1 /* MICD_STS */
+
+/*
+ * R64 (0x40) - Charge Pump (1)
+ */
+#define WM8995_CP_ENA                           0x8000 /* CP_ENA */
+#define WM8995_CP_ENA_MASK                      0x8000 /* CP_ENA */
+#define WM8995_CP_ENA_SHIFT                         15 /* CP_ENA */
+#define WM8995_CP_ENA_WIDTH                          1 /* CP_ENA */
+
+/*
+ * R69 (0x45) - Class W (1)
+ */
+#define WM8995_CP_DYN_SRC_SEL_MASK              0x0300 /* CP_DYN_SRC_SEL - [9:8] */
+#define WM8995_CP_DYN_SRC_SEL_SHIFT                  8 /* CP_DYN_SRC_SEL - [9:8] */
+#define WM8995_CP_DYN_SRC_SEL_WIDTH                  2 /* CP_DYN_SRC_SEL - [9:8] */
+#define WM8995_CP_DYN_PWR                       0x0001 /* CP_DYN_PWR */
+#define WM8995_CP_DYN_PWR_MASK                  0x0001 /* CP_DYN_PWR */
+#define WM8995_CP_DYN_PWR_SHIFT                      0 /* CP_DYN_PWR */
+#define WM8995_CP_DYN_PWR_WIDTH                      1 /* CP_DYN_PWR */
+
+/*
+ * R80 (0x50) - DC Servo (1)
+ */
+#define WM8995_DCS_ENA_CHAN_3                   0x0008 /* DCS_ENA_CHAN_3 */
+#define WM8995_DCS_ENA_CHAN_3_MASK              0x0008 /* DCS_ENA_CHAN_3 */
+#define WM8995_DCS_ENA_CHAN_3_SHIFT                  3 /* DCS_ENA_CHAN_3 */
+#define WM8995_DCS_ENA_CHAN_3_WIDTH                  1 /* DCS_ENA_CHAN_3 */
+#define WM8995_DCS_ENA_CHAN_2                   0x0004 /* DCS_ENA_CHAN_2 */
+#define WM8995_DCS_ENA_CHAN_2_MASK              0x0004 /* DCS_ENA_CHAN_2 */
+#define WM8995_DCS_ENA_CHAN_2_SHIFT                  2 /* DCS_ENA_CHAN_2 */
+#define WM8995_DCS_ENA_CHAN_2_WIDTH                  1 /* DCS_ENA_CHAN_2 */
+#define WM8995_DCS_ENA_CHAN_1                   0x0002 /* DCS_ENA_CHAN_1 */
+#define WM8995_DCS_ENA_CHAN_1_MASK              0x0002 /* DCS_ENA_CHAN_1 */
+#define WM8995_DCS_ENA_CHAN_1_SHIFT                  1 /* DCS_ENA_CHAN_1 */
+#define WM8995_DCS_ENA_CHAN_1_WIDTH                  1 /* DCS_ENA_CHAN_1 */
+#define WM8995_DCS_ENA_CHAN_0                   0x0001 /* DCS_ENA_CHAN_0 */
+#define WM8995_DCS_ENA_CHAN_0_MASK              0x0001 /* DCS_ENA_CHAN_0 */
+#define WM8995_DCS_ENA_CHAN_0_SHIFT                  0 /* DCS_ENA_CHAN_0 */
+#define WM8995_DCS_ENA_CHAN_0_WIDTH                  1 /* DCS_ENA_CHAN_0 */
+
+/*
+ * R81 (0x51) - DC Servo (2)
+ */
+#define WM8995_DCS_TRIG_SINGLE_3                0x8000 /* DCS_TRIG_SINGLE_3 */
+#define WM8995_DCS_TRIG_SINGLE_3_MASK           0x8000 /* DCS_TRIG_SINGLE_3 */
+#define WM8995_DCS_TRIG_SINGLE_3_SHIFT              15 /* DCS_TRIG_SINGLE_3 */
+#define WM8995_DCS_TRIG_SINGLE_3_WIDTH               1 /* DCS_TRIG_SINGLE_3 */
+#define WM8995_DCS_TRIG_SINGLE_2                0x4000 /* DCS_TRIG_SINGLE_2 */
+#define WM8995_DCS_TRIG_SINGLE_2_MASK           0x4000 /* DCS_TRIG_SINGLE_2 */
+#define WM8995_DCS_TRIG_SINGLE_2_SHIFT              14 /* DCS_TRIG_SINGLE_2 */
+#define WM8995_DCS_TRIG_SINGLE_2_WIDTH               1 /* DCS_TRIG_SINGLE_2 */
+#define WM8995_DCS_TRIG_SINGLE_1                0x2000 /* DCS_TRIG_SINGLE_1 */
+#define WM8995_DCS_TRIG_SINGLE_1_MASK           0x2000 /* DCS_TRIG_SINGLE_1 */
+#define WM8995_DCS_TRIG_SINGLE_1_SHIFT              13 /* DCS_TRIG_SINGLE_1 */
+#define WM8995_DCS_TRIG_SINGLE_1_WIDTH               1 /* DCS_TRIG_SINGLE_1 */
+#define WM8995_DCS_TRIG_SINGLE_0                0x1000 /* DCS_TRIG_SINGLE_0 */
+#define WM8995_DCS_TRIG_SINGLE_0_MASK           0x1000 /* DCS_TRIG_SINGLE_0 */
+#define WM8995_DCS_TRIG_SINGLE_0_SHIFT              12 /* DCS_TRIG_SINGLE_0 */
+#define WM8995_DCS_TRIG_SINGLE_0_WIDTH               1 /* DCS_TRIG_SINGLE_0 */
+#define WM8995_DCS_TRIG_SERIES_3                0x0800 /* DCS_TRIG_SERIES_3 */
+#define WM8995_DCS_TRIG_SERIES_3_MASK           0x0800 /* DCS_TRIG_SERIES_3 */
+#define WM8995_DCS_TRIG_SERIES_3_SHIFT              11 /* DCS_TRIG_SERIES_3 */
+#define WM8995_DCS_TRIG_SERIES_3_WIDTH               1 /* DCS_TRIG_SERIES_3 */
+#define WM8995_DCS_TRIG_SERIES_2                0x0400 /* DCS_TRIG_SERIES_2 */
+#define WM8995_DCS_TRIG_SERIES_2_MASK           0x0400 /* DCS_TRIG_SERIES_2 */
+#define WM8995_DCS_TRIG_SERIES_2_SHIFT              10 /* DCS_TRIG_SERIES_2 */
+#define WM8995_DCS_TRIG_SERIES_2_WIDTH               1 /* DCS_TRIG_SERIES_2 */
+#define WM8995_DCS_TRIG_SERIES_1                0x0200 /* DCS_TRIG_SERIES_1 */
+#define WM8995_DCS_TRIG_SERIES_1_MASK           0x0200 /* DCS_TRIG_SERIES_1 */
+#define WM8995_DCS_TRIG_SERIES_1_SHIFT               9 /* DCS_TRIG_SERIES_1 */
+#define WM8995_DCS_TRIG_SERIES_1_WIDTH               1 /* DCS_TRIG_SERIES_1 */
+#define WM8995_DCS_TRIG_SERIES_0                0x0100 /* DCS_TRIG_SERIES_0 */
+#define WM8995_DCS_TRIG_SERIES_0_MASK           0x0100 /* DCS_TRIG_SERIES_0 */
+#define WM8995_DCS_TRIG_SERIES_0_SHIFT               8 /* DCS_TRIG_SERIES_0 */
+#define WM8995_DCS_TRIG_SERIES_0_WIDTH               1 /* DCS_TRIG_SERIES_0 */
+#define WM8995_DCS_TRIG_STARTUP_3               0x0080 /* DCS_TRIG_STARTUP_3 */
+#define WM8995_DCS_TRIG_STARTUP_3_MASK          0x0080 /* DCS_TRIG_STARTUP_3 */
+#define WM8995_DCS_TRIG_STARTUP_3_SHIFT              7 /* DCS_TRIG_STARTUP_3 */
+#define WM8995_DCS_TRIG_STARTUP_3_WIDTH              1 /* DCS_TRIG_STARTUP_3 */
+#define WM8995_DCS_TRIG_STARTUP_2               0x0040 /* DCS_TRIG_STARTUP_2 */
+#define WM8995_DCS_TRIG_STARTUP_2_MASK          0x0040 /* DCS_TRIG_STARTUP_2 */
+#define WM8995_DCS_TRIG_STARTUP_2_SHIFT              6 /* DCS_TRIG_STARTUP_2 */
+#define WM8995_DCS_TRIG_STARTUP_2_WIDTH              1 /* DCS_TRIG_STARTUP_2 */
+#define WM8995_DCS_TRIG_STARTUP_1               0x0020 /* DCS_TRIG_STARTUP_1 */
+#define WM8995_DCS_TRIG_STARTUP_1_MASK          0x0020 /* DCS_TRIG_STARTUP_1 */
+#define WM8995_DCS_TRIG_STARTUP_1_SHIFT              5 /* DCS_TRIG_STARTUP_1 */
+#define WM8995_DCS_TRIG_STARTUP_1_WIDTH              1 /* DCS_TRIG_STARTUP_1 */
+#define WM8995_DCS_TRIG_STARTUP_0               0x0010 /* DCS_TRIG_STARTUP_0 */
+#define WM8995_DCS_TRIG_STARTUP_0_MASK          0x0010 /* DCS_TRIG_STARTUP_0 */
+#define WM8995_DCS_TRIG_STARTUP_0_SHIFT              4 /* DCS_TRIG_STARTUP_0 */
+#define WM8995_DCS_TRIG_STARTUP_0_WIDTH              1 /* DCS_TRIG_STARTUP_0 */
+#define WM8995_DCS_TRIG_DAC_WR_3                0x0008 /* DCS_TRIG_DAC_WR_3 */
+#define WM8995_DCS_TRIG_DAC_WR_3_MASK           0x0008 /* DCS_TRIG_DAC_WR_3 */
+#define WM8995_DCS_TRIG_DAC_WR_3_SHIFT               3 /* DCS_TRIG_DAC_WR_3 */
+#define WM8995_DCS_TRIG_DAC_WR_3_WIDTH               1 /* DCS_TRIG_DAC_WR_3 */
+#define WM8995_DCS_TRIG_DAC_WR_2                0x0004 /* DCS_TRIG_DAC_WR_2 */
+#define WM8995_DCS_TRIG_DAC_WR_2_MASK           0x0004 /* DCS_TRIG_DAC_WR_2 */
+#define WM8995_DCS_TRIG_DAC_WR_2_SHIFT               2 /* DCS_TRIG_DAC_WR_2 */
+#define WM8995_DCS_TRIG_DAC_WR_2_WIDTH               1 /* DCS_TRIG_DAC_WR_2 */
+#define WM8995_DCS_TRIG_DAC_WR_1                0x0002 /* DCS_TRIG_DAC_WR_1 */
+#define WM8995_DCS_TRIG_DAC_WR_1_MASK           0x0002 /* DCS_TRIG_DAC_WR_1 */
+#define WM8995_DCS_TRIG_DAC_WR_1_SHIFT               1 /* DCS_TRIG_DAC_WR_1 */
+#define WM8995_DCS_TRIG_DAC_WR_1_WIDTH               1 /* DCS_TRIG_DAC_WR_1 */
+#define WM8995_DCS_TRIG_DAC_WR_0                0x0001 /* DCS_TRIG_DAC_WR_0 */
+#define WM8995_DCS_TRIG_DAC_WR_0_MASK           0x0001 /* DCS_TRIG_DAC_WR_0 */
+#define WM8995_DCS_TRIG_DAC_WR_0_SHIFT               0 /* DCS_TRIG_DAC_WR_0 */
+#define WM8995_DCS_TRIG_DAC_WR_0_WIDTH               1 /* DCS_TRIG_DAC_WR_0 */
+
+/*
+ * R82 (0x52) - DC Servo (3)
+ */
+#define WM8995_DCS_TIMER_PERIOD_23_MASK         0x0F00 /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8995_DCS_TIMER_PERIOD_23_SHIFT             8 /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8995_DCS_TIMER_PERIOD_23_WIDTH             4 /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8995_DCS_TIMER_PERIOD_01_MASK         0x000F /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8995_DCS_TIMER_PERIOD_01_SHIFT             0 /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8995_DCS_TIMER_PERIOD_01_WIDTH             4 /* DCS_TIMER_PERIOD_01 - [3:0] */
+
+/*
+ * R84 (0x54) - DC Servo (5)
+ */
+#define WM8995_DCS_SERIES_NO_23_MASK            0x7F00 /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8995_DCS_SERIES_NO_23_SHIFT                8 /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8995_DCS_SERIES_NO_23_WIDTH                7 /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8995_DCS_SERIES_NO_01_MASK            0x007F /* DCS_SERIES_NO_01 - [6:0] */
+#define WM8995_DCS_SERIES_NO_01_SHIFT                0 /* DCS_SERIES_NO_01 - [6:0] */
+#define WM8995_DCS_SERIES_NO_01_WIDTH                7 /* DCS_SERIES_NO_01 - [6:0] */
+
+/*
+ * R85 (0x55) - DC Servo (6)
+ */
+#define WM8995_DCS_DAC_WR_VAL_3_MASK            0xFF00 /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8995_DCS_DAC_WR_VAL_3_SHIFT                8 /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8995_DCS_DAC_WR_VAL_3_WIDTH                8 /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8995_DCS_DAC_WR_VAL_2_MASK            0x00FF /* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8995_DCS_DAC_WR_VAL_2_SHIFT                0 /* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8995_DCS_DAC_WR_VAL_2_WIDTH                8 /* DCS_DAC_WR_VAL_2 - [7:0] */
+
+/*
+ * R86 (0x56) - DC Servo (7)
+ */
+#define WM8995_DCS_DAC_WR_VAL_1_MASK            0xFF00 /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8995_DCS_DAC_WR_VAL_1_SHIFT                8 /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8995_DCS_DAC_WR_VAL_1_WIDTH                8 /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8995_DCS_DAC_WR_VAL_0_MASK            0x00FF /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8995_DCS_DAC_WR_VAL_0_SHIFT                0 /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8995_DCS_DAC_WR_VAL_0_WIDTH                8 /* DCS_DAC_WR_VAL_0 - [7:0] */
+
+/*
+ * R87 (0x57) - DC Servo Readback 0
+ */
+#define WM8995_DCS_CAL_COMPLETE_MASK            0x0F00 /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8995_DCS_CAL_COMPLETE_SHIFT                8 /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8995_DCS_CAL_COMPLETE_WIDTH                4 /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8995_DCS_DAC_WR_COMPLETE_MASK         0x00F0 /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8995_DCS_DAC_WR_COMPLETE_SHIFT             4 /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8995_DCS_DAC_WR_COMPLETE_WIDTH             4 /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8995_DCS_STARTUP_COMPLETE_MASK        0x000F /* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8995_DCS_STARTUP_COMPLETE_SHIFT            0 /* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8995_DCS_STARTUP_COMPLETE_WIDTH            4 /* DCS_STARTUP_COMPLETE - [3:0] */
+
+/*
+ * R96 (0x60) - Analogue HP (1)
+ */
+#define WM8995_HPOUT1L_RMV_SHORT                0x0080 /* HPOUT1L_RMV_SHORT */
+#define WM8995_HPOUT1L_RMV_SHORT_MASK           0x0080 /* HPOUT1L_RMV_SHORT */
+#define WM8995_HPOUT1L_RMV_SHORT_SHIFT               7 /* HPOUT1L_RMV_SHORT */
+#define WM8995_HPOUT1L_RMV_SHORT_WIDTH               1 /* HPOUT1L_RMV_SHORT */
+#define WM8995_HPOUT1L_OUTP                     0x0040 /* HPOUT1L_OUTP */
+#define WM8995_HPOUT1L_OUTP_MASK                0x0040 /* HPOUT1L_OUTP */
+#define WM8995_HPOUT1L_OUTP_SHIFT                    6 /* HPOUT1L_OUTP */
+#define WM8995_HPOUT1L_OUTP_WIDTH                    1 /* HPOUT1L_OUTP */
+#define WM8995_HPOUT1L_DLY                      0x0020 /* HPOUT1L_DLY */
+#define WM8995_HPOUT1L_DLY_MASK                 0x0020 /* HPOUT1L_DLY */
+#define WM8995_HPOUT1L_DLY_SHIFT                     5 /* HPOUT1L_DLY */
+#define WM8995_HPOUT1L_DLY_WIDTH                     1 /* HPOUT1L_DLY */
+#define WM8995_HPOUT1R_RMV_SHORT                0x0008 /* HPOUT1R_RMV_SHORT */
+#define WM8995_HPOUT1R_RMV_SHORT_MASK           0x0008 /* HPOUT1R_RMV_SHORT */
+#define WM8995_HPOUT1R_RMV_SHORT_SHIFT               3 /* HPOUT1R_RMV_SHORT */
+#define WM8995_HPOUT1R_RMV_SHORT_WIDTH               1 /* HPOUT1R_RMV_SHORT */
+#define WM8995_HPOUT1R_OUTP                     0x0004 /* HPOUT1R_OUTP */
+#define WM8995_HPOUT1R_OUTP_MASK                0x0004 /* HPOUT1R_OUTP */
+#define WM8995_HPOUT1R_OUTP_SHIFT                    2 /* HPOUT1R_OUTP */
+#define WM8995_HPOUT1R_OUTP_WIDTH                    1 /* HPOUT1R_OUTP */
+#define WM8995_HPOUT1R_DLY                      0x0002 /* HPOUT1R_DLY */
+#define WM8995_HPOUT1R_DLY_MASK                 0x0002 /* HPOUT1R_DLY */
+#define WM8995_HPOUT1R_DLY_SHIFT                     1 /* HPOUT1R_DLY */
+#define WM8995_HPOUT1R_DLY_WIDTH                     1 /* HPOUT1R_DLY */
+
+/*
+ * R97 (0x61) - Analogue HP (2)
+ */
+#define WM8995_HPOUT2L_RMV_SHORT                0x0080 /* HPOUT2L_RMV_SHORT */
+#define WM8995_HPOUT2L_RMV_SHORT_MASK           0x0080 /* HPOUT2L_RMV_SHORT */
+#define WM8995_HPOUT2L_RMV_SHORT_SHIFT               7 /* HPOUT2L_RMV_SHORT */
+#define WM8995_HPOUT2L_RMV_SHORT_WIDTH               1 /* HPOUT2L_RMV_SHORT */
+#define WM8995_HPOUT2L_OUTP                     0x0040 /* HPOUT2L_OUTP */
+#define WM8995_HPOUT2L_OUTP_MASK                0x0040 /* HPOUT2L_OUTP */
+#define WM8995_HPOUT2L_OUTP_SHIFT                    6 /* HPOUT2L_OUTP */
+#define WM8995_HPOUT2L_OUTP_WIDTH                    1 /* HPOUT2L_OUTP */
+#define WM8995_HPOUT2L_DLY                      0x0020 /* HPOUT2L_DLY */
+#define WM8995_HPOUT2L_DLY_MASK                 0x0020 /* HPOUT2L_DLY */
+#define WM8995_HPOUT2L_DLY_SHIFT                     5 /* HPOUT2L_DLY */
+#define WM8995_HPOUT2L_DLY_WIDTH                     1 /* HPOUT2L_DLY */
+#define WM8995_HPOUT2R_RMV_SHORT                0x0008 /* HPOUT2R_RMV_SHORT */
+#define WM8995_HPOUT2R_RMV_SHORT_MASK           0x0008 /* HPOUT2R_RMV_SHORT */
+#define WM8995_HPOUT2R_RMV_SHORT_SHIFT               3 /* HPOUT2R_RMV_SHORT */
+#define WM8995_HPOUT2R_RMV_SHORT_WIDTH               1 /* HPOUT2R_RMV_SHORT */
+#define WM8995_HPOUT2R_OUTP                     0x0004 /* HPOUT2R_OUTP */
+#define WM8995_HPOUT2R_OUTP_MASK                0x0004 /* HPOUT2R_OUTP */
+#define WM8995_HPOUT2R_OUTP_SHIFT                    2 /* HPOUT2R_OUTP */
+#define WM8995_HPOUT2R_OUTP_WIDTH                    1 /* HPOUT2R_OUTP */
+#define WM8995_HPOUT2R_DLY                      0x0002 /* HPOUT2R_DLY */
+#define WM8995_HPOUT2R_DLY_MASK                 0x0002 /* HPOUT2R_DLY */
+#define WM8995_HPOUT2R_DLY_SHIFT                     1 /* HPOUT2R_DLY */
+#define WM8995_HPOUT2R_DLY_WIDTH                     1 /* HPOUT2R_DLY */
+
+/*
+ * R256 (0x100) - Chip Revision
+ */
+#define WM8995_CHIP_REV_MASK                    0x000F /* CHIP_REV - [3:0] */
+#define WM8995_CHIP_REV_SHIFT                        0 /* CHIP_REV - [3:0] */
+#define WM8995_CHIP_REV_WIDTH                        4 /* CHIP_REV - [3:0] */
+
+/*
+ * R257 (0x101) - Control Interface (1)
+ */
+#define WM8995_REG_SYNC                         0x8000 /* REG_SYNC */
+#define WM8995_REG_SYNC_MASK                    0x8000 /* REG_SYNC */
+#define WM8995_REG_SYNC_SHIFT                       15 /* REG_SYNC */
+#define WM8995_REG_SYNC_WIDTH                        1 /* REG_SYNC */
+#define WM8995_SPI_CONTRD                       0x0040 /* SPI_CONTRD */
+#define WM8995_SPI_CONTRD_MASK                  0x0040 /* SPI_CONTRD */
+#define WM8995_SPI_CONTRD_SHIFT                      6 /* SPI_CONTRD */
+#define WM8995_SPI_CONTRD_WIDTH                      1 /* SPI_CONTRD */
+#define WM8995_SPI_4WIRE                        0x0020 /* SPI_4WIRE */
+#define WM8995_SPI_4WIRE_MASK                   0x0020 /* SPI_4WIRE */
+#define WM8995_SPI_4WIRE_SHIFT                       5 /* SPI_4WIRE */
+#define WM8995_SPI_4WIRE_WIDTH                       1 /* SPI_4WIRE */
+#define WM8995_SPI_CFG                          0x0010 /* SPI_CFG */
+#define WM8995_SPI_CFG_MASK                     0x0010 /* SPI_CFG */
+#define WM8995_SPI_CFG_SHIFT                         4 /* SPI_CFG */
+#define WM8995_SPI_CFG_WIDTH                         1 /* SPI_CFG */
+#define WM8995_AUTO_INC                         0x0004 /* AUTO_INC */
+#define WM8995_AUTO_INC_MASK                    0x0004 /* AUTO_INC */
+#define WM8995_AUTO_INC_SHIFT                        2 /* AUTO_INC */
+#define WM8995_AUTO_INC_WIDTH                        1 /* AUTO_INC */
+
+/*
+ * R258 (0x102) - Control Interface (2)
+ */
+#define WM8995_CTRL_IF_SRC                      0x0001 /* CTRL_IF_SRC */
+#define WM8995_CTRL_IF_SRC_MASK                 0x0001 /* CTRL_IF_SRC */
+#define WM8995_CTRL_IF_SRC_SHIFT                     0 /* CTRL_IF_SRC */
+#define WM8995_CTRL_IF_SRC_WIDTH                     1 /* CTRL_IF_SRC */
+
+/*
+ * R272 (0x110) - Write Sequencer Ctrl (1)
+ */
+#define WM8995_WSEQ_ENA                         0x8000 /* WSEQ_ENA */
+#define WM8995_WSEQ_ENA_MASK                    0x8000 /* WSEQ_ENA */
+#define WM8995_WSEQ_ENA_SHIFT                       15 /* WSEQ_ENA */
+#define WM8995_WSEQ_ENA_WIDTH                        1 /* WSEQ_ENA */
+#define WM8995_WSEQ_ABORT                       0x0200 /* WSEQ_ABORT */
+#define WM8995_WSEQ_ABORT_MASK                  0x0200 /* WSEQ_ABORT */
+#define WM8995_WSEQ_ABORT_SHIFT                      9 /* WSEQ_ABORT */
+#define WM8995_WSEQ_ABORT_WIDTH                      1 /* WSEQ_ABORT */
+#define WM8995_WSEQ_START                       0x0100 /* WSEQ_START */
+#define WM8995_WSEQ_START_MASK                  0x0100 /* WSEQ_START */
+#define WM8995_WSEQ_START_SHIFT                      8 /* WSEQ_START */
+#define WM8995_WSEQ_START_WIDTH                      1 /* WSEQ_START */
+#define WM8995_WSEQ_START_INDEX_MASK            0x007F /* WSEQ_START_INDEX - [6:0] */
+#define WM8995_WSEQ_START_INDEX_SHIFT                0 /* WSEQ_START_INDEX - [6:0] */
+#define WM8995_WSEQ_START_INDEX_WIDTH                7 /* WSEQ_START_INDEX - [6:0] */
+
+/*
+ * R273 (0x111) - Write Sequencer Ctrl (2)
+ */
+#define WM8995_WSEQ_BUSY                        0x0100 /* WSEQ_BUSY */
+#define WM8995_WSEQ_BUSY_MASK                   0x0100 /* WSEQ_BUSY */
+#define WM8995_WSEQ_BUSY_SHIFT                       8 /* WSEQ_BUSY */
+#define WM8995_WSEQ_BUSY_WIDTH                       1 /* WSEQ_BUSY */
+#define WM8995_WSEQ_CURRENT_INDEX_MASK          0x007F /* WSEQ_CURRENT_INDEX - [6:0] */
+#define WM8995_WSEQ_CURRENT_INDEX_SHIFT              0 /* WSEQ_CURRENT_INDEX - [6:0] */
+#define WM8995_WSEQ_CURRENT_INDEX_WIDTH              7 /* WSEQ_CURRENT_INDEX - [6:0] */
+
+/*
+ * R512 (0x200) - AIF1 Clocking (1)
+ */
+#define WM8995_AIF1CLK_SRC_MASK                 0x0018 /* AIF1CLK_SRC - [4:3] */
+#define WM8995_AIF1CLK_SRC_SHIFT                     3 /* AIF1CLK_SRC - [4:3] */
+#define WM8995_AIF1CLK_SRC_WIDTH                     2 /* AIF1CLK_SRC - [4:3] */
+#define WM8995_AIF1CLK_INV                      0x0004 /* AIF1CLK_INV */
+#define WM8995_AIF1CLK_INV_MASK                 0x0004 /* AIF1CLK_INV */
+#define WM8995_AIF1CLK_INV_SHIFT                     2 /* AIF1CLK_INV */
+#define WM8995_AIF1CLK_INV_WIDTH                     1 /* AIF1CLK_INV */
+#define WM8995_AIF1CLK_DIV                      0x0002 /* AIF1CLK_DIV */
+#define WM8995_AIF1CLK_DIV_MASK                 0x0002 /* AIF1CLK_DIV */
+#define WM8995_AIF1CLK_DIV_SHIFT                     1 /* AIF1CLK_DIV */
+#define WM8995_AIF1CLK_DIV_WIDTH                     1 /* AIF1CLK_DIV */
+#define WM8995_AIF1CLK_ENA                      0x0001 /* AIF1CLK_ENA */
+#define WM8995_AIF1CLK_ENA_MASK                 0x0001 /* AIF1CLK_ENA */
+#define WM8995_AIF1CLK_ENA_SHIFT                     0 /* AIF1CLK_ENA */
+#define WM8995_AIF1CLK_ENA_WIDTH                     1 /* AIF1CLK_ENA */
+
+/*
+ * R513 (0x201) - AIF1 Clocking (2)
+ */
+#define WM8995_AIF1DAC_DIV_MASK                 0x0038 /* AIF1DAC_DIV - [5:3] */
+#define WM8995_AIF1DAC_DIV_SHIFT                     3 /* AIF1DAC_DIV - [5:3] */
+#define WM8995_AIF1DAC_DIV_WIDTH                     3 /* AIF1DAC_DIV - [5:3] */
+#define WM8995_AIF1ADC_DIV_MASK                 0x0007 /* AIF1ADC_DIV - [2:0] */
+#define WM8995_AIF1ADC_DIV_SHIFT                     0 /* AIF1ADC_DIV - [2:0] */
+#define WM8995_AIF1ADC_DIV_WIDTH                     3 /* AIF1ADC_DIV - [2:0] */
+
+/*
+ * R516 (0x204) - AIF2 Clocking (1)
+ */
+#define WM8995_AIF2CLK_SRC_MASK                 0x0018 /* AIF2CLK_SRC - [4:3] */
+#define WM8995_AIF2CLK_SRC_SHIFT                     3 /* AIF2CLK_SRC - [4:3] */
+#define WM8995_AIF2CLK_SRC_WIDTH                     2 /* AIF2CLK_SRC - [4:3] */
+#define WM8995_AIF2CLK_INV                      0x0004 /* AIF2CLK_INV */
+#define WM8995_AIF2CLK_INV_MASK                 0x0004 /* AIF2CLK_INV */
+#define WM8995_AIF2CLK_INV_SHIFT                     2 /* AIF2CLK_INV */
+#define WM8995_AIF2CLK_INV_WIDTH                     1 /* AIF2CLK_INV */
+#define WM8995_AIF2CLK_DIV                      0x0002 /* AIF2CLK_DIV */
+#define WM8995_AIF2CLK_DIV_MASK                 0x0002 /* AIF2CLK_DIV */
+#define WM8995_AIF2CLK_DIV_SHIFT                     1 /* AIF2CLK_DIV */
+#define WM8995_AIF2CLK_DIV_WIDTH                     1 /* AIF2CLK_DIV */
+#define WM8995_AIF2CLK_ENA                      0x0001 /* AIF2CLK_ENA */
+#define WM8995_AIF2CLK_ENA_MASK                 0x0001 /* AIF2CLK_ENA */
+#define WM8995_AIF2CLK_ENA_SHIFT                     0 /* AIF2CLK_ENA */
+#define WM8995_AIF2CLK_ENA_WIDTH                     1 /* AIF2CLK_ENA */
+
+/*
+ * R517 (0x205) - AIF2 Clocking (2)
+ */
+#define WM8995_AIF2DAC_DIV_MASK                 0x0038 /* AIF2DAC_DIV - [5:3] */
+#define WM8995_AIF2DAC_DIV_SHIFT                     3 /* AIF2DAC_DIV - [5:3] */
+#define WM8995_AIF2DAC_DIV_WIDTH                     3 /* AIF2DAC_DIV - [5:3] */
+#define WM8995_AIF2ADC_DIV_MASK                 0x0007 /* AIF2ADC_DIV - [2:0] */
+#define WM8995_AIF2ADC_DIV_SHIFT                     0 /* AIF2ADC_DIV - [2:0] */
+#define WM8995_AIF2ADC_DIV_WIDTH                     3 /* AIF2ADC_DIV - [2:0] */
+
+/*
+ * R520 (0x208) - Clocking (1)
+ */
+#define WM8995_LFCLK_ENA                        0x0020 /* LFCLK_ENA */
+#define WM8995_LFCLK_ENA_MASK                   0x0020 /* LFCLK_ENA */
+#define WM8995_LFCLK_ENA_SHIFT                       5 /* LFCLK_ENA */
+#define WM8995_LFCLK_ENA_WIDTH                       1 /* LFCLK_ENA */
+#define WM8995_TOCLK_ENA                        0x0010 /* TOCLK_ENA */
+#define WM8995_TOCLK_ENA_MASK                   0x0010 /* TOCLK_ENA */
+#define WM8995_TOCLK_ENA_SHIFT                       4 /* TOCLK_ENA */
+#define WM8995_TOCLK_ENA_WIDTH                       1 /* TOCLK_ENA */
+#define WM8995_AIF1DSPCLK_ENA                   0x0008 /* AIF1DSPCLK_ENA */
+#define WM8995_AIF1DSPCLK_ENA_MASK              0x0008 /* AIF1DSPCLK_ENA */
+#define WM8995_AIF1DSPCLK_ENA_SHIFT                  3 /* AIF1DSPCLK_ENA */
+#define WM8995_AIF1DSPCLK_ENA_WIDTH                  1 /* AIF1DSPCLK_ENA */
+#define WM8995_AIF2DSPCLK_ENA                   0x0004 /* AIF2DSPCLK_ENA */
+#define WM8995_AIF2DSPCLK_ENA_MASK              0x0004 /* AIF2DSPCLK_ENA */
+#define WM8995_AIF2DSPCLK_ENA_SHIFT                  2 /* AIF2DSPCLK_ENA */
+#define WM8995_AIF2DSPCLK_ENA_WIDTH                  1 /* AIF2DSPCLK_ENA */
+#define WM8995_SYSDSPCLK_ENA                    0x0002 /* SYSDSPCLK_ENA */
+#define WM8995_SYSDSPCLK_ENA_MASK               0x0002 /* SYSDSPCLK_ENA */
+#define WM8995_SYSDSPCLK_ENA_SHIFT                   1 /* SYSDSPCLK_ENA */
+#define WM8995_SYSDSPCLK_ENA_WIDTH                   1 /* SYSDSPCLK_ENA */
+#define WM8995_SYSCLK_SRC                       0x0001 /* SYSCLK_SRC */
+#define WM8995_SYSCLK_SRC_MASK                  0x0001 /* SYSCLK_SRC */
+#define WM8995_SYSCLK_SRC_SHIFT                      0 /* SYSCLK_SRC */
+#define WM8995_SYSCLK_SRC_WIDTH                      1 /* SYSCLK_SRC */
+
+/*
+ * R521 (0x209) - Clocking (2)
+ */
+#define WM8995_TOCLK_DIV_MASK                   0x0700 /* TOCLK_DIV - [10:8] */
+#define WM8995_TOCLK_DIV_SHIFT                       8 /* TOCLK_DIV - [10:8] */
+#define WM8995_TOCLK_DIV_WIDTH                       3 /* TOCLK_DIV - [10:8] */
+#define WM8995_DBCLK_DIV_MASK                   0x00F0 /* DBCLK_DIV - [7:4] */
+#define WM8995_DBCLK_DIV_SHIFT                       4 /* DBCLK_DIV - [7:4] */
+#define WM8995_DBCLK_DIV_WIDTH                       4 /* DBCLK_DIV - [7:4] */
+#define WM8995_OPCLK_DIV_MASK                   0x0007 /* OPCLK_DIV - [2:0] */
+#define WM8995_OPCLK_DIV_SHIFT                       0 /* OPCLK_DIV - [2:0] */
+#define WM8995_OPCLK_DIV_WIDTH                       3 /* OPCLK_DIV - [2:0] */
+
+/*
+ * R528 (0x210) - AIF1 Rate
+ */
+#define WM8995_AIF1_SR_MASK                     0x00F0 /* AIF1_SR - [7:4] */
+#define WM8995_AIF1_SR_SHIFT                         4 /* AIF1_SR - [7:4] */
+#define WM8995_AIF1_SR_WIDTH                         4 /* AIF1_SR - [7:4] */
+#define WM8995_AIF1CLK_RATE_MASK                0x000F /* AIF1CLK_RATE - [3:0] */
+#define WM8995_AIF1CLK_RATE_SHIFT                    0 /* AIF1CLK_RATE - [3:0] */
+#define WM8995_AIF1CLK_RATE_WIDTH                    4 /* AIF1CLK_RATE - [3:0] */
+
+/*
+ * R529 (0x211) - AIF2 Rate
+ */
+#define WM8995_AIF2_SR_MASK                     0x00F0 /* AIF2_SR - [7:4] */
+#define WM8995_AIF2_SR_SHIFT                         4 /* AIF2_SR - [7:4] */
+#define WM8995_AIF2_SR_WIDTH                         4 /* AIF2_SR - [7:4] */
+#define WM8995_AIF2CLK_RATE_MASK                0x000F /* AIF2CLK_RATE - [3:0] */
+#define WM8995_AIF2CLK_RATE_SHIFT                    0 /* AIF2CLK_RATE - [3:0] */
+#define WM8995_AIF2CLK_RATE_WIDTH                    4 /* AIF2CLK_RATE - [3:0] */
+
+/*
+ * R530 (0x212) - Rate Status
+ */
+#define WM8995_SR_ERROR_MASK                    0x000F /* SR_ERROR - [3:0] */
+#define WM8995_SR_ERROR_SHIFT                        0 /* SR_ERROR - [3:0] */
+#define WM8995_SR_ERROR_WIDTH                        4 /* SR_ERROR - [3:0] */
+
+/*
+ * R544 (0x220) - FLL1 Control (1)
+ */
+#define WM8995_FLL1_OSC_ENA                     0x0002 /* FLL1_OSC_ENA */
+#define WM8995_FLL1_OSC_ENA_MASK                0x0002 /* FLL1_OSC_ENA */
+#define WM8995_FLL1_OSC_ENA_SHIFT                    1 /* FLL1_OSC_ENA */
+#define WM8995_FLL1_OSC_ENA_WIDTH                    1 /* FLL1_OSC_ENA */
+#define WM8995_FLL1_ENA                         0x0001 /* FLL1_ENA */
+#define WM8995_FLL1_ENA_MASK                    0x0001 /* FLL1_ENA */
+#define WM8995_FLL1_ENA_SHIFT                        0 /* FLL1_ENA */
+#define WM8995_FLL1_ENA_WIDTH                        1 /* FLL1_ENA */
+
+/*
+ * R545 (0x221) - FLL1 Control (2)
+ */
+#define WM8995_FLL1_OUTDIV_MASK                 0x3F00 /* FLL1_OUTDIV - [13:8] */
+#define WM8995_FLL1_OUTDIV_SHIFT                     8 /* FLL1_OUTDIV - [13:8] */
+#define WM8995_FLL1_OUTDIV_WIDTH                     6 /* FLL1_OUTDIV - [13:8] */
+#define WM8995_FLL1_CTRL_RATE_MASK              0x0070 /* FLL1_CTRL_RATE - [6:4] */
+#define WM8995_FLL1_CTRL_RATE_SHIFT                  4 /* FLL1_CTRL_RATE - [6:4] */
+#define WM8995_FLL1_CTRL_RATE_WIDTH                  3 /* FLL1_CTRL_RATE - [6:4] */
+#define WM8995_FLL1_FRATIO_MASK                 0x0007 /* FLL1_FRATIO - [2:0] */
+#define WM8995_FLL1_FRATIO_SHIFT                     0 /* FLL1_FRATIO - [2:0] */
+#define WM8995_FLL1_FRATIO_WIDTH                     3 /* FLL1_FRATIO - [2:0] */
+
+/*
+ * R546 (0x222) - FLL1 Control (3)
+ */
+#define WM8995_FLL1_K_MASK                      0xFFFF /* FLL1_K - [15:0] */
+#define WM8995_FLL1_K_SHIFT                          0 /* FLL1_K - [15:0] */
+#define WM8995_FLL1_K_WIDTH                         16 /* FLL1_K - [15:0] */
+
+/*
+ * R547 (0x223) - FLL1 Control (4)
+ */
+#define WM8995_FLL1_N_MASK                      0x7FE0 /* FLL1_N - [14:5] */
+#define WM8995_FLL1_N_SHIFT                          5 /* FLL1_N - [14:5] */
+#define WM8995_FLL1_N_WIDTH                         10 /* FLL1_N - [14:5] */
+#define WM8995_FLL1_LOOP_GAIN_MASK              0x000F /* FLL1_LOOP_GAIN - [3:0] */
+#define WM8995_FLL1_LOOP_GAIN_SHIFT                  0 /* FLL1_LOOP_GAIN - [3:0] */
+#define WM8995_FLL1_LOOP_GAIN_WIDTH                  4 /* FLL1_LOOP_GAIN - [3:0] */
+
+/*
+ * R548 (0x224) - FLL1 Control (5)
+ */
+#define WM8995_FLL1_FRC_NCO_VAL_MASK            0x1F80 /* FLL1_FRC_NCO_VAL - [12:7] */
+#define WM8995_FLL1_FRC_NCO_VAL_SHIFT                7 /* FLL1_FRC_NCO_VAL - [12:7] */
+#define WM8995_FLL1_FRC_NCO_VAL_WIDTH                6 /* FLL1_FRC_NCO_VAL - [12:7] */
+#define WM8995_FLL1_FRC_NCO                     0x0040 /* FLL1_FRC_NCO */
+#define WM8995_FLL1_FRC_NCO_MASK                0x0040 /* FLL1_FRC_NCO */
+#define WM8995_FLL1_FRC_NCO_SHIFT                    6 /* FLL1_FRC_NCO */
+#define WM8995_FLL1_FRC_NCO_WIDTH                    1 /* FLL1_FRC_NCO */
+#define WM8995_FLL1_REFCLK_DIV_MASK             0x0018 /* FLL1_REFCLK_DIV - [4:3] */
+#define WM8995_FLL1_REFCLK_DIV_SHIFT                 3 /* FLL1_REFCLK_DIV - [4:3] */
+#define WM8995_FLL1_REFCLK_DIV_WIDTH                 2 /* FLL1_REFCLK_DIV - [4:3] */
+#define WM8995_FLL1_REFCLK_SRC_MASK             0x0003 /* FLL1_REFCLK_SRC - [1:0] */
+#define WM8995_FLL1_REFCLK_SRC_SHIFT                 0 /* FLL1_REFCLK_SRC - [1:0] */
+#define WM8995_FLL1_REFCLK_SRC_WIDTH                 2 /* FLL1_REFCLK_SRC - [1:0] */
+
+/*
+ * R576 (0x240) - FLL2 Control (1)
+ */
+#define WM8995_FLL2_OSC_ENA                     0x0002 /* FLL2_OSC_ENA */
+#define WM8995_FLL2_OSC_ENA_MASK                0x0002 /* FLL2_OSC_ENA */
+#define WM8995_FLL2_OSC_ENA_SHIFT                    1 /* FLL2_OSC_ENA */
+#define WM8995_FLL2_OSC_ENA_WIDTH                    1 /* FLL2_OSC_ENA */
+#define WM8995_FLL2_ENA                         0x0001 /* FLL2_ENA */
+#define WM8995_FLL2_ENA_MASK                    0x0001 /* FLL2_ENA */
+#define WM8995_FLL2_ENA_SHIFT                        0 /* FLL2_ENA */
+#define WM8995_FLL2_ENA_WIDTH                        1 /* FLL2_ENA */
+
+/*
+ * R577 (0x241) - FLL2 Control (2)
+ */
+#define WM8995_FLL2_OUTDIV_MASK                 0x3F00 /* FLL2_OUTDIV - [13:8] */
+#define WM8995_FLL2_OUTDIV_SHIFT                     8 /* FLL2_OUTDIV - [13:8] */
+#define WM8995_FLL2_OUTDIV_WIDTH                     6 /* FLL2_OUTDIV - [13:8] */
+#define WM8995_FLL2_CTRL_RATE_MASK              0x0070 /* FLL2_CTRL_RATE - [6:4] */
+#define WM8995_FLL2_CTRL_RATE_SHIFT                  4 /* FLL2_CTRL_RATE - [6:4] */
+#define WM8995_FLL2_CTRL_RATE_WIDTH                  3 /* FLL2_CTRL_RATE - [6:4] */
+#define WM8995_FLL2_FRATIO_MASK                 0x0007 /* FLL2_FRATIO - [2:0] */
+#define WM8995_FLL2_FRATIO_SHIFT                     0 /* FLL2_FRATIO - [2:0] */
+#define WM8995_FLL2_FRATIO_WIDTH                     3 /* FLL2_FRATIO - [2:0] */
+
+/*
+ * R578 (0x242) - FLL2 Control (3)
+ */
+#define WM8995_FLL2_K_MASK                      0xFFFF /* FLL2_K - [15:0] */
+#define WM8995_FLL2_K_SHIFT                          0 /* FLL2_K - [15:0] */
+#define WM8995_FLL2_K_WIDTH                         16 /* FLL2_K - [15:0] */
+
+/*
+ * R579 (0x243) - FLL2 Control (4)
+ */
+#define WM8995_FLL2_N_MASK                      0x7FE0 /* FLL2_N - [14:5] */
+#define WM8995_FLL2_N_SHIFT                          5 /* FLL2_N - [14:5] */
+#define WM8995_FLL2_N_WIDTH                         10 /* FLL2_N - [14:5] */
+#define WM8995_FLL2_LOOP_GAIN_MASK              0x000F /* FLL2_LOOP_GAIN - [3:0] */
+#define WM8995_FLL2_LOOP_GAIN_SHIFT                  0 /* FLL2_LOOP_GAIN - [3:0] */
+#define WM8995_FLL2_LOOP_GAIN_WIDTH                  4 /* FLL2_LOOP_GAIN - [3:0] */
+
+/*
+ * R580 (0x244) - FLL2 Control (5)
+ */
+#define WM8995_FLL2_FRC_NCO_VAL_MASK            0x1F80 /* FLL2_FRC_NCO_VAL - [12:7] */
+#define WM8995_FLL2_FRC_NCO_VAL_SHIFT                7 /* FLL2_FRC_NCO_VAL - [12:7] */
+#define WM8995_FLL2_FRC_NCO_VAL_WIDTH                6 /* FLL2_FRC_NCO_VAL - [12:7] */
+#define WM8995_FLL2_FRC_NCO                     0x0040 /* FLL2_FRC_NCO */
+#define WM8995_FLL2_FRC_NCO_MASK                0x0040 /* FLL2_FRC_NCO */
+#define WM8995_FLL2_FRC_NCO_SHIFT                    6 /* FLL2_FRC_NCO */
+#define WM8995_FLL2_FRC_NCO_WIDTH                    1 /* FLL2_FRC_NCO */
+#define WM8995_FLL2_REFCLK_DIV_MASK             0x0018 /* FLL2_REFCLK_DIV - [4:3] */
+#define WM8995_FLL2_REFCLK_DIV_SHIFT                 3 /* FLL2_REFCLK_DIV - [4:3] */
+#define WM8995_FLL2_REFCLK_DIV_WIDTH                 2 /* FLL2_REFCLK_DIV - [4:3] */
+#define WM8995_FLL2_REFCLK_SRC_MASK             0x0003 /* FLL2_REFCLK_SRC - [1:0] */
+#define WM8995_FLL2_REFCLK_SRC_SHIFT                 0 /* FLL2_REFCLK_SRC - [1:0] */
+#define WM8995_FLL2_REFCLK_SRC_WIDTH                 2 /* FLL2_REFCLK_SRC - [1:0] */
+
+/*
+ * R768 (0x300) - AIF1 Control (1)
+ */
+#define WM8995_AIF1ADCL_SRC                     0x8000 /* AIF1ADCL_SRC */
+#define WM8995_AIF1ADCL_SRC_MASK                0x8000 /* AIF1ADCL_SRC */
+#define WM8995_AIF1ADCL_SRC_SHIFT                   15 /* AIF1ADCL_SRC */
+#define WM8995_AIF1ADCL_SRC_WIDTH                    1 /* AIF1ADCL_SRC */
+#define WM8995_AIF1ADCR_SRC                     0x4000 /* AIF1ADCR_SRC */
+#define WM8995_AIF1ADCR_SRC_MASK                0x4000 /* AIF1ADCR_SRC */
+#define WM8995_AIF1ADCR_SRC_SHIFT                   14 /* AIF1ADCR_SRC */
+#define WM8995_AIF1ADCR_SRC_WIDTH                    1 /* AIF1ADCR_SRC */
+#define WM8995_AIF1ADC_TDM                      0x2000 /* AIF1ADC_TDM */
+#define WM8995_AIF1ADC_TDM_MASK                 0x2000 /* AIF1ADC_TDM */
+#define WM8995_AIF1ADC_TDM_SHIFT                    13 /* AIF1ADC_TDM */
+#define WM8995_AIF1ADC_TDM_WIDTH                     1 /* AIF1ADC_TDM */
+#define WM8995_AIF1_BCLK_INV                    0x0100 /* AIF1_BCLK_INV */
+#define WM8995_AIF1_BCLK_INV_MASK               0x0100 /* AIF1_BCLK_INV */
+#define WM8995_AIF1_BCLK_INV_SHIFT                   8 /* AIF1_BCLK_INV */
+#define WM8995_AIF1_BCLK_INV_WIDTH                   1 /* AIF1_BCLK_INV */
+#define WM8995_AIF1_LRCLK_INV                   0x0080 /* AIF1_LRCLK_INV */
+#define WM8995_AIF1_LRCLK_INV_MASK              0x0080 /* AIF1_LRCLK_INV */
+#define WM8995_AIF1_LRCLK_INV_SHIFT                  7 /* AIF1_LRCLK_INV */
+#define WM8995_AIF1_LRCLK_INV_WIDTH                  1 /* AIF1_LRCLK_INV */
+#define WM8995_AIF1_WL_MASK                     0x0060 /* AIF1_WL - [6:5] */
+#define WM8995_AIF1_WL_SHIFT                         5 /* AIF1_WL - [6:5] */
+#define WM8995_AIF1_WL_WIDTH                         2 /* AIF1_WL - [6:5] */
+#define WM8995_AIF1_FMT_MASK                    0x0018 /* AIF1_FMT - [4:3] */
+#define WM8995_AIF1_FMT_SHIFT                        3 /* AIF1_FMT - [4:3] */
+#define WM8995_AIF1_FMT_WIDTH                        2 /* AIF1_FMT - [4:3] */
+
+/*
+ * R769 (0x301) - AIF1 Control (2)
+ */
+#define WM8995_AIF1DACL_SRC                     0x8000 /* AIF1DACL_SRC */
+#define WM8995_AIF1DACL_SRC_MASK                0x8000 /* AIF1DACL_SRC */
+#define WM8995_AIF1DACL_SRC_SHIFT                   15 /* AIF1DACL_SRC */
+#define WM8995_AIF1DACL_SRC_WIDTH                    1 /* AIF1DACL_SRC */
+#define WM8995_AIF1DACR_SRC                     0x4000 /* AIF1DACR_SRC */
+#define WM8995_AIF1DACR_SRC_MASK                0x4000 /* AIF1DACR_SRC */
+#define WM8995_AIF1DACR_SRC_SHIFT                   14 /* AIF1DACR_SRC */
+#define WM8995_AIF1DACR_SRC_WIDTH                    1 /* AIF1DACR_SRC */
+#define WM8995_AIF1DAC_BOOST_MASK               0x0C00 /* AIF1DAC_BOOST - [11:10] */
+#define WM8995_AIF1DAC_BOOST_SHIFT                  10 /* AIF1DAC_BOOST - [11:10] */
+#define WM8995_AIF1DAC_BOOST_WIDTH                   2 /* AIF1DAC_BOOST - [11:10] */
+#define WM8995_AIF1DAC_COMP                     0x0010 /* AIF1DAC_COMP */
+#define WM8995_AIF1DAC_COMP_MASK                0x0010 /* AIF1DAC_COMP */
+#define WM8995_AIF1DAC_COMP_SHIFT                    4 /* AIF1DAC_COMP */
+#define WM8995_AIF1DAC_COMP_WIDTH                    1 /* AIF1DAC_COMP */
+#define WM8995_AIF1DAC_COMPMODE                 0x0008 /* AIF1DAC_COMPMODE */
+#define WM8995_AIF1DAC_COMPMODE_MASK            0x0008 /* AIF1DAC_COMPMODE */
+#define WM8995_AIF1DAC_COMPMODE_SHIFT                3 /* AIF1DAC_COMPMODE */
+#define WM8995_AIF1DAC_COMPMODE_WIDTH                1 /* AIF1DAC_COMPMODE */
+#define WM8995_AIF1ADC_COMP                     0x0004 /* AIF1ADC_COMP */
+#define WM8995_AIF1ADC_COMP_MASK                0x0004 /* AIF1ADC_COMP */
+#define WM8995_AIF1ADC_COMP_SHIFT                    2 /* AIF1ADC_COMP */
+#define WM8995_AIF1ADC_COMP_WIDTH                    1 /* AIF1ADC_COMP */
+#define WM8995_AIF1ADC_COMPMODE                 0x0002 /* AIF1ADC_COMPMODE */
+#define WM8995_AIF1ADC_COMPMODE_MASK            0x0002 /* AIF1ADC_COMPMODE */
+#define WM8995_AIF1ADC_COMPMODE_SHIFT                1 /* AIF1ADC_COMPMODE */
+#define WM8995_AIF1ADC_COMPMODE_WIDTH                1 /* AIF1ADC_COMPMODE */
+#define WM8995_AIF1_LOOPBACK                    0x0001 /* AIF1_LOOPBACK */
+#define WM8995_AIF1_LOOPBACK_MASK               0x0001 /* AIF1_LOOPBACK */
+#define WM8995_AIF1_LOOPBACK_SHIFT                   0 /* AIF1_LOOPBACK */
+#define WM8995_AIF1_LOOPBACK_WIDTH                   1 /* AIF1_LOOPBACK */
+
+/*
+ * R770 (0x302) - AIF1 Master/Slave
+ */
+#define WM8995_AIF1_TRI                         0x8000 /* AIF1_TRI */
+#define WM8995_AIF1_TRI_MASK                    0x8000 /* AIF1_TRI */
+#define WM8995_AIF1_TRI_SHIFT                       15 /* AIF1_TRI */
+#define WM8995_AIF1_TRI_WIDTH                        1 /* AIF1_TRI */
+#define WM8995_AIF1_MSTR                        0x4000 /* AIF1_MSTR */
+#define WM8995_AIF1_MSTR_MASK                   0x4000 /* AIF1_MSTR */
+#define WM8995_AIF1_MSTR_SHIFT                      14 /* AIF1_MSTR */
+#define WM8995_AIF1_MSTR_WIDTH                       1 /* AIF1_MSTR */
+#define WM8995_AIF1_CLK_FRC                     0x2000 /* AIF1_CLK_FRC */
+#define WM8995_AIF1_CLK_FRC_MASK                0x2000 /* AIF1_CLK_FRC */
+#define WM8995_AIF1_CLK_FRC_SHIFT                   13 /* AIF1_CLK_FRC */
+#define WM8995_AIF1_CLK_FRC_WIDTH                    1 /* AIF1_CLK_FRC */
+#define WM8995_AIF1_LRCLK_FRC                   0x1000 /* AIF1_LRCLK_FRC */
+#define WM8995_AIF1_LRCLK_FRC_MASK              0x1000 /* AIF1_LRCLK_FRC */
+#define WM8995_AIF1_LRCLK_FRC_SHIFT                 12 /* AIF1_LRCLK_FRC */
+#define WM8995_AIF1_LRCLK_FRC_WIDTH                  1 /* AIF1_LRCLK_FRC */
+
+/*
+ * R771 (0x303) - AIF1 BCLK
+ */
+#define WM8995_AIF1_BCLK_DIV_MASK               0x00F0 /* AIF1_BCLK_DIV - [7:4] */
+#define WM8995_AIF1_BCLK_DIV_SHIFT                   4 /* AIF1_BCLK_DIV - [7:4] */
+#define WM8995_AIF1_BCLK_DIV_WIDTH                   4 /* AIF1_BCLK_DIV - [7:4] */
+
+/*
+ * R772 (0x304) - AIF1ADC LRCLK
+ */
+#define WM8995_AIF1ADC_LRCLK_DIR                0x0800 /* AIF1ADC_LRCLK_DIR */
+#define WM8995_AIF1ADC_LRCLK_DIR_MASK           0x0800 /* AIF1ADC_LRCLK_DIR */
+#define WM8995_AIF1ADC_LRCLK_DIR_SHIFT              11 /* AIF1ADC_LRCLK_DIR */
+#define WM8995_AIF1ADC_LRCLK_DIR_WIDTH               1 /* AIF1ADC_LRCLK_DIR */
+#define WM8995_AIF1ADC_RATE_MASK                0x07FF /* AIF1ADC_RATE - [10:0] */
+#define WM8995_AIF1ADC_RATE_SHIFT                    0 /* AIF1ADC_RATE - [10:0] */
+#define WM8995_AIF1ADC_RATE_WIDTH                   11 /* AIF1ADC_RATE - [10:0] */
+
+/*
+ * R773 (0x305) - AIF1DAC LRCLK
+ */
+#define WM8995_AIF1DAC_LRCLK_DIR                0x0800 /* AIF1DAC_LRCLK_DIR */
+#define WM8995_AIF1DAC_LRCLK_DIR_MASK           0x0800 /* AIF1DAC_LRCLK_DIR */
+#define WM8995_AIF1DAC_LRCLK_DIR_SHIFT              11 /* AIF1DAC_LRCLK_DIR */
+#define WM8995_AIF1DAC_LRCLK_DIR_WIDTH               1 /* AIF1DAC_LRCLK_DIR */
+#define WM8995_AIF1DAC_RATE_MASK                0x07FF /* AIF1DAC_RATE - [10:0] */
+#define WM8995_AIF1DAC_RATE_SHIFT                    0 /* AIF1DAC_RATE - [10:0] */
+#define WM8995_AIF1DAC_RATE_WIDTH                   11 /* AIF1DAC_RATE - [10:0] */
+
+/*
+ * R774 (0x306) - AIF1DAC Data
+ */
+#define WM8995_AIF1DACL_DAT_INV                 0x0002 /* AIF1DACL_DAT_INV */
+#define WM8995_AIF1DACL_DAT_INV_MASK            0x0002 /* AIF1DACL_DAT_INV */
+#define WM8995_AIF1DACL_DAT_INV_SHIFT                1 /* AIF1DACL_DAT_INV */
+#define WM8995_AIF1DACL_DAT_INV_WIDTH                1 /* AIF1DACL_DAT_INV */
+#define WM8995_AIF1DACR_DAT_INV                 0x0001 /* AIF1DACR_DAT_INV */
+#define WM8995_AIF1DACR_DAT_INV_MASK            0x0001 /* AIF1DACR_DAT_INV */
+#define WM8995_AIF1DACR_DAT_INV_SHIFT                0 /* AIF1DACR_DAT_INV */
+#define WM8995_AIF1DACR_DAT_INV_WIDTH                1 /* AIF1DACR_DAT_INV */
+
+/*
+ * R775 (0x307) - AIF1ADC Data
+ */
+#define WM8995_AIF1ADCL_DAT_INV                 0x0002 /* AIF1ADCL_DAT_INV */
+#define WM8995_AIF1ADCL_DAT_INV_MASK            0x0002 /* AIF1ADCL_DAT_INV */
+#define WM8995_AIF1ADCL_DAT_INV_SHIFT                1 /* AIF1ADCL_DAT_INV */
+#define WM8995_AIF1ADCL_DAT_INV_WIDTH                1 /* AIF1ADCL_DAT_INV */
+#define WM8995_AIF1ADCR_DAT_INV                 0x0001 /* AIF1ADCR_DAT_INV */
+#define WM8995_AIF1ADCR_DAT_INV_MASK            0x0001 /* AIF1ADCR_DAT_INV */
+#define WM8995_AIF1ADCR_DAT_INV_SHIFT                0 /* AIF1ADCR_DAT_INV */
+#define WM8995_AIF1ADCR_DAT_INV_WIDTH                1 /* AIF1ADCR_DAT_INV */
+
+/*
+ * R784 (0x310) - AIF2 Control (1)
+ */
+#define WM8995_AIF2ADCL_SRC                     0x8000 /* AIF2ADCL_SRC */
+#define WM8995_AIF2ADCL_SRC_MASK                0x8000 /* AIF2ADCL_SRC */
+#define WM8995_AIF2ADCL_SRC_SHIFT                   15 /* AIF2ADCL_SRC */
+#define WM8995_AIF2ADCL_SRC_WIDTH                    1 /* AIF2ADCL_SRC */
+#define WM8995_AIF2ADCR_SRC                     0x4000 /* AIF2ADCR_SRC */
+#define WM8995_AIF2ADCR_SRC_MASK                0x4000 /* AIF2ADCR_SRC */
+#define WM8995_AIF2ADCR_SRC_SHIFT                   14 /* AIF2ADCR_SRC */
+#define WM8995_AIF2ADCR_SRC_WIDTH                    1 /* AIF2ADCR_SRC */
+#define WM8995_AIF2ADC_TDM                      0x2000 /* AIF2ADC_TDM */
+#define WM8995_AIF2ADC_TDM_MASK                 0x2000 /* AIF2ADC_TDM */
+#define WM8995_AIF2ADC_TDM_SHIFT                    13 /* AIF2ADC_TDM */
+#define WM8995_AIF2ADC_TDM_WIDTH                     1 /* AIF2ADC_TDM */
+#define WM8995_AIF2ADC_TDM_CHAN                 0x1000 /* AIF2ADC_TDM_CHAN */
+#define WM8995_AIF2ADC_TDM_CHAN_MASK            0x1000 /* AIF2ADC_TDM_CHAN */
+#define WM8995_AIF2ADC_TDM_CHAN_SHIFT               12 /* AIF2ADC_TDM_CHAN */
+#define WM8995_AIF2ADC_TDM_CHAN_WIDTH                1 /* AIF2ADC_TDM_CHAN */
+#define WM8995_AIF2_BCLK_INV                    0x0100 /* AIF2_BCLK_INV */
+#define WM8995_AIF2_BCLK_INV_MASK               0x0100 /* AIF2_BCLK_INV */
+#define WM8995_AIF2_BCLK_INV_SHIFT                   8 /* AIF2_BCLK_INV */
+#define WM8995_AIF2_BCLK_INV_WIDTH                   1 /* AIF2_BCLK_INV */
+#define WM8995_AIF2_LRCLK_INV                   0x0080 /* AIF2_LRCLK_INV */
+#define WM8995_AIF2_LRCLK_INV_MASK              0x0080 /* AIF2_LRCLK_INV */
+#define WM8995_AIF2_LRCLK_INV_SHIFT                  7 /* AIF2_LRCLK_INV */
+#define WM8995_AIF2_LRCLK_INV_WIDTH                  1 /* AIF2_LRCLK_INV */
+#define WM8995_AIF2_WL_MASK                     0x0060 /* AIF2_WL - [6:5] */
+#define WM8995_AIF2_WL_SHIFT                         5 /* AIF2_WL - [6:5] */
+#define WM8995_AIF2_WL_WIDTH                         2 /* AIF2_WL - [6:5] */
+#define WM8995_AIF2_FMT_MASK                    0x0018 /* AIF2_FMT - [4:3] */
+#define WM8995_AIF2_FMT_SHIFT                        3 /* AIF2_FMT - [4:3] */
+#define WM8995_AIF2_FMT_WIDTH                        2 /* AIF2_FMT - [4:3] */
+
+/*
+ * R785 (0x311) - AIF2 Control (2)
+ */
+#define WM8995_AIF2DACL_SRC                     0x8000 /* AIF2DACL_SRC */
+#define WM8995_AIF2DACL_SRC_MASK                0x8000 /* AIF2DACL_SRC */
+#define WM8995_AIF2DACL_SRC_SHIFT                   15 /* AIF2DACL_SRC */
+#define WM8995_AIF2DACL_SRC_WIDTH                    1 /* AIF2DACL_SRC */
+#define WM8995_AIF2DACR_SRC                     0x4000 /* AIF2DACR_SRC */
+#define WM8995_AIF2DACR_SRC_MASK                0x4000 /* AIF2DACR_SRC */
+#define WM8995_AIF2DACR_SRC_SHIFT                   14 /* AIF2DACR_SRC */
+#define WM8995_AIF2DACR_SRC_WIDTH                    1 /* AIF2DACR_SRC */
+#define WM8995_AIF2DAC_TDM                      0x2000 /* AIF2DAC_TDM */
+#define WM8995_AIF2DAC_TDM_MASK                 0x2000 /* AIF2DAC_TDM */
+#define WM8995_AIF2DAC_TDM_SHIFT                    13 /* AIF2DAC_TDM */
+#define WM8995_AIF2DAC_TDM_WIDTH                     1 /* AIF2DAC_TDM */
+#define WM8995_AIF2DAC_TDM_CHAN                 0x1000 /* AIF2DAC_TDM_CHAN */
+#define WM8995_AIF2DAC_TDM_CHAN_MASK            0x1000 /* AIF2DAC_TDM_CHAN */
+#define WM8995_AIF2DAC_TDM_CHAN_SHIFT               12 /* AIF2DAC_TDM_CHAN */
+#define WM8995_AIF2DAC_TDM_CHAN_WIDTH                1 /* AIF2DAC_TDM_CHAN */
+#define WM8995_AIF2DAC_BOOST_MASK               0x0C00 /* AIF2DAC_BOOST - [11:10] */
+#define WM8995_AIF2DAC_BOOST_SHIFT                  10 /* AIF2DAC_BOOST - [11:10] */
+#define WM8995_AIF2DAC_BOOST_WIDTH                   2 /* AIF2DAC_BOOST - [11:10] */
+#define WM8995_AIF2DAC_COMP                     0x0010 /* AIF2DAC_COMP */
+#define WM8995_AIF2DAC_COMP_MASK                0x0010 /* AIF2DAC_COMP */
+#define WM8995_AIF2DAC_COMP_SHIFT                    4 /* AIF2DAC_COMP */
+#define WM8995_AIF2DAC_COMP_WIDTH                    1 /* AIF2DAC_COMP */
+#define WM8995_AIF2DAC_COMPMODE                 0x0008 /* AIF2DAC_COMPMODE */
+#define WM8995_AIF2DAC_COMPMODE_MASK            0x0008 /* AIF2DAC_COMPMODE */
+#define WM8995_AIF2DAC_COMPMODE_SHIFT                3 /* AIF2DAC_COMPMODE */
+#define WM8995_AIF2DAC_COMPMODE_WIDTH                1 /* AIF2DAC_COMPMODE */
+#define WM8995_AIF2ADC_COMP                     0x0004 /* AIF2ADC_COMP */
+#define WM8995_AIF2ADC_COMP_MASK                0x0004 /* AIF2ADC_COMP */
+#define WM8995_AIF2ADC_COMP_SHIFT                    2 /* AIF2ADC_COMP */
+#define WM8995_AIF2ADC_COMP_WIDTH                    1 /* AIF2ADC_COMP */
+#define WM8995_AIF2ADC_COMPMODE                 0x0002 /* AIF2ADC_COMPMODE */
+#define WM8995_AIF2ADC_COMPMODE_MASK            0x0002 /* AIF2ADC_COMPMODE */
+#define WM8995_AIF2ADC_COMPMODE_SHIFT                1 /* AIF2ADC_COMPMODE */
+#define WM8995_AIF2ADC_COMPMODE_WIDTH                1 /* AIF2ADC_COMPMODE */
+#define WM8995_AIF2_LOOPBACK                    0x0001 /* AIF2_LOOPBACK */
+#define WM8995_AIF2_LOOPBACK_MASK               0x0001 /* AIF2_LOOPBACK */
+#define WM8995_AIF2_LOOPBACK_SHIFT                   0 /* AIF2_LOOPBACK */
+#define WM8995_AIF2_LOOPBACK_WIDTH                   1 /* AIF2_LOOPBACK */
+
+/*
+ * R786 (0x312) - AIF2 Master/Slave
+ */
+#define WM8995_AIF2_TRI                         0x8000 /* AIF2_TRI */
+#define WM8995_AIF2_TRI_MASK                    0x8000 /* AIF2_TRI */
+#define WM8995_AIF2_TRI_SHIFT                       15 /* AIF2_TRI */
+#define WM8995_AIF2_TRI_WIDTH                        1 /* AIF2_TRI */
+#define WM8995_AIF2_MSTR                        0x4000 /* AIF2_MSTR */
+#define WM8995_AIF2_MSTR_MASK                   0x4000 /* AIF2_MSTR */
+#define WM8995_AIF2_MSTR_SHIFT                      14 /* AIF2_MSTR */
+#define WM8995_AIF2_MSTR_WIDTH                       1 /* AIF2_MSTR */
+#define WM8995_AIF2_CLK_FRC                     0x2000 /* AIF2_CLK_FRC */
+#define WM8995_AIF2_CLK_FRC_MASK                0x2000 /* AIF2_CLK_FRC */
+#define WM8995_AIF2_CLK_FRC_SHIFT                   13 /* AIF2_CLK_FRC */
+#define WM8995_AIF2_CLK_FRC_WIDTH                    1 /* AIF2_CLK_FRC */
+#define WM8995_AIF2_LRCLK_FRC                   0x1000 /* AIF2_LRCLK_FRC */
+#define WM8995_AIF2_LRCLK_FRC_MASK              0x1000 /* AIF2_LRCLK_FRC */
+#define WM8995_AIF2_LRCLK_FRC_SHIFT                 12 /* AIF2_LRCLK_FRC */
+#define WM8995_AIF2_LRCLK_FRC_WIDTH                  1 /* AIF2_LRCLK_FRC */
+
+/*
+ * R787 (0x313) - AIF2 BCLK
+ */
+#define WM8995_AIF2_BCLK_DIV_MASK               0x00F0 /* AIF2_BCLK_DIV - [7:4] */
+#define WM8995_AIF2_BCLK_DIV_SHIFT                   4 /* AIF2_BCLK_DIV - [7:4] */
+#define WM8995_AIF2_BCLK_DIV_WIDTH                   4 /* AIF2_BCLK_DIV - [7:4] */
+
+/*
+ * R788 (0x314) - AIF2ADC LRCLK
+ */
+#define WM8995_AIF2ADC_LRCLK_DIR                0x0800 /* AIF2ADC_LRCLK_DIR */
+#define WM8995_AIF2ADC_LRCLK_DIR_MASK           0x0800 /* AIF2ADC_LRCLK_DIR */
+#define WM8995_AIF2ADC_LRCLK_DIR_SHIFT              11 /* AIF2ADC_LRCLK_DIR */
+#define WM8995_AIF2ADC_LRCLK_DIR_WIDTH               1 /* AIF2ADC_LRCLK_DIR */
+#define WM8995_AIF2ADC_RATE_MASK                0x07FF /* AIF2ADC_RATE - [10:0] */
+#define WM8995_AIF2ADC_RATE_SHIFT                    0 /* AIF2ADC_RATE - [10:0] */
+#define WM8995_AIF2ADC_RATE_WIDTH                   11 /* AIF2ADC_RATE - [10:0] */
+
+/*
+ * R789 (0x315) - AIF2DAC LRCLK
+ */
+#define WM8995_AIF2DAC_LRCLK_DIR                0x0800 /* AIF2DAC_LRCLK_DIR */
+#define WM8995_AIF2DAC_LRCLK_DIR_MASK           0x0800 /* AIF2DAC_LRCLK_DIR */
+#define WM8995_AIF2DAC_LRCLK_DIR_SHIFT              11 /* AIF2DAC_LRCLK_DIR */
+#define WM8995_AIF2DAC_LRCLK_DIR_WIDTH               1 /* AIF2DAC_LRCLK_DIR */
+#define WM8995_AIF2DAC_RATE_MASK                0x07FF /* AIF2DAC_RATE - [10:0] */
+#define WM8995_AIF2DAC_RATE_SHIFT                    0 /* AIF2DAC_RATE - [10:0] */
+#define WM8995_AIF2DAC_RATE_WIDTH                   11 /* AIF2DAC_RATE - [10:0] */
+
+/*
+ * R790 (0x316) - AIF2DAC Data
+ */
+#define WM8995_AIF2DACL_DAT_INV                 0x0002 /* AIF2DACL_DAT_INV */
+#define WM8995_AIF2DACL_DAT_INV_MASK            0x0002 /* AIF2DACL_DAT_INV */
+#define WM8995_AIF2DACL_DAT_INV_SHIFT                1 /* AIF2DACL_DAT_INV */
+#define WM8995_AIF2DACL_DAT_INV_WIDTH                1 /* AIF2DACL_DAT_INV */
+#define WM8995_AIF2DACR_DAT_INV                 0x0001 /* AIF2DACR_DAT_INV */
+#define WM8995_AIF2DACR_DAT_INV_MASK            0x0001 /* AIF2DACR_DAT_INV */
+#define WM8995_AIF2DACR_DAT_INV_SHIFT                0 /* AIF2DACR_DAT_INV */
+#define WM8995_AIF2DACR_DAT_INV_WIDTH                1 /* AIF2DACR_DAT_INV */
+
+/*
+ * R791 (0x317) - AIF2ADC Data
+ */
+#define WM8995_AIF2ADCL_DAT_INV                 0x0002 /* AIF2ADCL_DAT_INV */
+#define WM8995_AIF2ADCL_DAT_INV_MASK            0x0002 /* AIF2ADCL_DAT_INV */
+#define WM8995_AIF2ADCL_DAT_INV_SHIFT                1 /* AIF2ADCL_DAT_INV */
+#define WM8995_AIF2ADCL_DAT_INV_WIDTH                1 /* AIF2ADCL_DAT_INV */
+#define WM8995_AIF2ADCR_DAT_INV                 0x0001 /* AIF2ADCR_DAT_INV */
+#define WM8995_AIF2ADCR_DAT_INV_MASK            0x0001 /* AIF2ADCR_DAT_INV */
+#define WM8995_AIF2ADCR_DAT_INV_SHIFT                0 /* AIF2ADCR_DAT_INV */
+#define WM8995_AIF2ADCR_DAT_INV_WIDTH                1 /* AIF2ADCR_DAT_INV */
+
+/*
+ * R1024 (0x400) - AIF1 ADC1 Left Volume
+ */
+#define WM8995_AIF1ADC1_VU                      0x0100 /* AIF1ADC1_VU */
+#define WM8995_AIF1ADC1_VU_MASK                 0x0100 /* AIF1ADC1_VU */
+#define WM8995_AIF1ADC1_VU_SHIFT                     8 /* AIF1ADC1_VU */
+#define WM8995_AIF1ADC1_VU_WIDTH                     1 /* AIF1ADC1_VU */
+#define WM8995_AIF1ADC1L_VOL_MASK               0x00FF /* AIF1ADC1L_VOL - [7:0] */
+#define WM8995_AIF1ADC1L_VOL_SHIFT                   0 /* AIF1ADC1L_VOL - [7:0] */
+#define WM8995_AIF1ADC1L_VOL_WIDTH                   8 /* AIF1ADC1L_VOL - [7:0] */
+
+/*
+ * R1025 (0x401) - AIF1 ADC1 Right Volume
+ */
+#define WM8995_AIF1ADC1_VU                      0x0100 /* AIF1ADC1_VU */
+#define WM8995_AIF1ADC1_VU_MASK                 0x0100 /* AIF1ADC1_VU */
+#define WM8995_AIF1ADC1_VU_SHIFT                     8 /* AIF1ADC1_VU */
+#define WM8995_AIF1ADC1_VU_WIDTH                     1 /* AIF1ADC1_VU */
+#define WM8995_AIF1ADC1R_VOL_MASK               0x00FF /* AIF1ADC1R_VOL - [7:0] */
+#define WM8995_AIF1ADC1R_VOL_SHIFT                   0 /* AIF1ADC1R_VOL - [7:0] */
+#define WM8995_AIF1ADC1R_VOL_WIDTH                   8 /* AIF1ADC1R_VOL - [7:0] */
+
+/*
+ * R1026 (0x402) - AIF1 DAC1 Left Volume
+ */
+#define WM8995_AIF1DAC1_VU                      0x0100 /* AIF1DAC1_VU */
+#define WM8995_AIF1DAC1_VU_MASK                 0x0100 /* AIF1DAC1_VU */
+#define WM8995_AIF1DAC1_VU_SHIFT                     8 /* AIF1DAC1_VU */
+#define WM8995_AIF1DAC1_VU_WIDTH                     1 /* AIF1DAC1_VU */
+#define WM8995_AIF1DAC1L_VOL_MASK               0x00FF /* AIF1DAC1L_VOL - [7:0] */
+#define WM8995_AIF1DAC1L_VOL_SHIFT                   0 /* AIF1DAC1L_VOL - [7:0] */
+#define WM8995_AIF1DAC1L_VOL_WIDTH                   8 /* AIF1DAC1L_VOL - [7:0] */
+
+/*
+ * R1027 (0x403) - AIF1 DAC1 Right Volume
+ */
+#define WM8995_AIF1DAC1_VU                      0x0100 /* AIF1DAC1_VU */
+#define WM8995_AIF1DAC1_VU_MASK                 0x0100 /* AIF1DAC1_VU */
+#define WM8995_AIF1DAC1_VU_SHIFT                     8 /* AIF1DAC1_VU */
+#define WM8995_AIF1DAC1_VU_WIDTH                     1 /* AIF1DAC1_VU */
+#define WM8995_AIF1DAC1R_VOL_MASK               0x00FF /* AIF1DAC1R_VOL - [7:0] */
+#define WM8995_AIF1DAC1R_VOL_SHIFT                   0 /* AIF1DAC1R_VOL - [7:0] */
+#define WM8995_AIF1DAC1R_VOL_WIDTH                   8 /* AIF1DAC1R_VOL - [7:0] */
+
+/*
+ * R1028 (0x404) - AIF1 ADC2 Left Volume
+ */
+#define WM8995_AIF1ADC2_VU                      0x0100 /* AIF1ADC2_VU */
+#define WM8995_AIF1ADC2_VU_MASK                 0x0100 /* AIF1ADC2_VU */
+#define WM8995_AIF1ADC2_VU_SHIFT                     8 /* AIF1ADC2_VU */
+#define WM8995_AIF1ADC2_VU_WIDTH                     1 /* AIF1ADC2_VU */
+#define WM8995_AIF1ADC2L_VOL_MASK               0x00FF /* AIF1ADC2L_VOL - [7:0] */
+#define WM8995_AIF1ADC2L_VOL_SHIFT                   0 /* AIF1ADC2L_VOL - [7:0] */
+#define WM8995_AIF1ADC2L_VOL_WIDTH                   8 /* AIF1ADC2L_VOL - [7:0] */
+
+/*
+ * R1029 (0x405) - AIF1 ADC2 Right Volume
+ */
+#define WM8995_AIF1ADC2_VU                      0x0100 /* AIF1ADC2_VU */
+#define WM8995_AIF1ADC2_VU_MASK                 0x0100 /* AIF1ADC2_VU */
+#define WM8995_AIF1ADC2_VU_SHIFT                     8 /* AIF1ADC2_VU */
+#define WM8995_AIF1ADC2_VU_WIDTH                     1 /* AIF1ADC2_VU */
+#define WM8995_AIF1ADC2R_VOL_MASK               0x00FF /* AIF1ADC2R_VOL - [7:0] */
+#define WM8995_AIF1ADC2R_VOL_SHIFT                   0 /* AIF1ADC2R_VOL - [7:0] */
+#define WM8995_AIF1ADC2R_VOL_WIDTH                   8 /* AIF1ADC2R_VOL - [7:0] */
+
+/*
+ * R1030 (0x406) - AIF1 DAC2 Left Volume
+ */
+#define WM8995_AIF1DAC2_VU                      0x0100 /* AIF1DAC2_VU */
+#define WM8995_AIF1DAC2_VU_MASK                 0x0100 /* AIF1DAC2_VU */
+#define WM8995_AIF1DAC2_VU_SHIFT                     8 /* AIF1DAC2_VU */
+#define WM8995_AIF1DAC2_VU_WIDTH                     1 /* AIF1DAC2_VU */
+#define WM8995_AIF1DAC2L_VOL_MASK               0x00FF /* AIF1DAC2L_VOL - [7:0] */
+#define WM8995_AIF1DAC2L_VOL_SHIFT                   0 /* AIF1DAC2L_VOL - [7:0] */
+#define WM8995_AIF1DAC2L_VOL_WIDTH                   8 /* AIF1DAC2L_VOL - [7:0] */
+
+/*
+ * R1031 (0x407) - AIF1 DAC2 Right Volume
+ */
+#define WM8995_AIF1DAC2_VU                      0x0100 /* AIF1DAC2_VU */
+#define WM8995_AIF1DAC2_VU_MASK                 0x0100 /* AIF1DAC2_VU */
+#define WM8995_AIF1DAC2_VU_SHIFT                     8 /* AIF1DAC2_VU */
+#define WM8995_AIF1DAC2_VU_WIDTH                     1 /* AIF1DAC2_VU */
+#define WM8995_AIF1DAC2R_VOL_MASK               0x00FF /* AIF1DAC2R_VOL - [7:0] */
+#define WM8995_AIF1DAC2R_VOL_SHIFT                   0 /* AIF1DAC2R_VOL - [7:0] */
+#define WM8995_AIF1DAC2R_VOL_WIDTH                   8 /* AIF1DAC2R_VOL - [7:0] */
+
+/*
+ * R1040 (0x410) - AIF1 ADC1 Filters
+ */
+#define WM8995_AIF1ADC_4FS                      0x8000 /* AIF1ADC_4FS */
+#define WM8995_AIF1ADC_4FS_MASK                 0x8000 /* AIF1ADC_4FS */
+#define WM8995_AIF1ADC_4FS_SHIFT                    15 /* AIF1ADC_4FS */
+#define WM8995_AIF1ADC_4FS_WIDTH                     1 /* AIF1ADC_4FS */
+#define WM8995_AIF1ADC1L_HPF                    0x1000 /* AIF1ADC1L_HPF */
+#define WM8995_AIF1ADC1L_HPF_MASK               0x1000 /* AIF1ADC1L_HPF */
+#define WM8995_AIF1ADC1L_HPF_SHIFT                  12 /* AIF1ADC1L_HPF */
+#define WM8995_AIF1ADC1L_HPF_WIDTH                   1 /* AIF1ADC1L_HPF */
+#define WM8995_AIF1ADC1R_HPF                    0x0800 /* AIF1ADC1R_HPF */
+#define WM8995_AIF1ADC1R_HPF_MASK               0x0800 /* AIF1ADC1R_HPF */
+#define WM8995_AIF1ADC1R_HPF_SHIFT                  11 /* AIF1ADC1R_HPF */
+#define WM8995_AIF1ADC1R_HPF_WIDTH                   1 /* AIF1ADC1R_HPF */
+#define WM8995_AIF1ADC1_HPF_MODE                0x0008 /* AIF1ADC1_HPF_MODE */
+#define WM8995_AIF1ADC1_HPF_MODE_MASK           0x0008 /* AIF1ADC1_HPF_MODE */
+#define WM8995_AIF1ADC1_HPF_MODE_SHIFT               3 /* AIF1ADC1_HPF_MODE */
+#define WM8995_AIF1ADC1_HPF_MODE_WIDTH               1 /* AIF1ADC1_HPF_MODE */
+#define WM8995_AIF1ADC1_HPF_CUT_MASK            0x0007 /* AIF1ADC1_HPF_CUT - [2:0] */
+#define WM8995_AIF1ADC1_HPF_CUT_SHIFT                0 /* AIF1ADC1_HPF_CUT - [2:0] */
+#define WM8995_AIF1ADC1_HPF_CUT_WIDTH                3 /* AIF1ADC1_HPF_CUT - [2:0] */
+
+/*
+ * R1041 (0x411) - AIF1 ADC2 Filters
+ */
+#define WM8995_AIF1ADC2L_HPF                    0x1000 /* AIF1ADC2L_HPF */
+#define WM8995_AIF1ADC2L_HPF_MASK               0x1000 /* AIF1ADC2L_HPF */
+#define WM8995_AIF1ADC2L_HPF_SHIFT                  12 /* AIF1ADC2L_HPF */
+#define WM8995_AIF1ADC2L_HPF_WIDTH                   1 /* AIF1ADC2L_HPF */
+#define WM8995_AIF1ADC2R_HPF                    0x0800 /* AIF1ADC2R_HPF */
+#define WM8995_AIF1ADC2R_HPF_MASK               0x0800 /* AIF1ADC2R_HPF */
+#define WM8995_AIF1ADC2R_HPF_SHIFT                  11 /* AIF1ADC2R_HPF */
+#define WM8995_AIF1ADC2R_HPF_WIDTH                   1 /* AIF1ADC2R_HPF */
+#define WM8995_AIF1ADC2_HPF_MODE                0x0008 /* AIF1ADC2_HPF_MODE */
+#define WM8995_AIF1ADC2_HPF_MODE_MASK           0x0008 /* AIF1ADC2_HPF_MODE */
+#define WM8995_AIF1ADC2_HPF_MODE_SHIFT               3 /* AIF1ADC2_HPF_MODE */
+#define WM8995_AIF1ADC2_HPF_MODE_WIDTH               1 /* AIF1ADC2_HPF_MODE */
+#define WM8995_AIF1ADC2_HPF_CUT_MASK            0x0007 /* AIF1ADC2_HPF_CUT - [2:0] */
+#define WM8995_AIF1ADC2_HPF_CUT_SHIFT                0 /* AIF1ADC2_HPF_CUT - [2:0] */
+#define WM8995_AIF1ADC2_HPF_CUT_WIDTH                3 /* AIF1ADC2_HPF_CUT - [2:0] */
+
+/*
+ * R1056 (0x420) - AIF1 DAC1 Filters (1)
+ */
+#define WM8995_AIF1DAC1_MUTE                    0x0200 /* AIF1DAC1_MUTE */
+#define WM8995_AIF1DAC1_MUTE_MASK               0x0200 /* AIF1DAC1_MUTE */
+#define WM8995_AIF1DAC1_MUTE_SHIFT                   9 /* AIF1DAC1_MUTE */
+#define WM8995_AIF1DAC1_MUTE_WIDTH                   1 /* AIF1DAC1_MUTE */
+#define WM8995_AIF1DAC1_MONO                    0x0080 /* AIF1DAC1_MONO */
+#define WM8995_AIF1DAC1_MONO_MASK               0x0080 /* AIF1DAC1_MONO */
+#define WM8995_AIF1DAC1_MONO_SHIFT                   7 /* AIF1DAC1_MONO */
+#define WM8995_AIF1DAC1_MONO_WIDTH                   1 /* AIF1DAC1_MONO */
+#define WM8995_AIF1DAC1_MUTERATE                0x0020 /* AIF1DAC1_MUTERATE */
+#define WM8995_AIF1DAC1_MUTERATE_MASK           0x0020 /* AIF1DAC1_MUTERATE */
+#define WM8995_AIF1DAC1_MUTERATE_SHIFT               5 /* AIF1DAC1_MUTERATE */
+#define WM8995_AIF1DAC1_MUTERATE_WIDTH               1 /* AIF1DAC1_MUTERATE */
+#define WM8995_AIF1DAC1_UNMUTE_RAMP             0x0010 /* AIF1DAC1_UNMUTE_RAMP */
+#define WM8995_AIF1DAC1_UNMUTE_RAMP_MASK        0x0010 /* AIF1DAC1_UNMUTE_RAMP */
+#define WM8995_AIF1DAC1_UNMUTE_RAMP_SHIFT            4 /* AIF1DAC1_UNMUTE_RAMP */
+#define WM8995_AIF1DAC1_UNMUTE_RAMP_WIDTH            1 /* AIF1DAC1_UNMUTE_RAMP */
+#define WM8995_AIF1DAC1_DEEMP_MASK              0x0006 /* AIF1DAC1_DEEMP - [2:1] */
+#define WM8995_AIF1DAC1_DEEMP_SHIFT                  1 /* AIF1DAC1_DEEMP - [2:1] */
+#define WM8995_AIF1DAC1_DEEMP_WIDTH                  2 /* AIF1DAC1_DEEMP - [2:1] */
+
+/*
+ * R1057 (0x421) - AIF1 DAC1 Filters (2)
+ */
+#define WM8995_AIF1DAC1_3D_GAIN_MASK            0x3E00 /* AIF1DAC1_3D_GAIN - [13:9] */
+#define WM8995_AIF1DAC1_3D_GAIN_SHIFT                9 /* AIF1DAC1_3D_GAIN - [13:9] */
+#define WM8995_AIF1DAC1_3D_GAIN_WIDTH                5 /* AIF1DAC1_3D_GAIN - [13:9] */
+#define WM8995_AIF1DAC1_3D_ENA                  0x0100 /* AIF1DAC1_3D_ENA */
+#define WM8995_AIF1DAC1_3D_ENA_MASK             0x0100 /* AIF1DAC1_3D_ENA */
+#define WM8995_AIF1DAC1_3D_ENA_SHIFT                 8 /* AIF1DAC1_3D_ENA */
+#define WM8995_AIF1DAC1_3D_ENA_WIDTH                 1 /* AIF1DAC1_3D_ENA */
+
+/*
+ * R1058 (0x422) - AIF1 DAC2 Filters (1)
+ */
+#define WM8995_AIF1DAC2_MUTE                    0x0200 /* AIF1DAC2_MUTE */
+#define WM8995_AIF1DAC2_MUTE_MASK               0x0200 /* AIF1DAC2_MUTE */
+#define WM8995_AIF1DAC2_MUTE_SHIFT                   9 /* AIF1DAC2_MUTE */
+#define WM8995_AIF1DAC2_MUTE_WIDTH                   1 /* AIF1DAC2_MUTE */
+#define WM8995_AIF1DAC2_MONO                    0x0080 /* AIF1DAC2_MONO */
+#define WM8995_AIF1DAC2_MONO_MASK               0x0080 /* AIF1DAC2_MONO */
+#define WM8995_AIF1DAC2_MONO_SHIFT                   7 /* AIF1DAC2_MONO */
+#define WM8995_AIF1DAC2_MONO_WIDTH                   1 /* AIF1DAC2_MONO */
+#define WM8995_AIF1DAC2_MUTERATE                0x0020 /* AIF1DAC2_MUTERATE */
+#define WM8995_AIF1DAC2_MUTERATE_MASK           0x0020 /* AIF1DAC2_MUTERATE */
+#define WM8995_AIF1DAC2_MUTERATE_SHIFT               5 /* AIF1DAC2_MUTERATE */
+#define WM8995_AIF1DAC2_MUTERATE_WIDTH               1 /* AIF1DAC2_MUTERATE */
+#define WM8995_AIF1DAC2_UNMUTE_RAMP             0x0010 /* AIF1DAC2_UNMUTE_RAMP */
+#define WM8995_AIF1DAC2_UNMUTE_RAMP_MASK        0x0010 /* AIF1DAC2_UNMUTE_RAMP */
+#define WM8995_AIF1DAC2_UNMUTE_RAMP_SHIFT            4 /* AIF1DAC2_UNMUTE_RAMP */
+#define WM8995_AIF1DAC2_UNMUTE_RAMP_WIDTH            1 /* AIF1DAC2_UNMUTE_RAMP */
+#define WM8995_AIF1DAC2_DEEMP_MASK              0x0006 /* AIF1DAC2_DEEMP - [2:1] */
+#define WM8995_AIF1DAC2_DEEMP_SHIFT                  1 /* AIF1DAC2_DEEMP - [2:1] */
+#define WM8995_AIF1DAC2_DEEMP_WIDTH                  2 /* AIF1DAC2_DEEMP - [2:1] */
+
+/*
+ * R1059 (0x423) - AIF1 DAC2 Filters (2)
+ */
+#define WM8995_AIF1DAC2_3D_GAIN_MASK            0x3E00 /* AIF1DAC2_3D_GAIN - [13:9] */
+#define WM8995_AIF1DAC2_3D_GAIN_SHIFT                9 /* AIF1DAC2_3D_GAIN - [13:9] */
+#define WM8995_AIF1DAC2_3D_GAIN_WIDTH                5 /* AIF1DAC2_3D_GAIN - [13:9] */
+#define WM8995_AIF1DAC2_3D_ENA                  0x0100 /* AIF1DAC2_3D_ENA */
+#define WM8995_AIF1DAC2_3D_ENA_MASK             0x0100 /* AIF1DAC2_3D_ENA */
+#define WM8995_AIF1DAC2_3D_ENA_SHIFT                 8 /* AIF1DAC2_3D_ENA */
+#define WM8995_AIF1DAC2_3D_ENA_WIDTH                 1 /* AIF1DAC2_3D_ENA */
+
+/*
+ * R1088 (0x440) - AIF1 DRC1 (1)
+ */
+#define WM8995_AIF1DRC1_SIG_DET_RMS_MASK        0xF800 /* AIF1DRC1_SIG_DET_RMS - [15:11] */
+#define WM8995_AIF1DRC1_SIG_DET_RMS_SHIFT           11 /* AIF1DRC1_SIG_DET_RMS - [15:11] */
+#define WM8995_AIF1DRC1_SIG_DET_RMS_WIDTH            5 /* AIF1DRC1_SIG_DET_RMS - [15:11] */
+#define WM8995_AIF1DRC1_SIG_DET_PK_MASK         0x0600 /* AIF1DRC1_SIG_DET_PK - [10:9] */
+#define WM8995_AIF1DRC1_SIG_DET_PK_SHIFT             9 /* AIF1DRC1_SIG_DET_PK - [10:9] */
+#define WM8995_AIF1DRC1_SIG_DET_PK_WIDTH             2 /* AIF1DRC1_SIG_DET_PK - [10:9] */
+#define WM8995_AIF1DRC1_NG_ENA                  0x0100 /* AIF1DRC1_NG_ENA */
+#define WM8995_AIF1DRC1_NG_ENA_MASK             0x0100 /* AIF1DRC1_NG_ENA */
+#define WM8995_AIF1DRC1_NG_ENA_SHIFT                 8 /* AIF1DRC1_NG_ENA */
+#define WM8995_AIF1DRC1_NG_ENA_WIDTH                 1 /* AIF1DRC1_NG_ENA */
+#define WM8995_AIF1DRC1_SIG_DET_MODE            0x0080 /* AIF1DRC1_SIG_DET_MODE */
+#define WM8995_AIF1DRC1_SIG_DET_MODE_MASK       0x0080 /* AIF1DRC1_SIG_DET_MODE */
+#define WM8995_AIF1DRC1_SIG_DET_MODE_SHIFT           7 /* AIF1DRC1_SIG_DET_MODE */
+#define WM8995_AIF1DRC1_SIG_DET_MODE_WIDTH           1 /* AIF1DRC1_SIG_DET_MODE */
+#define WM8995_AIF1DRC1_SIG_DET                 0x0040 /* AIF1DRC1_SIG_DET */
+#define WM8995_AIF1DRC1_SIG_DET_MASK            0x0040 /* AIF1DRC1_SIG_DET */
+#define WM8995_AIF1DRC1_SIG_DET_SHIFT                6 /* AIF1DRC1_SIG_DET */
+#define WM8995_AIF1DRC1_SIG_DET_WIDTH                1 /* AIF1DRC1_SIG_DET */
+#define WM8995_AIF1DRC1_KNEE2_OP_ENA            0x0020 /* AIF1DRC1_KNEE2_OP_ENA */
+#define WM8995_AIF1DRC1_KNEE2_OP_ENA_MASK       0x0020 /* AIF1DRC1_KNEE2_OP_ENA */
+#define WM8995_AIF1DRC1_KNEE2_OP_ENA_SHIFT           5 /* AIF1DRC1_KNEE2_OP_ENA */
+#define WM8995_AIF1DRC1_KNEE2_OP_ENA_WIDTH           1 /* AIF1DRC1_KNEE2_OP_ENA */
+#define WM8995_AIF1DRC1_QR                      0x0010 /* AIF1DRC1_QR */
+#define WM8995_AIF1DRC1_QR_MASK                 0x0010 /* AIF1DRC1_QR */
+#define WM8995_AIF1DRC1_QR_SHIFT                     4 /* AIF1DRC1_QR */
+#define WM8995_AIF1DRC1_QR_WIDTH                     1 /* AIF1DRC1_QR */
+#define WM8995_AIF1DRC1_ANTICLIP                0x0008 /* AIF1DRC1_ANTICLIP */
+#define WM8995_AIF1DRC1_ANTICLIP_MASK           0x0008 /* AIF1DRC1_ANTICLIP */
+#define WM8995_AIF1DRC1_ANTICLIP_SHIFT               3 /* AIF1DRC1_ANTICLIP */
+#define WM8995_AIF1DRC1_ANTICLIP_WIDTH               1 /* AIF1DRC1_ANTICLIP */
+#define WM8995_AIF1DAC1_DRC_ENA                 0x0004 /* AIF1DAC1_DRC_ENA */
+#define WM8995_AIF1DAC1_DRC_ENA_MASK            0x0004 /* AIF1DAC1_DRC_ENA */
+#define WM8995_AIF1DAC1_DRC_ENA_SHIFT                2 /* AIF1DAC1_DRC_ENA */
+#define WM8995_AIF1DAC1_DRC_ENA_WIDTH                1 /* AIF1DAC1_DRC_ENA */
+#define WM8995_AIF1ADC1L_DRC_ENA                0x0002 /* AIF1ADC1L_DRC_ENA */
+#define WM8995_AIF1ADC1L_DRC_ENA_MASK           0x0002 /* AIF1ADC1L_DRC_ENA */
+#define WM8995_AIF1ADC1L_DRC_ENA_SHIFT               1 /* AIF1ADC1L_DRC_ENA */
+#define WM8995_AIF1ADC1L_DRC_ENA_WIDTH               1 /* AIF1ADC1L_DRC_ENA */
+#define WM8995_AIF1ADC1R_DRC_ENA                0x0001 /* AIF1ADC1R_DRC_ENA */
+#define WM8995_AIF1ADC1R_DRC_ENA_MASK           0x0001 /* AIF1ADC1R_DRC_ENA */
+#define WM8995_AIF1ADC1R_DRC_ENA_SHIFT               0 /* AIF1ADC1R_DRC_ENA */
+#define WM8995_AIF1ADC1R_DRC_ENA_WIDTH               1 /* AIF1ADC1R_DRC_ENA */
+
+/*
+ * R1089 (0x441) - AIF1 DRC1 (2)
+ */
+#define WM8995_AIF1DRC1_ATK_MASK                0x1E00 /* AIF1DRC1_ATK - [12:9] */
+#define WM8995_AIF1DRC1_ATK_SHIFT                    9 /* AIF1DRC1_ATK - [12:9] */
+#define WM8995_AIF1DRC1_ATK_WIDTH                    4 /* AIF1DRC1_ATK - [12:9] */
+#define WM8995_AIF1DRC1_DCY_MASK                0x01E0 /* AIF1DRC1_DCY - [8:5] */
+#define WM8995_AIF1DRC1_DCY_SHIFT                    5 /* AIF1DRC1_DCY - [8:5] */
+#define WM8995_AIF1DRC1_DCY_WIDTH                    4 /* AIF1DRC1_DCY - [8:5] */
+#define WM8995_AIF1DRC1_MINGAIN_MASK            0x001C /* AIF1DRC1_MINGAIN - [4:2] */
+#define WM8995_AIF1DRC1_MINGAIN_SHIFT                2 /* AIF1DRC1_MINGAIN - [4:2] */
+#define WM8995_AIF1DRC1_MINGAIN_WIDTH                3 /* AIF1DRC1_MINGAIN - [4:2] */
+#define WM8995_AIF1DRC1_MAXGAIN_MASK            0x0003 /* AIF1DRC1_MAXGAIN - [1:0] */
+#define WM8995_AIF1DRC1_MAXGAIN_SHIFT                0 /* AIF1DRC1_MAXGAIN - [1:0] */
+#define WM8995_AIF1DRC1_MAXGAIN_WIDTH                2 /* AIF1DRC1_MAXGAIN - [1:0] */
+
+/*
+ * R1090 (0x442) - AIF1 DRC1 (3)
+ */
+#define WM8995_AIF1DRC1_NG_MINGAIN_MASK         0xF000 /* AIF1DRC1_NG_MINGAIN - [15:12] */
+#define WM8995_AIF1DRC1_NG_MINGAIN_SHIFT            12 /* AIF1DRC1_NG_MINGAIN - [15:12] */
+#define WM8995_AIF1DRC1_NG_MINGAIN_WIDTH             4 /* AIF1DRC1_NG_MINGAIN - [15:12] */
+#define WM8995_AIF1DRC1_NG_EXP_MASK             0x0C00 /* AIF1DRC1_NG_EXP - [11:10] */
+#define WM8995_AIF1DRC1_NG_EXP_SHIFT                10 /* AIF1DRC1_NG_EXP - [11:10] */
+#define WM8995_AIF1DRC1_NG_EXP_WIDTH                 2 /* AIF1DRC1_NG_EXP - [11:10] */
+#define WM8995_AIF1DRC1_QR_THR_MASK             0x0300 /* AIF1DRC1_QR_THR - [9:8] */
+#define WM8995_AIF1DRC1_QR_THR_SHIFT                 8 /* AIF1DRC1_QR_THR - [9:8] */
+#define WM8995_AIF1DRC1_QR_THR_WIDTH                 2 /* AIF1DRC1_QR_THR - [9:8] */
+#define WM8995_AIF1DRC1_QR_DCY_MASK             0x00C0 /* AIF1DRC1_QR_DCY - [7:6] */
+#define WM8995_AIF1DRC1_QR_DCY_SHIFT                 6 /* AIF1DRC1_QR_DCY - [7:6] */
+#define WM8995_AIF1DRC1_QR_DCY_WIDTH                 2 /* AIF1DRC1_QR_DCY - [7:6] */
+#define WM8995_AIF1DRC1_HI_COMP_MASK            0x0038 /* AIF1DRC1_HI_COMP - [5:3] */
+#define WM8995_AIF1DRC1_HI_COMP_SHIFT                3 /* AIF1DRC1_HI_COMP - [5:3] */
+#define WM8995_AIF1DRC1_HI_COMP_WIDTH                3 /* AIF1DRC1_HI_COMP - [5:3] */
+#define WM8995_AIF1DRC1_LO_COMP_MASK            0x0007 /* AIF1DRC1_LO_COMP - [2:0] */
+#define WM8995_AIF1DRC1_LO_COMP_SHIFT                0 /* AIF1DRC1_LO_COMP - [2:0] */
+#define WM8995_AIF1DRC1_LO_COMP_WIDTH                3 /* AIF1DRC1_LO_COMP - [2:0] */
+
+/*
+ * R1091 (0x443) - AIF1 DRC1 (4)
+ */
+#define WM8995_AIF1DRC1_KNEE_IP_MASK            0x07E0 /* AIF1DRC1_KNEE_IP - [10:5] */
+#define WM8995_AIF1DRC1_KNEE_IP_SHIFT                5 /* AIF1DRC1_KNEE_IP - [10:5] */
+#define WM8995_AIF1DRC1_KNEE_IP_WIDTH                6 /* AIF1DRC1_KNEE_IP - [10:5] */
+#define WM8995_AIF1DRC1_KNEE_OP_MASK            0x001F /* AIF1DRC1_KNEE_OP - [4:0] */
+#define WM8995_AIF1DRC1_KNEE_OP_SHIFT                0 /* AIF1DRC1_KNEE_OP - [4:0] */
+#define WM8995_AIF1DRC1_KNEE_OP_WIDTH                5 /* AIF1DRC1_KNEE_OP - [4:0] */
+
+/*
+ * R1092 (0x444) - AIF1 DRC1 (5)
+ */
+#define WM8995_AIF1DRC1_KNEE2_IP_MASK           0x03E0 /* AIF1DRC1_KNEE2_IP - [9:5] */
+#define WM8995_AIF1DRC1_KNEE2_IP_SHIFT               5 /* AIF1DRC1_KNEE2_IP - [9:5] */
+#define WM8995_AIF1DRC1_KNEE2_IP_WIDTH               5 /* AIF1DRC1_KNEE2_IP - [9:5] */
+#define WM8995_AIF1DRC1_KNEE2_OP_MASK           0x001F /* AIF1DRC1_KNEE2_OP - [4:0] */
+#define WM8995_AIF1DRC1_KNEE2_OP_SHIFT               0 /* AIF1DRC1_KNEE2_OP - [4:0] */
+#define WM8995_AIF1DRC1_KNEE2_OP_WIDTH               5 /* AIF1DRC1_KNEE2_OP - [4:0] */
+
+/*
+ * R1104 (0x450) - AIF1 DRC2 (1)
+ */
+#define WM8995_AIF1DRC2_SIG_DET_RMS_MASK        0xF800 /* AIF1DRC2_SIG_DET_RMS - [15:11] */
+#define WM8995_AIF1DRC2_SIG_DET_RMS_SHIFT           11 /* AIF1DRC2_SIG_DET_RMS - [15:11] */
+#define WM8995_AIF1DRC2_SIG_DET_RMS_WIDTH            5 /* AIF1DRC2_SIG_DET_RMS - [15:11] */
+#define WM8995_AIF1DRC2_SIG_DET_PK_MASK         0x0600 /* AIF1DRC2_SIG_DET_PK - [10:9] */
+#define WM8995_AIF1DRC2_SIG_DET_PK_SHIFT             9 /* AIF1DRC2_SIG_DET_PK - [10:9] */
+#define WM8995_AIF1DRC2_SIG_DET_PK_WIDTH             2 /* AIF1DRC2_SIG_DET_PK - [10:9] */
+#define WM8995_AIF1DRC2_NG_ENA                  0x0100 /* AIF1DRC2_NG_ENA */
+#define WM8995_AIF1DRC2_NG_ENA_MASK             0x0100 /* AIF1DRC2_NG_ENA */
+#define WM8995_AIF1DRC2_NG_ENA_SHIFT                 8 /* AIF1DRC2_NG_ENA */
+#define WM8995_AIF1DRC2_NG_ENA_WIDTH                 1 /* AIF1DRC2_NG_ENA */
+#define WM8995_AIF1DRC2_SIG_DET_MODE            0x0080 /* AIF1DRC2_SIG_DET_MODE */
+#define WM8995_AIF1DRC2_SIG_DET_MODE_MASK       0x0080 /* AIF1DRC2_SIG_DET_MODE */
+#define WM8995_AIF1DRC2_SIG_DET_MODE_SHIFT           7 /* AIF1DRC2_SIG_DET_MODE */
+#define WM8995_AIF1DRC2_SIG_DET_MODE_WIDTH           1 /* AIF1DRC2_SIG_DET_MODE */
+#define WM8995_AIF1DRC2_SIG_DET                 0x0040 /* AIF1DRC2_SIG_DET */
+#define WM8995_AIF1DRC2_SIG_DET_MASK            0x0040 /* AIF1DRC2_SIG_DET */
+#define WM8995_AIF1DRC2_SIG_DET_SHIFT                6 /* AIF1DRC2_SIG_DET */
+#define WM8995_AIF1DRC2_SIG_DET_WIDTH                1 /* AIF1DRC2_SIG_DET */
+#define WM8995_AIF1DRC2_KNEE2_OP_ENA            0x0020 /* AIF1DRC2_KNEE2_OP_ENA */
+#define WM8995_AIF1DRC2_KNEE2_OP_ENA_MASK       0x0020 /* AIF1DRC2_KNEE2_OP_ENA */
+#define WM8995_AIF1DRC2_KNEE2_OP_ENA_SHIFT           5 /* AIF1DRC2_KNEE2_OP_ENA */
+#define WM8995_AIF1DRC2_KNEE2_OP_ENA_WIDTH           1 /* AIF1DRC2_KNEE2_OP_ENA */
+#define WM8995_AIF1DRC2_QR                      0x0010 /* AIF1DRC2_QR */
+#define WM8995_AIF1DRC2_QR_MASK                 0x0010 /* AIF1DRC2_QR */
+#define WM8995_AIF1DRC2_QR_SHIFT                     4 /* AIF1DRC2_QR */
+#define WM8995_AIF1DRC2_QR_WIDTH                     1 /* AIF1DRC2_QR */
+#define WM8995_AIF1DRC2_ANTICLIP                0x0008 /* AIF1DRC2_ANTICLIP */
+#define WM8995_AIF1DRC2_ANTICLIP_MASK           0x0008 /* AIF1DRC2_ANTICLIP */
+#define WM8995_AIF1DRC2_ANTICLIP_SHIFT               3 /* AIF1DRC2_ANTICLIP */
+#define WM8995_AIF1DRC2_ANTICLIP_WIDTH               1 /* AIF1DRC2_ANTICLIP */
+#define WM8995_AIF1DAC2_DRC_ENA                 0x0004 /* AIF1DAC2_DRC_ENA */
+#define WM8995_AIF1DAC2_DRC_ENA_MASK            0x0004 /* AIF1DAC2_DRC_ENA */
+#define WM8995_AIF1DAC2_DRC_ENA_SHIFT                2 /* AIF1DAC2_DRC_ENA */
+#define WM8995_AIF1DAC2_DRC_ENA_WIDTH                1 /* AIF1DAC2_DRC_ENA */
+#define WM8995_AIF1ADC2L_DRC_ENA                0x0002 /* AIF1ADC2L_DRC_ENA */
+#define WM8995_AIF1ADC2L_DRC_ENA_MASK           0x0002 /* AIF1ADC2L_DRC_ENA */
+#define WM8995_AIF1ADC2L_DRC_ENA_SHIFT               1 /* AIF1ADC2L_DRC_ENA */
+#define WM8995_AIF1ADC2L_DRC_ENA_WIDTH               1 /* AIF1ADC2L_DRC_ENA */
+#define WM8995_AIF1ADC2R_DRC_ENA                0x0001 /* AIF1ADC2R_DRC_ENA */
+#define WM8995_AIF1ADC2R_DRC_ENA_MASK           0x0001 /* AIF1ADC2R_DRC_ENA */
+#define WM8995_AIF1ADC2R_DRC_ENA_SHIFT               0 /* AIF1ADC2R_DRC_ENA */
+#define WM8995_AIF1ADC2R_DRC_ENA_WIDTH               1 /* AIF1ADC2R_DRC_ENA */
+
+/*
+ * R1105 (0x451) - AIF1 DRC2 (2)
+ */
+#define WM8995_AIF1DRC2_ATK_MASK                0x1E00 /* AIF1DRC2_ATK - [12:9] */
+#define WM8995_AIF1DRC2_ATK_SHIFT                    9 /* AIF1DRC2_ATK - [12:9] */
+#define WM8995_AIF1DRC2_ATK_WIDTH                    4 /* AIF1DRC2_ATK - [12:9] */
+#define WM8995_AIF1DRC2_DCY_MASK                0x01E0 /* AIF1DRC2_DCY - [8:5] */
+#define WM8995_AIF1DRC2_DCY_SHIFT                    5 /* AIF1DRC2_DCY - [8:5] */
+#define WM8995_AIF1DRC2_DCY_WIDTH                    4 /* AIF1DRC2_DCY - [8:5] */
+#define WM8995_AIF1DRC2_MINGAIN_MASK            0x001C /* AIF1DRC2_MINGAIN - [4:2] */
+#define WM8995_AIF1DRC2_MINGAIN_SHIFT                2 /* AIF1DRC2_MINGAIN - [4:2] */
+#define WM8995_AIF1DRC2_MINGAIN_WIDTH                3 /* AIF1DRC2_MINGAIN - [4:2] */
+#define WM8995_AIF1DRC2_MAXGAIN_MASK            0x0003 /* AIF1DRC2_MAXGAIN - [1:0] */
+#define WM8995_AIF1DRC2_MAXGAIN_SHIFT                0 /* AIF1DRC2_MAXGAIN - [1:0] */
+#define WM8995_AIF1DRC2_MAXGAIN_WIDTH                2 /* AIF1DRC2_MAXGAIN - [1:0] */
+
+/*
+ * R1106 (0x452) - AIF1 DRC2 (3)
+ */
+#define WM8995_AIF1DRC2_NG_MINGAIN_MASK         0xF000 /* AIF1DRC2_NG_MINGAIN - [15:12] */
+#define WM8995_AIF1DRC2_NG_MINGAIN_SHIFT            12 /* AIF1DRC2_NG_MINGAIN - [15:12] */
+#define WM8995_AIF1DRC2_NG_MINGAIN_WIDTH             4 /* AIF1DRC2_NG_MINGAIN - [15:12] */
+#define WM8995_AIF1DRC2_NG_EXP_MASK             0x0C00 /* AIF1DRC2_NG_EXP - [11:10] */
+#define WM8995_AIF1DRC2_NG_EXP_SHIFT                10 /* AIF1DRC2_NG_EXP - [11:10] */
+#define WM8995_AIF1DRC2_NG_EXP_WIDTH                 2 /* AIF1DRC2_NG_EXP - [11:10] */
+#define WM8995_AIF1DRC2_QR_THR_MASK             0x0300 /* AIF1DRC2_QR_THR - [9:8] */
+#define WM8995_AIF1DRC2_QR_THR_SHIFT                 8 /* AIF1DRC2_QR_THR - [9:8] */
+#define WM8995_AIF1DRC2_QR_THR_WIDTH                 2 /* AIF1DRC2_QR_THR - [9:8] */
+#define WM8995_AIF1DRC2_QR_DCY_MASK             0x00C0 /* AIF1DRC2_QR_DCY - [7:6] */
+#define WM8995_AIF1DRC2_QR_DCY_SHIFT                 6 /* AIF1DRC2_QR_DCY - [7:6] */
+#define WM8995_AIF1DRC2_QR_DCY_WIDTH                 2 /* AIF1DRC2_QR_DCY - [7:6] */
+#define WM8995_AIF1DRC2_HI_COMP_MASK            0x0038 /* AIF1DRC2_HI_COMP - [5:3] */
+#define WM8995_AIF1DRC2_HI_COMP_SHIFT                3 /* AIF1DRC2_HI_COMP - [5:3] */
+#define WM8995_AIF1DRC2_HI_COMP_WIDTH                3 /* AIF1DRC2_HI_COMP - [5:3] */
+#define WM8995_AIF1DRC2_LO_COMP_MASK            0x0007 /* AIF1DRC2_LO_COMP - [2:0] */
+#define WM8995_AIF1DRC2_LO_COMP_SHIFT                0 /* AIF1DRC2_LO_COMP - [2:0] */
+#define WM8995_AIF1DRC2_LO_COMP_WIDTH                3 /* AIF1DRC2_LO_COMP - [2:0] */
+
+/*
+ * R1107 (0x453) - AIF1 DRC2 (4)
+ */
+#define WM8995_AIF1DRC2_KNEE_IP_MASK            0x07E0 /* AIF1DRC2_KNEE_IP - [10:5] */
+#define WM8995_AIF1DRC2_KNEE_IP_SHIFT                5 /* AIF1DRC2_KNEE_IP - [10:5] */
+#define WM8995_AIF1DRC2_KNEE_IP_WIDTH                6 /* AIF1DRC2_KNEE_IP - [10:5] */
+#define WM8995_AIF1DRC2_KNEE_OP_MASK            0x001F /* AIF1DRC2_KNEE_OP - [4:0] */
+#define WM8995_AIF1DRC2_KNEE_OP_SHIFT                0 /* AIF1DRC2_KNEE_OP - [4:0] */
+#define WM8995_AIF1DRC2_KNEE_OP_WIDTH                5 /* AIF1DRC2_KNEE_OP - [4:0] */
+
+/*
+ * R1108 (0x454) - AIF1 DRC2 (5)
+ */
+#define WM8995_AIF1DRC2_KNEE2_IP_MASK           0x03E0 /* AIF1DRC2_KNEE2_IP - [9:5] */
+#define WM8995_AIF1DRC2_KNEE2_IP_SHIFT               5 /* AIF1DRC2_KNEE2_IP - [9:5] */
+#define WM8995_AIF1DRC2_KNEE2_IP_WIDTH               5 /* AIF1DRC2_KNEE2_IP - [9:5] */
+#define WM8995_AIF1DRC2_KNEE2_OP_MASK           0x001F /* AIF1DRC2_KNEE2_OP - [4:0] */
+#define WM8995_AIF1DRC2_KNEE2_OP_SHIFT               0 /* AIF1DRC2_KNEE2_OP - [4:0] */
+#define WM8995_AIF1DRC2_KNEE2_OP_WIDTH               5 /* AIF1DRC2_KNEE2_OP - [4:0] */
+
+/*
+ * R1152 (0x480) - AIF1 DAC1 EQ Gains (1)
+ */
+#define WM8995_AIF1DAC1_EQ_B1_GAIN_MASK         0xF800 /* AIF1DAC1_EQ_B1_GAIN - [15:11] */
+#define WM8995_AIF1DAC1_EQ_B1_GAIN_SHIFT            11 /* AIF1DAC1_EQ_B1_GAIN - [15:11] */
+#define WM8995_AIF1DAC1_EQ_B1_GAIN_WIDTH             5 /* AIF1DAC1_EQ_B1_GAIN - [15:11] */
+#define WM8995_AIF1DAC1_EQ_B2_GAIN_MASK         0x07C0 /* AIF1DAC1_EQ_B2_GAIN - [10:6] */
+#define WM8995_AIF1DAC1_EQ_B2_GAIN_SHIFT             6 /* AIF1DAC1_EQ_B2_GAIN - [10:6] */
+#define WM8995_AIF1DAC1_EQ_B2_GAIN_WIDTH             5 /* AIF1DAC1_EQ_B2_GAIN - [10:6] */
+#define WM8995_AIF1DAC1_EQ_B3_GAIN_MASK         0x003E /* AIF1DAC1_EQ_B3_GAIN - [5:1] */
+#define WM8995_AIF1DAC1_EQ_B3_GAIN_SHIFT             1 /* AIF1DAC1_EQ_B3_GAIN - [5:1] */
+#define WM8995_AIF1DAC1_EQ_B3_GAIN_WIDTH             5 /* AIF1DAC1_EQ_B3_GAIN - [5:1] */
+#define WM8995_AIF1DAC1_EQ_ENA                  0x0001 /* AIF1DAC1_EQ_ENA */
+#define WM8995_AIF1DAC1_EQ_ENA_MASK             0x0001 /* AIF1DAC1_EQ_ENA */
+#define WM8995_AIF1DAC1_EQ_ENA_SHIFT                 0 /* AIF1DAC1_EQ_ENA */
+#define WM8995_AIF1DAC1_EQ_ENA_WIDTH                 1 /* AIF1DAC1_EQ_ENA */
+
+/*
+ * R1153 (0x481) - AIF1 DAC1 EQ Gains (2)
+ */
+#define WM8995_AIF1DAC1_EQ_B4_GAIN_MASK         0xF800 /* AIF1DAC1_EQ_B4_GAIN - [15:11] */
+#define WM8995_AIF1DAC1_EQ_B4_GAIN_SHIFT            11 /* AIF1DAC1_EQ_B4_GAIN - [15:11] */
+#define WM8995_AIF1DAC1_EQ_B4_GAIN_WIDTH             5 /* AIF1DAC1_EQ_B4_GAIN - [15:11] */
+#define WM8995_AIF1DAC1_EQ_B5_GAIN_MASK         0x07C0 /* AIF1DAC1_EQ_B5_GAIN - [10:6] */
+#define WM8995_AIF1DAC1_EQ_B5_GAIN_SHIFT             6 /* AIF1DAC1_EQ_B5_GAIN - [10:6] */
+#define WM8995_AIF1DAC1_EQ_B5_GAIN_WIDTH             5 /* AIF1DAC1_EQ_B5_GAIN - [10:6] */
+
+/*
+ * R1154 (0x482) - AIF1 DAC1 EQ Band 1 A
+ */
+#define WM8995_AIF1DAC1_EQ_B1_A_MASK            0xFFFF /* AIF1DAC1_EQ_B1_A - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B1_A_SHIFT                0 /* AIF1DAC1_EQ_B1_A - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B1_A_WIDTH               16 /* AIF1DAC1_EQ_B1_A - [15:0] */
+
+/*
+ * R1155 (0x483) - AIF1 DAC1 EQ Band 1 B
+ */
+#define WM8995_AIF1DAC1_EQ_B1_B_MASK            0xFFFF /* AIF1DAC1_EQ_B1_B - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B1_B_SHIFT                0 /* AIF1DAC1_EQ_B1_B - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B1_B_WIDTH               16 /* AIF1DAC1_EQ_B1_B - [15:0] */
+
+/*
+ * R1156 (0x484) - AIF1 DAC1 EQ Band 1 PG
+ */
+#define WM8995_AIF1DAC1_EQ_B1_PG_MASK           0xFFFF /* AIF1DAC1_EQ_B1_PG - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B1_PG_SHIFT               0 /* AIF1DAC1_EQ_B1_PG - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B1_PG_WIDTH              16 /* AIF1DAC1_EQ_B1_PG - [15:0] */
+
+/*
+ * R1157 (0x485) - AIF1 DAC1 EQ Band 2 A
+ */
+#define WM8995_AIF1DAC1_EQ_B2_A_MASK            0xFFFF /* AIF1DAC1_EQ_B2_A - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B2_A_SHIFT                0 /* AIF1DAC1_EQ_B2_A - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B2_A_WIDTH               16 /* AIF1DAC1_EQ_B2_A - [15:0] */
+
+/*
+ * R1158 (0x486) - AIF1 DAC1 EQ Band 2 B
+ */
+#define WM8995_AIF1DAC1_EQ_B2_B_MASK            0xFFFF /* AIF1DAC1_EQ_B2_B - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B2_B_SHIFT                0 /* AIF1DAC1_EQ_B2_B - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B2_B_WIDTH               16 /* AIF1DAC1_EQ_B2_B - [15:0] */
+
+/*
+ * R1159 (0x487) - AIF1 DAC1 EQ Band 2 C
+ */
+#define WM8995_AIF1DAC1_EQ_B2_C_MASK            0xFFFF /* AIF1DAC1_EQ_B2_C - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B2_C_SHIFT                0 /* AIF1DAC1_EQ_B2_C - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B2_C_WIDTH               16 /* AIF1DAC1_EQ_B2_C - [15:0] */
+
+/*
+ * R1160 (0x488) - AIF1 DAC1 EQ Band 2 PG
+ */
+#define WM8995_AIF1DAC1_EQ_B2_PG_MASK           0xFFFF /* AIF1DAC1_EQ_B2_PG - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B2_PG_SHIFT               0 /* AIF1DAC1_EQ_B2_PG - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B2_PG_WIDTH              16 /* AIF1DAC1_EQ_B2_PG - [15:0] */
+
+/*
+ * R1161 (0x489) - AIF1 DAC1 EQ Band 3 A
+ */
+#define WM8995_AIF1DAC1_EQ_B3_A_MASK            0xFFFF /* AIF1DAC1_EQ_B3_A - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B3_A_SHIFT                0 /* AIF1DAC1_EQ_B3_A - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B3_A_WIDTH               16 /* AIF1DAC1_EQ_B3_A - [15:0] */
+
+/*
+ * R1162 (0x48A) - AIF1 DAC1 EQ Band 3 B
+ */
+#define WM8995_AIF1DAC1_EQ_B3_B_MASK            0xFFFF /* AIF1DAC1_EQ_B3_B - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B3_B_SHIFT                0 /* AIF1DAC1_EQ_B3_B - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B3_B_WIDTH               16 /* AIF1DAC1_EQ_B3_B - [15:0] */
+
+/*
+ * R1163 (0x48B) - AIF1 DAC1 EQ Band 3 C
+ */
+#define WM8995_AIF1DAC1_EQ_B3_C_MASK            0xFFFF /* AIF1DAC1_EQ_B3_C - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B3_C_SHIFT                0 /* AIF1DAC1_EQ_B3_C - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B3_C_WIDTH               16 /* AIF1DAC1_EQ_B3_C - [15:0] */
+
+/*
+ * R1164 (0x48C) - AIF1 DAC1 EQ Band 3 PG
+ */
+#define WM8995_AIF1DAC1_EQ_B3_PG_MASK           0xFFFF /* AIF1DAC1_EQ_B3_PG - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B3_PG_SHIFT               0 /* AIF1DAC1_EQ_B3_PG - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B3_PG_WIDTH              16 /* AIF1DAC1_EQ_B3_PG - [15:0] */
+
+/*
+ * R1165 (0x48D) - AIF1 DAC1 EQ Band 4 A
+ */
+#define WM8995_AIF1DAC1_EQ_B4_A_MASK            0xFFFF /* AIF1DAC1_EQ_B4_A - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B4_A_SHIFT                0 /* AIF1DAC1_EQ_B4_A - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B4_A_WIDTH               16 /* AIF1DAC1_EQ_B4_A - [15:0] */
+
+/*
+ * R1166 (0x48E) - AIF1 DAC1 EQ Band 4 B
+ */
+#define WM8995_AIF1DAC1_EQ_B4_B_MASK            0xFFFF /* AIF1DAC1_EQ_B4_B - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B4_B_SHIFT                0 /* AIF1DAC1_EQ_B4_B - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B4_B_WIDTH               16 /* AIF1DAC1_EQ_B4_B - [15:0] */
+
+/*
+ * R1167 (0x48F) - AIF1 DAC1 EQ Band 4 C
+ */
+#define WM8995_AIF1DAC1_EQ_B4_C_MASK            0xFFFF /* AIF1DAC1_EQ_B4_C - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B4_C_SHIFT                0 /* AIF1DAC1_EQ_B4_C - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B4_C_WIDTH               16 /* AIF1DAC1_EQ_B4_C - [15:0] */
+
+/*
+ * R1168 (0x490) - AIF1 DAC1 EQ Band 4 PG
+ */
+#define WM8995_AIF1DAC1_EQ_B4_PG_MASK           0xFFFF /* AIF1DAC1_EQ_B4_PG - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B4_PG_SHIFT               0 /* AIF1DAC1_EQ_B4_PG - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B4_PG_WIDTH              16 /* AIF1DAC1_EQ_B4_PG - [15:0] */
+
+/*
+ * R1169 (0x491) - AIF1 DAC1 EQ Band 5 A
+ */
+#define WM8995_AIF1DAC1_EQ_B5_A_MASK            0xFFFF /* AIF1DAC1_EQ_B5_A - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B5_A_SHIFT                0 /* AIF1DAC1_EQ_B5_A - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B5_A_WIDTH               16 /* AIF1DAC1_EQ_B5_A - [15:0] */
+
+/*
+ * R1170 (0x492) - AIF1 DAC1 EQ Band 5 B
+ */
+#define WM8995_AIF1DAC1_EQ_B5_B_MASK            0xFFFF /* AIF1DAC1_EQ_B5_B - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B5_B_SHIFT                0 /* AIF1DAC1_EQ_B5_B - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B5_B_WIDTH               16 /* AIF1DAC1_EQ_B5_B - [15:0] */
+
+/*
+ * R1171 (0x493) - AIF1 DAC1 EQ Band 5 PG
+ */
+#define WM8995_AIF1DAC1_EQ_B5_PG_MASK           0xFFFF /* AIF1DAC1_EQ_B5_PG - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B5_PG_SHIFT               0 /* AIF1DAC1_EQ_B5_PG - [15:0] */
+#define WM8995_AIF1DAC1_EQ_B5_PG_WIDTH              16 /* AIF1DAC1_EQ_B5_PG - [15:0] */
+
+/*
+ * R1184 (0x4A0) - AIF1 DAC2 EQ Gains (1)
+ */
+#define WM8995_AIF1DAC2_EQ_B1_GAIN_MASK         0xF800 /* AIF1DAC2_EQ_B1_GAIN - [15:11] */
+#define WM8995_AIF1DAC2_EQ_B1_GAIN_SHIFT            11 /* AIF1DAC2_EQ_B1_GAIN - [15:11] */
+#define WM8995_AIF1DAC2_EQ_B1_GAIN_WIDTH             5 /* AIF1DAC2_EQ_B1_GAIN - [15:11] */
+#define WM8995_AIF1DAC2_EQ_B2_GAIN_MASK         0x07C0 /* AIF1DAC2_EQ_B2_GAIN - [10:6] */
+#define WM8995_AIF1DAC2_EQ_B2_GAIN_SHIFT             6 /* AIF1DAC2_EQ_B2_GAIN - [10:6] */
+#define WM8995_AIF1DAC2_EQ_B2_GAIN_WIDTH             5 /* AIF1DAC2_EQ_B2_GAIN - [10:6] */
+#define WM8995_AIF1DAC2_EQ_B3_GAIN_MASK         0x003E /* AIF1DAC2_EQ_B3_GAIN - [5:1] */
+#define WM8995_AIF1DAC2_EQ_B3_GAIN_SHIFT             1 /* AIF1DAC2_EQ_B3_GAIN - [5:1] */
+#define WM8995_AIF1DAC2_EQ_B3_GAIN_WIDTH             5 /* AIF1DAC2_EQ_B3_GAIN - [5:1] */
+#define WM8995_AIF1DAC2_EQ_ENA                  0x0001 /* AIF1DAC2_EQ_ENA */
+#define WM8995_AIF1DAC2_EQ_ENA_MASK             0x0001 /* AIF1DAC2_EQ_ENA */
+#define WM8995_AIF1DAC2_EQ_ENA_SHIFT                 0 /* AIF1DAC2_EQ_ENA */
+#define WM8995_AIF1DAC2_EQ_ENA_WIDTH                 1 /* AIF1DAC2_EQ_ENA */
+
+/*
+ * R1185 (0x4A1) - AIF1 DAC2 EQ Gains (2)
+ */
+#define WM8995_AIF1DAC2_EQ_B4_GAIN_MASK         0xF800 /* AIF1DAC2_EQ_B4_GAIN - [15:11] */
+#define WM8995_AIF1DAC2_EQ_B4_GAIN_SHIFT            11 /* AIF1DAC2_EQ_B4_GAIN - [15:11] */
+#define WM8995_AIF1DAC2_EQ_B4_GAIN_WIDTH             5 /* AIF1DAC2_EQ_B4_GAIN - [15:11] */
+#define WM8995_AIF1DAC2_EQ_B5_GAIN_MASK         0x07C0 /* AIF1DAC2_EQ_B5_GAIN - [10:6] */
+#define WM8995_AIF1DAC2_EQ_B5_GAIN_SHIFT             6 /* AIF1DAC2_EQ_B5_GAIN - [10:6] */
+#define WM8995_AIF1DAC2_EQ_B5_GAIN_WIDTH             5 /* AIF1DAC2_EQ_B5_GAIN - [10:6] */
+
+/*
+ * R1186 (0x4A2) - AIF1 DAC2 EQ Band 1 A
+ */
+#define WM8995_AIF1DAC2_EQ_B1_A_MASK            0xFFFF /* AIF1DAC2_EQ_B1_A - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B1_A_SHIFT                0 /* AIF1DAC2_EQ_B1_A - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B1_A_WIDTH               16 /* AIF1DAC2_EQ_B1_A - [15:0] */
+
+/*
+ * R1187 (0x4A3) - AIF1 DAC2 EQ Band 1 B
+ */
+#define WM8995_AIF1DAC2_EQ_B1_B_MASK            0xFFFF /* AIF1DAC2_EQ_B1_B - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B1_B_SHIFT                0 /* AIF1DAC2_EQ_B1_B - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B1_B_WIDTH               16 /* AIF1DAC2_EQ_B1_B - [15:0] */
+
+/*
+ * R1188 (0x4A4) - AIF1 DAC2 EQ Band 1 PG
+ */
+#define WM8995_AIF1DAC2_EQ_B1_PG_MASK           0xFFFF /* AIF1DAC2_EQ_B1_PG - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B1_PG_SHIFT               0 /* AIF1DAC2_EQ_B1_PG - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B1_PG_WIDTH              16 /* AIF1DAC2_EQ_B1_PG - [15:0] */
+
+/*
+ * R1189 (0x4A5) - AIF1 DAC2 EQ Band 2 A
+ */
+#define WM8995_AIF1DAC2_EQ_B2_A_MASK            0xFFFF /* AIF1DAC2_EQ_B2_A - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B2_A_SHIFT                0 /* AIF1DAC2_EQ_B2_A - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B2_A_WIDTH               16 /* AIF1DAC2_EQ_B2_A - [15:0] */
+
+/*
+ * R1190 (0x4A6) - AIF1 DAC2 EQ Band 2 B
+ */
+#define WM8995_AIF1DAC2_EQ_B2_B_MASK            0xFFFF /* AIF1DAC2_EQ_B2_B - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B2_B_SHIFT                0 /* AIF1DAC2_EQ_B2_B - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B2_B_WIDTH               16 /* AIF1DAC2_EQ_B2_B - [15:0] */
+
+/*
+ * R1191 (0x4A7) - AIF1 DAC2 EQ Band 2 C
+ */
+#define WM8995_AIF1DAC2_EQ_B2_C_MASK            0xFFFF /* AIF1DAC2_EQ_B2_C - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B2_C_SHIFT                0 /* AIF1DAC2_EQ_B2_C - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B2_C_WIDTH               16 /* AIF1DAC2_EQ_B2_C - [15:0] */
+
+/*
+ * R1192 (0x4A8) - AIF1 DAC2 EQ Band 2 PG
+ */
+#define WM8995_AIF1DAC2_EQ_B2_PG_MASK           0xFFFF /* AIF1DAC2_EQ_B2_PG - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B2_PG_SHIFT               0 /* AIF1DAC2_EQ_B2_PG - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B2_PG_WIDTH              16 /* AIF1DAC2_EQ_B2_PG - [15:0] */
+
+/*
+ * R1193 (0x4A9) - AIF1 DAC2 EQ Band 3 A
+ */
+#define WM8995_AIF1DAC2_EQ_B3_A_MASK            0xFFFF /* AIF1DAC2_EQ_B3_A - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B3_A_SHIFT                0 /* AIF1DAC2_EQ_B3_A - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B3_A_WIDTH               16 /* AIF1DAC2_EQ_B3_A - [15:0] */
+
+/*
+ * R1194 (0x4AA) - AIF1 DAC2 EQ Band 3 B
+ */
+#define WM8995_AIF1DAC2_EQ_B3_B_MASK            0xFFFF /* AIF1DAC2_EQ_B3_B - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B3_B_SHIFT                0 /* AIF1DAC2_EQ_B3_B - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B3_B_WIDTH               16 /* AIF1DAC2_EQ_B3_B - [15:0] */
+
+/*
+ * R1195 (0x4AB) - AIF1 DAC2 EQ Band 3 C
+ */
+#define WM8995_AIF1DAC2_EQ_B3_C_MASK            0xFFFF /* AIF1DAC2_EQ_B3_C - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B3_C_SHIFT                0 /* AIF1DAC2_EQ_B3_C - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B3_C_WIDTH               16 /* AIF1DAC2_EQ_B3_C - [15:0] */
+
+/*
+ * R1196 (0x4AC) - AIF1 DAC2 EQ Band 3 PG
+ */
+#define WM8995_AIF1DAC2_EQ_B3_PG_MASK           0xFFFF /* AIF1DAC2_EQ_B3_PG - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B3_PG_SHIFT               0 /* AIF1DAC2_EQ_B3_PG - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B3_PG_WIDTH              16 /* AIF1DAC2_EQ_B3_PG - [15:0] */
+
+/*
+ * R1197 (0x4AD) - AIF1 DAC2 EQ Band 4 A
+ */
+#define WM8995_AIF1DAC2_EQ_B4_A_MASK            0xFFFF /* AIF1DAC2_EQ_B4_A - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B4_A_SHIFT                0 /* AIF1DAC2_EQ_B4_A - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B4_A_WIDTH               16 /* AIF1DAC2_EQ_B4_A - [15:0] */
+
+/*
+ * R1198 (0x4AE) - AIF1 DAC2 EQ Band 4 B
+ */
+#define WM8995_AIF1DAC2_EQ_B4_B_MASK            0xFFFF /* AIF1DAC2_EQ_B4_B - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B4_B_SHIFT                0 /* AIF1DAC2_EQ_B4_B - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B4_B_WIDTH               16 /* AIF1DAC2_EQ_B4_B - [15:0] */
+
+/*
+ * R1199 (0x4AF) - AIF1 DAC2 EQ Band 4 C
+ */
+#define WM8995_AIF1DAC2_EQ_B4_C_MASK            0xFFFF /* AIF1DAC2_EQ_B4_C - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B4_C_SHIFT                0 /* AIF1DAC2_EQ_B4_C - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B4_C_WIDTH               16 /* AIF1DAC2_EQ_B4_C - [15:0] */
+
+/*
+ * R1200 (0x4B0) - AIF1 DAC2 EQ Band 4 PG
+ */
+#define WM8995_AIF1DAC2_EQ_B4_PG_MASK           0xFFFF /* AIF1DAC2_EQ_B4_PG - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B4_PG_SHIFT               0 /* AIF1DAC2_EQ_B4_PG - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B4_PG_WIDTH              16 /* AIF1DAC2_EQ_B4_PG - [15:0] */
+
+/*
+ * R1201 (0x4B1) - AIF1 DAC2 EQ Band 5 A
+ */
+#define WM8995_AIF1DAC2_EQ_B5_A_MASK            0xFFFF /* AIF1DAC2_EQ_B5_A - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B5_A_SHIFT                0 /* AIF1DAC2_EQ_B5_A - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B5_A_WIDTH               16 /* AIF1DAC2_EQ_B5_A - [15:0] */
+
+/*
+ * R1202 (0x4B2) - AIF1 DAC2 EQ Band 5 B
+ */
+#define WM8995_AIF1DAC2_EQ_B5_B_MASK            0xFFFF /* AIF1DAC2_EQ_B5_B - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B5_B_SHIFT                0 /* AIF1DAC2_EQ_B5_B - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B5_B_WIDTH               16 /* AIF1DAC2_EQ_B5_B - [15:0] */
+
+/*
+ * R1203 (0x4B3) - AIF1 DAC2 EQ Band 5 PG
+ */
+#define WM8995_AIF1DAC2_EQ_B5_PG_MASK           0xFFFF /* AIF1DAC2_EQ_B5_PG - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B5_PG_SHIFT               0 /* AIF1DAC2_EQ_B5_PG - [15:0] */
+#define WM8995_AIF1DAC2_EQ_B5_PG_WIDTH              16 /* AIF1DAC2_EQ_B5_PG - [15:0] */
+
+/*
+ * R1280 (0x500) - AIF2 ADC Left Volume
+ */
+#define WM8995_AIF2ADC_VU                       0x0100 /* AIF2ADC_VU */
+#define WM8995_AIF2ADC_VU_MASK                  0x0100 /* AIF2ADC_VU */
+#define WM8995_AIF2ADC_VU_SHIFT                      8 /* AIF2ADC_VU */
+#define WM8995_AIF2ADC_VU_WIDTH                      1 /* AIF2ADC_VU */
+#define WM8995_AIF2ADCL_VOL_MASK                0x00FF /* AIF2ADCL_VOL - [7:0] */
+#define WM8995_AIF2ADCL_VOL_SHIFT                    0 /* AIF2ADCL_VOL - [7:0] */
+#define WM8995_AIF2ADCL_VOL_WIDTH                    8 /* AIF2ADCL_VOL - [7:0] */
+
+/*
+ * R1281 (0x501) - AIF2 ADC Right Volume
+ */
+#define WM8995_AIF2ADC_VU                       0x0100 /* AIF2ADC_VU */
+#define WM8995_AIF2ADC_VU_MASK                  0x0100 /* AIF2ADC_VU */
+#define WM8995_AIF2ADC_VU_SHIFT                      8 /* AIF2ADC_VU */
+#define WM8995_AIF2ADC_VU_WIDTH                      1 /* AIF2ADC_VU */
+#define WM8995_AIF2ADCR_VOL_MASK                0x00FF /* AIF2ADCR_VOL - [7:0] */
+#define WM8995_AIF2ADCR_VOL_SHIFT                    0 /* AIF2ADCR_VOL - [7:0] */
+#define WM8995_AIF2ADCR_VOL_WIDTH                    8 /* AIF2ADCR_VOL - [7:0] */
+
+/*
+ * R1282 (0x502) - AIF2 DAC Left Volume
+ */
+#define WM8995_AIF2DAC_VU                       0x0100 /* AIF2DAC_VU */
+#define WM8995_AIF2DAC_VU_MASK                  0x0100 /* AIF2DAC_VU */
+#define WM8995_AIF2DAC_VU_SHIFT                      8 /* AIF2DAC_VU */
+#define WM8995_AIF2DAC_VU_WIDTH                      1 /* AIF2DAC_VU */
+#define WM8995_AIF2DACL_VOL_MASK                0x00FF /* AIF2DACL_VOL - [7:0] */
+#define WM8995_AIF2DACL_VOL_SHIFT                    0 /* AIF2DACL_VOL - [7:0] */
+#define WM8995_AIF2DACL_VOL_WIDTH                    8 /* AIF2DACL_VOL - [7:0] */
+
+/*
+ * R1283 (0x503) - AIF2 DAC Right Volume
+ */
+#define WM8995_AIF2DAC_VU                       0x0100 /* AIF2DAC_VU */
+#define WM8995_AIF2DAC_VU_MASK                  0x0100 /* AIF2DAC_VU */
+#define WM8995_AIF2DAC_VU_SHIFT                      8 /* AIF2DAC_VU */
+#define WM8995_AIF2DAC_VU_WIDTH                      1 /* AIF2DAC_VU */
+#define WM8995_AIF2DACR_VOL_MASK                0x00FF /* AIF2DACR_VOL - [7:0] */
+#define WM8995_AIF2DACR_VOL_SHIFT                    0 /* AIF2DACR_VOL - [7:0] */
+#define WM8995_AIF2DACR_VOL_WIDTH                    8 /* AIF2DACR_VOL - [7:0] */
+
+/*
+ * R1296 (0x510) - AIF2 ADC Filters
+ */
+#define WM8995_AIF2ADC_4FS                      0x8000 /* AIF2ADC_4FS */
+#define WM8995_AIF2ADC_4FS_MASK                 0x8000 /* AIF2ADC_4FS */
+#define WM8995_AIF2ADC_4FS_SHIFT                    15 /* AIF2ADC_4FS */
+#define WM8995_AIF2ADC_4FS_WIDTH                     1 /* AIF2ADC_4FS */
+#define WM8995_AIF2ADCL_HPF                     0x1000 /* AIF2ADCL_HPF */
+#define WM8995_AIF2ADCL_HPF_MASK                0x1000 /* AIF2ADCL_HPF */
+#define WM8995_AIF2ADCL_HPF_SHIFT                   12 /* AIF2ADCL_HPF */
+#define WM8995_AIF2ADCL_HPF_WIDTH                    1 /* AIF2ADCL_HPF */
+#define WM8995_AIF2ADCR_HPF                     0x0800 /* AIF2ADCR_HPF */
+#define WM8995_AIF2ADCR_HPF_MASK                0x0800 /* AIF2ADCR_HPF */
+#define WM8995_AIF2ADCR_HPF_SHIFT                   11 /* AIF2ADCR_HPF */
+#define WM8995_AIF2ADCR_HPF_WIDTH                    1 /* AIF2ADCR_HPF */
+#define WM8995_AIF2ADC_HPF_MODE                 0x0008 /* AIF2ADC_HPF_MODE */
+#define WM8995_AIF2ADC_HPF_MODE_MASK            0x0008 /* AIF2ADC_HPF_MODE */
+#define WM8995_AIF2ADC_HPF_MODE_SHIFT                3 /* AIF2ADC_HPF_MODE */
+#define WM8995_AIF2ADC_HPF_MODE_WIDTH                1 /* AIF2ADC_HPF_MODE */
+#define WM8995_AIF2ADC_HPF_CUT_MASK             0x0007 /* AIF2ADC_HPF_CUT - [2:0] */
+#define WM8995_AIF2ADC_HPF_CUT_SHIFT                 0 /* AIF2ADC_HPF_CUT - [2:0] */
+#define WM8995_AIF2ADC_HPF_CUT_WIDTH                 3 /* AIF2ADC_HPF_CUT - [2:0] */
+
+/*
+ * R1312 (0x520) - AIF2 DAC Filters (1)
+ */
+#define WM8995_AIF2DAC_MUTE                     0x0200 /* AIF2DAC_MUTE */
+#define WM8995_AIF2DAC_MUTE_MASK                0x0200 /* AIF2DAC_MUTE */
+#define WM8995_AIF2DAC_MUTE_SHIFT                    9 /* AIF2DAC_MUTE */
+#define WM8995_AIF2DAC_MUTE_WIDTH                    1 /* AIF2DAC_MUTE */
+#define WM8995_AIF2DAC_MONO                     0x0080 /* AIF2DAC_MONO */
+#define WM8995_AIF2DAC_MONO_MASK                0x0080 /* AIF2DAC_MONO */
+#define WM8995_AIF2DAC_MONO_SHIFT                    7 /* AIF2DAC_MONO */
+#define WM8995_AIF2DAC_MONO_WIDTH                    1 /* AIF2DAC_MONO */
+#define WM8995_AIF2DAC_MUTERATE                 0x0020 /* AIF2DAC_MUTERATE */
+#define WM8995_AIF2DAC_MUTERATE_MASK            0x0020 /* AIF2DAC_MUTERATE */
+#define WM8995_AIF2DAC_MUTERATE_SHIFT                5 /* AIF2DAC_MUTERATE */
+#define WM8995_AIF2DAC_MUTERATE_WIDTH                1 /* AIF2DAC_MUTERATE */
+#define WM8995_AIF2DAC_UNMUTE_RAMP              0x0010 /* AIF2DAC_UNMUTE_RAMP */
+#define WM8995_AIF2DAC_UNMUTE_RAMP_MASK         0x0010 /* AIF2DAC_UNMUTE_RAMP */
+#define WM8995_AIF2DAC_UNMUTE_RAMP_SHIFT             4 /* AIF2DAC_UNMUTE_RAMP */
+#define WM8995_AIF2DAC_UNMUTE_RAMP_WIDTH             1 /* AIF2DAC_UNMUTE_RAMP */
+#define WM8995_AIF2DAC_DEEMP_MASK               0x0006 /* AIF2DAC_DEEMP - [2:1] */
+#define WM8995_AIF2DAC_DEEMP_SHIFT                   1 /* AIF2DAC_DEEMP - [2:1] */
+#define WM8995_AIF2DAC_DEEMP_WIDTH                   2 /* AIF2DAC_DEEMP - [2:1] */
+
+/*
+ * R1313 (0x521) - AIF2 DAC Filters (2)
+ */
+#define WM8995_AIF2DAC_3D_GAIN_MASK             0x3E00 /* AIF2DAC_3D_GAIN - [13:9] */
+#define WM8995_AIF2DAC_3D_GAIN_SHIFT                 9 /* AIF2DAC_3D_GAIN - [13:9] */
+#define WM8995_AIF2DAC_3D_GAIN_WIDTH                 5 /* AIF2DAC_3D_GAIN - [13:9] */
+#define WM8995_AIF2DAC_3D_ENA                   0x0100 /* AIF2DAC_3D_ENA */
+#define WM8995_AIF2DAC_3D_ENA_MASK              0x0100 /* AIF2DAC_3D_ENA */
+#define WM8995_AIF2DAC_3D_ENA_SHIFT                  8 /* AIF2DAC_3D_ENA */
+#define WM8995_AIF2DAC_3D_ENA_WIDTH                  1 /* AIF2DAC_3D_ENA */
+
+/*
+ * R1344 (0x540) - AIF2 DRC (1)
+ */
+#define WM8995_AIF2DRC_SIG_DET_RMS_MASK         0xF800 /* AIF2DRC_SIG_DET_RMS - [15:11] */
+#define WM8995_AIF2DRC_SIG_DET_RMS_SHIFT            11 /* AIF2DRC_SIG_DET_RMS - [15:11] */
+#define WM8995_AIF2DRC_SIG_DET_RMS_WIDTH             5 /* AIF2DRC_SIG_DET_RMS - [15:11] */
+#define WM8995_AIF2DRC_SIG_DET_PK_MASK          0x0600 /* AIF2DRC_SIG_DET_PK - [10:9] */
+#define WM8995_AIF2DRC_SIG_DET_PK_SHIFT              9 /* AIF2DRC_SIG_DET_PK - [10:9] */
+#define WM8995_AIF2DRC_SIG_DET_PK_WIDTH              2 /* AIF2DRC_SIG_DET_PK - [10:9] */
+#define WM8995_AIF2DRC_NG_ENA                   0x0100 /* AIF2DRC_NG_ENA */
+#define WM8995_AIF2DRC_NG_ENA_MASK              0x0100 /* AIF2DRC_NG_ENA */
+#define WM8995_AIF2DRC_NG_ENA_SHIFT                  8 /* AIF2DRC_NG_ENA */
+#define WM8995_AIF2DRC_NG_ENA_WIDTH                  1 /* AIF2DRC_NG_ENA */
+#define WM8995_AIF2DRC_SIG_DET_MODE             0x0080 /* AIF2DRC_SIG_DET_MODE */
+#define WM8995_AIF2DRC_SIG_DET_MODE_MASK        0x0080 /* AIF2DRC_SIG_DET_MODE */
+#define WM8995_AIF2DRC_SIG_DET_MODE_SHIFT            7 /* AIF2DRC_SIG_DET_MODE */
+#define WM8995_AIF2DRC_SIG_DET_MODE_WIDTH            1 /* AIF2DRC_SIG_DET_MODE */
+#define WM8995_AIF2DRC_SIG_DET                  0x0040 /* AIF2DRC_SIG_DET */
+#define WM8995_AIF2DRC_SIG_DET_MASK             0x0040 /* AIF2DRC_SIG_DET */
+#define WM8995_AIF2DRC_SIG_DET_SHIFT                 6 /* AIF2DRC_SIG_DET */
+#define WM8995_AIF2DRC_SIG_DET_WIDTH                 1 /* AIF2DRC_SIG_DET */
+#define WM8995_AIF2DRC_KNEE2_OP_ENA             0x0020 /* AIF2DRC_KNEE2_OP_ENA */
+#define WM8995_AIF2DRC_KNEE2_OP_ENA_MASK        0x0020 /* AIF2DRC_KNEE2_OP_ENA */
+#define WM8995_AIF2DRC_KNEE2_OP_ENA_SHIFT            5 /* AIF2DRC_KNEE2_OP_ENA */
+#define WM8995_AIF2DRC_KNEE2_OP_ENA_WIDTH            1 /* AIF2DRC_KNEE2_OP_ENA */
+#define WM8995_AIF2DRC_QR                       0x0010 /* AIF2DRC_QR */
+#define WM8995_AIF2DRC_QR_MASK                  0x0010 /* AIF2DRC_QR */
+#define WM8995_AIF2DRC_QR_SHIFT                      4 /* AIF2DRC_QR */
+#define WM8995_AIF2DRC_QR_WIDTH                      1 /* AIF2DRC_QR */
+#define WM8995_AIF2DRC_ANTICLIP                 0x0008 /* AIF2DRC_ANTICLIP */
+#define WM8995_AIF2DRC_ANTICLIP_MASK            0x0008 /* AIF2DRC_ANTICLIP */
+#define WM8995_AIF2DRC_ANTICLIP_SHIFT                3 /* AIF2DRC_ANTICLIP */
+#define WM8995_AIF2DRC_ANTICLIP_WIDTH                1 /* AIF2DRC_ANTICLIP */
+#define WM8995_AIF2DAC_DRC_ENA                  0x0004 /* AIF2DAC_DRC_ENA */
+#define WM8995_AIF2DAC_DRC_ENA_MASK             0x0004 /* AIF2DAC_DRC_ENA */
+#define WM8995_AIF2DAC_DRC_ENA_SHIFT                 2 /* AIF2DAC_DRC_ENA */
+#define WM8995_AIF2DAC_DRC_ENA_WIDTH                 1 /* AIF2DAC_DRC_ENA */
+#define WM8995_AIF2ADCL_DRC_ENA                 0x0002 /* AIF2ADCL_DRC_ENA */
+#define WM8995_AIF2ADCL_DRC_ENA_MASK            0x0002 /* AIF2ADCL_DRC_ENA */
+#define WM8995_AIF2ADCL_DRC_ENA_SHIFT                1 /* AIF2ADCL_DRC_ENA */
+#define WM8995_AIF2ADCL_DRC_ENA_WIDTH                1 /* AIF2ADCL_DRC_ENA */
+#define WM8995_AIF2ADCR_DRC_ENA                 0x0001 /* AIF2ADCR_DRC_ENA */
+#define WM8995_AIF2ADCR_DRC_ENA_MASK            0x0001 /* AIF2ADCR_DRC_ENA */
+#define WM8995_AIF2ADCR_DRC_ENA_SHIFT                0 /* AIF2ADCR_DRC_ENA */
+#define WM8995_AIF2ADCR_DRC_ENA_WIDTH                1 /* AIF2ADCR_DRC_ENA */
+
+/*
+ * R1345 (0x541) - AIF2 DRC (2)
+ */
+#define WM8995_AIF2DRC_ATK_MASK                 0x1E00 /* AIF2DRC_ATK - [12:9] */
+#define WM8995_AIF2DRC_ATK_SHIFT                     9 /* AIF2DRC_ATK - [12:9] */
+#define WM8995_AIF2DRC_ATK_WIDTH                     4 /* AIF2DRC_ATK - [12:9] */
+#define WM8995_AIF2DRC_DCY_MASK                 0x01E0 /* AIF2DRC_DCY - [8:5] */
+#define WM8995_AIF2DRC_DCY_SHIFT                     5 /* AIF2DRC_DCY - [8:5] */
+#define WM8995_AIF2DRC_DCY_WIDTH                     4 /* AIF2DRC_DCY - [8:5] */
+#define WM8995_AIF2DRC_MINGAIN_MASK             0x001C /* AIF2DRC_MINGAIN - [4:2] */
+#define WM8995_AIF2DRC_MINGAIN_SHIFT                 2 /* AIF2DRC_MINGAIN - [4:2] */
+#define WM8995_AIF2DRC_MINGAIN_WIDTH                 3 /* AIF2DRC_MINGAIN - [4:2] */
+#define WM8995_AIF2DRC_MAXGAIN_MASK             0x0003 /* AIF2DRC_MAXGAIN - [1:0] */
+#define WM8995_AIF2DRC_MAXGAIN_SHIFT                 0 /* AIF2DRC_MAXGAIN - [1:0] */
+#define WM8995_AIF2DRC_MAXGAIN_WIDTH                 2 /* AIF2DRC_MAXGAIN - [1:0] */
+
+/*
+ * R1346 (0x542) - AIF2 DRC (3)
+ */
+#define WM8995_AIF2DRC_NG_MINGAIN_MASK          0xF000 /* AIF2DRC_NG_MINGAIN - [15:12] */
+#define WM8995_AIF2DRC_NG_MINGAIN_SHIFT             12 /* AIF2DRC_NG_MINGAIN - [15:12] */
+#define WM8995_AIF2DRC_NG_MINGAIN_WIDTH              4 /* AIF2DRC_NG_MINGAIN - [15:12] */
+#define WM8995_AIF2DRC_NG_EXP_MASK              0x0C00 /* AIF2DRC_NG_EXP - [11:10] */
+#define WM8995_AIF2DRC_NG_EXP_SHIFT                 10 /* AIF2DRC_NG_EXP - [11:10] */
+#define WM8995_AIF2DRC_NG_EXP_WIDTH                  2 /* AIF2DRC_NG_EXP - [11:10] */
+#define WM8995_AIF2DRC_QR_THR_MASK              0x0300 /* AIF2DRC_QR_THR - [9:8] */
+#define WM8995_AIF2DRC_QR_THR_SHIFT                  8 /* AIF2DRC_QR_THR - [9:8] */
+#define WM8995_AIF2DRC_QR_THR_WIDTH                  2 /* AIF2DRC_QR_THR - [9:8] */
+#define WM8995_AIF2DRC_QR_DCY_MASK              0x00C0 /* AIF2DRC_QR_DCY - [7:6] */
+#define WM8995_AIF2DRC_QR_DCY_SHIFT                  6 /* AIF2DRC_QR_DCY - [7:6] */
+#define WM8995_AIF2DRC_QR_DCY_WIDTH                  2 /* AIF2DRC_QR_DCY - [7:6] */
+#define WM8995_AIF2DRC_HI_COMP_MASK             0x0038 /* AIF2DRC_HI_COMP - [5:3] */
+#define WM8995_AIF2DRC_HI_COMP_SHIFT                 3 /* AIF2DRC_HI_COMP - [5:3] */
+#define WM8995_AIF2DRC_HI_COMP_WIDTH                 3 /* AIF2DRC_HI_COMP - [5:3] */
+#define WM8995_AIF2DRC_LO_COMP_MASK             0x0007 /* AIF2DRC_LO_COMP - [2:0] */
+#define WM8995_AIF2DRC_LO_COMP_SHIFT                 0 /* AIF2DRC_LO_COMP - [2:0] */
+#define WM8995_AIF2DRC_LO_COMP_WIDTH                 3 /* AIF2DRC_LO_COMP - [2:0] */
+
+/*
+ * R1347 (0x543) - AIF2 DRC (4)
+ */
+#define WM8995_AIF2DRC_KNEE_IP_MASK             0x07E0 /* AIF2DRC_KNEE_IP - [10:5] */
+#define WM8995_AIF2DRC_KNEE_IP_SHIFT                 5 /* AIF2DRC_KNEE_IP - [10:5] */
+#define WM8995_AIF2DRC_KNEE_IP_WIDTH                 6 /* AIF2DRC_KNEE_IP - [10:5] */
+#define WM8995_AIF2DRC_KNEE_OP_MASK             0x001F /* AIF2DRC_KNEE_OP - [4:0] */
+#define WM8995_AIF2DRC_KNEE_OP_SHIFT                 0 /* AIF2DRC_KNEE_OP - [4:0] */
+#define WM8995_AIF2DRC_KNEE_OP_WIDTH                 5 /* AIF2DRC_KNEE_OP - [4:0] */
+
+/*
+ * R1348 (0x544) - AIF2 DRC (5)
+ */
+#define WM8995_AIF2DRC_KNEE2_IP_MASK            0x03E0 /* AIF2DRC_KNEE2_IP - [9:5] */
+#define WM8995_AIF2DRC_KNEE2_IP_SHIFT                5 /* AIF2DRC_KNEE2_IP - [9:5] */
+#define WM8995_AIF2DRC_KNEE2_IP_WIDTH                5 /* AIF2DRC_KNEE2_IP - [9:5] */
+#define WM8995_AIF2DRC_KNEE2_OP_MASK            0x001F /* AIF2DRC_KNEE2_OP - [4:0] */
+#define WM8995_AIF2DRC_KNEE2_OP_SHIFT                0 /* AIF2DRC_KNEE2_OP - [4:0] */
+#define WM8995_AIF2DRC_KNEE2_OP_WIDTH                5 /* AIF2DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R1408 (0x580) - AIF2 EQ Gains (1)
+ */
+#define WM8995_AIF2DAC_EQ_B1_GAIN_MASK          0xF800 /* AIF2DAC_EQ_B1_GAIN - [15:11] */
+#define WM8995_AIF2DAC_EQ_B1_GAIN_SHIFT             11 /* AIF2DAC_EQ_B1_GAIN - [15:11] */
+#define WM8995_AIF2DAC_EQ_B1_GAIN_WIDTH              5 /* AIF2DAC_EQ_B1_GAIN - [15:11] */
+#define WM8995_AIF2DAC_EQ_B2_GAIN_MASK          0x07C0 /* AIF2DAC_EQ_B2_GAIN - [10:6] */
+#define WM8995_AIF2DAC_EQ_B2_GAIN_SHIFT              6 /* AIF2DAC_EQ_B2_GAIN - [10:6] */
+#define WM8995_AIF2DAC_EQ_B2_GAIN_WIDTH              5 /* AIF2DAC_EQ_B2_GAIN - [10:6] */
+#define WM8995_AIF2DAC_EQ_B3_GAIN_MASK          0x003E /* AIF2DAC_EQ_B3_GAIN - [5:1] */
+#define WM8995_AIF2DAC_EQ_B3_GAIN_SHIFT              1 /* AIF2DAC_EQ_B3_GAIN - [5:1] */
+#define WM8995_AIF2DAC_EQ_B3_GAIN_WIDTH              5 /* AIF2DAC_EQ_B3_GAIN - [5:1] */
+#define WM8995_AIF2DAC_EQ_ENA                   0x0001 /* AIF2DAC_EQ_ENA */
+#define WM8995_AIF2DAC_EQ_ENA_MASK              0x0001 /* AIF2DAC_EQ_ENA */
+#define WM8995_AIF2DAC_EQ_ENA_SHIFT                  0 /* AIF2DAC_EQ_ENA */
+#define WM8995_AIF2DAC_EQ_ENA_WIDTH                  1 /* AIF2DAC_EQ_ENA */
+
+/*
+ * R1409 (0x581) - AIF2 EQ Gains (2)
+ */
+#define WM8995_AIF2DAC_EQ_B4_GAIN_MASK          0xF800 /* AIF2DAC_EQ_B4_GAIN - [15:11] */
+#define WM8995_AIF2DAC_EQ_B4_GAIN_SHIFT             11 /* AIF2DAC_EQ_B4_GAIN - [15:11] */
+#define WM8995_AIF2DAC_EQ_B4_GAIN_WIDTH              5 /* AIF2DAC_EQ_B4_GAIN - [15:11] */
+#define WM8995_AIF2DAC_EQ_B5_GAIN_MASK          0x07C0 /* AIF2DAC_EQ_B5_GAIN - [10:6] */
+#define WM8995_AIF2DAC_EQ_B5_GAIN_SHIFT              6 /* AIF2DAC_EQ_B5_GAIN - [10:6] */
+#define WM8995_AIF2DAC_EQ_B5_GAIN_WIDTH              5 /* AIF2DAC_EQ_B5_GAIN - [10:6] */
+
+/*
+ * R1410 (0x582) - AIF2 EQ Band 1 A
+ */
+#define WM8995_AIF2DAC_EQ_B1_A_MASK             0xFFFF /* AIF2DAC_EQ_B1_A - [15:0] */
+#define WM8995_AIF2DAC_EQ_B1_A_SHIFT                 0 /* AIF2DAC_EQ_B1_A - [15:0] */
+#define WM8995_AIF2DAC_EQ_B1_A_WIDTH                16 /* AIF2DAC_EQ_B1_A - [15:0] */
+
+/*
+ * R1411 (0x583) - AIF2 EQ Band 1 B
+ */
+#define WM8995_AIF2DAC_EQ_B1_B_MASK             0xFFFF /* AIF2DAC_EQ_B1_B - [15:0] */
+#define WM8995_AIF2DAC_EQ_B1_B_SHIFT                 0 /* AIF2DAC_EQ_B1_B - [15:0] */
+#define WM8995_AIF2DAC_EQ_B1_B_WIDTH                16 /* AIF2DAC_EQ_B1_B - [15:0] */
+
+/*
+ * R1412 (0x584) - AIF2 EQ Band 1 PG
+ */
+#define WM8995_AIF2DAC_EQ_B1_PG_MASK            0xFFFF /* AIF2DAC_EQ_B1_PG - [15:0] */
+#define WM8995_AIF2DAC_EQ_B1_PG_SHIFT                0 /* AIF2DAC_EQ_B1_PG - [15:0] */
+#define WM8995_AIF2DAC_EQ_B1_PG_WIDTH               16 /* AIF2DAC_EQ_B1_PG - [15:0] */
+
+/*
+ * R1413 (0x585) - AIF2 EQ Band 2 A
+ */
+#define WM8995_AIF2DAC_EQ_B2_A_MASK             0xFFFF /* AIF2DAC_EQ_B2_A - [15:0] */
+#define WM8995_AIF2DAC_EQ_B2_A_SHIFT                 0 /* AIF2DAC_EQ_B2_A - [15:0] */
+#define WM8995_AIF2DAC_EQ_B2_A_WIDTH                16 /* AIF2DAC_EQ_B2_A - [15:0] */
+
+/*
+ * R1414 (0x586) - AIF2 EQ Band 2 B
+ */
+#define WM8995_AIF2DAC_EQ_B2_B_MASK             0xFFFF /* AIF2DAC_EQ_B2_B - [15:0] */
+#define WM8995_AIF2DAC_EQ_B2_B_SHIFT                 0 /* AIF2DAC_EQ_B2_B - [15:0] */
+#define WM8995_AIF2DAC_EQ_B2_B_WIDTH                16 /* AIF2DAC_EQ_B2_B - [15:0] */
+
+/*
+ * R1415 (0x587) - AIF2 EQ Band 2 C
+ */
+#define WM8995_AIF2DAC_EQ_B2_C_MASK             0xFFFF /* AIF2DAC_EQ_B2_C - [15:0] */
+#define WM8995_AIF2DAC_EQ_B2_C_SHIFT                 0 /* AIF2DAC_EQ_B2_C - [15:0] */
+#define WM8995_AIF2DAC_EQ_B2_C_WIDTH                16 /* AIF2DAC_EQ_B2_C - [15:0] */
+
+/*
+ * R1416 (0x588) - AIF2 EQ Band 2 PG
+ */
+#define WM8995_AIF2DAC_EQ_B2_PG_MASK            0xFFFF /* AIF2DAC_EQ_B2_PG - [15:0] */
+#define WM8995_AIF2DAC_EQ_B2_PG_SHIFT                0 /* AIF2DAC_EQ_B2_PG - [15:0] */
+#define WM8995_AIF2DAC_EQ_B2_PG_WIDTH               16 /* AIF2DAC_EQ_B2_PG - [15:0] */
+
+/*
+ * R1417 (0x589) - AIF2 EQ Band 3 A
+ */
+#define WM8995_AIF2DAC_EQ_B3_A_MASK             0xFFFF /* AIF2DAC_EQ_B3_A - [15:0] */
+#define WM8995_AIF2DAC_EQ_B3_A_SHIFT                 0 /* AIF2DAC_EQ_B3_A - [15:0] */
+#define WM8995_AIF2DAC_EQ_B3_A_WIDTH                16 /* AIF2DAC_EQ_B3_A - [15:0] */
+
+/*
+ * R1418 (0x58A) - AIF2 EQ Band 3 B
+ */
+#define WM8995_AIF2DAC_EQ_B3_B_MASK             0xFFFF /* AIF2DAC_EQ_B3_B - [15:0] */
+#define WM8995_AIF2DAC_EQ_B3_B_SHIFT                 0 /* AIF2DAC_EQ_B3_B - [15:0] */
+#define WM8995_AIF2DAC_EQ_B3_B_WIDTH                16 /* AIF2DAC_EQ_B3_B - [15:0] */
+
+/*
+ * R1419 (0x58B) - AIF2 EQ Band 3 C
+ */
+#define WM8995_AIF2DAC_EQ_B3_C_MASK             0xFFFF /* AIF2DAC_EQ_B3_C - [15:0] */
+#define WM8995_AIF2DAC_EQ_B3_C_SHIFT                 0 /* AIF2DAC_EQ_B3_C - [15:0] */
+#define WM8995_AIF2DAC_EQ_B3_C_WIDTH                16 /* AIF2DAC_EQ_B3_C - [15:0] */
+
+/*
+ * R1420 (0x58C) - AIF2 EQ Band 3 PG
+ */
+#define WM8995_AIF2DAC_EQ_B3_PG_MASK            0xFFFF /* AIF2DAC_EQ_B3_PG - [15:0] */
+#define WM8995_AIF2DAC_EQ_B3_PG_SHIFT                0 /* AIF2DAC_EQ_B3_PG - [15:0] */
+#define WM8995_AIF2DAC_EQ_B3_PG_WIDTH               16 /* AIF2DAC_EQ_B3_PG - [15:0] */
+
+/*
+ * R1421 (0x58D) - AIF2 EQ Band 4 A
+ */
+#define WM8995_AIF2DAC_EQ_B4_A_MASK             0xFFFF /* AIF2DAC_EQ_B4_A - [15:0] */
+#define WM8995_AIF2DAC_EQ_B4_A_SHIFT                 0 /* AIF2DAC_EQ_B4_A - [15:0] */
+#define WM8995_AIF2DAC_EQ_B4_A_WIDTH                16 /* AIF2DAC_EQ_B4_A - [15:0] */
+
+/*
+ * R1422 (0x58E) - AIF2 EQ Band 4 B
+ */
+#define WM8995_AIF2DAC_EQ_B4_B_MASK             0xFFFF /* AIF2DAC_EQ_B4_B - [15:0] */
+#define WM8995_AIF2DAC_EQ_B4_B_SHIFT                 0 /* AIF2DAC_EQ_B4_B - [15:0] */
+#define WM8995_AIF2DAC_EQ_B4_B_WIDTH                16 /* AIF2DAC_EQ_B4_B - [15:0] */
+
+/*
+ * R1423 (0x58F) - AIF2 EQ Band 4 C
+ */
+#define WM8995_AIF2DAC_EQ_B4_C_MASK             0xFFFF /* AIF2DAC_EQ_B4_C - [15:0] */
+#define WM8995_AIF2DAC_EQ_B4_C_SHIFT                 0 /* AIF2DAC_EQ_B4_C - [15:0] */
+#define WM8995_AIF2DAC_EQ_B4_C_WIDTH                16 /* AIF2DAC_EQ_B4_C - [15:0] */
+
+/*
+ * R1424 (0x590) - AIF2 EQ Band 4 PG
+ */
+#define WM8995_AIF2DAC_EQ_B4_PG_MASK            0xFFFF /* AIF2DAC_EQ_B4_PG - [15:0] */
+#define WM8995_AIF2DAC_EQ_B4_PG_SHIFT                0 /* AIF2DAC_EQ_B4_PG - [15:0] */
+#define WM8995_AIF2DAC_EQ_B4_PG_WIDTH               16 /* AIF2DAC_EQ_B4_PG - [15:0] */
+
+/*
+ * R1425 (0x591) - AIF2 EQ Band 5 A
+ */
+#define WM8995_AIF2DAC_EQ_B5_A_MASK             0xFFFF /* AIF2DAC_EQ_B5_A - [15:0] */
+#define WM8995_AIF2DAC_EQ_B5_A_SHIFT                 0 /* AIF2DAC_EQ_B5_A - [15:0] */
+#define WM8995_AIF2DAC_EQ_B5_A_WIDTH                16 /* AIF2DAC_EQ_B5_A - [15:0] */
+
+/*
+ * R1426 (0x592) - AIF2 EQ Band 5 B
+ */
+#define WM8995_AIF2DAC_EQ_B5_B_MASK             0xFFFF /* AIF2DAC_EQ_B5_B - [15:0] */
+#define WM8995_AIF2DAC_EQ_B5_B_SHIFT                 0 /* AIF2DAC_EQ_B5_B - [15:0] */
+#define WM8995_AIF2DAC_EQ_B5_B_WIDTH                16 /* AIF2DAC_EQ_B5_B - [15:0] */
+
+/*
+ * R1427 (0x593) - AIF2 EQ Band 5 PG
+ */
+#define WM8995_AIF2DAC_EQ_B5_PG_MASK            0xFFFF /* AIF2DAC_EQ_B5_PG - [15:0] */
+#define WM8995_AIF2DAC_EQ_B5_PG_SHIFT                0 /* AIF2DAC_EQ_B5_PG - [15:0] */
+#define WM8995_AIF2DAC_EQ_B5_PG_WIDTH               16 /* AIF2DAC_EQ_B5_PG - [15:0] */
+
+/*
+ * R1536 (0x600) - DAC1 Mixer Volumes
+ */
+#define WM8995_ADCR_DAC1_VOL_MASK               0x03E0 /* ADCR_DAC1_VOL - [9:5] */
+#define WM8995_ADCR_DAC1_VOL_SHIFT                   5 /* ADCR_DAC1_VOL - [9:5] */
+#define WM8995_ADCR_DAC1_VOL_WIDTH                   5 /* ADCR_DAC1_VOL - [9:5] */
+#define WM8995_ADCL_DAC1_VOL_MASK               0x001F /* ADCL_DAC1_VOL - [4:0] */
+#define WM8995_ADCL_DAC1_VOL_SHIFT                   0 /* ADCL_DAC1_VOL - [4:0] */
+#define WM8995_ADCL_DAC1_VOL_WIDTH                   5 /* ADCL_DAC1_VOL - [4:0] */
+
+/*
+ * R1537 (0x601) - DAC1 Left Mixer Routing
+ */
+#define WM8995_ADCR_TO_DAC1L                    0x0020 /* ADCR_TO_DAC1L */
+#define WM8995_ADCR_TO_DAC1L_MASK               0x0020 /* ADCR_TO_DAC1L */
+#define WM8995_ADCR_TO_DAC1L_SHIFT                   5 /* ADCR_TO_DAC1L */
+#define WM8995_ADCR_TO_DAC1L_WIDTH                   1 /* ADCR_TO_DAC1L */
+#define WM8995_ADCL_TO_DAC1L                    0x0010 /* ADCL_TO_DAC1L */
+#define WM8995_ADCL_TO_DAC1L_MASK               0x0010 /* ADCL_TO_DAC1L */
+#define WM8995_ADCL_TO_DAC1L_SHIFT                   4 /* ADCL_TO_DAC1L */
+#define WM8995_ADCL_TO_DAC1L_WIDTH                   1 /* ADCL_TO_DAC1L */
+#define WM8995_AIF2DACL_TO_DAC1L                0x0004 /* AIF2DACL_TO_DAC1L */
+#define WM8995_AIF2DACL_TO_DAC1L_MASK           0x0004 /* AIF2DACL_TO_DAC1L */
+#define WM8995_AIF2DACL_TO_DAC1L_SHIFT               2 /* AIF2DACL_TO_DAC1L */
+#define WM8995_AIF2DACL_TO_DAC1L_WIDTH               1 /* AIF2DACL_TO_DAC1L */
+#define WM8995_AIF1DAC2L_TO_DAC1L               0x0002 /* AIF1DAC2L_TO_DAC1L */
+#define WM8995_AIF1DAC2L_TO_DAC1L_MASK          0x0002 /* AIF1DAC2L_TO_DAC1L */
+#define WM8995_AIF1DAC2L_TO_DAC1L_SHIFT              1 /* AIF1DAC2L_TO_DAC1L */
+#define WM8995_AIF1DAC2L_TO_DAC1L_WIDTH              1 /* AIF1DAC2L_TO_DAC1L */
+#define WM8995_AIF1DAC1L_TO_DAC1L               0x0001 /* AIF1DAC1L_TO_DAC1L */
+#define WM8995_AIF1DAC1L_TO_DAC1L_MASK          0x0001 /* AIF1DAC1L_TO_DAC1L */
+#define WM8995_AIF1DAC1L_TO_DAC1L_SHIFT              0 /* AIF1DAC1L_TO_DAC1L */
+#define WM8995_AIF1DAC1L_TO_DAC1L_WIDTH              1 /* AIF1DAC1L_TO_DAC1L */
+
+/*
+ * R1538 (0x602) - DAC1 Right Mixer Routing
+ */
+#define WM8995_ADCR_TO_DAC1R                    0x0020 /* ADCR_TO_DAC1R */
+#define WM8995_ADCR_TO_DAC1R_MASK               0x0020 /* ADCR_TO_DAC1R */
+#define WM8995_ADCR_TO_DAC1R_SHIFT                   5 /* ADCR_TO_DAC1R */
+#define WM8995_ADCR_TO_DAC1R_WIDTH                   1 /* ADCR_TO_DAC1R */
+#define WM8995_ADCL_TO_DAC1R                    0x0010 /* ADCL_TO_DAC1R */
+#define WM8995_ADCL_TO_DAC1R_MASK               0x0010 /* ADCL_TO_DAC1R */
+#define WM8995_ADCL_TO_DAC1R_SHIFT                   4 /* ADCL_TO_DAC1R */
+#define WM8995_ADCL_TO_DAC1R_WIDTH                   1 /* ADCL_TO_DAC1R */
+#define WM8995_AIF2DACR_TO_DAC1R                0x0004 /* AIF2DACR_TO_DAC1R */
+#define WM8995_AIF2DACR_TO_DAC1R_MASK           0x0004 /* AIF2DACR_TO_DAC1R */
+#define WM8995_AIF2DACR_TO_DAC1R_SHIFT               2 /* AIF2DACR_TO_DAC1R */
+#define WM8995_AIF2DACR_TO_DAC1R_WIDTH               1 /* AIF2DACR_TO_DAC1R */
+#define WM8995_AIF1DAC2R_TO_DAC1R               0x0002 /* AIF1DAC2R_TO_DAC1R */
+#define WM8995_AIF1DAC2R_TO_DAC1R_MASK          0x0002 /* AIF1DAC2R_TO_DAC1R */
+#define WM8995_AIF1DAC2R_TO_DAC1R_SHIFT              1 /* AIF1DAC2R_TO_DAC1R */
+#define WM8995_AIF1DAC2R_TO_DAC1R_WIDTH              1 /* AIF1DAC2R_TO_DAC1R */
+#define WM8995_AIF1DAC1R_TO_DAC1R               0x0001 /* AIF1DAC1R_TO_DAC1R */
+#define WM8995_AIF1DAC1R_TO_DAC1R_MASK          0x0001 /* AIF1DAC1R_TO_DAC1R */
+#define WM8995_AIF1DAC1R_TO_DAC1R_SHIFT              0 /* AIF1DAC1R_TO_DAC1R */
+#define WM8995_AIF1DAC1R_TO_DAC1R_WIDTH              1 /* AIF1DAC1R_TO_DAC1R */
+
+/*
+ * R1539 (0x603) - DAC2 Mixer Volumes
+ */
+#define WM8995_ADCR_DAC2_VOL_MASK               0x03E0 /* ADCR_DAC2_VOL - [9:5] */
+#define WM8995_ADCR_DAC2_VOL_SHIFT                   5 /* ADCR_DAC2_VOL - [9:5] */
+#define WM8995_ADCR_DAC2_VOL_WIDTH                   5 /* ADCR_DAC2_VOL - [9:5] */
+#define WM8995_ADCL_DAC2_VOL_MASK               0x001F /* ADCL_DAC2_VOL - [4:0] */
+#define WM8995_ADCL_DAC2_VOL_SHIFT                   0 /* ADCL_DAC2_VOL - [4:0] */
+#define WM8995_ADCL_DAC2_VOL_WIDTH                   5 /* ADCL_DAC2_VOL - [4:0] */
+
+/*
+ * R1540 (0x604) - DAC2 Left Mixer Routing
+ */
+#define WM8995_ADCR_TO_DAC2L                    0x0020 /* ADCR_TO_DAC2L */
+#define WM8995_ADCR_TO_DAC2L_MASK               0x0020 /* ADCR_TO_DAC2L */
+#define WM8995_ADCR_TO_DAC2L_SHIFT                   5 /* ADCR_TO_DAC2L */
+#define WM8995_ADCR_TO_DAC2L_WIDTH                   1 /* ADCR_TO_DAC2L */
+#define WM8995_ADCL_TO_DAC2L                    0x0010 /* ADCL_TO_DAC2L */
+#define WM8995_ADCL_TO_DAC2L_MASK               0x0010 /* ADCL_TO_DAC2L */
+#define WM8995_ADCL_TO_DAC2L_SHIFT                   4 /* ADCL_TO_DAC2L */
+#define WM8995_ADCL_TO_DAC2L_WIDTH                   1 /* ADCL_TO_DAC2L */
+#define WM8995_AIF2DACL_TO_DAC2L                0x0004 /* AIF2DACL_TO_DAC2L */
+#define WM8995_AIF2DACL_TO_DAC2L_MASK           0x0004 /* AIF2DACL_TO_DAC2L */
+#define WM8995_AIF2DACL_TO_DAC2L_SHIFT               2 /* AIF2DACL_TO_DAC2L */
+#define WM8995_AIF2DACL_TO_DAC2L_WIDTH               1 /* AIF2DACL_TO_DAC2L */
+#define WM8995_AIF1DAC2L_TO_DAC2L               0x0002 /* AIF1DAC2L_TO_DAC2L */
+#define WM8995_AIF1DAC2L_TO_DAC2L_MASK          0x0002 /* AIF1DAC2L_TO_DAC2L */
+#define WM8995_AIF1DAC2L_TO_DAC2L_SHIFT              1 /* AIF1DAC2L_TO_DAC2L */
+#define WM8995_AIF1DAC2L_TO_DAC2L_WIDTH              1 /* AIF1DAC2L_TO_DAC2L */
+#define WM8995_AIF1DAC1L_TO_DAC2L               0x0001 /* AIF1DAC1L_TO_DAC2L */
+#define WM8995_AIF1DAC1L_TO_DAC2L_MASK          0x0001 /* AIF1DAC1L_TO_DAC2L */
+#define WM8995_AIF1DAC1L_TO_DAC2L_SHIFT              0 /* AIF1DAC1L_TO_DAC2L */
+#define WM8995_AIF1DAC1L_TO_DAC2L_WIDTH              1 /* AIF1DAC1L_TO_DAC2L */
+
+/*
+ * R1541 (0x605) - DAC2 Right Mixer Routing
+ */
+#define WM8995_ADCR_TO_DAC2R                    0x0020 /* ADCR_TO_DAC2R */
+#define WM8995_ADCR_TO_DAC2R_MASK               0x0020 /* ADCR_TO_DAC2R */
+#define WM8995_ADCR_TO_DAC2R_SHIFT                   5 /* ADCR_TO_DAC2R */
+#define WM8995_ADCR_TO_DAC2R_WIDTH                   1 /* ADCR_TO_DAC2R */
+#define WM8995_ADCL_TO_DAC2R                    0x0010 /* ADCL_TO_DAC2R */
+#define WM8995_ADCL_TO_DAC2R_MASK               0x0010 /* ADCL_TO_DAC2R */
+#define WM8995_ADCL_TO_DAC2R_SHIFT                   4 /* ADCL_TO_DAC2R */
+#define WM8995_ADCL_TO_DAC2R_WIDTH                   1 /* ADCL_TO_DAC2R */
+#define WM8995_AIF2DACR_TO_DAC2R                0x0004 /* AIF2DACR_TO_DAC2R */
+#define WM8995_AIF2DACR_TO_DAC2R_MASK           0x0004 /* AIF2DACR_TO_DAC2R */
+#define WM8995_AIF2DACR_TO_DAC2R_SHIFT               2 /* AIF2DACR_TO_DAC2R */
+#define WM8995_AIF2DACR_TO_DAC2R_WIDTH               1 /* AIF2DACR_TO_DAC2R */
+#define WM8995_AIF1DAC2R_TO_DAC2R               0x0002 /* AIF1DAC2R_TO_DAC2R */
+#define WM8995_AIF1DAC2R_TO_DAC2R_MASK          0x0002 /* AIF1DAC2R_TO_DAC2R */
+#define WM8995_AIF1DAC2R_TO_DAC2R_SHIFT              1 /* AIF1DAC2R_TO_DAC2R */
+#define WM8995_AIF1DAC2R_TO_DAC2R_WIDTH              1 /* AIF1DAC2R_TO_DAC2R */
+#define WM8995_AIF1DAC1R_TO_DAC2R               0x0001 /* AIF1DAC1R_TO_DAC2R */
+#define WM8995_AIF1DAC1R_TO_DAC2R_MASK          0x0001 /* AIF1DAC1R_TO_DAC2R */
+#define WM8995_AIF1DAC1R_TO_DAC2R_SHIFT              0 /* AIF1DAC1R_TO_DAC2R */
+#define WM8995_AIF1DAC1R_TO_DAC2R_WIDTH              1 /* AIF1DAC1R_TO_DAC2R */
+
+/*
+ * R1542 (0x606) - AIF1 ADC1 Left Mixer Routing
+ */
+#define WM8995_ADC1L_TO_AIF1ADC1L               0x0002 /* ADC1L_TO_AIF1ADC1L */
+#define WM8995_ADC1L_TO_AIF1ADC1L_MASK          0x0002 /* ADC1L_TO_AIF1ADC1L */
+#define WM8995_ADC1L_TO_AIF1ADC1L_SHIFT              1 /* ADC1L_TO_AIF1ADC1L */
+#define WM8995_ADC1L_TO_AIF1ADC1L_WIDTH              1 /* ADC1L_TO_AIF1ADC1L */
+#define WM8995_AIF2DACL_TO_AIF1ADC1L            0x0001 /* AIF2DACL_TO_AIF1ADC1L */
+#define WM8995_AIF2DACL_TO_AIF1ADC1L_MASK       0x0001 /* AIF2DACL_TO_AIF1ADC1L */
+#define WM8995_AIF2DACL_TO_AIF1ADC1L_SHIFT           0 /* AIF2DACL_TO_AIF1ADC1L */
+#define WM8995_AIF2DACL_TO_AIF1ADC1L_WIDTH           1 /* AIF2DACL_TO_AIF1ADC1L */
+
+/*
+ * R1543 (0x607) - AIF1 ADC1 Right Mixer Routing
+ */
+#define WM8995_ADC1R_TO_AIF1ADC1R               0x0002 /* ADC1R_TO_AIF1ADC1R */
+#define WM8995_ADC1R_TO_AIF1ADC1R_MASK          0x0002 /* ADC1R_TO_AIF1ADC1R */
+#define WM8995_ADC1R_TO_AIF1ADC1R_SHIFT              1 /* ADC1R_TO_AIF1ADC1R */
+#define WM8995_ADC1R_TO_AIF1ADC1R_WIDTH              1 /* ADC1R_TO_AIF1ADC1R */
+#define WM8995_AIF2DACR_TO_AIF1ADC1R            0x0001 /* AIF2DACR_TO_AIF1ADC1R */
+#define WM8995_AIF2DACR_TO_AIF1ADC1R_MASK       0x0001 /* AIF2DACR_TO_AIF1ADC1R */
+#define WM8995_AIF2DACR_TO_AIF1ADC1R_SHIFT           0 /* AIF2DACR_TO_AIF1ADC1R */
+#define WM8995_AIF2DACR_TO_AIF1ADC1R_WIDTH           1 /* AIF2DACR_TO_AIF1ADC1R */
+
+/*
+ * R1544 (0x608) - AIF1 ADC2 Left Mixer Routing
+ */
+#define WM8995_ADC2L_TO_AIF1ADC2L               0x0002 /* ADC2L_TO_AIF1ADC2L */
+#define WM8995_ADC2L_TO_AIF1ADC2L_MASK          0x0002 /* ADC2L_TO_AIF1ADC2L */
+#define WM8995_ADC2L_TO_AIF1ADC2L_SHIFT              1 /* ADC2L_TO_AIF1ADC2L */
+#define WM8995_ADC2L_TO_AIF1ADC2L_WIDTH              1 /* ADC2L_TO_AIF1ADC2L */
+#define WM8995_AIF2DACL_TO_AIF1ADC2L            0x0001 /* AIF2DACL_TO_AIF1ADC2L */
+#define WM8995_AIF2DACL_TO_AIF1ADC2L_MASK       0x0001 /* AIF2DACL_TO_AIF1ADC2L */
+#define WM8995_AIF2DACL_TO_AIF1ADC2L_SHIFT           0 /* AIF2DACL_TO_AIF1ADC2L */
+#define WM8995_AIF2DACL_TO_AIF1ADC2L_WIDTH           1 /* AIF2DACL_TO_AIF1ADC2L */
+
+/*
+ * R1545 (0x609) - AIF1 ADC2 Right mixer Routing
+ */
+#define WM8995_ADC2R_TO_AIF1ADC2R               0x0002 /* ADC2R_TO_AIF1ADC2R */
+#define WM8995_ADC2R_TO_AIF1ADC2R_MASK          0x0002 /* ADC2R_TO_AIF1ADC2R */
+#define WM8995_ADC2R_TO_AIF1ADC2R_SHIFT              1 /* ADC2R_TO_AIF1ADC2R */
+#define WM8995_ADC2R_TO_AIF1ADC2R_WIDTH              1 /* ADC2R_TO_AIF1ADC2R */
+#define WM8995_AIF2DACR_TO_AIF1ADC2R            0x0001 /* AIF2DACR_TO_AIF1ADC2R */
+#define WM8995_AIF2DACR_TO_AIF1ADC2R_MASK       0x0001 /* AIF2DACR_TO_AIF1ADC2R */
+#define WM8995_AIF2DACR_TO_AIF1ADC2R_SHIFT           0 /* AIF2DACR_TO_AIF1ADC2R */
+#define WM8995_AIF2DACR_TO_AIF1ADC2R_WIDTH           1 /* AIF2DACR_TO_AIF1ADC2R */
+
+/*
+ * R1552 (0x610) - DAC Softmute
+ */
+#define WM8995_DAC_SOFTMUTEMODE                 0x0002 /* DAC_SOFTMUTEMODE */
+#define WM8995_DAC_SOFTMUTEMODE_MASK            0x0002 /* DAC_SOFTMUTEMODE */
+#define WM8995_DAC_SOFTMUTEMODE_SHIFT                1 /* DAC_SOFTMUTEMODE */
+#define WM8995_DAC_SOFTMUTEMODE_WIDTH                1 /* DAC_SOFTMUTEMODE */
+#define WM8995_DAC_MUTERATE                     0x0001 /* DAC_MUTERATE */
+#define WM8995_DAC_MUTERATE_MASK                0x0001 /* DAC_MUTERATE */
+#define WM8995_DAC_MUTERATE_SHIFT                    0 /* DAC_MUTERATE */
+#define WM8995_DAC_MUTERATE_WIDTH                    1 /* DAC_MUTERATE */
+
+/*
+ * R1568 (0x620) - Oversampling
+ */
+#define WM8995_ADC_OSR128                       0x0002 /* ADC_OSR128 */
+#define WM8995_ADC_OSR128_MASK                  0x0002 /* ADC_OSR128 */
+#define WM8995_ADC_OSR128_SHIFT                      1 /* ADC_OSR128 */
+#define WM8995_ADC_OSR128_WIDTH                      1 /* ADC_OSR128 */
+#define WM8995_DAC_OSR128                       0x0001 /* DAC_OSR128 */
+#define WM8995_DAC_OSR128_MASK                  0x0001 /* DAC_OSR128 */
+#define WM8995_DAC_OSR128_SHIFT                      0 /* DAC_OSR128 */
+#define WM8995_DAC_OSR128_WIDTH                      1 /* DAC_OSR128 */
+
+/*
+ * R1569 (0x621) - Sidetone
+ */
+#define WM8995_ST_LPF                           0x1000 /* ST_LPF */
+#define WM8995_ST_LPF_MASK                      0x1000 /* ST_LPF */
+#define WM8995_ST_LPF_SHIFT                         12 /* ST_LPF */
+#define WM8995_ST_LPF_WIDTH                          1 /* ST_LPF */
+#define WM8995_ST_HPF_CUT_MASK                  0x0380 /* ST_HPF_CUT - [9:7] */
+#define WM8995_ST_HPF_CUT_SHIFT                      7 /* ST_HPF_CUT - [9:7] */
+#define WM8995_ST_HPF_CUT_WIDTH                      3 /* ST_HPF_CUT - [9:7] */
+#define WM8995_ST_HPF                           0x0040 /* ST_HPF */
+#define WM8995_ST_HPF_MASK                      0x0040 /* ST_HPF */
+#define WM8995_ST_HPF_SHIFT                          6 /* ST_HPF */
+#define WM8995_ST_HPF_WIDTH                          1 /* ST_HPF */
+#define WM8995_STR_SEL                          0x0002 /* STR_SEL */
+#define WM8995_STR_SEL_MASK                     0x0002 /* STR_SEL */
+#define WM8995_STR_SEL_SHIFT                         1 /* STR_SEL */
+#define WM8995_STR_SEL_WIDTH                         1 /* STR_SEL */
+#define WM8995_STL_SEL                          0x0001 /* STL_SEL */
+#define WM8995_STL_SEL_MASK                     0x0001 /* STL_SEL */
+#define WM8995_STL_SEL_SHIFT                         0 /* STL_SEL */
+#define WM8995_STL_SEL_WIDTH                         1 /* STL_SEL */
+
+/*
+ * R1792 (0x700) - GPIO 1
+ */
+#define WM8995_GP1_DIR                          0x8000 /* GP1_DIR */
+#define WM8995_GP1_DIR_MASK                     0x8000 /* GP1_DIR */
+#define WM8995_GP1_DIR_SHIFT                        15 /* GP1_DIR */
+#define WM8995_GP1_DIR_WIDTH                         1 /* GP1_DIR */
+#define WM8995_GP1_PU                           0x4000 /* GP1_PU */
+#define WM8995_GP1_PU_MASK                      0x4000 /* GP1_PU */
+#define WM8995_GP1_PU_SHIFT                         14 /* GP1_PU */
+#define WM8995_GP1_PU_WIDTH                          1 /* GP1_PU */
+#define WM8995_GP1_PD                           0x2000 /* GP1_PD */
+#define WM8995_GP1_PD_MASK                      0x2000 /* GP1_PD */
+#define WM8995_GP1_PD_SHIFT                         13 /* GP1_PD */
+#define WM8995_GP1_PD_WIDTH                          1 /* GP1_PD */
+#define WM8995_GP1_POL                          0x0400 /* GP1_POL */
+#define WM8995_GP1_POL_MASK                     0x0400 /* GP1_POL */
+#define WM8995_GP1_POL_SHIFT                        10 /* GP1_POL */
+#define WM8995_GP1_POL_WIDTH                         1 /* GP1_POL */
+#define WM8995_GP1_OP_CFG                       0x0200 /* GP1_OP_CFG */
+#define WM8995_GP1_OP_CFG_MASK                  0x0200 /* GP1_OP_CFG */
+#define WM8995_GP1_OP_CFG_SHIFT                      9 /* GP1_OP_CFG */
+#define WM8995_GP1_OP_CFG_WIDTH                      1 /* GP1_OP_CFG */
+#define WM8995_GP1_DB                           0x0100 /* GP1_DB */
+#define WM8995_GP1_DB_MASK                      0x0100 /* GP1_DB */
+#define WM8995_GP1_DB_SHIFT                          8 /* GP1_DB */
+#define WM8995_GP1_DB_WIDTH                          1 /* GP1_DB */
+#define WM8995_GP1_LVL                          0x0040 /* GP1_LVL */
+#define WM8995_GP1_LVL_MASK                     0x0040 /* GP1_LVL */
+#define WM8995_GP1_LVL_SHIFT                         6 /* GP1_LVL */
+#define WM8995_GP1_LVL_WIDTH                         1 /* GP1_LVL */
+#define WM8995_GP1_FN_MASK                      0x001F /* GP1_FN - [4:0] */
+#define WM8995_GP1_FN_SHIFT                          0 /* GP1_FN - [4:0] */
+#define WM8995_GP1_FN_WIDTH                          5 /* GP1_FN - [4:0] */
+
+/*
+ * R1793 (0x701) - GPIO 2
+ */
+#define WM8995_GP2_DIR                          0x8000 /* GP2_DIR */
+#define WM8995_GP2_DIR_MASK                     0x8000 /* GP2_DIR */
+#define WM8995_GP2_DIR_SHIFT                        15 /* GP2_DIR */
+#define WM8995_GP2_DIR_WIDTH                         1 /* GP2_DIR */
+#define WM8995_GP2_PU                           0x4000 /* GP2_PU */
+#define WM8995_GP2_PU_MASK                      0x4000 /* GP2_PU */
+#define WM8995_GP2_PU_SHIFT                         14 /* GP2_PU */
+#define WM8995_GP2_PU_WIDTH                          1 /* GP2_PU */
+#define WM8995_GP2_PD                           0x2000 /* GP2_PD */
+#define WM8995_GP2_PD_MASK                      0x2000 /* GP2_PD */
+#define WM8995_GP2_PD_SHIFT                         13 /* GP2_PD */
+#define WM8995_GP2_PD_WIDTH                          1 /* GP2_PD */
+#define WM8995_GP2_POL                          0x0400 /* GP2_POL */
+#define WM8995_GP2_POL_MASK                     0x0400 /* GP2_POL */
+#define WM8995_GP2_POL_SHIFT                        10 /* GP2_POL */
+#define WM8995_GP2_POL_WIDTH                         1 /* GP2_POL */
+#define WM8995_GP2_OP_CFG                       0x0200 /* GP2_OP_CFG */
+#define WM8995_GP2_OP_CFG_MASK                  0x0200 /* GP2_OP_CFG */
+#define WM8995_GP2_OP_CFG_SHIFT                      9 /* GP2_OP_CFG */
+#define WM8995_GP2_OP_CFG_WIDTH                      1 /* GP2_OP_CFG */
+#define WM8995_GP2_DB                           0x0100 /* GP2_DB */
+#define WM8995_GP2_DB_MASK                      0x0100 /* GP2_DB */
+#define WM8995_GP2_DB_SHIFT                          8 /* GP2_DB */
+#define WM8995_GP2_DB_WIDTH                          1 /* GP2_DB */
+#define WM8995_GP2_LVL                          0x0040 /* GP2_LVL */
+#define WM8995_GP2_LVL_MASK                     0x0040 /* GP2_LVL */
+#define WM8995_GP2_LVL_SHIFT                         6 /* GP2_LVL */
+#define WM8995_GP2_LVL_WIDTH                         1 /* GP2_LVL */
+#define WM8995_GP2_FN_MASK                      0x001F /* GP2_FN - [4:0] */
+#define WM8995_GP2_FN_SHIFT                          0 /* GP2_FN - [4:0] */
+#define WM8995_GP2_FN_WIDTH                          5 /* GP2_FN - [4:0] */
+
+/*
+ * R1794 (0x702) - GPIO 3
+ */
+#define WM8995_GP3_DIR                          0x8000 /* GP3_DIR */
+#define WM8995_GP3_DIR_MASK                     0x8000 /* GP3_DIR */
+#define WM8995_GP3_DIR_SHIFT                        15 /* GP3_DIR */
+#define WM8995_GP3_DIR_WIDTH                         1 /* GP3_DIR */
+#define WM8995_GP3_PU                           0x4000 /* GP3_PU */
+#define WM8995_GP3_PU_MASK                      0x4000 /* GP3_PU */
+#define WM8995_GP3_PU_SHIFT                         14 /* GP3_PU */
+#define WM8995_GP3_PU_WIDTH                          1 /* GP3_PU */
+#define WM8995_GP3_PD                           0x2000 /* GP3_PD */
+#define WM8995_GP3_PD_MASK                      0x2000 /* GP3_PD */
+#define WM8995_GP3_PD_SHIFT                         13 /* GP3_PD */
+#define WM8995_GP3_PD_WIDTH                          1 /* GP3_PD */
+#define WM8995_GP3_POL                          0x0400 /* GP3_POL */
+#define WM8995_GP3_POL_MASK                     0x0400 /* GP3_POL */
+#define WM8995_GP3_POL_SHIFT                        10 /* GP3_POL */
+#define WM8995_GP3_POL_WIDTH                         1 /* GP3_POL */
+#define WM8995_GP3_OP_CFG                       0x0200 /* GP3_OP_CFG */
+#define WM8995_GP3_OP_CFG_MASK                  0x0200 /* GP3_OP_CFG */
+#define WM8995_GP3_OP_CFG_SHIFT                      9 /* GP3_OP_CFG */
+#define WM8995_GP3_OP_CFG_WIDTH                      1 /* GP3_OP_CFG */
+#define WM8995_GP3_DB                           0x0100 /* GP3_DB */
+#define WM8995_GP3_DB_MASK                      0x0100 /* GP3_DB */
+#define WM8995_GP3_DB_SHIFT                          8 /* GP3_DB */
+#define WM8995_GP3_DB_WIDTH                          1 /* GP3_DB */
+#define WM8995_GP3_LVL                          0x0040 /* GP3_LVL */
+#define WM8995_GP3_LVL_MASK                     0x0040 /* GP3_LVL */
+#define WM8995_GP3_LVL_SHIFT                         6 /* GP3_LVL */
+#define WM8995_GP3_LVL_WIDTH                         1 /* GP3_LVL */
+#define WM8995_GP3_FN_MASK                      0x001F /* GP3_FN - [4:0] */
+#define WM8995_GP3_FN_SHIFT                          0 /* GP3_FN - [4:0] */
+#define WM8995_GP3_FN_WIDTH                          5 /* GP3_FN - [4:0] */
+
+/*
+ * R1795 (0x703) - GPIO 4
+ */
+#define WM8995_GP4_DIR                          0x8000 /* GP4_DIR */
+#define WM8995_GP4_DIR_MASK                     0x8000 /* GP4_DIR */
+#define WM8995_GP4_DIR_SHIFT                        15 /* GP4_DIR */
+#define WM8995_GP4_DIR_WIDTH                         1 /* GP4_DIR */
+#define WM8995_GP4_PU                           0x4000 /* GP4_PU */
+#define WM8995_GP4_PU_MASK                      0x4000 /* GP4_PU */
+#define WM8995_GP4_PU_SHIFT                         14 /* GP4_PU */
+#define WM8995_GP4_PU_WIDTH                          1 /* GP4_PU */
+#define WM8995_GP4_PD                           0x2000 /* GP4_PD */
+#define WM8995_GP4_PD_MASK                      0x2000 /* GP4_PD */
+#define WM8995_GP4_PD_SHIFT                         13 /* GP4_PD */
+#define WM8995_GP4_PD_WIDTH                          1 /* GP4_PD */
+#define WM8995_GP4_POL                          0x0400 /* GP4_POL */
+#define WM8995_GP4_POL_MASK                     0x0400 /* GP4_POL */
+#define WM8995_GP4_POL_SHIFT                        10 /* GP4_POL */
+#define WM8995_GP4_POL_WIDTH                         1 /* GP4_POL */
+#define WM8995_GP4_OP_CFG                       0x0200 /* GP4_OP_CFG */
+#define WM8995_GP4_OP_CFG_MASK                  0x0200 /* GP4_OP_CFG */
+#define WM8995_GP4_OP_CFG_SHIFT                      9 /* GP4_OP_CFG */
+#define WM8995_GP4_OP_CFG_WIDTH                      1 /* GP4_OP_CFG */
+#define WM8995_GP4_DB                           0x0100 /* GP4_DB */
+#define WM8995_GP4_DB_MASK                      0x0100 /* GP4_DB */
+#define WM8995_GP4_DB_SHIFT                          8 /* GP4_DB */
+#define WM8995_GP4_DB_WIDTH                          1 /* GP4_DB */
+#define WM8995_GP4_LVL                          0x0040 /* GP4_LVL */
+#define WM8995_GP4_LVL_MASK                     0x0040 /* GP4_LVL */
+#define WM8995_GP4_LVL_SHIFT                         6 /* GP4_LVL */
+#define WM8995_GP4_LVL_WIDTH                         1 /* GP4_LVL */
+#define WM8995_GP4_FN_MASK                      0x001F /* GP4_FN - [4:0] */
+#define WM8995_GP4_FN_SHIFT                          0 /* GP4_FN - [4:0] */
+#define WM8995_GP4_FN_WIDTH                          5 /* GP4_FN - [4:0] */
+
+/*
+ * R1796 (0x704) - GPIO 5
+ */
+#define WM8995_GP5_DIR                          0x8000 /* GP5_DIR */
+#define WM8995_GP5_DIR_MASK                     0x8000 /* GP5_DIR */
+#define WM8995_GP5_DIR_SHIFT                        15 /* GP5_DIR */
+#define WM8995_GP5_DIR_WIDTH                         1 /* GP5_DIR */
+#define WM8995_GP5_PU                           0x4000 /* GP5_PU */
+#define WM8995_GP5_PU_MASK                      0x4000 /* GP5_PU */
+#define WM8995_GP5_PU_SHIFT                         14 /* GP5_PU */
+#define WM8995_GP5_PU_WIDTH                          1 /* GP5_PU */
+#define WM8995_GP5_PD                           0x2000 /* GP5_PD */
+#define WM8995_GP5_PD_MASK                      0x2000 /* GP5_PD */
+#define WM8995_GP5_PD_SHIFT                         13 /* GP5_PD */
+#define WM8995_GP5_PD_WIDTH                          1 /* GP5_PD */
+#define WM8995_GP5_POL                          0x0400 /* GP5_POL */
+#define WM8995_GP5_POL_MASK                     0x0400 /* GP5_POL */
+#define WM8995_GP5_POL_SHIFT                        10 /* GP5_POL */
+#define WM8995_GP5_POL_WIDTH                         1 /* GP5_POL */
+#define WM8995_GP5_OP_CFG                       0x0200 /* GP5_OP_CFG */
+#define WM8995_GP5_OP_CFG_MASK                  0x0200 /* GP5_OP_CFG */
+#define WM8995_GP5_OP_CFG_SHIFT                      9 /* GP5_OP_CFG */
+#define WM8995_GP5_OP_CFG_WIDTH                      1 /* GP5_OP_CFG */
+#define WM8995_GP5_DB                           0x0100 /* GP5_DB */
+#define WM8995_GP5_DB_MASK                      0x0100 /* GP5_DB */
+#define WM8995_GP5_DB_SHIFT                          8 /* GP5_DB */
+#define WM8995_GP5_DB_WIDTH                          1 /* GP5_DB */
+#define WM8995_GP5_LVL                          0x0040 /* GP5_LVL */
+#define WM8995_GP5_LVL_MASK                     0x0040 /* GP5_LVL */
+#define WM8995_GP5_LVL_SHIFT                         6 /* GP5_LVL */
+#define WM8995_GP5_LVL_WIDTH                         1 /* GP5_LVL */
+#define WM8995_GP5_FN_MASK                      0x001F /* GP5_FN - [4:0] */
+#define WM8995_GP5_FN_SHIFT                          0 /* GP5_FN - [4:0] */
+#define WM8995_GP5_FN_WIDTH                          5 /* GP5_FN - [4:0] */
+
+/*
+ * R1797 (0x705) - GPIO 6
+ */
+#define WM8995_GP6_DIR                          0x8000 /* GP6_DIR */
+#define WM8995_GP6_DIR_MASK                     0x8000 /* GP6_DIR */
+#define WM8995_GP6_DIR_SHIFT                        15 /* GP6_DIR */
+#define WM8995_GP6_DIR_WIDTH                         1 /* GP6_DIR */
+#define WM8995_GP6_PU                           0x4000 /* GP6_PU */
+#define WM8995_GP6_PU_MASK                      0x4000 /* GP6_PU */
+#define WM8995_GP6_PU_SHIFT                         14 /* GP6_PU */
+#define WM8995_GP6_PU_WIDTH                          1 /* GP6_PU */
+#define WM8995_GP6_PD                           0x2000 /* GP6_PD */
+#define WM8995_GP6_PD_MASK                      0x2000 /* GP6_PD */
+#define WM8995_GP6_PD_SHIFT                         13 /* GP6_PD */
+#define WM8995_GP6_PD_WIDTH                          1 /* GP6_PD */
+#define WM8995_GP6_POL                          0x0400 /* GP6_POL */
+#define WM8995_GP6_POL_MASK                     0x0400 /* GP6_POL */
+#define WM8995_GP6_POL_SHIFT                        10 /* GP6_POL */
+#define WM8995_GP6_POL_WIDTH                         1 /* GP6_POL */
+#define WM8995_GP6_OP_CFG                       0x0200 /* GP6_OP_CFG */
+#define WM8995_GP6_OP_CFG_MASK                  0x0200 /* GP6_OP_CFG */
+#define WM8995_GP6_OP_CFG_SHIFT                      9 /* GP6_OP_CFG */
+#define WM8995_GP6_OP_CFG_WIDTH                      1 /* GP6_OP_CFG */
+#define WM8995_GP6_DB                           0x0100 /* GP6_DB */
+#define WM8995_GP6_DB_MASK                      0x0100 /* GP6_DB */
+#define WM8995_GP6_DB_SHIFT                          8 /* GP6_DB */
+#define WM8995_GP6_DB_WIDTH                          1 /* GP6_DB */
+#define WM8995_GP6_LVL                          0x0040 /* GP6_LVL */
+#define WM8995_GP6_LVL_MASK                     0x0040 /* GP6_LVL */
+#define WM8995_GP6_LVL_SHIFT                         6 /* GP6_LVL */
+#define WM8995_GP6_LVL_WIDTH                         1 /* GP6_LVL */
+#define WM8995_GP6_FN_MASK                      0x001F /* GP6_FN - [4:0] */
+#define WM8995_GP6_FN_SHIFT                          0 /* GP6_FN - [4:0] */
+#define WM8995_GP6_FN_WIDTH                          5 /* GP6_FN - [4:0] */
+
+/*
+ * R1798 (0x706) - GPIO 7
+ */
+#define WM8995_GP7_DIR                          0x8000 /* GP7_DIR */
+#define WM8995_GP7_DIR_MASK                     0x8000 /* GP7_DIR */
+#define WM8995_GP7_DIR_SHIFT                        15 /* GP7_DIR */
+#define WM8995_GP7_DIR_WIDTH                         1 /* GP7_DIR */
+#define WM8995_GP7_PU                           0x4000 /* GP7_PU */
+#define WM8995_GP7_PU_MASK                      0x4000 /* GP7_PU */
+#define WM8995_GP7_PU_SHIFT                         14 /* GP7_PU */
+#define WM8995_GP7_PU_WIDTH                          1 /* GP7_PU */
+#define WM8995_GP7_PD                           0x2000 /* GP7_PD */
+#define WM8995_GP7_PD_MASK                      0x2000 /* GP7_PD */
+#define WM8995_GP7_PD_SHIFT                         13 /* GP7_PD */
+#define WM8995_GP7_PD_WIDTH                          1 /* GP7_PD */
+#define WM8995_GP7_POL                          0x0400 /* GP7_POL */
+#define WM8995_GP7_POL_MASK                     0x0400 /* GP7_POL */
+#define WM8995_GP7_POL_SHIFT                        10 /* GP7_POL */
+#define WM8995_GP7_POL_WIDTH                         1 /* GP7_POL */
+#define WM8995_GP7_OP_CFG                       0x0200 /* GP7_OP_CFG */
+#define WM8995_GP7_OP_CFG_MASK                  0x0200 /* GP7_OP_CFG */
+#define WM8995_GP7_OP_CFG_SHIFT                      9 /* GP7_OP_CFG */
+#define WM8995_GP7_OP_CFG_WIDTH                      1 /* GP7_OP_CFG */
+#define WM8995_GP7_DB                           0x0100 /* GP7_DB */
+#define WM8995_GP7_DB_MASK                      0x0100 /* GP7_DB */
+#define WM8995_GP7_DB_SHIFT                          8 /* GP7_DB */
+#define WM8995_GP7_DB_WIDTH                          1 /* GP7_DB */
+#define WM8995_GP7_LVL                          0x0040 /* GP7_LVL */
+#define WM8995_GP7_LVL_MASK                     0x0040 /* GP7_LVL */
+#define WM8995_GP7_LVL_SHIFT                         6 /* GP7_LVL */
+#define WM8995_GP7_LVL_WIDTH                         1 /* GP7_LVL */
+#define WM8995_GP7_FN_MASK                      0x001F /* GP7_FN - [4:0] */
+#define WM8995_GP7_FN_SHIFT                          0 /* GP7_FN - [4:0] */
+#define WM8995_GP7_FN_WIDTH                          5 /* GP7_FN - [4:0] */
+
+/*
+ * R1799 (0x707) - GPIO 8
+ */
+#define WM8995_GP8_DIR                          0x8000 /* GP8_DIR */
+#define WM8995_GP8_DIR_MASK                     0x8000 /* GP8_DIR */
+#define WM8995_GP8_DIR_SHIFT                        15 /* GP8_DIR */
+#define WM8995_GP8_DIR_WIDTH                         1 /* GP8_DIR */
+#define WM8995_GP8_PU                           0x4000 /* GP8_PU */
+#define WM8995_GP8_PU_MASK                      0x4000 /* GP8_PU */
+#define WM8995_GP8_PU_SHIFT                         14 /* GP8_PU */
+#define WM8995_GP8_PU_WIDTH                          1 /* GP8_PU */
+#define WM8995_GP8_PD                           0x2000 /* GP8_PD */
+#define WM8995_GP8_PD_MASK                      0x2000 /* GP8_PD */
+#define WM8995_GP8_PD_SHIFT                         13 /* GP8_PD */
+#define WM8995_GP8_PD_WIDTH                          1 /* GP8_PD */
+#define WM8995_GP8_POL                          0x0400 /* GP8_POL */
+#define WM8995_GP8_POL_MASK                     0x0400 /* GP8_POL */
+#define WM8995_GP8_POL_SHIFT                        10 /* GP8_POL */
+#define WM8995_GP8_POL_WIDTH                         1 /* GP8_POL */
+#define WM8995_GP8_OP_CFG                       0x0200 /* GP8_OP_CFG */
+#define WM8995_GP8_OP_CFG_MASK                  0x0200 /* GP8_OP_CFG */
+#define WM8995_GP8_OP_CFG_SHIFT                      9 /* GP8_OP_CFG */
+#define WM8995_GP8_OP_CFG_WIDTH                      1 /* GP8_OP_CFG */
+#define WM8995_GP8_DB                           0x0100 /* GP8_DB */
+#define WM8995_GP8_DB_MASK                      0x0100 /* GP8_DB */
+#define WM8995_GP8_DB_SHIFT                          8 /* GP8_DB */
+#define WM8995_GP8_DB_WIDTH                          1 /* GP8_DB */
+#define WM8995_GP8_LVL                          0x0040 /* GP8_LVL */
+#define WM8995_GP8_LVL_MASK                     0x0040 /* GP8_LVL */
+#define WM8995_GP8_LVL_SHIFT                         6 /* GP8_LVL */
+#define WM8995_GP8_LVL_WIDTH                         1 /* GP8_LVL */
+#define WM8995_GP8_FN_MASK                      0x001F /* GP8_FN - [4:0] */
+#define WM8995_GP8_FN_SHIFT                          0 /* GP8_FN - [4:0] */
+#define WM8995_GP8_FN_WIDTH                          5 /* GP8_FN - [4:0] */
+
+/*
+ * R1800 (0x708) - GPIO 9
+ */
+#define WM8995_GP9_DIR                          0x8000 /* GP9_DIR */
+#define WM8995_GP9_DIR_MASK                     0x8000 /* GP9_DIR */
+#define WM8995_GP9_DIR_SHIFT                        15 /* GP9_DIR */
+#define WM8995_GP9_DIR_WIDTH                         1 /* GP9_DIR */
+#define WM8995_GP9_PU                           0x4000 /* GP9_PU */
+#define WM8995_GP9_PU_MASK                      0x4000 /* GP9_PU */
+#define WM8995_GP9_PU_SHIFT                         14 /* GP9_PU */
+#define WM8995_GP9_PU_WIDTH                          1 /* GP9_PU */
+#define WM8995_GP9_PD                           0x2000 /* GP9_PD */
+#define WM8995_GP9_PD_MASK                      0x2000 /* GP9_PD */
+#define WM8995_GP9_PD_SHIFT                         13 /* GP9_PD */
+#define WM8995_GP9_PD_WIDTH                          1 /* GP9_PD */
+#define WM8995_GP9_POL                          0x0400 /* GP9_POL */
+#define WM8995_GP9_POL_MASK                     0x0400 /* GP9_POL */
+#define WM8995_GP9_POL_SHIFT                        10 /* GP9_POL */
+#define WM8995_GP9_POL_WIDTH                         1 /* GP9_POL */
+#define WM8995_GP9_OP_CFG                       0x0200 /* GP9_OP_CFG */
+#define WM8995_GP9_OP_CFG_MASK                  0x0200 /* GP9_OP_CFG */
+#define WM8995_GP9_OP_CFG_SHIFT                      9 /* GP9_OP_CFG */
+#define WM8995_GP9_OP_CFG_WIDTH                      1 /* GP9_OP_CFG */
+#define WM8995_GP9_DB                           0x0100 /* GP9_DB */
+#define WM8995_GP9_DB_MASK                      0x0100 /* GP9_DB */
+#define WM8995_GP9_DB_SHIFT                          8 /* GP9_DB */
+#define WM8995_GP9_DB_WIDTH                          1 /* GP9_DB */
+#define WM8995_GP9_LVL                          0x0040 /* GP9_LVL */
+#define WM8995_GP9_LVL_MASK                     0x0040 /* GP9_LVL */
+#define WM8995_GP9_LVL_SHIFT                         6 /* GP9_LVL */
+#define WM8995_GP9_LVL_WIDTH                         1 /* GP9_LVL */
+#define WM8995_GP9_FN_MASK                      0x001F /* GP9_FN - [4:0] */
+#define WM8995_GP9_FN_SHIFT                          0 /* GP9_FN - [4:0] */
+#define WM8995_GP9_FN_WIDTH                          5 /* GP9_FN - [4:0] */
+
+/*
+ * R1801 (0x709) - GPIO 10
+ */
+#define WM8995_GP10_DIR                         0x8000 /* GP10_DIR */
+#define WM8995_GP10_DIR_MASK                    0x8000 /* GP10_DIR */
+#define WM8995_GP10_DIR_SHIFT                       15 /* GP10_DIR */
+#define WM8995_GP10_DIR_WIDTH                        1 /* GP10_DIR */
+#define WM8995_GP10_PU                          0x4000 /* GP10_PU */
+#define WM8995_GP10_PU_MASK                     0x4000 /* GP10_PU */
+#define WM8995_GP10_PU_SHIFT                        14 /* GP10_PU */
+#define WM8995_GP10_PU_WIDTH                         1 /* GP10_PU */
+#define WM8995_GP10_PD                          0x2000 /* GP10_PD */
+#define WM8995_GP10_PD_MASK                     0x2000 /* GP10_PD */
+#define WM8995_GP10_PD_SHIFT                        13 /* GP10_PD */
+#define WM8995_GP10_PD_WIDTH                         1 /* GP10_PD */
+#define WM8995_GP10_POL                         0x0400 /* GP10_POL */
+#define WM8995_GP10_POL_MASK                    0x0400 /* GP10_POL */
+#define WM8995_GP10_POL_SHIFT                       10 /* GP10_POL */
+#define WM8995_GP10_POL_WIDTH                        1 /* GP10_POL */
+#define WM8995_GP10_OP_CFG                      0x0200 /* GP10_OP_CFG */
+#define WM8995_GP10_OP_CFG_MASK                 0x0200 /* GP10_OP_CFG */
+#define WM8995_GP10_OP_CFG_SHIFT                     9 /* GP10_OP_CFG */
+#define WM8995_GP10_OP_CFG_WIDTH                     1 /* GP10_OP_CFG */
+#define WM8995_GP10_DB                          0x0100 /* GP10_DB */
+#define WM8995_GP10_DB_MASK                     0x0100 /* GP10_DB */
+#define WM8995_GP10_DB_SHIFT                         8 /* GP10_DB */
+#define WM8995_GP10_DB_WIDTH                         1 /* GP10_DB */
+#define WM8995_GP10_LVL                         0x0040 /* GP10_LVL */
+#define WM8995_GP10_LVL_MASK                    0x0040 /* GP10_LVL */
+#define WM8995_GP10_LVL_SHIFT                        6 /* GP10_LVL */
+#define WM8995_GP10_LVL_WIDTH                        1 /* GP10_LVL */
+#define WM8995_GP10_FN_MASK                     0x001F /* GP10_FN - [4:0] */
+#define WM8995_GP10_FN_SHIFT                         0 /* GP10_FN - [4:0] */
+#define WM8995_GP10_FN_WIDTH                         5 /* GP10_FN - [4:0] */
+
+/*
+ * R1802 (0x70A) - GPIO 11
+ */
+#define WM8995_GP11_DIR                         0x8000 /* GP11_DIR */
+#define WM8995_GP11_DIR_MASK                    0x8000 /* GP11_DIR */
+#define WM8995_GP11_DIR_SHIFT                       15 /* GP11_DIR */
+#define WM8995_GP11_DIR_WIDTH                        1 /* GP11_DIR */
+#define WM8995_GP11_PU                          0x4000 /* GP11_PU */
+#define WM8995_GP11_PU_MASK                     0x4000 /* GP11_PU */
+#define WM8995_GP11_PU_SHIFT                        14 /* GP11_PU */
+#define WM8995_GP11_PU_WIDTH                         1 /* GP11_PU */
+#define WM8995_GP11_PD                          0x2000 /* GP11_PD */
+#define WM8995_GP11_PD_MASK                     0x2000 /* GP11_PD */
+#define WM8995_GP11_PD_SHIFT                        13 /* GP11_PD */
+#define WM8995_GP11_PD_WIDTH                         1 /* GP11_PD */
+#define WM8995_GP11_POL                         0x0400 /* GP11_POL */
+#define WM8995_GP11_POL_MASK                    0x0400 /* GP11_POL */
+#define WM8995_GP11_POL_SHIFT                       10 /* GP11_POL */
+#define WM8995_GP11_POL_WIDTH                        1 /* GP11_POL */
+#define WM8995_GP11_OP_CFG                      0x0200 /* GP11_OP_CFG */
+#define WM8995_GP11_OP_CFG_MASK                 0x0200 /* GP11_OP_CFG */
+#define WM8995_GP11_OP_CFG_SHIFT                     9 /* GP11_OP_CFG */
+#define WM8995_GP11_OP_CFG_WIDTH                     1 /* GP11_OP_CFG */
+#define WM8995_GP11_DB                          0x0100 /* GP11_DB */
+#define WM8995_GP11_DB_MASK                     0x0100 /* GP11_DB */
+#define WM8995_GP11_DB_SHIFT                         8 /* GP11_DB */
+#define WM8995_GP11_DB_WIDTH                         1 /* GP11_DB */
+#define WM8995_GP11_LVL                         0x0040 /* GP11_LVL */
+#define WM8995_GP11_LVL_MASK                    0x0040 /* GP11_LVL */
+#define WM8995_GP11_LVL_SHIFT                        6 /* GP11_LVL */
+#define WM8995_GP11_LVL_WIDTH                        1 /* GP11_LVL */
+#define WM8995_GP11_FN_MASK                     0x001F /* GP11_FN - [4:0] */
+#define WM8995_GP11_FN_SHIFT                         0 /* GP11_FN - [4:0] */
+#define WM8995_GP11_FN_WIDTH                         5 /* GP11_FN - [4:0] */
+
+/*
+ * R1803 (0x70B) - GPIO 12
+ */
+#define WM8995_GP12_DIR                         0x8000 /* GP12_DIR */
+#define WM8995_GP12_DIR_MASK                    0x8000 /* GP12_DIR */
+#define WM8995_GP12_DIR_SHIFT                       15 /* GP12_DIR */
+#define WM8995_GP12_DIR_WIDTH                        1 /* GP12_DIR */
+#define WM8995_GP12_PU                          0x4000 /* GP12_PU */
+#define WM8995_GP12_PU_MASK                     0x4000 /* GP12_PU */
+#define WM8995_GP12_PU_SHIFT                        14 /* GP12_PU */
+#define WM8995_GP12_PU_WIDTH                         1 /* GP12_PU */
+#define WM8995_GP12_PD                          0x2000 /* GP12_PD */
+#define WM8995_GP12_PD_MASK                     0x2000 /* GP12_PD */
+#define WM8995_GP12_PD_SHIFT                        13 /* GP12_PD */
+#define WM8995_GP12_PD_WIDTH                         1 /* GP12_PD */
+#define WM8995_GP12_POL                         0x0400 /* GP12_POL */
+#define WM8995_GP12_POL_MASK                    0x0400 /* GP12_POL */
+#define WM8995_GP12_POL_SHIFT                       10 /* GP12_POL */
+#define WM8995_GP12_POL_WIDTH                        1 /* GP12_POL */
+#define WM8995_GP12_OP_CFG                      0x0200 /* GP12_OP_CFG */
+#define WM8995_GP12_OP_CFG_MASK                 0x0200 /* GP12_OP_CFG */
+#define WM8995_GP12_OP_CFG_SHIFT                     9 /* GP12_OP_CFG */
+#define WM8995_GP12_OP_CFG_WIDTH                     1 /* GP12_OP_CFG */
+#define WM8995_GP12_DB                          0x0100 /* GP12_DB */
+#define WM8995_GP12_DB_MASK                     0x0100 /* GP12_DB */
+#define WM8995_GP12_DB_SHIFT                         8 /* GP12_DB */
+#define WM8995_GP12_DB_WIDTH                         1 /* GP12_DB */
+#define WM8995_GP12_LVL                         0x0040 /* GP12_LVL */
+#define WM8995_GP12_LVL_MASK                    0x0040 /* GP12_LVL */
+#define WM8995_GP12_LVL_SHIFT                        6 /* GP12_LVL */
+#define WM8995_GP12_LVL_WIDTH                        1 /* GP12_LVL */
+#define WM8995_GP12_FN_MASK                     0x001F /* GP12_FN - [4:0] */
+#define WM8995_GP12_FN_SHIFT                         0 /* GP12_FN - [4:0] */
+#define WM8995_GP12_FN_WIDTH                         5 /* GP12_FN - [4:0] */
+
+/*
+ * R1804 (0x70C) - GPIO 13
+ */
+#define WM8995_GP13_DIR                         0x8000 /* GP13_DIR */
+#define WM8995_GP13_DIR_MASK                    0x8000 /* GP13_DIR */
+#define WM8995_GP13_DIR_SHIFT                       15 /* GP13_DIR */
+#define WM8995_GP13_DIR_WIDTH                        1 /* GP13_DIR */
+#define WM8995_GP13_PU                          0x4000 /* GP13_PU */
+#define WM8995_GP13_PU_MASK                     0x4000 /* GP13_PU */
+#define WM8995_GP13_PU_SHIFT                        14 /* GP13_PU */
+#define WM8995_GP13_PU_WIDTH                         1 /* GP13_PU */
+#define WM8995_GP13_PD                          0x2000 /* GP13_PD */
+#define WM8995_GP13_PD_MASK                     0x2000 /* GP13_PD */
+#define WM8995_GP13_PD_SHIFT                        13 /* GP13_PD */
+#define WM8995_GP13_PD_WIDTH                         1 /* GP13_PD */
+#define WM8995_GP13_POL                         0x0400 /* GP13_POL */
+#define WM8995_GP13_POL_MASK                    0x0400 /* GP13_POL */
+#define WM8995_GP13_POL_SHIFT                       10 /* GP13_POL */
+#define WM8995_GP13_POL_WIDTH                        1 /* GP13_POL */
+#define WM8995_GP13_OP_CFG                      0x0200 /* GP13_OP_CFG */
+#define WM8995_GP13_OP_CFG_MASK                 0x0200 /* GP13_OP_CFG */
+#define WM8995_GP13_OP_CFG_SHIFT                     9 /* GP13_OP_CFG */
+#define WM8995_GP13_OP_CFG_WIDTH                     1 /* GP13_OP_CFG */
+#define WM8995_GP13_DB                          0x0100 /* GP13_DB */
+#define WM8995_GP13_DB_MASK                     0x0100 /* GP13_DB */
+#define WM8995_GP13_DB_SHIFT                         8 /* GP13_DB */
+#define WM8995_GP13_DB_WIDTH                         1 /* GP13_DB */
+#define WM8995_GP13_LVL                         0x0040 /* GP13_LVL */
+#define WM8995_GP13_LVL_MASK                    0x0040 /* GP13_LVL */
+#define WM8995_GP13_LVL_SHIFT                        6 /* GP13_LVL */
+#define WM8995_GP13_LVL_WIDTH                        1 /* GP13_LVL */
+#define WM8995_GP13_FN_MASK                     0x001F /* GP13_FN - [4:0] */
+#define WM8995_GP13_FN_SHIFT                         0 /* GP13_FN - [4:0] */
+#define WM8995_GP13_FN_WIDTH                         5 /* GP13_FN - [4:0] */
+
+/*
+ * R1805 (0x70D) - GPIO 14
+ */
+#define WM8995_GP14_DIR                         0x8000 /* GP14_DIR */
+#define WM8995_GP14_DIR_MASK                    0x8000 /* GP14_DIR */
+#define WM8995_GP14_DIR_SHIFT                       15 /* GP14_DIR */
+#define WM8995_GP14_DIR_WIDTH                        1 /* GP14_DIR */
+#define WM8995_GP14_PU                          0x4000 /* GP14_PU */
+#define WM8995_GP14_PU_MASK                     0x4000 /* GP14_PU */
+#define WM8995_GP14_PU_SHIFT                        14 /* GP14_PU */
+#define WM8995_GP14_PU_WIDTH                         1 /* GP14_PU */
+#define WM8995_GP14_PD                          0x2000 /* GP14_PD */
+#define WM8995_GP14_PD_MASK                     0x2000 /* GP14_PD */
+#define WM8995_GP14_PD_SHIFT                        13 /* GP14_PD */
+#define WM8995_GP14_PD_WIDTH                         1 /* GP14_PD */
+#define WM8995_GP14_POL                         0x0400 /* GP14_POL */
+#define WM8995_GP14_POL_MASK                    0x0400 /* GP14_POL */
+#define WM8995_GP14_POL_SHIFT                       10 /* GP14_POL */
+#define WM8995_GP14_POL_WIDTH                        1 /* GP14_POL */
+#define WM8995_GP14_OP_CFG                      0x0200 /* GP14_OP_CFG */
+#define WM8995_GP14_OP_CFG_MASK                 0x0200 /* GP14_OP_CFG */
+#define WM8995_GP14_OP_CFG_SHIFT                     9 /* GP14_OP_CFG */
+#define WM8995_GP14_OP_CFG_WIDTH                     1 /* GP14_OP_CFG */
+#define WM8995_GP14_DB                          0x0100 /* GP14_DB */
+#define WM8995_GP14_DB_MASK                     0x0100 /* GP14_DB */
+#define WM8995_GP14_DB_SHIFT                         8 /* GP14_DB */
+#define WM8995_GP14_DB_WIDTH                         1 /* GP14_DB */
+#define WM8995_GP14_LVL                         0x0040 /* GP14_LVL */
+#define WM8995_GP14_LVL_MASK                    0x0040 /* GP14_LVL */
+#define WM8995_GP14_LVL_SHIFT                        6 /* GP14_LVL */
+#define WM8995_GP14_LVL_WIDTH                        1 /* GP14_LVL */
+#define WM8995_GP14_FN_MASK                     0x001F /* GP14_FN - [4:0] */
+#define WM8995_GP14_FN_SHIFT                         0 /* GP14_FN - [4:0] */
+#define WM8995_GP14_FN_WIDTH                         5 /* GP14_FN - [4:0] */
+
+/*
+ * R1824 (0x720) - Pull Control (1)
+ */
+#define WM8995_DMICDAT3_PD                      0x4000 /* DMICDAT3_PD */
+#define WM8995_DMICDAT3_PD_MASK                 0x4000 /* DMICDAT3_PD */
+#define WM8995_DMICDAT3_PD_SHIFT                    14 /* DMICDAT3_PD */
+#define WM8995_DMICDAT3_PD_WIDTH                     1 /* DMICDAT3_PD */
+#define WM8995_DMICDAT2_PD                      0x1000 /* DMICDAT2_PD */
+#define WM8995_DMICDAT2_PD_MASK                 0x1000 /* DMICDAT2_PD */
+#define WM8995_DMICDAT2_PD_SHIFT                    12 /* DMICDAT2_PD */
+#define WM8995_DMICDAT2_PD_WIDTH                     1 /* DMICDAT2_PD */
+#define WM8995_DMICDAT1_PD                      0x0400 /* DMICDAT1_PD */
+#define WM8995_DMICDAT1_PD_MASK                 0x0400 /* DMICDAT1_PD */
+#define WM8995_DMICDAT1_PD_SHIFT                    10 /* DMICDAT1_PD */
+#define WM8995_DMICDAT1_PD_WIDTH                     1 /* DMICDAT1_PD */
+#define WM8995_MCLK2_PU                         0x0200 /* MCLK2_PU */
+#define WM8995_MCLK2_PU_MASK                    0x0200 /* MCLK2_PU */
+#define WM8995_MCLK2_PU_SHIFT                        9 /* MCLK2_PU */
+#define WM8995_MCLK2_PU_WIDTH                        1 /* MCLK2_PU */
+#define WM8995_MCLK2_PD                         0x0100 /* MCLK2_PD */
+#define WM8995_MCLK2_PD_MASK                    0x0100 /* MCLK2_PD */
+#define WM8995_MCLK2_PD_SHIFT                        8 /* MCLK2_PD */
+#define WM8995_MCLK2_PD_WIDTH                        1 /* MCLK2_PD */
+#define WM8995_MCLK1_PU                         0x0080 /* MCLK1_PU */
+#define WM8995_MCLK1_PU_MASK                    0x0080 /* MCLK1_PU */
+#define WM8995_MCLK1_PU_SHIFT                        7 /* MCLK1_PU */
+#define WM8995_MCLK1_PU_WIDTH                        1 /* MCLK1_PU */
+#define WM8995_MCLK1_PD                         0x0040 /* MCLK1_PD */
+#define WM8995_MCLK1_PD_MASK                    0x0040 /* MCLK1_PD */
+#define WM8995_MCLK1_PD_SHIFT                        6 /* MCLK1_PD */
+#define WM8995_MCLK1_PD_WIDTH                        1 /* MCLK1_PD */
+#define WM8995_DACDAT1_PU                       0x0020 /* DACDAT1_PU */
+#define WM8995_DACDAT1_PU_MASK                  0x0020 /* DACDAT1_PU */
+#define WM8995_DACDAT1_PU_SHIFT                      5 /* DACDAT1_PU */
+#define WM8995_DACDAT1_PU_WIDTH                      1 /* DACDAT1_PU */
+#define WM8995_DACDAT1_PD                       0x0010 /* DACDAT1_PD */
+#define WM8995_DACDAT1_PD_MASK                  0x0010 /* DACDAT1_PD */
+#define WM8995_DACDAT1_PD_SHIFT                      4 /* DACDAT1_PD */
+#define WM8995_DACDAT1_PD_WIDTH                      1 /* DACDAT1_PD */
+#define WM8995_DACLRCLK1_PU                     0x0008 /* DACLRCLK1_PU */
+#define WM8995_DACLRCLK1_PU_MASK                0x0008 /* DACLRCLK1_PU */
+#define WM8995_DACLRCLK1_PU_SHIFT                    3 /* DACLRCLK1_PU */
+#define WM8995_DACLRCLK1_PU_WIDTH                    1 /* DACLRCLK1_PU */
+#define WM8995_DACLRCLK1_PD                     0x0004 /* DACLRCLK1_PD */
+#define WM8995_DACLRCLK1_PD_MASK                0x0004 /* DACLRCLK1_PD */
+#define WM8995_DACLRCLK1_PD_SHIFT                    2 /* DACLRCLK1_PD */
+#define WM8995_DACLRCLK1_PD_WIDTH                    1 /* DACLRCLK1_PD */
+#define WM8995_BCLK1_PU                         0x0002 /* BCLK1_PU */
+#define WM8995_BCLK1_PU_MASK                    0x0002 /* BCLK1_PU */
+#define WM8995_BCLK1_PU_SHIFT                        1 /* BCLK1_PU */
+#define WM8995_BCLK1_PU_WIDTH                        1 /* BCLK1_PU */
+#define WM8995_BCLK1_PD                         0x0001 /* BCLK1_PD */
+#define WM8995_BCLK1_PD_MASK                    0x0001 /* BCLK1_PD */
+#define WM8995_BCLK1_PD_SHIFT                        0 /* BCLK1_PD */
+#define WM8995_BCLK1_PD_WIDTH                        1 /* BCLK1_PD */
+
+/*
+ * R1825 (0x721) - Pull Control (2)
+ */
+#define WM8995_LDO1ENA_PD                       0x0010 /* LDO1ENA_PD */
+#define WM8995_LDO1ENA_PD_MASK                  0x0010 /* LDO1ENA_PD */
+#define WM8995_LDO1ENA_PD_SHIFT                      4 /* LDO1ENA_PD */
+#define WM8995_LDO1ENA_PD_WIDTH                      1 /* LDO1ENA_PD */
+#define WM8995_MODE_PD                          0x0004 /* MODE_PD */
+#define WM8995_MODE_PD_MASK                     0x0004 /* MODE_PD */
+#define WM8995_MODE_PD_SHIFT                         2 /* MODE_PD */
+#define WM8995_MODE_PD_WIDTH                         1 /* MODE_PD */
+#define WM8995_CSNADDR_PD                       0x0001 /* CSNADDR_PD */
+#define WM8995_CSNADDR_PD_MASK                  0x0001 /* CSNADDR_PD */
+#define WM8995_CSNADDR_PD_SHIFT                      0 /* CSNADDR_PD */
+#define WM8995_CSNADDR_PD_WIDTH                      1 /* CSNADDR_PD */
+
+/*
+ * R1840 (0x730) - Interrupt Status 1
+ */
+#define WM8995_GP14_EINT                        0x2000 /* GP14_EINT */
+#define WM8995_GP14_EINT_MASK                   0x2000 /* GP14_EINT */
+#define WM8995_GP14_EINT_SHIFT                      13 /* GP14_EINT */
+#define WM8995_GP14_EINT_WIDTH                       1 /* GP14_EINT */
+#define WM8995_GP13_EINT                        0x1000 /* GP13_EINT */
+#define WM8995_GP13_EINT_MASK                   0x1000 /* GP13_EINT */
+#define WM8995_GP13_EINT_SHIFT                      12 /* GP13_EINT */
+#define WM8995_GP13_EINT_WIDTH                       1 /* GP13_EINT */
+#define WM8995_GP12_EINT                        0x0800 /* GP12_EINT */
+#define WM8995_GP12_EINT_MASK                   0x0800 /* GP12_EINT */
+#define WM8995_GP12_EINT_SHIFT                      11 /* GP12_EINT */
+#define WM8995_GP12_EINT_WIDTH                       1 /* GP12_EINT */
+#define WM8995_GP11_EINT                        0x0400 /* GP11_EINT */
+#define WM8995_GP11_EINT_MASK                   0x0400 /* GP11_EINT */
+#define WM8995_GP11_EINT_SHIFT                      10 /* GP11_EINT */
+#define WM8995_GP11_EINT_WIDTH                       1 /* GP11_EINT */
+#define WM8995_GP10_EINT                        0x0200 /* GP10_EINT */
+#define WM8995_GP10_EINT_MASK                   0x0200 /* GP10_EINT */
+#define WM8995_GP10_EINT_SHIFT                       9 /* GP10_EINT */
+#define WM8995_GP10_EINT_WIDTH                       1 /* GP10_EINT */
+#define WM8995_GP9_EINT                         0x0100 /* GP9_EINT */
+#define WM8995_GP9_EINT_MASK                    0x0100 /* GP9_EINT */
+#define WM8995_GP9_EINT_SHIFT                        8 /* GP9_EINT */
+#define WM8995_GP9_EINT_WIDTH                        1 /* GP9_EINT */
+#define WM8995_GP8_EINT                         0x0080 /* GP8_EINT */
+#define WM8995_GP8_EINT_MASK                    0x0080 /* GP8_EINT */
+#define WM8995_GP8_EINT_SHIFT                        7 /* GP8_EINT */
+#define WM8995_GP8_EINT_WIDTH                        1 /* GP8_EINT */
+#define WM8995_GP7_EINT                         0x0040 /* GP7_EINT */
+#define WM8995_GP7_EINT_MASK                    0x0040 /* GP7_EINT */
+#define WM8995_GP7_EINT_SHIFT                        6 /* GP7_EINT */
+#define WM8995_GP7_EINT_WIDTH                        1 /* GP7_EINT */
+#define WM8995_GP6_EINT                         0x0020 /* GP6_EINT */
+#define WM8995_GP6_EINT_MASK                    0x0020 /* GP6_EINT */
+#define WM8995_GP6_EINT_SHIFT                        5 /* GP6_EINT */
+#define WM8995_GP6_EINT_WIDTH                        1 /* GP6_EINT */
+#define WM8995_GP5_EINT                         0x0010 /* GP5_EINT */
+#define WM8995_GP5_EINT_MASK                    0x0010 /* GP5_EINT */
+#define WM8995_GP5_EINT_SHIFT                        4 /* GP5_EINT */
+#define WM8995_GP5_EINT_WIDTH                        1 /* GP5_EINT */
+#define WM8995_GP4_EINT                         0x0008 /* GP4_EINT */
+#define WM8995_GP4_EINT_MASK                    0x0008 /* GP4_EINT */
+#define WM8995_GP4_EINT_SHIFT                        3 /* GP4_EINT */
+#define WM8995_GP4_EINT_WIDTH                        1 /* GP4_EINT */
+#define WM8995_GP3_EINT                         0x0004 /* GP3_EINT */
+#define WM8995_GP3_EINT_MASK                    0x0004 /* GP3_EINT */
+#define WM8995_GP3_EINT_SHIFT                        2 /* GP3_EINT */
+#define WM8995_GP3_EINT_WIDTH                        1 /* GP3_EINT */
+#define WM8995_GP2_EINT                         0x0002 /* GP2_EINT */
+#define WM8995_GP2_EINT_MASK                    0x0002 /* GP2_EINT */
+#define WM8995_GP2_EINT_SHIFT                        1 /* GP2_EINT */
+#define WM8995_GP2_EINT_WIDTH                        1 /* GP2_EINT */
+#define WM8995_GP1_EINT                         0x0001 /* GP1_EINT */
+#define WM8995_GP1_EINT_MASK                    0x0001 /* GP1_EINT */
+#define WM8995_GP1_EINT_SHIFT                        0 /* GP1_EINT */
+#define WM8995_GP1_EINT_WIDTH                        1 /* GP1_EINT */
+
+/*
+ * R1841 (0x731) - Interrupt Status 2
+ */
+#define WM8995_DCS_DONE_23_EINT                 0x1000 /* DCS_DONE_23_EINT */
+#define WM8995_DCS_DONE_23_EINT_MASK            0x1000 /* DCS_DONE_23_EINT */
+#define WM8995_DCS_DONE_23_EINT_SHIFT               12 /* DCS_DONE_23_EINT */
+#define WM8995_DCS_DONE_23_EINT_WIDTH                1 /* DCS_DONE_23_EINT */
+#define WM8995_DCS_DONE_01_EINT                 0x0800 /* DCS_DONE_01_EINT */
+#define WM8995_DCS_DONE_01_EINT_MASK            0x0800 /* DCS_DONE_01_EINT */
+#define WM8995_DCS_DONE_01_EINT_SHIFT               11 /* DCS_DONE_01_EINT */
+#define WM8995_DCS_DONE_01_EINT_WIDTH                1 /* DCS_DONE_01_EINT */
+#define WM8995_WSEQ_DONE_EINT                   0x0400 /* WSEQ_DONE_EINT */
+#define WM8995_WSEQ_DONE_EINT_MASK              0x0400 /* WSEQ_DONE_EINT */
+#define WM8995_WSEQ_DONE_EINT_SHIFT                 10 /* WSEQ_DONE_EINT */
+#define WM8995_WSEQ_DONE_EINT_WIDTH                  1 /* WSEQ_DONE_EINT */
+#define WM8995_FIFOS_ERR_EINT                   0x0200 /* FIFOS_ERR_EINT */
+#define WM8995_FIFOS_ERR_EINT_MASK              0x0200 /* FIFOS_ERR_EINT */
+#define WM8995_FIFOS_ERR_EINT_SHIFT                  9 /* FIFOS_ERR_EINT */
+#define WM8995_FIFOS_ERR_EINT_WIDTH                  1 /* FIFOS_ERR_EINT */
+#define WM8995_AIF2DRC_SIG_DET_EINT             0x0100 /* AIF2DRC_SIG_DET_EINT */
+#define WM8995_AIF2DRC_SIG_DET_EINT_MASK        0x0100 /* AIF2DRC_SIG_DET_EINT */
+#define WM8995_AIF2DRC_SIG_DET_EINT_SHIFT            8 /* AIF2DRC_SIG_DET_EINT */
+#define WM8995_AIF2DRC_SIG_DET_EINT_WIDTH            1 /* AIF2DRC_SIG_DET_EINT */
+#define WM8995_AIF1DRC2_SIG_DET_EINT            0x0080 /* AIF1DRC2_SIG_DET_EINT */
+#define WM8995_AIF1DRC2_SIG_DET_EINT_MASK       0x0080 /* AIF1DRC2_SIG_DET_EINT */
+#define WM8995_AIF1DRC2_SIG_DET_EINT_SHIFT           7 /* AIF1DRC2_SIG_DET_EINT */
+#define WM8995_AIF1DRC2_SIG_DET_EINT_WIDTH           1 /* AIF1DRC2_SIG_DET_EINT */
+#define WM8995_AIF1DRC1_SIG_DET_EINT            0x0040 /* AIF1DRC1_SIG_DET_EINT */
+#define WM8995_AIF1DRC1_SIG_DET_EINT_MASK       0x0040 /* AIF1DRC1_SIG_DET_EINT */
+#define WM8995_AIF1DRC1_SIG_DET_EINT_SHIFT           6 /* AIF1DRC1_SIG_DET_EINT */
+#define WM8995_AIF1DRC1_SIG_DET_EINT_WIDTH           1 /* AIF1DRC1_SIG_DET_EINT */
+#define WM8995_SRC2_LOCK_EINT                   0x0020 /* SRC2_LOCK_EINT */
+#define WM8995_SRC2_LOCK_EINT_MASK              0x0020 /* SRC2_LOCK_EINT */
+#define WM8995_SRC2_LOCK_EINT_SHIFT                  5 /* SRC2_LOCK_EINT */
+#define WM8995_SRC2_LOCK_EINT_WIDTH                  1 /* SRC2_LOCK_EINT */
+#define WM8995_SRC1_LOCK_EINT                   0x0010 /* SRC1_LOCK_EINT */
+#define WM8995_SRC1_LOCK_EINT_MASK              0x0010 /* SRC1_LOCK_EINT */
+#define WM8995_SRC1_LOCK_EINT_SHIFT                  4 /* SRC1_LOCK_EINT */
+#define WM8995_SRC1_LOCK_EINT_WIDTH                  1 /* SRC1_LOCK_EINT */
+#define WM8995_FLL2_LOCK_EINT                   0x0008 /* FLL2_LOCK_EINT */
+#define WM8995_FLL2_LOCK_EINT_MASK              0x0008 /* FLL2_LOCK_EINT */
+#define WM8995_FLL2_LOCK_EINT_SHIFT                  3 /* FLL2_LOCK_EINT */
+#define WM8995_FLL2_LOCK_EINT_WIDTH                  1 /* FLL2_LOCK_EINT */
+#define WM8995_FLL1_LOCK_EINT                   0x0004 /* FLL1_LOCK_EINT */
+#define WM8995_FLL1_LOCK_EINT_MASK              0x0004 /* FLL1_LOCK_EINT */
+#define WM8995_FLL1_LOCK_EINT_SHIFT                  2 /* FLL1_LOCK_EINT */
+#define WM8995_FLL1_LOCK_EINT_WIDTH                  1 /* FLL1_LOCK_EINT */
+#define WM8995_HP_DONE_EINT                     0x0002 /* HP_DONE_EINT */
+#define WM8995_HP_DONE_EINT_MASK                0x0002 /* HP_DONE_EINT */
+#define WM8995_HP_DONE_EINT_SHIFT                    1 /* HP_DONE_EINT */
+#define WM8995_HP_DONE_EINT_WIDTH                    1 /* HP_DONE_EINT */
+#define WM8995_MICD_EINT                        0x0001 /* MICD_EINT */
+#define WM8995_MICD_EINT_MASK                   0x0001 /* MICD_EINT */
+#define WM8995_MICD_EINT_SHIFT                       0 /* MICD_EINT */
+#define WM8995_MICD_EINT_WIDTH                       1 /* MICD_EINT */
+
+/*
+ * R1842 (0x732) - Interrupt Raw Status 2
+ */
+#define WM8995_DCS_DONE_23_STS                  0x1000 /* DCS_DONE_23_STS */
+#define WM8995_DCS_DONE_23_STS_MASK             0x1000 /* DCS_DONE_23_STS */
+#define WM8995_DCS_DONE_23_STS_SHIFT                12 /* DCS_DONE_23_STS */
+#define WM8995_DCS_DONE_23_STS_WIDTH                 1 /* DCS_DONE_23_STS */
+#define WM8995_DCS_DONE_01_STS                  0x0800 /* DCS_DONE_01_STS */
+#define WM8995_DCS_DONE_01_STS_MASK             0x0800 /* DCS_DONE_01_STS */
+#define WM8995_DCS_DONE_01_STS_SHIFT                11 /* DCS_DONE_01_STS */
+#define WM8995_DCS_DONE_01_STS_WIDTH                 1 /* DCS_DONE_01_STS */
+#define WM8995_WSEQ_DONE_STS                    0x0400 /* WSEQ_DONE_STS */
+#define WM8995_WSEQ_DONE_STS_MASK               0x0400 /* WSEQ_DONE_STS */
+#define WM8995_WSEQ_DONE_STS_SHIFT                  10 /* WSEQ_DONE_STS */
+#define WM8995_WSEQ_DONE_STS_WIDTH                   1 /* WSEQ_DONE_STS */
+#define WM8995_FIFOS_ERR_STS                    0x0200 /* FIFOS_ERR_STS */
+#define WM8995_FIFOS_ERR_STS_MASK               0x0200 /* FIFOS_ERR_STS */
+#define WM8995_FIFOS_ERR_STS_SHIFT                   9 /* FIFOS_ERR_STS */
+#define WM8995_FIFOS_ERR_STS_WIDTH                   1 /* FIFOS_ERR_STS */
+#define WM8995_AIF2DRC_SIG_DET_STS              0x0100 /* AIF2DRC_SIG_DET_STS */
+#define WM8995_AIF2DRC_SIG_DET_STS_MASK         0x0100 /* AIF2DRC_SIG_DET_STS */
+#define WM8995_AIF2DRC_SIG_DET_STS_SHIFT             8 /* AIF2DRC_SIG_DET_STS */
+#define WM8995_AIF2DRC_SIG_DET_STS_WIDTH             1 /* AIF2DRC_SIG_DET_STS */
+#define WM8995_AIF1DRC2_SIG_DET_STS             0x0080 /* AIF1DRC2_SIG_DET_STS */
+#define WM8995_AIF1DRC2_SIG_DET_STS_MASK        0x0080 /* AIF1DRC2_SIG_DET_STS */
+#define WM8995_AIF1DRC2_SIG_DET_STS_SHIFT            7 /* AIF1DRC2_SIG_DET_STS */
+#define WM8995_AIF1DRC2_SIG_DET_STS_WIDTH            1 /* AIF1DRC2_SIG_DET_STS */
+#define WM8995_AIF1DRC1_SIG_DET_STS             0x0040 /* AIF1DRC1_SIG_DET_STS */
+#define WM8995_AIF1DRC1_SIG_DET_STS_MASK        0x0040 /* AIF1DRC1_SIG_DET_STS */
+#define WM8995_AIF1DRC1_SIG_DET_STS_SHIFT            6 /* AIF1DRC1_SIG_DET_STS */
+#define WM8995_AIF1DRC1_SIG_DET_STS_WIDTH            1 /* AIF1DRC1_SIG_DET_STS */
+#define WM8995_SRC2_LOCK_STS                    0x0020 /* SRC2_LOCK_STS */
+#define WM8995_SRC2_LOCK_STS_MASK               0x0020 /* SRC2_LOCK_STS */
+#define WM8995_SRC2_LOCK_STS_SHIFT                   5 /* SRC2_LOCK_STS */
+#define WM8995_SRC2_LOCK_STS_WIDTH                   1 /* SRC2_LOCK_STS */
+#define WM8995_SRC1_LOCK_STS                    0x0010 /* SRC1_LOCK_STS */
+#define WM8995_SRC1_LOCK_STS_MASK               0x0010 /* SRC1_LOCK_STS */
+#define WM8995_SRC1_LOCK_STS_SHIFT                   4 /* SRC1_LOCK_STS */
+#define WM8995_SRC1_LOCK_STS_WIDTH                   1 /* SRC1_LOCK_STS */
+#define WM8995_FLL2_LOCK_STS                    0x0008 /* FLL2_LOCK_STS */
+#define WM8995_FLL2_LOCK_STS_MASK               0x0008 /* FLL2_LOCK_STS */
+#define WM8995_FLL2_LOCK_STS_SHIFT                   3 /* FLL2_LOCK_STS */
+#define WM8995_FLL2_LOCK_STS_WIDTH                   1 /* FLL2_LOCK_STS */
+#define WM8995_FLL1_LOCK_STS                    0x0004 /* FLL1_LOCK_STS */
+#define WM8995_FLL1_LOCK_STS_MASK               0x0004 /* FLL1_LOCK_STS */
+#define WM8995_FLL1_LOCK_STS_SHIFT                   2 /* FLL1_LOCK_STS */
+#define WM8995_FLL1_LOCK_STS_WIDTH                   1 /* FLL1_LOCK_STS */
+
+/*
+ * R1848 (0x738) - Interrupt Status 1 Mask
+ */
+#define WM8995_IM_GP14_EINT                     0x2000 /* IM_GP14_EINT */
+#define WM8995_IM_GP14_EINT_MASK                0x2000 /* IM_GP14_EINT */
+#define WM8995_IM_GP14_EINT_SHIFT                   13 /* IM_GP14_EINT */
+#define WM8995_IM_GP14_EINT_WIDTH                    1 /* IM_GP14_EINT */
+#define WM8995_IM_GP13_EINT                     0x1000 /* IM_GP13_EINT */
+#define WM8995_IM_GP13_EINT_MASK                0x1000 /* IM_GP13_EINT */
+#define WM8995_IM_GP13_EINT_SHIFT                   12 /* IM_GP13_EINT */
+#define WM8995_IM_GP13_EINT_WIDTH                    1 /* IM_GP13_EINT */
+#define WM8995_IM_GP12_EINT                     0x0800 /* IM_GP12_EINT */
+#define WM8995_IM_GP12_EINT_MASK                0x0800 /* IM_GP12_EINT */
+#define WM8995_IM_GP12_EINT_SHIFT                   11 /* IM_GP12_EINT */
+#define WM8995_IM_GP12_EINT_WIDTH                    1 /* IM_GP12_EINT */
+#define WM8995_IM_GP11_EINT                     0x0400 /* IM_GP11_EINT */
+#define WM8995_IM_GP11_EINT_MASK                0x0400 /* IM_GP11_EINT */
+#define WM8995_IM_GP11_EINT_SHIFT                   10 /* IM_GP11_EINT */
+#define WM8995_IM_GP11_EINT_WIDTH                    1 /* IM_GP11_EINT */
+#define WM8995_IM_GP10_EINT                     0x0200 /* IM_GP10_EINT */
+#define WM8995_IM_GP10_EINT_MASK                0x0200 /* IM_GP10_EINT */
+#define WM8995_IM_GP10_EINT_SHIFT                    9 /* IM_GP10_EINT */
+#define WM8995_IM_GP10_EINT_WIDTH                    1 /* IM_GP10_EINT */
+#define WM8995_IM_GP9_EINT                      0x0100 /* IM_GP9_EINT */
+#define WM8995_IM_GP9_EINT_MASK                 0x0100 /* IM_GP9_EINT */
+#define WM8995_IM_GP9_EINT_SHIFT                     8 /* IM_GP9_EINT */
+#define WM8995_IM_GP9_EINT_WIDTH                     1 /* IM_GP9_EINT */
+#define WM8995_IM_GP8_EINT                      0x0080 /* IM_GP8_EINT */
+#define WM8995_IM_GP8_EINT_MASK                 0x0080 /* IM_GP8_EINT */
+#define WM8995_IM_GP8_EINT_SHIFT                     7 /* IM_GP8_EINT */
+#define WM8995_IM_GP8_EINT_WIDTH                     1 /* IM_GP8_EINT */
+#define WM8995_IM_GP7_EINT                      0x0040 /* IM_GP7_EINT */
+#define WM8995_IM_GP7_EINT_MASK                 0x0040 /* IM_GP7_EINT */
+#define WM8995_IM_GP7_EINT_SHIFT                     6 /* IM_GP7_EINT */
+#define WM8995_IM_GP7_EINT_WIDTH                     1 /* IM_GP7_EINT */
+#define WM8995_IM_GP6_EINT                      0x0020 /* IM_GP6_EINT */
+#define WM8995_IM_GP6_EINT_MASK                 0x0020 /* IM_GP6_EINT */
+#define WM8995_IM_GP6_EINT_SHIFT                     5 /* IM_GP6_EINT */
+#define WM8995_IM_GP6_EINT_WIDTH                     1 /* IM_GP6_EINT */
+#define WM8995_IM_GP5_EINT                      0x0010 /* IM_GP5_EINT */
+#define WM8995_IM_GP5_EINT_MASK                 0x0010 /* IM_GP5_EINT */
+#define WM8995_IM_GP5_EINT_SHIFT                     4 /* IM_GP5_EINT */
+#define WM8995_IM_GP5_EINT_WIDTH                     1 /* IM_GP5_EINT */
+#define WM8995_IM_GP4_EINT                      0x0008 /* IM_GP4_EINT */
+#define WM8995_IM_GP4_EINT_MASK                 0x0008 /* IM_GP4_EINT */
+#define WM8995_IM_GP4_EINT_SHIFT                     3 /* IM_GP4_EINT */
+#define WM8995_IM_GP4_EINT_WIDTH                     1 /* IM_GP4_EINT */
+#define WM8995_IM_GP3_EINT                      0x0004 /* IM_GP3_EINT */
+#define WM8995_IM_GP3_EINT_MASK                 0x0004 /* IM_GP3_EINT */
+#define WM8995_IM_GP3_EINT_SHIFT                     2 /* IM_GP3_EINT */
+#define WM8995_IM_GP3_EINT_WIDTH                     1 /* IM_GP3_EINT */
+#define WM8995_IM_GP2_EINT                      0x0002 /* IM_GP2_EINT */
+#define WM8995_IM_GP2_EINT_MASK                 0x0002 /* IM_GP2_EINT */
+#define WM8995_IM_GP2_EINT_SHIFT                     1 /* IM_GP2_EINT */
+#define WM8995_IM_GP2_EINT_WIDTH                     1 /* IM_GP2_EINT */
+#define WM8995_IM_GP1_EINT                      0x0001 /* IM_GP1_EINT */
+#define WM8995_IM_GP1_EINT_MASK                 0x0001 /* IM_GP1_EINT */
+#define WM8995_IM_GP1_EINT_SHIFT                     0 /* IM_GP1_EINT */
+#define WM8995_IM_GP1_EINT_WIDTH                     1 /* IM_GP1_EINT */
+
+/*
+ * R1849 (0x739) - Interrupt Status 2 Mask
+ */
+#define WM8995_IM_DCS_DONE_23_EINT              0x1000 /* IM_DCS_DONE_23_EINT */
+#define WM8995_IM_DCS_DONE_23_EINT_MASK         0x1000 /* IM_DCS_DONE_23_EINT */
+#define WM8995_IM_DCS_DONE_23_EINT_SHIFT            12 /* IM_DCS_DONE_23_EINT */
+#define WM8995_IM_DCS_DONE_23_EINT_WIDTH             1 /* IM_DCS_DONE_23_EINT */
+#define WM8995_IM_DCS_DONE_01_EINT              0x0800 /* IM_DCS_DONE_01_EINT */
+#define WM8995_IM_DCS_DONE_01_EINT_MASK         0x0800 /* IM_DCS_DONE_01_EINT */
+#define WM8995_IM_DCS_DONE_01_EINT_SHIFT            11 /* IM_DCS_DONE_01_EINT */
+#define WM8995_IM_DCS_DONE_01_EINT_WIDTH             1 /* IM_DCS_DONE_01_EINT */
+#define WM8995_IM_WSEQ_DONE_EINT                0x0400 /* IM_WSEQ_DONE_EINT */
+#define WM8995_IM_WSEQ_DONE_EINT_MASK           0x0400 /* IM_WSEQ_DONE_EINT */
+#define WM8995_IM_WSEQ_DONE_EINT_SHIFT              10 /* IM_WSEQ_DONE_EINT */
+#define WM8995_IM_WSEQ_DONE_EINT_WIDTH               1 /* IM_WSEQ_DONE_EINT */
+#define WM8995_IM_FIFOS_ERR_EINT                0x0200 /* IM_FIFOS_ERR_EINT */
+#define WM8995_IM_FIFOS_ERR_EINT_MASK           0x0200 /* IM_FIFOS_ERR_EINT */
+#define WM8995_IM_FIFOS_ERR_EINT_SHIFT               9 /* IM_FIFOS_ERR_EINT */
+#define WM8995_IM_FIFOS_ERR_EINT_WIDTH               1 /* IM_FIFOS_ERR_EINT */
+#define WM8995_IM_AIF2DRC_SIG_DET_EINT          0x0100 /* IM_AIF2DRC_SIG_DET_EINT */
+#define WM8995_IM_AIF2DRC_SIG_DET_EINT_MASK     0x0100 /* IM_AIF2DRC_SIG_DET_EINT */
+#define WM8995_IM_AIF2DRC_SIG_DET_EINT_SHIFT         8 /* IM_AIF2DRC_SIG_DET_EINT */
+#define WM8995_IM_AIF2DRC_SIG_DET_EINT_WIDTH         1 /* IM_AIF2DRC_SIG_DET_EINT */
+#define WM8995_IM_AIF1DRC2_SIG_DET_EINT         0x0080 /* IM_AIF1DRC2_SIG_DET_EINT */
+#define WM8995_IM_AIF1DRC2_SIG_DET_EINT_MASK    0x0080 /* IM_AIF1DRC2_SIG_DET_EINT */
+#define WM8995_IM_AIF1DRC2_SIG_DET_EINT_SHIFT        7 /* IM_AIF1DRC2_SIG_DET_EINT */
+#define WM8995_IM_AIF1DRC2_SIG_DET_EINT_WIDTH        1 /* IM_AIF1DRC2_SIG_DET_EINT */
+#define WM8995_IM_AIF1DRC1_SIG_DET_EINT         0x0040 /* IM_AIF1DRC1_SIG_DET_EINT */
+#define WM8995_IM_AIF1DRC1_SIG_DET_EINT_MASK    0x0040 /* IM_AIF1DRC1_SIG_DET_EINT */
+#define WM8995_IM_AIF1DRC1_SIG_DET_EINT_SHIFT        6 /* IM_AIF1DRC1_SIG_DET_EINT */
+#define WM8995_IM_AIF1DRC1_SIG_DET_EINT_WIDTH        1 /* IM_AIF1DRC1_SIG_DET_EINT */
+#define WM8995_IM_SRC2_LOCK_EINT                0x0020 /* IM_SRC2_LOCK_EINT */
+#define WM8995_IM_SRC2_LOCK_EINT_MASK           0x0020 /* IM_SRC2_LOCK_EINT */
+#define WM8995_IM_SRC2_LOCK_EINT_SHIFT               5 /* IM_SRC2_LOCK_EINT */
+#define WM8995_IM_SRC2_LOCK_EINT_WIDTH               1 /* IM_SRC2_LOCK_EINT */
+#define WM8995_IM_SRC1_LOCK_EINT                0x0010 /* IM_SRC1_LOCK_EINT */
+#define WM8995_IM_SRC1_LOCK_EINT_MASK           0x0010 /* IM_SRC1_LOCK_EINT */
+#define WM8995_IM_SRC1_LOCK_EINT_SHIFT               4 /* IM_SRC1_LOCK_EINT */
+#define WM8995_IM_SRC1_LOCK_EINT_WIDTH               1 /* IM_SRC1_LOCK_EINT */
+#define WM8995_IM_FLL2_LOCK_EINT                0x0008 /* IM_FLL2_LOCK_EINT */
+#define WM8995_IM_FLL2_LOCK_EINT_MASK           0x0008 /* IM_FLL2_LOCK_EINT */
+#define WM8995_IM_FLL2_LOCK_EINT_SHIFT               3 /* IM_FLL2_LOCK_EINT */
+#define WM8995_IM_FLL2_LOCK_EINT_WIDTH               1 /* IM_FLL2_LOCK_EINT */
+#define WM8995_IM_FLL1_LOCK_EINT                0x0004 /* IM_FLL1_LOCK_EINT */
+#define WM8995_IM_FLL1_LOCK_EINT_MASK           0x0004 /* IM_FLL1_LOCK_EINT */
+#define WM8995_IM_FLL1_LOCK_EINT_SHIFT               2 /* IM_FLL1_LOCK_EINT */
+#define WM8995_IM_FLL1_LOCK_EINT_WIDTH               1 /* IM_FLL1_LOCK_EINT */
+#define WM8995_IM_HP_DONE_EINT                  0x0002 /* IM_HP_DONE_EINT */
+#define WM8995_IM_HP_DONE_EINT_MASK             0x0002 /* IM_HP_DONE_EINT */
+#define WM8995_IM_HP_DONE_EINT_SHIFT                 1 /* IM_HP_DONE_EINT */
+#define WM8995_IM_HP_DONE_EINT_WIDTH                 1 /* IM_HP_DONE_EINT */
+#define WM8995_IM_MICD_EINT                     0x0001 /* IM_MICD_EINT */
+#define WM8995_IM_MICD_EINT_MASK                0x0001 /* IM_MICD_EINT */
+#define WM8995_IM_MICD_EINT_SHIFT                    0 /* IM_MICD_EINT */
+#define WM8995_IM_MICD_EINT_WIDTH                    1 /* IM_MICD_EINT */
+
+/*
+ * R1856 (0x740) - Interrupt Control
+ */
+#define WM8995_IM_IRQ                           0x0001 /* IM_IRQ */
+#define WM8995_IM_IRQ_MASK                      0x0001 /* IM_IRQ */
+#define WM8995_IM_IRQ_SHIFT                          0 /* IM_IRQ */
+#define WM8995_IM_IRQ_WIDTH                          1 /* IM_IRQ */
+
+/*
+ * R2048 (0x800) - Left PDM Speaker 1
+ */
+#define WM8995_SPK1L_ENA                        0x0010 /* SPK1L_ENA */
+#define WM8995_SPK1L_ENA_MASK                   0x0010 /* SPK1L_ENA */
+#define WM8995_SPK1L_ENA_SHIFT                       4 /* SPK1L_ENA */
+#define WM8995_SPK1L_ENA_WIDTH                       1 /* SPK1L_ENA */
+#define WM8995_SPK1L_MUTE                       0x0008 /* SPK1L_MUTE */
+#define WM8995_SPK1L_MUTE_MASK                  0x0008 /* SPK1L_MUTE */
+#define WM8995_SPK1L_MUTE_SHIFT                      3 /* SPK1L_MUTE */
+#define WM8995_SPK1L_MUTE_WIDTH                      1 /* SPK1L_MUTE */
+#define WM8995_SPK1L_MUTE_ZC                    0x0004 /* SPK1L_MUTE_ZC */
+#define WM8995_SPK1L_MUTE_ZC_MASK               0x0004 /* SPK1L_MUTE_ZC */
+#define WM8995_SPK1L_MUTE_ZC_SHIFT                   2 /* SPK1L_MUTE_ZC */
+#define WM8995_SPK1L_MUTE_ZC_WIDTH                   1 /* SPK1L_MUTE_ZC */
+#define WM8995_SPK1L_SRC_MASK                   0x0003 /* SPK1L_SRC - [1:0] */
+#define WM8995_SPK1L_SRC_SHIFT                       0 /* SPK1L_SRC - [1:0] */
+#define WM8995_SPK1L_SRC_WIDTH                       2 /* SPK1L_SRC - [1:0] */
+
+/*
+ * R2049 (0x801) - Right PDM Speaker 1
+ */
+#define WM8995_SPK1R_ENA                        0x0010 /* SPK1R_ENA */
+#define WM8995_SPK1R_ENA_MASK                   0x0010 /* SPK1R_ENA */
+#define WM8995_SPK1R_ENA_SHIFT                       4 /* SPK1R_ENA */
+#define WM8995_SPK1R_ENA_WIDTH                       1 /* SPK1R_ENA */
+#define WM8995_SPK1R_MUTE                       0x0008 /* SPK1R_MUTE */
+#define WM8995_SPK1R_MUTE_MASK                  0x0008 /* SPK1R_MUTE */
+#define WM8995_SPK1R_MUTE_SHIFT                      3 /* SPK1R_MUTE */
+#define WM8995_SPK1R_MUTE_WIDTH                      1 /* SPK1R_MUTE */
+#define WM8995_SPK1R_MUTE_ZC                    0x0004 /* SPK1R_MUTE_ZC */
+#define WM8995_SPK1R_MUTE_ZC_MASK               0x0004 /* SPK1R_MUTE_ZC */
+#define WM8995_SPK1R_MUTE_ZC_SHIFT                   2 /* SPK1R_MUTE_ZC */
+#define WM8995_SPK1R_MUTE_ZC_WIDTH                   1 /* SPK1R_MUTE_ZC */
+#define WM8995_SPK1R_SRC_MASK                   0x0003 /* SPK1R_SRC - [1:0] */
+#define WM8995_SPK1R_SRC_SHIFT                       0 /* SPK1R_SRC - [1:0] */
+#define WM8995_SPK1R_SRC_WIDTH                       2 /* SPK1R_SRC - [1:0] */
+
+/*
+ * R2050 (0x802) - PDM Speaker 1 Mute Sequence
+ */
+#define WM8995_SPK1_MUTE_SEQ1_MASK              0x00FF /* SPK1_MUTE_SEQ1 - [7:0] */
+#define WM8995_SPK1_MUTE_SEQ1_SHIFT                  0 /* SPK1_MUTE_SEQ1 - [7:0] */
+#define WM8995_SPK1_MUTE_SEQ1_WIDTH                  8 /* SPK1_MUTE_SEQ1 - [7:0] */
+
+/*
+ * R2056 (0x808) - Left PDM Speaker 2
+ */
+#define WM8995_SPK2L_ENA                        0x0010 /* SPK2L_ENA */
+#define WM8995_SPK2L_ENA_MASK                   0x0010 /* SPK2L_ENA */
+#define WM8995_SPK2L_ENA_SHIFT                       4 /* SPK2L_ENA */
+#define WM8995_SPK2L_ENA_WIDTH                       1 /* SPK2L_ENA */
+#define WM8995_SPK2L_MUTE                       0x0008 /* SPK2L_MUTE */
+#define WM8995_SPK2L_MUTE_MASK                  0x0008 /* SPK2L_MUTE */
+#define WM8995_SPK2L_MUTE_SHIFT                      3 /* SPK2L_MUTE */
+#define WM8995_SPK2L_MUTE_WIDTH                      1 /* SPK2L_MUTE */
+#define WM8995_SPK2L_MUTE_ZC                    0x0004 /* SPK2L_MUTE_ZC */
+#define WM8995_SPK2L_MUTE_ZC_MASK               0x0004 /* SPK2L_MUTE_ZC */
+#define WM8995_SPK2L_MUTE_ZC_SHIFT                   2 /* SPK2L_MUTE_ZC */
+#define WM8995_SPK2L_MUTE_ZC_WIDTH                   1 /* SPK2L_MUTE_ZC */
+#define WM8995_SPK2L_SRC_MASK                   0x0003 /* SPK2L_SRC - [1:0] */
+#define WM8995_SPK2L_SRC_SHIFT                       0 /* SPK2L_SRC - [1:0] */
+#define WM8995_SPK2L_SRC_WIDTH                       2 /* SPK2L_SRC - [1:0] */
+
+/*
+ * R2057 (0x809) - Right PDM Speaker 2
+ */
+#define WM8995_SPK2R_ENA                        0x0010 /* SPK2R_ENA */
+#define WM8995_SPK2R_ENA_MASK                   0x0010 /* SPK2R_ENA */
+#define WM8995_SPK2R_ENA_SHIFT                       4 /* SPK2R_ENA */
+#define WM8995_SPK2R_ENA_WIDTH                       1 /* SPK2R_ENA */
+#define WM8995_SPK2R_MUTE                       0x0008 /* SPK2R_MUTE */
+#define WM8995_SPK2R_MUTE_MASK                  0x0008 /* SPK2R_MUTE */
+#define WM8995_SPK2R_MUTE_SHIFT                      3 /* SPK2R_MUTE */
+#define WM8995_SPK2R_MUTE_WIDTH                      1 /* SPK2R_MUTE */
+#define WM8995_SPK2R_MUTE_ZC                    0x0004 /* SPK2R_MUTE_ZC */
+#define WM8995_SPK2R_MUTE_ZC_MASK               0x0004 /* SPK2R_MUTE_ZC */
+#define WM8995_SPK2R_MUTE_ZC_SHIFT                   2 /* SPK2R_MUTE_ZC */
+#define WM8995_SPK2R_MUTE_ZC_WIDTH                   1 /* SPK2R_MUTE_ZC */
+#define WM8995_SPK2R_SRC_MASK                   0x0003 /* SPK2R_SRC - [1:0] */
+#define WM8995_SPK2R_SRC_SHIFT                       0 /* SPK2R_SRC - [1:0] */
+#define WM8995_SPK2R_SRC_WIDTH                       2 /* SPK2R_SRC - [1:0] */
+
+/*
+ * R2058 (0x80A) - PDM Speaker 2 Mute Sequence
+ */
+#define WM8995_SPK2_MUTE_SEQ1_MASK              0x00FF /* SPK2_MUTE_SEQ1 - [7:0] */
+#define WM8995_SPK2_MUTE_SEQ1_SHIFT                  0 /* SPK2_MUTE_SEQ1 - [7:0] */
+#define WM8995_SPK2_MUTE_SEQ1_WIDTH                  8 /* SPK2_MUTE_SEQ1 - [7:0] */
+
+#define WM8995_CLASS_W_SWITCH(xname, reg, shift, max, invert) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_volsw, \
+       .get = snd_soc_dapm_get_volsw, .put = wm8995_put_class_w, \
+       .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) \
+}
+
+struct wm8995_reg_access {
+       u16 read;
+       u16 write;
+       u16 vol;
+};
+
+/* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */
+enum clk_src {
+       WM8995_SYSCLK_MCLK1 = 1,
+       WM8995_SYSCLK_MCLK2,
+       WM8995_SYSCLK_FLL1,
+       WM8995_SYSCLK_FLL2,
+       WM8995_SYSCLK_OPCLK
+};
+
+#define WM8995_FLL1 1
+#define WM8995_FLL2 2
+
+#define WM8995_FLL_SRC_MCLK1  1
+#define WM8995_FLL_SRC_MCLK2  2
+#define WM8995_FLL_SRC_LRCLK  3
+#define WM8995_FLL_SRC_BCLK   4
+
+#endif /* _WM8995_H */
index a486670..43825b2 100644 (file)
@@ -23,7 +23,6 @@
 #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>
 
@@ -158,7 +157,6 @@ static struct {
 struct wm9081_priv {
        enum snd_soc_control_type control_type;
        void *control_data;
-       u16 reg_cache[WM9081_MAX_REGISTER + 1];
        int sysclk_source;
        int mclk_rate;
        int sysclk_rate;
@@ -591,6 +589,10 @@ static int wm9081_set_fll(struct snd_soc_codec *codec, int fll_id,
        reg5 |= fll_div.fll_clk_ref_div << WM9081_FLL_CLK_REF_DIV_SHIFT;
        snd_soc_write(codec, WM9081_FLL_CONTROL_5, reg5);
 
+       /* Set gain to the recommended value */
+       snd_soc_update_bits(codec, WM9081_FLL_CONTROL_4,
+                           WM9081_FLL_GAIN_MASK, 0);
+
        /* Enable the FLL */
        snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1 | WM9081_FLL_ENA);
 
@@ -805,7 +807,7 @@ static int wm9081_set_bias_level(struct snd_soc_codec *codec,
 
        case SND_SOC_BIAS_STANDBY:
                /* Initial cold start */
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        /* Disable LINEOUT discharge */
                        reg = snd_soc_read(codec, WM9081_ANTI_POP_CONTROL);
                        reg &= ~WM9081_LINEOUT_DISCH;
@@ -865,7 +867,7 @@ static int wm9081_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
 
        return 0;
 }
@@ -1228,6 +1230,7 @@ static struct snd_soc_dai_driver wm9081_dai = {
 static int wm9081_probe(struct snd_soc_codec *codec)
 {
        struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
        u16 reg;
 
@@ -1269,9 +1272,9 @@ static int wm9081_probe(struct snd_soc_codec *codec)
                                     ARRAY_SIZE(wm9081_eq_controls));
        }
 
-       snd_soc_dapm_new_controls(codec, wm9081_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, wm9081_dapm_widgets,
                                  ARRAY_SIZE(wm9081_dapm_widgets));
-       snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
+       snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths));
 
        return ret;
 }
index 6e5f64f..a788c42 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/slab.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/tlv.h>
 #include <sound/wm9090.h>
 
@@ -442,31 +441,32 @@ static const struct snd_soc_dapm_route audio_map_in2_diff[] = {
 static int wm9090_add_controls(struct snd_soc_codec *codec)
 {
        struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int i;
 
-       snd_soc_dapm_new_controls(codec, wm9090_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, wm9090_dapm_widgets,
                                  ARRAY_SIZE(wm9090_dapm_widgets));
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        snd_soc_add_controls(codec, wm9090_controls,
                             ARRAY_SIZE(wm9090_controls));
 
        if (wm9090->pdata.lin1_diff) {
-               snd_soc_dapm_add_routes(codec, audio_map_in1_diff,
+               snd_soc_dapm_add_routes(dapm, audio_map_in1_diff,
                                        ARRAY_SIZE(audio_map_in1_diff));
        } else {
-               snd_soc_dapm_add_routes(codec, audio_map_in1_se,
+               snd_soc_dapm_add_routes(dapm, audio_map_in1_se,
                                        ARRAY_SIZE(audio_map_in1_se));
                snd_soc_add_controls(codec, wm9090_in1_se_controls,
                                     ARRAY_SIZE(wm9090_in1_se_controls));
        }
 
        if (wm9090->pdata.lin2_diff) {
-               snd_soc_dapm_add_routes(codec, audio_map_in2_diff,
+               snd_soc_dapm_add_routes(dapm, audio_map_in2_diff,
                                        ARRAY_SIZE(audio_map_in2_diff));
        } else {
-               snd_soc_dapm_add_routes(codec, audio_map_in2_se,
+               snd_soc_dapm_add_routes(dapm, audio_map_in2_se,
                                        ARRAY_SIZE(audio_map_in2_se));
                snd_soc_add_controls(codec, wm9090_in2_se_controls,
                                     ARRAY_SIZE(wm9090_in2_se_controls));
@@ -513,7 +513,7 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        /* Restore the register cache */
                        for (i = 1; i < codec->driver->reg_cache_size; i++) {
                                if (reg_cache[i] == wm9090_reg_defaults[i])
@@ -543,7 +543,7 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
                break;
        }
 
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
 
        return 0;
 }
index a144acd..47b357a 100644 (file)
@@ -19,7 +19,6 @@
 #include <sound/ac97_codec.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include "wm9705.h"
 
@@ -203,9 +202,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int wm9705_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, wm9705_dapm_widgets,
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       snd_soc_dapm_new_controls(dapm, wm9705_dapm_widgets,
                                        ARRAY_SIZE(wm9705_dapm_widgets));
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
 }
index d2f224d..bf5d4ef 100644 (file)
@@ -20,7 +20,6 @@
 #include <sound/ac97_codec.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include "wm9712.h"
 
 #define WM9712_VERSION "0.4"
@@ -432,10 +431,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int wm9712_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, wm9712_dapm_widgets,
-                                 ARRAY_SIZE(wm9712_dapm_widgets));
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_new_controls(dapm, wm9712_dapm_widgets,
+                                 ARRAY_SIZE(wm9712_dapm_widgets));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
 }
@@ -570,7 +570,7 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec,
                ac97_write(codec, AC97_POWERDOWN, 0xffff);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index 7da13b0..38ed985 100644 (file)
@@ -26,7 +26,6 @@
 #include <sound/pcm_params.h>
 #include <sound/tlv.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include "wm9713.h"
 
@@ -647,10 +646,12 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static int wm9713_add_widgets(struct snd_soc_codec *codec)
 {
-       snd_soc_dapm_new_controls(codec, wm9713_dapm_widgets,
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       snd_soc_dapm_new_controls(dapm, wm9713_dapm_widgets,
                                  ARRAY_SIZE(wm9713_dapm_widgets));
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
 }
@@ -1147,7 +1148,7 @@ static int wm9713_set_bias_level(struct snd_soc_codec *codec,
                ac97_write(codec, AC97_POWERDOWN, 0xffff);
                break;
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
        return 0;
 }
 
index 0e24092..c466982 100644 (file)
@@ -22,7 +22,6 @@
 #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>
 
@@ -94,41 +93,61 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
        u16 reg, reg_l, reg_r, dcs_cfg;
 
-       /* Set for 32 series updates */
-       snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
-                           WM8993_DCS_SERIES_NO_01_MASK,
-                           32 << WM8993_DCS_SERIES_NO_01_SHIFT);
-       wait_for_dc_servo(codec,
-                         WM8993_DCS_TRIG_SERIES_0 | WM8993_DCS_TRIG_SERIES_1);
+       /* If we're using a digital only path and have a previously
+        * callibrated DC servo offset stored then use that. */
+       if (hubs->class_w && hubs->class_w_dcs) {
+               dev_dbg(codec->dev, "Using cached DC servo offset %x\n",
+                       hubs->class_w_dcs);
+               snd_soc_write(codec, WM8993_DC_SERVO_3, hubs->class_w_dcs);
+               wait_for_dc_servo(codec,
+                                 WM8993_DCS_TRIG_DAC_WR_0 |
+                                 WM8993_DCS_TRIG_DAC_WR_1);
+               return;
+       }
+
+       /* Devices not using a DCS code correction have startup mode */
+       if (hubs->dcs_codes) {
+               /* Set for 32 series updates */
+               snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
+                                   WM8993_DCS_SERIES_NO_01_MASK,
+                                   32 << WM8993_DCS_SERIES_NO_01_SHIFT);
+               wait_for_dc_servo(codec,
+                                 WM8993_DCS_TRIG_SERIES_0 |
+                                 WM8993_DCS_TRIG_SERIES_1);
+       } else {
+               wait_for_dc_servo(codec,
+                                 WM8993_DCS_TRIG_STARTUP_0 |
+                                 WM8993_DCS_TRIG_STARTUP_1);
+       }
+
+       /* Different chips in the family support different readback
+        * methods.
+        */
+       switch (hubs->dcs_readback_mode) {
+       case 0:
+               reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1)
+                       & WM8993_DCS_INTEG_CHAN_0_MASK;
+               reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
+                       & WM8993_DCS_INTEG_CHAN_1_MASK;
+               break;
+       case 1:
+               reg = snd_soc_read(codec, WM8993_DC_SERVO_3);
+               reg_l = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
+                       >> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
+               reg_r = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
+               break;
+       default:
+               WARN(1, "Unknown DCS readback method\n");
+               break;
+       }
+
+       dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
 
        /* Apply correction to DC servo result */
        if (hubs->dcs_codes) {
                dev_dbg(codec->dev, "Applying %d code DC servo correction\n",
                        hubs->dcs_codes);
 
-               /* Different chips in the family support different
-                * readback methods.
-                */
-               switch (hubs->dcs_readback_mode) {
-               case 0:
-                       reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1)
-                               & WM8993_DCS_INTEG_CHAN_0_MASK;;
-                       reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
-                               & WM8993_DCS_INTEG_CHAN_1_MASK;
-                       break;
-               case 1:
-                       reg = snd_soc_read(codec, WM8993_DC_SERVO_3);
-                       reg_l = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
-                               >> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
-                       reg_r = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
-                       break;
-               default:
-                       WARN(1, "Unknown DCS readback method\n");
-                       break;
-               }
-
-               dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
-
                /* HPOUT1L */
                if (reg_l + hubs->dcs_codes > 0 &&
                    reg_l + hubs->dcs_codes < 0xff)
@@ -148,7 +167,15 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
                wait_for_dc_servo(codec,
                                  WM8993_DCS_TRIG_DAC_WR_0 |
                                  WM8993_DCS_TRIG_DAC_WR_1);
+       } else {
+               dcs_cfg = reg_l << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
+               dcs_cfg |= reg_r;
        }
+
+       /* Save the callibrated offset if we're in class W mode and
+        * therefore don't have any analogue signal mixed in. */
+       if (hubs->class_w)
+               hubs->class_w_dcs = dcs_cfg;
 }
 
 /*
@@ -163,6 +190,9 @@ static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
 
        ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
 
+       /* Updating the analogue gains invalidates the DC servo cache */
+       hubs->class_w_dcs = 0;
+
        /* If we're applying an offset correction then updating the
         * callibration would be likely to introduce further offsets. */
        if (hubs->dcs_codes)
@@ -791,6 +821,8 @@ static const struct snd_soc_dapm_route lineout2_se_routes[] = {
 
 int wm_hubs_add_analogue_controls(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
        /* Latch volume update bits & default ZC on */
        snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_1_2_VOLUME,
                            WM8993_IN1_VU, WM8993_IN1_VU);
@@ -819,7 +851,7 @@ int wm_hubs_add_analogue_controls(struct snd_soc_codec *codec)
        snd_soc_add_controls(codec, analogue_snd_controls,
                             ARRAY_SIZE(analogue_snd_controls));
 
-       snd_soc_dapm_new_controls(codec, analogue_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, analogue_dapm_widgets,
                                  ARRAY_SIZE(analogue_dapm_widgets));
        return 0;
 }
@@ -828,24 +860,26 @@ EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_controls);
 int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec,
                                int lineout1_diff, int lineout2_diff)
 {
-       snd_soc_dapm_add_routes(codec, analogue_routes,
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       snd_soc_dapm_add_routes(dapm, analogue_routes,
                                ARRAY_SIZE(analogue_routes));
 
        if (lineout1_diff)
-               snd_soc_dapm_add_routes(codec,
+               snd_soc_dapm_add_routes(dapm,
                                        lineout1_diff_routes,
                                        ARRAY_SIZE(lineout1_diff_routes));
        else
-               snd_soc_dapm_add_routes(codec,
+               snd_soc_dapm_add_routes(dapm,
                                        lineout1_se_routes,
                                        ARRAY_SIZE(lineout1_se_routes));
 
        if (lineout2_diff)
-               snd_soc_dapm_add_routes(codec,
+               snd_soc_dapm_add_routes(dapm,
                                        lineout2_diff_routes,
                                        ARRAY_SIZE(lineout2_diff_routes));
        else
-               snd_soc_dapm_add_routes(codec,
+               snd_soc_dapm_add_routes(dapm,
                                        lineout2_se_routes,
                                        ARRAY_SIZE(lineout2_se_routes));
 
@@ -872,7 +906,7 @@ int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec,
         * VMID as an output and can disable it.
         */
        if (lineout1_diff && lineout2_diff)
-               codec->idle_bias_off = 1;
+               codec->dapm.idle_bias_off = 1;
 
        if (lineout1fb)
                snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
index e51c166..f8a5e97 100644 (file)
@@ -23,6 +23,9 @@ struct wm_hubs_data {
        int dcs_codes;
        int dcs_readback_mode;
        int hp_startup_mode;
+
+       bool class_w;
+       u16 class_w_dcs;
 };
 
 extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *);
index bc9e6b0..0c2d6ba 100644 (file)
@@ -18,7 +18,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/dma.h>
 #include <asm/mach-types.h>
@@ -27,7 +26,6 @@
 #include <mach/edma.h>
 #include <mach/mux.h>
 
-#include "../codecs/tlv320aic3x.h"
 #include "davinci-pcm.h"
 #include "davinci-i2s.h"
 #include "davinci-mcasp.h"
@@ -132,26 +130,27 @@ static const struct snd_soc_dapm_route audio_map[] = {
 static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
        /* Add davinci-evm specific widgets */
-       snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets,
                                  ARRAY_SIZE(aic3x_dapm_widgets));
 
        /* Set up davinci-evm specific audio path audio_map */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        /* not connected */
-       snd_soc_dapm_disable_pin(codec, "MONO_LOUT");
-       snd_soc_dapm_disable_pin(codec, "HPLCOM");
-       snd_soc_dapm_disable_pin(codec, "HPRCOM");
+       snd_soc_dapm_disable_pin(dapm, "MONO_LOUT");
+       snd_soc_dapm_disable_pin(dapm, "HPLCOM");
+       snd_soc_dapm_disable_pin(dapm, "HPRCOM");
 
        /* always connected */
-       snd_soc_dapm_enable_pin(codec, "Headphone Jack");
-       snd_soc_dapm_enable_pin(codec, "Line Out");
-       snd_soc_dapm_enable_pin(codec, "Mic Jack");
-       snd_soc_dapm_enable_pin(codec, "Line In");
+       snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+       snd_soc_dapm_enable_pin(dapm, "Line Out");
+       snd_soc_dapm_enable_pin(dapm, "Mic Jack");
+       snd_soc_dapm_enable_pin(dapm, "Line In");
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
 
        return 0;
 }
index 6c6666a..0fe558c 100644 (file)
@@ -21,7 +21,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/dma.h>
 #include <asm/mach-types.h>
index 4f48733..9ac93f6 100644 (file)
@@ -352,13 +352,13 @@ static struct snd_soc_dai_driver ep93xx_i2s_dai = {
        .playback       = {
                .channels_min   = 2,
                .channels_max   = 2,
-               .rates          = SNDRV_PCM_RATE_8000_48000,
+               .rates          = SNDRV_PCM_RATE_8000_96000,
                .formats        = EP93XX_I2S_FORMATS,
        },
        .capture        = {
                 .channels_min  = 2,
                 .channels_max  = 2,
-                .rates         = SNDRV_PCM_RATE_8000_48000,
+                .rates         = SNDRV_PCM_RATE_8000_96000,
                 .formats       = EP93XX_I2S_FORMATS,
        },
        .ops            = &ep93xx_i2s_dai_ops,
index 2f121dd..0667077 100644 (file)
@@ -35,9 +35,9 @@ static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
                                   SNDRV_PCM_INFO_INTERLEAVED   |
                                   SNDRV_PCM_INFO_BLOCK_TRANSFER),
                                   
-       .rates                  = SNDRV_PCM_RATE_8000_48000,
+       .rates                  = SNDRV_PCM_RATE_8000_96000,
        .rate_min               = SNDRV_PCM_RATE_8000,
-       .rate_max               = SNDRV_PCM_RATE_48000,
+       .rate_max               = SNDRV_PCM_RATE_96000,
        
        .formats                = (SNDRV_PCM_FMTBIT_S16_LE |
                                   SNDRV_PCM_FMTBIT_S24_LE |
index 28ab5ff..dfe1d7f 100644 (file)
@@ -15,7 +15,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
@@ -79,11 +78,12 @@ static const struct snd_soc_dapm_route audio_map[] = {
 static int snappercl15_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets,
                                  ARRAY_SIZE(tlv320aic23_dapm_widgets));
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
        return 0;
 }
 
index dd4fffd..e20c9e1 100644 (file)
@@ -22,7 +22,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <asm/mach-types.h>
 
 #include "../codecs/tlv320aic23.h"
index 390b6ff..30894ea 100644 (file)
@@ -456,13 +456,13 @@ static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
 static struct snd_soc_dai_driver imx_ssi_dai = {
        .probe = imx_ssi_dai_probe,
        .playback = {
-               .channels_min = 2,
+               .channels_min = 1,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000_96000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
        .capture = {
-               .channels_min = 2,
+               .channels_min = 1,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000_96000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
index 9eabc28..a7deb5c 100644 (file)
@@ -17,7 +17,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <asm/mach-types.h>
 
 static struct snd_soc_card imx_phycore;
index 30fdb15..75b4c72 100644 (file)
@@ -19,7 +19,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <mach/audmux.h>
 
@@ -213,11 +212,12 @@ static struct snd_soc_jack_pin mic_jack_pins[] = {
 static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_new_controls(codec, wm1133_ev1_widgets,
+       snd_soc_dapm_new_controls(dapm, wm1133_ev1_widgets,
                                  ARRAY_SIZE(wm1133_ev1_widgets));
 
-       snd_soc_dapm_add_routes(codec, wm1133_ev1_map,
+       snd_soc_dapm_add_routes(dapm, wm1133_ev1_map,
                                ARRAY_SIZE(wm1133_ev1_map));
 
        /* Headphone jack detection */
@@ -234,7 +234,7 @@ static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd)
        wm8350_mic_jack_detect(codec, &mic_jack, SND_JACK_MICROPHONE,
                               SND_JACK_BTN_0);
 
-       snd_soc_dapm_force_enable_pin(codec, "Mic Bias");
+       snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
 
        return 0;
 }
index f3cffd1..419bf4f 100644 (file)
@@ -28,7 +28,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/initval.h>
 
 #include "jz4740-i2s.h"
index ef1a99e..49723e3 100644 (file)
@@ -19,7 +19,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <linux/gpio.h>
 
 #define QI_LB60_SND_GPIO JZ_GPIO_PORTB(29)
@@ -59,10 +58,11 @@ static int qi_lb60_codec_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
-       snd_soc_dapm_nc_pin(codec, "LIN");
-       snd_soc_dapm_nc_pin(codec, "RIN");
+       snd_soc_dapm_nc_pin(dapm, "LIN");
+       snd_soc_dapm_nc_pin(dapm, "RIN");
 
        ret = snd_soc_dai_set_fmt(cpu_dai, QI_LB60_DAIFMT);
        if (ret < 0) {
@@ -70,9 +70,11 @@ static int qi_lb60_codec_init(struct snd_soc_pcm_runtime *rtd)
                return ret;
        }
 
-       snd_soc_dapm_new_controls(codec, qi_lb60_widgets, ARRAY_SIZE(qi_lb60_widgets));
-       snd_soc_dapm_add_routes(codec, qi_lb60_routes, ARRAY_SIZE(qi_lb60_routes));
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_new_controls(dapm, qi_lb60_widgets,
+                                 ARRAY_SIZE(qi_lb60_widgets));
+       snd_soc_dapm_add_routes(dapm, qi_lb60_routes,
+                               ARRAY_SIZE(qi_lb60_routes));
+       snd_soc_dapm_sync(dapm);
 
        return 0;
 }
index 16ec2a2..8f49e16 100644 (file)
@@ -11,10 +11,19 @@ config SND_KIRKWOOD_SOC_I2S
 
 config SND_KIRKWOOD_SOC_OPENRD
        tristate "SoC Audio support for Kirkwood Openrd Client"
-       depends on SND_KIRKWOOD_SOC && MACH_OPENRD_CLIENT
+       depends on SND_KIRKWOOD_SOC && (MACH_OPENRD_CLIENT || MACH_OPENRD_ULTIMATE)
        select SND_KIRKWOOD_SOC_I2S
        select SND_SOC_CS42L51
        help
          Say Y if you want to add support for SoC audio on
          Openrd Client.
 
+config SND_KIRKWOOD_SOC_T5325
+       tristate "SoC Audio support for HP t5325"
+       depends on SND_KIRKWOOD_SOC && MACH_T5325
+       select SND_KIRKWOOD_SOC_I2S
+       select SND_SOC_ALC5623
+       help
+         Say Y if you want to add support for SoC audio on
+         the HP t5325 thin client.
+
index 33a16dc..3e62ae9 100644 (file)
@@ -5,5 +5,7 @@ obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o
 obj-$(CONFIG_SND_KIRKWOOD_SOC_I2S) += snd-soc-kirkwood-i2s.o
 
 snd-soc-openrd-objs := kirkwood-openrd.o
+snd-soc-t5325-objs := kirkwood-t5325.o
 
 obj-$(CONFIG_SND_KIRKWOOD_SOC_OPENRD) += snd-soc-openrd.o
+obj-$(CONFIG_SND_KIRKWOOD_SOC_T5325) += snd-soc-t5325.o
index 9d7c81e..d863afb 100644 (file)
@@ -86,7 +86,7 @@ static int __init openrd_client_init(void)
 {
        int ret;
 
-       if (!machine_is_openrd_client())
+       if (!machine_is_openrd_client() && !machine_is_openrd_ultimate())
                return 0;
 
        openrd_client_snd_device = platform_device_alloc("soc-audio", -1);
diff --git a/sound/soc/kirkwood/kirkwood-t5325.c b/sound/soc/kirkwood/kirkwood-t5325.c
new file mode 100644 (file)
index 0000000..c8d2195
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * kirkwood-t5325.c
+ *
+ * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.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.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <mach/kirkwood.h>
+#include <plat/audio.h>
+#include <asm/mach-types.h>
+#include "../codecs/alc5623.h"
+
+static int t5325_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       int ret;
+       unsigned int freq, fmt;
+
+       fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS;
+       ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+       if (ret < 0)
+               return ret;
+
+       freq = params_rate(params) * 256;
+
+       return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN);
+
+}
+
+static struct snd_soc_ops t5325_ops = {
+       .hw_params = t5325_hw_params,
+};
+
+static const struct snd_soc_dapm_widget t5325_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route t5325_route[] = {
+       { "Headphone Jack",     NULL,   "HPL" },
+       { "Headphone Jack",     NULL,   "HPR" },
+
+       {"Speaker",             NULL,   "SPKOUT"},
+       {"Speaker",             NULL,   "SPKOUTN"},
+
+       { "MIC1",               NULL,   "Mic Jack" },
+       { "MIC2",               NULL,   "Mic Jack" },
+};
+
+static int t5325_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       snd_soc_dapm_new_controls(dapm, t5325_dapm_widgets,
+                               ARRAY_SIZE(t5325_dapm_widgets));
+
+       snd_soc_dapm_add_routes(dapm, t5325_route, ARRAY_SIZE(t5325_route));
+
+       snd_soc_dapm_enable_pin(dapm, "Mic Jack");
+       snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+       snd_soc_dapm_enable_pin(dapm, "Speaker");
+
+       snd_soc_dapm_sync(dapm);
+
+       return 0;
+}
+
+static struct snd_soc_dai_link t5325_dai[] = {
+{
+       .name = "ALC5621",
+       .stream_name = "ALC5621 HiFi",
+       .cpu_dai_name = "kirkwood-i2s",
+       .platform_name = "kirkwood-pcm-audio",
+       .codec_dai_name = "alc5621-hifi",
+       .codec_name = "alc562x-codec.0-001a",
+       .ops = &t5325_ops,
+       .init = t5325_dai_init,
+},
+};
+
+
+static struct snd_soc_card t5325 = {
+       .name = "t5325",
+       .dai_link = t5325_dai,
+       .num_links = ARRAY_SIZE(t5325_dai),
+};
+
+static struct platform_device *t5325_snd_device;
+
+static int __init t5325_init(void)
+{
+       int ret;
+
+       if (!machine_is_t5325())
+               return 0;
+
+       t5325_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!t5325_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(t5325_snd_device,
+                       &t5325);
+
+       ret = platform_device_add(t5325_snd_device);
+       if (ret) {
+               printk(KERN_ERR "%s: platform_device_add failed\n", __func__);
+               platform_device_put(t5325_snd_device);
+       }
+
+       return ret;
+}
+module_init(t5325_init);
+
+static void __exit t5325_exit(void)
+{
+       platform_device_unregister(t5325_snd_device);
+}
+module_exit(t5325_exit);
+
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
+MODULE_DESCRIPTION("ALSA SoC t5325 audio client");
+MODULE_LICENSE("GPL");
index 161f5b6..38a2d0d 100644 (file)
@@ -18,7 +18,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include "nuc900-audio.h"
 
index 979dd50..1617504 100644 (file)
@@ -22,7 +22,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
@@ -114,20 +113,21 @@ static const struct snd_soc_dapm_route audio_map[] = {
 static int am3517evm_aic23_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
        /* Add am3517-evm specific widgets */
-       snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets,
                                  ARRAY_SIZE(tlv320aic23_dapm_widgets));
 
        /* Set up davinci-evm specific audio path audio_map */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        /* always connected */
-       snd_soc_dapm_enable_pin(codec, "Line Out");
-       snd_soc_dapm_enable_pin(codec, "Line In");
-       snd_soc_dapm_enable_pin(codec, "Mic In");
+       snd_soc_dapm_enable_pin(dapm, "Line Out");
+       snd_soc_dapm_enable_pin(dapm, "Line In");
+       snd_soc_dapm_enable_pin(dapm, "Mic In");
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
 
        return 0;
 }
index 438146a..2101bdc 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/spinlock.h>
 #include <linux/tty.h>
 
-#include <sound/soc-dapm.h>
+#include <sound/soc.h>
 #include <sound/jack.h>
 
 #include <asm/mach-types.h>
@@ -94,6 +94,7 @@ static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
                                        struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        struct soc_enum *control = (struct soc_enum *)kcontrol->private_value;
        unsigned short pins;
        int pin, changed = 0;
@@ -112,48 +113,48 @@ static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
 
        /* Setup pins after corresponding bits if changed */
        pin = !!(pins & (1 << AMS_DELTA_MOUTHPIECE));
-       if (pin != snd_soc_dapm_get_pin_status(codec, "Mouthpiece")) {
+       if (pin != snd_soc_dapm_get_pin_status(dapm, "Mouthpiece")) {
                changed = 1;
                if (pin)
-                       snd_soc_dapm_enable_pin(codec, "Mouthpiece");
+                       snd_soc_dapm_enable_pin(dapm, "Mouthpiece");
                else
-                       snd_soc_dapm_disable_pin(codec, "Mouthpiece");
+                       snd_soc_dapm_disable_pin(dapm, "Mouthpiece");
        }
        pin = !!(pins & (1 << AMS_DELTA_EARPIECE));
-       if (pin != snd_soc_dapm_get_pin_status(codec, "Earpiece")) {
+       if (pin != snd_soc_dapm_get_pin_status(dapm, "Earpiece")) {
                changed = 1;
                if (pin)
-                       snd_soc_dapm_enable_pin(codec, "Earpiece");
+                       snd_soc_dapm_enable_pin(dapm, "Earpiece");
                else
-                       snd_soc_dapm_disable_pin(codec, "Earpiece");
+                       snd_soc_dapm_disable_pin(dapm, "Earpiece");
        }
        pin = !!(pins & (1 << AMS_DELTA_MICROPHONE));
-       if (pin != snd_soc_dapm_get_pin_status(codec, "Microphone")) {
+       if (pin != snd_soc_dapm_get_pin_status(dapm, "Microphone")) {
                changed = 1;
                if (pin)
-                       snd_soc_dapm_enable_pin(codec, "Microphone");
+                       snd_soc_dapm_enable_pin(dapm, "Microphone");
                else
-                       snd_soc_dapm_disable_pin(codec, "Microphone");
+                       snd_soc_dapm_disable_pin(dapm, "Microphone");
        }
        pin = !!(pins & (1 << AMS_DELTA_SPEAKER));
-       if (pin != snd_soc_dapm_get_pin_status(codec, "Speaker")) {
+       if (pin != snd_soc_dapm_get_pin_status(dapm, "Speaker")) {
                changed = 1;
                if (pin)
-                       snd_soc_dapm_enable_pin(codec, "Speaker");
+                       snd_soc_dapm_enable_pin(dapm, "Speaker");
                else
-                       snd_soc_dapm_disable_pin(codec, "Speaker");
+                       snd_soc_dapm_disable_pin(dapm, "Speaker");
        }
        pin = !!(pins & (1 << AMS_DELTA_AGC));
        if (pin != ams_delta_audio_agc) {
                ams_delta_audio_agc = pin;
                changed = 1;
                if (pin)
-                       snd_soc_dapm_enable_pin(codec, "AGCIN");
+                       snd_soc_dapm_enable_pin(dapm, "AGCIN");
                else
-                       snd_soc_dapm_disable_pin(codec, "AGCIN");
+                       snd_soc_dapm_disable_pin(dapm, "AGCIN");
        }
        if (changed)
-               snd_soc_dapm_sync(codec);
+               snd_soc_dapm_sync(dapm);
 
        mutex_unlock(&codec->mutex);
 
@@ -164,19 +165,20 @@ static int ams_delta_get_audio_mode(struct snd_kcontrol *kcontrol,
                                        struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        unsigned short pins, mode;
 
-       pins = ((snd_soc_dapm_get_pin_status(codec, "Mouthpiece") <<
+       pins = ((snd_soc_dapm_get_pin_status(dapm, "Mouthpiece") <<
                                                        AMS_DELTA_MOUTHPIECE) |
-                       (snd_soc_dapm_get_pin_status(codec, "Earpiece") <<
+                       (snd_soc_dapm_get_pin_status(dapm, "Earpiece") <<
                                                        AMS_DELTA_EARPIECE));
        if (pins)
-               pins |= (snd_soc_dapm_get_pin_status(codec, "Microphone") <<
+               pins |= (snd_soc_dapm_get_pin_status(dapm, "Microphone") <<
                                                        AMS_DELTA_MICROPHONE);
        else
-               pins = ((snd_soc_dapm_get_pin_status(codec, "Microphone") <<
+               pins = ((snd_soc_dapm_get_pin_status(dapm, "Microphone") <<
                                                        AMS_DELTA_MICROPHONE) |
-                       (snd_soc_dapm_get_pin_status(codec, "Speaker") <<
+                       (snd_soc_dapm_get_pin_status(dapm, "Speaker") <<
                                                        AMS_DELTA_SPEAKER) |
                        (ams_delta_audio_agc << AMS_DELTA_AGC));
 
@@ -300,6 +302,7 @@ static int cx81801_open(struct tty_struct *tty)
 static void cx81801_close(struct tty_struct *tty)
 {
        struct snd_soc_codec *codec = tty->disc_data;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
        del_timer_sync(&cx81801_timer);
 
@@ -312,12 +315,12 @@ static void cx81801_close(struct tty_struct *tty)
        v253_ops.close(tty);
 
        /* Revert back to default audio input/output constellation */
-       snd_soc_dapm_disable_pin(codec, "Mouthpiece");
-       snd_soc_dapm_enable_pin(codec, "Earpiece");
-       snd_soc_dapm_enable_pin(codec, "Microphone");
-       snd_soc_dapm_disable_pin(codec, "Speaker");
-       snd_soc_dapm_disable_pin(codec, "AGCIN");
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_disable_pin(dapm, "Mouthpiece");
+       snd_soc_dapm_enable_pin(dapm, "Earpiece");
+       snd_soc_dapm_enable_pin(dapm, "Microphone");
+       snd_soc_dapm_disable_pin(dapm, "Speaker");
+       snd_soc_dapm_disable_pin(dapm, "AGCIN");
+       snd_soc_dapm_sync(dapm);
 }
 
 /* Line discipline .hangup() */
@@ -432,16 +435,16 @@ static int ams_delta_set_bias_level(struct snd_soc_card *card,
        case SND_SOC_BIAS_ON:
        case SND_SOC_BIAS_PREPARE:
        case SND_SOC_BIAS_STANDBY:
-               if (codec->bias_level == SND_SOC_BIAS_OFF)
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
                        ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_NRESET,
                                                AMS_DELTA_LATCH2_MODEM_NRESET);
                break;
        case SND_SOC_BIAS_OFF:
-               if (codec->bias_level != SND_SOC_BIAS_OFF)
+               if (codec->dapm.bias_level != SND_SOC_BIAS_OFF)
                        ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_NRESET,
                                                0);
        }
-       codec->bias_level = level;
+       codec->dapm.bias_level = level;
 
        return 0;
 }
@@ -492,6 +495,7 @@ static void ams_delta_shutdown(struct snd_pcm_substream *substream)
 static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_soc_card *card = rtd->card;
        int ret;
@@ -541,7 +545,7 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
        }
 
        /* Add board specific DAPM widgets and routes */
-       ret = snd_soc_dapm_new_controls(codec, ams_delta_dapm_widgets,
+       ret = snd_soc_dapm_new_controls(dapm, ams_delta_dapm_widgets,
                                        ARRAY_SIZE(ams_delta_dapm_widgets));
        if (ret) {
                dev_warn(card->dev,
@@ -550,7 +554,7 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
                return 0;
        }
 
-       ret = snd_soc_dapm_add_routes(codec, ams_delta_audio_map,
+       ret = snd_soc_dapm_add_routes(dapm, ams_delta_audio_map,
                                        ARRAY_SIZE(ams_delta_audio_map));
        if (ret) {
                dev_warn(card->dev,
@@ -560,13 +564,13 @@ static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
        }
 
        /* Set up initial pin constellation */
-       snd_soc_dapm_disable_pin(codec, "Mouthpiece");
-       snd_soc_dapm_enable_pin(codec, "Earpiece");
-       snd_soc_dapm_enable_pin(codec, "Microphone");
-       snd_soc_dapm_disable_pin(codec, "Speaker");
-       snd_soc_dapm_disable_pin(codec, "AGCIN");
-       snd_soc_dapm_disable_pin(codec, "AGCOUT");
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_disable_pin(dapm, "Mouthpiece");
+       snd_soc_dapm_enable_pin(dapm, "Earpiece");
+       snd_soc_dapm_enable_pin(dapm, "Microphone");
+       snd_soc_dapm_disable_pin(dapm, "Speaker");
+       snd_soc_dapm_disable_pin(dapm, "AGCIN");
+       snd_soc_dapm_disable_pin(dapm, "AGCOUT");
+       snd_soc_dapm_sync(dapm);
 
        /* Add virtual switch */
        ret = snd_soc_add_controls(codec, ams_delta_audio_controls,
index fd3a40f..0ae3470 100644 (file)
@@ -24,7 +24,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
index a3b6d89..83d213b 100644 (file)
@@ -27,7 +27,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
@@ -36,7 +35,6 @@
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
-#include "../codecs/tlv320aic3x.h"
 
 #define N810_HEADSET_AMP_GPIO  10
 #define N810_SPEAKER_AMP_GPIO  101
@@ -58,6 +56,7 @@ static int n810_dmic_func;
 
 static void n810_ext_control(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int hp = 0, line1l = 0;
 
        switch (n810_jack_func) {
@@ -72,25 +71,25 @@ static void n810_ext_control(struct snd_soc_codec *codec)
        }
 
        if (n810_spk_func)
-               snd_soc_dapm_enable_pin(codec, "Ext Spk");
+               snd_soc_dapm_enable_pin(dapm, "Ext Spk");
        else
-               snd_soc_dapm_disable_pin(codec, "Ext Spk");
+               snd_soc_dapm_disable_pin(dapm, "Ext Spk");
 
        if (hp)
-               snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+               snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
        else
-               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
        if (line1l)
-               snd_soc_dapm_enable_pin(codec, "LINE1L");
+               snd_soc_dapm_enable_pin(dapm, "LINE1L");
        else
-               snd_soc_dapm_disable_pin(codec, "LINE1L");
+               snd_soc_dapm_disable_pin(dapm, "LINE1L");
 
        if (n810_dmic_func)
-               snd_soc_dapm_enable_pin(codec, "DMic");
+               snd_soc_dapm_enable_pin(dapm, "DMic");
        else
-               snd_soc_dapm_disable_pin(codec, "DMic");
+               snd_soc_dapm_disable_pin(dapm, "DMic");
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
 }
 
 static int n810_startup(struct snd_pcm_substream *substream)
@@ -274,17 +273,18 @@ static const struct snd_kcontrol_new aic33_n810_controls[] = {
 static int n810_aic33_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int err;
 
        /* Not connected */
-       snd_soc_dapm_nc_pin(codec, "MONO_LOUT");
-       snd_soc_dapm_nc_pin(codec, "HPLCOM");
-       snd_soc_dapm_nc_pin(codec, "HPRCOM");
-       snd_soc_dapm_nc_pin(codec, "MIC3L");
-       snd_soc_dapm_nc_pin(codec, "MIC3R");
-       snd_soc_dapm_nc_pin(codec, "LINE1R");
-       snd_soc_dapm_nc_pin(codec, "LINE2L");
-       snd_soc_dapm_nc_pin(codec, "LINE2R");
+       snd_soc_dapm_nc_pin(dapm, "MONO_LOUT");
+       snd_soc_dapm_nc_pin(dapm, "HPLCOM");
+       snd_soc_dapm_nc_pin(dapm, "HPRCOM");
+       snd_soc_dapm_nc_pin(dapm, "MIC3L");
+       snd_soc_dapm_nc_pin(dapm, "MIC3R");
+       snd_soc_dapm_nc_pin(dapm, "LINE1R");
+       snd_soc_dapm_nc_pin(dapm, "LINE2L");
+       snd_soc_dapm_nc_pin(dapm, "LINE2R");
 
        /* Add N810 specific controls */
        err = snd_soc_add_controls(codec, aic33_n810_controls,
@@ -293,13 +293,13 @@ static int n810_aic33_init(struct snd_soc_pcm_runtime *rtd)
                return err;
 
        /* Add N810 specific widgets */
-       snd_soc_dapm_new_controls(codec, aic33_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, aic33_dapm_widgets,
                                  ARRAY_SIZE(aic33_dapm_widgets));
 
        /* Set up N810 specific audio path audio_map */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
 
        return 0;
 }
index 7e84f24..d203f4d 100644 (file)
@@ -102,6 +102,17 @@ static const int omap24xx_dma_reqs[][2] = {
 static const int omap24xx_dma_reqs[][2] = {};
 #endif
 
+#if defined(CONFIG_ARCH_OMAP4)
+static const int omap44xx_dma_reqs[][2] = {
+       { OMAP44XX_DMA_MCBSP1_TX, OMAP44XX_DMA_MCBSP1_RX },
+       { OMAP44XX_DMA_MCBSP2_TX, OMAP44XX_DMA_MCBSP2_RX },
+       { OMAP44XX_DMA_MCBSP3_TX, OMAP44XX_DMA_MCBSP3_RX },
+       { OMAP44XX_DMA_MCBSP4_TX, OMAP44XX_DMA_MCBSP4_RX },
+};
+#else
+static const int omap44xx_dma_reqs[][2] = {};
+#endif
+
 #if defined(CONFIG_ARCH_OMAP2420)
 static const unsigned long omap2420_mcbsp_port[][2] = {
        { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1,
@@ -147,6 +158,21 @@ static const unsigned long omap34xx_mcbsp_port[][2] = {
 static const unsigned long omap34xx_mcbsp_port[][2] = {};
 #endif
 
+#if defined(CONFIG_ARCH_OMAP4)
+static const unsigned long omap44xx_mcbsp_port[][2] = {
+       { OMAP44XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP44XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP44XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP44XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP44XX_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP44XX_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP44XX_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP44XX_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
+};
+#else
+static const unsigned long omap44xx_mcbsp_port[][2] = {};
+#endif
+
 static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -224,7 +250,7 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
         * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words)
         * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words)
         */
-       if (cpu_is_omap343x()) {
+       if (cpu_is_omap343x() || cpu_is_omap44xx()) {
                /*
                * Rule for the buffer size. We should not allow
                * smaller buffer than the FIFO size to avoid underruns
@@ -332,6 +358,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
        } else if (cpu_is_omap343x()) {
                dma = omap24xx_dma_reqs[bus_id][substream->stream];
                port = omap34xx_mcbsp_port[bus_id][substream->stream];
+        } else if (cpu_is_omap44xx()) {
+               dma = omap44xx_dma_reqs[bus_id][substream->stream];
+               port = omap44xx_mcbsp_port[bus_id][substream->stream];
        } else {
                return -ENODEV;
        }
@@ -498,11 +527,11 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        regs->spcr2     |= XINTM(3) | FREE;
        regs->spcr1     |= RINTM(3);
        /* RFIG and XFIG are not defined in 34xx */
-       if (!cpu_is_omap34xx()) {
+       if (!cpu_is_omap34xx() && !cpu_is_omap44xx()) {
                regs->rcr2      |= RFIG;
                regs->xcr2      |= XFIG;
        }
-       if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+       if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) {
                regs->xccr = DXENDLY(1) | XDMAEN | XDISABLE;
                regs->rccr = RFULL_CYCLE | RDMAEN | RDISABLE;
        }
index ffdcc5a..110c106 100644 (file)
@@ -50,6 +50,10 @@ enum omap_mcbsp_div {
 #undef  NUM_LINKS
 #define NUM_LINKS      3
 #endif
+#if defined(CONFIG_ARCH_OMAP4)
+#undef  NUM_LINKS
+#define NUM_LINKS      4
+#endif
 #if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
 #undef  NUM_LINKS
 #define NUM_LINKS      5
index cf3fc8a..29b60d6 100644 (file)
@@ -26,7 +26,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
index e56832b..40db813 100644 (file)
@@ -24,7 +24,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
index 810f1e3..0daa044 100644 (file)
@@ -22,7 +22,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
index 4ee33ce..8047c52 100644 (file)
@@ -28,7 +28,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
 #include <plat/mcbsp.h>
@@ -170,51 +169,53 @@ static const struct snd_soc_dapm_route omap3pandora_in_map[] = {
 static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
        /* All TWL4030 output pins are floating */
-       snd_soc_dapm_nc_pin(codec, "EARPIECE");
-       snd_soc_dapm_nc_pin(codec, "PREDRIVEL");
-       snd_soc_dapm_nc_pin(codec, "PREDRIVER");
-       snd_soc_dapm_nc_pin(codec, "HSOL");
-       snd_soc_dapm_nc_pin(codec, "HSOR");
-       snd_soc_dapm_nc_pin(codec, "CARKITL");
-       snd_soc_dapm_nc_pin(codec, "CARKITR");
-       snd_soc_dapm_nc_pin(codec, "HFL");
-       snd_soc_dapm_nc_pin(codec, "HFR");
-       snd_soc_dapm_nc_pin(codec, "VIBRA");
-
-       ret = snd_soc_dapm_new_controls(codec, omap3pandora_out_dapm_widgets,
+       snd_soc_dapm_nc_pin(dapm, "EARPIECE");
+       snd_soc_dapm_nc_pin(dapm, "PREDRIVEL");
+       snd_soc_dapm_nc_pin(dapm, "PREDRIVER");
+       snd_soc_dapm_nc_pin(dapm, "HSOL");
+       snd_soc_dapm_nc_pin(dapm, "HSOR");
+       snd_soc_dapm_nc_pin(dapm, "CARKITL");
+       snd_soc_dapm_nc_pin(dapm, "CARKITR");
+       snd_soc_dapm_nc_pin(dapm, "HFL");
+       snd_soc_dapm_nc_pin(dapm, "HFR");
+       snd_soc_dapm_nc_pin(dapm, "VIBRA");
+
+       ret = snd_soc_dapm_new_controls(dapm, omap3pandora_out_dapm_widgets,
                                ARRAY_SIZE(omap3pandora_out_dapm_widgets));
        if (ret < 0)
                return ret;
 
-       snd_soc_dapm_add_routes(codec, omap3pandora_out_map,
+       snd_soc_dapm_add_routes(dapm, omap3pandora_out_map,
                ARRAY_SIZE(omap3pandora_out_map));
 
-       return snd_soc_dapm_sync(codec);
+       return snd_soc_dapm_sync(dapm);
 }
 
 static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
        /* Not comnnected */
-       snd_soc_dapm_nc_pin(codec, "HSMIC");
-       snd_soc_dapm_nc_pin(codec, "CARKITMIC");
-       snd_soc_dapm_nc_pin(codec, "DIGIMIC0");
-       snd_soc_dapm_nc_pin(codec, "DIGIMIC1");
+       snd_soc_dapm_nc_pin(dapm, "HSMIC");
+       snd_soc_dapm_nc_pin(dapm, "CARKITMIC");
+       snd_soc_dapm_nc_pin(dapm, "DIGIMIC0");
+       snd_soc_dapm_nc_pin(dapm, "DIGIMIC1");
 
-       ret = snd_soc_dapm_new_controls(codec, omap3pandora_in_dapm_widgets,
+       ret = snd_soc_dapm_new_controls(dapm, omap3pandora_in_dapm_widgets,
                                ARRAY_SIZE(omap3pandora_in_dapm_widgets));
        if (ret < 0)
                return ret;
 
-       snd_soc_dapm_add_routes(codec, omap3pandora_in_map,
+       snd_soc_dapm_add_routes(dapm, omap3pandora_in_map,
                ARRAY_SIZE(omap3pandora_in_map));
 
-       return snd_soc_dapm_sync(codec);
+       return snd_soc_dapm_sync(dapm);
 }
 
 static struct snd_soc_ops omap3pandora_ops = {
index 65ae00e..7e75e77 100644 (file)
@@ -26,7 +26,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
@@ -116,19 +115,20 @@ static const struct snd_soc_dapm_route audio_map[] = {
 static int osk_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
        /* Add osk5912 specific widgets */
-       snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets,
                                  ARRAY_SIZE(tlv320aic23_dapm_widgets));
 
        /* Set up osk5912 specific audio path audio_map */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_enable_pin(codec, "Headphone Jack");
-       snd_soc_dapm_enable_pin(codec, "Line In");
-       snd_soc_dapm_enable_pin(codec, "Mic Jack");
+       snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+       snd_soc_dapm_enable_pin(dapm, "Line In");
+       snd_soc_dapm_enable_pin(dapm, "Mic Jack");
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
 
        return 0;
 }
index e95a607..bbcf380 100644 (file)
@@ -24,7 +24,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
index 04b5723..09fb0df 100644 (file)
 #include <sound/jack.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <plat/mcbsp.h>
 
 #include <asm/mach-types.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
-#include "../codecs/tlv320aic3x.h"
 
 #define RX51_TVOUT_SEL_GPIO            40
 #define RX51_JACK_DETECT_GPIO          177
@@ -58,19 +56,21 @@ static int rx51_jack_func;
 
 static void rx51_ext_control(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
        if (rx51_spk_func)
-               snd_soc_dapm_enable_pin(codec, "Ext Spk");
+               snd_soc_dapm_enable_pin(dapm, "Ext Spk");
        else
-               snd_soc_dapm_disable_pin(codec, "Ext Spk");
+               snd_soc_dapm_disable_pin(dapm, "Ext Spk");
        if (rx51_dmic_func)
-               snd_soc_dapm_enable_pin(codec, "DMic");
+               snd_soc_dapm_enable_pin(dapm, "DMic");
        else
-               snd_soc_dapm_disable_pin(codec, "DMic");
+               snd_soc_dapm_disable_pin(dapm, "DMic");
 
        gpio_set_value(RX51_TVOUT_SEL_GPIO,
                       rx51_jack_func == RX51_JACK_TVOUT);
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
 }
 
 static int rx51_startup(struct snd_pcm_substream *substream)
@@ -244,12 +244,13 @@ static const struct snd_kcontrol_new aic34_rx51_controls[] = {
 static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int err;
 
        /* Set up NC codec pins */
-       snd_soc_dapm_nc_pin(codec, "MIC3L");
-       snd_soc_dapm_nc_pin(codec, "MIC3R");
-       snd_soc_dapm_nc_pin(codec, "LINE1R");
+       snd_soc_dapm_nc_pin(dapm, "MIC3L");
+       snd_soc_dapm_nc_pin(dapm, "MIC3R");
+       snd_soc_dapm_nc_pin(dapm, "LINE1R");
 
        /* Add RX-51 specific controls */
        err = snd_soc_add_controls(codec, aic34_rx51_controls,
@@ -258,13 +259,13 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
                return err;
 
        /* Add RX-51 specific widgets */
-       snd_soc_dapm_new_controls(codec, aic34_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, aic34_dapm_widgets,
                                  ARRAY_SIZE(aic34_dapm_widgets));
 
        /* Set up RX-51 specific audio path audio_map */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
 
        /* AV jack detection */
        err = snd_soc_jack_new(codec, "AV Jack",
index 07fbcf7..3f72d17 100644 (file)
@@ -28,7 +28,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/jack.h>
 
 #include <asm/mach-types.h>
@@ -191,39 +190,40 @@ static const struct snd_soc_dapm_route audio_map[] = {
 static int sdp3430_twl4030_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
        /* Add SDP3430 specific widgets */
-       ret = snd_soc_dapm_new_controls(codec, sdp3430_twl4030_dapm_widgets,
+       ret = snd_soc_dapm_new_controls(dapm, sdp3430_twl4030_dapm_widgets,
                                ARRAY_SIZE(sdp3430_twl4030_dapm_widgets));
        if (ret)
                return ret;
 
        /* Set up SDP3430 specific audio path audio_map */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        /* SDP3430 connected pins */
-       snd_soc_dapm_enable_pin(codec, "Ext Mic");
-       snd_soc_dapm_enable_pin(codec, "Ext Spk");
-       snd_soc_dapm_disable_pin(codec, "Headset Mic");
-       snd_soc_dapm_disable_pin(codec, "Headset Stereophone");
+       snd_soc_dapm_enable_pin(dapm, "Ext Mic");
+       snd_soc_dapm_enable_pin(dapm, "Ext Spk");
+       snd_soc_dapm_disable_pin(dapm, "Headset Mic");
+       snd_soc_dapm_disable_pin(dapm, "Headset Stereophone");
 
        /* TWL4030 not connected pins */
-       snd_soc_dapm_nc_pin(codec, "AUXL");
-       snd_soc_dapm_nc_pin(codec, "AUXR");
-       snd_soc_dapm_nc_pin(codec, "CARKITMIC");
-       snd_soc_dapm_nc_pin(codec, "DIGIMIC0");
-       snd_soc_dapm_nc_pin(codec, "DIGIMIC1");
-
-       snd_soc_dapm_nc_pin(codec, "OUTL");
-       snd_soc_dapm_nc_pin(codec, "OUTR");
-       snd_soc_dapm_nc_pin(codec, "EARPIECE");
-       snd_soc_dapm_nc_pin(codec, "PREDRIVEL");
-       snd_soc_dapm_nc_pin(codec, "PREDRIVER");
-       snd_soc_dapm_nc_pin(codec, "CARKITL");
-       snd_soc_dapm_nc_pin(codec, "CARKITR");
-
-       ret = snd_soc_dapm_sync(codec);
+       snd_soc_dapm_nc_pin(dapm, "AUXL");
+       snd_soc_dapm_nc_pin(dapm, "AUXR");
+       snd_soc_dapm_nc_pin(dapm, "CARKITMIC");
+       snd_soc_dapm_nc_pin(dapm, "DIGIMIC0");
+       snd_soc_dapm_nc_pin(dapm, "DIGIMIC1");
+
+       snd_soc_dapm_nc_pin(dapm, "OUTL");
+       snd_soc_dapm_nc_pin(dapm, "OUTR");
+       snd_soc_dapm_nc_pin(dapm, "EARPIECE");
+       snd_soc_dapm_nc_pin(dapm, "PREDRIVEL");
+       snd_soc_dapm_nc_pin(dapm, "PREDRIVER");
+       snd_soc_dapm_nc_pin(dapm, "CARKITL");
+       snd_soc_dapm_nc_pin(dapm, "CARKITR");
+
+       ret = snd_soc_dapm_sync(dapm);
        if (ret)
                return ret;
 
index 4b4463d..189e039 100644 (file)
@@ -24,7 +24,7 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
+#include <sound/jack.h>
 
 #include <asm/mach-types.h>
 #include <plat/hardware.h>
@@ -66,6 +66,21 @@ static struct snd_soc_ops sdp4430_ops = {
        .hw_params = sdp4430_hw_params,
 };
 
+/* Headset jack */
+static struct snd_soc_jack hs_jack;
+
+/*Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       },
+       {
+               .pin = "Headset Stereophone",
+               .mask = SND_JACK_HEADPHONE,
+       },
+};
+
 static int sdp4430_get_power_mode(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
@@ -102,6 +117,7 @@ static const struct snd_soc_dapm_widget sdp4430_twl6040_dapm_widgets[] = {
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
        SND_SOC_DAPM_HP("Headset Stereophone", NULL),
        SND_SOC_DAPM_SPK("Earphone Spk", NULL),
+       SND_SOC_DAPM_INPUT("Aux/FM Stereo In"),
 };
 
 static const struct snd_soc_dapm_route audio_map[] = {
@@ -124,11 +140,16 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
        /* Earphone speaker */
        {"Earphone Spk", NULL, "EP"},
+
+       /* Aux/FM Stereo In: AFML, AFMR */
+       {"AFML", NULL, "Aux/FM Stereo In"},
+       {"AFMR", NULL, "Aux/FM Stereo In"},
 };
 
 static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
        /* Add SDP4430 specific controls */
@@ -138,25 +159,39 @@ static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
                return ret;
 
        /* Add SDP4430 specific widgets */
-       ret = snd_soc_dapm_new_controls(codec, sdp4430_twl6040_dapm_widgets,
+       ret = snd_soc_dapm_new_controls(dapm, sdp4430_twl6040_dapm_widgets,
                                ARRAY_SIZE(sdp4430_twl6040_dapm_widgets));
        if (ret)
                return ret;
 
        /* Set up SDP4430 specific audio path audio_map */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        /* SDP4430 connected pins */
-       snd_soc_dapm_enable_pin(codec, "Ext Mic");
-       snd_soc_dapm_enable_pin(codec, "Ext Spk");
-       snd_soc_dapm_enable_pin(codec, "Headset Mic");
-       snd_soc_dapm_enable_pin(codec, "Headset Stereophone");
+       snd_soc_dapm_enable_pin(dapm, "Ext Mic");
+       snd_soc_dapm_enable_pin(dapm, "Ext Spk");
+       snd_soc_dapm_enable_pin(dapm, "AFML");
+       snd_soc_dapm_enable_pin(dapm, "AFMR");
+       snd_soc_dapm_enable_pin(dapm, "Headset Mic");
+       snd_soc_dapm_enable_pin(dapm, "Headset Stereophone");
+
+       ret = snd_soc_dapm_sync(dapm);
+       if (ret)
+               return ret;
+
+       /* Headset jack detection */
+       ret = snd_soc_jack_new(codec, "Headset Jack",
+                               SND_JACK_HEADSET, &hs_jack);
+       if (ret)
+               return ret;
 
-       /* TWL6040 not connected pins */
-       snd_soc_dapm_nc_pin(codec, "AFML");
-       snd_soc_dapm_nc_pin(codec, "AFMR");
+       ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
+                               hs_jack_pins);
 
-       ret = snd_soc_dapm_sync(codec);
+       if (machine_is_omap_4430sdp())
+               twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
+       else
+               snd_soc_jack_report(&hs_jack, SND_JACK_HEADSET, SND_JACK_HEADSET);
 
        return ret;
 }
index 718031e..0170994 100644 (file)
@@ -24,7 +24,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
@@ -162,35 +161,36 @@ static const struct snd_soc_dapm_route audio_map[] = {
 static int zoom2_twl4030_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
        /* Add Zoom2 specific widgets */
-       ret = snd_soc_dapm_new_controls(codec, zoom2_twl4030_dapm_widgets,
+       ret = snd_soc_dapm_new_controls(dapm, zoom2_twl4030_dapm_widgets,
                                ARRAY_SIZE(zoom2_twl4030_dapm_widgets));
        if (ret)
                return ret;
 
        /* Set up Zoom2 specific audio path audio_map */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        /* Zoom2 connected pins */
-       snd_soc_dapm_enable_pin(codec, "Ext Mic");
-       snd_soc_dapm_enable_pin(codec, "Ext Spk");
-       snd_soc_dapm_enable_pin(codec, "Headset Mic");
-       snd_soc_dapm_enable_pin(codec, "Headset Stereophone");
-       snd_soc_dapm_enable_pin(codec, "Aux In");
+       snd_soc_dapm_enable_pin(dapm, "Ext Mic");
+       snd_soc_dapm_enable_pin(dapm, "Ext Spk");
+       snd_soc_dapm_enable_pin(dapm, "Headset Mic");
+       snd_soc_dapm_enable_pin(dapm, "Headset Stereophone");
+       snd_soc_dapm_enable_pin(dapm, "Aux In");
 
        /* TWL4030 not connected pins */
-       snd_soc_dapm_nc_pin(codec, "CARKITMIC");
-       snd_soc_dapm_nc_pin(codec, "DIGIMIC0");
-       snd_soc_dapm_nc_pin(codec, "DIGIMIC1");
-       snd_soc_dapm_nc_pin(codec, "EARPIECE");
-       snd_soc_dapm_nc_pin(codec, "PREDRIVEL");
-       snd_soc_dapm_nc_pin(codec, "PREDRIVER");
-       snd_soc_dapm_nc_pin(codec, "CARKITL");
-       snd_soc_dapm_nc_pin(codec, "CARKITR");
-
-       ret = snd_soc_dapm_sync(codec);
+       snd_soc_dapm_nc_pin(dapm, "CARKITMIC");
+       snd_soc_dapm_nc_pin(dapm, "DIGIMIC0");
+       snd_soc_dapm_nc_pin(dapm, "DIGIMIC1");
+       snd_soc_dapm_nc_pin(dapm, "EARPIECE");
+       snd_soc_dapm_nc_pin(dapm, "PREDRIVEL");
+       snd_soc_dapm_nc_pin(dapm, "PREDRIVER");
+       snd_soc_dapm_nc_pin(dapm, "CARKITL");
+       snd_soc_dapm_nc_pin(dapm, "CARKITR");
+
+       ret = snd_soc_dapm_sync(dapm);
 
        return ret;
 }
index f451acd..fc592f0 100644 (file)
@@ -23,7 +23,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
 #include <mach/corgi.h>
@@ -48,51 +47,53 @@ static int corgi_spk_func;
 
 static void corgi_ext_control(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
        /* set up jack connection */
        switch (corgi_jack_func) {
        case CORGI_HP:
                /* set = unmute headphone */
                gpio_set_value(CORGI_GPIO_MUTE_L, 1);
                gpio_set_value(CORGI_GPIO_MUTE_R, 1);
-               snd_soc_dapm_disable_pin(codec, "Mic Jack");
-               snd_soc_dapm_disable_pin(codec, "Line Jack");
-               snd_soc_dapm_enable_pin(codec, "Headphone Jack");
-               snd_soc_dapm_disable_pin(codec, "Headset Jack");
+               snd_soc_dapm_disable_pin(dapm, "Mic Jack");
+               snd_soc_dapm_disable_pin(dapm, "Line Jack");
+               snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin(dapm, "Headset Jack");
                break;
        case CORGI_MIC:
                /* reset = mute headphone */
                gpio_set_value(CORGI_GPIO_MUTE_L, 0);
                gpio_set_value(CORGI_GPIO_MUTE_R, 0);
-               snd_soc_dapm_enable_pin(codec, "Mic Jack");
-               snd_soc_dapm_disable_pin(codec, "Line Jack");
-               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
-               snd_soc_dapm_disable_pin(codec, "Headset Jack");
+               snd_soc_dapm_enable_pin(dapm, "Mic Jack");
+               snd_soc_dapm_disable_pin(dapm, "Line Jack");
+               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin(dapm, "Headset Jack");
                break;
        case CORGI_LINE:
                gpio_set_value(CORGI_GPIO_MUTE_L, 0);
                gpio_set_value(CORGI_GPIO_MUTE_R, 0);
-               snd_soc_dapm_disable_pin(codec, "Mic Jack");
-               snd_soc_dapm_enable_pin(codec, "Line Jack");
-               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
-               snd_soc_dapm_disable_pin(codec, "Headset Jack");
+               snd_soc_dapm_disable_pin(dapm, "Mic Jack");
+               snd_soc_dapm_enable_pin(dapm, "Line Jack");
+               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin(dapm, "Headset Jack");
                break;
        case CORGI_HEADSET:
                gpio_set_value(CORGI_GPIO_MUTE_L, 0);
                gpio_set_value(CORGI_GPIO_MUTE_R, 1);
-               snd_soc_dapm_enable_pin(codec, "Mic Jack");
-               snd_soc_dapm_disable_pin(codec, "Line Jack");
-               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
-               snd_soc_dapm_enable_pin(codec, "Headset Jack");
+               snd_soc_dapm_enable_pin(dapm, "Mic Jack");
+               snd_soc_dapm_disable_pin(dapm, "Line Jack");
+               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+               snd_soc_dapm_enable_pin(dapm, "Headset Jack");
                break;
        }
 
        if (corgi_spk_func == CORGI_SPK_ON)
-               snd_soc_dapm_enable_pin(codec, "Ext Spk");
+               snd_soc_dapm_enable_pin(dapm, "Ext Spk");
        else
-               snd_soc_dapm_disable_pin(codec, "Ext Spk");
+               snd_soc_dapm_disable_pin(dapm, "Ext Spk");
 
        /* signal a DAPM event */
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
 }
 
 static int corgi_startup(struct snd_pcm_substream *substream)
@@ -279,10 +280,11 @@ static const struct snd_kcontrol_new wm8731_corgi_controls[] = {
 static int corgi_wm8731_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int err;
 
-       snd_soc_dapm_nc_pin(codec, "LLINEIN");
-       snd_soc_dapm_nc_pin(codec, "RLINEIN");
+       snd_soc_dapm_nc_pin(dapm, "LLINEIN");
+       snd_soc_dapm_nc_pin(dapm, "RLINEIN");
 
        /* Add corgi specific controls */
        err = snd_soc_add_controls(codec, wm8731_corgi_controls,
@@ -291,13 +293,13 @@ static int corgi_wm8731_init(struct snd_soc_pcm_runtime *rtd)
                return err;
 
        /* Add corgi specific widgets */
-       snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, wm8731_dapm_widgets,
                                  ARRAY_SIZE(wm8731_dapm_widgets));
 
        /* Set up corgi specific audio path audio_map */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
        return 0;
 }
 
index c82cedb..28333e7 100644 (file)
@@ -16,7 +16,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <mach/audio.h>
 #include <mach/eseries-gpio.h>
@@ -92,23 +91,24 @@ static const struct snd_soc_dapm_route audio_map[] = {
 static int e740_ac97_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
-
-       snd_soc_dapm_nc_pin(codec, "HPOUTL");
-       snd_soc_dapm_nc_pin(codec, "HPOUTR");
-       snd_soc_dapm_nc_pin(codec, "PHONE");
-       snd_soc_dapm_nc_pin(codec, "LINEINL");
-       snd_soc_dapm_nc_pin(codec, "LINEINR");
-       snd_soc_dapm_nc_pin(codec, "CDINL");
-       snd_soc_dapm_nc_pin(codec, "CDINR");
-       snd_soc_dapm_nc_pin(codec, "PCBEEP");
-       snd_soc_dapm_nc_pin(codec, "MIC2");
-
-       snd_soc_dapm_new_controls(codec, e740_dapm_widgets,
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       snd_soc_dapm_nc_pin(dapm, "HPOUTL");
+       snd_soc_dapm_nc_pin(dapm, "HPOUTR");
+       snd_soc_dapm_nc_pin(dapm, "PHONE");
+       snd_soc_dapm_nc_pin(dapm, "LINEINL");
+       snd_soc_dapm_nc_pin(dapm, "LINEINR");
+       snd_soc_dapm_nc_pin(dapm, "CDINL");
+       snd_soc_dapm_nc_pin(dapm, "CDINR");
+       snd_soc_dapm_nc_pin(dapm, "PCBEEP");
+       snd_soc_dapm_nc_pin(dapm, "MIC2");
+
+       snd_soc_dapm_new_controls(dapm, e740_dapm_widgets,
                                        ARRAY_SIZE(e740_dapm_widgets));
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
 
        return 0;
 }
index 4c14380..01bf316 100644 (file)
@@ -16,7 +16,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <mach/audio.h>
 #include <mach/eseries-gpio.h>
@@ -74,23 +73,24 @@ static const struct snd_soc_dapm_route audio_map[] = {
 static int e750_ac97_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
-
-       snd_soc_dapm_nc_pin(codec, "LOUT");
-       snd_soc_dapm_nc_pin(codec, "ROUT");
-       snd_soc_dapm_nc_pin(codec, "PHONE");
-       snd_soc_dapm_nc_pin(codec, "LINEINL");
-       snd_soc_dapm_nc_pin(codec, "LINEINR");
-       snd_soc_dapm_nc_pin(codec, "CDINL");
-       snd_soc_dapm_nc_pin(codec, "CDINR");
-       snd_soc_dapm_nc_pin(codec, "PCBEEP");
-       snd_soc_dapm_nc_pin(codec, "MIC2");
-
-       snd_soc_dapm_new_controls(codec, e750_dapm_widgets,
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       snd_soc_dapm_nc_pin(dapm, "LOUT");
+       snd_soc_dapm_nc_pin(dapm, "ROUT");
+       snd_soc_dapm_nc_pin(dapm, "PHONE");
+       snd_soc_dapm_nc_pin(dapm, "LINEINL");
+       snd_soc_dapm_nc_pin(dapm, "LINEINR");
+       snd_soc_dapm_nc_pin(dapm, "CDINL");
+       snd_soc_dapm_nc_pin(dapm, "CDINR");
+       snd_soc_dapm_nc_pin(dapm, "PCBEEP");
+       snd_soc_dapm_nc_pin(dapm, "MIC2");
+
+       snd_soc_dapm_new_controls(dapm, e750_dapm_widgets,
                                        ARRAY_SIZE(e750_dapm_widgets));
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
 
        return 0;
 }
index d42e5fe..c6a37c6 100644 (file)
@@ -16,7 +16,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
 #include <mach/audio.h>
@@ -75,12 +74,13 @@ static const struct snd_soc_dapm_route audio_map[] = {
 static int e800_ac97_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_new_controls(codec, e800_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, e800_dapm_widgets,
                                        ARRAY_SIZE(e800_dapm_widgets));
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_sync(dapm);
 
        return 0;
 }
index eadf9d3..fc22e6e 100644 (file)
@@ -26,7 +26,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
 #include <mach/audio.h>
index 5ef0526..67dcc36 100644 (file)
@@ -26,7 +26,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/uda1380.h>
 
 #include <mach/magician.h>
@@ -44,27 +43,29 @@ static int magician_in_sel = MAGICIAN_MIC;
 
 static void magician_ext_control(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
        if (magician_spk_switch)
-               snd_soc_dapm_enable_pin(codec, "Speaker");
+               snd_soc_dapm_enable_pin(dapm, "Speaker");
        else
-               snd_soc_dapm_disable_pin(codec, "Speaker");
+               snd_soc_dapm_disable_pin(dapm, "Speaker");
        if (magician_hp_switch)
-               snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+               snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
        else
-               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
 
        switch (magician_in_sel) {
        case MAGICIAN_MIC:
-               snd_soc_dapm_disable_pin(codec, "Headset Mic");
-               snd_soc_dapm_enable_pin(codec, "Call Mic");
+               snd_soc_dapm_disable_pin(dapm, "Headset Mic");
+               snd_soc_dapm_enable_pin(dapm, "Call Mic");
                break;
        case MAGICIAN_MIC_EXT:
-               snd_soc_dapm_disable_pin(codec, "Call Mic");
-               snd_soc_dapm_enable_pin(codec, "Headset Mic");
+               snd_soc_dapm_disable_pin(dapm, "Call Mic");
+               snd_soc_dapm_enable_pin(dapm, "Headset Mic");
                break;
        }
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
 }
 
 static int magician_startup(struct snd_pcm_substream *substream)
@@ -399,15 +400,16 @@ static const struct snd_kcontrol_new uda1380_magician_controls[] = {
 static int magician_uda1380_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int err;
 
        /* NC codec pins */
-       snd_soc_dapm_nc_pin(codec, "VOUTLHP");
-       snd_soc_dapm_nc_pin(codec, "VOUTRHP");
+       snd_soc_dapm_nc_pin(dapm, "VOUTLHP");
+       snd_soc_dapm_nc_pin(dapm, "VOUTRHP");
 
        /* FIXME: is anything connected here? */
-       snd_soc_dapm_nc_pin(codec, "VINL");
-       snd_soc_dapm_nc_pin(codec, "VINR");
+       snd_soc_dapm_nc_pin(dapm, "VINL");
+       snd_soc_dapm_nc_pin(dapm, "VINR");
 
        /* Add magician specific controls */
        err = snd_soc_add_controls(codec, uda1380_magician_controls,
@@ -416,13 +418,13 @@ static int magician_uda1380_init(struct snd_soc_pcm_runtime *rtd)
                return err;
 
        /* Add magician specific widgets */
-       snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, uda1380_dapm_widgets,
                                  ARRAY_SIZE(uda1380_dapm_widgets));
 
        /* Set up magician specific audio path interconnects */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
        return 0;
 }
 
index f284cc5..0d70fc8 100644 (file)
@@ -50,7 +50,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/initval.h>
 #include <sound/ac97_codec.h>
 
@@ -130,13 +129,14 @@ static const struct snd_soc_dapm_route audio_map[] = {
 static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        unsigned short reg;
 
        /* Add mioa701 specific widgets */
-       snd_soc_dapm_new_controls(codec, ARRAY_AND_SIZE(mioa701_dapm_widgets));
+       snd_soc_dapm_new_controls(dapm, ARRAY_AND_SIZE(mioa701_dapm_widgets));
 
        /* Set up mioa701 specific audio path audio_mapnects */
-       snd_soc_dapm_add_routes(codec, ARRAY_AND_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, ARRAY_AND_SIZE(audio_map));
 
        /* Prepare GPIO8 for rear speaker amplifier */
        reg = codec->driver->read(codec, AC97_GPIO_CFG);
@@ -146,12 +146,12 @@ static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd)
        reg = codec->driver->read(codec, AC97_3D_CONTROL);
        codec->driver->write(codec, AC97_3D_CONTROL, reg | 0xc000);
 
-       snd_soc_dapm_enable_pin(codec, "Front Speaker");
-       snd_soc_dapm_enable_pin(codec, "Rear Speaker");
-       snd_soc_dapm_enable_pin(codec, "Front Mic");
-       snd_soc_dapm_enable_pin(codec, "GSM Line In");
-       snd_soc_dapm_enable_pin(codec, "GSM Line Out");
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_enable_pin(dapm, "Front Speaker");
+       snd_soc_dapm_enable_pin(dapm, "Rear Speaker");
+       snd_soc_dapm_enable_pin(dapm, "Front Mic");
+       snd_soc_dapm_enable_pin(dapm, "GSM Line In");
+       snd_soc_dapm_enable_pin(dapm, "GSM Line Out");
+       snd_soc_dapm_sync(dapm);
 
        return 0;
 }
index 13f6d48..857db96 100644 (file)
@@ -21,7 +21,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/jack.h>
 
 #include <asm/mach-types.h>
@@ -77,37 +76,38 @@ static struct snd_soc_card palm27x_asoc;
 static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int err;
 
        /* add palm27x specific widgets */
-       err = snd_soc_dapm_new_controls(codec, palm27x_dapm_widgets,
+       err = snd_soc_dapm_new_controls(dapm, palm27x_dapm_widgets,
                                ARRAY_SIZE(palm27x_dapm_widgets));
        if (err)
                return err;
 
        /* set up palm27x specific audio path audio_map */
-       err = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       err = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
        if (err)
                return err;
 
        /* connected pins */
        if (machine_is_palmld())
-               snd_soc_dapm_enable_pin(codec, "MIC1");
-       snd_soc_dapm_enable_pin(codec, "HPOUTL");
-       snd_soc_dapm_enable_pin(codec, "HPOUTR");
-       snd_soc_dapm_enable_pin(codec, "LOUT2");
-       snd_soc_dapm_enable_pin(codec, "ROUT2");
+               snd_soc_dapm_enable_pin(dapm, "MIC1");
+       snd_soc_dapm_enable_pin(dapm, "HPOUTL");
+       snd_soc_dapm_enable_pin(dapm, "HPOUTR");
+       snd_soc_dapm_enable_pin(dapm, "LOUT2");
+       snd_soc_dapm_enable_pin(dapm, "ROUT2");
 
        /* not connected pins */
-       snd_soc_dapm_nc_pin(codec, "OUT3");
-       snd_soc_dapm_nc_pin(codec, "MONOOUT");
-       snd_soc_dapm_nc_pin(codec, "LINEINL");
-       snd_soc_dapm_nc_pin(codec, "LINEINR");
-       snd_soc_dapm_nc_pin(codec, "PCBEEP");
-       snd_soc_dapm_nc_pin(codec, "PHONE");
-       snd_soc_dapm_nc_pin(codec, "MIC2");
-
-       err = snd_soc_dapm_sync(codec);
+       snd_soc_dapm_nc_pin(dapm, "OUT3");
+       snd_soc_dapm_nc_pin(dapm, "MONOOUT");
+       snd_soc_dapm_nc_pin(dapm, "LINEINL");
+       snd_soc_dapm_nc_pin(dapm, "LINEINR");
+       snd_soc_dapm_nc_pin(dapm, "PCBEEP");
+       snd_soc_dapm_nc_pin(dapm, "PHONE");
+       snd_soc_dapm_nc_pin(dapm, "MIC2");
+
+       err = snd_soc_dapm_sync(dapm);
        if (err)
                return err;
 
index 84edd03..6298ee1 100644 (file)
@@ -23,7 +23,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
 #include <asm/hardware/locomo.h>
@@ -46,6 +45,8 @@ static int poodle_spk_func;
 
 static void poodle_ext_control(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
        /* set up jack connection */
        if (poodle_jack_func == POODLE_HP) {
                /* set = unmute headphone */
@@ -53,23 +54,23 @@ static void poodle_ext_control(struct snd_soc_codec *codec)
                        POODLE_LOCOMO_GPIO_MUTE_L, 1);
                locomo_gpio_write(&poodle_locomo_device.dev,
                        POODLE_LOCOMO_GPIO_MUTE_R, 1);
-               snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+               snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
        } else {
                locomo_gpio_write(&poodle_locomo_device.dev,
                        POODLE_LOCOMO_GPIO_MUTE_L, 0);
                locomo_gpio_write(&poodle_locomo_device.dev,
                        POODLE_LOCOMO_GPIO_MUTE_R, 0);
-               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
        }
 
        /* set the enpoints to their new connetion states */
        if (poodle_spk_func == POODLE_SPK_ON)
-               snd_soc_dapm_enable_pin(codec, "Ext Spk");
+               snd_soc_dapm_enable_pin(dapm, "Ext Spk");
        else
-               snd_soc_dapm_disable_pin(codec, "Ext Spk");
+               snd_soc_dapm_disable_pin(dapm, "Ext Spk");
 
        /* signal a DAPM event */
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
 }
 
 static int poodle_startup(struct snd_pcm_substream *substream)
@@ -244,11 +245,12 @@ static const struct snd_kcontrol_new wm8731_poodle_controls[] = {
 static int poodle_wm8731_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int err;
 
-       snd_soc_dapm_nc_pin(codec, "LLINEIN");
-       snd_soc_dapm_nc_pin(codec, "RLINEIN");
-       snd_soc_dapm_enable_pin(codec, "MICIN");
+       snd_soc_dapm_nc_pin(dapm, "LLINEIN");
+       snd_soc_dapm_nc_pin(dapm, "RLINEIN");
+       snd_soc_dapm_enable_pin(dapm, "MICIN");
 
        /* Add poodle specific controls */
        err = snd_soc_add_controls(codec, wm8731_poodle_controls,
@@ -257,13 +259,13 @@ static int poodle_wm8731_init(struct snd_soc_pcm_runtime *rtd)
                return err;
 
        /* Add poodle specific widgets */
-       snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, wm8731_dapm_widgets,
                                  ARRAY_SIZE(wm8731_dapm_widgets));
 
        /* Set up poodle specific audio path audio_map */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
        return 0;
 }
 
index 2cda82b..0fd60f4 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/gpio.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
 
index d63cb47..9595189 100644 (file)
@@ -18,7 +18,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/jack.h>
 
 #include <asm/mach-types.h>
@@ -133,20 +132,21 @@ static struct snd_soc_card snd_soc_card_saarb = {
 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;
        int ret;
 
-       snd_soc_dapm_new_controls(codec, saarb_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, saarb_dapm_widgets,
                                  ARRAY_SIZE(saarb_dapm_widgets));
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        /* connected pins */
-       snd_soc_dapm_enable_pin(codec, "Ext Speaker");
-       snd_soc_dapm_enable_pin(codec, "Ext Mic 1");
-       snd_soc_dapm_enable_pin(codec, "Ext Mic 3");
-       snd_soc_dapm_disable_pin(codec, "Headset Mic 2");
-       snd_soc_dapm_disable_pin(codec, "Headset Stereophone");
+       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");
 
-       ret = snd_soc_dapm_sync(codec);
+       ret = snd_soc_dapm_sync(dapm);
        if (ret)
                return ret;
 
index 0b30d7d..c2acb69 100644 (file)
@@ -23,7 +23,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
 #include <mach/spitz.h>
@@ -46,61 +45,63 @@ static int spitz_spk_func;
 
 static void spitz_ext_control(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
        if (spitz_spk_func == SPITZ_SPK_ON)
-               snd_soc_dapm_enable_pin(codec, "Ext Spk");
+               snd_soc_dapm_enable_pin(dapm, "Ext Spk");
        else
-               snd_soc_dapm_disable_pin(codec, "Ext Spk");
+               snd_soc_dapm_disable_pin(dapm, "Ext Spk");
 
        /* set up jack connection */
        switch (spitz_jack_func) {
        case SPITZ_HP:
                /* enable and unmute hp jack, disable mic bias */
-               snd_soc_dapm_disable_pin(codec, "Headset Jack");
-               snd_soc_dapm_disable_pin(codec, "Mic Jack");
-               snd_soc_dapm_disable_pin(codec, "Line Jack");
-               snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+               snd_soc_dapm_disable_pin(dapm, "Headset Jack");
+               snd_soc_dapm_disable_pin(dapm, "Mic Jack");
+               snd_soc_dapm_disable_pin(dapm, "Line Jack");
+               snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
                gpio_set_value(SPITZ_GPIO_MUTE_L, 1);
                gpio_set_value(SPITZ_GPIO_MUTE_R, 1);
                break;
        case SPITZ_MIC:
                /* enable mic jack and bias, mute hp */
-               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
-               snd_soc_dapm_disable_pin(codec, "Headset Jack");
-               snd_soc_dapm_disable_pin(codec, "Line Jack");
-               snd_soc_dapm_enable_pin(codec, "Mic Jack");
+               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin(dapm, "Headset Jack");
+               snd_soc_dapm_disable_pin(dapm, "Line Jack");
+               snd_soc_dapm_enable_pin(dapm, "Mic Jack");
                gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
                gpio_set_value(SPITZ_GPIO_MUTE_R, 0);
                break;
        case SPITZ_LINE:
                /* enable line jack, disable mic bias and mute hp */
-               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
-               snd_soc_dapm_disable_pin(codec, "Headset Jack");
-               snd_soc_dapm_disable_pin(codec, "Mic Jack");
-               snd_soc_dapm_enable_pin(codec, "Line Jack");
+               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin(dapm, "Headset Jack");
+               snd_soc_dapm_disable_pin(dapm, "Mic Jack");
+               snd_soc_dapm_enable_pin(dapm, "Line Jack");
                gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
                gpio_set_value(SPITZ_GPIO_MUTE_R, 0);
                break;
        case SPITZ_HEADSET:
                /* enable and unmute headset jack enable mic bias, mute L hp */
-               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
-               snd_soc_dapm_enable_pin(codec, "Mic Jack");
-               snd_soc_dapm_disable_pin(codec, "Line Jack");
-               snd_soc_dapm_enable_pin(codec, "Headset Jack");
+               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+               snd_soc_dapm_enable_pin(dapm, "Mic Jack");
+               snd_soc_dapm_disable_pin(dapm, "Line Jack");
+               snd_soc_dapm_enable_pin(dapm, "Headset Jack");
                gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
                gpio_set_value(SPITZ_GPIO_MUTE_R, 1);
                break;
        case SPITZ_HP_OFF:
 
                /* jack removed, everything off */
-               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
-               snd_soc_dapm_disable_pin(codec, "Headset Jack");
-               snd_soc_dapm_disable_pin(codec, "Mic Jack");
-               snd_soc_dapm_disable_pin(codec, "Line Jack");
+               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin(dapm, "Headset Jack");
+               snd_soc_dapm_disable_pin(dapm, "Mic Jack");
+               snd_soc_dapm_disable_pin(dapm, "Line Jack");
                gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
                gpio_set_value(SPITZ_GPIO_MUTE_R, 0);
                break;
        }
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
 }
 
 static int spitz_startup(struct snd_pcm_substream *substream)
@@ -281,16 +282,17 @@ static const struct snd_kcontrol_new wm8750_spitz_controls[] = {
 static int spitz_wm8750_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int err;
 
        /* NC codec pins */
-       snd_soc_dapm_nc_pin(codec, "RINPUT1");
-       snd_soc_dapm_nc_pin(codec, "LINPUT2");
-       snd_soc_dapm_nc_pin(codec, "RINPUT2");
-       snd_soc_dapm_nc_pin(codec, "LINPUT3");
-       snd_soc_dapm_nc_pin(codec, "RINPUT3");
-       snd_soc_dapm_nc_pin(codec, "OUT3");
-       snd_soc_dapm_nc_pin(codec, "MONO1");
+       snd_soc_dapm_nc_pin(dapm, "RINPUT1");
+       snd_soc_dapm_nc_pin(dapm, "LINPUT2");
+       snd_soc_dapm_nc_pin(dapm, "RINPUT2");
+       snd_soc_dapm_nc_pin(dapm, "LINPUT3");
+       snd_soc_dapm_nc_pin(dapm, "RINPUT3");
+       snd_soc_dapm_nc_pin(dapm, "OUT3");
+       snd_soc_dapm_nc_pin(dapm, "MONO1");
 
        /* Add spitz specific controls */
        err = snd_soc_add_controls(codec, wm8750_spitz_controls,
@@ -299,13 +301,13 @@ static int spitz_wm8750_init(struct snd_soc_pcm_runtime *rtd)
                return err;
 
        /* Add spitz specific widgets */
-       snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, wm8750_dapm_widgets,
                                  ARRAY_SIZE(wm8750_dapm_widgets));
 
        /* Set up spitz specific audio paths */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
        return 0;
 }
 
index 248c283..f881f65 100644 (file)
@@ -18,7 +18,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/jack.h>
 
 #include <asm/mach-types.h>
@@ -133,20 +132,21 @@ static struct snd_soc_card snd_soc_card_evb3 = {
 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;
        int ret;
 
-       snd_soc_dapm_new_controls(codec, evb3_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, evb3_dapm_widgets,
                                  ARRAY_SIZE(evb3_dapm_widgets));
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        /* connected pins */
-       snd_soc_dapm_enable_pin(codec, "Ext Speaker");
-       snd_soc_dapm_enable_pin(codec, "Ext Mic 1");
-       snd_soc_dapm_enable_pin(codec, "Ext Mic 3");
-       snd_soc_dapm_disable_pin(codec, "Headset Mic 2");
-       snd_soc_dapm_disable_pin(codec, "Headset Stereophone");
+       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");
 
-       ret = snd_soc_dapm_sync(codec);
+       ret = snd_soc_dapm_sync(dapm);
        if (ret)
                return ret;
 
index 7b983f9..f75804e 100644 (file)
@@ -26,7 +26,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
 #include <mach/tosa.h>
@@ -49,31 +48,33 @@ static int tosa_spk_func;
 
 static void tosa_ext_control(struct snd_soc_codec *codec)
 {
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
        /* set up jack connection */
        switch (tosa_jack_func) {
        case TOSA_HP:
-               snd_soc_dapm_disable_pin(codec, "Mic (Internal)");
-               snd_soc_dapm_enable_pin(codec, "Headphone Jack");
-               snd_soc_dapm_disable_pin(codec, "Headset Jack");
+               snd_soc_dapm_disable_pin(dapm, "Mic (Internal)");
+               snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin(dapm, "Headset Jack");
                break;
        case TOSA_MIC_INT:
-               snd_soc_dapm_enable_pin(codec, "Mic (Internal)");
-               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
-               snd_soc_dapm_disable_pin(codec, "Headset Jack");
+               snd_soc_dapm_enable_pin(dapm, "Mic (Internal)");
+               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin(dapm, "Headset Jack");
                break;
        case TOSA_HEADSET:
-               snd_soc_dapm_disable_pin(codec, "Mic (Internal)");
-               snd_soc_dapm_disable_pin(codec, "Headphone Jack");
-               snd_soc_dapm_enable_pin(codec, "Headset Jack");
+               snd_soc_dapm_disable_pin(dapm, "Mic (Internal)");
+               snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+               snd_soc_dapm_enable_pin(dapm, "Headset Jack");
                break;
        }
 
        if (tosa_spk_func == TOSA_SPK_ON)
-               snd_soc_dapm_enable_pin(codec, "Speaker");
+               snd_soc_dapm_enable_pin(dapm, "Speaker");
        else
-               snd_soc_dapm_disable_pin(codec, "Speaker");
+               snd_soc_dapm_disable_pin(dapm, "Speaker");
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
 }
 
 static int tosa_startup(struct snd_pcm_substream *substream)
@@ -191,10 +192,11 @@ static const struct snd_kcontrol_new tosa_controls[] = {
 static int tosa_ac97_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int err;
 
-       snd_soc_dapm_nc_pin(codec, "OUT3");
-       snd_soc_dapm_nc_pin(codec, "MONOOUT");
+       snd_soc_dapm_nc_pin(dapm, "OUT3");
+       snd_soc_dapm_nc_pin(dapm, "MONOOUT");
 
        /* add tosa specific controls */
        err = snd_soc_add_controls(codec, tosa_controls,
@@ -203,13 +205,13 @@ static int tosa_ac97_init(struct snd_soc_pcm_runtime *rtd)
                return err;
 
        /* add tosa specific widgets */
-       snd_soc_dapm_new_controls(codec, tosa_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, tosa_dapm_widgets,
                                  ARRAY_SIZE(tosa_dapm_widgets));
 
        /* set up tosa specific audio path audio_map */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
        return 0;
 }
 
index 4cc841b..2d4f896 100644 (file)
@@ -21,7 +21,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/jack.h>
 
 #include <asm/mach-types.h>
@@ -140,22 +139,23 @@ static const struct snd_soc_dapm_route audio_map[] = {
 static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
 
        /* NC codec pins */
-       snd_soc_dapm_disable_pin(codec, "LINPUT3");
-       snd_soc_dapm_disable_pin(codec, "RINPUT3");
-       snd_soc_dapm_disable_pin(codec, "OUT3");
-       snd_soc_dapm_disable_pin(codec, "MONO");
+       snd_soc_dapm_disable_pin(dapm, "LINPUT3");
+       snd_soc_dapm_disable_pin(dapm, "RINPUT3");
+       snd_soc_dapm_disable_pin(dapm, "OUT3");
+       snd_soc_dapm_disable_pin(dapm, "MONO");
 
        /* Add z2 specific widgets */
-       snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, wm8750_dapm_widgets,
                                 ARRAY_SIZE(wm8750_dapm_widgets));
 
        /* Set up z2 specific audio paths */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
-       ret = snd_soc_dapm_sync(codec);
+       ret = snd_soc_dapm_sync(dapm);
        if (ret)
                goto err;
 
index d27e05a..b222a7d 100644 (file)
@@ -20,7 +20,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include "../codecs/wm9713.h"
 #include "pxa2xx-ac97.h"
@@ -73,21 +72,22 @@ static const struct snd_soc_dapm_route audio_map[] = {
 static int zylonite_wm9713_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
        if (clk_pout)
                snd_soc_dai_set_pll(rtd->codec_dai, 0, 0,
                                    clk_get_rate(pout), 0);
 
-       snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, zylonite_dapm_widgets,
                                  ARRAY_SIZE(zylonite_dapm_widgets));
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        /* Static setup for now */
-       snd_soc_dapm_enable_pin(codec, "Headphone");
-       snd_soc_dapm_enable_pin(codec, "Headset Earpiece");
+       snd_soc_dapm_enable_pin(dapm, "Headphone");
+       snd_soc_dapm_enable_pin(dapm, "Headset Earpiece");
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
        return 0;
 }
 
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
deleted file mode 100644 (file)
index d85bf8a..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-config SND_S3C24XX_SOC
-       tristate "SoC Audio for the Samsung S3CXXXX chips"
-       depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210
-       select S3C64XX_DMA if ARCH_S3C64XX
-       select S3C2410_DMA if ARCH_S3C2410
-       help
-         Say Y or M if you want to add support for codecs attached to
-         the S3C24XX AC97 or I2S interfaces. You will also need to
-         select the audio interfaces to support below.
-
-config SND_S3C24XX_SOC_I2S
-       tristate
-       select S3C2410_DMA
-
-config SND_S3C_I2SV2_SOC
-       tristate
-
-config SND_S3C2412_SOC_I2S
-       tristate
-       select SND_S3C_I2SV2_SOC
-       select S3C2410_DMA
-
-config SND_S3C64XX_SOC_I2S
-       tristate
-       select SND_S3C_I2SV2_SOC
-       select S3C64XX_DMA
-
-config SND_S3C64XX_SOC_I2S_V4
-       tristate
-       select SND_S3C_I2SV2_SOC
-       select S3C64XX_DMA
-
-config SND_S3C_SOC_PCM
-       tristate
-
-config SND_S3C_SOC_AC97
-       tristate
-       select SND_SOC_AC97_BUS
-
-config SND_S5P_SOC_SPDIF
-       tristate
-       select SND_SOC_SPDIF
-
-config SND_S3C24XX_SOC_NEO1973_WM8753
-       tristate "SoC I2S Audio support for NEO1973 - WM8753"
-       depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA01
-       select SND_S3C24XX_SOC_I2S
-       select SND_SOC_WM8753
-       help
-         Say Y if you want to add support for SoC audio on smdk2440
-         with the WM8753.
-
-config SND_S3C24XX_SOC_NEO1973_GTA02_WM8753
-       tristate "Audio support for the Openmoko Neo FreeRunner (GTA02)"
-       depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA02
-       select SND_S3C24XX_SOC_I2S
-       select SND_SOC_WM8753
-       help
-         This driver provides audio support for the Openmoko Neo FreeRunner
-         smartphone.
-         
-config SND_S3C24XX_SOC_JIVE_WM8750
-       tristate "SoC I2S Audio support for Jive"
-       depends on SND_S3C24XX_SOC && MACH_JIVE
-       select SND_SOC_WM8750
-       select SND_S3C2412_SOC_I2S
-       help
-         Sat Y if you want to add support for SoC audio on the Jive.
-
-config SND_S3C64XX_SOC_WM8580
-       tristate "SoC I2S Audio support for WM8580 on SMDK64XX"
-       depends on SND_S3C24XX_SOC && MACH_SMDK6410
-       select SND_SOC_WM8580
-       select SND_S3C64XX_SOC_I2S_V4
-       help
-         Say Y if you want to add support for SoC audio on the SMDK6410.
-
-config SND_S3C24XX_SOC_SMDK2443_WM9710
-       tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
-       depends on SND_S3C24XX_SOC && MACH_SMDK2443
-       select S3C2410_DMA
-       select AC97_BUS
-       select SND_SOC_AC97_CODEC
-       select SND_S3C_SOC_AC97
-       help
-         Say Y if you want to add support for SoC audio on smdk2443
-         with the WM9710.
-
-config SND_S3C24XX_SOC_LN2440SBC_ALC650
-       tristate "SoC AC97 Audio support for LN2440SBC - ALC650"
-       depends on SND_S3C24XX_SOC && ARCH_S3C2410
-       select S3C2410_DMA
-       select AC97_BUS
-       select SND_SOC_AC97_CODEC
-       select SND_S3C_SOC_AC97
-       help
-         Say Y if you want to add support for SoC audio on ln2440sbc
-         with the ALC650.
-
-config SND_S3C24XX_SOC_S3C24XX_UDA134X
-       tristate "SoC I2S Audio support UDA134X wired to a S3C24XX"
-               depends on SND_S3C24XX_SOC && ARCH_S3C2410
-               select SND_S3C24XX_SOC_I2S
-       select SND_SOC_L3
-               select SND_SOC_UDA134X
-
-config SND_S3C24XX_SOC_SIMTEC
-       tristate
-       help
-         Internal node for common S3C24XX/Simtec suppor
-
-config SND_S3C24XX_SOC_SIMTEC_TLV320AIC23
-       tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards"
-       depends on SND_S3C24XX_SOC && ARCH_S3C2410
-       select SND_S3C24XX_SOC_I2S
-       select SND_SOC_TLV320AIC23
-       select SND_S3C24XX_SOC_SIMTEC
-
-config SND_S3C24XX_SOC_SIMTEC_HERMES
-       tristate "SoC I2S Audio support for Simtec Hermes board"
-       depends on SND_S3C24XX_SOC && ARCH_S3C2410
-       select SND_S3C24XX_SOC_I2S
-       select SND_SOC_TLV320AIC3X
-       select SND_S3C24XX_SOC_SIMTEC
-
-config SND_S3C24XX_SOC_RX1950_UDA1380
-       tristate "Audio support for the HP iPAQ RX1950"
-       depends on SND_S3C24XX_SOC && MACH_RX1950
-       select SND_S3C24XX_SOC_I2S
-       select SND_SOC_UDA1380
-       help
-         This driver provides audio support for HP iPAQ RX1950 PDA.
-
-config SND_SOC_SMDK_WM9713
-       tristate "SoC AC97 Audio support for SMDK with WM9713"
-       depends on SND_S3C24XX_SOC && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
-       select SND_SOC_WM9713
-       select SND_S3C_SOC_AC97
-       help
-         Sat Y if you want to add support for SoC audio on the SMDK.
-
-config SND_S3C64XX_SOC_SMARTQ
-       tristate "SoC I2S Audio support for SmartQ board"
-       depends on SND_S3C24XX_SOC && MACH_SMARTQ
-       select SND_S3C64XX_SOC_I2S
-       select SND_SOC_WM8750
-
-config SND_S5PC110_SOC_AQUILA_WM8994
-       tristate "SoC I2S Audio support for AQUILA - WM8994"
-       depends on SND_S3C24XX_SOC && MACH_AQUILA
-       select SND_S3C64XX_SOC_I2S_V4
-       select SND_SOC_WM8994
-       help
-         Say Y if you want to add support for SoC audio on aquila
-         with the WM8994.
-
-config SND_S5PV210_SOC_GONI_WM8994
-       tristate "SoC I2S Audio support for GONI - WM8994"
-       depends on SND_S3C24XX_SOC && MACH_GONI
-       select SND_S3C64XX_SOC_I2S_V4
-       select SND_SOC_WM8994
-       help
-         Say Y if you want to add support for SoC audio on goni
-         with the WM8994.
-
-config SND_SOC_SMDK_SPDIF
-       tristate "SoC S/PDIF Audio support for SMDK"
-       depends on SND_S3C24XX_SOC && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210)
-       select SND_S5P_SOC_SPDIF
-       help
-         Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
deleted file mode 100644 (file)
index ee8f41d..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-# S3c24XX Platform Support
-snd-soc-s3c24xx-objs := s3c-dma.o
-snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
-snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
-snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o
-snd-soc-s3c-ac97-objs := s3c-ac97.o
-snd-soc-s3c64xx-i2s-v4-objs := s3c64xx-i2s-v4.o
-snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
-snd-soc-s3c-pcm-objs := s3c-pcm.o
-snd-soc-samsung-spdif-objs := spdif.o
-
-obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
-obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
-obj-$(CONFIG_SND_S3C_SOC_AC97) += snd-soc-s3c-ac97.o
-obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
-obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o
-obj-$(CONFIG_SND_S3C64XX_SOC_I2S_V4) += snd-soc-s3c64xx-i2s-v4.o
-obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
-obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-s3c-pcm.o
-obj-$(CONFIG_SND_S5P_SOC_SPDIF) += snd-soc-samsung-spdif.o
-
-# S3C24XX Machine Support
-snd-soc-jive-wm8750-objs := jive_wm8750.o
-snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
-snd-soc-neo1973-gta02-wm8753-objs := neo1973_gta02_wm8753.o
-snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o
-snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o
-snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o
-snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o
-snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o
-snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o
-snd-soc-rx1950-uda1380-objs := rx1950_uda1380.o
-snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o
-snd-soc-smdk-wm9713-objs := smdk_wm9713.o
-snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
-snd-soc-aquila-wm8994-objs := aquila_wm8994.o
-snd-soc-goni-wm8994-objs := goni_wm8994.o
-snd-soc-smdk-spdif-objs := smdk_spdif.o
-
-obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o
-obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
-obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_GTA02_WM8753) += snd-soc-neo1973-gta02-wm8753.o
-obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
-obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o
-obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o
-obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o
-obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o
-obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o
-obj-$(CONFIG_SND_S3C24XX_SOC_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o
-obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o
-obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o
-obj-$(CONFIG_SND_S3C64XX_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
-obj-$(CONFIG_SND_S5PC110_SOC_AQUILA_WM8994) += snd-soc-aquila-wm8994.o
-obj-$(CONFIG_SND_S5PV210_SOC_GONI_WM8994) += snd-soc-goni-wm8994.o
-obj-$(CONFIG_SND_SOC_SMDK_SPDIF) += snd-soc-smdk-spdif.o
diff --git a/sound/soc/s3c24xx/aquila_wm8994.c b/sound/soc/s3c24xx/aquila_wm8994.c
deleted file mode 100644 (file)
index 235d197..0000000
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * aquila_wm8994.c
- *
- * Copyright (C) 2010 Samsung Electronics Co.Ltd
- * Author: Chanwoo Choi <cw00.choi@samsung.com>
- *
- *  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/moduleparam.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/jack.h>
-#include <asm/mach-types.h>
-#include <mach/gpio.h>
-#include <mach/regs-clock.h>
-
-#include <linux/mfd/wm8994/core.h>
-#include <linux/mfd/wm8994/registers.h>
-#include "../codecs/wm8994.h"
-#include "s3c-dma.h"
-#include "s3c64xx-i2s.h"
-
-static struct snd_soc_card aquila;
-static struct platform_device *aquila_snd_device;
-
-/* 3.5 pie jack */
-static struct snd_soc_jack jack;
-
-/* 3.5 pie jack detection DAPM pins */
-static struct snd_soc_jack_pin jack_pins[] = {
-       {
-               .pin = "Headset Mic",
-               .mask = SND_JACK_MICROPHONE,
-       }, {
-               .pin = "Headset Stereophone",
-               .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL |
-                       SND_JACK_AVOUT,
-       },
-};
-
-/* 3.5 pie jack detection gpios */
-static struct snd_soc_jack_gpio jack_gpios[] = {
-       {
-               .gpio = S5PV210_GPH0(6),
-               .name = "DET_3.5",
-               .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL |
-                       SND_JACK_AVOUT,
-               .debounce_time = 200,
-       },
-};
-
-static const struct snd_soc_dapm_widget aquila_dapm_widgets[] = {
-       SND_SOC_DAPM_SPK("Ext Spk", NULL),
-       SND_SOC_DAPM_SPK("Ext Rcv", NULL),
-       SND_SOC_DAPM_HP("Headset Stereophone", NULL),
-       SND_SOC_DAPM_MIC("Headset Mic", NULL),
-       SND_SOC_DAPM_MIC("Main Mic", NULL),
-       SND_SOC_DAPM_MIC("2nd Mic", NULL),
-       SND_SOC_DAPM_LINE("Radio In", NULL),
-};
-
-static const struct snd_soc_dapm_route aquila_dapm_routes[] = {
-       {"Ext Spk", NULL, "SPKOUTLP"},
-       {"Ext Spk", NULL, "SPKOUTLN"},
-
-       {"Ext Rcv", NULL, "HPOUT2N"},
-       {"Ext Rcv", NULL, "HPOUT2P"},
-
-       {"Headset Stereophone", NULL, "HPOUT1L"},
-       {"Headset Stereophone", NULL, "HPOUT1R"},
-
-       {"IN1RN", NULL, "Headset Mic"},
-       {"IN1RP", NULL, "Headset Mic"},
-
-       {"IN1RN", NULL, "2nd Mic"},
-       {"IN1RP", NULL, "2nd Mic"},
-
-       {"IN1LN", NULL, "Main Mic"},
-       {"IN1LP", NULL, "Main Mic"},
-
-       {"IN2LN", NULL, "Radio In"},
-       {"IN2RN", NULL, "Radio In"},
-};
-
-static int aquila_wm8994_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       int ret;
-
-       /* add aquila specific widgets */
-       snd_soc_dapm_new_controls(codec, aquila_dapm_widgets,
-                       ARRAY_SIZE(aquila_dapm_widgets));
-
-       /* set up aquila specific audio routes */
-       snd_soc_dapm_add_routes(codec, aquila_dapm_routes,
-                       ARRAY_SIZE(aquila_dapm_routes));
-
-       /* set endpoints to not connected */
-       snd_soc_dapm_nc_pin(codec, "IN2LP:VXRN");
-       snd_soc_dapm_nc_pin(codec, "IN2RP:VXRP");
-       snd_soc_dapm_nc_pin(codec, "LINEOUT1N");
-       snd_soc_dapm_nc_pin(codec, "LINEOUT1P");
-       snd_soc_dapm_nc_pin(codec, "LINEOUT2N");
-       snd_soc_dapm_nc_pin(codec, "LINEOUT2P");
-       snd_soc_dapm_nc_pin(codec, "SPKOUTRN");
-       snd_soc_dapm_nc_pin(codec, "SPKOUTRP");
-
-       snd_soc_dapm_sync(codec);
-
-       /* Headset jack detection */
-       ret = snd_soc_jack_new(&aquila, "Headset Jack",
-                       SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT,
-                       &jack);
-       if (ret)
-               return ret;
-
-       ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins);
-       if (ret)
-               return ret;
-
-       ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
-static int aquila_hifi_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;
-       unsigned int pll_out = 24000000;
-       int ret = 0;
-
-       /* set the cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* set the cpu system clock */
-       ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK,
-                       0, SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* set the codec FLL */
-       ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out,
-                       params_rate(params) * 256);
-       if (ret < 0)
-               return ret;
-
-       /* set the codec system clock */
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
-                       params_rate(params) * 256, SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static struct snd_soc_ops aquila_hifi_ops = {
-       .hw_params = aquila_hifi_hw_params,
-};
-
-static int aquila_voice_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;
-       unsigned int pll_out = 24000000;
-       int ret = 0;
-
-       if (params_rate(params) != 8000)
-               return -EINVAL;
-
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
-                       SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* set the codec FLL */
-       ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out,
-                       params_rate(params) * 256);
-       if (ret < 0)
-               return ret;
-
-       /* set the codec system clock */
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
-                       params_rate(params) * 256, SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static struct snd_soc_dai_driver voice_dai = {
-       .name = "aquila-voice-dai",
-       .playback = {
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .capture = {
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-};
-
-static struct snd_soc_ops aquila_voice_ops = {
-       .hw_params = aquila_voice_hw_params,
-};
-
-static struct snd_soc_dai_link aquila_dai[] = {
-{
-       .name = "WM8994",
-       .stream_name = "WM8994 HiFi",
-       .cpu_dai_name = "s3c64xx-i2s-v4",
-       .codec_dai_name = "wm8994-hifi",
-       .platform_name = "s3c24xx-pcm-audio",
-       .codec_name = "wm8994-codec.0-0x1a",
-       .init = aquila_wm8994_init,
-       .ops = &aquila_hifi_ops,
-}, {
-       .name = "WM8994 Voice",
-       .stream_name = "Voice",
-       .cpu_dai_name = "aquila-voice-dai",
-       .codec_dai_name = "wm8994-voice",
-       .platform_name = "s3c24xx-pcm-audio",
-       .codec_name = "wm8994-codec.0-0x1a",
-       .ops = &aquila_voice_ops,
-},
-};
-
-static struct snd_soc_card aquila = {
-       .name = "aquila",
-       .dai_link = aquila_dai,
-       .num_links = ARRAY_SIZE(aquila_dai),
-};
-
-static int __init aquila_init(void)
-{
-       int ret;
-
-       if (!machine_is_aquila())
-               return -ENODEV;
-
-       aquila_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!aquila_snd_device)
-               return -ENOMEM;
-
-       /* register voice DAI here */
-       ret = snd_soc_register_dai(&aquila_snd_device->dev, &voice_dai);
-       if (ret)
-               return ret;
-
-       platform_set_drvdata(aquila_snd_device, &aquila);
-       ret = platform_device_add(aquila_snd_device);
-
-       if (ret)
-               platform_device_put(aquila_snd_device);
-
-       return ret;
-}
-
-static void __exit aquila_exit(void)
-{
-       platform_device_unregister(aquila_snd_device);
-}
-
-module_init(aquila_init);
-module_exit(aquila_exit);
-
-/* Module information */
-MODULE_DESCRIPTION("ALSA SoC WM8994 Aquila(S5PC110)");
-MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/goni_wm8994.c b/sound/soc/s3c24xx/goni_wm8994.c
deleted file mode 100644 (file)
index 694f702..0000000
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * goni_wm8994.c
- *
- * Copyright (C) 2010 Samsung Electronics Co.Ltd
- * Author: Chanwoo Choi <cw00.choi@samsung.com>
- *
- *  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/moduleparam.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/jack.h>
-#include <asm/mach-types.h>
-#include <mach/gpio.h>
-#include <mach/regs-clock.h>
-
-#include <linux/mfd/wm8994/core.h>
-#include <linux/mfd/wm8994/registers.h>
-#include "../codecs/wm8994.h"
-#include "s3c-dma.h"
-#include "s3c64xx-i2s.h"
-
-static struct snd_soc_card goni;
-static struct platform_device *goni_snd_device;
-
-/* 3.5 pie jack */
-static struct snd_soc_jack jack;
-
-/* 3.5 pie jack detection DAPM pins */
-static struct snd_soc_jack_pin jack_pins[] = {
-       {
-               .pin = "Headset Mic",
-               .mask = SND_JACK_MICROPHONE,
-       }, {
-               .pin = "Headset Stereophone",
-               .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL |
-                       SND_JACK_AVOUT,
-       },
-};
-
-/* 3.5 pie jack detection gpios */
-static struct snd_soc_jack_gpio jack_gpios[] = {
-       {
-               .gpio = S5PV210_GPH0(6),
-               .name = "DET_3.5",
-               .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL |
-                       SND_JACK_AVOUT,
-               .debounce_time = 200,
-       },
-};
-
-static const struct snd_soc_dapm_widget goni_dapm_widgets[] = {
-       SND_SOC_DAPM_SPK("Ext Left Spk", NULL),
-       SND_SOC_DAPM_SPK("Ext Right Spk", NULL),
-       SND_SOC_DAPM_SPK("Ext Rcv", NULL),
-       SND_SOC_DAPM_HP("Headset Stereophone", NULL),
-       SND_SOC_DAPM_MIC("Headset Mic", NULL),
-       SND_SOC_DAPM_MIC("Main Mic", NULL),
-       SND_SOC_DAPM_MIC("2nd Mic", NULL),
-       SND_SOC_DAPM_LINE("Radio In", NULL),
-};
-
-static const struct snd_soc_dapm_route goni_dapm_routes[] = {
-       {"Ext Left Spk", NULL, "SPKOUTLP"},
-       {"Ext Left Spk", NULL, "SPKOUTLN"},
-
-       {"Ext Right Spk", NULL, "SPKOUTRP"},
-       {"Ext Right Spk", NULL, "SPKOUTRN"},
-
-       {"Ext Rcv", NULL, "HPOUT2N"},
-       {"Ext Rcv", NULL, "HPOUT2P"},
-
-       {"Headset Stereophone", NULL, "HPOUT1L"},
-       {"Headset Stereophone", NULL, "HPOUT1R"},
-
-       {"IN1RN", NULL, "Headset Mic"},
-       {"IN1RP", NULL, "Headset Mic"},
-
-       {"IN1RN", NULL, "2nd Mic"},
-       {"IN1RP", NULL, "2nd Mic"},
-
-       {"IN1LN", NULL, "Main Mic"},
-       {"IN1LP", NULL, "Main Mic"},
-
-       {"IN2LN", NULL, "Radio In"},
-       {"IN2RN", NULL, "Radio In"},
-};
-
-static int goni_wm8994_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       int ret;
-
-       /* add goni specific widgets */
-       snd_soc_dapm_new_controls(codec, goni_dapm_widgets,
-                       ARRAY_SIZE(goni_dapm_widgets));
-
-       /* set up goni specific audio routes */
-       snd_soc_dapm_add_routes(codec, goni_dapm_routes,
-                       ARRAY_SIZE(goni_dapm_routes));
-
-       /* set endpoints to not connected */
-       snd_soc_dapm_nc_pin(codec, "IN2LP:VXRN");
-       snd_soc_dapm_nc_pin(codec, "IN2RP:VXRP");
-       snd_soc_dapm_nc_pin(codec, "LINEOUT1N");
-       snd_soc_dapm_nc_pin(codec, "LINEOUT1P");
-       snd_soc_dapm_nc_pin(codec, "LINEOUT2N");
-       snd_soc_dapm_nc_pin(codec, "LINEOUT2P");
-
-       snd_soc_dapm_sync(codec);
-
-       /* Headset jack detection */
-       ret = snd_soc_jack_new(&goni, "Headset Jack",
-                       SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT,
-                       &jack);
-       if (ret)
-               return ret;
-
-       ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins);
-       if (ret)
-               return ret;
-
-       ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
-static int goni_hifi_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;
-       unsigned int pll_out = 24000000;
-       int ret = 0;
-
-       /* set the cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* set the cpu system clock */
-       ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK,
-                       0, SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* set the codec FLL */
-       ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out,
-                       params_rate(params) * 256);
-       if (ret < 0)
-               return ret;
-
-       /* set the codec system clock */
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
-                       params_rate(params) * 256, SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static struct snd_soc_ops goni_hifi_ops = {
-       .hw_params = goni_hifi_hw_params,
-};
-
-static int goni_voice_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;
-       unsigned int pll_out = 24000000;
-       int ret = 0;
-
-       if (params_rate(params) != 8000)
-               return -EINVAL;
-
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
-                       SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* set the codec FLL */
-       ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out,
-                       params_rate(params) * 256);
-       if (ret < 0)
-               return ret;
-
-       /* set the codec system clock */
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
-                       params_rate(params) * 256, SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static struct snd_soc_dai_driver voice_dai = {
-       .name = "goni-voice-dai",
-       .id = 0,
-       .playback = {
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .capture = {
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-};
-
-static struct snd_soc_ops goni_voice_ops = {
-       .hw_params = goni_voice_hw_params,
-};
-
-static struct snd_soc_dai_link goni_dai[] = {
-{
-       .name = "WM8994",
-       .stream_name = "WM8994 HiFi",
-       .cpu_dai_name = "s3c64xx-i2s-v4",
-       .codec_dai_name = "wm8994-hifi",
-       .platform_name = "s3c24xx-pcm-audio",
-       .codec_name = "wm8994-codec.0-0x1a",
-       .init = goni_wm8994_init,
-       .ops = &goni_hifi_ops,
-}, {
-       .name = "WM8994 Voice",
-       .stream_name = "Voice",
-       .cpu_dai_name = "goni-voice-dai",
-       .codec_dai_name = "wm8994-voice",
-       .platform_name = "s3c24xx-pcm-audio",
-       .codec_name = "wm8994-codec.0-0x1a",
-       .ops = &goni_voice_ops,
-},
-};
-
-static struct snd_soc_card goni = {
-       .name = "goni",
-       .dai_link = goni_dai,
-       .num_links = ARRAY_SIZE(goni_dai),
-};
-
-static int __init goni_init(void)
-{
-       int ret;
-
-       if (!machine_is_goni())
-               return -ENODEV;
-
-       goni_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!goni_snd_device)
-               return -ENOMEM;
-
-       /* register voice DAI here */
-       ret = snd_soc_register_dai(&goni_snd_device->dev, &voice_dai);
-       if (ret)
-               return ret;
-
-       platform_set_drvdata(goni_snd_device, &goni);
-       ret = platform_device_add(goni_snd_device);
-
-       if (ret)
-               platform_device_put(goni_snd_device);
-
-       return ret;
-}
-
-static void __exit goni_exit(void)
-{
-       platform_device_unregister(goni_snd_device);
-}
-
-module_init(goni_init);
-module_exit(goni_exit);
-
-/* Module information */
-MODULE_DESCRIPTION("ALSA SoC WM8994 GONI(S5PV210)");
-MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/jive_wm8750.c b/sound/soc/s3c24xx/jive_wm8750.c
deleted file mode 100644 (file)
index 49605cd..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-/* sound/soc/s3c24xx/jive_wm8750.c
- *
- * Copyright 2007,2008 Simtec Electronics
- *
- * Based on sound/soc/pxa/spitz.c
- *     Copyright 2005 Wolfson Microelectronics PLC.
- *     Copyright 2005 Openedhand Ltd.
- *
- * 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/clk.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include <asm/mach-types.h>
-
-#include "s3c-dma.h"
-#include "s3c2412-i2s.h"
-
-#include "../codecs/wm8750.h"
-
-static const struct snd_soc_dapm_route audio_map[] = {
-       { "Headphone Jack", NULL, "LOUT1" },
-       { "Headphone Jack", NULL, "ROUT1" },
-       { "Internal Speaker", NULL, "LOUT2" },
-       { "Internal Speaker", NULL, "ROUT2" },
-       { "LINPUT1", NULL, "Line Input" },
-       { "RINPUT1", NULL, "Line Input" },
-};
-
-static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
-       SND_SOC_DAPM_HP("Headphone Jack", NULL),
-       SND_SOC_DAPM_SPK("Internal Speaker", NULL),
-       SND_SOC_DAPM_LINE("Line In", NULL),
-};
-
-static int jive_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;
-       struct s3c_i2sv2_rate_calc div;
-       unsigned int clk = 0;
-       int ret = 0;
-
-       switch (params_rate(params)) {
-       case 8000:
-       case 16000:
-       case 48000:
-       case 96000:
-               clk = 12288000;
-               break;
-       case 11025:
-       case 22050:
-       case 44100:
-               clk = 11289600;
-               break;
-       }
-
-       s3c_i2sv2_iis_calc_rate(&div, NULL, params_rate(params),
-                               s3c_i2sv2_get_clock(cpu_dai));
-
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set the codec system clock for DAC and ADC */
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
-                                    SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_RCLK, div.fs_div);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_PRESCALER,
-                                    div.clk_div - 1);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static struct snd_soc_ops jive_ops = {
-       .hw_params      = jive_hw_params,
-};
-
-static int jive_wm8750_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       int err;
-
-       /* These endpoints are not being used. */
-       snd_soc_dapm_nc_pin(codec, "LINPUT2");
-       snd_soc_dapm_nc_pin(codec, "RINPUT2");
-       snd_soc_dapm_nc_pin(codec, "LINPUT3");
-       snd_soc_dapm_nc_pin(codec, "RINPUT3");
-       snd_soc_dapm_nc_pin(codec, "OUT3");
-       snd_soc_dapm_nc_pin(codec, "MONO");
-
-       /* Add jive specific widgets */
-       err = snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets,
-                                       ARRAY_SIZE(wm8750_dapm_widgets));
-       if (err) {
-               printk(KERN_ERR "%s: failed to add widgets (%d)\n",
-                      __func__, err);
-               return err;
-       }
-
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
-       snd_soc_dapm_sync(codec);
-
-       return 0;
-}
-
-static struct snd_soc_dai_link jive_dai = {
-       .name           = "wm8750",
-       .stream_name    = "WM8750",
-       .cpu_dai_name   = "s3c2412-i2s",
-       .codec_dai_name = "wm8750-hifi",
-       .platform_name  = "s3c24xx-pcm-audio",
-       .codec_name     = "wm8750-codec.0-0x1a",
-       .init           = jive_wm8750_init,
-       .ops            = &jive_ops,
-};
-
-/* jive audio machine driver */
-static struct snd_soc_card snd_soc_machine_jive = {
-       .name           = "Jive",
-       .dai_link       = &jive_dai,
-       .num_links      = 1,
-};
-
-static struct platform_device *jive_snd_device;
-
-static int __init jive_init(void)
-{
-       int ret;
-
-       if (!machine_is_jive())
-               return 0;
-
-       printk("JIVE WM8750 Audio support\n");
-
-       jive_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!jive_snd_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(jive_snd_device, &snd_soc_machine_jive);
-       ret = platform_device_add(jive_snd_device);
-
-       if (ret)
-               platform_device_put(jive_snd_device);
-
-       return ret;
-}
-
-static void __exit jive_exit(void)
-{
-       platform_device_unregister(jive_snd_device);
-}
-
-module_init(jive_init);
-module_exit(jive_exit);
-
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_DESCRIPTION("ALSA SoC Jive Audio support");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/lm4857.h b/sound/soc/s3c24xx/lm4857.h
deleted file mode 100644 (file)
index 0cf5b70..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * lm4857.h  --  ALSA Soc Audio Layer
- *
- * Copyright 2007 Wolfson Microelectronics PLC.
- * Author: Graeme Gregory
- *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
- *
- *  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.
- *
- *  Revision history
- *    18th Jun 2007   Initial version.
- */
-
-#ifndef LM4857_H_
-#define LM4857_H_
-
-/* The register offsets in the cache array */
-#define LM4857_MVOL 0
-#define LM4857_LVOL 1
-#define LM4857_RVOL 2
-#define LM4857_CTRL 3
-
-/* the shifts required to set these bits */
-#define LM4857_3D 5
-#define LM4857_WAKEUP 5
-#define LM4857_EPGAIN 4
-
-#endif /*LM4857_H_*/
-
diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c
deleted file mode 100644 (file)
index abe64ab..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * SoC audio for ln2440sbc
- *
- * Copyright 2007 KonekTel, a.s.
- * Author: Ivan Kuten
- *         ivan.kuten@promwad.com
- *
- * Heavily based on smdk2443_wm9710.c
- * Copyright 2007 Wolfson Microelectronics PLC.
- * Author: Graeme Gregory
- *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.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/device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include "s3c-dma.h"
-#include "s3c-ac97.h"
-
-static struct snd_soc_card ln2440sbc;
-
-static struct snd_soc_dai_link ln2440sbc_dai[] = {
-{
-       .name = "AC97",
-       .stream_name = "AC97 HiFi",
-       .cpu_dai_name = "s3c-ac97",
-       .codec_dai_name = "ac97-hifi",
-       .codec_name = "ac97-codec",
-       .platform_name = "s3c24xx-pcm-audio",
-},
-};
-
-static struct snd_soc_card ln2440sbc = {
-       .name = "LN2440SBC",
-       .dai_link = ln2440sbc_dai,
-       .num_links = ARRAY_SIZE(ln2440sbc_dai),
-};
-
-static struct platform_device *ln2440sbc_snd_ac97_device;
-
-static int __init ln2440sbc_init(void)
-{
-       int ret;
-
-       ln2440sbc_snd_ac97_device = platform_device_alloc("soc-audio", -1);
-       if (!ln2440sbc_snd_ac97_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(ln2440sbc_snd_ac97_device, &ln2440sbc);
-       ret = platform_device_add(ln2440sbc_snd_ac97_device);
-
-       if (ret)
-               platform_device_put(ln2440sbc_snd_ac97_device);
-
-       return ret;
-}
-
-static void __exit ln2440sbc_exit(void)
-{
-       platform_device_unregister(ln2440sbc_snd_ac97_device);
-}
-
-module_init(ln2440sbc_init);
-module_exit(ln2440sbc_exit);
-
-/* Module information */
-MODULE_AUTHOR("Ivan Kuten");
-MODULE_DESCRIPTION("ALSA SoC ALC650 LN2440SBC");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
deleted file mode 100644 (file)
index e97bdf1..0000000
+++ /dev/null
@@ -1,504 +0,0 @@
-/*
- * neo1973_gta02_wm8753.c  --  SoC audio for Openmoko Freerunner(GTA02)
- *
- * Copyright 2007 Openmoko Inc
- * Author: Graeme Gregory <graeme@openmoko.org>
- * Copyright 2007 Wolfson Microelectronics PLC.
- * Author: Graeme Gregory <linux@wolfsonmicro.com>
- * Copyright 2009 Wolfson Microelectronics
- *
- *  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/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 <sound/soc-dapm.h>
-
-#include <asm/mach-types.h>
-
-#include <plat/regs-iis.h>
-
-#include <mach/regs-clock.h>
-#include <asm/io.h>
-#include <mach/gta02.h>
-#include "../codecs/wm8753.h"
-#include "s3c-dma.h"
-#include "s3c24xx-i2s.h"
-
-static struct snd_soc_card neo1973_gta02;
-
-static int neo1973_gta02_hifi_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;
-       unsigned int pll_out = 0, bclk = 0;
-       int ret = 0;
-       unsigned long iis_clkrate;
-
-       iis_clkrate = s3c24xx_i2s_get_clockrate();
-
-       switch (params_rate(params)) {
-       case 8000:
-       case 16000:
-               pll_out = 12288000;
-               break;
-       case 48000:
-               bclk = WM8753_BCLK_DIV_4;
-               pll_out = 12288000;
-               break;
-       case 96000:
-               bclk = WM8753_BCLK_DIV_2;
-               pll_out = 12288000;
-               break;
-       case 11025:
-               bclk = WM8753_BCLK_DIV_16;
-               pll_out = 11289600;
-               break;
-       case 22050:
-               bclk = WM8753_BCLK_DIV_8;
-               pll_out = 11289600;
-               break;
-       case 44100:
-               bclk = WM8753_BCLK_DIV_4;
-               pll_out = 11289600;
-               break;
-       case 88200:
-               bclk = WM8753_BCLK_DIV_2;
-               pll_out = 11289600;
-               break;
-       }
-
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai,
-               SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-               SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai,
-               SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-               SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* set the codec system clock for DAC and ADC */
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
-               SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       /* set MCLK division for sample rate */
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
-               S3C2410_IISMOD_32FS);
-       if (ret < 0)
-               return ret;
-
-       /* set codec BCLK division for sample rate */
-       ret = snd_soc_dai_set_clkdiv(codec_dai,
-                                       WM8753_BCLKDIV, bclk);
-       if (ret < 0)
-               return ret;
-
-       /* set prescaler division for sample rate */
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
-               S3C24XX_PRESCALE(4, 4));
-       if (ret < 0)
-               return ret;
-
-       /* codec PLL input is PCLK/4 */
-       ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
-               iis_clkrate / 4, pll_out);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
-       /* disable the PLL */
-       return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
-}
-
-/*
- * Neo1973 WM8753 HiFi DAI opserations.
- */
-static struct snd_soc_ops neo1973_gta02_hifi_ops = {
-       .hw_params = neo1973_gta02_hifi_hw_params,
-       .hw_free = neo1973_gta02_hifi_hw_free,
-};
-
-static int neo1973_gta02_voice_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;
-       unsigned int pcmdiv = 0;
-       int ret = 0;
-       unsigned long iis_clkrate;
-
-       iis_clkrate = s3c24xx_i2s_get_clockrate();
-
-       if (params_rate(params) != 8000)
-               return -EINVAL;
-       if (params_channels(params) != 1)
-               return -EINVAL;
-
-       pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
-
-       /* todo: gg check mode (DSP_B) against CSR datasheet */
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set the codec system clock for DAC and ADC */
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK,
-               12288000, SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       /* set codec PCM division for sample rate */
-       ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV,
-                                       pcmdiv);
-       if (ret < 0)
-               return ret;
-
-       /* configure and enable PLL for 12.288MHz output */
-       ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
-               iis_clkrate / 4, 12288000);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
-       /* disable the PLL */
-       return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
-}
-
-static struct snd_soc_ops neo1973_gta02_voice_ops = {
-       .hw_params = neo1973_gta02_voice_hw_params,
-       .hw_free = neo1973_gta02_voice_hw_free,
-};
-
-#define LM4853_AMP 1
-#define LM4853_SPK 2
-
-static u8 lm4853_state;
-
-/* This has no effect, it exists only to maintain compatibility with
- * existing ALSA state files.
- */
-static int lm4853_set_state(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       int val = ucontrol->value.integer.value[0];
-
-       if (val)
-               lm4853_state |= LM4853_AMP;
-       else
-               lm4853_state &= ~LM4853_AMP;
-
-       return 0;
-}
-
-static int lm4853_get_state(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       ucontrol->value.integer.value[0] = lm4853_state & LM4853_AMP;
-
-       return 0;
-}
-
-static int lm4853_set_spk(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       int val = ucontrol->value.integer.value[0];
-
-       if (val) {
-               lm4853_state |= LM4853_SPK;
-               gpio_set_value(GTA02_GPIO_HP_IN, 0);
-       } else {
-               lm4853_state &= ~LM4853_SPK;
-               gpio_set_value(GTA02_GPIO_HP_IN, 1);
-       }
-
-       return 0;
-}
-
-static int lm4853_get_spk(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       ucontrol->value.integer.value[0] = (lm4853_state & LM4853_SPK) >> 1;
-
-       return 0;
-}
-
-static int lm4853_event(struct snd_soc_dapm_widget *w,
-                       struct snd_kcontrol *k,
-                       int event)
-{
-       gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event));
-
-       return 0;
-}
-
-static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
-       SND_SOC_DAPM_SPK("Stereo Out", lm4853_event),
-       SND_SOC_DAPM_LINE("GSM Line Out", NULL),
-       SND_SOC_DAPM_LINE("GSM Line In", NULL),
-       SND_SOC_DAPM_MIC("Headset Mic", NULL),
-       SND_SOC_DAPM_MIC("Handset Mic", NULL),
-       SND_SOC_DAPM_SPK("Handset Spk", NULL),
-};
-
-
-/* example machine audio_mapnections */
-static const struct snd_soc_dapm_route audio_map[] = {
-
-       /* Connections to the lm4853 amp */
-       {"Stereo Out", NULL, "LOUT1"},
-       {"Stereo Out", NULL, "ROUT1"},
-
-       /* Connections to the GSM Module */
-       {"GSM Line Out", NULL, "MONO1"},
-       {"GSM Line Out", NULL, "MONO2"},
-       {"RXP", NULL, "GSM Line In"},
-       {"RXN", NULL, "GSM Line In"},
-
-       /* Connections to Headset */
-       {"MIC1", NULL, "Mic Bias"},
-       {"Mic Bias", NULL, "Headset Mic"},
-
-       /* Call Mic */
-       {"MIC2", NULL, "Mic Bias"},
-       {"MIC2N", NULL, "Mic Bias"},
-       {"Mic Bias", NULL, "Handset Mic"},
-
-       /* Call Speaker */
-       {"Handset Spk", NULL, "LOUT2"},
-       {"Handset Spk", NULL, "ROUT2"},
-
-       /* Connect the ALC pins */
-       {"ACIN", NULL, "ACOP"},
-};
-
-static const struct snd_kcontrol_new wm8753_neo1973_gta02_controls[] = {
-       SOC_DAPM_PIN_SWITCH("Stereo Out"),
-       SOC_DAPM_PIN_SWITCH("GSM Line Out"),
-       SOC_DAPM_PIN_SWITCH("GSM Line In"),
-       SOC_DAPM_PIN_SWITCH("Headset Mic"),
-       SOC_DAPM_PIN_SWITCH("Handset Mic"),
-       SOC_DAPM_PIN_SWITCH("Handset Spk"),
-
-       /* This has no effect, it exists only to maintain compatibility with
-        * existing ALSA state files.
-        */
-       SOC_SINGLE_EXT("Amp State Switch", 6, 0, 1, 0,
-               lm4853_get_state,
-               lm4853_set_state),
-       SOC_SINGLE_EXT("Amp Spk Switch", 7, 0, 1, 0,
-               lm4853_get_spk,
-               lm4853_set_spk),
-};
-
-/*
- * This is an example machine initialisation for a wm8753 connected to a
- * neo1973 GTA02.
- */
-static int neo1973_gta02_wm8753_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       int err;
-
-       /* set up NC codec pins */
-       snd_soc_dapm_nc_pin(codec, "OUT3");
-       snd_soc_dapm_nc_pin(codec, "OUT4");
-       snd_soc_dapm_nc_pin(codec, "LINE1");
-       snd_soc_dapm_nc_pin(codec, "LINE2");
-
-       /* Add neo1973 gta02 specific widgets */
-       snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets,
-                                 ARRAY_SIZE(wm8753_dapm_widgets));
-
-       /* add neo1973 gta02 specific controls */
-       err = snd_soc_add_controls(codec, wm8753_neo1973_gta02_controls,
-               ARRAY_SIZE(wm8753_neo1973_gta02_controls));
-
-       if (err < 0)
-               return err;
-
-       /* set up neo1973 gta02 specific audio path audio_map */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
-
-       /* set endpoints to default off mode */
-       snd_soc_dapm_disable_pin(codec, "Stereo Out");
-       snd_soc_dapm_disable_pin(codec, "GSM Line Out");
-       snd_soc_dapm_disable_pin(codec, "GSM Line In");
-       snd_soc_dapm_disable_pin(codec, "Headset Mic");
-       snd_soc_dapm_disable_pin(codec, "Handset Mic");
-       snd_soc_dapm_disable_pin(codec, "Handset Spk");
-
-       /* allow audio paths from the GSM modem to run during suspend */
-       snd_soc_dapm_ignore_suspend(codec, "Stereo Out");
-       snd_soc_dapm_ignore_suspend(codec, "GSM Line Out");
-       snd_soc_dapm_ignore_suspend(codec, "GSM Line In");
-       snd_soc_dapm_ignore_suspend(codec, "Headset Mic");
-       snd_soc_dapm_ignore_suspend(codec, "Handset Mic");
-       snd_soc_dapm_ignore_suspend(codec, "Handset Spk");
-
-       snd_soc_dapm_sync(codec);
-
-       return 0;
-}
-
-/*
- * BT Codec DAI
- */
-static struct snd_soc_dai_driver bt_dai = {
-       .name = "bluetooth-dai",
-       .playback = {
-               .channels_min = 1,
-               .channels_max = 1,
-               .rates = SNDRV_PCM_RATE_8000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .capture = {
-               .channels_min = 1,
-               .channels_max = 1,
-               .rates = SNDRV_PCM_RATE_8000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-};
-
-static struct snd_soc_dai_link neo1973_gta02_dai[] = {
-{ /* Hifi Playback - for similatious use with voice below */
-       .name = "WM8753",
-       .stream_name = "WM8753 HiFi",
-       .cpu_dai_name = "s3c24xx-i2s",
-       .codec_dai_name = "wm8753-hifi",
-       .init = neo1973_gta02_wm8753_init,
-       .platform_name = "s3c24xx-pcm-audio",
-       .codec_name = "wm8753-codec.0-0x1a",
-       .ops = &neo1973_gta02_hifi_ops,
-},
-{ /* Voice via BT */
-       .name = "Bluetooth",
-       .stream_name = "Voice",
-       .cpu_dai_name = "bluetooth-dai",
-       .codec_dai_name = "wm8753-voice",
-       .ops = &neo1973_gta02_voice_ops,
-       .codec_name = "wm8753-codec.0-0x1a",
-       .platform_name = "s3c24xx-pcm-audio",
-},
-};
-
-static struct snd_soc_card neo1973_gta02 = {
-       .name = "neo1973-gta02",
-       .dai_link = neo1973_gta02_dai,
-       .num_links = ARRAY_SIZE(neo1973_gta02_dai),
-};
-
-static struct platform_device *neo1973_gta02_snd_device;
-
-static int __init neo1973_gta02_init(void)
-{
-       int ret;
-
-       if (!machine_is_neo1973_gta02()) {
-               printk(KERN_INFO
-                      "Only GTA02 is supported by this ASoC driver\n");
-               return -ENODEV;
-       }
-
-       neo1973_gta02_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!neo1973_gta02_snd_device)
-               return -ENOMEM;
-
-       /* register bluetooth DAI here */
-       ret = snd_soc_register_dai(&neo1973_gta02_snd_device->dev, -1, &bt_dai);
-       if (ret) {
-               platform_device_put(neo1973_gta02_snd_device);
-               return ret;
-       }
-
-       platform_set_drvdata(neo1973_gta02_snd_device, &neo1973_gta02);
-       ret = platform_device_add(neo1973_gta02_snd_device);
-
-       if (ret) {
-               platform_device_put(neo1973_gta02_snd_device);
-               return ret;
-       }
-
-       /* Initialise GPIOs used by amp */
-       ret = gpio_request(GTA02_GPIO_HP_IN, "GTA02_HP_IN");
-       if (ret) {
-               pr_err("gta02_wm8753: Failed to register GPIO %d\n", GTA02_GPIO_HP_IN);
-               goto err_unregister_device;
-       }
-
-       ret = gpio_direction_output(GTA02_GPIO_HP_IN, 1);
-       if (ret) {
-               pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_HP_IN);
-               goto err_free_gpio_hp_in;
-       }
-
-       ret = gpio_request(GTA02_GPIO_AMP_SHUT, "GTA02_AMP_SHUT");
-       if (ret) {
-               pr_err("gta02_wm8753: Failed to register GPIO %d\n", GTA02_GPIO_AMP_SHUT);
-               goto err_free_gpio_hp_in;
-       }
-
-       ret = gpio_direction_output(GTA02_GPIO_AMP_SHUT, 1);
-       if (ret) {
-               pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_AMP_SHUT);
-               goto err_free_gpio_amp_shut;
-       }
-
-       return 0;
-
-err_free_gpio_amp_shut:
-       gpio_free(GTA02_GPIO_AMP_SHUT);
-err_free_gpio_hp_in:
-       gpio_free(GTA02_GPIO_HP_IN);
-err_unregister_device:
-       platform_device_unregister(neo1973_gta02_snd_device);
-       return ret;
-}
-module_init(neo1973_gta02_init);
-
-static void __exit neo1973_gta02_exit(void)
-{
-       snd_soc_unregister_dai(&neo1973_gta02_snd_device->dev, -1);
-       platform_device_unregister(neo1973_gta02_snd_device);
-       gpio_free(GTA02_GPIO_HP_IN);
-       gpio_free(GTA02_GPIO_AMP_SHUT);
-}
-module_exit(neo1973_gta02_exit);
-
-/* Module information */
-MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org");
-MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 GTA02");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
deleted file mode 100644 (file)
index f4f2ee7..0000000
+++ /dev/null
@@ -1,704 +0,0 @@
-/*
- * neo1973_wm8753.c  --  SoC audio for Neo1973
- *
- * Copyright 2007 Wolfson Microelectronics PLC.
- * Author: Graeme Gregory
- *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
- *
- *  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/moduleparam.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/i2c.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/tlv.h>
-
-#include <asm/mach-types.h>
-#include <asm/hardware/scoop.h>
-#include <mach/regs-clock.h>
-#include <mach/regs-gpio.h>
-#include <mach/hardware.h>
-#include <linux/io.h>
-#include <mach/spi-gpio.h>
-
-#include <plat/regs-iis.h>
-
-#include "../codecs/wm8753.h"
-#include "lm4857.h"
-#include "s3c-dma.h"
-#include "s3c24xx-i2s.h"
-
-/* define the scenarios */
-#define NEO_AUDIO_OFF                  0
-#define NEO_GSM_CALL_AUDIO_HANDSET     1
-#define NEO_GSM_CALL_AUDIO_HEADSET     2
-#define NEO_GSM_CALL_AUDIO_BLUETOOTH   3
-#define NEO_STEREO_TO_SPEAKERS         4
-#define NEO_STEREO_TO_HEADPHONES       5
-#define NEO_CAPTURE_HANDSET            6
-#define NEO_CAPTURE_HEADSET            7
-#define NEO_CAPTURE_BLUETOOTH          8
-
-static struct snd_soc_card neo1973;
-static struct i2c_client *i2c;
-
-static int neo1973_hifi_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;
-       unsigned int pll_out = 0, bclk = 0;
-       int ret = 0;
-       unsigned long iis_clkrate;
-
-       pr_debug("Entered %s\n", __func__);
-
-       iis_clkrate = s3c24xx_i2s_get_clockrate();
-
-       switch (params_rate(params)) {
-       case 8000:
-       case 16000:
-               pll_out = 12288000;
-               break;
-       case 48000:
-               bclk = WM8753_BCLK_DIV_4;
-               pll_out = 12288000;
-               break;
-       case 96000:
-               bclk = WM8753_BCLK_DIV_2;
-               pll_out = 12288000;
-               break;
-       case 11025:
-               bclk = WM8753_BCLK_DIV_16;
-               pll_out = 11289600;
-               break;
-       case 22050:
-               bclk = WM8753_BCLK_DIV_8;
-               pll_out = 11289600;
-               break;
-       case 44100:
-               bclk = WM8753_BCLK_DIV_4;
-               pll_out = 11289600;
-               break;
-       case 88200:
-               bclk = WM8753_BCLK_DIV_2;
-               pll_out = 11289600;
-               break;
-       }
-
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai,
-               SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-               SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai,
-               SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-               SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* set the codec system clock for DAC and ADC */
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
-               SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       /* set MCLK division for sample rate */
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
-               S3C2410_IISMOD_32FS);
-       if (ret < 0)
-               return ret;
-
-       /* set codec BCLK division for sample rate */
-       ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
-       if (ret < 0)
-               return ret;
-
-       /* set prescaler division for sample rate */
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
-               S3C24XX_PRESCALE(4, 4));
-       if (ret < 0)
-               return ret;
-
-       /* codec PLL input is PCLK/4 */
-       ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
-               iis_clkrate / 4, pll_out);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
-       pr_debug("Entered %s\n", __func__);
-
-       /* disable the PLL */
-       return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
-}
-
-/*
- * Neo1973 WM8753 HiFi DAI opserations.
- */
-static struct snd_soc_ops neo1973_hifi_ops = {
-       .hw_params = neo1973_hifi_hw_params,
-       .hw_free = neo1973_hifi_hw_free,
-};
-
-static int neo1973_voice_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;
-       unsigned int pcmdiv = 0;
-       int ret = 0;
-       unsigned long iis_clkrate;
-
-       pr_debug("Entered %s\n", __func__);
-
-       iis_clkrate = s3c24xx_i2s_get_clockrate();
-
-       if (params_rate(params) != 8000)
-               return -EINVAL;
-       if (params_channels(params) != 1)
-               return -EINVAL;
-
-       pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
-
-       /* todo: gg check mode (DSP_B) against CSR datasheet */
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set the codec system clock for DAC and ADC */
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
-               SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       /* set codec PCM division for sample rate */
-       ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
-       if (ret < 0)
-               return ret;
-
-       /* configure and enable PLL for 12.288MHz output */
-       ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
-               iis_clkrate / 4, 12288000);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-
-       pr_debug("Entered %s\n", __func__);
-
-       /* disable the PLL */
-       return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
-}
-
-static struct snd_soc_ops neo1973_voice_ops = {
-       .hw_params = neo1973_voice_hw_params,
-       .hw_free = neo1973_voice_hw_free,
-};
-
-static int neo1973_scenario;
-
-static int neo1973_get_scenario(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       ucontrol->value.integer.value[0] = neo1973_scenario;
-       return 0;
-}
-
-static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario)
-{
-       pr_debug("Entered %s\n", __func__);
-
-       switch (neo1973_scenario) {
-       case NEO_AUDIO_OFF:
-               snd_soc_dapm_disable_pin(codec, "Audio Out");
-               snd_soc_dapm_disable_pin(codec, "GSM Line Out");
-               snd_soc_dapm_disable_pin(codec, "GSM Line In");
-               snd_soc_dapm_disable_pin(codec, "Headset Mic");
-               snd_soc_dapm_disable_pin(codec, "Call Mic");
-               break;
-       case NEO_GSM_CALL_AUDIO_HANDSET:
-               snd_soc_dapm_enable_pin(codec, "Audio Out");
-               snd_soc_dapm_enable_pin(codec, "GSM Line Out");
-               snd_soc_dapm_enable_pin(codec, "GSM Line In");
-               snd_soc_dapm_disable_pin(codec, "Headset Mic");
-               snd_soc_dapm_enable_pin(codec, "Call Mic");
-               break;
-       case NEO_GSM_CALL_AUDIO_HEADSET:
-               snd_soc_dapm_enable_pin(codec, "Audio Out");
-               snd_soc_dapm_enable_pin(codec, "GSM Line Out");
-               snd_soc_dapm_enable_pin(codec, "GSM Line In");
-               snd_soc_dapm_enable_pin(codec, "Headset Mic");
-               snd_soc_dapm_disable_pin(codec, "Call Mic");
-               break;
-       case NEO_GSM_CALL_AUDIO_BLUETOOTH:
-               snd_soc_dapm_disable_pin(codec, "Audio Out");
-               snd_soc_dapm_enable_pin(codec, "GSM Line Out");
-               snd_soc_dapm_enable_pin(codec, "GSM Line In");
-               snd_soc_dapm_disable_pin(codec, "Headset Mic");
-               snd_soc_dapm_disable_pin(codec, "Call Mic");
-               break;
-       case NEO_STEREO_TO_SPEAKERS:
-               snd_soc_dapm_enable_pin(codec, "Audio Out");
-               snd_soc_dapm_disable_pin(codec, "GSM Line Out");
-               snd_soc_dapm_disable_pin(codec, "GSM Line In");
-               snd_soc_dapm_disable_pin(codec, "Headset Mic");
-               snd_soc_dapm_disable_pin(codec, "Call Mic");
-               break;
-       case NEO_STEREO_TO_HEADPHONES:
-               snd_soc_dapm_enable_pin(codec, "Audio Out");
-               snd_soc_dapm_disable_pin(codec, "GSM Line Out");
-               snd_soc_dapm_disable_pin(codec, "GSM Line In");
-               snd_soc_dapm_disable_pin(codec, "Headset Mic");
-               snd_soc_dapm_disable_pin(codec, "Call Mic");
-               break;
-       case NEO_CAPTURE_HANDSET:
-               snd_soc_dapm_disable_pin(codec, "Audio Out");
-               snd_soc_dapm_disable_pin(codec, "GSM Line Out");
-               snd_soc_dapm_disable_pin(codec, "GSM Line In");
-               snd_soc_dapm_disable_pin(codec, "Headset Mic");
-               snd_soc_dapm_enable_pin(codec, "Call Mic");
-               break;
-       case NEO_CAPTURE_HEADSET:
-               snd_soc_dapm_disable_pin(codec, "Audio Out");
-               snd_soc_dapm_disable_pin(codec, "GSM Line Out");
-               snd_soc_dapm_disable_pin(codec, "GSM Line In");
-               snd_soc_dapm_enable_pin(codec, "Headset Mic");
-               snd_soc_dapm_disable_pin(codec, "Call Mic");
-               break;
-       case NEO_CAPTURE_BLUETOOTH:
-               snd_soc_dapm_disable_pin(codec, "Audio Out");
-               snd_soc_dapm_disable_pin(codec, "GSM Line Out");
-               snd_soc_dapm_disable_pin(codec, "GSM Line In");
-               snd_soc_dapm_disable_pin(codec, "Headset Mic");
-               snd_soc_dapm_disable_pin(codec, "Call Mic");
-               break;
-       default:
-               snd_soc_dapm_disable_pin(codec, "Audio Out");
-               snd_soc_dapm_disable_pin(codec, "GSM Line Out");
-               snd_soc_dapm_disable_pin(codec, "GSM Line In");
-               snd_soc_dapm_disable_pin(codec, "Headset Mic");
-               snd_soc_dapm_disable_pin(codec, "Call Mic");
-       }
-
-       snd_soc_dapm_sync(codec);
-
-       return 0;
-}
-
-static int neo1973_set_scenario(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-
-       pr_debug("Entered %s\n", __func__);
-
-       if (neo1973_scenario == ucontrol->value.integer.value[0])
-               return 0;
-
-       neo1973_scenario = ucontrol->value.integer.value[0];
-       set_scenario_endpoints(codec, neo1973_scenario);
-       return 1;
-}
-
-static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0};
-
-static void lm4857_write_regs(void)
-{
-       pr_debug("Entered %s\n", __func__);
-
-       if (i2c_master_send(i2c, lm4857_regs, 4) != 4)
-               printk(KERN_ERR "lm4857: i2c write failed\n");
-}
-
-static int lm4857_get_reg(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-       int reg = mc->reg;
-       int shift = mc->shift;
-       int mask = mc->max;
-
-       pr_debug("Entered %s\n", __func__);
-
-       ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask;
-       return 0;
-}
-
-static int lm4857_set_reg(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-       int reg = mc->reg;
-       int shift = mc->shift;
-       int mask = mc->max;
-
-       if (((lm4857_regs[reg] >> shift) & mask) ==
-               ucontrol->value.integer.value[0])
-               return 0;
-
-       lm4857_regs[reg] &= ~(mask << shift);
-       lm4857_regs[reg] |= ucontrol->value.integer.value[0] << shift;
-       lm4857_write_regs();
-       return 1;
-}
-
-static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       u8 value = lm4857_regs[LM4857_CTRL] & 0x0F;
-
-       pr_debug("Entered %s\n", __func__);
-
-       if (value)
-               value -= 5;
-
-       ucontrol->value.integer.value[0] = value;
-       return 0;
-}
-
-static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       u8 value = ucontrol->value.integer.value[0];
-
-       pr_debug("Entered %s\n", __func__);
-
-       if (value)
-               value += 5;
-
-       if ((lm4857_regs[LM4857_CTRL] & 0x0F) == value)
-               return 0;
-
-       lm4857_regs[LM4857_CTRL] &= 0xF0;
-       lm4857_regs[LM4857_CTRL] |= value;
-       lm4857_write_regs();
-       return 1;
-}
-
-static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
-       SND_SOC_DAPM_LINE("Audio Out", NULL),
-       SND_SOC_DAPM_LINE("GSM Line Out", NULL),
-       SND_SOC_DAPM_LINE("GSM Line In", NULL),
-       SND_SOC_DAPM_MIC("Headset Mic", NULL),
-       SND_SOC_DAPM_MIC("Call Mic", NULL),
-};
-
-
-static const struct snd_soc_dapm_route dapm_routes[] = {
-
-       /* Connections to the lm4857 amp */
-       {"Audio Out", NULL, "LOUT1"},
-       {"Audio Out", NULL, "ROUT1"},
-
-       /* Connections to the GSM Module */
-       {"GSM Line Out", NULL, "MONO1"},
-       {"GSM Line Out", NULL, "MONO2"},
-       {"RXP", NULL, "GSM Line In"},
-       {"RXN", NULL, "GSM Line In"},
-
-       /* Connections to Headset */
-       {"MIC1", NULL, "Mic Bias"},
-       {"Mic Bias", NULL, "Headset Mic"},
-
-       /* Call Mic */
-       {"MIC2", NULL, "Mic Bias"},
-       {"MIC2N", NULL, "Mic Bias"},
-       {"Mic Bias", NULL, "Call Mic"},
-
-       /* Connect the ALC pins */
-       {"ACIN", NULL, "ACOP"},
-};
-
-static const char *lm4857_mode[] = {
-       "Off",
-       "Call Speaker",
-       "Stereo Speakers",
-       "Stereo Speakers + Headphones",
-       "Headphones"
-};
-
-static const struct soc_enum lm4857_mode_enum[] = {
-       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode),
-};
-
-static const char *neo_scenarios[] = {
-       "Off",
-       "GSM Handset",
-       "GSM Headset",
-       "GSM Bluetooth",
-       "Speakers",
-       "Headphones",
-       "Capture Handset",
-       "Capture Headset",
-       "Capture Bluetooth"
-};
-
-static const struct soc_enum neo_scenario_enum[] = {
-       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios), neo_scenarios),
-};
-
-static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0);
-static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0);
-
-static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
-       SOC_SINGLE_EXT_TLV("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0,
-               lm4857_get_reg, lm4857_set_reg, stereo_tlv),
-       SOC_SINGLE_EXT_TLV("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0,
-               lm4857_get_reg, lm4857_set_reg, stereo_tlv),
-       SOC_SINGLE_EXT_TLV("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0,
-               lm4857_get_reg, lm4857_set_reg, mono_tlv),
-       SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0],
-               lm4857_get_mode, lm4857_set_mode),
-       SOC_ENUM_EXT("Neo Mode", neo_scenario_enum[0],
-               neo1973_get_scenario, neo1973_set_scenario),
-       SOC_SINGLE_EXT("Amp Spk 3D Playback Switch", LM4857_LVOL, 5, 1, 0,
-               lm4857_get_reg, lm4857_set_reg),
-       SOC_SINGLE_EXT("Amp HP 3d Playback Switch", LM4857_RVOL, 5, 1, 0,
-               lm4857_get_reg, lm4857_set_reg),
-       SOC_SINGLE_EXT("Amp Fast Wakeup Playback Switch", LM4857_CTRL, 5, 1, 0,
-               lm4857_get_reg, lm4857_set_reg),
-       SOC_SINGLE_EXT("Amp Earpiece 6dB Playback Switch", LM4857_CTRL, 4, 1, 0,
-               lm4857_get_reg, lm4857_set_reg),
-};
-
-/*
- * This is an example machine initialisation for a wm8753 connected to a
- * neo1973 II. It is missing logic to detect hp/mic insertions and logic
- * to re-route the audio in such an event.
- */
-static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       int err;
-
-       pr_debug("Entered %s\n", __func__);
-
-       /* set up NC codec pins */
-       snd_soc_dapm_nc_pin(codec, "LOUT2");
-       snd_soc_dapm_nc_pin(codec, "ROUT2");
-       snd_soc_dapm_nc_pin(codec, "OUT3");
-       snd_soc_dapm_nc_pin(codec, "OUT4");
-       snd_soc_dapm_nc_pin(codec, "LINE1");
-       snd_soc_dapm_nc_pin(codec, "LINE2");
-
-       /* Add neo1973 specific widgets */
-       snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets,
-                                 ARRAY_SIZE(wm8753_dapm_widgets));
-
-       /* set endpoints to default mode */
-       set_scenario_endpoints(codec, NEO_AUDIO_OFF);
-
-       /* add neo1973 specific controls */
-       err = snd_soc_add_controls(codec, wm8753_neo1973_controls,
-                               ARRAY_SIZE(8753_neo1973_controls));
-       if (err < 0)
-               return err;
-
-       /* set up neo1973 specific audio routes */
-       err = snd_soc_dapm_add_routes(codec, dapm_routes,
-                                     ARRAY_SIZE(dapm_routes));
-
-       snd_soc_dapm_sync(codec);
-       return 0;
-}
-
-/*
- * BT Codec DAI
- */
-static struct snd_soc_dai bt_dai = {
-       .name = "bluetooth-dai",
-       .playback = {
-               .channels_min = 1,
-               .channels_max = 1,
-               .rates = SNDRV_PCM_RATE_8000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .capture = {
-               .channels_min = 1,
-               .channels_max = 1,
-               .rates = SNDRV_PCM_RATE_8000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-};
-
-static struct snd_soc_dai_link neo1973_dai[] = {
-{ /* Hifi Playback - for similatious use with voice below */
-       .name = "WM8753",
-       .stream_name = "WM8753 HiFi",
-       .platform_name = "s3c24xx-pcm-audio",
-       .cpu_dai_name = "s3c24xx-i2s",
-       .codec_dai_name = "wm8753-hifi",
-       .codec_name = "wm8753-codec.0-0x1a",
-       .init = neo1973_wm8753_init,
-       .ops = &neo1973_hifi_ops,
-},
-{ /* Voice via BT */
-       .name = "Bluetooth",
-       .stream_name = "Voice",
-       .platform_name = "s3c24xx-pcm-audio",
-       .cpu_dai_name = "bluetooth-dai",
-       .codec_dai_name = "wm8753-voice",
-       .codec_name = "wm8753-codec.0-0x1a",
-       .ops = &neo1973_voice_ops,
-},
-};
-
-static struct snd_soc_card neo1973 = {
-       .name = "neo1973",
-       .dai_link = neo1973_dai,
-       .num_links = ARRAY_SIZE(neo1973_dai),
-};
-
-static int lm4857_i2c_probe(struct i2c_client *client,
-                           const struct i2c_device_id *id)
-{
-       pr_debug("Entered %s\n", __func__);
-
-       i2c = client;
-
-       lm4857_write_regs();
-       return 0;
-}
-
-static int lm4857_i2c_remove(struct i2c_client *client)
-{
-       pr_debug("Entered %s\n", __func__);
-
-       i2c = NULL;
-
-       return 0;
-}
-
-static u8 lm4857_state;
-
-static int lm4857_suspend(struct i2c_client *dev, pm_message_t state)
-{
-       pr_debug("Entered %s\n", __func__);
-
-       dev_dbg(&dev->dev, "lm4857_suspend\n");
-       lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf;
-       if (lm4857_state) {
-               lm4857_regs[LM4857_CTRL] &= 0xf0;
-               lm4857_write_regs();
-       }
-       return 0;
-}
-
-static int lm4857_resume(struct i2c_client *dev)
-{
-       pr_debug("Entered %s\n", __func__);
-
-       if (lm4857_state) {
-               lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f);
-               lm4857_write_regs();
-       }
-       return 0;
-}
-
-static void lm4857_shutdown(struct i2c_client *dev)
-{
-       pr_debug("Entered %s\n", __func__);
-
-       dev_dbg(&dev->dev, "lm4857_shutdown\n");
-       lm4857_regs[LM4857_CTRL] &= 0xf0;
-       lm4857_write_regs();
-}
-
-static const struct i2c_device_id lm4857_i2c_id[] = {
-       { "neo1973_lm4857", 0 },
-       { }
-};
-
-static struct i2c_driver lm4857_i2c_driver = {
-       .driver = {
-               .name = "LM4857 I2C Amp",
-               .owner = THIS_MODULE,
-       },
-       .suspend =        lm4857_suspend,
-       .resume =         lm4857_resume,
-       .shutdown =       lm4857_shutdown,
-       .probe =          lm4857_i2c_probe,
-       .remove =         lm4857_i2c_remove,
-       .id_table =       lm4857_i2c_id,
-};
-
-static struct platform_device *neo1973_snd_device;
-
-static int __init neo1973_init(void)
-{
-       int ret;
-
-       pr_debug("Entered %s\n", __func__);
-
-       if (!machine_is_neo1973_gta01()) {
-               printk(KERN_INFO
-                       "Only GTA01 hardware supported by ASoC driver\n");
-               return -ENODEV;
-       }
-
-       neo1973_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!neo1973_snd_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(neo1973_snd_device, &neo1973);
-       ret = platform_device_add(neo1973_snd_device);
-
-       if (ret) {
-               platform_device_put(neo1973_snd_device);
-               return ret;
-       }
-
-       ret = i2c_add_driver(&lm4857_i2c_driver);
-
-       if (ret != 0)
-               platform_device_unregister(neo1973_snd_device);
-
-       return ret;
-}
-
-static void __exit neo1973_exit(void)
-{
-       pr_debug("Entered %s\n", __func__);
-
-       i2c_del_driver(&lm4857_i2c_driver);
-       platform_device_unregister(neo1973_snd_device);
-}
-
-module_init(neo1973_init);
-module_exit(neo1973_exit);
-
-/* Module information */
-MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org");
-MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/regs-i2s-v2.h b/sound/soc/s3c24xx/regs-i2s-v2.h
deleted file mode 100644 (file)
index 5e5e568..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/* linux/include/asm-arm/plat-s3c24xx/regs-s3c2412-iis.h
- *
- * Copyright 2007 Simtec Electronics <linux@simtec.co.uk>
- *     http://armlinux.simtec.co.uk/
- *
- * 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.
- *
- * S3C2412 IIS register definition
-*/
-
-#ifndef __ASM_ARCH_REGS_S3C2412_IIS_H
-#define __ASM_ARCH_REGS_S3C2412_IIS_H
-
-#define S3C2412_IISCON                 (0x00)
-#define S3C2412_IISMOD                 (0x04)
-#define S3C2412_IISFIC                 (0x08)
-#define S3C2412_IISPSR                 (0x0C)
-#define S3C2412_IISTXD                 (0x10)
-#define S3C2412_IISRXD                 (0x14)
-
-#define S5PC1XX_IISFICS                0x18
-#define S5PC1XX_IISTXDS                0x1C
-
-#define S5PC1XX_IISCON_SW_RST          (1 << 31)
-#define S5PC1XX_IISCON_FRXOFSTATUS     (1 << 26)
-#define S5PC1XX_IISCON_FRXORINTEN      (1 << 25)
-#define S5PC1XX_IISCON_FTXSURSTAT      (1 << 24)
-#define S5PC1XX_IISCON_FTXSURINTEN     (1 << 23)
-#define S5PC1XX_IISCON_TXSDMAPAUSE     (1 << 20)
-#define S5PC1XX_IISCON_TXSDMACTIVE     (1 << 18)
-
-#define S3C64XX_IISCON_FTXURSTATUS     (1 << 17)
-#define S3C64XX_IISCON_FTXURINTEN      (1 << 16)
-#define S3C64XX_IISCON_TXFIFO2_EMPTY   (1 << 15)
-#define S3C64XX_IISCON_TXFIFO1_EMPTY   (1 << 14)
-#define S3C64XX_IISCON_TXFIFO2_FULL    (1 << 13)
-#define S3C64XX_IISCON_TXFIFO1_FULL    (1 << 12)
-
-#define S3C2412_IISCON_LRINDEX         (1 << 11)
-#define S3C2412_IISCON_TXFIFO_EMPTY    (1 << 10)
-#define S3C2412_IISCON_RXFIFO_EMPTY    (1 << 9)
-#define S3C2412_IISCON_TXFIFO_FULL     (1 << 8)
-#define S3C2412_IISCON_RXFIFO_FULL     (1 << 7)
-#define S3C2412_IISCON_TXDMA_PAUSE     (1 << 6)
-#define S3C2412_IISCON_RXDMA_PAUSE     (1 << 5)
-#define S3C2412_IISCON_TXCH_PAUSE      (1 << 4)
-#define S3C2412_IISCON_RXCH_PAUSE      (1 << 3)
-#define S3C2412_IISCON_TXDMA_ACTIVE    (1 << 2)
-#define S3C2412_IISCON_RXDMA_ACTIVE    (1 << 1)
-#define S3C2412_IISCON_IIS_ACTIVE      (1 << 0)
-
-#define S5PC1XX_IISMOD_OPCLK_CDCLK_OUT (0 << 30)
-#define S5PC1XX_IISMOD_OPCLK_CDCLK_IN  (1 << 30)
-#define S5PC1XX_IISMOD_OPCLK_BCLK_OUT  (2 << 30)
-#define S5PC1XX_IISMOD_OPCLK_PCLK      (3 << 30)
-#define S5PC1XX_IISMOD_OPCLK_MASK      (3 << 30)
-#define S5PC1XX_IISMOD_TXS_IDMA                (1 << 28) /* Sec_TXFIFO use I-DMA */
-#define S5PC1XX_IISMOD_BLCS_MASK       0x3
-#define S5PC1XX_IISMOD_BLCS_SHIFT      26
-#define S5PC1XX_IISMOD_BLCP_MASK       0x3
-#define S5PC1XX_IISMOD_BLCP_SHIFT      24
-
-#define S3C64XX_IISMOD_C2DD_HHALF      (1 << 21) /* Discard Higher-half */
-#define S3C64XX_IISMOD_C2DD_LHALF      (1 << 20) /* Discard Lower-half */
-#define S3C64XX_IISMOD_C1DD_HHALF      (1 << 19)
-#define S3C64XX_IISMOD_C1DD_LHALF      (1 << 18)
-#define S3C64XX_IISMOD_DC2_EN          (1 << 17)
-#define S3C64XX_IISMOD_DC1_EN          (1 << 16)
-#define S3C64XX_IISMOD_BLC_16BIT       (0 << 13)
-#define S3C64XX_IISMOD_BLC_8BIT                (1 << 13)
-#define S3C64XX_IISMOD_BLC_24BIT       (2 << 13)
-#define S3C64XX_IISMOD_BLC_MASK                (3 << 13)
-
-#define S3C2412_IISMOD_IMS_SYSMUX      (1 << 10)
-#define S3C2412_IISMOD_SLAVE           (1 << 11)
-#define S3C2412_IISMOD_MODE_TXONLY     (0 << 8)
-#define S3C2412_IISMOD_MODE_RXONLY     (1 << 8)
-#define S3C2412_IISMOD_MODE_TXRX       (2 << 8)
-#define S3C2412_IISMOD_MODE_MASK       (3 << 8)
-#define S3C2412_IISMOD_LR_LLOW         (0 << 7)
-#define S3C2412_IISMOD_LR_RLOW         (1 << 7)
-#define S3C2412_IISMOD_SDF_IIS         (0 << 5)
-#define S3C2412_IISMOD_SDF_MSB         (1 << 5)
-#define S3C2412_IISMOD_SDF_LSB         (2 << 5)
-#define S3C2412_IISMOD_SDF_MASK                (3 << 5)
-#define S3C2412_IISMOD_RCLK_256FS      (0 << 3)
-#define S3C2412_IISMOD_RCLK_512FS      (1 << 3)
-#define S3C2412_IISMOD_RCLK_384FS      (2 << 3)
-#define S3C2412_IISMOD_RCLK_768FS      (3 << 3)
-#define S3C2412_IISMOD_RCLK_MASK       (3 << 3)
-#define S3C2412_IISMOD_BCLK_32FS       (0 << 1)
-#define S3C2412_IISMOD_BCLK_48FS       (1 << 1)
-#define S3C2412_IISMOD_BCLK_16FS       (2 << 1)
-#define S3C2412_IISMOD_BCLK_24FS       (3 << 1)
-#define S3C2412_IISMOD_BCLK_MASK       (3 << 1)
-#define S3C2412_IISMOD_8BIT            (1 << 0)
-
-#define S3C64XX_IISMOD_CDCLKCON                (1 << 12)
-
-#define S3C2412_IISPSR_PSREN           (1 << 15)
-
-#define S3C64XX_IISFIC_TX2COUNT(x)     (((x) >>  24) & 0xf)
-#define S3C64XX_IISFIC_TX1COUNT(x)     (((x) >>  16) & 0xf)
-
-#define S3C2412_IISFIC_TXFLUSH         (1 << 15)
-#define S3C2412_IISFIC_RXFLUSH         (1 << 7)
-#define S3C2412_IISFIC_TXCOUNT(x)      (((x) >>  8) & 0xf)
-#define S3C2412_IISFIC_RXCOUNT(x)      (((x) >>  0) & 0xf)
-
-#define S5PC1XX_IISFICS_TXFLUSH                (1 << 15)
-#define S5PC1XX_IISFICS_TXCOUNT(x)     (((x) >>  8) & 0x7f)
-
-#endif /* __ASM_ARCH_REGS_S3C2412_IIS_H */
diff --git a/sound/soc/s3c24xx/rx1950_uda1380.c b/sound/soc/s3c24xx/rx1950_uda1380.c
deleted file mode 100644 (file)
index 468cc11..0000000
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * rx1950.c  --  ALSA Soc Audio Layer
- *
- * Copyright (c) 2010 Vasily Khoruzhick <anarsoul@gmail.com>
- *
- * Based on smdk2440.c and magician.c
- *
- * Authors: Graeme Gregory graeme.gregory@wolfsonmicro.com
- *          Philipp Zabel <philipp.zabel@gmail.com>
- *          Denis Grigoriev <dgreenday@gmail.com>
- *          Vasily Khoruzhick <anarsoul@gmail.com>
- *
- *  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/moduleparam.h>
-#include <linux/platform_device.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/clk.h>
-
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/uda1380.h>
-#include <sound/jack.h>
-
-#include <plat/regs-iis.h>
-
-#include <mach/regs-clock.h>
-
-#include <asm/mach-types.h>
-
-#include "s3c-dma.h"
-#include "s3c24xx-i2s.h"
-#include "../codecs/uda1380.h"
-
-static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd);
-static int rx1950_startup(struct snd_pcm_substream *substream);
-static int rx1950_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params);
-static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
-                               struct snd_kcontrol *kcontrol, int event);
-
-static unsigned int rates[] = {
-       16000,
-       44100,
-       48000,
-};
-
-static struct snd_pcm_hw_constraint_list hw_rates = {
-       .count = ARRAY_SIZE(rates),
-       .list = rates,
-       .mask = 0,
-};
-
-static struct snd_soc_jack hp_jack;
-
-static struct snd_soc_jack_pin hp_jack_pins[] = {
-       {
-               .pin    = "Headphone Jack",
-               .mask   = SND_JACK_HEADPHONE,
-       },
-       {
-               .pin    = "Speaker",
-               .mask   = SND_JACK_HEADPHONE,
-               .invert = 1,
-       },
-};
-
-static struct snd_soc_jack_gpio hp_jack_gpios[] = {
-       [0] = {
-               .gpio                   = S3C2410_GPG(12),
-               .name                   = "hp-gpio",
-               .report                 = SND_JACK_HEADPHONE,
-               .invert                 = 1,
-               .debounce_time          = 200,
-       },
-};
-
-static struct snd_soc_ops rx1950_ops = {
-       .startup        = rx1950_startup,
-       .hw_params      = rx1950_hw_params,
-};
-
-/* s3c24xx digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link rx1950_uda1380_dai[] = {
-       {
-               .name           = "uda1380",
-               .stream_name    = "UDA1380 Duplex",
-               .cpu_dai_name   = "s3c24xx-iis",
-               .codec_dai_name = "uda1380-hifi",
-               .init           = rx1950_uda1380_init,
-               .platform_name  = "s3c24xx-pcm-audio",
-               .codec_name     = "uda1380-codec.0-001a",
-               .ops            = &rx1950_ops,
-       },
-};
-
-static struct snd_soc_card rx1950_asoc = {
-       .name = "rx1950",
-       .dai_link = rx1950_uda1380_dai,
-       .num_links = ARRAY_SIZE(rx1950_uda1380_dai),
-};
-
-/* rx1950 machine dapm widgets */
-static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
-       SND_SOC_DAPM_HP("Headphone Jack", NULL),
-       SND_SOC_DAPM_MIC("Mic Jack", NULL),
-       SND_SOC_DAPM_SPK("Speaker", rx1950_spk_power),
-};
-
-/* rx1950 machine audio_map */
-static const struct snd_soc_dapm_route audio_map[] = {
-       /* headphone connected to VOUTLHP, VOUTRHP */
-       {"Headphone Jack", NULL, "VOUTLHP"},
-       {"Headphone Jack", NULL, "VOUTRHP"},
-
-       /* ext speaker connected to VOUTL, VOUTR  */
-       {"Speaker", NULL, "VOUTL"},
-       {"Speaker", NULL, "VOUTR"},
-
-       /* mic is connected to VINM */
-       {"VINM", NULL, "Mic Jack"},
-};
-
-static struct platform_device *s3c24xx_snd_device;
-
-static int rx1950_startup(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-
-       runtime->hw.rate_min = hw_rates.list[0];
-       runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1];
-       runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
-
-       return snd_pcm_hw_constraint_list(runtime, 0,
-                                       SNDRV_PCM_HW_PARAM_RATE,
-                                       &hw_rates);
-}
-
-static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
-                               struct snd_kcontrol *kcontrol, int event)
-{
-       if (SND_SOC_DAPM_EVENT_ON(event))
-               gpio_set_value(S3C2410_GPA(1), 1);
-       else
-               gpio_set_value(S3C2410_GPA(1), 0);
-
-       return 0;
-}
-
-static int rx1950_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;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       int div;
-       int ret;
-       unsigned int rate = params_rate(params);
-       int clk_source, fs_mode;
-
-       switch (rate) {
-       case 16000:
-       case 48000:
-               clk_source = S3C24XX_CLKSRC_PCLK;
-               fs_mode = S3C2410_IISMOD_256FS;
-               div = s3c24xx_i2s_get_clockrate() / (256 * rate);
-               if (s3c24xx_i2s_get_clockrate() % (256 * rate) > (128 * rate))
-                       div++;
-               break;
-       case 44100:
-       case 88200:
-               clk_source = S3C24XX_CLKSRC_MPLL;
-               fs_mode = S3C2410_IISMOD_384FS;
-               div = 1;
-               break;
-       default:
-               printk(KERN_ERR "%s: rate %d is not supported\n",
-                       __func__, rate);
-               return -EINVAL;
-       }
-
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* select clock source */
-       ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source, rate,
-                       SND_SOC_CLOCK_OUT);
-       if (ret < 0)
-               return ret;
-
-       /* set MCLK division for sample rate */
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
-               fs_mode);
-       if (ret < 0)
-               return ret;
-
-       /* set BCLK division for sample rate */
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
-               S3C2410_IISMOD_32FS);
-       if (ret < 0)
-               return ret;
-
-       /* set prescaler division for sample rate */
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
-               S3C24XX_PRESCALE(div, div));
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       int err;
-
-       /* Add rx1950 specific widgets */
-       err = snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets,
-                                 ARRAY_SIZE(uda1380_dapm_widgets));
-
-       if (err)
-               return err;
-
-       /* Set up rx1950 specific audio path audio_mapnects */
-       err = snd_soc_dapm_add_routes(codec, audio_map,
-                                     ARRAY_SIZE(audio_map));
-
-       if (err)
-               return err;
-
-       snd_soc_dapm_enable_pin(codec, "Headphone Jack");
-       snd_soc_dapm_enable_pin(codec, "Speaker");
-
-       snd_soc_dapm_sync(codec);
-
-       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
-               &hp_jack);
-
-       snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
-               hp_jack_pins);
-
-       snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
-               hp_jack_gpios);
-
-       return 0;
-}
-
-static int __init rx1950_init(void)
-{
-       int ret;
-
-       if (!machine_is_rx1950())
-               return -ENODEV;
-
-       /* configure some gpios */
-       ret = gpio_request(S3C2410_GPA(1), "speaker-power");
-       if (ret)
-               goto err_gpio;
-
-       ret = gpio_direction_output(S3C2410_GPA(1), 0);
-       if (ret)
-               goto err_gpio_conf;
-
-       s3c24xx_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!s3c24xx_snd_device) {
-               ret = -ENOMEM;
-               goto err_plat_alloc;
-       }
-
-       platform_set_drvdata(s3c24xx_snd_device, &rx1950_asoc);
-       ret = platform_device_add(s3c24xx_snd_device);
-
-       if (ret) {
-               platform_device_put(s3c24xx_snd_device);
-               goto err_plat_add;
-       }
-
-       return 0;
-
-err_plat_add:
-err_plat_alloc:
-err_gpio_conf:
-       gpio_free(S3C2410_GPA(1));
-
-err_gpio:
-       return ret;
-}
-
-static void __exit rx1950_exit(void)
-{
-       platform_device_unregister(s3c24xx_snd_device);
-       snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
-               hp_jack_gpios);
-       gpio_free(S3C2410_GPA(1));
-}
-
-module_init(rx1950_init);
-module_exit(rx1950_exit);
-
-/* Module information */
-MODULE_AUTHOR("Vasily Khoruzhick");
-MODULE_DESCRIPTION("ALSA SoC RX1950");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c-ac97.c b/sound/soc/s3c24xx/s3c-ac97.c
deleted file mode 100644 (file)
index f891eb7..0000000
+++ /dev/null
@@ -1,520 +0,0 @@
-/* sound/soc/s3c24xx/s3c-ac97.c
- *
- * ALSA SoC Audio Layer - S3C AC97 Controller driver
- *     Evolved from s3c2443-ac97.c
- *
- * Copyright (c) 2010 Samsung Electronics Co. Ltd
- *     Author: Jaswinder Singh <jassi.brar@samsung.com>
- *     Credits: Graeme Gregory, Sean Choi
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-
-#include <sound/soc.h>
-
-#include <plat/regs-ac97.h>
-#include <mach/dma.h>
-#include <plat/audio.h>
-
-#include "s3c-dma.h"
-#include "s3c-ac97.h"
-
-#define AC_CMD_ADDR(x) (x << 16)
-#define AC_CMD_DATA(x) (x & 0xffff)
-
-struct s3c_ac97_info {
-       struct clk         *ac97_clk;
-       void __iomem       *regs;
-       struct mutex       lock;
-       struct completion  done;
-};
-static struct s3c_ac97_info s3c_ac97;
-
-static struct s3c2410_dma_client s3c_dma_client_out = {
-       .name = "AC97 PCMOut"
-};
-
-static struct s3c2410_dma_client s3c_dma_client_in = {
-       .name = "AC97 PCMIn"
-};
-
-static struct s3c2410_dma_client s3c_dma_client_micin = {
-       .name = "AC97 MicIn"
-};
-
-static struct s3c_dma_params s3c_ac97_pcm_out = {
-       .client         = &s3c_dma_client_out,
-       .dma_size       = 4,
-};
-
-static struct s3c_dma_params s3c_ac97_pcm_in = {
-       .client         = &s3c_dma_client_in,
-       .dma_size       = 4,
-};
-
-static struct s3c_dma_params s3c_ac97_mic_in = {
-       .client         = &s3c_dma_client_micin,
-       .dma_size       = 4,
-};
-
-static void s3c_ac97_activate(struct snd_ac97 *ac97)
-{
-       u32 ac_glbctrl, stat;
-
-       stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
-       if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
-               return; /* Return if already active */
-
-       INIT_COMPLETION(s3c_ac97.done);
-
-       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
-       ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
-       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-       msleep(1);
-
-       ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
-       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-       msleep(1);
-
-       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
-       ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
-       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
-       if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
-               pr_err("AC97: Unable to activate!");
-}
-
-static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
-       unsigned short reg)
-{
-       u32 ac_glbctrl, ac_codec_cmd;
-       u32 stat, addr, data;
-
-       mutex_lock(&s3c_ac97.lock);
-
-       s3c_ac97_activate(ac97);
-
-       INIT_COMPLETION(s3c_ac97.done);
-
-       ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
-       ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg);
-       writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
-
-       udelay(50);
-
-       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
-       ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
-       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
-       if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
-               pr_err("AC97: Unable to read!");
-
-       stat = readl(s3c_ac97.regs + S3C_AC97_STAT);
-       addr = (stat >> 16) & 0x7f;
-       data = (stat & 0xffff);
-
-       if (addr != reg)
-               pr_err("s3c-ac97: req addr = %02x, rep addr = %02x\n",
-                       reg, addr);
-
-       mutex_unlock(&s3c_ac97.lock);
-
-       return (unsigned short)data;
-}
-
-static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
-       unsigned short val)
-{
-       u32 ac_glbctrl, ac_codec_cmd;
-
-       mutex_lock(&s3c_ac97.lock);
-
-       s3c_ac97_activate(ac97);
-
-       INIT_COMPLETION(s3c_ac97.done);
-
-       ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
-       ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val);
-       writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
-
-       udelay(50);
-
-       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
-       ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
-       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
-       if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
-               pr_err("AC97: Unable to write!");
-
-       ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
-       ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
-       writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
-
-       mutex_unlock(&s3c_ac97.lock);
-}
-
-static void s3c_ac97_cold_reset(struct snd_ac97 *ac97)
-{
-       pr_debug("AC97: Cold reset\n");
-       writel(S3C_AC97_GLBCTRL_COLDRESET,
-                       s3c_ac97.regs + S3C_AC97_GLBCTRL);
-       msleep(1);
-
-       writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-       msleep(1);
-}
-
-static void s3c_ac97_warm_reset(struct snd_ac97 *ac97)
-{
-       u32 stat;
-
-       stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
-       if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
-               return; /* Return if already active */
-
-       pr_debug("AC97: Warm reset\n");
-
-       writel(S3C_AC97_GLBCTRL_WARMRESET, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-       msleep(1);
-
-       writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-       msleep(1);
-
-       s3c_ac97_activate(ac97);
-}
-
-static irqreturn_t s3c_ac97_irq(int irq, void *dev_id)
-{
-       u32 ac_glbctrl, ac_glbstat;
-
-       ac_glbstat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT);
-
-       if (ac_glbstat & S3C_AC97_GLBSTAT_CODECREADY) {
-
-               ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
-               ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE;
-               writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
-               complete(&s3c_ac97.done);
-       }
-
-       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
-       ac_glbctrl |= (1<<30); /* Clear interrupt */
-       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
-       return IRQ_HANDLED;
-}
-
-struct snd_ac97_bus_ops soc_ac97_ops = {
-       .read       = s3c_ac97_read,
-       .write      = s3c_ac97_write,
-       .warm_reset = s3c_ac97_warm_reset,
-       .reset      = s3c_ac97_cold_reset,
-};
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
-
-static int s3c_ac97_hw_params(struct snd_pcm_substream *substream,
-                                 struct snd_pcm_hw_params *params,
-                                 struct snd_soc_dai *dai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct s3c_dma_params *dma_data;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               dma_data = &s3c_ac97_pcm_out;
-       else
-               dma_data = &s3c_ac97_pcm_in;
-
-       snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
-
-       return 0;
-}
-
-static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
-                               struct snd_soc_dai *dai)
-{
-       u32 ac_glbctrl;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct s3c_dma_params *dma_data =
-               snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
-       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-               ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
-       else
-               ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-                       ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
-               else
-                       ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA;
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               break;
-       }
-
-       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
-       s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
-
-       return 0;
-}
-
-static int s3c_ac97_hw_mic_params(struct snd_pcm_substream *substream,
-                                     struct snd_pcm_hw_params *params,
-                                     struct snd_soc_dai *dai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               return -ENODEV;
-       else
-               snd_soc_dai_set_dma_data(cpu_dai, substream, &s3c_ac97_mic_in);
-
-       return 0;
-}
-
-static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
-                                   int cmd, struct snd_soc_dai *dai)
-{
-       u32 ac_glbctrl;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct s3c_dma_params *dma_data =
-               snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
-       ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               ac_glbctrl |= S3C_AC97_GLBCTRL_MICINTM_DMA;
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               break;
-       }
-
-       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
-
-       s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
-
-       return 0;
-}
-
-static struct snd_soc_dai_ops s3c_ac97_dai_ops = {
-       .hw_params      = s3c_ac97_hw_params,
-       .trigger        = s3c_ac97_trigger,
-};
-
-static struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = {
-       .hw_params      = s3c_ac97_hw_mic_params,
-       .trigger        = s3c_ac97_mic_trigger,
-};
-
-static struct snd_soc_dai_driver s3c_ac97_dai[] = {
-       [S3C_AC97_DAI_PCM] = {
-               .name = "s3c-ac97",
-               .ac97_control = 1,
-               .playback = {
-                       .stream_name = "AC97 Playback",
-                       .channels_min = 2,
-                       .channels_max = 2,
-                       .rates = SNDRV_PCM_RATE_8000_48000,
-                       .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-               .capture = {
-                       .stream_name = "AC97 Capture",
-                       .channels_min = 2,
-                       .channels_max = 2,
-                       .rates = SNDRV_PCM_RATE_8000_48000,
-                       .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-               .ops = &s3c_ac97_dai_ops,
-       },
-       [S3C_AC97_DAI_MIC] = {
-               .name = "s3c-ac97-mic",
-               .ac97_control = 1,
-               .capture = {
-                       .stream_name = "AC97 Mic Capture",
-                       .channels_min = 1,
-                       .channels_max = 1,
-                       .rates = SNDRV_PCM_RATE_8000_48000,
-                       .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-               .ops = &s3c_ac97_mic_dai_ops,
-       },
-};
-
-static __devinit int s3c_ac97_probe(struct platform_device *pdev)
-{
-       struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res;
-       struct s3c_audio_pdata *ac97_pdata;
-       int ret;
-
-       ac97_pdata = pdev->dev.platform_data;
-       if (!ac97_pdata || !ac97_pdata->cfg_gpio) {
-               dev_err(&pdev->dev, "cfg_gpio callback not provided!\n");
-               return -EINVAL;
-       }
-
-       /* Check for availability of necessary resource */
-       dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!dmatx_res) {
-               dev_err(&pdev->dev, "Unable to get AC97-TX dma resource\n");
-               return -ENXIO;
-       }
-
-       dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-       if (!dmarx_res) {
-               dev_err(&pdev->dev, "Unable to get AC97-RX dma resource\n");
-               return -ENXIO;
-       }
-
-       dmamic_res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
-       if (!dmamic_res) {
-               dev_err(&pdev->dev, "Unable to get AC97-MIC dma resource\n");
-               return -ENXIO;
-       }
-
-       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mem_res) {
-               dev_err(&pdev->dev, "Unable to get register resource\n");
-               return -ENXIO;
-       }
-
-       irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!irq_res) {
-               dev_err(&pdev->dev, "AC97 IRQ not provided!\n");
-               return -ENXIO;
-       }
-
-       if (!request_mem_region(mem_res->start,
-                               resource_size(mem_res), "s3c-ac97")) {
-               dev_err(&pdev->dev, "Unable to request register region\n");
-               return -EBUSY;
-       }
-
-       s3c_ac97_pcm_out.channel = dmatx_res->start;
-       s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
-       s3c_ac97_pcm_in.channel = dmarx_res->start;
-       s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
-       s3c_ac97_mic_in.channel = dmamic_res->start;
-       s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA;
-
-       init_completion(&s3c_ac97.done);
-       mutex_init(&s3c_ac97.lock);
-
-       s3c_ac97.regs = ioremap(mem_res->start, resource_size(mem_res));
-       if (s3c_ac97.regs == NULL) {
-               dev_err(&pdev->dev, "Unable to ioremap register region\n");
-               ret = -ENXIO;
-               goto err1;
-       }
-
-       s3c_ac97.ac97_clk = clk_get(&pdev->dev, "ac97");
-       if (IS_ERR(s3c_ac97.ac97_clk)) {
-               dev_err(&pdev->dev, "s3c-ac97 failed to get ac97_clock\n");
-               ret = -ENODEV;
-               goto err2;
-       }
-       clk_enable(s3c_ac97.ac97_clk);
-
-       if (ac97_pdata->cfg_gpio(pdev)) {
-               dev_err(&pdev->dev, "Unable to configure gpio\n");
-               ret = -EINVAL;
-               goto err3;
-       }
-
-       ret = request_irq(irq_res->start, s3c_ac97_irq,
-                                       IRQF_DISABLED, "AC97", NULL);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "s3c-ac97: interrupt request failed.\n");
-               goto err4;
-       }
-
-       ret = snd_soc_register_dais(&pdev->dev, s3c_ac97_dai,
-                       ARRAY_SIZE(s3c_ac97_dai));
-       if (ret)
-               goto err5;
-
-       return 0;
-
-err5:
-       free_irq(irq_res->start, NULL);
-err4:
-err3:
-       clk_disable(s3c_ac97.ac97_clk);
-       clk_put(s3c_ac97.ac97_clk);
-err2:
-       iounmap(s3c_ac97.regs);
-err1:
-       release_mem_region(mem_res->start, resource_size(mem_res));
-
-       return ret;
-}
-
-static __devexit int s3c_ac97_remove(struct platform_device *pdev)
-{
-       struct resource *mem_res, *irq_res;
-
-       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai));
-
-       irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (irq_res)
-               free_irq(irq_res->start, NULL);
-
-       clk_disable(s3c_ac97.ac97_clk);
-       clk_put(s3c_ac97.ac97_clk);
-
-       iounmap(s3c_ac97.regs);
-
-       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (mem_res)
-               release_mem_region(mem_res->start, resource_size(mem_res));
-
-       return 0;
-}
-
-static struct platform_driver s3c_ac97_driver = {
-       .probe  = s3c_ac97_probe,
-       .remove = s3c_ac97_remove,
-       .driver = {
-               .name = "s3c-ac97",
-               .owner = THIS_MODULE,
-       },
-};
-
-static int __init s3c_ac97_init(void)
-{
-       return platform_driver_register(&s3c_ac97_driver);
-}
-module_init(s3c_ac97_init);
-
-static void __exit s3c_ac97_exit(void)
-{
-       platform_driver_unregister(&s3c_ac97_driver);
-}
-module_exit(s3c_ac97_exit);
-
-MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
-MODULE_DESCRIPTION("AC97 driver for the Samsung SoC");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s3c-ac97");
diff --git a/sound/soc/s3c24xx/s3c-ac97.h b/sound/soc/s3c24xx/s3c-ac97.h
deleted file mode 100644 (file)
index 5dcedd0..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* sound/soc/s3c24xx/s3c-ac97.h
- *
- * ALSA SoC Audio Layer - S3C AC97 Controller driver
- *     Evolved from s3c2443-ac97.h
- *
- * Copyright (c) 2010 Samsung Electronics Co. Ltd
- *     Author: Jaswinder Singh <jassi.brar@samsung.com>
- *     Credits: Graeme Gregory, Sean Choi
- *
- * 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 __S3C_AC97_H_
-#define __S3C_AC97_H_
-
-#define S3C_AC97_DAI_PCM 0
-#define S3C_AC97_DAI_MIC 1
-
-#endif /* __S3C_AC97_H_ */
diff --git a/sound/soc/s3c24xx/s3c-dma.c b/sound/soc/s3c24xx/s3c-dma.c
deleted file mode 100644 (file)
index 243f79b..0000000
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- * s3c-dma.c  --  ALSA Soc Audio Layer
- *
- * (c) 2006 Wolfson Microelectronics PLC.
- * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
- *
- * Copyright 2004-2005 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- *  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/init.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/dma-mapping.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <asm/dma.h>
-#include <mach/hardware.h>
-#include <mach/dma.h>
-
-#include "s3c-dma.h"
-
-static const struct snd_pcm_hardware s3c_dma_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,
-       .formats                = SNDRV_PCM_FMTBIT_S16_LE |
-                                   SNDRV_PCM_FMTBIT_U16_LE |
-                                   SNDRV_PCM_FMTBIT_U8 |
-                                   SNDRV_PCM_FMTBIT_S8,
-       .channels_min           = 2,
-       .channels_max           = 2,
-       .buffer_bytes_max       = 128*1024,
-       .period_bytes_min       = PAGE_SIZE,
-       .period_bytes_max       = PAGE_SIZE*2,
-       .periods_min            = 2,
-       .periods_max            = 128,
-       .fifo_size              = 32,
-};
-
-struct s3c24xx_runtime_data {
-       spinlock_t lock;
-       int state;
-       unsigned int dma_loaded;
-       unsigned int dma_limit;
-       unsigned int dma_period;
-       dma_addr_t dma_start;
-       dma_addr_t dma_pos;
-       dma_addr_t dma_end;
-       struct s3c_dma_params *params;
-};
-
-/* s3c_dma_enqueue
- *
- * place a dma buffer onto the queue for the dma system
- * to handle.
-*/
-static void s3c_dma_enqueue(struct snd_pcm_substream *substream)
-{
-       struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
-       dma_addr_t pos = prtd->dma_pos;
-       unsigned int limit;
-       int ret;
-
-       pr_debug("Entered %s\n", __func__);
-
-       if (s3c_dma_has_circular())
-               limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
-       else
-               limit = prtd->dma_limit;
-
-       pr_debug("%s: loaded %d, limit %d\n",
-                               __func__, prtd->dma_loaded, limit);
-
-       while (prtd->dma_loaded < limit) {
-               unsigned long len = prtd->dma_period;
-
-               pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
-
-               if ((pos + len) > prtd->dma_end) {
-                       len  = prtd->dma_end - pos;
-                       pr_debug("%s: corrected dma len %ld\n", __func__, len);
-               }
-
-               ret = s3c2410_dma_enqueue(prtd->params->channel,
-                       substream, pos, len);
-
-               if (ret == 0) {
-                       prtd->dma_loaded++;
-                       pos += prtd->dma_period;
-                       if (pos >= prtd->dma_end)
-                               pos = prtd->dma_start;
-               } else
-                       break;
-       }
-
-       prtd->dma_pos = pos;
-}
-
-static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel,
-                               void *dev_id, int size,
-                               enum s3c2410_dma_buffresult result)
-{
-       struct snd_pcm_substream *substream = dev_id;
-       struct s3c24xx_runtime_data *prtd;
-
-       pr_debug("Entered %s\n", __func__);
-
-       if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR)
-               return;
-
-       prtd = substream->runtime->private_data;
-
-       if (substream)
-               snd_pcm_period_elapsed(substream);
-
-       spin_lock(&prtd->lock);
-       if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) {
-               prtd->dma_loaded--;
-               s3c_dma_enqueue(substream);
-       }
-
-       spin_unlock(&prtd->lock);
-}
-
-static int s3c_dma_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct s3c24xx_runtime_data *prtd = runtime->private_data;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       unsigned long totbytes = params_buffer_bytes(params);
-       struct s3c_dma_params *dma =
-               snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-       int ret = 0;
-
-
-       pr_debug("Entered %s\n", __func__);
-
-       /* return if this is a bufferless transfer e.g.
-        * codec <--> BT codec or GSM modem -- lg FIXME */
-       if (!dma)
-               return 0;
-
-       /* this may get called several times by oss emulation
-        * with different params -HW */
-       if (prtd->params == NULL) {
-               /* prepare DMA */
-               prtd->params = dma;
-
-               pr_debug("params %p, client %p, channel %d\n", prtd->params,
-                       prtd->params->client, prtd->params->channel);
-
-               ret = s3c2410_dma_request(prtd->params->channel,
-                                         prtd->params->client, NULL);
-
-               if (ret < 0) {
-                       printk(KERN_ERR "failed to get dma channel\n");
-                       return ret;
-               }
-
-               /* use the circular buffering if we have it available. */
-               if (s3c_dma_has_circular())
-                       s3c2410_dma_setflags(prtd->params->channel,
-                                            S3C2410_DMAF_CIRCULAR);
-       }
-
-       s3c2410_dma_set_buffdone_fn(prtd->params->channel,
-                                   s3c24xx_audio_buffdone);
-
-       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-
-       runtime->dma_bytes = totbytes;
-
-       spin_lock_irq(&prtd->lock);
-       prtd->dma_loaded = 0;
-       prtd->dma_limit = runtime->hw.periods_min;
-       prtd->dma_period = params_period_bytes(params);
-       prtd->dma_start = runtime->dma_addr;
-       prtd->dma_pos = prtd->dma_start;
-       prtd->dma_end = prtd->dma_start + totbytes;
-       spin_unlock_irq(&prtd->lock);
-
-       return 0;
-}
-
-static int s3c_dma_hw_free(struct snd_pcm_substream *substream)
-{
-       struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
-
-       pr_debug("Entered %s\n", __func__);
-
-       /* TODO - do we need to ensure DMA flushed */
-       snd_pcm_set_runtime_buffer(substream, NULL);
-
-       if (prtd->params) {
-               s3c2410_dma_free(prtd->params->channel, prtd->params->client);
-               prtd->params = NULL;
-       }
-
-       return 0;
-}
-
-static int s3c_dma_prepare(struct snd_pcm_substream *substream)
-{
-       struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
-       int ret = 0;
-
-       pr_debug("Entered %s\n", __func__);
-
-       /* return if this is a bufferless transfer e.g.
-        * codec <--> BT codec or GSM modem -- lg FIXME */
-       if (!prtd->params)
-               return 0;
-
-       /* channel needs configuring for mem=>device, increment memory addr,
-        * sync to pclk, half-word transfers to the IIS-FIFO. */
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               s3c2410_dma_devconfig(prtd->params->channel,
-                                     S3C2410_DMASRC_MEM,
-                                     prtd->params->dma_addr);
-       } else {
-               s3c2410_dma_devconfig(prtd->params->channel,
-                                     S3C2410_DMASRC_HW,
-                                     prtd->params->dma_addr);
-       }
-
-       s3c2410_dma_config(prtd->params->channel,
-                          prtd->params->dma_size);
-
-       /* flush the DMA channel */
-       s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH);
-       prtd->dma_loaded = 0;
-       prtd->dma_pos = prtd->dma_start;
-
-       /* enqueue dma buffers */
-       s3c_dma_enqueue(substream);
-
-       return ret;
-}
-
-static int s3c_dma_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
-       int ret = 0;
-
-       pr_debug("Entered %s\n", __func__);
-
-       spin_lock(&prtd->lock);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               prtd->state |= ST_RUNNING;
-               s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START);
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               prtd->state &= ~ST_RUNNING;
-               s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STOP);
-               break;
-
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-       spin_unlock(&prtd->lock);
-
-       return ret;
-}
-
-static snd_pcm_uframes_t
-s3c_dma_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct s3c24xx_runtime_data *prtd = runtime->private_data;
-       unsigned long res;
-       dma_addr_t src, dst;
-
-       pr_debug("Entered %s\n", __func__);
-
-       spin_lock(&prtd->lock);
-       s3c2410_dma_getposition(prtd->params->channel, &src, &dst);
-
-       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-               res = dst - prtd->dma_start;
-       else
-               res = src - prtd->dma_start;
-
-       spin_unlock(&prtd->lock);
-
-       pr_debug("Pointer %x %x\n", src, dst);
-
-       /* we seem to be getting the odd error from the pcm library due
-        * to out-of-bounds pointers. this is maybe due to the dma engine
-        * not having loaded the new values for the channel before being
-        * callled... (todo - fix )
-        */
-
-       if (res >= snd_pcm_lib_buffer_bytes(substream)) {
-               if (res == snd_pcm_lib_buffer_bytes(substream))
-                       res = 0;
-       }
-
-       return bytes_to_frames(substream->runtime, res);
-}
-
-static int s3c_dma_open(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct s3c24xx_runtime_data *prtd;
-
-       pr_debug("Entered %s\n", __func__);
-
-       snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
-       snd_soc_set_runtime_hwparams(substream, &s3c_dma_hardware);
-
-       prtd = kzalloc(sizeof(struct s3c24xx_runtime_data), GFP_KERNEL);
-       if (prtd == NULL)
-               return -ENOMEM;
-
-       spin_lock_init(&prtd->lock);
-
-       runtime->private_data = prtd;
-       return 0;
-}
-
-static int s3c_dma_close(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct s3c24xx_runtime_data *prtd = runtime->private_data;
-
-       pr_debug("Entered %s\n", __func__);
-
-       if (!prtd)
-               pr_debug("s3c_dma_close called with prtd == NULL\n");
-
-       kfree(prtd);
-
-       return 0;
-}
-
-static int s3c_dma_mmap(struct snd_pcm_substream *substream,
-       struct vm_area_struct *vma)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-
-       pr_debug("Entered %s\n", __func__);
-
-       return dma_mmap_writecombine(substream->pcm->card->dev, vma,
-                                    runtime->dma_area,
-                                    runtime->dma_addr,
-                                    runtime->dma_bytes);
-}
-
-static struct snd_pcm_ops s3c_dma_ops = {
-       .open           = s3c_dma_open,
-       .close          = s3c_dma_close,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = s3c_dma_hw_params,
-       .hw_free        = s3c_dma_hw_free,
-       .prepare        = s3c_dma_prepare,
-       .trigger        = s3c_dma_trigger,
-       .pointer        = s3c_dma_pointer,
-       .mmap           = s3c_dma_mmap,
-};
-
-static int s3c_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 = s3c_dma_hardware.buffer_bytes_max;
-
-       pr_debug("Entered %s\n", __func__);
-
-       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 void s3c_dma_free_dma_buffers(struct snd_pcm *pcm)
-{
-       struct snd_pcm_substream *substream;
-       struct snd_dma_buffer *buf;
-       int stream;
-
-       pr_debug("Entered %s\n", __func__);
-
-       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 s3c_dma_mask = DMA_BIT_MASK(32);
-
-static int s3c_dma_new(struct snd_card *card,
-       struct snd_soc_dai *dai, struct snd_pcm *pcm)
-{
-       int ret = 0;
-
-       pr_debug("Entered %s\n", __func__);
-
-       if (!card->dev->dma_mask)
-               card->dev->dma_mask = &s3c_dma_mask;
-       if (!card->dev->coherent_dma_mask)
-               card->dev->coherent_dma_mask = 0xffffffff;
-
-       if (dai->driver->playback.channels_min) {
-               ret = s3c_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_PLAYBACK);
-               if (ret)
-                       goto out;
-       }
-
-       if (dai->driver->capture.channels_min) {
-               ret = s3c_preallocate_dma_buffer(pcm,
-                       SNDRV_PCM_STREAM_CAPTURE);
-               if (ret)
-                       goto out;
-       }
- out:
-       return ret;
-}
-
-static struct snd_soc_platform_driver s3c24xx_soc_platform = {
-       .ops            = &s3c_dma_ops,
-       .pcm_new        = s3c_dma_new,
-       .pcm_free       = s3c_dma_free_dma_buffers,
-};
-
-static int __devinit s3c24xx_soc_platform_probe(struct platform_device *pdev)
-{
-       return snd_soc_register_platform(&pdev->dev, &s3c24xx_soc_platform);
-}
-
-static int __devexit s3c24xx_soc_platform_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_platform(&pdev->dev);
-       return 0;
-}
-
-static struct platform_driver s3c24xx_pcm_driver = {
-       .driver = {
-               .name = "s3c24xx-pcm-audio",
-               .owner = THIS_MODULE,
-       },
-
-       .probe = s3c24xx_soc_platform_probe,
-       .remove = __devexit_p(s3c24xx_soc_platform_remove),
-};
-
-static int __init snd_s3c24xx_pcm_init(void)
-{
-       return platform_driver_register(&s3c24xx_pcm_driver);
-}
-module_init(snd_s3c24xx_pcm_init);
-
-static void __exit snd_s3c24xx_pcm_exit(void)
-{
-       platform_driver_unregister(&s3c24xx_pcm_driver);
-}
-module_exit(snd_s3c24xx_pcm_exit);
-
-MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
-MODULE_DESCRIPTION("Samsung S3C Audio DMA module");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s3c24xx-pcm-audio");
diff --git a/sound/soc/s3c24xx/s3c-dma.h b/sound/soc/s3c24xx/s3c-dma.h
deleted file mode 100644 (file)
index 748c07d..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- *  s3c-dma.h --
- *
- *  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.
- *
- *  ALSA PCM interface for the Samsung S3C24xx CPU
- */
-
-#ifndef _S3C_AUDIO_H
-#define _S3C_AUDIO_H
-
-#define ST_RUNNING             (1<<0)
-#define ST_OPENED              (1<<1)
-
-struct s3c_dma_params {
-       struct s3c2410_dma_client *client;      /* stream identifier */
-       int channel;                            /* Channel ID */
-       dma_addr_t dma_addr;
-       int dma_size;                   /* Size of the DMA transfer */
-};
-
-#define S3C24XX_DAI_I2S                        0
-
-/* platform data */
-extern struct snd_ac97_bus_ops s3c24xx_ac97_ops;
-
-#endif
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c
deleted file mode 100644 (file)
index b3866d5..0000000
+++ /dev/null
@@ -1,757 +0,0 @@
-/* sound/soc/s3c24xx/s3c-i2c-v2.c
- *
- * ALSA Soc Audio Layer - I2S core for newer Samsung SoCs.
- *
- * Copyright (c) 2006 Wolfson Microelectronics PLC.
- *     Graeme Gregory graeme.gregory@wolfsonmicro.com
- *     linux@wolfsonmicro.com
- *
- * Copyright (c) 2008, 2007, 2004-2005 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * 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/delay.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <mach/dma.h>
-
-#include "regs-i2s-v2.h"
-#include "s3c-i2s-v2.h"
-#include "s3c-dma.h"
-
-#undef S3C_IIS_V2_SUPPORTED
-
-#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) \
-       || defined(CONFIG_CPU_S5PV210)
-#define S3C_IIS_V2_SUPPORTED
-#endif
-
-#ifdef CONFIG_PLAT_S3C64XX
-#define S3C_IIS_V2_SUPPORTED
-#endif
-
-#ifndef S3C_IIS_V2_SUPPORTED
-#error Unsupported CPU model
-#endif
-
-#define S3C2412_I2S_DEBUG_CON 0
-
-static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
-{
-       return snd_soc_dai_get_drvdata(cpu_dai);
-}
-
-#define bit_set(v, b) (((v) & (b)) ? 1 : 0)
-
-#if S3C2412_I2S_DEBUG_CON
-static void dbg_showcon(const char *fn, u32 con)
-{
-       printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn,
-              bit_set(con, S3C2412_IISCON_LRINDEX),
-              bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY),
-              bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY),
-              bit_set(con, S3C2412_IISCON_TXFIFO_FULL),
-              bit_set(con, S3C2412_IISCON_RXFIFO_FULL));
-
-       printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n",
-              fn,
-              bit_set(con, S3C2412_IISCON_TXDMA_PAUSE),
-              bit_set(con, S3C2412_IISCON_RXDMA_PAUSE),
-              bit_set(con, S3C2412_IISCON_TXCH_PAUSE),
-              bit_set(con, S3C2412_IISCON_RXCH_PAUSE));
-       printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn,
-              bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE),
-              bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE),
-              bit_set(con, S3C2412_IISCON_IIS_ACTIVE));
-}
-#else
-static inline void dbg_showcon(const char *fn, u32 con)
-{
-}
-#endif
-
-
-/* Turn on or off the transmission path. */
-static void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on)
-{
-       void __iomem *regs = i2s->regs;
-       u32 fic, con, mod;
-
-       pr_debug("%s(%d)\n", __func__, on);
-
-       fic = readl(regs + S3C2412_IISFIC);
-       con = readl(regs + S3C2412_IISCON);
-       mod = readl(regs + S3C2412_IISMOD);
-
-       pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
-
-       if (on) {
-               con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
-               con &= ~S3C2412_IISCON_TXDMA_PAUSE;
-               con &= ~S3C2412_IISCON_TXCH_PAUSE;
-
-               switch (mod & S3C2412_IISMOD_MODE_MASK) {
-               case S3C2412_IISMOD_MODE_TXONLY:
-               case S3C2412_IISMOD_MODE_TXRX:
-                       /* do nothing, we are in the right mode */
-                       break;
-
-               case S3C2412_IISMOD_MODE_RXONLY:
-                       mod &= ~S3C2412_IISMOD_MODE_MASK;
-                       mod |= S3C2412_IISMOD_MODE_TXRX;
-                       break;
-
-               default:
-                       dev_err(i2s->dev, "TXEN: Invalid MODE %x in IISMOD\n",
-                               mod & S3C2412_IISMOD_MODE_MASK);
-                       break;
-               }
-
-               writel(con, regs + S3C2412_IISCON);
-               writel(mod, regs + S3C2412_IISMOD);
-       } else {
-               /* Note, we do not have any indication that the FIFO problems
-                * tha the S3C2410/2440 had apply here, so we should be able
-                * to disable the DMA and TX without resetting the FIFOS.
-                */
-
-               con |=  S3C2412_IISCON_TXDMA_PAUSE;
-               con |=  S3C2412_IISCON_TXCH_PAUSE;
-               con &= ~S3C2412_IISCON_TXDMA_ACTIVE;
-
-               switch (mod & S3C2412_IISMOD_MODE_MASK) {
-               case S3C2412_IISMOD_MODE_TXRX:
-                       mod &= ~S3C2412_IISMOD_MODE_MASK;
-                       mod |= S3C2412_IISMOD_MODE_RXONLY;
-                       break;
-
-               case S3C2412_IISMOD_MODE_TXONLY:
-                       mod &= ~S3C2412_IISMOD_MODE_MASK;
-                       con &= ~S3C2412_IISCON_IIS_ACTIVE;
-                       break;
-
-               default:
-                       dev_err(i2s->dev, "TXDIS: Invalid MODE %x in IISMOD\n",
-                               mod & S3C2412_IISMOD_MODE_MASK);
-                       break;
-               }
-
-               writel(mod, regs + S3C2412_IISMOD);
-               writel(con, regs + S3C2412_IISCON);
-       }
-
-       fic = readl(regs + S3C2412_IISFIC);
-       dbg_showcon(__func__, con);
-       pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
-}
-
-static void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on)
-{
-       void __iomem *regs = i2s->regs;
-       u32 fic, con, mod;
-
-       pr_debug("%s(%d)\n", __func__, on);
-
-       fic = readl(regs + S3C2412_IISFIC);
-       con = readl(regs + S3C2412_IISCON);
-       mod = readl(regs + S3C2412_IISMOD);
-
-       pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
-
-       if (on) {
-               con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
-               con &= ~S3C2412_IISCON_RXDMA_PAUSE;
-               con &= ~S3C2412_IISCON_RXCH_PAUSE;
-
-               switch (mod & S3C2412_IISMOD_MODE_MASK) {
-               case S3C2412_IISMOD_MODE_TXRX:
-               case S3C2412_IISMOD_MODE_RXONLY:
-                       /* do nothing, we are in the right mode */
-                       break;
-
-               case S3C2412_IISMOD_MODE_TXONLY:
-                       mod &= ~S3C2412_IISMOD_MODE_MASK;
-                       mod |= S3C2412_IISMOD_MODE_TXRX;
-                       break;
-
-               default:
-                       dev_err(i2s->dev, "RXEN: Invalid MODE %x in IISMOD\n",
-                               mod & S3C2412_IISMOD_MODE_MASK);
-               }
-
-               writel(mod, regs + S3C2412_IISMOD);
-               writel(con, regs + S3C2412_IISCON);
-       } else {
-               /* See txctrl notes on FIFOs. */
-
-               con &= ~S3C2412_IISCON_RXDMA_ACTIVE;
-               con |=  S3C2412_IISCON_RXDMA_PAUSE;
-               con |=  S3C2412_IISCON_RXCH_PAUSE;
-
-               switch (mod & S3C2412_IISMOD_MODE_MASK) {
-               case S3C2412_IISMOD_MODE_RXONLY:
-                       con &= ~S3C2412_IISCON_IIS_ACTIVE;
-                       mod &= ~S3C2412_IISMOD_MODE_MASK;
-                       break;
-
-               case S3C2412_IISMOD_MODE_TXRX:
-                       mod &= ~S3C2412_IISMOD_MODE_MASK;
-                       mod |= S3C2412_IISMOD_MODE_TXONLY;
-                       break;
-
-               default:
-                       dev_err(i2s->dev, "RXDIS: Invalid MODE %x in IISMOD\n",
-                               mod & S3C2412_IISMOD_MODE_MASK);
-               }
-
-               writel(con, regs + S3C2412_IISCON);
-               writel(mod, regs + S3C2412_IISMOD);
-       }
-
-       fic = readl(regs + S3C2412_IISFIC);
-       pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
-}
-
-#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
-
-/*
- * Wait for the LR signal to allow synchronisation to the L/R clock
- * from the codec. May only be needed for slave mode.
- */
-static int s3c2412_snd_lrsync(struct s3c_i2sv2_info *i2s)
-{
-       u32 iiscon;
-       unsigned long loops = msecs_to_loops(5);
-
-       pr_debug("Entered %s\n", __func__);
-
-       while (--loops) {
-               iiscon = readl(i2s->regs + S3C2412_IISCON);
-               if (iiscon & S3C2412_IISCON_LRINDEX)
-                       break;
-
-               cpu_relax();
-       }
-
-       if (!loops) {
-               printk(KERN_ERR "%s: timeout\n", __func__);
-               return -ETIMEDOUT;
-       }
-
-       return 0;
-}
-
-/*
- * Set S3C2412 I2S DAI format
- */
-static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
-                              unsigned int fmt)
-{
-       struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
-       u32 iismod;
-
-       pr_debug("Entered %s\n", __func__);
-
-       iismod = readl(i2s->regs + S3C2412_IISMOD);
-       pr_debug("hw_params r: IISMOD: %x \n", iismod);
-
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
-               i2s->master = 0;
-               iismod |= S3C2412_IISMOD_SLAVE;
-               break;
-       case SND_SOC_DAIFMT_CBS_CFS:
-               i2s->master = 1;
-               iismod &= ~S3C2412_IISMOD_SLAVE;
-               break;
-       default:
-               pr_err("unknwon master/slave format\n");
-               return -EINVAL;
-       }
-
-       iismod &= ~S3C2412_IISMOD_SDF_MASK;
-
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_RIGHT_J:
-               iismod |= S3C2412_IISMOD_LR_RLOW;
-               iismod |= S3C2412_IISMOD_SDF_MSB;
-               break;
-       case SND_SOC_DAIFMT_LEFT_J:
-               iismod |= S3C2412_IISMOD_LR_RLOW;
-               iismod |= S3C2412_IISMOD_SDF_LSB;
-               break;
-       case SND_SOC_DAIFMT_I2S:
-               iismod &= ~S3C2412_IISMOD_LR_RLOW;
-               iismod |= S3C2412_IISMOD_SDF_IIS;
-               break;
-       default:
-               pr_err("Unknown data format\n");
-               return -EINVAL;
-       }
-
-       writel(iismod, i2s->regs + S3C2412_IISMOD);
-       pr_debug("hw_params w: IISMOD: %x \n", iismod);
-       return 0;
-}
-
-static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
-                                struct snd_pcm_hw_params *params,
-                                struct snd_soc_dai *dai)
-{
-       struct s3c_i2sv2_info *i2s = to_info(dai);
-       struct s3c_dma_params *dma_data;
-       u32 iismod;
-
-       pr_debug("Entered %s\n", __func__);
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               dma_data = i2s->dma_playback;
-       else
-               dma_data = i2s->dma_capture;
-
-       snd_soc_dai_set_dma_data(dai, substream, dma_data);
-
-       /* Working copies of register */
-       iismod = readl(i2s->regs + S3C2412_IISMOD);
-       pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
-
-       iismod &= ~S3C64XX_IISMOD_BLC_MASK;
-       /* Sample size */
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S8:
-               iismod |= S3C64XX_IISMOD_BLC_8BIT;
-               break;
-       case SNDRV_PCM_FORMAT_S16_LE:
-               break;
-       case SNDRV_PCM_FORMAT_S24_LE:
-               iismod |= S3C64XX_IISMOD_BLC_24BIT;
-               break;
-       }
-
-       writel(iismod, i2s->regs + S3C2412_IISMOD);
-       pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
-
-       return 0;
-}
-
-static int s3c_i2sv2_set_sysclk(struct snd_soc_dai *cpu_dai,
-                                 int clk_id, unsigned int freq, int dir)
-{
-       struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
-       u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
-
-       pr_debug("Entered %s\n", __func__);
-       pr_debug("%s r: IISMOD: %x\n", __func__, iismod);
-
-       switch (clk_id) {
-       case S3C_I2SV2_CLKSRC_PCLK:
-               iismod &= ~S3C2412_IISMOD_IMS_SYSMUX;
-               break;
-
-       case S3C_I2SV2_CLKSRC_AUDIOBUS:
-               iismod |= S3C2412_IISMOD_IMS_SYSMUX;
-               break;
-
-       case S3C_I2SV2_CLKSRC_CDCLK:
-               /* Error if controller doesn't have the CDCLKCON bit */
-               if (!(i2s->feature & S3C_FEATURE_CDCLKCON))
-                       return -EINVAL;
-
-               switch (dir) {
-               case SND_SOC_CLOCK_IN:
-                       iismod |= S3C64XX_IISMOD_CDCLKCON;
-                       break;
-               case SND_SOC_CLOCK_OUT:
-                       iismod &= ~S3C64XX_IISMOD_CDCLKCON;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       writel(iismod, i2s->regs + S3C2412_IISMOD);
-       pr_debug("%s w: IISMOD: %x\n", __func__, iismod);
-
-       return 0;
-}
-
-static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
-                              struct snd_soc_dai *dai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct s3c_i2sv2_info *i2s = to_info(rtd->cpu_dai);
-       int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
-       unsigned long irqs;
-       int ret = 0;
-       struct s3c_dma_params *dma_data =
-               snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-       pr_debug("Entered %s\n", __func__);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-               /* On start, ensure that the FIFOs are cleared and reset. */
-
-               writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH,
-                      i2s->regs + S3C2412_IISFIC);
-
-               /* clear again, just in case */
-               writel(0x0, i2s->regs + S3C2412_IISFIC);
-
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               if (!i2s->master) {
-                       ret = s3c2412_snd_lrsync(i2s);
-                       if (ret)
-                               goto exit_err;
-               }
-
-               local_irq_save(irqs);
-
-               if (capture)
-                       s3c2412_snd_rxctrl(i2s, 1);
-               else
-                       s3c2412_snd_txctrl(i2s, 1);
-
-               local_irq_restore(irqs);
-
-               /*
-                * Load the next buffer to DMA to meet the reqirement
-                * of the auto reload mechanism of S3C24XX.
-                * This call won't bother S3C64XX.
-                */
-               s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
-
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               local_irq_save(irqs);
-
-               if (capture)
-                       s3c2412_snd_rxctrl(i2s, 0);
-               else
-                       s3c2412_snd_txctrl(i2s, 0);
-
-               local_irq_restore(irqs);
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-exit_err:
-       return ret;
-}
-
-/*
- * Set S3C2412 Clock dividers
- */
-static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
-                                 int div_id, int div)
-{
-       struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
-       u32 reg;
-
-       pr_debug("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
-
-       switch (div_id) {
-       case S3C_I2SV2_DIV_BCLK:
-               switch (div) {
-               case 16:
-                       div = S3C2412_IISMOD_BCLK_16FS;
-                       break;
-
-               case 32:
-                       div = S3C2412_IISMOD_BCLK_32FS;
-                       break;
-
-               case 24:
-                       div = S3C2412_IISMOD_BCLK_24FS;
-                       break;
-
-               case 48:
-                       div = S3C2412_IISMOD_BCLK_48FS;
-                       break;
-
-               default:
-                       return -EINVAL;
-               }
-
-               reg = readl(i2s->regs + S3C2412_IISMOD);
-               reg &= ~S3C2412_IISMOD_BCLK_MASK;
-               writel(reg | div, i2s->regs + S3C2412_IISMOD);
-
-               pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
-               break;
-
-       case S3C_I2SV2_DIV_RCLK:
-               switch (div) {
-               case 256:
-                       div = S3C2412_IISMOD_RCLK_256FS;
-                       break;
-
-               case 384:
-                       div = S3C2412_IISMOD_RCLK_384FS;
-                       break;
-
-               case 512:
-                       div = S3C2412_IISMOD_RCLK_512FS;
-                       break;
-
-               case 768:
-                       div = S3C2412_IISMOD_RCLK_768FS;
-                       break;
-
-               default:
-                       return -EINVAL;
-               }
-
-               reg = readl(i2s->regs + S3C2412_IISMOD);
-               reg &= ~S3C2412_IISMOD_RCLK_MASK;
-               writel(reg | div, i2s->regs + S3C2412_IISMOD);
-               pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
-               break;
-
-       case S3C_I2SV2_DIV_PRESCALER:
-               if (div >= 0) {
-                       writel((div << 8) | S3C2412_IISPSR_PSREN,
-                              i2s->regs + S3C2412_IISPSR);
-               } else {
-                       writel(0x0, i2s->regs + S3C2412_IISPSR);
-               }
-               pr_debug("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR));
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static snd_pcm_sframes_t s3c2412_i2s_delay(struct snd_pcm_substream *substream,
-                                          struct snd_soc_dai *dai)
-{
-       struct s3c_i2sv2_info *i2s = to_info(dai);
-       u32 reg = readl(i2s->regs + S3C2412_IISFIC);
-       snd_pcm_sframes_t delay;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               delay = S3C2412_IISFIC_TXCOUNT(reg);
-       else
-               delay = S3C2412_IISFIC_RXCOUNT(reg);
-
-       return delay;
-}
-
-struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai)
-{
-       struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
-       u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
-
-       if (iismod & S3C2412_IISMOD_IMS_SYSMUX)
-               return i2s->iis_cclk;
-       else
-               return i2s->iis_pclk;
-}
-EXPORT_SYMBOL_GPL(s3c_i2sv2_get_clock);
-
-/* default table of all avaialable root fs divisors */
-static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 };
-
-int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
-                           unsigned int *fstab,
-                           unsigned int rate, struct clk *clk)
-{
-       unsigned long clkrate = clk_get_rate(clk);
-       unsigned int div;
-       unsigned int fsclk;
-       unsigned int actual;
-       unsigned int fs;
-       unsigned int fsdiv;
-       signed int deviation = 0;
-       unsigned int best_fs = 0;
-       unsigned int best_div = 0;
-       unsigned int best_rate = 0;
-       unsigned int best_deviation = INT_MAX;
-
-       pr_debug("Input clock rate %ldHz\n", clkrate);
-
-       if (fstab == NULL)
-               fstab = iis_fs_tab;
-
-       for (fs = 0; fs < ARRAY_SIZE(iis_fs_tab); fs++) {
-               fsdiv = iis_fs_tab[fs];
-
-               fsclk = clkrate / fsdiv;
-               div = fsclk / rate;
-
-               if ((fsclk % rate) > (rate / 2))
-                       div++;
-
-               if (div <= 1)
-                       continue;
-
-               actual = clkrate / (fsdiv * div);
-               deviation = actual - rate;
-
-               printk(KERN_DEBUG "%ufs: div %u => result %u, deviation %d\n",
-                      fsdiv, div, actual, deviation);
-
-               deviation = abs(deviation);
-
-               if (deviation < best_deviation) {
-                       best_fs = fsdiv;
-                       best_div = div;
-                       best_rate = actual;
-                       best_deviation = deviation;
-               }
-
-               if (deviation == 0)
-                       break;
-       }
-
-       printk(KERN_DEBUG "best: fs=%u, div=%u, rate=%u\n",
-              best_fs, best_div, best_rate);
-
-       info->fs_div = best_fs;
-       info->clk_div = best_div;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(s3c_i2sv2_iis_calc_rate);
-
-int s3c_i2sv2_probe(struct snd_soc_dai *dai,
-                   struct s3c_i2sv2_info *i2s,
-                   unsigned long base)
-{
-       struct device *dev = dai->dev;
-       unsigned int iismod;
-
-       i2s->dev = dev;
-
-       /* record our i2s structure for later use in the callbacks */
-       snd_soc_dai_set_drvdata(dai, i2s);
-
-       i2s->regs = ioremap(base, 0x100);
-       if (i2s->regs == NULL) {
-               dev_err(dev, "cannot ioremap registers\n");
-               return -ENXIO;
-       }
-
-       i2s->iis_pclk = clk_get(dev, "iis");
-       if (IS_ERR(i2s->iis_pclk)) {
-               dev_err(dev, "failed to get iis_clock\n");
-               iounmap(i2s->regs);
-               return -ENOENT;
-       }
-
-       clk_enable(i2s->iis_pclk);
-
-       /* Mark ourselves as in TXRX mode so we can run through our cleanup
-        * process without warnings. */
-       iismod = readl(i2s->regs + S3C2412_IISMOD);
-       iismod |= S3C2412_IISMOD_MODE_TXRX;
-       writel(iismod, i2s->regs + S3C2412_IISMOD);
-       s3c2412_snd_txctrl(i2s, 0);
-       s3c2412_snd_rxctrl(i2s, 0);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(s3c_i2sv2_probe);
-
-#ifdef CONFIG_PM
-static int s3c2412_i2s_suspend(struct snd_soc_dai *dai)
-{
-       struct s3c_i2sv2_info *i2s = to_info(dai);
-       u32 iismod;
-
-       if (dai->active) {
-               i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD);
-               i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON);
-               i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR);
-
-               /* some basic suspend checks */
-
-               iismod = readl(i2s->regs + S3C2412_IISMOD);
-
-               if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
-                       pr_warning("%s: RXDMA active?\n", __func__);
-
-               if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
-                       pr_warning("%s: TXDMA active?\n", __func__);
-
-               if (iismod & S3C2412_IISCON_IIS_ACTIVE)
-                       pr_warning("%s: IIS active\n", __func__);
-       }
-
-       return 0;
-}
-
-static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
-{
-       struct s3c_i2sv2_info *i2s = to_info(dai);
-
-       pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n",
-               dai->active, i2s->suspend_iismod, i2s->suspend_iiscon);
-
-       if (dai->active) {
-               writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
-               writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD);
-               writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR);
-
-               writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH,
-                      i2s->regs + S3C2412_IISFIC);
-
-               ndelay(250);
-               writel(0x0, i2s->regs + S3C2412_IISFIC);
-       }
-
-       return 0;
-}
-#else
-#define s3c2412_i2s_suspend NULL
-#define s3c2412_i2s_resume  NULL
-#endif
-
-int s3c_i2sv2_register_dai(struct device *dev, int id,
-               struct snd_soc_dai_driver *drv)
-{
-       struct snd_soc_dai_ops *ops = drv->ops;
-
-       ops->trigger = s3c2412_i2s_trigger;
-       if (!ops->hw_params)
-               ops->hw_params = s3c_i2sv2_hw_params;
-       ops->set_fmt = s3c2412_i2s_set_fmt;
-       ops->set_clkdiv = s3c2412_i2s_set_clkdiv;
-       ops->set_sysclk = s3c_i2sv2_set_sysclk;
-
-       /* Allow overriding by (for example) IISv4 */
-       if (!ops->delay)
-               ops->delay = s3c2412_i2s_delay;
-
-       drv->suspend = s3c2412_i2s_suspend;
-       drv->resume = s3c2412_i2s_resume;
-
-       return snd_soc_register_dai(dev, drv);
-}
-EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai);
-
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.h b/sound/soc/s3c24xx/s3c-i2s-v2.h
deleted file mode 100644 (file)
index d458301..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/* sound/soc/s3c24xx/s3c-i2s-v2.h
- *
- * ALSA Soc Audio Layer - S3C_I2SV2 I2S driver
- *
- * Copyright (c) 2007 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- *  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 code is the core support for the I2S block found in a number of
- * Samsung SoC devices which is unofficially named I2S-V2. Currently the
- * S3C2412 and the S3C64XX series use this block to provide 1 or 2 I2S
- * channels via configurable GPIO.
- */
-
-#ifndef __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H
-#define __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H __FILE__
-
-#define S3C_I2SV2_DIV_BCLK     (1)
-#define S3C_I2SV2_DIV_RCLK     (2)
-#define S3C_I2SV2_DIV_PRESCALER        (3)
-
-#define S3C_I2SV2_CLKSRC_PCLK          0
-#define S3C_I2SV2_CLKSRC_AUDIOBUS      1
-#define S3C_I2SV2_CLKSRC_CDCLK         2
-
-/* Set this flag for I2S controllers that have the bit IISMOD[12]
- * bridge/break RCLK signal and external Xi2sCDCLK pin.
- */
-#define S3C_FEATURE_CDCLKCON   (1 << 0)
-
-/**
- * struct s3c_i2sv2_info - S3C I2S-V2 information
- * @dev: The parent device passed to use from the probe.
- * @regs: The pointer to the device registe block.
- * @feature: Set of bit-flags indicating features of the controller.
- * @master: True if the I2S core is the I2S bit clock master.
- * @dma_playback: DMA information for playback channel.
- * @dma_capture: DMA information for capture channel.
- * @suspend_iismod: PM save for the IISMOD register.
- * @suspend_iiscon: PM save for the IISCON register.
- * @suspend_iispsr: PM save for the IISPSR register.
- *
- * This is the private codec state for the hardware associated with an
- * I2S channel such as the register mappings and clock sources.
- */
-struct s3c_i2sv2_info {
-       struct device   *dev;
-       void __iomem    *regs;
-
-       u32             feature;
-
-       struct clk      *iis_pclk;
-       struct clk      *iis_cclk;
-
-       unsigned char    master;
-
-       struct s3c_dma_params   *dma_playback;
-       struct s3c_dma_params   *dma_capture;
-
-       u32              suspend_iismod;
-       u32              suspend_iiscon;
-       u32              suspend_iispsr;
-
-       unsigned long   base;
-};
-
-extern struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai);
-
-struct s3c_i2sv2_rate_calc {
-       unsigned int    clk_div;        /* for prescaler */
-       unsigned int    fs_div;         /* for root frame clock */
-};
-
-extern int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
-                                  unsigned int *fstab,
-                                  unsigned int rate, struct clk *clk);
-
-/**
- * s3c_i2sv2_probe - probe for i2s device helper
- * @dai: The ASoC DAI structure supplied to the original probe.
- * @i2s: Our local i2s structure to fill in.
- * @base: The base address for the registers.
- */
-extern int s3c_i2sv2_probe(struct snd_soc_dai *dai,
-                          struct s3c_i2sv2_info *i2s,
-                          unsigned long base);
-
-/**
- * s3c_i2sv2_register_dai - register dai with soc core
- * @dev: DAI device
- * @id: DAI ID
- * @drv: The driver structure to register
- *
- * Fill in any missing fields and then register the given dai with the
- * soc core.
- */
-extern int s3c_i2sv2_register_dai(struct device *dev, int id,
-               struct snd_soc_dai_driver *drv);
-
-#endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */
diff --git a/sound/soc/s3c24xx/s3c-pcm.c b/sound/soc/s3c24xx/s3c-pcm.c
deleted file mode 100644 (file)
index 2e020e1..0000000
+++ /dev/null
@@ -1,552 +0,0 @@
-/* sound/soc/s3c24xx/s3c-pcm.c
- *
- * ALSA SoC Audio Layer - S3C PCM-Controller driver
- *
- * Copyright (c) 2009 Samsung Electronics Co. Ltd
- * Author: Jaswinder Singh <jassi.brar@samsung.com>
- * based upon I2S drivers by Ben Dooks.
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <linux/io.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-
-#include <plat/audio.h>
-#include <plat/dma.h>
-
-#include "s3c-dma.h"
-#include "s3c-pcm.h"
-
-static struct s3c2410_dma_client s3c_pcm_dma_client_out = {
-       .name           = "PCM Stereo out"
-};
-
-static struct s3c2410_dma_client s3c_pcm_dma_client_in = {
-       .name           = "PCM Stereo in"
-};
-
-static struct s3c_dma_params s3c_pcm_stereo_out[] = {
-       [0] = {
-               .client         = &s3c_pcm_dma_client_out,
-               .dma_size       = 4,
-       },
-       [1] = {
-               .client         = &s3c_pcm_dma_client_out,
-               .dma_size       = 4,
-       },
-};
-
-static struct s3c_dma_params s3c_pcm_stereo_in[] = {
-       [0] = {
-               .client         = &s3c_pcm_dma_client_in,
-               .dma_size       = 4,
-       },
-       [1] = {
-               .client         = &s3c_pcm_dma_client_in,
-               .dma_size       = 4,
-       },
-};
-
-static struct s3c_pcm_info s3c_pcm[2];
-
-static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on)
-{
-       void __iomem *regs = pcm->regs;
-       u32 ctl, clkctl;
-
-       clkctl = readl(regs + S3C_PCM_CLKCTL);
-       ctl = readl(regs + S3C_PCM_CTL);
-       ctl &= ~(S3C_PCM_CTL_TXDIPSTICK_MASK
-                        << S3C_PCM_CTL_TXDIPSTICK_SHIFT);
-
-       if (on) {
-               ctl |= S3C_PCM_CTL_TXDMA_EN;
-               ctl |= S3C_PCM_CTL_TXFIFO_EN;
-               ctl |= S3C_PCM_CTL_ENABLE;
-               ctl |= (0x4<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
-               clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
-       } else {
-               ctl &= ~S3C_PCM_CTL_TXDMA_EN;
-               ctl &= ~S3C_PCM_CTL_TXFIFO_EN;
-
-               if (!(ctl & S3C_PCM_CTL_RXFIFO_EN)) {
-                       ctl &= ~S3C_PCM_CTL_ENABLE;
-                       if (!pcm->idleclk)
-                               clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
-               }
-       }
-
-       writel(clkctl, regs + S3C_PCM_CLKCTL);
-       writel(ctl, regs + S3C_PCM_CTL);
-}
-
-static void s3c_pcm_snd_rxctrl(struct s3c_pcm_info *pcm, int on)
-{
-       void __iomem *regs = pcm->regs;
-       u32 ctl, clkctl;
-
-       ctl = readl(regs + S3C_PCM_CTL);
-       clkctl = readl(regs + S3C_PCM_CLKCTL);
-       ctl &= ~(S3C_PCM_CTL_RXDIPSTICK_MASK
-                        << S3C_PCM_CTL_RXDIPSTICK_SHIFT);
-
-       if (on) {
-               ctl |= S3C_PCM_CTL_RXDMA_EN;
-               ctl |= S3C_PCM_CTL_RXFIFO_EN;
-               ctl |= S3C_PCM_CTL_ENABLE;
-               ctl |= (0x20<<S3C_PCM_CTL_RXDIPSTICK_SHIFT);
-               clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
-       } else {
-               ctl &= ~S3C_PCM_CTL_RXDMA_EN;
-               ctl &= ~S3C_PCM_CTL_RXFIFO_EN;
-
-               if (!(ctl & S3C_PCM_CTL_TXFIFO_EN)) {
-                       ctl &= ~S3C_PCM_CTL_ENABLE;
-                       if (!pcm->idleclk)
-                               clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
-               }
-       }
-
-       writel(clkctl, regs + S3C_PCM_CLKCTL);
-       writel(ctl, regs + S3C_PCM_CTL);
-}
-
-static int s3c_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
-                              struct snd_soc_dai *dai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
-       unsigned long flags;
-
-       dev_dbg(pcm->dev, "Entered %s\n", __func__);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               spin_lock_irqsave(&pcm->lock, flags);
-
-               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-                       s3c_pcm_snd_rxctrl(pcm, 1);
-               else
-                       s3c_pcm_snd_txctrl(pcm, 1);
-
-               spin_unlock_irqrestore(&pcm->lock, flags);
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               spin_lock_irqsave(&pcm->lock, flags);
-
-               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-                       s3c_pcm_snd_rxctrl(pcm, 0);
-               else
-                       s3c_pcm_snd_txctrl(pcm, 0);
-
-               spin_unlock_irqrestore(&pcm->lock, flags);
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
-                                struct snd_pcm_hw_params *params,
-                                struct snd_soc_dai *socdai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
-       struct s3c_dma_params *dma_data;
-       void __iomem *regs = pcm->regs;
-       struct clk *clk;
-       int sclk_div, sync_div;
-       unsigned long flags;
-       u32 clkctl;
-
-       dev_dbg(pcm->dev, "Entered %s\n", __func__);
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               dma_data = pcm->dma_playback;
-       else
-               dma_data = pcm->dma_capture;
-
-       snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
-
-       /* Strictly check for sample size */
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       spin_lock_irqsave(&pcm->lock, flags);
-
-       /* Get hold of the PCMSOURCE_CLK */
-       clkctl = readl(regs + S3C_PCM_CLKCTL);
-       if (clkctl & S3C_PCM_CLKCTL_SERCLKSEL_PCLK)
-               clk = pcm->pclk;
-       else
-               clk = pcm->cclk;
-
-       /* Set the SCLK divider */
-       sclk_div = clk_get_rate(clk) / pcm->sclk_per_fs /
-                                       params_rate(params) / 2 - 1;
-
-       clkctl &= ~(S3C_PCM_CLKCTL_SCLKDIV_MASK
-                       << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
-       clkctl |= ((sclk_div & S3C_PCM_CLKCTL_SCLKDIV_MASK)
-                       << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
-
-       /* Set the SYNC divider */
-       sync_div = pcm->sclk_per_fs - 1;
-
-       clkctl &= ~(S3C_PCM_CLKCTL_SYNCDIV_MASK
-                               << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
-       clkctl |= ((sync_div & S3C_PCM_CLKCTL_SYNCDIV_MASK)
-                               << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
-
-       writel(clkctl, regs + S3C_PCM_CLKCTL);
-
-       spin_unlock_irqrestore(&pcm->lock, flags);
-
-       dev_dbg(pcm->dev, "PCMSOURCE_CLK-%lu SCLK=%ufs SCLK_DIV=%d SYNC_DIV=%d\n",
-                               clk_get_rate(clk), pcm->sclk_per_fs,
-                               sclk_div, sync_div);
-
-       return 0;
-}
-
-static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai,
-                              unsigned int fmt)
-{
-       struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
-       void __iomem *regs = pcm->regs;
-       unsigned long flags;
-       int ret = 0;
-       u32 ctl;
-
-       dev_dbg(pcm->dev, "Entered %s\n", __func__);
-
-       spin_lock_irqsave(&pcm->lock, flags);
-
-       ctl = readl(regs + S3C_PCM_CTL);
-
-       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-       case SND_SOC_DAIFMT_NB_NF:
-               /* Nothing to do, NB_NF by default */
-               break;
-       default:
-               dev_err(pcm->dev, "Unsupported clock inversion!\n");
-               ret = -EINVAL;
-               goto exit;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBS_CFS:
-               /* Nothing to do, Master by default */
-               break;
-       default:
-               dev_err(pcm->dev, "Unsupported master/slave format!\n");
-               ret = -EINVAL;
-               goto exit;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
-       case SND_SOC_DAIFMT_CONT:
-               pcm->idleclk = 1;
-               break;
-       case SND_SOC_DAIFMT_GATED:
-               pcm->idleclk = 0;
-               break;
-       default:
-               dev_err(pcm->dev, "Invalid Clock gating request!\n");
-               ret = -EINVAL;
-               goto exit;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_DSP_A:
-               ctl |= S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
-               ctl |= S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
-               break;
-       case SND_SOC_DAIFMT_DSP_B:
-               ctl &= ~S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
-               ctl &= ~S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
-               break;
-       default:
-               dev_err(pcm->dev, "Unsupported data format!\n");
-               ret = -EINVAL;
-               goto exit;
-       }
-
-       writel(ctl, regs + S3C_PCM_CTL);
-
-exit:
-       spin_unlock_irqrestore(&pcm->lock, flags);
-
-       return ret;
-}
-
-static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai,
-                                               int div_id, int div)
-{
-       struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
-
-       switch (div_id) {
-       case S3C_PCM_SCLK_PER_FS:
-               pcm->sclk_per_fs = div;
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai,
-                                 int clk_id, unsigned int freq, int dir)
-{
-       struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
-       void __iomem *regs = pcm->regs;
-       u32 clkctl = readl(regs + S3C_PCM_CLKCTL);
-
-       switch (clk_id) {
-       case S3C_PCM_CLKSRC_PCLK:
-               clkctl |= S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
-               break;
-
-       case S3C_PCM_CLKSRC_MUX:
-               clkctl &= ~S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
-
-               if (clk_get_rate(pcm->cclk) != freq)
-                       clk_set_rate(pcm->cclk, freq);
-
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       writel(clkctl, regs + S3C_PCM_CLKCTL);
-
-       return 0;
-}
-
-static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
-       .set_sysclk     = s3c_pcm_set_sysclk,
-       .set_clkdiv     = s3c_pcm_set_clkdiv,
-       .trigger        = s3c_pcm_trigger,
-       .hw_params      = s3c_pcm_hw_params,
-       .set_fmt        = s3c_pcm_set_fmt,
-};
-
-#define S3C_PCM_RATES  SNDRV_PCM_RATE_8000_96000
-
-#define S3C_PCM_DAI_DECLARE                    \
-       .symmetric_rates = 1,                                   \
-       .ops = &s3c_pcm_dai_ops,                                \
-       .playback = {                                           \
-               .channels_min   = 2,                            \
-               .channels_max   = 2,                            \
-               .rates          = S3C_PCM_RATES,                \
-               .formats        = SNDRV_PCM_FMTBIT_S16_LE,      \
-       },                                                      \
-       .capture = {                                            \
-               .channels_min   = 2,                            \
-               .channels_max   = 2,                            \
-               .rates          = S3C_PCM_RATES,                \
-               .formats        = SNDRV_PCM_FMTBIT_S16_LE,      \
-       }
-
-struct snd_soc_dai_driver s3c_pcm_dai[] = {
-       [0] = {
-               .name   = "samsung-pcm.0",
-               S3C_PCM_DAI_DECLARE,
-       },
-       [1] = {
-               .name   = "samsung-pcm.1",
-               S3C_PCM_DAI_DECLARE,
-       },
-};
-EXPORT_SYMBOL_GPL(s3c_pcm_dai);
-
-static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
-{
-       struct s3c_pcm_info *pcm;
-       struct resource *mem_res, *dmatx_res, *dmarx_res;
-       struct s3c_audio_pdata *pcm_pdata;
-       int ret;
-
-       /* Check for valid device index */
-       if ((pdev->id < 0) || pdev->id >= ARRAY_SIZE(s3c_pcm)) {
-               dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
-               return -EINVAL;
-       }
-
-       pcm_pdata = pdev->dev.platform_data;
-
-       /* Check for availability of necessary resource */
-       dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!dmatx_res) {
-               dev_err(&pdev->dev, "Unable to get PCM-TX dma resource\n");
-               return -ENXIO;
-       }
-
-       dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-       if (!dmarx_res) {
-               dev_err(&pdev->dev, "Unable to get PCM-RX dma resource\n");
-               return -ENXIO;
-       }
-
-       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mem_res) {
-               dev_err(&pdev->dev, "Unable to get register resource\n");
-               return -ENXIO;
-       }
-
-       if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) {
-               dev_err(&pdev->dev, "Unable to configure gpio\n");
-               return -EINVAL;
-       }
-
-       pcm = &s3c_pcm[pdev->id];
-       pcm->dev = &pdev->dev;
-
-       spin_lock_init(&pcm->lock);
-
-       /* Default is 128fs */
-       pcm->sclk_per_fs = 128;
-
-       pcm->cclk = clk_get(&pdev->dev, "audio-bus");
-       if (IS_ERR(pcm->cclk)) {
-               dev_err(&pdev->dev, "failed to get audio-bus\n");
-               ret = PTR_ERR(pcm->cclk);
-               goto err1;
-       }
-       clk_enable(pcm->cclk);
-
-       /* record our pcm structure for later use in the callbacks */
-       dev_set_drvdata(&pdev->dev, pcm);
-
-       if (!request_mem_region(mem_res->start,
-                               resource_size(mem_res), "samsung-pcm")) {
-               dev_err(&pdev->dev, "Unable to request register region\n");
-               ret = -EBUSY;
-               goto err2;
-       }
-
-       pcm->regs = ioremap(mem_res->start, 0x100);
-       if (pcm->regs == NULL) {
-               dev_err(&pdev->dev, "cannot ioremap registers\n");
-               ret = -ENXIO;
-               goto err3;
-       }
-
-       pcm->pclk = clk_get(&pdev->dev, "pcm");
-       if (IS_ERR(pcm->pclk)) {
-               dev_err(&pdev->dev, "failed to get pcm_clock\n");
-               ret = -ENOENT;
-               goto err4;
-       }
-       clk_enable(pcm->pclk);
-
-       ret = snd_soc_register_dai(&pdev->dev, &s3c_pcm_dai[pdev->id]);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "failed to get pcm_clock\n");
-               goto err5;
-       }
-
-       s3c_pcm_stereo_in[pdev->id].dma_addr = mem_res->start
-                                                       + S3C_PCM_RXFIFO;
-       s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start
-                                                       + S3C_PCM_TXFIFO;
-
-       s3c_pcm_stereo_in[pdev->id].channel = dmarx_res->start;
-       s3c_pcm_stereo_out[pdev->id].channel = dmatx_res->start;
-
-       pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id];
-       pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id];
-
-       return 0;
-
-err5:
-       clk_disable(pcm->pclk);
-       clk_put(pcm->pclk);
-err4:
-       iounmap(pcm->regs);
-err3:
-       release_mem_region(mem_res->start, resource_size(mem_res));
-err2:
-       clk_disable(pcm->cclk);
-       clk_put(pcm->cclk);
-err1:
-       return ret;
-}
-
-static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev)
-{
-       struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id];
-       struct resource *mem_res;
-
-       snd_soc_unregister_dai(&pdev->dev);
-
-       iounmap(pcm->regs);
-
-       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(mem_res->start, resource_size(mem_res));
-
-       clk_disable(pcm->cclk);
-       clk_disable(pcm->pclk);
-       clk_put(pcm->pclk);
-       clk_put(pcm->cclk);
-
-       return 0;
-}
-
-static struct platform_driver s3c_pcm_driver = {
-       .probe  = s3c_pcm_dev_probe,
-       .remove = s3c_pcm_dev_remove,
-       .driver = {
-               .name = "samsung-pcm",
-               .owner = THIS_MODULE,
-       },
-};
-
-static int __init s3c_pcm_init(void)
-{
-       return platform_driver_register(&s3c_pcm_driver);
-}
-module_init(s3c_pcm_init);
-
-static void __exit s3c_pcm_exit(void)
-{
-       platform_driver_unregister(&s3c_pcm_driver);
-}
-module_exit(s3c_pcm_exit);
-
-/* Module information */
-MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
-MODULE_DESCRIPTION("S3C PCM Controller Driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:samsung-pcm");
diff --git a/sound/soc/s3c24xx/s3c-pcm.h b/sound/soc/s3c24xx/s3c-pcm.h
deleted file mode 100644 (file)
index f60baa1..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/*  sound/soc/s3c24xx/s3c-pcm.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 __S3C_PCM_H
-#define __S3C_PCM_H __FILE__
-
-/*Register Offsets */
-#define S3C_PCM_CTL    (0x00)
-#define S3C_PCM_CLKCTL (0x04)
-#define S3C_PCM_TXFIFO (0x08)
-#define S3C_PCM_RXFIFO (0x0C)
-#define S3C_PCM_IRQCTL (0x10)
-#define S3C_PCM_IRQSTAT        (0x14)
-#define S3C_PCM_FIFOSTAT       (0x18)
-#define S3C_PCM_CLRINT (0x20)
-
-/* PCM_CTL Bit-Fields */
-#define S3C_PCM_CTL_TXDIPSTICK_MASK            (0x3f)
-#define S3C_PCM_CTL_TXDIPSTICK_SHIFT   (13)
-#define S3C_PCM_CTL_RXDIPSTICK_MASK            (0x3f)
-#define S3C_PCM_CTL_RXDIPSTICK_SHIFT   (7)
-#define S3C_PCM_CTL_TXDMA_EN           (0x1<<6)
-#define S3C_PCM_CTL_RXDMA_EN           (0x1<<5)
-#define S3C_PCM_CTL_TXMSB_AFTER_FSYNC  (0x1<<4)
-#define S3C_PCM_CTL_RXMSB_AFTER_FSYNC  (0x1<<3)
-#define S3C_PCM_CTL_TXFIFO_EN          (0x1<<2)
-#define S3C_PCM_CTL_RXFIFO_EN          (0x1<<1)
-#define S3C_PCM_CTL_ENABLE                     (0x1<<0)
-
-/* PCM_CLKCTL Bit-Fields */
-#define S3C_PCM_CLKCTL_SERCLK_EN               (0x1<<19)
-#define S3C_PCM_CLKCTL_SERCLKSEL_PCLK  (0x1<<18)
-#define S3C_PCM_CLKCTL_SCLKDIV_MASK            (0x1ff)
-#define S3C_PCM_CLKCTL_SYNCDIV_MASK            (0x1ff)
-#define S3C_PCM_CLKCTL_SCLKDIV_SHIFT   (9)
-#define S3C_PCM_CLKCTL_SYNCDIV_SHIFT   (0)
-
-/* PCM_TXFIFO Bit-Fields */
-#define S3C_PCM_TXFIFO_DVALID  (0x1<<16)
-#define S3C_PCM_TXFIFO_DATA_MSK        (0xffff<<0)
-
-/* PCM_RXFIFO Bit-Fields */
-#define S3C_PCM_RXFIFO_DVALID  (0x1<<16)
-#define S3C_PCM_RXFIFO_DATA_MSK        (0xffff<<0)
-
-/* PCM_IRQCTL Bit-Fields */
-#define S3C_PCM_IRQCTL_IRQEN           (0x1<<14)
-#define S3C_PCM_IRQCTL_WRDEN           (0x1<<12)
-#define S3C_PCM_IRQCTL_TXEMPTYEN               (0x1<<11)
-#define S3C_PCM_IRQCTL_TXALMSTEMPTYEN  (0x1<<10)
-#define S3C_PCM_IRQCTL_TXFULLEN                (0x1<<9)
-#define S3C_PCM_IRQCTL_TXALMSTFULLEN   (0x1<<8)
-#define S3C_PCM_IRQCTL_TXSTARVEN               (0x1<<7)
-#define S3C_PCM_IRQCTL_TXERROVRFLEN            (0x1<<6)
-#define S3C_PCM_IRQCTL_RXEMPTEN                (0x1<<5)
-#define S3C_PCM_IRQCTL_RXALMSTEMPTEN   (0x1<<4)
-#define S3C_PCM_IRQCTL_RXFULLEN                (0x1<<3)
-#define S3C_PCM_IRQCTL_RXALMSTFULLEN   (0x1<<2)
-#define S3C_PCM_IRQCTL_RXSTARVEN               (0x1<<1)
-#define S3C_PCM_IRQCTL_RXERROVRFLEN            (0x1<<0)
-
-/* PCM_IRQSTAT Bit-Fields */
-#define S3C_PCM_IRQSTAT_IRQPND         (0x1<<13)
-#define S3C_PCM_IRQSTAT_WRD_XFER               (0x1<<12)
-#define S3C_PCM_IRQSTAT_TXEMPTY                (0x1<<11)
-#define S3C_PCM_IRQSTAT_TXALMSTEMPTY   (0x1<<10)
-#define S3C_PCM_IRQSTAT_TXFULL         (0x1<<9)
-#define S3C_PCM_IRQSTAT_TXALMSTFULL            (0x1<<8)
-#define S3C_PCM_IRQSTAT_TXSTARV                (0x1<<7)
-#define S3C_PCM_IRQSTAT_TXERROVRFL             (0x1<<6)
-#define S3C_PCM_IRQSTAT_RXEMPT         (0x1<<5)
-#define S3C_PCM_IRQSTAT_RXALMSTEMPT            (0x1<<4)
-#define S3C_PCM_IRQSTAT_RXFULL         (0x1<<3)
-#define S3C_PCM_IRQSTAT_RXALMSTFULL            (0x1<<2)
-#define S3C_PCM_IRQSTAT_RXSTARV                (0x1<<1)
-#define S3C_PCM_IRQSTAT_RXERROVRFL             (0x1<<0)
-
-/* PCM_FIFOSTAT Bit-Fields */
-#define S3C_PCM_FIFOSTAT_TXCNT_MSK             (0x3f<<14)
-#define S3C_PCM_FIFOSTAT_TXFIFOEMPTY   (0x1<<13)
-#define S3C_PCM_FIFOSTAT_TXFIFOALMSTEMPTY      (0x1<<12)
-#define S3C_PCM_FIFOSTAT_TXFIFOFULL            (0x1<<11)
-#define S3C_PCM_FIFOSTAT_TXFIFOALMSTFULL       (0x1<<10)
-#define S3C_PCM_FIFOSTAT_RXCNT_MSK             (0x3f<<4)
-#define S3C_PCM_FIFOSTAT_RXFIFOEMPTY   (0x1<<3)
-#define S3C_PCM_FIFOSTAT_RXFIFOALMSTEMPTY      (0x1<<2)
-#define S3C_PCM_FIFOSTAT_RXFIFOFULL            (0x1<<1)
-#define S3C_PCM_FIFOSTAT_RXFIFOALMSTFULL       (0x1<<0)
-
-#define S3C_PCM_CLKSRC_PCLK    0
-#define S3C_PCM_CLKSRC_MUX     1
-
-#define S3C_PCM_SCLK_PER_FS    0
-
-/**
- * struct s3c_pcm_info - S3C PCM Controller information
- * @dev: The parent device passed to use from the probe.
- * @regs: The pointer to the device register block.
- * @dma_playback: DMA information for playback channel.
- * @dma_capture: DMA information for capture channel.
- */
-struct s3c_pcm_info {
-       spinlock_t lock;
-       struct device   *dev;
-       void __iomem    *regs;
-
-       unsigned int sclk_per_fs;
-
-       /* Whether to keep PCMSCLK enabled even when idle(no active xfer) */
-       unsigned int idleclk;
-
-       struct clk      *pclk;
-       struct clk      *cclk;
-
-       struct s3c_dma_params   *dma_playback;
-       struct s3c_dma_params   *dma_capture;
-};
-
-#endif /* __S3C_PCM_H */
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c
deleted file mode 100644 (file)
index 4a861cf..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-/* sound/soc/s3c24xx/s3c2412-i2s.c
- *
- * ALSA Soc Audio Layer - S3C2412 I2S driver
- *
- * Copyright (c) 2006 Wolfson Microelectronics PLC.
- *     Graeme Gregory graeme.gregory@wolfsonmicro.com
- *     linux@wolfsonmicro.com
- *
- * Copyright (c) 2007, 2004-2005 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/clk.h>
-#include <linux/kernel.h>
-#include <linux/io.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-#include <mach/hardware.h>
-
-#include <mach/regs-gpio.h>
-#include <mach/dma.h>
-
-#include "s3c-dma.h"
-#include "regs-i2s-v2.h"
-#include "s3c2412-i2s.h"
-
-#define S3C2412_I2S_DEBUG 0
-
-static struct s3c2410_dma_client s3c2412_dma_client_out = {
-       .name           = "I2S PCM Stereo out"
-};
-
-static struct s3c2410_dma_client s3c2412_dma_client_in = {
-       .name           = "I2S PCM Stereo in"
-};
-
-static struct s3c_dma_params s3c2412_i2s_pcm_stereo_out = {
-       .client         = &s3c2412_dma_client_out,
-       .channel        = DMACH_I2S_OUT,
-       .dma_addr       = S3C2410_PA_IIS + S3C2412_IISTXD,
-       .dma_size       = 4,
-};
-
-static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = {
-       .client         = &s3c2412_dma_client_in,
-       .channel        = DMACH_I2S_IN,
-       .dma_addr       = S3C2410_PA_IIS + S3C2412_IISRXD,
-       .dma_size       = 4,
-};
-
-static struct s3c_i2sv2_info s3c2412_i2s;
-
-static int s3c2412_i2s_probe(struct snd_soc_dai *dai)
-{
-       int ret;
-
-       pr_debug("Entered %s\n", __func__);
-
-       ret = s3c_i2sv2_probe(dai, &s3c2412_i2s, S3C2410_PA_IIS);
-       if (ret)
-               return ret;
-
-       s3c2412_i2s.dma_capture = &s3c2412_i2s_pcm_stereo_in;
-       s3c2412_i2s.dma_playback = &s3c2412_i2s_pcm_stereo_out;
-
-       s3c2412_i2s.iis_cclk = clk_get(dai->dev, "i2sclk");
-       if (s3c2412_i2s.iis_cclk == NULL) {
-               pr_err("failed to get i2sclk clock\n");
-               iounmap(s3c2412_i2s.regs);
-               return -ENODEV;
-       }
-
-       /* Set MPLL as the source for IIS CLK */
-
-       clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll"));
-       clk_enable(s3c2412_i2s.iis_cclk);
-
-       s3c2412_i2s.iis_cclk = s3c2412_i2s.iis_pclk;
-
-       /* Configure the I2S pins in correct mode */
-       s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK);
-       s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK);
-       s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK);
-       s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);
-       s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);
-
-       return 0;
-}
-
-static int s3c2412_i2s_remove(struct snd_soc_dai *dai)
-{
-       clk_disable(s3c2412_i2s.iis_cclk);
-       clk_put(s3c2412_i2s.iis_cclk);
-       iounmap(s3c2412_i2s.regs);
-
-       return 0;
-}
-
-static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
-                                struct snd_pcm_hw_params *params,
-                                struct snd_soc_dai *cpu_dai)
-{
-       struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(cpu_dai);
-       struct s3c_dma_params *dma_data;
-       u32 iismod;
-
-       pr_debug("Entered %s\n", __func__);
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               dma_data = i2s->dma_playback;
-       else
-               dma_data = i2s->dma_capture;
-
-       snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
-
-       iismod = readl(i2s->regs + S3C2412_IISMOD);
-       pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
-
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S8:
-               iismod |= S3C2412_IISMOD_8BIT;
-               break;
-       case SNDRV_PCM_FORMAT_S16_LE:
-               iismod &= ~S3C2412_IISMOD_8BIT;
-               break;
-       }
-
-       writel(iismod, i2s->regs + S3C2412_IISMOD);
-       pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
-
-       return 0;
-}
-
-#define S3C2412_I2S_RATES \
-       (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
-       SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
-       SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
-
-static struct snd_soc_dai_ops s3c2412_i2s_dai_ops = {
-       .hw_params      = s3c2412_i2s_hw_params,
-};
-
-static struct snd_soc_dai_driver s3c2412_i2s_dai = {
-       .probe          = s3c2412_i2s_probe,
-       .remove = s3c2412_i2s_remove,
-       .playback = {
-               .channels_min   = 2,
-               .channels_max   = 2,
-               .rates          = S3C2412_I2S_RATES,
-               .formats        = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .capture = {
-               .channels_min   = 2,
-               .channels_max   = 2,
-               .rates          = S3C2412_I2S_RATES,
-               .formats        = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .ops = &s3c2412_i2s_dai_ops,
-};
-
-static __devinit int s3c2412_iis_dev_probe(struct platform_device *pdev)
-{
-       return snd_soc_register_dai(&pdev->dev, &s3c2412_i2s_dai);
-}
-
-static __devexit int s3c2412_iis_dev_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_dai(&pdev->dev);
-       return 0;
-}
-
-static struct platform_driver s3c2412_iis_driver = {
-       .probe  = s3c2412_iis_dev_probe,
-       .remove = s3c2412_iis_dev_remove,
-       .driver = {
-               .name = "s3c2412-iis",
-               .owner = THIS_MODULE,
-       },
-};
-
-static int __init s3c2412_i2s_init(void)
-{
-       return platform_driver_register(&s3c2412_iis_driver);
-}
-module_init(s3c2412_i2s_init);
-
-static void __exit s3c2412_i2s_exit(void)
-{
-       platform_driver_unregister(&s3c2412_iis_driver);
-}
-module_exit(s3c2412_i2s_exit);
-
-/* Module information */
-MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
-MODULE_DESCRIPTION("S3C2412 I2S SoC Interface");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s3c2412-iis");
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.h b/sound/soc/s3c24xx/s3c2412-i2s.h
deleted file mode 100644 (file)
index 01a0471..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/* sound/soc/s3c24xx/s3c2412-i2s.c
- *
- * ALSA Soc Audio Layer - S3C2412 I2S driver
- *
- * Copyright (c) 2007 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- *  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 __SND_SOC_S3C24XX_S3C2412_I2S_H
-#define __SND_SOC_S3C24XX_S3C2412_I2S_H __FILE__
-
-#include "s3c-i2s-v2.h"
-
-#define S3C2412_DIV_BCLK       S3C_I2SV2_DIV_BCLK
-#define S3C2412_DIV_RCLK       S3C_I2SV2_DIV_RCLK
-#define S3C2412_DIV_PRESCALER  S3C_I2SV2_DIV_PRESCALER
-
-#define S3C2412_CLKSRC_PCLK    S3C_I2SV2_CLKSRC_PCLK
-#define S3C2412_CLKSRC_I2SCLK  S3C_I2SV2_CLKSRC_AUDIOBUS
-
-#endif /* __SND_SOC_S3C24XX_S3C2412_I2S_H */
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c
deleted file mode 100644 (file)
index e060daa..0000000
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- * s3c24xx-i2s.c  --  ALSA Soc Audio Layer
- *
- * (c) 2006 Wolfson Microelectronics PLC.
- * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
- *
- * Copyright 2004-2005 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- *  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/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/jiffies.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-
-#include <mach/hardware.h>
-#include <mach/regs-gpio.h>
-#include <mach/regs-clock.h>
-
-#include <asm/dma.h>
-#include <mach/dma.h>
-
-#include <plat/regs-iis.h>
-
-#include "s3c-dma.h"
-#include "s3c24xx-i2s.h"
-
-static struct s3c2410_dma_client s3c24xx_dma_client_out = {
-       .name = "I2S PCM Stereo out"
-};
-
-static struct s3c2410_dma_client s3c24xx_dma_client_in = {
-       .name = "I2S PCM Stereo in"
-};
-
-static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_out = {
-       .client         = &s3c24xx_dma_client_out,
-       .channel        = DMACH_I2S_OUT,
-       .dma_addr       = S3C2410_PA_IIS + S3C2410_IISFIFO,
-       .dma_size       = 2,
-};
-
-static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_in = {
-       .client         = &s3c24xx_dma_client_in,
-       .channel        = DMACH_I2S_IN,
-       .dma_addr       = S3C2410_PA_IIS + S3C2410_IISFIFO,
-       .dma_size       = 2,
-};
-
-struct s3c24xx_i2s_info {
-       void __iomem    *regs;
-       struct clk      *iis_clk;
-       u32             iiscon;
-       u32             iismod;
-       u32             iisfcon;
-       u32             iispsr;
-};
-static struct s3c24xx_i2s_info s3c24xx_i2s;
-
-static void s3c24xx_snd_txctrl(int on)
-{
-       u32 iisfcon;
-       u32 iiscon;
-       u32 iismod;
-
-       pr_debug("Entered %s\n", __func__);
-
-       iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
-       iiscon  = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
-       iismod  = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
-
-       pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
-
-       if (on) {
-               iisfcon |= S3C2410_IISFCON_TXDMA | S3C2410_IISFCON_TXENABLE;
-               iiscon  |= S3C2410_IISCON_TXDMAEN | S3C2410_IISCON_IISEN;
-               iiscon  &= ~S3C2410_IISCON_TXIDLE;
-               iismod  |= S3C2410_IISMOD_TXMODE;
-
-               writel(iismod,  s3c24xx_i2s.regs + S3C2410_IISMOD);
-               writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
-               writel(iiscon,  s3c24xx_i2s.regs + S3C2410_IISCON);
-       } else {
-               /* note, we have to disable the FIFOs otherwise bad things
-                * seem to happen when the DMA stops. According to the
-                * Samsung supplied kernel, this should allow the DMA
-                * engine and FIFOs to reset. If this isn't allowed, the
-                * DMA engine will simply freeze randomly.
-                */
-
-               iisfcon &= ~S3C2410_IISFCON_TXENABLE;
-               iisfcon &= ~S3C2410_IISFCON_TXDMA;
-               iiscon  |=  S3C2410_IISCON_TXIDLE;
-               iiscon  &= ~S3C2410_IISCON_TXDMAEN;
-               iismod  &= ~S3C2410_IISMOD_TXMODE;
-
-               writel(iiscon,  s3c24xx_i2s.regs + S3C2410_IISCON);
-               writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
-               writel(iismod,  s3c24xx_i2s.regs + S3C2410_IISMOD);
-       }
-
-       pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
-}
-
-static void s3c24xx_snd_rxctrl(int on)
-{
-       u32 iisfcon;
-       u32 iiscon;
-       u32 iismod;
-
-       pr_debug("Entered %s\n", __func__);
-
-       iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
-       iiscon  = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
-       iismod  = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
-
-       pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
-
-       if (on) {
-               iisfcon |= S3C2410_IISFCON_RXDMA | S3C2410_IISFCON_RXENABLE;
-               iiscon  |= S3C2410_IISCON_RXDMAEN | S3C2410_IISCON_IISEN;
-               iiscon  &= ~S3C2410_IISCON_RXIDLE;
-               iismod  |= S3C2410_IISMOD_RXMODE;
-
-               writel(iismod,  s3c24xx_i2s.regs + S3C2410_IISMOD);
-               writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
-               writel(iiscon,  s3c24xx_i2s.regs + S3C2410_IISCON);
-       } else {
-               /* note, we have to disable the FIFOs otherwise bad things
-                * seem to happen when the DMA stops. According to the
-                * Samsung supplied kernel, this should allow the DMA
-                * engine and FIFOs to reset. If this isn't allowed, the
-                * DMA engine will simply freeze randomly.
-                */
-
-               iisfcon &= ~S3C2410_IISFCON_RXENABLE;
-               iisfcon &= ~S3C2410_IISFCON_RXDMA;
-               iiscon  |= S3C2410_IISCON_RXIDLE;
-               iiscon  &= ~S3C2410_IISCON_RXDMAEN;
-               iismod  &= ~S3C2410_IISMOD_RXMODE;
-
-               writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
-               writel(iiscon,  s3c24xx_i2s.regs + S3C2410_IISCON);
-               writel(iismod,  s3c24xx_i2s.regs + S3C2410_IISMOD);
-       }
-
-       pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
-}
-
-/*
- * Wait for the LR signal to allow synchronisation to the L/R clock
- * from the codec. May only be needed for slave mode.
- */
-static int s3c24xx_snd_lrsync(void)
-{
-       u32 iiscon;
-       int timeout = 50; /* 5ms */
-
-       pr_debug("Entered %s\n", __func__);
-
-       while (1) {
-               iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
-               if (iiscon & S3C2410_IISCON_LRINDEX)
-                       break;
-
-               if (!timeout--)
-                       return -ETIMEDOUT;
-               udelay(100);
-       }
-
-       return 0;
-}
-
-/*
- * Check whether CPU is the master or slave
- */
-static inline int s3c24xx_snd_is_clkmaster(void)
-{
-       pr_debug("Entered %s\n", __func__);
-
-       return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1;
-}
-
-/*
- * Set S3C24xx I2S DAI format
- */
-static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
-               unsigned int fmt)
-{
-       u32 iismod;
-
-       pr_debug("Entered %s\n", __func__);
-
-       iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
-       pr_debug("hw_params r: IISMOD: %x \n", iismod);
-
-       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:
-               iismod |= S3C2410_IISMOD_SLAVE;
-               break;
-       case SND_SOC_DAIFMT_CBS_CFS:
-               iismod &= ~S3C2410_IISMOD_SLAVE;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-       case SND_SOC_DAIFMT_LEFT_J:
-               iismod |= S3C2410_IISMOD_MSB;
-               break;
-       case SND_SOC_DAIFMT_I2S:
-               iismod &= ~S3C2410_IISMOD_MSB;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
-       pr_debug("hw_params w: IISMOD: %x \n", iismod);
-       return 0;
-}
-
-static int s3c24xx_i2s_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 s3c_dma_params *dma_data;
-       u32 iismod;
-
-       pr_debug("Entered %s\n", __func__);
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               dma_data = &s3c24xx_i2s_pcm_stereo_out;
-       else
-               dma_data = &s3c24xx_i2s_pcm_stereo_in;
-
-       snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
-
-       /* Working copies of register */
-       iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
-       pr_debug("hw_params r: IISMOD: %x\n", iismod);
-
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S8:
-               iismod &= ~S3C2410_IISMOD_16BIT;
-               dma_data->dma_size = 1;
-               break;
-       case SNDRV_PCM_FORMAT_S16_LE:
-               iismod |= S3C2410_IISMOD_16BIT;
-               dma_data->dma_size = 2;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
-       pr_debug("hw_params w: IISMOD: %x\n", iismod);
-       return 0;
-}
-
-static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
-                              struct snd_soc_dai *dai)
-{
-       int ret = 0;
-       struct s3c_dma_params *dma_data =
-               snd_soc_dai_get_dma_data(dai, substream);
-
-       pr_debug("Entered %s\n", __func__);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               if (!s3c24xx_snd_is_clkmaster()) {
-                       ret = s3c24xx_snd_lrsync();
-                       if (ret)
-                               goto exit_err;
-               }
-
-               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-                       s3c24xx_snd_rxctrl(1);
-               else
-                       s3c24xx_snd_txctrl(1);
-
-               s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-                       s3c24xx_snd_rxctrl(0);
-               else
-                       s3c24xx_snd_txctrl(0);
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
-
-exit_err:
-       return ret;
-}
-
-/*
- * Set S3C24xx Clock source
- */
-static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
-       int clk_id, unsigned int freq, int dir)
-{
-       u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
-
-       pr_debug("Entered %s\n", __func__);
-
-       iismod &= ~S3C2440_IISMOD_MPLL;
-
-       switch (clk_id) {
-       case S3C24XX_CLKSRC_PCLK:
-               break;
-       case S3C24XX_CLKSRC_MPLL:
-               iismod |= S3C2440_IISMOD_MPLL;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
-       return 0;
-}
-
-/*
- * Set S3C24xx Clock dividers
- */
-static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
-       int div_id, int div)
-{
-       u32 reg;
-
-       pr_debug("Entered %s\n", __func__);
-
-       switch (div_id) {
-       case S3C24XX_DIV_BCLK:
-               reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~S3C2410_IISMOD_FS_MASK;
-               writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
-               break;
-       case S3C24XX_DIV_MCLK:
-               reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~(S3C2410_IISMOD_384FS);
-               writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
-               break;
-       case S3C24XX_DIV_PRESCALER:
-               writel(div, s3c24xx_i2s.regs + S3C2410_IISPSR);
-               reg = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
-               writel(reg | S3C2410_IISCON_PSCEN, s3c24xx_i2s.regs + S3C2410_IISCON);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/*
- * To avoid duplicating clock code, allow machine driver to
- * get the clockrate from here.
- */
-u32 s3c24xx_i2s_get_clockrate(void)
-{
-       return clk_get_rate(s3c24xx_i2s.iis_clk);
-}
-EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
-
-static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
-{
-       pr_debug("Entered %s\n", __func__);
-
-       s3c24xx_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100);
-       if (s3c24xx_i2s.regs == NULL)
-               return -ENXIO;
-
-       s3c24xx_i2s.iis_clk = clk_get(dai->dev, "iis");
-       if (s3c24xx_i2s.iis_clk == NULL) {
-               pr_err("failed to get iis_clock\n");
-               iounmap(s3c24xx_i2s.regs);
-               return -ENODEV;
-       }
-       clk_enable(s3c24xx_i2s.iis_clk);
-
-       /* Configure the I2S pins in correct mode */
-       s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK);
-       s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK);
-       s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK);
-       s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);
-       s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);
-
-       writel(S3C2410_IISCON_IISEN, s3c24xx_i2s.regs + S3C2410_IISCON);
-
-       s3c24xx_snd_txctrl(0);
-       s3c24xx_snd_rxctrl(0);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)
-{
-       pr_debug("Entered %s\n", __func__);
-
-       s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
-       s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
-       s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
-       s3c24xx_i2s.iispsr = readl(s3c24xx_i2s.regs + S3C2410_IISPSR);
-
-       clk_disable(s3c24xx_i2s.iis_clk);
-
-       return 0;
-}
-
-static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)
-{
-       pr_debug("Entered %s\n", __func__);
-       clk_enable(s3c24xx_i2s.iis_clk);
-
-       writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
-       writel(s3c24xx_i2s.iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
-       writel(s3c24xx_i2s.iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
-       writel(s3c24xx_i2s.iispsr, s3c24xx_i2s.regs + S3C2410_IISPSR);
-
-       return 0;
-}
-#else
-#define s3c24xx_i2s_suspend NULL
-#define s3c24xx_i2s_resume NULL
-#endif
-
-
-#define S3C24XX_I2S_RATES \
-       (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
-       SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
-       SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
-
-static struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = {
-       .trigger        = s3c24xx_i2s_trigger,
-       .hw_params      = s3c24xx_i2s_hw_params,
-       .set_fmt        = s3c24xx_i2s_set_fmt,
-       .set_clkdiv     = s3c24xx_i2s_set_clkdiv,
-       .set_sysclk     = s3c24xx_i2s_set_sysclk,
-};
-
-static struct snd_soc_dai_driver s3c24xx_i2s_dai = {
-       .probe = s3c24xx_i2s_probe,
-       .suspend = s3c24xx_i2s_suspend,
-       .resume = s3c24xx_i2s_resume,
-       .playback = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = S3C24XX_I2S_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
-       .capture = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = S3C24XX_I2S_RATES,
-               .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = &s3c24xx_i2s_dai_ops,
-};
-
-static __devinit int s3c24xx_iis_dev_probe(struct platform_device *pdev)
-{
-       return snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai);
-}
-
-static __devexit int s3c24xx_iis_dev_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_dai(&pdev->dev);
-       return 0;
-}
-
-static struct platform_driver s3c24xx_iis_driver = {
-       .probe  = s3c24xx_iis_dev_probe,
-       .remove = s3c24xx_iis_dev_remove,
-       .driver = {
-               .name = "s3c24xx-iis",
-               .owner = THIS_MODULE,
-       },
-};
-
-static int __init s3c24xx_i2s_init(void)
-{
-       return platform_driver_register(&s3c24xx_iis_driver);
-}
-module_init(s3c24xx_i2s_init);
-
-static void __exit s3c24xx_i2s_exit(void)
-{
-       platform_driver_unregister(&s3c24xx_iis_driver);
-}
-module_exit(s3c24xx_i2s_exit);
-
-/* Module information */
-MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
-MODULE_DESCRIPTION("s3c24xx I2S SoC Interface");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s3c24xx-iis");
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.h b/sound/soc/s3c24xx/s3c24xx-i2s.h
deleted file mode 100644 (file)
index f9ca04e..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * s3c24xx-i2s.c  --  ALSA Soc Audio Layer
- *
- * Copyright 2005 Wolfson Microelectronics PLC.
- * Author: Graeme Gregory
- *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
- *
- *  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.
- *
- *  Revision history
- *    10th Nov 2006   Initial version.
- */
-
-#ifndef S3C24XXI2S_H_
-#define S3C24XXI2S_H_
-
-/* clock sources */
-#define S3C24XX_CLKSRC_PCLK 0
-#define S3C24XX_CLKSRC_MPLL 1
-
-/* Clock dividers */
-#define S3C24XX_DIV_MCLK       0
-#define S3C24XX_DIV_BCLK       1
-#define S3C24XX_DIV_PRESCALER  2
-
-/* prescaler */
-#define S3C24XX_PRESCALE(a,b) \
-       (((a - 1) << S3C2410_IISPSR_INTSHIFT) | ((b - 1) << S3C2410_IISPSR_EXTSHFIT))
-
-u32 s3c24xx_i2s_get_clockrate(void);
-
-#endif /*S3C24XXI2S_H_*/
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.c b/sound/soc/s3c24xx/s3c24xx_simtec.c
deleted file mode 100644 (file)
index c4c1114..0000000
+++ /dev/null
@@ -1,395 +0,0 @@
-/* sound/soc/s3c24xx/s3c24xx_simtec.c
- *
- * Copyright 2009 Simtec Electronics
- *
- * 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/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/clk.h>
-#include <linux/i2c.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include <plat/audio-simtec.h>
-
-#include "s3c-dma.h"
-#include "s3c24xx-i2s.h"
-#include "s3c24xx_simtec.h"
-
-static struct s3c24xx_audio_simtec_pdata *pdata;
-static struct clk *xtal_clk;
-
-static int spk_gain;
-static int spk_unmute;
-
-/**
- * speaker_gain_get - read the speaker gain setting.
- * @kcontrol: The control for the speaker gain.
- * @ucontrol: The value that needs to be updated.
- *
- * Read the value for the AMP gain control.
- */
-static int speaker_gain_get(struct snd_kcontrol *kcontrol,
-                           struct snd_ctl_elem_value *ucontrol)
-{
-       ucontrol->value.integer.value[0] = spk_gain;
-       return 0;
-}
-
-/**
- * speaker_gain_set - set the value of the speaker amp gain
- * @value: The value to write.
- */
-static void speaker_gain_set(int value)
-{
-       gpio_set_value_cansleep(pdata->amp_gain[0], value & 1);
-       gpio_set_value_cansleep(pdata->amp_gain[1], value >> 1);
-}
-
-/**
- * speaker_gain_put - set the speaker gain setting.
- * @kcontrol: The control for the speaker gain.
- * @ucontrol: The value that needs to be set.
- *
- * Set the value of the speaker gain from the specified
- * @ucontrol setting.
- *
- * Note, if the speaker amp is muted, then we do not set a gain value
- * as at-least one of the ICs that is fitted will try and power up even
- * if the main control is set to off.
- */
-static int speaker_gain_put(struct snd_kcontrol *kcontrol,
-                           struct snd_ctl_elem_value *ucontrol)
-{
-       int value = ucontrol->value.integer.value[0];
-
-       spk_gain = value;
-
-       if (!spk_unmute)
-               speaker_gain_set(value);
-
-       return 0;
-}
-
-static const struct snd_kcontrol_new amp_gain_controls[] = {
-       SOC_SINGLE_EXT("Speaker Gain", 0, 0, 3, 0,
-                      speaker_gain_get, speaker_gain_put),
-};
-
-/**
- * spk_unmute_state - set the unmute state of the speaker
- * @to: zero to unmute, non-zero to ununmute.
- */
-static void spk_unmute_state(int to)
-{
-       pr_debug("%s: to=%d\n", __func__, to);
-
-       spk_unmute = to;
-       gpio_set_value(pdata->amp_gpio, to);
-
-       /* if we're umuting, also re-set the gain */
-       if (to && pdata->amp_gain[0] > 0)
-               speaker_gain_set(spk_gain);
-}
-
-/**
- * speaker_unmute_get - read the speaker unmute setting.
- * @kcontrol: The control for the speaker gain.
- * @ucontrol: The value that needs to be updated.
- *
- * Read the value for the AMP gain control.
- */
-static int speaker_unmute_get(struct snd_kcontrol *kcontrol,
-                           struct snd_ctl_elem_value *ucontrol)
-{
-       ucontrol->value.integer.value[0] = spk_unmute;
-       return 0;
-}
-
-/**
- * speaker_unmute_put - set the speaker unmute setting.
- * @kcontrol: The control for the speaker gain.
- * @ucontrol: The value that needs to be set.
- *
- * Set the value of the speaker gain from the specified
- * @ucontrol setting.
- */
-static int speaker_unmute_put(struct snd_kcontrol *kcontrol,
-                           struct snd_ctl_elem_value *ucontrol)
-{
-       spk_unmute_state(ucontrol->value.integer.value[0]);
-       return 0;
-}
-
-/* This is added as a manual control as the speaker amps create clicks
- * when their power state is changed, which are far more noticeable than
- * anything produced by the CODEC itself.
- */
-static const struct snd_kcontrol_new amp_unmute_controls[] = {
-       SOC_SINGLE_EXT("Speaker Switch", 0, 0, 1, 0,
-                      speaker_unmute_get, speaker_unmute_put),
-};
-
-void simtec_audio_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-
-       if (pdata->amp_gpio > 0) {
-               pr_debug("%s: adding amp routes\n", __func__);
-
-               snd_soc_add_controls(codec, amp_unmute_controls,
-                                    ARRAY_SIZE(amp_unmute_controls));
-       }
-
-       if (pdata->amp_gain[0] > 0) {
-               pr_debug("%s: adding amp controls\n", __func__);
-               snd_soc_add_controls(codec, amp_gain_controls,
-                                    ARRAY_SIZE(amp_gain_controls));
-       }
-}
-EXPORT_SYMBOL_GPL(simtec_audio_init);
-
-#define CODEC_CLOCK 12000000
-
-/**
- * simtec_hw_params - update hardware parameters
- * @substream: The audio substream instance.
- * @params: The parameters requested.
- *
- * Update the codec data routing and configuration  settings
- * from the supplied data.
- */
-static int simtec_hw_params(struct snd_pcm_substream *substream,
-                           struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int ret;
-
-       /* Set the CODEC as the bus clock master, I2S */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBM_CFM);
-       if (ret) {
-               pr_err("%s: failed set cpu dai format\n", __func__);
-               return ret;
-       }
-
-       /* Set the CODEC as the bus clock master */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBM_CFM);
-       if (ret) {
-               pr_err("%s: failed set codec dai format\n", __func__);
-               return ret;
-       }
-
-       ret = snd_soc_dai_set_sysclk(codec_dai, 0,
-                                    CODEC_CLOCK, SND_SOC_CLOCK_IN);
-       if (ret) {
-               pr_err( "%s: failed setting codec sysclk\n", __func__);
-               return ret;
-       }
-
-       if (pdata->use_mpllin) {
-               ret = snd_soc_dai_set_sysclk(cpu_dai, S3C24XX_CLKSRC_MPLL,
-                                            0, SND_SOC_CLOCK_OUT);
-
-               if (ret) {
-                       pr_err("%s: failed to set MPLLin as clksrc\n",
-                              __func__);
-                       return ret;
-               }
-       }
-
-       if (pdata->output_cdclk) {
-               int cdclk_scale;
-
-               cdclk_scale = clk_get_rate(xtal_clk) / CODEC_CLOCK;
-               cdclk_scale--;
-
-               ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
-                                            cdclk_scale);
-       }
-
-       return 0;
-}
-
-static int simtec_call_startup(struct s3c24xx_audio_simtec_pdata *pd)
-{
-       /* call any board supplied startup code, this currently only
-        * covers the bast/vr1000 which have a CPLD in the way of the
-        * LRCLK */
-       if (pd->startup)
-               pd->startup();
-
-       return 0;
-}
-
-static struct snd_soc_ops simtec_snd_ops = {
-       .hw_params      = simtec_hw_params,
-};
-
-/**
- * attach_gpio_amp - get and configure the necessary gpios
- * @dev: The device we're probing.
- * @pd: The platform data supplied by the board.
- *
- * If there is a GPIO based amplifier attached to the board, claim
- * the necessary GPIO lines for it, and set default values.
- */
-static int attach_gpio_amp(struct device *dev,
-                          struct s3c24xx_audio_simtec_pdata *pd)
-{
-       int ret;
-
-       /* attach gpio amp gain (if any) */
-       if (pdata->amp_gain[0] > 0) {
-               ret = gpio_request(pd->amp_gain[0], "gpio-amp-gain0");
-               if (ret) {
-                       dev_err(dev, "cannot get amp gpio gain0\n");
-                       return ret;
-               }
-
-               ret = gpio_request(pd->amp_gain[1], "gpio-amp-gain1");
-               if (ret) {
-                       dev_err(dev, "cannot get amp gpio gain1\n");
-                       gpio_free(pdata->amp_gain[0]);
-                       return ret;
-               }
-
-               gpio_direction_output(pd->amp_gain[0], 0);
-               gpio_direction_output(pd->amp_gain[1], 0);
-       }
-
-       /* note, currently we assume GPA0 isn't valid amp */
-       if (pdata->amp_gpio > 0) {
-               ret = gpio_request(pd->amp_gpio, "gpio-amp");
-               if (ret) {
-                       dev_err(dev, "cannot get amp gpio %d (%d)\n",
-                               pd->amp_gpio, ret);
-                       goto err_amp;
-               }
-
-               /* set the amp off at startup */
-               spk_unmute_state(0);
-       }
-
-       return 0;
-
-err_amp:
-       if (pd->amp_gain[0] > 0) {
-               gpio_free(pd->amp_gain[0]);
-               gpio_free(pd->amp_gain[1]);
-       }
-
-       return ret;
-}
-
-static void detach_gpio_amp(struct s3c24xx_audio_simtec_pdata *pd)
-{
-       if (pd->amp_gain[0] > 0) {
-               gpio_free(pd->amp_gain[0]);
-               gpio_free(pd->amp_gain[1]);
-       }
-
-       if (pd->amp_gpio > 0)
-               gpio_free(pd->amp_gpio);
-}
-
-#ifdef CONFIG_PM
-int simtec_audio_resume(struct device *dev)
-{
-       simtec_call_startup(pdata);
-       return 0;
-}
-
-const struct dev_pm_ops simtec_audio_pmops = {
-       .resume = simtec_audio_resume,
-};
-EXPORT_SYMBOL_GPL(simtec_audio_pmops);
-#endif
-
-int __devinit simtec_audio_core_probe(struct platform_device *pdev,
-                                     struct snd_soc_card *card)
-{
-       struct platform_device *snd_dev;
-       int ret;
-
-       card->dai_link->ops = &simtec_snd_ops;
-
-       pdata = pdev->dev.platform_data;
-       if (!pdata) {
-               dev_err(&pdev->dev, "no platform data supplied\n");
-               return -EINVAL;
-       }
-
-       simtec_call_startup(pdata);
-
-       xtal_clk = clk_get(&pdev->dev, "xtal");
-       if (IS_ERR(xtal_clk)) {
-               dev_err(&pdev->dev, "could not get clkout0\n");
-               return -EINVAL;
-       }
-
-       dev_info(&pdev->dev, "xtal rate is %ld\n", clk_get_rate(xtal_clk));
-
-       ret = attach_gpio_amp(&pdev->dev, pdata);
-       if (ret)
-               goto err_clk;
-
-       snd_dev = platform_device_alloc("soc-audio", -1);
-       if (!snd_dev) {
-               dev_err(&pdev->dev, "failed to alloc soc-audio devicec\n");
-               ret = -ENOMEM;
-               goto err_gpio;
-       }
-
-       platform_set_drvdata(snd_dev, card);
-
-       ret = platform_device_add(snd_dev);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to add soc-audio dev\n");
-               goto err_pdev;
-       }
-
-       platform_set_drvdata(pdev, snd_dev);
-       return 0;
-
-err_pdev:
-       platform_device_put(snd_dev);
-
-err_gpio:
-       detach_gpio_amp(pdata);
-
-err_clk:
-       clk_put(xtal_clk);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(simtec_audio_core_probe);
-
-int __devexit simtec_audio_remove(struct platform_device *pdev)
-{
-       struct platform_device *snd_dev = platform_get_drvdata(pdev);
-
-       platform_device_unregister(snd_dev);
-
-       detach_gpio_amp(pdata);
-       clk_put(xtal_clk);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(simtec_audio_remove);
-
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_DESCRIPTION("ALSA SoC Simtec Audio common support");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.h b/sound/soc/s3c24xx/s3c24xx_simtec.h
deleted file mode 100644 (file)
index e63d5ff..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/* sound/soc/s3c24xx/s3c24xx_simtec.h
- *
- * Copyright 2009 Simtec Electronics
- *
- * 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.
-*/
-
-extern void simtec_audio_init(struct snd_soc_pcm_runtime *rtd);
-
-extern int simtec_audio_core_probe(struct platform_device *pdev,
-                                  struct snd_soc_card *card);
-
-extern int simtec_audio_remove(struct platform_device *pdev);
-
-#ifdef CONFIG_PM
-extern const struct dev_pm_ops simtec_audio_pmops;
-#define simtec_audio_pm &simtec_audio_pmops
-#else
-#define simtec_audio_pm NULL
-#endif
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
deleted file mode 100644 (file)
index f884537..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/* sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
- *
- * Copyright 2009 Simtec Electronics
- *
- * 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/clk.h>
-#include <linux/platform_device.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include <plat/audio-simtec.h>
-
-#include "s3c-dma.h"
-#include "s3c24xx-i2s.h"
-#include "s3c24xx_simtec.h"
-
-#include "../codecs/tlv320aic3x.h"
-
-static const struct snd_soc_dapm_widget dapm_widgets[] = {
-       SND_SOC_DAPM_LINE("GSM Out", NULL),
-       SND_SOC_DAPM_LINE("GSM In", NULL),
-       SND_SOC_DAPM_LINE("Line In", NULL),
-       SND_SOC_DAPM_LINE("Line Out", NULL),
-       SND_SOC_DAPM_LINE("ZV", NULL),
-       SND_SOC_DAPM_MIC("Mic Jack", NULL),
-       SND_SOC_DAPM_HP("Headphone Jack", NULL),
-};
-
-static const struct snd_soc_dapm_route base_map[] = {
-       /* Headphone connected to HP{L,R}OUT and HP{L,R}COM */
-
-       { "Headphone Jack", NULL, "HPLOUT" },
-       { "Headphone Jack", NULL, "HPLCOM" },
-       { "Headphone Jack", NULL, "HPROUT" },
-       { "Headphone Jack", NULL, "HPRCOM" },
-
-       /* ZV connected to Line1 */
-
-       { "LINE1L", NULL, "ZV" },
-       { "LINE1R", NULL, "ZV" },
-
-       /* Line In connected to Line2 */
-
-       { "LINE2L", NULL, "Line In" },
-       { "LINE2R", NULL, "Line In" },
-
-       /* Microphone connected to MIC3R and MIC_BIAS */
-
-       { "MIC3L", NULL, "Mic Jack" },
-
-       /* GSM connected to MONO_LOUT and MIC3L (in) */
-
-       { "GSM Out", NULL, "MONO_LOUT" },
-       { "MIC3L", NULL, "GSM In" },
-
-       /* Speaker is connected to LINEOUT{LN,LP,RN,RP}, however we are
-        * not using the DAPM to power it up and down as there it makes
-        * a click when powering up. */
-};
-
-/**
- * simtec_hermes_init - initialise and add controls
- * @codec; The codec instance to attach to.
- *
- * Attach our controls and configure the necessary codec
- * mappings for our sound card instance.
-*/
-static int simtec_hermes_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-
-       snd_soc_dapm_new_controls(codec, dapm_widgets,
-                                 ARRAY_SIZE(dapm_widgets));
-
-       snd_soc_dapm_add_routes(codec, base_map, ARRAY_SIZE(base_map));
-
-       snd_soc_dapm_enable_pin(codec, "Headphone Jack");
-       snd_soc_dapm_enable_pin(codec, "Line In");
-       snd_soc_dapm_enable_pin(codec, "Line Out");
-       snd_soc_dapm_enable_pin(codec, "Mic Jack");
-
-       simtec_audio_init(rtd);
-       snd_soc_dapm_sync(codec);
-
-       return 0;
-}
-
-static struct snd_soc_dai_link simtec_dai_aic33 = {
-       .name           = "tlv320aic33",
-       .stream_name    = "TLV320AIC33",
-       .codec_name     = "tlv320aic3x-codec.0-0x1a",
-       .cpu_dai_name   = "s3c24xx-i2s",
-       .codec_dai_name = "tlv320aic3x-hifi",
-       .platform_name  = "s3c24xx-pcm-audio",
-       .init           = simtec_hermes_init,
-};
-
-/* simtec audio machine driver */
-static struct snd_soc_card snd_soc_machine_simtec_aic33 = {
-       .name           = "Simtec-Hermes",
-       .dai_link       = &simtec_dai_aic33,
-       .num_links      = 1,
-};
-
-static int __devinit simtec_audio_hermes_probe(struct platform_device *pd)
-{
-       dev_info(&pd->dev, "probing....\n");
-       return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic33);
-}
-
-static struct platform_driver simtec_audio_hermes_platdrv = {
-       .driver = {
-               .owner  = THIS_MODULE,
-               .name   = "s3c24xx-simtec-hermes-snd",
-               .pm     = simtec_audio_pm,
-       },
-       .probe  = simtec_audio_hermes_probe,
-       .remove = __devexit_p(simtec_audio_remove),
-};
-
-MODULE_ALIAS("platform:s3c24xx-simtec-hermes-snd");
-
-static int __init simtec_hermes_modinit(void)
-{
-       return platform_driver_register(&simtec_audio_hermes_platdrv);
-}
-
-static void __exit simtec_hermes_modexit(void)
-{
-       platform_driver_unregister(&simtec_audio_hermes_platdrv);
-}
-
-module_init(simtec_hermes_modinit);
-module_exit(simtec_hermes_modexit);
-
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_DESCRIPTION("ALSA SoC Simtec Audio support");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
deleted file mode 100644 (file)
index c096759..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/* sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
- *
- * Copyright 2009 Simtec Electronics
- *
- * 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/clk.h>
-#include <linux/platform_device.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include <plat/audio-simtec.h>
-
-#include "s3c-dma.h"
-#include "s3c24xx-i2s.h"
-#include "s3c24xx_simtec.h"
-
-#include "../codecs/tlv320aic23.h"
-
-/* supported machines:
- *
- * Machine     Connections             AMP
- * -------     -----------             ---
- * BAST                MIC, HPOUT, LOUT, LIN   TPA2001D1 (HPOUTL,R) (gain hardwired)
- * VR1000      HPOUT, LIN              None
- * VR2000      LIN, LOUT, MIC, HP      LM4871 (HPOUTL,R)
- * DePicture   LIN, LOUT, MIC, HP      LM4871 (HPOUTL,R)
- * Anubis      LIN, LOUT, MIC, HP      TPA2001D1 (HPOUTL,R)
- */
-
-static const struct snd_soc_dapm_widget dapm_widgets[] = {
-       SND_SOC_DAPM_HP("Headphone Jack", NULL),
-       SND_SOC_DAPM_LINE("Line In", NULL),
-       SND_SOC_DAPM_LINE("Line Out", NULL),
-       SND_SOC_DAPM_MIC("Mic Jack", NULL),
-};
-
-static const struct snd_soc_dapm_route base_map[] = {
-       { "Headphone Jack", NULL, "LHPOUT"},
-       { "Headphone Jack", NULL, "RHPOUT"},
-
-       { "Line Out", NULL, "LOUT" },
-       { "Line Out", NULL, "ROUT" },
-
-       { "LLINEIN", NULL, "Line In"},
-       { "RLINEIN", NULL, "Line In"},
-
-       { "MICIN", NULL, "Mic Jack"},
-};
-
-/**
- * simtec_tlv320aic23_init - initialise and add controls
- * @codec; The codec instance to attach to.
- *
- * Attach our controls and configure the necessary codec
- * mappings for our sound card instance.
-*/
-static int simtec_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-
-       snd_soc_dapm_new_controls(codec, dapm_widgets,
-                                 ARRAY_SIZE(dapm_widgets));
-
-       snd_soc_dapm_add_routes(codec, base_map, ARRAY_SIZE(base_map));
-
-       snd_soc_dapm_enable_pin(codec, "Headphone Jack");
-       snd_soc_dapm_enable_pin(codec, "Line In");
-       snd_soc_dapm_enable_pin(codec, "Line Out");
-       snd_soc_dapm_enable_pin(codec, "Mic Jack");
-
-       simtec_audio_init(rtd);
-       snd_soc_dapm_sync(codec);
-
-       return 0;
-}
-
-static struct snd_soc_dai_link simtec_dai_aic23 = {
-       .name           = "tlv320aic23",
-       .stream_name    = "TLV320AIC23",
-       .codec_name     = "tlv320aic3x-codec.0-0x1a",
-       .cpu_dai_name   = "s3c24xx-i2s",
-       .codec_dai_name = "tlv320aic3x-hifi",
-       .platform_name  = "s3c24xx-pcm-audio",
-       .init           = simtec_tlv320aic23_init,
-};
-
-/* simtec audio machine driver */
-static struct snd_soc_card snd_soc_machine_simtec_aic23 = {
-       .name           = "Simtec",
-       .dai_link       = &simtec_dai_aic23,
-       .num_links      = 1,
-};
-
-static int __devinit simtec_audio_tlv320aic23_probe(struct platform_device *pd)
-{
-       return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic23);
-}
-
-static struct platform_driver simtec_audio_tlv320aic23_platdrv = {
-       .driver = {
-               .owner  = THIS_MODULE,
-               .name   = "s3c24xx-simtec-tlv320aic23",
-               .pm     = simtec_audio_pm,
-       },
-       .probe  = simtec_audio_tlv320aic23_probe,
-       .remove = __devexit_p(simtec_audio_remove),
-};
-
-MODULE_ALIAS("platform:s3c24xx-simtec-tlv320aic23");
-
-static int __init simtec_tlv320aic23_modinit(void)
-{
-       return platform_driver_register(&simtec_audio_tlv320aic23_platdrv);
-}
-
-static void __exit simtec_tlv320aic23_modexit(void)
-{
-       platform_driver_unregister(&simtec_audio_tlv320aic23_platdrv);
-}
-
-module_init(simtec_tlv320aic23_modinit);
-module_exit(simtec_tlv320aic23_modexit);
-
-MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_DESCRIPTION("ALSA SoC Simtec Audio support");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c
deleted file mode 100644 (file)
index bd48ffb..0000000
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * Modifications by Christian Pellegrin <chripell@evolware.org>
- *
- * s3c24xx_uda134x.c  --  S3C24XX_UDA134X ALSA SoC Audio board driver
- *
- * Copyright 2007 Dension Audio Systems Ltd.
- * Author: Zoltan Devai
- *
- * 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/clk.h>
-#include <linux/mutex.h>
-#include <linux/gpio.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-#include <sound/s3c24xx_uda134x.h>
-#include <sound/uda134x.h>
-
-#include <plat/regs-iis.h>
-
-#include "s3c-dma.h"
-#include "s3c24xx-i2s.h"
-#include "../codecs/uda134x.h"
-
-
-/* #define ENFORCE_RATES 1 */
-/*
-  Unfortunately the S3C24XX in master mode has a limited capacity of
-  generating the clock for the codec. If you define this only rates
-  that are really available will be enforced. But be careful, most
-  user level application just want the usual sampling frequencies (8,
-  11.025, 22.050, 44.1 kHz) and anyway resampling is a costly
-  operation for embedded systems. So if you aren't very lucky or your
-  hardware engineer wasn't very forward-looking it's better to leave
-  this undefined. If you do so an approximate value for the requested
-  sampling rate in the range -/+ 5% will be chosen. If this in not
-  possible an error will be returned.
-*/
-
-static struct clk *xtal;
-static struct clk *pclk;
-/* this is need because we don't have a place where to keep the
- * pointers to the clocks in each substream. We get the clocks only
- * when we are actually using them so we don't block stuff like
- * frequency change or oscillator power-off */
-static int clk_users;
-static DEFINE_MUTEX(clk_lock);
-
-static unsigned int rates[33 * 2];
-#ifdef ENFORCE_RATES
-static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
-       .count  = ARRAY_SIZE(rates),
-       .list   = rates,
-       .mask   = 0,
-};
-#endif
-
-static struct platform_device *s3c24xx_uda134x_snd_device;
-
-static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
-{
-       int ret = 0;
-#ifdef ENFORCE_RATES
-       struct snd_pcm_runtime *runtime = substream->runtime;
-#endif
-
-       mutex_lock(&clk_lock);
-       pr_debug("%s %d\n", __func__, clk_users);
-       if (clk_users == 0) {
-               xtal = clk_get(&s3c24xx_uda134x_snd_device->dev, "xtal");
-               if (!xtal) {
-                       printk(KERN_ERR "%s cannot get xtal\n", __func__);
-                       ret = -EBUSY;
-               } else {
-                       pclk = clk_get(&s3c24xx_uda134x_snd_device->dev,
-                                      "pclk");
-                       if (!pclk) {
-                               printk(KERN_ERR "%s cannot get pclk\n",
-                                      __func__);
-                               clk_put(xtal);
-                               ret = -EBUSY;
-                       }
-               }
-               if (!ret) {
-                       int i, j;
-
-                       for (i = 0; i < 2; i++) {
-                               int fs = i ? 256 : 384;
-
-                               rates[i*33] = clk_get_rate(xtal) / fs;
-                               for (j = 1; j < 33; j++)
-                                       rates[i*33 + j] = clk_get_rate(pclk) /
-                                               (j * fs);
-                       }
-               }
-       }
-       clk_users += 1;
-       mutex_unlock(&clk_lock);
-       if (!ret) {
-#ifdef ENFORCE_RATES
-               ret = snd_pcm_hw_constraint_list(runtime, 0,
-                                                SNDRV_PCM_HW_PARAM_RATE,
-                                                &hw_constraints_rates);
-               if (ret < 0)
-                       printk(KERN_ERR "%s cannot set constraints\n",
-                              __func__);
-#endif
-       }
-       return ret;
-}
-
-static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream)
-{
-       mutex_lock(&clk_lock);
-       pr_debug("%s %d\n", __func__, clk_users);
-       clk_users -= 1;
-       if (clk_users == 0) {
-               clk_put(xtal);
-               xtal = NULL;
-               clk_put(pclk);
-               pclk = NULL;
-       }
-       mutex_unlock(&clk_lock);
-}
-
-static int s3c24xx_uda134x_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;
-       unsigned int clk = 0;
-       int ret = 0;
-       int clk_source, fs_mode;
-       unsigned long rate = params_rate(params);
-       long err, cerr;
-       unsigned int div;
-       int i, bi;
-
-       err = 999999;
-       bi = 0;
-       for (i = 0; i < 2*33; i++) {
-               cerr = rates[i] - rate;
-               if (cerr < 0)
-                       cerr = -cerr;
-               if (cerr < err) {
-                       err = cerr;
-                       bi = i;
-               }
-       }
-       if (bi / 33 == 1)
-               fs_mode = S3C2410_IISMOD_256FS;
-       else
-               fs_mode = S3C2410_IISMOD_384FS;
-       if (bi % 33 == 0) {
-               clk_source = S3C24XX_CLKSRC_MPLL;
-               div = 1;
-       } else {
-               clk_source = S3C24XX_CLKSRC_PCLK;
-               div = bi % 33;
-       }
-       pr_debug("%s desired rate %lu, %d\n", __func__, rate, bi);
-
-       clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate;
-       pr_debug("%s will use: %s %s %d sysclk %d err %ld\n", __func__,
-                fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS",
-                clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK",
-                div, clk, err);
-
-       if ((err * 100 / rate) > 5) {
-               printk(KERN_ERR "S3C24XX_UDA134X: effective frequency "
-                      "too different from desired (%ld%%)\n",
-                      err * 100 / rate);
-               return -EINVAL;
-       }
-
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk,
-                       SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, fs_mode);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
-                       S3C2410_IISMOD_32FS);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
-                       S3C24XX_PRESCALE(div, div));
-       if (ret < 0)
-               return ret;
-
-       /* set the codec system clock for DAC and ADC */
-       ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
-                       SND_SOC_CLOCK_OUT);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static struct snd_soc_ops s3c24xx_uda134x_ops = {
-       .startup = s3c24xx_uda134x_startup,
-       .shutdown = s3c24xx_uda134x_shutdown,
-       .hw_params = s3c24xx_uda134x_hw_params,
-};
-
-static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
-       .name = "UDA134X",
-       .stream_name = "UDA134X",
-       .codec_name = "uda134x-hifi",
-       .codec_dai_name = "uda134x-hifi",
-       .cpu_dai_name = "s3c24xx-i2s",
-       .ops = &s3c24xx_uda134x_ops,
-       .platform_name  = "s3c24xx-pcm-audio",
-};
-
-static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
-       .name = "S3C24XX_UDA134X",
-       .dai_link = &s3c24xx_uda134x_dai_link,
-       .num_links = 1,
-};
-
-static struct s3c24xx_uda134x_platform_data *s3c24xx_uda134x_l3_pins;
-
-static void setdat(int v)
-{
-       gpio_set_value(s3c24xx_uda134x_l3_pins->l3_data, v > 0);
-}
-
-static void setclk(int v)
-{
-       gpio_set_value(s3c24xx_uda134x_l3_pins->l3_clk, v > 0);
-}
-
-static void setmode(int v)
-{
-       gpio_set_value(s3c24xx_uda134x_l3_pins->l3_mode, v > 0);
-}
-
-/* FIXME - This must be codec platform data but in which board file ?? */
-static struct uda134x_platform_data s3c24xx_uda134x = {
-       .l3 = {
-               .setdat = setdat,
-               .setclk = setclk,
-               .setmode = setmode,
-               .data_hold = 1,
-               .data_setup = 1,
-               .clock_high = 1,
-               .mode_hold = 1,
-               .mode = 1,
-               .mode_setup = 1,
-       },
-};
-
-static int s3c24xx_uda134x_setup_pin(int pin, char *fun)
-{
-       if (gpio_request(pin, "s3c24xx_uda134x") < 0) {
-               printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
-                      "l3 %s pin already in use", fun);
-               return -EBUSY;
-       }
-       gpio_direction_output(pin, 0);
-       return 0;
-}
-
-static int s3c24xx_uda134x_probe(struct platform_device *pdev)
-{
-       int ret;
-
-       printk(KERN_INFO "S3C24XX_UDA134X SoC Audio driver\n");
-
-       s3c24xx_uda134x_l3_pins = pdev->dev.platform_data;
-       if (s3c24xx_uda134x_l3_pins == NULL) {
-               printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
-                      "unable to find platform data\n");
-               return -ENODEV;
-       }
-       s3c24xx_uda134x.power = s3c24xx_uda134x_l3_pins->power;
-       s3c24xx_uda134x.model = s3c24xx_uda134x_l3_pins->model;
-
-       if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_data,
-                                     "data") < 0)
-               return -EBUSY;
-       if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_clk,
-                                     "clk") < 0) {
-               gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
-               return -EBUSY;
-       }
-       if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_mode,
-                                     "mode") < 0) {
-               gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
-               gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
-               return -EBUSY;
-       }
-
-       s3c24xx_uda134x_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!s3c24xx_uda134x_snd_device) {
-               printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
-                      "Unable to register\n");
-               return -ENOMEM;
-       }
-
-       platform_set_drvdata(s3c24xx_uda134x_snd_device,
-                            &snd_soc_s3c24xx_uda134x);
-       ret = platform_device_add(s3c24xx_uda134x_snd_device);
-       if (ret) {
-               printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n");
-               platform_device_put(s3c24xx_uda134x_snd_device);
-       }
-
-       return ret;
-}
-
-static int s3c24xx_uda134x_remove(struct platform_device *pdev)
-{
-       platform_device_unregister(s3c24xx_uda134x_snd_device);
-       gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
-       gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
-       gpio_free(s3c24xx_uda134x_l3_pins->l3_mode);
-       return 0;
-}
-
-static struct platform_driver s3c24xx_uda134x_driver = {
-       .probe  = s3c24xx_uda134x_probe,
-       .remove = s3c24xx_uda134x_remove,
-       .driver = {
-               .name = "s3c24xx_uda134x",
-               .owner = THIS_MODULE,
-       },
-};
-
-static int __init s3c24xx_uda134x_init(void)
-{
-       return platform_driver_register(&s3c24xx_uda134x_driver);
-}
-
-static void __exit s3c24xx_uda134x_exit(void)
-{
-       platform_driver_unregister(&s3c24xx_uda134x_driver);
-}
-
-
-module_init(s3c24xx_uda134x_init);
-module_exit(s3c24xx_uda134x_exit);
-
-MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
-MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s-v4.c b/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
deleted file mode 100644 (file)
index a962847..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-/* sound/soc/s3c24xx/s3c64xx-i2s-v4.c
- *
- * ALSA SoC Audio Layer - S3C64XX I2Sv4 driver
- * Copyright (c) 2010 Samsung Electronics Co. Ltd
- *     Author: Jaswinder Singh <jassi.brar@samsung.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/clk.h>
-#include <linux/gpio.h>
-#include <linux/io.h>
-
-#include <sound/soc.h>
-#include <sound/pcm_params.h>
-
-#include <plat/audio.h>
-
-#include <mach/map.h>
-#include <mach/dma.h>
-
-#include "s3c-dma.h"
-#include "regs-i2s-v2.h"
-#include "s3c64xx-i2s.h"
-
-static struct s3c2410_dma_client s3c64xx_dma_client_out = {
-       .name           = "I2Sv4 PCM Stereo out"
-};
-
-static struct s3c2410_dma_client s3c64xx_dma_client_in = {
-       .name           = "I2Sv4 PCM Stereo in"
-};
-
-static struct s3c_dma_params s3c64xx_i2sv4_pcm_stereo_out;
-static struct s3c_dma_params s3c64xx_i2sv4_pcm_stereo_in;
-static struct s3c_i2sv2_info s3c64xx_i2sv4;
-
-static int s3c64xx_i2sv4_probe(struct snd_soc_dai *dai)
-{
-       struct s3c_i2sv2_info *i2s = &s3c64xx_i2sv4;
-       int ret = 0;
-
-       snd_soc_dai_set_drvdata(dai, i2s);
-
-       ret = s3c_i2sv2_probe(dai, i2s, i2s->base);
-
-       return ret;
-}
-
-static int s3c_i2sv4_hw_params(struct snd_pcm_substream *substream,
-                                struct snd_pcm_hw_params *params,
-                                struct snd_soc_dai *cpu_dai)
-{
-       struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(cpu_dai);
-       struct s3c_dma_params *dma_data;
-       u32 iismod;
-
-       dev_dbg(cpu_dai->dev, "Entered %s\n", __func__);
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               dma_data = i2s->dma_playback;
-       else
-               dma_data = i2s->dma_capture;
-
-       snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
-
-       iismod = readl(i2s->regs + S3C2412_IISMOD);
-       dev_dbg(cpu_dai->dev, "%s: r: IISMOD: %x\n", __func__, iismod);
-
-       iismod &= ~S3C64XX_IISMOD_BLC_MASK;
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S8:
-               iismod |= S3C64XX_IISMOD_BLC_8BIT;
-               break;
-       case SNDRV_PCM_FORMAT_S16_LE:
-               break;
-       case SNDRV_PCM_FORMAT_S24_LE:
-               iismod |= S3C64XX_IISMOD_BLC_24BIT;
-               break;
-       }
-
-       writel(iismod, i2s->regs + S3C2412_IISMOD);
-       dev_dbg(cpu_dai->dev, "%s: w: IISMOD: %x\n", __func__, iismod);
-
-       return 0;
-}
-
-static struct snd_soc_dai_ops s3c64xx_i2sv4_dai_ops = {
-       .hw_params      = s3c_i2sv4_hw_params,
-};
-
-static struct snd_soc_dai_driver s3c64xx_i2s_v4_dai = {
-       .symmetric_rates = 1,
-       .playback = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = S3C64XX_I2S_RATES,
-               .formats = S3C64XX_I2S_FMTS,
-       },
-       .capture = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = S3C64XX_I2S_RATES,
-               .formats = S3C64XX_I2S_FMTS,
-       },
-       .probe = s3c64xx_i2sv4_probe,
-       .ops = &s3c64xx_i2sv4_dai_ops,
-};
-
-static __devinit int s3c64xx_i2sv4_dev_probe(struct platform_device *pdev)
-{
-       struct s3c_audio_pdata *i2s_pdata;
-       struct s3c_i2sv2_info *i2s;
-       struct resource *res;
-       int ret;
-
-       i2s = &s3c64xx_i2sv4;
-
-       i2s->feature |= S3C_FEATURE_CDCLKCON;
-
-       i2s->dma_capture = &s3c64xx_i2sv4_pcm_stereo_in;
-       i2s->dma_playback = &s3c64xx_i2sv4_pcm_stereo_out;
-
-       res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n");
-               return -ENXIO;
-       }
-       i2s->dma_playback->channel = res->start;
-
-       res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-       if (!res) {
-               dev_err(&pdev->dev, "Unable to get I2S-RX dma resource\n");
-               return -ENXIO;
-       }
-       i2s->dma_capture->channel = res->start;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "Unable to get I2S SFR address\n");
-               return -ENXIO;
-       }
-
-       if (!request_mem_region(res->start, resource_size(res),
-                               "s3c64xx-i2s-v4")) {
-               dev_err(&pdev->dev, "Unable to request SFR region\n");
-               return -EBUSY;
-       }
-       i2s->dma_capture->dma_addr = res->start + S3C2412_IISRXD;
-       i2s->dma_playback->dma_addr = res->start + S3C2412_IISTXD;
-
-       i2s->dma_capture->client = &s3c64xx_dma_client_in;
-       i2s->dma_capture->dma_size = 4;
-       i2s->dma_playback->client = &s3c64xx_dma_client_out;
-       i2s->dma_playback->dma_size = 4;
-
-       i2s->base = res->start;
-
-       i2s_pdata = pdev->dev.platform_data;
-       if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
-               dev_err(&pdev->dev, "Unable to configure gpio\n");
-               return -EINVAL;
-       }
-
-       i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus");
-       if (IS_ERR(i2s->iis_cclk)) {
-               dev_err(&pdev->dev, "failed to get audio-bus\n");
-               ret = PTR_ERR(i2s->iis_cclk);
-               goto err;
-       }
-
-       clk_enable(i2s->iis_cclk);
-
-       ret = s3c_i2sv2_register_dai(&pdev->dev, pdev->id, &s3c64xx_i2s_v4_dai);
-       if (ret != 0)
-               goto err_i2sv2;
-
-       return 0;
-
-err_i2sv2:
-       clk_put(i2s->iis_cclk);
-err:
-       return ret;
-}
-
-static __devexit int s3c64xx_i2sv4_dev_remove(struct platform_device *pdev)
-{
-       struct s3c_i2sv2_info *i2s = &s3c64xx_i2sv4;
-       struct resource *res;
-
-       snd_soc_unregister_dai(&pdev->dev);
-       clk_put(i2s->iis_cclk);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res)
-               release_mem_region(res->start, resource_size(res));
-       else
-               dev_warn(&pdev->dev, "Unable to get I2S SFR address\n");
-               
-       return 0;
-}
-
-static struct platform_driver s3c64xx_i2sv4_driver = {
-       .probe  = s3c64xx_i2sv4_dev_probe,
-       .remove = s3c64xx_i2sv4_dev_remove,
-       .driver = {
-               .name = "s3c64xx-iis-v4",
-               .owner = THIS_MODULE,
-       },
-};
-
-static int __init s3c64xx_i2sv4_init(void)
-{
-       return platform_driver_register(&s3c64xx_i2sv4_driver);
-}
-module_init(s3c64xx_i2sv4_init);
-
-static void __exit s3c64xx_i2sv4_exit(void)
-{
-       platform_driver_unregister(&s3c64xx_i2sv4_driver);
-}
-module_exit(s3c64xx_i2sv4_exit);
-
-/* Module information */
-MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
-MODULE_DESCRIPTION("S3C64XX I2Sv4 SoC Interface");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s3c64xx-iis-v4");
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c
deleted file mode 100644 (file)
index ae7acb6..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/* sound/soc/s3c24xx/s3c64xx-i2s.c
- *
- * ALSA SoC Audio Layer - S3C64XX I2S driver
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *      Ben Dooks <ben@simtec.co.uk>
- *      http://armlinux.simtec.co.uk/
- *
- * 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/clk.h>
-#include <linux/gpio.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-
-#include <sound/soc.h>
-
-#include <plat/audio.h>
-
-#include <mach/map.h>
-#include <mach/dma.h>
-
-#include "s3c-dma.h"
-#include "regs-i2s-v2.h"
-#include "s3c64xx-i2s.h"
-
-/* The value should be set to maximum of the total number
- * of I2Sv3 controllers that any supported SoC has.
- */
-#define MAX_I2SV3      2
-
-static struct s3c2410_dma_client s3c64xx_dma_client_out = {
-       .name           = "I2S PCM Stereo out"
-};
-
-static struct s3c2410_dma_client s3c64xx_dma_client_in = {
-       .name           = "I2S PCM Stereo in"
-};
-
-static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_out[MAX_I2SV3];
-static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_in[MAX_I2SV3];
-static struct s3c_i2sv2_info s3c64xx_i2s[MAX_I2SV3];
-
-struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai)
-{
-       struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(dai);
-       u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
-
-       if (iismod & S3C2412_IISMOD_IMS_SYSMUX)
-               return i2s->iis_cclk;
-       else
-               return i2s->iis_pclk;
-}
-EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock);
-
-static int s3c64xx_i2s_probe(struct snd_soc_dai *dai)
-{
-       struct s3c_i2sv2_info *i2s;
-       int ret;
-
-       if (dai->id >= MAX_I2SV3) {
-               dev_err(dai->dev, "id %d out of range\n", dai->id);
-               return -EINVAL;
-       }
-
-       i2s = &s3c64xx_i2s[dai->id];
-       snd_soc_dai_set_drvdata(dai, i2s);
-
-       i2s->iis_cclk = clk_get(dai->dev, "audio-bus");
-       if (IS_ERR(i2s->iis_cclk)) {
-               dev_err(dai->dev, "failed to get audio-bus\n");
-               ret = PTR_ERR(i2s->iis_cclk);
-               goto err;
-       }
-
-       clk_enable(i2s->iis_cclk);
-
-       ret = s3c_i2sv2_probe(dai, i2s, i2s->base);
-       if (ret)
-               goto err_clk;
-
-       return 0;
-
-err_clk:
-       clk_disable(i2s->iis_cclk);
-       clk_put(i2s->iis_cclk);
-err:
-       kfree(i2s);
-       return ret;
-}
-
-static int s3c64xx_i2s_remove(struct snd_soc_dai *dai)
-{
-       struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(dai);
-
-       clk_disable(i2s->iis_cclk);
-       clk_put(i2s->iis_cclk);
-       kfree(i2s);
-       return 0;
-}
-
-static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops;
-
-static struct snd_soc_dai_driver s3c64xx_i2s_dai[MAX_I2SV3] = {
-{
-       .name = "s3c64xx-i2s-0",
-       .probe = s3c64xx_i2s_probe,
-       .remove = s3c64xx_i2s_remove,
-       .playback = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = S3C64XX_I2S_RATES,
-               .formats = S3C64XX_I2S_FMTS,},
-       .capture = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = S3C64XX_I2S_RATES,
-               .formats = S3C64XX_I2S_FMTS,},
-       .ops = &s3c64xx_i2s_dai_ops,
-       .symmetric_rates = 1,
-}, {
-       .name = "s3c64xx-i2s-1",
-       .probe = s3c64xx_i2s_probe,
-       .remove = s3c64xx_i2s_remove,
-       .playback = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = S3C64XX_I2S_RATES,
-               .formats = S3C64XX_I2S_FMTS,},
-       .capture = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = S3C64XX_I2S_RATES,
-               .formats = S3C64XX_I2S_FMTS,},
-       .ops = &s3c64xx_i2s_dai_ops,
-       .symmetric_rates = 1,
-},};
-
-static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev)
-{
-       struct s3c_audio_pdata *i2s_pdata;
-       struct s3c_i2sv2_info *i2s;
-       struct resource *res;
-       int i, ret;
-
-       if (pdev->id >= MAX_I2SV3) {
-               dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
-               return -EINVAL;
-       }
-
-       i2s = &s3c64xx_i2s[pdev->id];
-
-       i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id];
-       i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id];
-
-       res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n");
-               return -ENXIO;
-       }
-       i2s->dma_playback->channel = res->start;
-
-       res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-       if (!res) {
-               dev_err(&pdev->dev, "Unable to get I2S-RX dma resource\n");
-               return -ENXIO;
-       }
-       i2s->dma_capture->channel = res->start;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "Unable to get I2S SFR address\n");
-               return -ENXIO;
-       }
-
-       if (!request_mem_region(res->start, resource_size(res),
-                               "s3c64xx-i2s")) {
-               dev_err(&pdev->dev, "Unable to request SFR region\n");
-               return -EBUSY;
-       }
-       i2s->base = res->start;
-
-       i2s_pdata = pdev->dev.platform_data;
-       if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
-               dev_err(&pdev->dev, "Unable to configure gpio\n");
-               return -EINVAL;
-       }
-       i2s->dma_capture->dma_addr = res->start + S3C2412_IISRXD;
-       i2s->dma_playback->dma_addr = res->start + S3C2412_IISTXD;
-
-       i2s->dma_capture->client = &s3c64xx_dma_client_in;
-       i2s->dma_capture->dma_size = 4;
-       i2s->dma_playback->client = &s3c64xx_dma_client_out;
-       i2s->dma_playback->dma_size = 4;
-
-       for (i = 0; i < ARRAY_SIZE(s3c64xx_i2s_dai); i++) {
-               ret = s3c_i2sv2_register_dai(&pdev->dev, i,
-                                               &s3c64xx_i2s_dai[i]);
-               if (ret != 0)
-                       return ret;
-       }
-
-       return 0;
-}
-
-static __devexit int s3c64xx_iis_dev_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c64xx_i2s_dai));
-       return 0;
-}
-
-static struct platform_driver s3c64xx_iis_driver = {
-       .probe  = s3c64xx_iis_dev_probe,
-       .remove = s3c64xx_iis_dev_remove,
-       .driver = {
-               .name = "s3c64xx-iis",
-               .owner = THIS_MODULE,
-       },
-};
-
-static int __init s3c64xx_i2s_init(void)
-{
-       return platform_driver_register(&s3c64xx_iis_driver);
-}
-module_init(s3c64xx_i2s_init);
-
-static void __exit s3c64xx_i2s_exit(void)
-{
-       platform_driver_unregister(&s3c64xx_iis_driver);
-}
-module_exit(s3c64xx_i2s_exit);
-
-/* Module information */
-MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
-MODULE_DESCRIPTION("S3C64XX I2S SoC Interface");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s3c64xx-iis");
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h
deleted file mode 100644 (file)
index de4075d..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* sound/soc/s3c24xx/s3c64xx-i2s.h
- *
- * ALSA SoC Audio Layer - S3C64XX I2S driver
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *      Ben Dooks <ben@simtec.co.uk>
- *      http://armlinux.simtec.co.uk/
- *
- * 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 __SND_SOC_S3C24XX_S3C64XX_I2S_H
-#define __SND_SOC_S3C24XX_S3C64XX_I2S_H __FILE__
-
-struct clk;
-
-#include "s3c-i2s-v2.h"
-
-#define S3C64XX_DIV_BCLK       S3C_I2SV2_DIV_BCLK
-#define S3C64XX_DIV_RCLK       S3C_I2SV2_DIV_RCLK
-#define S3C64XX_DIV_PRESCALER  S3C_I2SV2_DIV_PRESCALER
-
-#define S3C64XX_CLKSRC_PCLK    S3C_I2SV2_CLKSRC_PCLK
-#define S3C64XX_CLKSRC_MUX     S3C_I2SV2_CLKSRC_AUDIOBUS
-#define S3C64XX_CLKSRC_CDCLK    S3C_I2SV2_CLKSRC_CDCLK
-
-#define S3C64XX_I2S_RATES \
-       (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
-       SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
-       SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
-
-#define S3C64XX_I2S_FMTS \
-       (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
-        SNDRV_PCM_FMTBIT_S24_LE)
-
-struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai);
-
-#endif /* __SND_SOC_S3C24XX_S3C64XX_I2S_H */
diff --git a/sound/soc/s3c24xx/smartq_wm8987.c b/sound/soc/s3c24xx/smartq_wm8987.c
deleted file mode 100644 (file)
index dd20ca7..0000000
+++ /dev/null
@@ -1,290 +0,0 @@
-/* sound/soc/s3c24xx/smartq_wm8987.c
- *
- * Copyright 2010 Maurus Cuelenaere <mcuelenaere@gmail.com>
- *
- * Based on smdk6410_wm8987.c
- *     Copyright 2007 Wolfson Microelectronics PLC. - linux@wolfsonmicro.com
- *     Graeme Gregory - graeme.gregory@wolfsonmicro.com
- *
- *  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/platform_device.h>
-#include <linux/gpio.h>
-
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc-dapm.h>
-#include <sound/jack.h>
-
-#include <asm/mach-types.h>
-
-#include "s3c-dma.h"
-#include "s3c64xx-i2s.h"
-
-#include "../codecs/wm8750.h"
-
-/*
- * WM8987 is register compatible with WM8750, so using that as base driver.
- */
-
-static struct snd_soc_card snd_soc_smartq;
-
-static int smartq_hifi_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->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct s3c_i2sv2_rate_calc div;
-       unsigned int clk = 0;
-       int ret;
-
-       s3c_i2sv2_iis_calc_rate(&div, NULL, params_rate(params),
-                               s3c_i2sv2_get_clock(cpu_dai));
-
-       switch (params_rate(params)) {
-       case 8000:
-       case 16000:
-       case 32000:
-       case 48000:
-       case 96000:
-               clk = 12288000;
-               break;
-       case 11025:
-       case 22050:
-       case 44100:
-       case 88200:
-               clk = 11289600;
-               break;
-       }
-
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                                            SND_SOC_DAIFMT_NB_NF |
-                                            SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                                          SND_SOC_DAIFMT_NB_NF |
-                                          SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set the codec system clock for DAC and ADC */
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
-                                    SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       /* set MCLK division for sample rate */
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_RCLK, div.fs_div);
-       if (ret < 0)
-               return ret;
-
-       /* set prescaler division for sample rate */
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_PRESCALER,
-                                    div.clk_div - 1);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-/*
- * SmartQ WM8987 HiFi DAI operations.
- */
-static struct snd_soc_ops smartq_hifi_ops = {
-       .hw_params = smartq_hifi_hw_params,
-};
-
-static struct snd_soc_jack smartq_jack;
-
-static struct snd_soc_jack_pin smartq_jack_pins[] = {
-       /* Disable speaker when headphone is plugged in */
-       {
-               .pin    = "Internal Speaker",
-               .mask   = SND_JACK_HEADPHONE,
-       },
-};
-
-static struct snd_soc_jack_gpio smartq_jack_gpios[] = {
-       {
-               .gpio           = S3C64XX_GPL(12),
-               .name           = "headphone detect",
-               .report         = SND_JACK_HEADPHONE,
-               .debounce_time  = 200,
-       },
-};
-
-static const struct snd_kcontrol_new wm8987_smartq_controls[] = {
-       SOC_DAPM_PIN_SWITCH("Internal Speaker"),
-       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
-       SOC_DAPM_PIN_SWITCH("Internal Mic"),
-};
-
-static int smartq_speaker_event(struct snd_soc_dapm_widget *w,
-                               struct snd_kcontrol *k,
-                               int event)
-{
-       gpio_set_value(S3C64XX_GPK(12), SND_SOC_DAPM_EVENT_OFF(event));
-
-       return 0;
-}
-
-static const struct snd_soc_dapm_widget wm8987_dapm_widgets[] = {
-       SND_SOC_DAPM_SPK("Internal Speaker", smartq_speaker_event),
-       SND_SOC_DAPM_HP("Headphone Jack", NULL),
-       SND_SOC_DAPM_MIC("Internal Mic", NULL),
-};
-
-static const struct snd_soc_dapm_route audio_map[] = {
-       {"Headphone Jack", NULL, "LOUT2"},
-       {"Headphone Jack", NULL, "ROUT2"},
-
-       {"Internal Speaker", NULL, "LOUT2"},
-       {"Internal Speaker", NULL, "ROUT2"},
-
-       {"Mic Bias", NULL, "Internal Mic"},
-       {"LINPUT2", NULL, "Mic Bias"},
-};
-
-static int smartq_wm8987_init(struct snd_soc_codec *codec)
-{
-       int err = 0;
-
-       /* Add SmartQ specific widgets */
-       snd_soc_dapm_new_controls(codec, wm8987_dapm_widgets,
-                                 ARRAY_SIZE(wm8987_dapm_widgets));
-
-       /* add SmartQ specific controls */
-       err = snd_soc_add_controls(codec, wm8987_smartq_controls,
-                                  ARRAY_SIZE(wm8987_smartq_controls));
-
-       if (err < 0)
-               return err;
-
-       /* setup SmartQ specific audio path */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
-
-       /* set endpoints to not connected */
-       snd_soc_dapm_nc_pin(codec, "LINPUT1");
-       snd_soc_dapm_nc_pin(codec, "RINPUT1");
-       snd_soc_dapm_nc_pin(codec, "OUT3");
-       snd_soc_dapm_nc_pin(codec, "ROUT1");
-
-       /* set endpoints to default off mode */
-       snd_soc_dapm_enable_pin(codec, "Internal Speaker");
-       snd_soc_dapm_enable_pin(codec, "Internal Mic");
-       snd_soc_dapm_disable_pin(codec, "Headphone Jack");
-
-       err = snd_soc_dapm_sync(codec);
-       if (err)
-               return err;
-
-       /* Headphone jack detection */
-       err = snd_soc_jack_new(&snd_soc_smartq, "Headphone Jack",
-                              SND_JACK_HEADPHONE, &smartq_jack);
-       if (err)
-               return err;
-
-       err = snd_soc_jack_add_pins(&smartq_jack, ARRAY_SIZE(smartq_jack_pins),
-                                   smartq_jack_pins);
-       if (err)
-               return err;
-
-       err = snd_soc_jack_add_gpios(&smartq_jack,
-                                    ARRAY_SIZE(smartq_jack_gpios),
-                                    smartq_jack_gpios);
-
-       return err;
-}
-
-static struct snd_soc_dai_link smartq_dai[] = {
-       {
-               .name           = "wm8987",
-               .stream_name    = "SmartQ Hi-Fi",
-               .cpu_dai_name   = "s3c64xx-i2s.0",
-               .codec_dai_name = "wm8750-hifi",
-               .platform_name  = "s3c24xx-pcm-audio",
-               .codec_name     = "wm8750-codec.0-0x1a",
-               .init           = smartq_wm8987_init,
-               .ops            = &smartq_hifi_ops,
-       },
-};
-
-static struct snd_soc_card snd_soc_smartq = {
-       .name = "SmartQ",
-       .dai_link = smartq_dai,
-       .num_links = ARRAY_SIZE(smartq_dai),
-};
-
-static struct platform_device *smartq_snd_device;
-
-static int __init smartq_init(void)
-{
-       int ret;
-
-       if (!machine_is_smartq7() && !machine_is_smartq5()) {
-               pr_info("Only SmartQ is supported by this ASoC driver\n");
-               return -ENODEV;
-       }
-
-       smartq_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!smartq_snd_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(smartq_snd_device, &snd_soc_smartq);
-
-       ret = platform_device_add(smartq_snd_device);
-       if (ret) {
-               platform_device_put(smartq_snd_device);
-               return ret;
-       }
-
-       /* Initialise GPIOs used by amplifiers */
-       ret = gpio_request(S3C64XX_GPK(12), "amplifiers shutdown");
-       if (ret) {
-               dev_err(&smartq_snd_device->dev, "Failed to register GPK12\n");
-               goto err_unregister_device;
-       }
-
-       /* Disable amplifiers */
-       ret = gpio_direction_output(S3C64XX_GPK(12), 1);
-       if (ret) {
-               dev_err(&smartq_snd_device->dev, "Failed to configure GPK12\n");
-               goto err_free_gpio_amp_shut;
-       }
-
-       return 0;
-
-err_free_gpio_amp_shut:
-       gpio_free(S3C64XX_GPK(12));
-err_unregister_device:
-       platform_device_unregister(smartq_snd_device);
-
-       return ret;
-}
-
-static void __exit smartq_exit(void)
-{
-       snd_soc_jack_free_gpios(&smartq_jack, ARRAY_SIZE(smartq_jack_gpios),
-                               smartq_jack_gpios);
-
-       platform_device_unregister(smartq_snd_device);
-}
-
-module_init(smartq_init);
-module_exit(smartq_exit);
-
-/* Module information */
-MODULE_AUTHOR("Maurus Cuelenaere <mcuelenaere@gmail.com>");
-MODULE_DESCRIPTION("ALSA SoC SmartQ WM8987");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c
deleted file mode 100644 (file)
index 4613288..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * smdk2443_wm9710.c  --  SoC audio for smdk2443
- *
- * Copyright 2007 Wolfson Microelectronics PLC.
- * Author: Graeme Gregory
- *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
- *
- *  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/device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include "s3c-dma.h"
-#include "s3c-ac97.h"
-
-static struct snd_soc_card smdk2443;
-
-static struct snd_soc_dai_link smdk2443_dai[] = {
-{
-       .name = "AC97",
-       .stream_name = "AC97 HiFi",
-       .cpu_dai_name = "s3c-ac97",
-       .codec_dai_name = "ac97-hifi",
-       .codec_name = "ac97-codec",
-       .platform_name = "s3c24xx-pcm-audio",
-},
-};
-
-static struct snd_soc_card smdk2443 = {
-       .name = "SMDK2443",
-       .dai_link = smdk2443_dai,
-       .num_links = ARRAY_SIZE(smdk2443_dai),
-};
-
-static struct platform_device *smdk2443_snd_ac97_device;
-
-static int __init smdk2443_init(void)
-{
-       int ret;
-
-       smdk2443_snd_ac97_device = platform_device_alloc("soc-audio", -1);
-       if (!smdk2443_snd_ac97_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(smdk2443_snd_ac97_device, &smdk2443);
-       ret = platform_device_add(smdk2443_snd_ac97_device);
-
-       if (ret)
-               platform_device_put(smdk2443_snd_ac97_device);
-
-       return ret;
-}
-
-static void __exit smdk2443_exit(void)
-{
-       platform_device_unregister(smdk2443_snd_ac97_device);
-}
-
-module_init(smdk2443_init);
-module_exit(smdk2443_exit);
-
-/* Module information */
-MODULE_AUTHOR("Graeme Gregory, graeme.gregory@wolfsonmicro.com, www.wolfsonmicro.com");
-MODULE_DESCRIPTION("ALSA SoC WM9710 SMDK2443");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c
deleted file mode 100644 (file)
index 052e499..0000000
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- *  smdk64xx_wm8580.c
- *
- *  Copyright (c) 2009 Samsung Electronics Co. Ltd
- *  Author: Jaswinder Singh <jassi.brar@samsung.com>
- *
- *  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/platform_device.h>
-#include <linux/clk.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-#include <sound/soc-dapm.h>
-
-#include "../codecs/wm8580.h"
-#include "s3c-dma.h"
-#include "s3c64xx-i2s.h"
-
-/*
- * Default CFG switch settings to use this driver:
- *
- *   SMDK6410: Set CFG1 1-3 Off, CFG2 1-4 On
- */
-
-/* SMDK64XX has a 12MHZ crystal attached to WM8580 */
-#define SMDK64XX_WM8580_FREQ 12000000
-
-static int smdk64xx_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;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       unsigned int pll_out;
-       int bfs, rfs, ret;
-
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_U8:
-       case SNDRV_PCM_FORMAT_S8:
-               bfs = 16;
-               break;
-       case SNDRV_PCM_FORMAT_U16_LE:
-       case SNDRV_PCM_FORMAT_S16_LE:
-               bfs = 32;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* The Fvco for WM8580 PLLs must fall within [90,100]MHz.
-        * This criterion can't be met if we request PLL output
-        * as {8000x256, 64000x256, 11025x256}Hz.
-        * As a wayout, we rather change rfs to a minimum value that
-        * results in (params_rate(params) * rfs), and itself, acceptable
-        * to both - the CODEC and the CPU.
-        */
-       switch (params_rate(params)) {
-       case 16000:
-       case 22050:
-       case 32000:
-       case 44100:
-       case 48000:
-       case 88200:
-       case 96000:
-               rfs = 256;
-               break;
-       case 64000:
-               rfs = 384;
-               break;
-       case 8000:
-       case 11025:
-               rfs = 512;
-               break;
-       default:
-               return -EINVAL;
-       }
-       pll_out = params_rate(params) * rfs;
-
-       /* Set the Codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
-                                        | SND_SOC_DAIFMT_NB_NF
-                                        | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* Set the AP DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
-                                        | SND_SOC_DAIFMT_NB_NF
-                                        | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_CDCLK,
-                                       0, SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       /* We use PCLK for basic ops in SoC-Slave mode */
-       ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK,
-                                       0, SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       /* Set WM8580 to drive MCLK from its PLLA */
-       ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
-                                       WM8580_CLKSRC_PLLA);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
-                                       SMDK64XX_WM8580_FREQ, pll_out);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA,
-                                    pll_out, SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_BCLK, bfs);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_RCLK, rfs);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-/*
- * SMDK64XX WM8580 DAI operations.
- */
-static struct snd_soc_ops smdk64xx_ops = {
-       .hw_params = smdk64xx_hw_params,
-};
-
-/* SMDK64xx Playback widgets */
-static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = {
-       SND_SOC_DAPM_HP("Front", NULL),
-       SND_SOC_DAPM_HP("Center+Sub", NULL),
-       SND_SOC_DAPM_HP("Rear", NULL),
-};
-
-/* SMDK64xx Capture widgets */
-static const struct snd_soc_dapm_widget wm8580_dapm_widgets_cpt[] = {
-       SND_SOC_DAPM_MIC("MicIn", NULL),
-       SND_SOC_DAPM_LINE("LineIn", NULL),
-};
-
-/* SMDK-PAIFTX connections */
-static const struct snd_soc_dapm_route audio_map_tx[] = {
-       /* MicIn feeds AINL */
-       {"AINL", NULL, "MicIn"},
-
-       /* LineIn feeds AINL/R */
-       {"AINL", NULL, "LineIn"},
-       {"AINR", NULL, "LineIn"},
-};
-
-/* SMDK-PAIFRX connections */
-static const struct snd_soc_dapm_route audio_map_rx[] = {
-       /* Front Left/Right are fed VOUT1L/R */
-       {"Front", NULL, "VOUT1L"},
-       {"Front", NULL, "VOUT1R"},
-
-       /* Center/Sub are fed VOUT2L/R */
-       {"Center+Sub", NULL, "VOUT2L"},
-       {"Center+Sub", NULL, "VOUT2R"},
-
-       /* Rear Left/Right are fed VOUT3L/R */
-       {"Rear", NULL, "VOUT3L"},
-       {"Rear", NULL, "VOUT3R"},
-};
-
-static int smdk64xx_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-
-       /* Add smdk64xx specific Capture widgets */
-       snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_cpt,
-                                 ARRAY_SIZE(wm8580_dapm_widgets_cpt));
-
-       /* Set up PAIFTX audio path */
-       snd_soc_dapm_add_routes(codec, audio_map_tx, ARRAY_SIZE(audio_map_tx));
-
-       /* Enabling the microphone requires the fitting of a 0R
-        * resistor to connect the line from the microphone jack.
-        */
-       snd_soc_dapm_disable_pin(codec, "MicIn");
-
-       /* signal a DAPM event */
-       snd_soc_dapm_sync(codec);
-
-       return 0;
-}
-
-static int smdk64xx_wm8580_init_paifrx(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-
-       /* Add smdk64xx specific Playback widgets */
-       snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_pbk,
-                                 ARRAY_SIZE(wm8580_dapm_widgets_pbk));
-
-       /* Set up PAIFRX audio path */
-       snd_soc_dapm_add_routes(codec, audio_map_rx, ARRAY_SIZE(audio_map_rx));
-
-       /* signal a DAPM event */
-       snd_soc_dapm_sync(codec);
-
-       return 0;
-}
-
-static struct snd_soc_dai_link smdk64xx_dai[] = {
-{ /* Primary Playback i/f */
-       .name = "WM8580 PAIF RX",
-       .stream_name = "Playback",
-       .cpu_dai_name = "s3c64xx-iis-v4",
-       .codec_dai_name = "wm8580-hifi-playback",
-       .platform_name = "s3c24xx-pcm-audio",
-       .codec_name = "wm8580-codec.0-001b",
-       .init = smdk64xx_wm8580_init_paifrx,
-       .ops = &smdk64xx_ops,
-},
-{ /* Primary Capture i/f */
-       .name = "WM8580 PAIF TX",
-       .stream_name = "Capture",
-       .cpu_dai_name = "s3c64xx-iis-v4",
-       .codec_dai_name = "wm8580-hifi-capture",
-       .platform_name = "s3c24xx-pcm-audio",
-       .codec_name = "wm8580-codec.0-001b",
-       .init = smdk64xx_wm8580_init_paiftx,
-       .ops = &smdk64xx_ops,
-},
-};
-
-static struct snd_soc_card smdk64xx = {
-       .name = "SMDK64xx 5.1",
-       .dai_link = smdk64xx_dai,
-       .num_links = ARRAY_SIZE(smdk64xx_dai),
-};
-
-static struct platform_device *smdk64xx_snd_device;
-
-static int __init smdk64xx_audio_init(void)
-{
-       int ret;
-
-       smdk64xx_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!smdk64xx_snd_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(smdk64xx_snd_device, &smdk64xx);
-       ret = platform_device_add(smdk64xx_snd_device);
-
-       if (ret)
-               platform_device_put(smdk64xx_snd_device);
-
-       return ret;
-}
-module_init(smdk64xx_audio_init);
-
-MODULE_AUTHOR("Jaswinder Singh, jassi.brar@samsung.com");
-MODULE_DESCRIPTION("ALSA SoC SMDK64XX WM8580");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/smdk_spdif.c b/sound/soc/s3c24xx/smdk_spdif.c
deleted file mode 100644 (file)
index 761e02b..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * smdk_spdif.c  --  S/PDIF audio for SMDK
- *
- * Copyright 2010 Samsung Electronics Co. Ltd.
- *
- * 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/device.h>
-#include <linux/clk.h>
-
-#include <plat/devs.h>
-
-#include <sound/soc.h>
-
-#include "s3c-dma.h"
-#include "spdif.h"
-
-/* Audio clock settings are belonged to board specific part. Every
- * board can set audio source clock setting which is matched with H/W
- * like this function-'set_audio_clock_heirachy'.
- */
-static int set_audio_clock_heirachy(struct platform_device *pdev)
-{
-       struct clk *fout_epll, *mout_epll, *sclk_audio0, *sclk_spdif;
-       int ret;
-
-       fout_epll = clk_get(NULL, "fout_epll");
-       if (IS_ERR(fout_epll)) {
-               printk(KERN_WARNING "%s: Cannot find fout_epll.\n",
-                               __func__);
-               return -EINVAL;
-       }
-
-       mout_epll = clk_get(NULL, "mout_epll");
-       if (IS_ERR(mout_epll)) {
-               printk(KERN_WARNING "%s: Cannot find mout_epll.\n",
-                               __func__);
-               ret = -EINVAL;
-               goto out1;
-       }
-
-       sclk_audio0 = clk_get(&pdev->dev, "sclk_audio");
-       if (IS_ERR(sclk_audio0)) {
-               printk(KERN_WARNING "%s: Cannot find sclk_audio.\n",
-                               __func__);
-               ret = -EINVAL;
-               goto out2;
-       }
-
-       sclk_spdif = clk_get(NULL, "sclk_spdif");
-       if (IS_ERR(sclk_spdif)) {
-               printk(KERN_WARNING "%s: Cannot find sclk_spdif.\n",
-                               __func__);
-               ret = -EINVAL;
-               goto out3;
-       }
-
-       /* Set audio clock hierarchy for S/PDIF */
-       clk_set_parent(mout_epll, fout_epll);
-       clk_set_parent(sclk_audio0, mout_epll);
-       clk_set_parent(sclk_spdif, sclk_audio0);
-
-       clk_put(sclk_spdif);
-out3:
-       clk_put(sclk_audio0);
-out2:
-       clk_put(mout_epll);
-out1:
-       clk_put(fout_epll);
-
-       return ret;
-}
-
-/* We should haved to set clock directly on this part because of clock
- * scheme of Samsudng SoCs did not support to set rates from abstrct
- * clock of it's hierarchy.
- */
-static int set_audio_clock_rate(unsigned long epll_rate,
-                               unsigned long audio_rate)
-{
-       struct clk *fout_epll, *sclk_spdif;
-
-       fout_epll = clk_get(NULL, "fout_epll");
-       if (IS_ERR(fout_epll)) {
-               printk(KERN_ERR "%s: failed to get fout_epll\n", __func__);
-               return -ENOENT;
-       }
-
-       clk_set_rate(fout_epll, epll_rate);
-       clk_put(fout_epll);
-
-       sclk_spdif = clk_get(NULL, "sclk_spdif");
-       if (IS_ERR(sclk_spdif)) {
-               printk(KERN_ERR "%s: failed to get sclk_spdif\n", __func__);
-               return -ENOENT;
-       }
-
-       clk_set_rate(sclk_spdif, audio_rate);
-       clk_put(sclk_spdif);
-
-       return 0;
-}
-
-static int smdk_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;
-       unsigned long pll_out, rclk_rate;
-       int ret, ratio;
-
-       switch (params_rate(params)) {
-       case 44100:
-               pll_out = 45158400;
-               break;
-       case 32000:
-       case 48000:
-       case 96000:
-               pll_out = 49152000;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* Setting ratio to 512fs helps to use S/PDIF with HDMI without
-        * modify S/PDIF ASoC machine driver.
-        */
-       ratio = 512;
-       rclk_rate = params_rate(params) * ratio;
-
-       /* Set audio source clock rates */
-       ret = set_audio_clock_rate(pll_out, rclk_rate);
-       if (ret < 0)
-               return ret;
-
-       /* Set S/PDIF uses internal source clock */
-       ret = snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK,
-                                       rclk_rate, SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       return ret;
-}
-
-static struct snd_soc_ops smdk_spdif_ops = {
-       .hw_params = smdk_hw_params,
-};
-
-static struct snd_soc_card smdk;
-
-static struct snd_soc_dai_link smdk_dai = {
-       .name = "S/PDIF",
-       .stream_name = "S/PDIF PCM Playback",
-       .platform_name = "s3c24xx-pcm-audio",
-       .cpu_dai_name = "samsung-spdif",
-       .codec_dai_name = "dit-hifi",
-       .codec_name = "spdif-dit",
-       .ops = &smdk_spdif_ops,
-};
-
-static struct snd_soc_card smdk = {
-       .name = "SMDK-S/PDIF",
-       .dai_link = &smdk_dai,
-       .num_links = 1,
-};
-
-static struct platform_device *smdk_snd_spdif_dit_device;
-static struct platform_device *smdk_snd_spdif_device;
-
-static int __init smdk_init(void)
-{
-       int ret;
-
-       smdk_snd_spdif_dit_device = platform_device_alloc("spdif-dit", -1);
-       if (!smdk_snd_spdif_dit_device)
-               return -ENOMEM;
-
-       ret = platform_device_add(smdk_snd_spdif_dit_device);
-       if (ret)
-               goto err2;
-
-       smdk_snd_spdif_device = platform_device_alloc("soc-audio", -1);
-       if (!smdk_snd_spdif_device) {
-               ret = -ENOMEM;
-               goto err2;
-       }
-
-       platform_set_drvdata(smdk_snd_spdif_device, &smdk);
-
-       ret = platform_device_add(smdk_snd_spdif_device);
-       if (ret)
-               goto err1;
-
-       /* Set audio clock hierarchy manually */
-       ret = set_audio_clock_heirachy(smdk_snd_spdif_device);
-       if (ret)
-               goto err1;
-
-       return 0;
-err1:
-       platform_device_put(smdk_snd_spdif_device);
-err2:
-       platform_device_put(smdk_snd_spdif_dit_device);
-       return ret;
-}
-
-static void __exit smdk_exit(void)
-{
-       platform_device_unregister(smdk_snd_spdif_device);
-}
-
-module_init(smdk_init);
-module_exit(smdk_exit);
-
-MODULE_AUTHOR("Seungwhan Youn, <sw.youn@samsung.com>");
-MODULE_DESCRIPTION("ALSA SoC SMDK+S/PDIF");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/smdk_wm9713.c b/sound/soc/s3c24xx/smdk_wm9713.c
deleted file mode 100644 (file)
index 33ba8fd..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * smdk_wm9713.c  --  SoC audio for SMDK
- *
- * Copyright 2010 Samsung Electronics Co. Ltd.
- * Author: Jaswinder Singh Brar <jassi.brar@samsung.com>
- *
- * 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/device.h>
-#include <sound/soc.h>
-
-#include "s3c-dma.h"
-#include "s3c-ac97.h"
-
-static struct snd_soc_card smdk;
-
-/*
- * Default CFG switch settings to use this driver:
- *
- *   SMDK6410: Set CFG1 1-3 On, CFG2 1-4 Off
- *   SMDKC100: Set CFG6 1-3 On, CFG7 1   On
- *   SMDKC110: Set CFGB10 1-2 Off, CFGB12 1-3 On
- *   SMDKV210: Set CFGB10 1-2 Off, CFGB12 1-3 On
- */
-
-/*
- Playback (HeadPhone):-
-       $ amixer sset 'Headphone' unmute
-       $ amixer sset 'Right Headphone Out Mux' 'Headphone'
-       $ amixer sset 'Left Headphone Out Mux' 'Headphone'
-       $ amixer sset 'Right HP Mixer PCM' unmute
-       $ amixer sset 'Left HP Mixer PCM' unmute
-
- Capture (LineIn):-
-       $ amixer sset 'Right Capture Source' 'Line'
-       $ amixer sset 'Left Capture Source' 'Line'
-*/
-
-static struct snd_soc_dai_link smdk_dai = {
-       .name = "AC97",
-       .stream_name = "AC97 PCM",
-       .platform_name = "s3c24xx-pcm-audio",
-       .cpu_dai_name = "s3c-ac97",
-       .codec_dai_name = "wm9713-hifi",
-       .codec_name = "wm9713-codec",
-};
-
-static struct snd_soc_card smdk = {
-       .name = "SMDK WM9713",
-       .dai_link = &smdk_dai,
-       .num_links = 1,
-};
-
-static struct platform_device *smdk_snd_wm9713_device;
-static struct platform_device *smdk_snd_ac97_device;
-
-static int __init smdk_init(void)
-{
-       int ret;
-
-       smdk_snd_wm9713_device = platform_device_alloc("wm9713-codec", -1);
-       if (!smdk_snd_wm9713_device)
-               return -ENOMEM;
-
-       ret = platform_device_add(smdk_snd_wm9713_device);
-       if (ret)
-               goto err;
-
-       smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1);
-       if (!smdk_snd_ac97_device) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       platform_set_drvdata(smdk_snd_ac97_device, &smdk);
-
-       ret = platform_device_add(smdk_snd_ac97_device);
-       if (ret) {
-               platform_device_put(smdk_snd_ac97_device);
-               goto err;
-       }
-
-       return 0;
-err:
-       platform_device_put(smdk_snd_wm9713_device);
-       return ret;
-}
-
-static void __exit smdk_exit(void)
-{
-       platform_device_unregister(smdk_snd_ac97_device);
-       platform_device_unregister(smdk_snd_wm9713_device);
-}
-
-module_init(smdk_init);
-module_exit(smdk_exit);
-
-/* Module information */
-MODULE_AUTHOR("Jaswinder Singh Brar, jassi.brar@samsung.com");
-MODULE_DESCRIPTION("ALSA SoC SMDK+WM9713");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/spdif.c b/sound/soc/s3c24xx/spdif.c
deleted file mode 100644 (file)
index ce554e9..0000000
+++ /dev/null
@@ -1,501 +0,0 @@
-/* sound/soc/s3c24xx/spdif.c
- *
- * ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
- *
- * Copyright (c) 2010 Samsung Electronics Co. Ltd
- *             http://www.samsung.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/clk.h>
-#include <linux/io.h>
-
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <plat/audio.h>
-#include <mach/dma.h>
-
-#include "s3c-dma.h"
-#include "spdif.h"
-
-/* Registers */
-#define CLKCON                         0x00
-#define CON                            0x04
-#define BSTAS                          0x08
-#define CSTAS                          0x0C
-#define DATA_OUTBUF                    0x10
-#define DCNT                           0x14
-#define BSTAS_S                                0x18
-#define DCNT_S                         0x1C
-
-#define CLKCTL_MASK                    0x7
-#define CLKCTL_MCLK_EXT                        (0x1 << 2)
-#define CLKCTL_PWR_ON                  (0x1 << 0)
-
-#define CON_MASK                       0x3ffffff
-#define CON_FIFO_TH_SHIFT              19
-#define CON_FIFO_TH_MASK               (0x7 << 19)
-#define CON_USERDATA_23RDBIT           (0x1 << 12)
-
-#define CON_SW_RESET                   (0x1 << 5)
-
-#define CON_MCLKDIV_MASK               (0x3 << 3)
-#define CON_MCLKDIV_256FS              (0x0 << 3)
-#define CON_MCLKDIV_384FS              (0x1 << 3)
-#define CON_MCLKDIV_512FS              (0x2 << 3)
-
-#define CON_PCM_MASK                   (0x3 << 1)
-#define CON_PCM_16BIT                  (0x0 << 1)
-#define CON_PCM_20BIT                  (0x1 << 1)
-#define CON_PCM_24BIT                  (0x2 << 1)
-
-#define CON_PCM_DATA                   (0x1 << 0)
-
-#define CSTAS_MASK                     0x3fffffff
-#define CSTAS_SAMP_FREQ_MASK           (0xF << 24)
-#define CSTAS_SAMP_FREQ_44             (0x0 << 24)
-#define CSTAS_SAMP_FREQ_48             (0x2 << 24)
-#define CSTAS_SAMP_FREQ_32             (0x3 << 24)
-#define CSTAS_SAMP_FREQ_96             (0xA << 24)
-
-#define CSTAS_CATEGORY_MASK            (0xFF << 8)
-#define CSTAS_CATEGORY_CODE_CDP                (0x01 << 8)
-
-#define CSTAS_NO_COPYRIGHT             (0x1 << 2)
-
-/**
- * struct samsung_spdif_info - Samsung S/PDIF Controller information
- * @lock: Spin lock for S/PDIF.
- * @dev: The parent device passed to use from the probe.
- * @regs: The pointer to the device register block.
- * @clk_rate: Current clock rate for calcurate ratio.
- * @pclk: The peri-clock pointer for spdif master operation.
- * @sclk: The source clock pointer for making sync signals.
- * @save_clkcon: Backup clkcon reg. in suspend.
- * @save_con: Backup con reg. in suspend.
- * @save_cstas: Backup cstas reg. in suspend.
- * @dma_playback: DMA information for playback channel.
- */
-struct samsung_spdif_info {
-       spinlock_t      lock;
-       struct device   *dev;
-       void __iomem    *regs;
-       unsigned long   clk_rate;
-       struct clk      *pclk;
-       struct clk      *sclk;
-       u32             saved_clkcon;
-       u32             saved_con;
-       u32             saved_cstas;
-       struct s3c_dma_params   *dma_playback;
-};
-
-static struct s3c2410_dma_client spdif_dma_client_out = {
-       .name           = "S/PDIF Stereo out",
-};
-
-static struct s3c_dma_params spdif_stereo_out;
-static struct samsung_spdif_info spdif_info;
-
-static inline struct samsung_spdif_info *to_info(struct snd_soc_dai *cpu_dai)
-{
-       return snd_soc_dai_get_drvdata(cpu_dai);
-}
-
-static void spdif_snd_txctrl(struct samsung_spdif_info *spdif, int on)
-{
-       void __iomem *regs = spdif->regs;
-       u32 clkcon;
-
-       dev_dbg(spdif->dev, "Entered %s\n", __func__);
-
-       clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
-       if (on)
-               writel(clkcon | CLKCTL_PWR_ON, regs + CLKCON);
-       else
-               writel(clkcon & ~CLKCTL_PWR_ON, regs + CLKCON);
-}
-
-static int spdif_set_sysclk(struct snd_soc_dai *cpu_dai,
-                               int clk_id, unsigned int freq, int dir)
-{
-       struct samsung_spdif_info *spdif = to_info(cpu_dai);
-       u32 clkcon;
-
-       dev_dbg(spdif->dev, "Entered %s\n", __func__);
-
-       clkcon = readl(spdif->regs + CLKCON);
-
-       if (clk_id == SND_SOC_SPDIF_INT_MCLK)
-               clkcon &= ~CLKCTL_MCLK_EXT;
-       else
-               clkcon |= CLKCTL_MCLK_EXT;
-
-       writel(clkcon, spdif->regs + CLKCON);
-
-       spdif->clk_rate = freq;
-
-       return 0;
-}
-
-static int spdif_trigger(struct snd_pcm_substream *substream, int cmd,
-                               struct snd_soc_dai *dai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
-       unsigned long flags;
-
-       dev_dbg(spdif->dev, "Entered %s\n", __func__);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               spin_lock_irqsave(&spdif->lock, flags);
-               spdif_snd_txctrl(spdif, 1);
-               spin_unlock_irqrestore(&spdif->lock, flags);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               spin_lock_irqsave(&spdif->lock, flags);
-               spdif_snd_txctrl(spdif, 0);
-               spin_unlock_irqrestore(&spdif->lock, flags);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int spdif_sysclk_ratios[] = {
-       512, 384, 256,
-};
-
-static int spdif_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params,
-                               struct snd_soc_dai *socdai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
-       void __iomem *regs = spdif->regs;
-       struct s3c_dma_params *dma_data;
-       u32 con, clkcon, cstas;
-       unsigned long flags;
-       int i, ratio;
-
-       dev_dbg(spdif->dev, "Entered %s\n", __func__);
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               dma_data = spdif->dma_playback;
-       else {
-               dev_err(spdif->dev, "Capture is not supported\n");
-               return -EINVAL;
-       }
-
-       snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
-
-       spin_lock_irqsave(&spdif->lock, flags);
-
-       con = readl(regs + CON) & CON_MASK;
-       cstas = readl(regs + CSTAS) & CSTAS_MASK;
-       clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
-
-       con &= ~CON_FIFO_TH_MASK;
-       con |= (0x7 << CON_FIFO_TH_SHIFT);
-       con |= CON_USERDATA_23RDBIT;
-       con |= CON_PCM_DATA;
-
-       con &= ~CON_PCM_MASK;
-       switch (params_format(params)) {
-       case SNDRV_PCM_FORMAT_S16_LE:
-               con |= CON_PCM_16BIT;
-               break;
-       default:
-               dev_err(spdif->dev, "Unsupported data size.\n");
-               goto err;
-       }
-
-       ratio = spdif->clk_rate / params_rate(params);
-       for (i = 0; i < ARRAY_SIZE(spdif_sysclk_ratios); i++)
-               if (ratio == spdif_sysclk_ratios[i])
-                       break;
-       if (i == ARRAY_SIZE(spdif_sysclk_ratios)) {
-               dev_err(spdif->dev, "Invalid clock ratio %ld/%d\n",
-                               spdif->clk_rate, params_rate(params));
-               goto err;
-       }
-
-       con &= ~CON_MCLKDIV_MASK;
-       switch (ratio) {
-       case 256:
-               con |= CON_MCLKDIV_256FS;
-               break;
-       case 384:
-               con |= CON_MCLKDIV_384FS;
-               break;
-       case 512:
-               con |= CON_MCLKDIV_512FS;
-               break;
-       }
-
-       cstas &= ~CSTAS_SAMP_FREQ_MASK;
-       switch (params_rate(params)) {
-       case 44100:
-               cstas |= CSTAS_SAMP_FREQ_44;
-               break;
-       case 48000:
-               cstas |= CSTAS_SAMP_FREQ_48;
-               break;
-       case 32000:
-               cstas |= CSTAS_SAMP_FREQ_32;
-               break;
-       case 96000:
-               cstas |= CSTAS_SAMP_FREQ_96;
-               break;
-       default:
-               dev_err(spdif->dev, "Invalid sampling rate %d\n",
-                               params_rate(params));
-               goto err;
-       }
-
-       cstas &= ~CSTAS_CATEGORY_MASK;
-       cstas |= CSTAS_CATEGORY_CODE_CDP;
-       cstas |= CSTAS_NO_COPYRIGHT;
-
-       writel(con, regs + CON);
-       writel(cstas, regs + CSTAS);
-       writel(clkcon, regs + CLKCON);
-
-       spin_unlock_irqrestore(&spdif->lock, flags);
-
-       return 0;
-err:
-       spin_unlock_irqrestore(&spdif->lock, flags);
-       return -EINVAL;
-}
-
-static void spdif_shutdown(struct snd_pcm_substream *substream,
-                               struct snd_soc_dai *dai)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
-       void __iomem *regs = spdif->regs;
-       u32 con, clkcon;
-
-       dev_dbg(spdif->dev, "Entered %s\n", __func__);
-
-       con = readl(regs + CON) & CON_MASK;
-       clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
-
-       writel(con | CON_SW_RESET, regs + CON);
-       cpu_relax();
-
-       writel(clkcon & ~CLKCTL_PWR_ON, regs + CLKCON);
-}
-
-#ifdef CONFIG_PM
-static int spdif_suspend(struct snd_soc_dai *cpu_dai)
-{
-       struct samsung_spdif_info *spdif = to_info(cpu_dai);
-       u32 con = spdif->saved_con;
-
-       dev_dbg(spdif->dev, "Entered %s\n", __func__);
-
-       spdif->saved_clkcon = readl(spdif->regs + CLKCON) & CLKCTL_MASK;
-       spdif->saved_con = readl(spdif->regs + CON) & CON_MASK;
-       spdif->saved_cstas = readl(spdif->regs + CSTAS) & CSTAS_MASK;
-
-       writel(con | CON_SW_RESET, spdif->regs + CON);
-       cpu_relax();
-
-       return 0;
-}
-
-static int spdif_resume(struct snd_soc_dai *cpu_dai)
-{
-       struct samsung_spdif_info *spdif = to_info(cpu_dai);
-
-       dev_dbg(spdif->dev, "Entered %s\n", __func__);
-
-       writel(spdif->saved_clkcon, spdif->regs + CLKCON);
-       writel(spdif->saved_con, spdif->regs + CON);
-       writel(spdif->saved_cstas, spdif->regs + CSTAS);
-
-       return 0;
-}
-#else
-#define spdif_suspend NULL
-#define spdif_resume NULL
-#endif
-
-static struct snd_soc_dai_ops spdif_dai_ops = {
-       .set_sysclk     = spdif_set_sysclk,
-       .trigger        = spdif_trigger,
-       .hw_params      = spdif_hw_params,
-       .shutdown       = spdif_shutdown,
-};
-
-struct snd_soc_dai_driver samsung_spdif_dai = {
-       .name = "samsung-spdif",
-       .playback = {
-               .stream_name = "S/PDIF Playback",
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = (SNDRV_PCM_RATE_32000 |
-                               SNDRV_PCM_RATE_44100 |
-                               SNDRV_PCM_RATE_48000 |
-                               SNDRV_PCM_RATE_96000),
-               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
-       .ops = &spdif_dai_ops,
-       .suspend = spdif_suspend,
-       .resume = spdif_resume,
-};
-
-static __devinit int spdif_probe(struct platform_device *pdev)
-{
-       struct s3c_audio_pdata *spdif_pdata;
-       struct resource *mem_res, *dma_res;
-       struct samsung_spdif_info *spdif;
-       int ret;
-
-       spdif_pdata = pdev->dev.platform_data;
-
-       dev_dbg(&pdev->dev, "Entered %s\n", __func__);
-
-       dma_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (!dma_res) {
-               dev_err(&pdev->dev, "Unable to get dma resource.\n");
-               return -ENXIO;
-       }
-
-       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mem_res) {
-               dev_err(&pdev->dev, "Unable to get register resource.\n");
-               return -ENXIO;
-       }
-
-       if (spdif_pdata && spdif_pdata->cfg_gpio
-                       && spdif_pdata->cfg_gpio(pdev)) {
-               dev_err(&pdev->dev, "Unable to configure GPIO pins\n");
-               return -EINVAL;
-       }
-
-       spdif = &spdif_info;
-       spdif->dev = &pdev->dev;
-
-       spin_lock_init(&spdif->lock);
-
-       spdif->pclk = clk_get(&pdev->dev, "spdif");
-       if (IS_ERR(spdif->pclk)) {
-               dev_err(&pdev->dev, "failed to get peri-clock\n");
-               ret = -ENOENT;
-               goto err0;
-       }
-       clk_enable(spdif->pclk);
-
-       spdif->sclk = clk_get(&pdev->dev, "sclk_spdif");
-       if (IS_ERR(spdif->sclk)) {
-               dev_err(&pdev->dev, "failed to get internal source clock\n");
-               ret = -ENOENT;
-               goto err1;
-       }
-       clk_enable(spdif->sclk);
-
-       /* Request S/PDIF Register's memory region */
-       if (!request_mem_region(mem_res->start,
-                               resource_size(mem_res), "samsung-spdif")) {
-               dev_err(&pdev->dev, "Unable to request register region\n");
-               ret = -EBUSY;
-               goto err2;
-       }
-
-       spdif->regs = ioremap(mem_res->start, 0x100);
-       if (spdif->regs == NULL) {
-               dev_err(&pdev->dev, "Cannot ioremap registers\n");
-               ret = -ENXIO;
-               goto err3;
-       }
-
-       dev_set_drvdata(&pdev->dev, spdif);
-
-       ret = snd_soc_register_dai(&pdev->dev, &samsung_spdif_dai);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "fail to register dai\n");
-               goto err4;
-       }
-
-       spdif_stereo_out.dma_size = 2;
-       spdif_stereo_out.client = &spdif_dma_client_out;
-       spdif_stereo_out.dma_addr = mem_res->start + DATA_OUTBUF;
-       spdif_stereo_out.channel = dma_res->start;
-
-       spdif->dma_playback = &spdif_stereo_out;
-
-       return 0;
-
-err4:
-       iounmap(spdif->regs);
-err3:
-       release_mem_region(mem_res->start, resource_size(mem_res));
-err2:
-       clk_disable(spdif->sclk);
-       clk_put(spdif->sclk);
-err1:
-       clk_disable(spdif->pclk);
-       clk_put(spdif->pclk);
-err0:
-       return ret;
-}
-
-static __devexit int spdif_remove(struct platform_device *pdev)
-{
-       struct samsung_spdif_info *spdif = &spdif_info;
-       struct resource *mem_res;
-
-       snd_soc_unregister_dai(&pdev->dev);
-
-       iounmap(spdif->regs);
-
-       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (mem_res)
-               release_mem_region(mem_res->start, resource_size(mem_res));
-
-       clk_disable(spdif->sclk);
-       clk_put(spdif->sclk);
-       clk_disable(spdif->pclk);
-       clk_put(spdif->pclk);
-
-       return 0;
-}
-
-static struct platform_driver samsung_spdif_driver = {
-       .probe  = spdif_probe,
-       .remove = spdif_remove,
-       .driver = {
-               .name   = "samsung-spdif",
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init spdif_init(void)
-{
-       return platform_driver_register(&samsung_spdif_driver);
-}
-module_init(spdif_init);
-
-static void __exit spdif_exit(void)
-{
-       platform_driver_unregister(&samsung_spdif_driver);
-}
-module_exit(spdif_exit);
-
-MODULE_AUTHOR("Seungwhan Youn, <sw.youn@samsung.com>");
-MODULE_DESCRIPTION("Samsung S/PDIF Controller Driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:samsung-spdif");
diff --git a/sound/soc/s3c24xx/spdif.h b/sound/soc/s3c24xx/spdif.h
deleted file mode 100644 (file)
index 3ed5559..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* sound/soc/s3c24xx/spdif.h
- *
- * ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
- *
- * Copyright (c) 2010 Samsung Electronics Co. Ltd
- *             http://www.samsung.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 __SND_SOC_SAMSUNG_SPDIF_H
-#define __SND_SOC_SAMSUNG_SPDIF_H      __FILE__
-
-#define SND_SOC_SPDIF_INT_MCLK         0
-#define SND_SOC_SPDIF_EXT_MCLK         1
-
-#endif /* __SND_SOC_SAMSUNG_SPDIF_H */
index c1244c5..5890e43 100644 (file)
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include <variant/dmac.h>
 
-#include "../codecs/tlv320aic3x.h"
 #include "s6000-pcm.h"
 #include "s6000-i2s.h"
 
@@ -107,6 +105,7 @@ static int output_type_put(struct snd_kcontrol *kcontrol,
                           struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = kcontrol->private_data;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        unsigned int val = (ucontrol->value.enumerated.item[0] != 0);
        char *differential = "Audio Out Differential";
        char *stereo = "Audio Out Stereo";
@@ -114,10 +113,10 @@ static int output_type_put(struct snd_kcontrol *kcontrol,
        if (kcontrol->private_value == val)
                return 0;
        kcontrol->private_value = val;
-       snd_soc_dapm_disable_pin(codec, val ? differential : stereo);
-       snd_soc_dapm_sync(codec);
-       snd_soc_dapm_enable_pin(codec, val ? stereo : differential);
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_disable_pin(dapm, val ? differential : stereo);
+       snd_soc_dapm_sync(dapm);
+       snd_soc_dapm_enable_pin(dapm, val ? stereo : differential);
+       snd_soc_dapm_sync(dapm);
 
        return 1;
 }
@@ -137,35 +136,36 @@ static const struct snd_kcontrol_new audio_out_mux = {
 static int s6105_aic3x_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
        /* Add s6105 specific widgets */
-       snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets,
                                  ARRAY_SIZE(aic3x_dapm_widgets));
 
        /* Set up s6105 specific audio path audio_map */
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        /* not present */
-       snd_soc_dapm_nc_pin(codec, "MONO_LOUT");
-       snd_soc_dapm_nc_pin(codec, "LINE2L");
-       snd_soc_dapm_nc_pin(codec, "LINE2R");
+       snd_soc_dapm_nc_pin(dapm, "MONO_LOUT");
+       snd_soc_dapm_nc_pin(dapm, "LINE2L");
+       snd_soc_dapm_nc_pin(dapm, "LINE2R");
 
        /* not connected */
-       snd_soc_dapm_nc_pin(codec, "MIC3L"); /* LINE2L on this chip */
-       snd_soc_dapm_nc_pin(codec, "MIC3R"); /* LINE2R on this chip */
-       snd_soc_dapm_nc_pin(codec, "LLOUT");
-       snd_soc_dapm_nc_pin(codec, "RLOUT");
-       snd_soc_dapm_nc_pin(codec, "HPRCOM");
+       snd_soc_dapm_nc_pin(dapm, "MIC3L"); /* LINE2L on this chip */
+       snd_soc_dapm_nc_pin(dapm, "MIC3R"); /* LINE2R on this chip */
+       snd_soc_dapm_nc_pin(dapm, "LLOUT");
+       snd_soc_dapm_nc_pin(dapm, "RLOUT");
+       snd_soc_dapm_nc_pin(dapm, "HPRCOM");
 
        /* always connected */
-       snd_soc_dapm_enable_pin(codec, "Audio In");
+       snd_soc_dapm_enable_pin(dapm, "Audio In");
 
        /* must correspond to audio_out_mux.private_value initializer */
-       snd_soc_dapm_disable_pin(codec, "Audio Out Differential");
-       snd_soc_dapm_sync(codec);
-       snd_soc_dapm_enable_pin(codec, "Audio Out Stereo");
+       snd_soc_dapm_disable_pin(dapm, "Audio Out Differential");
+       snd_soc_dapm_sync(dapm);
+       snd_soc_dapm_enable_pin(dapm, "Audio Out Stereo");
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
 
        snd_ctl_add(codec->card->snd_card, snd_ctl_new1(&audio_out_mux, codec));
 
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
new file mode 100644 (file)
index 0000000..a6a6b5f
--- /dev/null
@@ -0,0 +1,171 @@
+config SND_SOC_SAMSUNG
+       tristate "ASoC support for Samsung"
+       depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5P64X0 || ARCH_S5P6442 || ARCH_S5PV310
+       select S3C64XX_DMA if ARCH_S3C64XX
+       select S3C2410_DMA if ARCH_S3C2410
+       help
+         Say Y or M if you want to add support for codecs attached to
+         the Samsung SoCs' Audio interfaces. You will also need to
+         select the audio interfaces to support below.
+
+config SND_S3C24XX_I2S
+       tristate
+       select S3C2410_DMA
+
+config SND_S3C_I2SV2_SOC
+       tristate
+
+config SND_S3C2412_SOC_I2S
+       tristate
+       select SND_S3C_I2SV2_SOC
+       select S3C2410_DMA
+
+config SND_SAMSUNG_PCM
+       tristate
+
+config SND_SAMSUNG_AC97
+       tristate
+       select SND_SOC_AC97_BUS
+
+config SND_SAMSUNG_SPDIF
+       tristate
+       select SND_SOC_SPDIF
+
+config SND_SAMSUNG_I2S
+       tristate
+
+config SND_SOC_SAMSUNG_NEO1973_WM8753
+       tristate "SoC I2S Audio support for NEO1973 - WM8753"
+       depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA01
+       select SND_S3C24XX_I2S
+       select SND_SOC_WM8753
+       help
+         Say Y if you want to add support for SoC audio on smdk2440
+         with the WM8753.
+
+config SND_SOC_SAMSUNG_NEO1973_GTA02_WM8753
+       tristate "Audio support for the Openmoko Neo FreeRunner (GTA02)"
+       depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA02
+       select SND_S3C24XX_I2S
+       select SND_SOC_WM8753
+       help
+         This driver provides audio support for the Openmoko Neo FreeRunner
+         smartphone.
+         
+config SND_SOC_SAMSUNG_JIVE_WM8750
+       tristate "SoC I2S Audio support for Jive"
+       depends on SND_SOC_SAMSUNG && MACH_JIVE
+       select SND_SOC_WM8750
+       select SND_S3C2412_SOC_I2S
+       help
+         Sat Y if you want to add support for SoC audio on the Jive.
+
+config SND_SOC_SAMSUNG_SMDK_WM8580
+       tristate "SoC I2S Audio support for WM8580 on SMDK"
+       depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDK6440 || MACH_SMDK6450 || MACH_SMDK6442 || MACH_SMDKV210 || MACH_SMDKC110)
+       select SND_SOC_WM8580
+       select SND_SAMSUNG_I2S
+       help
+         Say Y if you want to add support for SoC audio on the SMDKs.
+
+config SND_SOC_SAMSUNG_SMDK_WM8994
+       tristate "SoC I2S Audio support for WM8994 on SMDK"
+       depends on SND_SOC_SAMSUNG && (MACH_SMDKV310 || MACH_SMDKC210)
+       select SND_SOC_WM8994
+       select SND_SAMSUNG_I2S
+       help
+               Say Y if you want to add support for SoC audio on the SMDKs.
+
+config SND_SOC_SAMSUNG_SMDK2443_WM9710
+       tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
+       depends on SND_SOC_SAMSUNG && MACH_SMDK2443
+       select S3C2410_DMA
+       select AC97_BUS
+       select SND_SOC_AC97_CODEC
+       select SND_SAMSUNG_AC97
+       help
+         Say Y if you want to add support for SoC audio on smdk2443
+         with the WM9710.
+
+config SND_SOC_SAMSUNG_LN2440SBC_ALC650
+       tristate "SoC AC97 Audio support for LN2440SBC - ALC650"
+       depends on SND_SOC_SAMSUNG && ARCH_S3C2410
+       select S3C2410_DMA
+       select AC97_BUS
+       select SND_SOC_AC97_CODEC
+       select SND_SAMSUNG_AC97
+       help
+         Say Y if you want to add support for SoC audio on ln2440sbc
+         with the ALC650.
+
+config SND_SOC_SAMSUNG_S3C24XX_UDA134X
+       tristate "SoC I2S Audio support UDA134X wired to a S3C24XX"
+       depends on SND_SOC_SAMSUNG && ARCH_S3C2410
+       select SND_S3C24XX_I2S
+       select SND_SOC_L3
+       select SND_SOC_UDA134X
+
+config SND_SOC_SAMSUNG_SIMTEC
+       tristate
+       help
+         Internal node for common S3C24XX/Simtec suppor
+
+config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23
+       tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards"
+       depends on SND_SOC_SAMSUNG && ARCH_S3C2410
+       select SND_S3C24XX_I2S
+       select SND_SOC_TLV320AIC23
+       select SND_SOC_SAMSUNG_SIMTEC
+
+config SND_SOC_SAMSUNG_SIMTEC_HERMES
+       tristate "SoC I2S Audio support for Simtec Hermes board"
+       depends on SND_SOC_SAMSUNG && ARCH_S3C2410
+       select SND_S3C24XX_I2S
+       select SND_SOC_TLV320AIC3X
+       select SND_SOC_SAMSUNG_SIMTEC
+
+config SND_SOC_SAMSUNG_H1940_UDA1380
+       tristate "Audio support for the HP iPAQ H1940"
+       depends on SND_SOC_SAMSUNG && ARCH_H1940
+       select SND_S3C24XX_I2S
+       select SND_SOC_UDA1380
+       help
+         This driver provides audio support for HP iPAQ h1940 PDA.
+
+config SND_SOC_SAMSUNG_RX1950_UDA1380
+       tristate "Audio support for the HP iPAQ RX1950"
+       depends on SND_SOC_SAMSUNG && MACH_RX1950
+       select SND_S3C24XX_I2S
+       select SND_SOC_UDA1380
+       help
+         This driver provides audio support for HP iPAQ RX1950 PDA.
+
+config SND_SOC_SAMSUNG_SMDK_WM9713
+       tristate "SoC AC97 Audio support for SMDK with WM9713"
+       depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 || MACH_SMDKV310 || MACH_SMDKC210)
+       select SND_SOC_WM9713
+       select SND_SAMSUNG_AC97
+       help
+         Sat Y if you want to add support for SoC audio on the SMDK.
+
+config SND_SOC_SMARTQ
+       tristate "SoC I2S Audio support for SmartQ board"
+       depends on SND_SOC_SAMSUNG && MACH_SMARTQ
+       select SND_SAMSUNG_I2S
+       select SND_SOC_WM8750
+
+config SND_SOC_GONI_AQUILA_WM8994
+       tristate "SoC I2S Audio support for AQUILA/GONI - WM8994"
+       depends on SND_SOC_SAMSUNG && (MACH_GONI || MACH_AQUILA)
+       select SND_SAMSUNG_I2S
+       select SND_SOC_WM8994
+       help
+         Say Y if you want to add support for SoC audio on goni or aquila
+         with the WM8994.
+
+config SND_SOC_SAMSUNG_SMDK_SPDIF
+       tristate "SoC S/PDIF Audio support for SMDK"
+       depends on SND_SOC_SAMSUNG && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210)
+       select SND_SAMSUNG_SPDIF
+       help
+         Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile
new file mode 100644 (file)
index 0000000..705d4e8
--- /dev/null
@@ -0,0 +1,55 @@
+# S3c24XX Platform Support
+snd-soc-s3c24xx-objs := dma.o
+snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
+snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
+snd-soc-ac97-objs := ac97.o
+snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
+snd-soc-samsung-spdif-objs := spdif.o
+snd-soc-pcm-objs := pcm.o
+snd-soc-i2s-objs := i2s.o
+
+obj-$(CONFIG_SND_SOC_SAMSUNG) += snd-soc-s3c24xx.o
+obj-$(CONFIG_SND_S3C24XX_I2S) += snd-soc-s3c24xx-i2s.o
+obj-$(CONFIG_SND_SAMSUNG_AC97) += snd-soc-ac97.o
+obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
+obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
+obj-$(CONFIG_SND_SAMSUNG_SPDIF) += snd-soc-samsung-spdif.o
+obj-$(CONFIG_SND_SAMSUNG_PCM) += snd-soc-pcm.o
+obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-i2s.o
+
+# S3C24XX Machine Support
+snd-soc-jive-wm8750-objs := jive_wm8750.o
+snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
+snd-soc-neo1973-gta02-wm8753-objs := neo1973_gta02_wm8753.o
+snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o
+snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o
+snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o
+snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o
+snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o
+snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o
+snd-soc-h1940-uda1380-objs := h1940_uda1380.o
+snd-soc-rx1950-uda1380-objs := rx1950_uda1380.o
+snd-soc-smdk-wm8580-objs := smdk_wm8580.o
+snd-soc-smdk-wm8994-objs := smdk_wm8994.o
+snd-soc-smdk-wm9713-objs := smdk_wm9713.o
+snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
+snd-soc-goni-wm8994-objs := goni_wm8994.o
+snd-soc-smdk-spdif-objs := smdk_spdif.o
+
+obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
+obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
+obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_GTA02_WM8753) += snd-soc-neo1973-gta02-wm8753.o
+obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
+obj-$(CONFIG_SND_SOC_SAMSUNG_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o
+obj-$(CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o
+obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC) += snd-soc-s3c24xx-simtec.o
+obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o
+obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o
+obj-$(CONFIG_SND_SOC_SAMSUNG_H1940_UDA1380) += snd-soc-h1940-uda1380.o
+obj-$(CONFIG_SND_SOC_SAMSUNG_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o
+obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8580) += snd-soc-smdk-wm8580.o
+obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994) += snd-soc-smdk-wm8994.o
+obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM9713) += snd-soc-smdk-wm9713.o
+obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
+obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o
+obj-$(CONFIG_SND_SOC_GONI_AQUILA_WM8994) += snd-soc-goni-wm8994.o
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c
new file mode 100644 (file)
index 0000000..4770a95
--- /dev/null
@@ -0,0 +1,520 @@
+/* sound/soc/samsung/ac97.c
+ *
+ * ALSA SoC Audio Layer - S3C AC97 Controller driver
+ *     Evolved from s3c2443-ac97.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ *     Author: Jaswinder Singh <jassi.brar@samsung.com>
+ *     Credits: Graeme Gregory, Sean Choi
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <sound/soc.h>
+
+#include <plat/regs-ac97.h>
+#include <mach/dma.h>
+#include <plat/audio.h>
+
+#include "dma.h"
+#include "ac97.h"
+
+#define AC_CMD_ADDR(x) (x << 16)
+#define AC_CMD_DATA(x) (x & 0xffff)
+
+struct s3c_ac97_info {
+       struct clk         *ac97_clk;
+       void __iomem       *regs;
+       struct mutex       lock;
+       struct completion  done;
+};
+static struct s3c_ac97_info s3c_ac97;
+
+static struct s3c2410_dma_client s3c_dma_client_out = {
+       .name = "AC97 PCMOut"
+};
+
+static struct s3c2410_dma_client s3c_dma_client_in = {
+       .name = "AC97 PCMIn"
+};
+
+static struct s3c2410_dma_client s3c_dma_client_micin = {
+       .name = "AC97 MicIn"
+};
+
+static struct s3c_dma_params s3c_ac97_pcm_out = {
+       .client         = &s3c_dma_client_out,
+       .dma_size       = 4,
+};
+
+static struct s3c_dma_params s3c_ac97_pcm_in = {
+       .client         = &s3c_dma_client_in,
+       .dma_size       = 4,
+};
+
+static struct s3c_dma_params s3c_ac97_mic_in = {
+       .client         = &s3c_dma_client_micin,
+       .dma_size       = 4,
+};
+
+static void s3c_ac97_activate(struct snd_ac97 *ac97)
+{
+       u32 ac_glbctrl, stat;
+
+       stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
+       if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
+               return; /* Return if already active */
+
+       INIT_COMPLETION(s3c_ac97.done);
+
+       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
+       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
+       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
+       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+       if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
+               pr_err("AC97: Unable to activate!");
+}
+
+static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
+       unsigned short reg)
+{
+       u32 ac_glbctrl, ac_codec_cmd;
+       u32 stat, addr, data;
+
+       mutex_lock(&s3c_ac97.lock);
+
+       s3c_ac97_activate(ac97);
+
+       INIT_COMPLETION(s3c_ac97.done);
+
+       ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+       ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg);
+       writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+
+       udelay(50);
+
+       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
+       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+       if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
+               pr_err("AC97: Unable to read!");
+
+       stat = readl(s3c_ac97.regs + S3C_AC97_STAT);
+       addr = (stat >> 16) & 0x7f;
+       data = (stat & 0xffff);
+
+       if (addr != reg)
+               pr_err("ac97: req addr = %02x, rep addr = %02x\n",
+                       reg, addr);
+
+       mutex_unlock(&s3c_ac97.lock);
+
+       return (unsigned short)data;
+}
+
+static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+       unsigned short val)
+{
+       u32 ac_glbctrl, ac_codec_cmd;
+
+       mutex_lock(&s3c_ac97.lock);
+
+       s3c_ac97_activate(ac97);
+
+       INIT_COMPLETION(s3c_ac97.done);
+
+       ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+       ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val);
+       writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+
+       udelay(50);
+
+       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
+       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+       if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
+               pr_err("AC97: Unable to write!");
+
+       ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+       ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
+       writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
+
+       mutex_unlock(&s3c_ac97.lock);
+}
+
+static void s3c_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+       pr_debug("AC97: Cold reset\n");
+       writel(S3C_AC97_GLBCTRL_COLDRESET,
+                       s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+}
+
+static void s3c_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+       u32 stat;
+
+       stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
+       if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
+               return; /* Return if already active */
+
+       pr_debug("AC97: Warm reset\n");
+
+       writel(S3C_AC97_GLBCTRL_WARMRESET, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       s3c_ac97_activate(ac97);
+}
+
+static irqreturn_t s3c_ac97_irq(int irq, void *dev_id)
+{
+       u32 ac_glbctrl, ac_glbstat;
+
+       ac_glbstat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT);
+
+       if (ac_glbstat & S3C_AC97_GLBSTAT_CODECREADY) {
+
+               ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+               ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE;
+               writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+               complete(&s3c_ac97.done);
+       }
+
+       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl |= (1<<30); /* Clear interrupt */
+       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+       return IRQ_HANDLED;
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+       .read       = s3c_ac97_read,
+       .write      = s3c_ac97_write,
+       .warm_reset = s3c_ac97_warm_reset,
+       .reset      = s3c_ac97_cold_reset,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int s3c_ac97_hw_params(struct snd_pcm_substream *substream,
+                                 struct snd_pcm_hw_params *params,
+                                 struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct s3c_dma_params *dma_data;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dma_data = &s3c_ac97_pcm_out;
+       else
+               dma_data = &s3c_ac97_pcm_in;
+
+       snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
+
+       return 0;
+}
+
+static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
+                               struct snd_soc_dai *dai)
+{
+       u32 ac_glbctrl;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct s3c_dma_params *dma_data =
+               snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+               ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
+       else
+               ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+                       ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
+               else
+                       ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA;
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               break;
+       }
+
+       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+       s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
+
+       return 0;
+}
+
+static int s3c_ac97_hw_mic_params(struct snd_pcm_substream *substream,
+                                     struct snd_pcm_hw_params *params,
+                                     struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               return -ENODEV;
+       else
+               snd_soc_dai_set_dma_data(cpu_dai, substream, &s3c_ac97_mic_in);
+
+       return 0;
+}
+
+static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
+                                   int cmd, struct snd_soc_dai *dai)
+{
+       u32 ac_glbctrl;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct s3c_dma_params *dma_data =
+               snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+       ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               ac_glbctrl |= S3C_AC97_GLBCTRL_MICINTM_DMA;
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               break;
+       }
+
+       writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
+
+       s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops s3c_ac97_dai_ops = {
+       .hw_params      = s3c_ac97_hw_params,
+       .trigger        = s3c_ac97_trigger,
+};
+
+static struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = {
+       .hw_params      = s3c_ac97_hw_mic_params,
+       .trigger        = s3c_ac97_mic_trigger,
+};
+
+static struct snd_soc_dai_driver s3c_ac97_dai[] = {
+       [S3C_AC97_DAI_PCM] = {
+               .name = "samsung-ac97",
+               .ac97_control = 1,
+               .playback = {
+                       .stream_name = "AC97 Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+               .capture = {
+                       .stream_name = "AC97 Capture",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+               .ops = &s3c_ac97_dai_ops,
+       },
+       [S3C_AC97_DAI_MIC] = {
+               .name = "samsung-ac97-mic",
+               .ac97_control = 1,
+               .capture = {
+                       .stream_name = "AC97 Mic Capture",
+                       .channels_min = 1,
+                       .channels_max = 1,
+                       .rates = SNDRV_PCM_RATE_8000_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+               .ops = &s3c_ac97_mic_dai_ops,
+       },
+};
+
+static __devinit int s3c_ac97_probe(struct platform_device *pdev)
+{
+       struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res;
+       struct s3c_audio_pdata *ac97_pdata;
+       int ret;
+
+       ac97_pdata = pdev->dev.platform_data;
+       if (!ac97_pdata || !ac97_pdata->cfg_gpio) {
+               dev_err(&pdev->dev, "cfg_gpio callback not provided!\n");
+               return -EINVAL;
+       }
+
+       /* Check for availability of necessary resource */
+       dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!dmatx_res) {
+               dev_err(&pdev->dev, "Unable to get AC97-TX dma resource\n");
+               return -ENXIO;
+       }
+
+       dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+       if (!dmarx_res) {
+               dev_err(&pdev->dev, "Unable to get AC97-RX dma resource\n");
+               return -ENXIO;
+       }
+
+       dmamic_res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
+       if (!dmamic_res) {
+               dev_err(&pdev->dev, "Unable to get AC97-MIC dma resource\n");
+               return -ENXIO;
+       }
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem_res) {
+               dev_err(&pdev->dev, "Unable to get register resource\n");
+               return -ENXIO;
+       }
+
+       irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!irq_res) {
+               dev_err(&pdev->dev, "AC97 IRQ not provided!\n");
+               return -ENXIO;
+       }
+
+       if (!request_mem_region(mem_res->start,
+                               resource_size(mem_res), "ac97")) {
+               dev_err(&pdev->dev, "Unable to request register region\n");
+               return -EBUSY;
+       }
+
+       s3c_ac97_pcm_out.channel = dmatx_res->start;
+       s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
+       s3c_ac97_pcm_in.channel = dmarx_res->start;
+       s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
+       s3c_ac97_mic_in.channel = dmamic_res->start;
+       s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA;
+
+       init_completion(&s3c_ac97.done);
+       mutex_init(&s3c_ac97.lock);
+
+       s3c_ac97.regs = ioremap(mem_res->start, resource_size(mem_res));
+       if (s3c_ac97.regs == NULL) {
+               dev_err(&pdev->dev, "Unable to ioremap register region\n");
+               ret = -ENXIO;
+               goto err1;
+       }
+
+       s3c_ac97.ac97_clk = clk_get(&pdev->dev, "ac97");
+       if (IS_ERR(s3c_ac97.ac97_clk)) {
+               dev_err(&pdev->dev, "ac97 failed to get ac97_clock\n");
+               ret = -ENODEV;
+               goto err2;
+       }
+       clk_enable(s3c_ac97.ac97_clk);
+
+       if (ac97_pdata->cfg_gpio(pdev)) {
+               dev_err(&pdev->dev, "Unable to configure gpio\n");
+               ret = -EINVAL;
+               goto err3;
+       }
+
+       ret = request_irq(irq_res->start, s3c_ac97_irq,
+                                       IRQF_DISABLED, "AC97", NULL);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "ac97: interrupt request failed.\n");
+               goto err4;
+       }
+
+       ret = snd_soc_register_dais(&pdev->dev, s3c_ac97_dai,
+                       ARRAY_SIZE(s3c_ac97_dai));
+       if (ret)
+               goto err5;
+
+       return 0;
+
+err5:
+       free_irq(irq_res->start, NULL);
+err4:
+err3:
+       clk_disable(s3c_ac97.ac97_clk);
+       clk_put(s3c_ac97.ac97_clk);
+err2:
+       iounmap(s3c_ac97.regs);
+err1:
+       release_mem_region(mem_res->start, resource_size(mem_res));
+
+       return ret;
+}
+
+static __devexit int s3c_ac97_remove(struct platform_device *pdev)
+{
+       struct resource *mem_res, *irq_res;
+
+       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai));
+
+       irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (irq_res)
+               free_irq(irq_res->start, NULL);
+
+       clk_disable(s3c_ac97.ac97_clk);
+       clk_put(s3c_ac97.ac97_clk);
+
+       iounmap(s3c_ac97.regs);
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (mem_res)
+               release_mem_region(mem_res->start, resource_size(mem_res));
+
+       return 0;
+}
+
+static struct platform_driver s3c_ac97_driver = {
+       .probe  = s3c_ac97_probe,
+       .remove = s3c_ac97_remove,
+       .driver = {
+               .name = "samsung-ac97",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init s3c_ac97_init(void)
+{
+       return platform_driver_register(&s3c_ac97_driver);
+}
+module_init(s3c_ac97_init);
+
+static void __exit s3c_ac97_exit(void)
+{
+       platform_driver_unregister(&s3c_ac97_driver);
+}
+module_exit(s3c_ac97_exit);
+
+MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
+MODULE_DESCRIPTION("AC97 driver for the Samsung SoC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-ac97");
diff --git a/sound/soc/samsung/ac97.h b/sound/soc/samsung/ac97.h
new file mode 100644 (file)
index 0000000..0d0e1b5
--- /dev/null
@@ -0,0 +1,21 @@
+/* sound/soc/samsung/ac97.h
+ *
+ * ALSA SoC Audio Layer - S3C AC97 Controller driver
+ *     Evolved from s3c2443-ac97.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ *     Author: Jaswinder Singh <jassi.brar@samsung.com>
+ *     Credits: Graeme Gregory, Sean Choi
+ *
+ * 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 __S3C_AC97_H_
+#define __S3C_AC97_H_
+
+#define S3C_AC97_DAI_PCM 0
+#define S3C_AC97_DAI_MIC 1
+
+#endif /* __S3C_AC97_H_ */
diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c
new file mode 100644 (file)
index 0000000..2124019
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+ * dma.c  --  ALSA Soc Audio Layer
+ *
+ * (c) 2006 Wolfson Microelectronics PLC.
+ * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ * Copyright 2004-2005 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ *  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/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/dma.h>
+#include <mach/hardware.h>
+#include <mach/dma.h>
+
+#include "dma.h"
+
+static const struct snd_pcm_hardware dma_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,
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE |
+                                   SNDRV_PCM_FMTBIT_U16_LE |
+                                   SNDRV_PCM_FMTBIT_U8 |
+                                   SNDRV_PCM_FMTBIT_S8,
+       .channels_min           = 2,
+       .channels_max           = 2,
+       .buffer_bytes_max       = 128*1024,
+       .period_bytes_min       = PAGE_SIZE,
+       .period_bytes_max       = PAGE_SIZE*2,
+       .periods_min            = 2,
+       .periods_max            = 128,
+       .fifo_size              = 32,
+};
+
+struct runtime_data {
+       spinlock_t lock;
+       int state;
+       unsigned int dma_loaded;
+       unsigned int dma_limit;
+       unsigned int dma_period;
+       dma_addr_t dma_start;
+       dma_addr_t dma_pos;
+       dma_addr_t dma_end;
+       struct s3c_dma_params *params;
+};
+
+/* dma_enqueue
+ *
+ * place a dma buffer onto the queue for the dma system
+ * to handle.
+*/
+static void dma_enqueue(struct snd_pcm_substream *substream)
+{
+       struct runtime_data *prtd = substream->runtime->private_data;
+       dma_addr_t pos = prtd->dma_pos;
+       unsigned int limit;
+       int ret;
+
+       pr_debug("Entered %s\n", __func__);
+
+       if (s3c_dma_has_circular())
+               limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
+       else
+               limit = prtd->dma_limit;
+
+       pr_debug("%s: loaded %d, limit %d\n",
+                               __func__, prtd->dma_loaded, limit);
+
+       while (prtd->dma_loaded < limit) {
+               unsigned long len = prtd->dma_period;
+
+               pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
+
+               if ((pos + len) > prtd->dma_end) {
+                       len  = prtd->dma_end - pos;
+                       pr_debug("%s: corrected dma len %ld\n", __func__, len);
+               }
+
+               ret = s3c2410_dma_enqueue(prtd->params->channel,
+                       substream, pos, len);
+
+               if (ret == 0) {
+                       prtd->dma_loaded++;
+                       pos += prtd->dma_period;
+                       if (pos >= prtd->dma_end)
+                               pos = prtd->dma_start;
+               } else
+                       break;
+       }
+
+       prtd->dma_pos = pos;
+}
+
+static void audio_buffdone(struct s3c2410_dma_chan *channel,
+                               void *dev_id, int size,
+                               enum s3c2410_dma_buffresult result)
+{
+       struct snd_pcm_substream *substream = dev_id;
+       struct runtime_data *prtd;
+
+       pr_debug("Entered %s\n", __func__);
+
+       if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR)
+               return;
+
+       prtd = substream->runtime->private_data;
+
+       if (substream)
+               snd_pcm_period_elapsed(substream);
+
+       spin_lock(&prtd->lock);
+       if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) {
+               prtd->dma_loaded--;
+               dma_enqueue(substream);
+       }
+
+       spin_unlock(&prtd->lock);
+}
+
+static int dma_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct runtime_data *prtd = runtime->private_data;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       unsigned long totbytes = params_buffer_bytes(params);
+       struct s3c_dma_params *dma =
+               snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+       int ret = 0;
+
+
+       pr_debug("Entered %s\n", __func__);
+
+       /* return if this is a bufferless transfer e.g.
+        * codec <--> BT codec or GSM modem -- lg FIXME */
+       if (!dma)
+               return 0;
+
+       /* this may get called several times by oss emulation
+        * with different params -HW */
+       if (prtd->params == NULL) {
+               /* prepare DMA */
+               prtd->params = dma;
+
+               pr_debug("params %p, client %p, channel %d\n", prtd->params,
+                       prtd->params->client, prtd->params->channel);
+
+               ret = s3c2410_dma_request(prtd->params->channel,
+                                         prtd->params->client, NULL);
+
+               if (ret < 0) {
+                       printk(KERN_ERR "failed to get dma channel\n");
+                       return ret;
+               }
+
+               /* use the circular buffering if we have it available. */
+               if (s3c_dma_has_circular())
+                       s3c2410_dma_setflags(prtd->params->channel,
+                                            S3C2410_DMAF_CIRCULAR);
+       }
+
+       s3c2410_dma_set_buffdone_fn(prtd->params->channel,
+                                   audio_buffdone);
+
+       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+       runtime->dma_bytes = totbytes;
+
+       spin_lock_irq(&prtd->lock);
+       prtd->dma_loaded = 0;
+       prtd->dma_limit = runtime->hw.periods_min;
+       prtd->dma_period = params_period_bytes(params);
+       prtd->dma_start = runtime->dma_addr;
+       prtd->dma_pos = prtd->dma_start;
+       prtd->dma_end = prtd->dma_start + totbytes;
+       spin_unlock_irq(&prtd->lock);
+
+       return 0;
+}
+
+static int dma_hw_free(struct snd_pcm_substream *substream)
+{
+       struct runtime_data *prtd = substream->runtime->private_data;
+
+       pr_debug("Entered %s\n", __func__);
+
+       /* TODO - do we need to ensure DMA flushed */
+       snd_pcm_set_runtime_buffer(substream, NULL);
+
+       if (prtd->params) {
+               s3c2410_dma_free(prtd->params->channel, prtd->params->client);
+               prtd->params = NULL;
+       }
+
+       return 0;
+}
+
+static int dma_prepare(struct snd_pcm_substream *substream)
+{
+       struct runtime_data *prtd = substream->runtime->private_data;
+       int ret = 0;
+
+       pr_debug("Entered %s\n", __func__);
+
+       /* return if this is a bufferless transfer e.g.
+        * codec <--> BT codec or GSM modem -- lg FIXME */
+       if (!prtd->params)
+               return 0;
+
+       /* channel needs configuring for mem=>device, increment memory addr,
+        * sync to pclk, half-word transfers to the IIS-FIFO. */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               s3c2410_dma_devconfig(prtd->params->channel,
+                                     S3C2410_DMASRC_MEM,
+                                     prtd->params->dma_addr);
+       } else {
+               s3c2410_dma_devconfig(prtd->params->channel,
+                                     S3C2410_DMASRC_HW,
+                                     prtd->params->dma_addr);
+       }
+
+       s3c2410_dma_config(prtd->params->channel,
+                          prtd->params->dma_size);
+
+       /* flush the DMA channel */
+       s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH);
+       prtd->dma_loaded = 0;
+       prtd->dma_pos = prtd->dma_start;
+
+       /* enqueue dma buffers */
+       dma_enqueue(substream);
+
+       return ret;
+}
+
+static int dma_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct runtime_data *prtd = substream->runtime->private_data;
+       int ret = 0;
+
+       pr_debug("Entered %s\n", __func__);
+
+       spin_lock(&prtd->lock);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               prtd->state |= ST_RUNNING;
+               s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START);
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               prtd->state &= ~ST_RUNNING;
+               s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STOP);
+               break;
+
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       spin_unlock(&prtd->lock);
+
+       return ret;
+}
+
+static snd_pcm_uframes_t
+dma_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct runtime_data *prtd = runtime->private_data;
+       unsigned long res;
+       dma_addr_t src, dst;
+
+       pr_debug("Entered %s\n", __func__);
+
+       spin_lock(&prtd->lock);
+       s3c2410_dma_getposition(prtd->params->channel, &src, &dst);
+
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+               res = dst - prtd->dma_start;
+       else
+               res = src - prtd->dma_start;
+
+       spin_unlock(&prtd->lock);
+
+       pr_debug("Pointer %x %x\n", src, dst);
+
+       /* we seem to be getting the odd error from the pcm library due
+        * to out-of-bounds pointers. this is maybe due to the dma engine
+        * not having loaded the new values for the channel before being
+        * callled... (todo - fix )
+        */
+
+       if (res >= snd_pcm_lib_buffer_bytes(substream)) {
+               if (res == snd_pcm_lib_buffer_bytes(substream))
+                       res = 0;
+       }
+
+       return bytes_to_frames(substream->runtime, res);
+}
+
+static int dma_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct runtime_data *prtd;
+
+       pr_debug("Entered %s\n", __func__);
+
+       snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+       snd_soc_set_runtime_hwparams(substream, &dma_hardware);
+
+       prtd = kzalloc(sizeof(struct runtime_data), GFP_KERNEL);
+       if (prtd == NULL)
+               return -ENOMEM;
+
+       spin_lock_init(&prtd->lock);
+
+       runtime->private_data = prtd;
+       return 0;
+}
+
+static int dma_close(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct runtime_data *prtd = runtime->private_data;
+
+       pr_debug("Entered %s\n", __func__);
+
+       if (!prtd)
+               pr_debug("dma_close called with prtd == NULL\n");
+
+       kfree(prtd);
+
+       return 0;
+}
+
+static int dma_mmap(struct snd_pcm_substream *substream,
+       struct vm_area_struct *vma)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       pr_debug("Entered %s\n", __func__);
+
+       return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+                                    runtime->dma_area,
+                                    runtime->dma_addr,
+                                    runtime->dma_bytes);
+}
+
+static struct snd_pcm_ops dma_ops = {
+       .open           = dma_open,
+       .close          = dma_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = dma_hw_params,
+       .hw_free        = dma_hw_free,
+       .prepare        = dma_prepare,
+       .trigger        = dma_trigger,
+       .pointer        = dma_pointer,
+       .mmap           = dma_mmap,
+};
+
+static int 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 = dma_hardware.buffer_bytes_max;
+
+       pr_debug("Entered %s\n", __func__);
+
+       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 void dma_free_dma_buffers(struct snd_pcm *pcm)
+{
+       struct snd_pcm_substream *substream;
+       struct snd_dma_buffer *buf;
+       int stream;
+
+       pr_debug("Entered %s\n", __func__);
+
+       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 dma_mask = DMA_BIT_MASK(32);
+
+static int dma_new(struct snd_card *card,
+       struct snd_soc_dai *dai, struct snd_pcm *pcm)
+{
+       int ret = 0;
+
+       pr_debug("Entered %s\n", __func__);
+
+       if (!card->dev->dma_mask)
+               card->dev->dma_mask = &dma_mask;
+       if (!card->dev->coherent_dma_mask)
+               card->dev->coherent_dma_mask = 0xffffffff;
+
+       if (dai->driver->playback.channels_min) {
+               ret = preallocate_dma_buffer(pcm,
+                       SNDRV_PCM_STREAM_PLAYBACK);
+               if (ret)
+                       goto out;
+       }
+
+       if (dai->driver->capture.channels_min) {
+               ret = preallocate_dma_buffer(pcm,
+                       SNDRV_PCM_STREAM_CAPTURE);
+               if (ret)
+                       goto out;
+       }
+out:
+       return ret;
+}
+
+static struct snd_soc_platform_driver samsung_asoc_platform = {
+       .ops            = &dma_ops,
+       .pcm_new        = dma_new,
+       .pcm_free       = dma_free_dma_buffers,
+};
+
+static int __devinit samsung_asoc_platform_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_platform(&pdev->dev, &samsung_asoc_platform);
+}
+
+static int __devexit samsung_asoc_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver asoc_dma_driver = {
+       .driver = {
+               .name = "samsung-audio",
+               .owner = THIS_MODULE,
+       },
+
+       .probe = samsung_asoc_platform_probe,
+       .remove = __devexit_p(samsung_asoc_platform_remove),
+};
+
+static int __init samsung_asoc_init(void)
+{
+       return platform_driver_register(&asoc_dma_driver);
+}
+module_init(samsung_asoc_init);
+
+static void __exit samsung_asoc_exit(void)
+{
+       platform_driver_unregister(&asoc_dma_driver);
+}
+module_exit(samsung_asoc_exit);
+
+MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("Samsung ASoC DMA Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-audio");
diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h
new file mode 100644 (file)
index 0000000..f8cd2b4
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *  dma.h --
+ *
+ *  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.
+ *
+ *  ALSA PCM interface for the Samsung S3C24xx CPU
+ */
+
+#ifndef _S3C_AUDIO_H
+#define _S3C_AUDIO_H
+
+#define ST_RUNNING             (1<<0)
+#define ST_OPENED              (1<<1)
+
+struct s3c_dma_params {
+       struct s3c2410_dma_client *client;      /* stream identifier */
+       int channel;                            /* Channel ID */
+       dma_addr_t dma_addr;
+       int dma_size;                   /* Size of the DMA transfer */
+};
+
+#define S3C24XX_DAI_I2S                        0
+
+/* platform data */
+extern struct snd_ac97_bus_ops s3c24xx_ac97_ops;
+
+#endif
diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c
new file mode 100644 (file)
index 0000000..34dd9ef
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * goni_wm8994.c
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Chanwoo Choi <cw00.choi@samsung.com>
+ *
+ *  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/moduleparam.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <mach/gpio.h>
+#include <mach/regs-clock.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include "../codecs/wm8994.h"
+#include "dma.h"
+#include "i2s.h"
+
+#define MACHINE_NAME   0
+#define CPU_VOICE_DAI  1
+
+static const char *aquila_str[] = {
+       [MACHINE_NAME] = "aquila",
+       [CPU_VOICE_DAI] = "aquila-voice-dai",
+};
+
+static struct snd_soc_card goni;
+static struct platform_device *goni_snd_device;
+
+/* 3.5 pie jack */
+static struct snd_soc_jack jack;
+
+/* 3.5 pie jack detection DAPM pins */
+static struct snd_soc_jack_pin jack_pins[] = {
+       {
+               .pin = "Headset Mic",
+               .mask = SND_JACK_MICROPHONE,
+       }, {
+               .pin = "Headset Stereophone",
+               .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL |
+                       SND_JACK_AVOUT,
+       },
+};
+
+/* 3.5 pie jack detection gpios */
+static struct snd_soc_jack_gpio jack_gpios[] = {
+       {
+               .gpio = S5PV210_GPH0(6),
+               .name = "DET_3.5",
+               .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL |
+                       SND_JACK_AVOUT,
+               .debounce_time = 200,
+       },
+};
+
+static const struct snd_soc_dapm_widget goni_dapm_widgets[] = {
+       SND_SOC_DAPM_SPK("Ext Left Spk", NULL),
+       SND_SOC_DAPM_SPK("Ext Right Spk", NULL),
+       SND_SOC_DAPM_SPK("Ext Rcv", NULL),
+       SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Main Mic", NULL),
+       SND_SOC_DAPM_MIC("2nd Mic", NULL),
+       SND_SOC_DAPM_LINE("Radio In", NULL),
+};
+
+static const struct snd_soc_dapm_route goni_dapm_routes[] = {
+       {"Ext Left Spk", NULL, "SPKOUTLP"},
+       {"Ext Left Spk", NULL, "SPKOUTLN"},
+
+       {"Ext Right Spk", NULL, "SPKOUTRP"},
+       {"Ext Right Spk", NULL, "SPKOUTRN"},
+
+       {"Ext Rcv", NULL, "HPOUT2N"},
+       {"Ext Rcv", NULL, "HPOUT2P"},
+
+       {"Headset Stereophone", NULL, "HPOUT1L"},
+       {"Headset Stereophone", NULL, "HPOUT1R"},
+
+       {"IN1RN", NULL, "Headset Mic"},
+       {"IN1RP", NULL, "Headset Mic"},
+
+       {"IN1RN", NULL, "2nd Mic"},
+       {"IN1RP", NULL, "2nd Mic"},
+
+       {"IN1LN", NULL, "Main Mic"},
+       {"IN1LP", NULL, "Main Mic"},
+
+       {"IN2LN", NULL, "Radio In"},
+       {"IN2RN", NULL, "Radio In"},
+};
+
+static int goni_wm8994_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       int ret;
+
+       /* add goni specific widgets */
+       snd_soc_dapm_new_controls(dapm, goni_dapm_widgets,
+                       ARRAY_SIZE(goni_dapm_widgets));
+
+       /* set up goni specific audio routes */
+       snd_soc_dapm_add_routes(dapm, goni_dapm_routes,
+                       ARRAY_SIZE(goni_dapm_routes));
+
+       /* set endpoints to not connected */
+       snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN");
+       snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP");
+       snd_soc_dapm_nc_pin(dapm, "LINEOUT1N");
+       snd_soc_dapm_nc_pin(dapm, "LINEOUT1P");
+       snd_soc_dapm_nc_pin(dapm, "LINEOUT2N");
+       snd_soc_dapm_nc_pin(dapm, "LINEOUT2P");
+
+       if (machine_is_aquila()) {
+               snd_soc_dapm_nc_pin(dapm, "SPKOUTRN");
+               snd_soc_dapm_nc_pin(dapm, "SPKOUTRP");
+       }
+
+       snd_soc_dapm_sync(dapm);
+
+       /* Headset jack detection */
+       ret = snd_soc_jack_new(codec, "Headset Jack",
+                       SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT,
+                       &jack);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int goni_hifi_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;
+       unsigned int pll_out = 24000000;
+       int ret = 0;
+
+       /* set the cpu DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       /* set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec FLL */
+       ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out,
+                       params_rate(params) * 256);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec system clock */
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
+                       params_rate(params) * 256, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_ops goni_hifi_ops = {
+       .hw_params = goni_hifi_hw_params,
+};
+
+static int goni_voice_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;
+       unsigned int pll_out = 24000000;
+       int ret = 0;
+
+       if (params_rate(params) != 8000)
+               return -EINVAL;
+
+       /* set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
+                       SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec FLL */
+       ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out,
+                       params_rate(params) * 256);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec system clock */
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
+                       params_rate(params) * 256, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_dai_driver voice_dai = {
+       .name = "goni-voice-dai",
+       .id = 0,
+       .playback = {
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+};
+
+static struct snd_soc_ops goni_voice_ops = {
+       .hw_params = goni_voice_hw_params,
+};
+
+static struct snd_soc_dai_link goni_dai[] = {
+{
+       .name = "WM8994",
+       .stream_name = "WM8994 HiFi",
+       .cpu_dai_name = "samsung-i2s.0",
+       .codec_dai_name = "wm8994-hifi",
+       .platform_name = "samsung-audio",
+       .codec_name = "wm8994-codec.0-0x1a",
+       .init = goni_wm8994_init,
+       .ops = &goni_hifi_ops,
+}, {
+       .name = "WM8994 Voice",
+       .stream_name = "Voice",
+       .cpu_dai_name = "goni-voice-dai",
+       .codec_dai_name = "wm8994-voice",
+       .platform_name = "samsung-audio",
+       .codec_name = "wm8994-codec.0-0x1a",
+       .ops = &goni_voice_ops,
+},
+};
+
+static struct snd_soc_card goni = {
+       .name = "goni",
+       .dai_link = goni_dai,
+       .num_links = ARRAY_SIZE(goni_dai),
+};
+
+static int __init goni_init(void)
+{
+       int ret;
+
+       if (machine_is_aquila()) {
+               voice_dai.name = aquila_str[CPU_VOICE_DAI];
+               goni_dai[1].cpu_dai_name = aquila_str[CPU_VOICE_DAI];
+               goni.name = aquila_str[MACHINE_NAME];
+       } else if (!machine_is_goni())
+               return -ENODEV;
+
+       goni_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!goni_snd_device)
+               return -ENOMEM;
+
+       /* register voice DAI here */
+       ret = snd_soc_register_dai(&goni_snd_device->dev, &voice_dai);
+       if (ret) {
+               platform_device_put(goni_snd_device);
+               return ret;
+       }
+
+       platform_set_drvdata(goni_snd_device, &goni);
+       ret = platform_device_add(goni_snd_device);
+
+       if (ret) {
+               snd_soc_unregister_dai(&goni_snd_device->dev);
+               platform_device_put(goni_snd_device);
+       }
+
+       return ret;
+}
+
+static void __exit goni_exit(void)
+{
+       snd_soc_unregister_dai(&goni_snd_device->dev);
+       platform_device_unregister(goni_snd_device);
+}
+
+module_init(goni_init);
+module_exit(goni_exit);
+
+/* Module information */
+MODULE_DESCRIPTION("ALSA SoC WM8994 GONI(S5PV210)");
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c
new file mode 100644 (file)
index 0000000..c45f7ce
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * h1940-uda1380.c  --  ALSA Soc Audio Layer
+ *
+ * Copyright (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
+ * Copyright (c) 2010 Vasily Khoruzhick <anarsoul@gmail.com>
+ *
+ * Based on version from Arnaud Patard <arnaud.patard@rtp-net.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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+
+#include <sound/soc.h>
+#include <sound/uda1380.h>
+#include <sound/jack.h>
+
+#include <plat/regs-iis.h>
+
+#include <mach/h1940-latch.h>
+
+#include <asm/mach-types.h>
+
+#include "dma.h"
+#include "s3c24xx-i2s.h"
+#include "../codecs/uda1380.h"
+
+static unsigned int rates[] = {
+       11025,
+       22050,
+       44100,
+};
+
+static struct snd_pcm_hw_constraint_list hw_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list = rates,
+       .mask = 0,
+};
+
+static struct snd_soc_jack hp_jack;
+
+static struct snd_soc_jack_pin hp_jack_pins[] = {
+       {
+               .pin    = "Headphone Jack",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Speaker",
+               .mask   = SND_JACK_HEADPHONE,
+               .invert = 1,
+       },
+};
+
+static struct snd_soc_jack_gpio hp_jack_gpios[] = {
+       {
+               .gpio                   = S3C2410_GPG(4),
+               .name                   = "hp-gpio",
+               .report                 = SND_JACK_HEADPHONE,
+               .invert                 = 1,
+               .debounce_time          = 200,
+       },
+};
+
+static int h1940_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       runtime->hw.rate_min = hw_rates.list[0];
+       runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1];
+       runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
+
+       return snd_pcm_hw_constraint_list(runtime, 0,
+                                       SNDRV_PCM_HW_PARAM_RATE,
+                                       &hw_rates);
+}
+
+static int h1940_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;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int div;
+       int ret;
+       unsigned int rate = params_rate(params);
+
+       switch (rate) {
+       case 11025:
+       case 22050:
+       case 44100:
+               div = s3c24xx_i2s_get_clockrate() / (384 * rate);
+               if (s3c24xx_i2s_get_clockrate() % (384 * rate) > (192 * rate))
+                       div++;
+               break;
+       default:
+               dev_err(&rtd->dev, "%s: rate %d is not supported\n",
+                       __func__, rate);
+               return -EINVAL;
+       }
+
+       /* set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* set cpu DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* select clock source */
+       ret = snd_soc_dai_set_sysclk(cpu_dai, S3C24XX_CLKSRC_PCLK, rate,
+                       SND_SOC_CLOCK_OUT);
+       if (ret < 0)
+               return ret;
+
+       /* set MCLK division for sample rate */
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
+               S3C2410_IISMOD_384FS);
+       if (ret < 0)
+               return ret;
+
+       /* set BCLK division for sample rate */
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
+               S3C2410_IISMOD_32FS);
+       if (ret < 0)
+               return ret;
+
+       /* set prescaler division for sample rate */
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+               S3C24XX_PRESCALE(div, div));
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_ops h1940_ops = {
+       .startup        = h1940_startup,
+       .hw_params      = h1940_hw_params,
+};
+
+static int h1940_spk_power(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol, int event)
+{
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               gpio_set_value(H1940_LATCH_AUDIO_POWER, 1);
+       else
+               gpio_set_value(H1940_LATCH_AUDIO_POWER, 0);
+
+       return 0;
+}
+
+/* h1940 machine dapm widgets */
+static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+       SND_SOC_DAPM_SPK("Speaker", h1940_spk_power),
+};
+
+/* h1940 machine audio_map */
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* headphone connected to VOUTLHP, VOUTRHP */
+       {"Headphone Jack", NULL, "VOUTLHP"},
+       {"Headphone Jack", NULL, "VOUTRHP"},
+
+       /* ext speaker connected to VOUTL, VOUTR  */
+       {"Speaker", NULL, "VOUTL"},
+       {"Speaker", NULL, "VOUTR"},
+
+       /* mic is connected to VINM */
+       {"VINM", NULL, "Mic Jack"},
+};
+
+static struct platform_device *s3c24xx_snd_device;
+
+static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       int err;
+
+       /* Add h1940 specific widgets */
+       err = snd_soc_dapm_new_controls(dapm, uda1380_dapm_widgets,
+                                 ARRAY_SIZE(uda1380_dapm_widgets));
+       if (err)
+               return err;
+
+       /* Set up h1940 specific audio path audio_mapnects */
+       err = snd_soc_dapm_add_routes(dapm, audio_map,
+                                     ARRAY_SIZE(audio_map));
+       if (err)
+               return err;
+
+       snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+       snd_soc_dapm_enable_pin(dapm, "Speaker");
+       snd_soc_dapm_enable_pin(dapm, "Mic Jack");
+
+       snd_soc_dapm_sync(dapm);
+
+       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
+               &hp_jack);
+
+       snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
+               hp_jack_pins);
+
+       snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
+               hp_jack_gpios);
+
+       return 0;
+}
+
+/* s3c24xx digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link h1940_uda1380_dai[] = {
+       {
+               .name           = "uda1380",
+               .stream_name    = "UDA1380 Duplex",
+               .cpu_dai_name   = "s3c24xx-iis",
+               .codec_dai_name = "uda1380-hifi",
+               .init           = h1940_uda1380_init,
+               .platform_name  = "samsung-audio",
+               .codec_name     = "uda1380-codec.0-001a",
+               .ops            = &h1940_ops,
+       },
+};
+
+static struct snd_soc_card h1940_asoc = {
+       .name = "h1940",
+       .dai_link = h1940_uda1380_dai,
+       .num_links = ARRAY_SIZE(h1940_uda1380_dai),
+};
+
+static int __init h1940_init(void)
+{
+       int ret;
+
+       if (!machine_is_h1940())
+               return -ENODEV;
+
+       /* configure some gpios */
+       ret = gpio_request(H1940_LATCH_AUDIO_POWER, "speaker-power");
+       if (ret)
+               goto err_out;
+
+       ret = gpio_direction_output(H1940_LATCH_AUDIO_POWER, 0);
+       if (ret)
+               goto err_gpio;
+
+       s3c24xx_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!s3c24xx_snd_device) {
+               ret = -ENOMEM;
+               goto err_gpio;
+       }
+
+       platform_set_drvdata(s3c24xx_snd_device, &h1940_asoc);
+       ret = platform_device_add(s3c24xx_snd_device);
+
+       if (ret)
+               goto err_plat;
+
+       return 0;
+
+err_plat:
+       platform_device_put(s3c24xx_snd_device);
+err_gpio:
+       gpio_free(H1940_LATCH_AUDIO_POWER);
+
+err_out:
+       return ret;
+}
+
+static void __exit h1940_exit(void)
+{
+       platform_device_unregister(s3c24xx_snd_device);
+       snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
+               hp_jack_gpios);
+       gpio_free(H1940_LATCH_AUDIO_POWER);
+}
+
+module_init(h1940_init);
+module_exit(h1940_exit);
+
+/* Module information */
+MODULE_AUTHOR("Arnaud Patard, Vasily Khoruzhick");
+MODULE_DESCRIPTION("ALSA SoC H1940");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
new file mode 100644 (file)
index 0000000..d00ac3a
--- /dev/null
@@ -0,0 +1,1258 @@
+/* sound/soc/samsung/i2s.c
+ *
+ * ALSA SoC Audio Layer - Samsung I2S Controller driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd.
+ *     Jaswinder Singh <jassi.brar@samsung.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/delay.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <plat/audio.h>
+
+#include "dma.h"
+#include "i2s.h"
+
+#define I2SCON         0x0
+#define I2SMOD         0x4
+#define I2SFIC         0x8
+#define I2SPSR         0xc
+#define I2STXD         0x10
+#define I2SRXD         0x14
+#define I2SFICS                0x18
+#define I2STXDS                0x1c
+
+#define CON_RSTCLR             (1 << 31)
+#define CON_FRXOFSTATUS                (1 << 26)
+#define CON_FRXORINTEN         (1 << 25)
+#define CON_FTXSURSTAT         (1 << 24)
+#define CON_FTXSURINTEN                (1 << 23)
+#define CON_TXSDMA_PAUSE       (1 << 20)
+#define CON_TXSDMA_ACTIVE      (1 << 18)
+
+#define CON_FTXURSTATUS                (1 << 17)
+#define CON_FTXURINTEN         (1 << 16)
+#define CON_TXFIFO2_EMPTY      (1 << 15)
+#define CON_TXFIFO1_EMPTY      (1 << 14)
+#define CON_TXFIFO2_FULL       (1 << 13)
+#define CON_TXFIFO1_FULL       (1 << 12)
+
+#define CON_LRINDEX            (1 << 11)
+#define CON_TXFIFO_EMPTY       (1 << 10)
+#define CON_RXFIFO_EMPTY       (1 << 9)
+#define CON_TXFIFO_FULL                (1 << 8)
+#define CON_RXFIFO_FULL                (1 << 7)
+#define CON_TXDMA_PAUSE                (1 << 6)
+#define CON_RXDMA_PAUSE                (1 << 5)
+#define CON_TXCH_PAUSE         (1 << 4)
+#define CON_RXCH_PAUSE         (1 << 3)
+#define CON_TXDMA_ACTIVE       (1 << 2)
+#define CON_RXDMA_ACTIVE       (1 << 1)
+#define CON_ACTIVE             (1 << 0)
+
+#define MOD_OPCLK_CDCLK_OUT    (0 << 30)
+#define MOD_OPCLK_CDCLK_IN     (1 << 30)
+#define MOD_OPCLK_BCLK_OUT     (2 << 30)
+#define MOD_OPCLK_PCLK         (3 << 30)
+#define MOD_OPCLK_MASK         (3 << 30)
+#define MOD_TXS_IDMA           (1 << 28) /* Sec_TXFIFO use I-DMA */
+
+#define MOD_BLCS_SHIFT 26
+#define MOD_BLCS_16BIT (0 << MOD_BLCS_SHIFT)
+#define MOD_BLCS_8BIT  (1 << MOD_BLCS_SHIFT)
+#define MOD_BLCS_24BIT (2 << MOD_BLCS_SHIFT)
+#define MOD_BLCS_MASK  (3 << MOD_BLCS_SHIFT)
+#define MOD_BLCP_SHIFT 24
+#define MOD_BLCP_16BIT (0 << MOD_BLCP_SHIFT)
+#define MOD_BLCP_8BIT  (1 << MOD_BLCP_SHIFT)
+#define MOD_BLCP_24BIT (2 << MOD_BLCP_SHIFT)
+#define MOD_BLCP_MASK  (3 << MOD_BLCP_SHIFT)
+
+#define MOD_C2DD_HHALF         (1 << 21) /* Discard Higher-half */
+#define MOD_C2DD_LHALF         (1 << 20) /* Discard Lower-half */
+#define MOD_C1DD_HHALF         (1 << 19)
+#define MOD_C1DD_LHALF         (1 << 18)
+#define MOD_DC2_EN             (1 << 17)
+#define MOD_DC1_EN             (1 << 16)
+#define MOD_BLC_16BIT          (0 << 13)
+#define MOD_BLC_8BIT           (1 << 13)
+#define MOD_BLC_24BIT          (2 << 13)
+#define MOD_BLC_MASK           (3 << 13)
+
+#define MOD_IMS_SYSMUX         (1 << 10)
+#define MOD_SLAVE              (1 << 11)
+#define MOD_TXONLY             (0 << 8)
+#define MOD_RXONLY             (1 << 8)
+#define MOD_TXRX               (2 << 8)
+#define MOD_MASK               (3 << 8)
+#define MOD_LR_LLOW            (0 << 7)
+#define MOD_LR_RLOW            (1 << 7)
+#define MOD_SDF_IIS            (0 << 5)
+#define MOD_SDF_MSB            (1 << 5)
+#define MOD_SDF_LSB            (2 << 5)
+#define MOD_SDF_MASK           (3 << 5)
+#define MOD_RCLK_256FS         (0 << 3)
+#define MOD_RCLK_512FS         (1 << 3)
+#define MOD_RCLK_384FS         (2 << 3)
+#define MOD_RCLK_768FS         (3 << 3)
+#define MOD_RCLK_MASK          (3 << 3)
+#define MOD_BCLK_32FS          (0 << 1)
+#define MOD_BCLK_48FS          (1 << 1)
+#define MOD_BCLK_16FS          (2 << 1)
+#define MOD_BCLK_24FS          (3 << 1)
+#define MOD_BCLK_MASK          (3 << 1)
+#define MOD_8BIT               (1 << 0)
+
+#define MOD_CDCLKCON           (1 << 12)
+
+#define PSR_PSREN              (1 << 15)
+
+#define FIC_TX2COUNT(x)                (((x) >>  24) & 0xf)
+#define FIC_TX1COUNT(x)                (((x) >>  16) & 0xf)
+
+#define FIC_TXFLUSH            (1 << 15)
+#define FIC_RXFLUSH            (1 << 7)
+#define FIC_TXCOUNT(x)         (((x) >>  8) & 0xf)
+#define FIC_RXCOUNT(x)         (((x) >>  0) & 0xf)
+#define FICS_TXCOUNT(x)                (((x) >>  8) & 0x7f)
+
+#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
+
+struct i2s_dai {
+       /* Platform device for this DAI */
+       struct platform_device *pdev;
+       /* IOREMAP'd SFRs */
+       void __iomem    *addr;
+       /* Physical base address of SFRs */
+       u32     base;
+       /* Rate of RCLK source clock */
+       unsigned long rclk_srcrate;
+       /* Frame Clock */
+       unsigned frmclk;
+       /*
+        * Specifically requested RCLK,BCLK by MACHINE Driver.
+        * 0 indicates CPU driver is free to choose any value.
+        */
+       unsigned rfs, bfs;
+       /* I2S Controller's core clock */
+       struct clk *clk;
+       /* Clock for generating I2S signals */
+       struct clk *op_clk;
+       /* Array of clock names for op_clk */
+       const char **src_clk;
+       /* Pointer to the Primary_Fifo if this is Sec_Fifo, NULL otherwise */
+       struct i2s_dai *pri_dai;
+       /* Pointer to the Secondary_Fifo if it has one, NULL otherwise */
+       struct i2s_dai *sec_dai;
+#define DAI_OPENED     (1 << 0) /* Dai is opened */
+#define DAI_MANAGER    (1 << 1) /* Dai is the manager */
+       unsigned mode;
+       /* Driver for this DAI */
+       struct snd_soc_dai_driver i2s_dai_drv;
+       /* DMA parameters */
+       struct s3c_dma_params dma_playback;
+       struct s3c_dma_params dma_capture;
+       u32     quirks;
+       u32     suspend_i2smod;
+       u32     suspend_i2scon;
+       u32     suspend_i2spsr;
+};
+
+/* Lock for cross i/f checks */
+static DEFINE_SPINLOCK(lock);
+
+/* If this is the 'overlay' stereo DAI */
+static inline bool is_secondary(struct i2s_dai *i2s)
+{
+       return i2s->pri_dai ? true : false;
+}
+
+/* If operating in SoC-Slave mode */
+static inline bool is_slave(struct i2s_dai *i2s)
+{
+       return (readl(i2s->addr + I2SMOD) & MOD_SLAVE) ? true : false;
+}
+
+/* If this interface of the controller is transmitting data */
+static inline bool tx_active(struct i2s_dai *i2s)
+{
+       u32 active;
+
+       if (!i2s)
+               return false;
+
+       active = readl(i2s->addr + I2SMOD);
+
+       if (is_secondary(i2s))
+               active &= CON_TXSDMA_ACTIVE;
+       else
+               active &= CON_TXDMA_ACTIVE;
+
+       return active ? true : false;
+}
+
+/* If the other interface of the controller is transmitting data */
+static inline bool other_tx_active(struct i2s_dai *i2s)
+{
+       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+
+       return tx_active(other);
+}
+
+/* If any interface of the controller is transmitting data */
+static inline bool any_tx_active(struct i2s_dai *i2s)
+{
+       return tx_active(i2s) || other_tx_active(i2s);
+}
+
+/* If this interface of the controller is receiving data */
+static inline bool rx_active(struct i2s_dai *i2s)
+{
+       u32 active;
+
+       if (!i2s)
+               return false;
+
+       active = readl(i2s->addr + I2SMOD) & CON_RXDMA_ACTIVE;
+
+       return active ? true : false;
+}
+
+/* If the other interface of the controller is receiving data */
+static inline bool other_rx_active(struct i2s_dai *i2s)
+{
+       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+
+       return rx_active(other);
+}
+
+/* If any interface of the controller is receiving data */
+static inline bool any_rx_active(struct i2s_dai *i2s)
+{
+       return rx_active(i2s) || other_rx_active(i2s);
+}
+
+/* If the other DAI is transmitting or receiving data */
+static inline bool other_active(struct i2s_dai *i2s)
+{
+       return other_rx_active(i2s) || other_tx_active(i2s);
+}
+
+/* If this DAI is transmitting or receiving data */
+static inline bool this_active(struct i2s_dai *i2s)
+{
+       return tx_active(i2s) || rx_active(i2s);
+}
+
+/* If the controller is active anyway */
+static inline bool any_active(struct i2s_dai *i2s)
+{
+       return this_active(i2s) || other_active(i2s);
+}
+
+static inline struct i2s_dai *to_info(struct snd_soc_dai *dai)
+{
+       return snd_soc_dai_get_drvdata(dai);
+}
+
+static inline bool is_opened(struct i2s_dai *i2s)
+{
+       if (i2s && (i2s->mode & DAI_OPENED))
+               return true;
+       else
+               return false;
+}
+
+static inline bool is_manager(struct i2s_dai *i2s)
+{
+       if (is_opened(i2s) && (i2s->mode & DAI_MANAGER))
+               return true;
+       else
+               return false;
+}
+
+/* Read RCLK of I2S (in multiples of LRCLK) */
+static inline unsigned get_rfs(struct i2s_dai *i2s)
+{
+       u32 rfs = (readl(i2s->addr + I2SMOD) >> 3) & 0x3;
+
+       switch (rfs) {
+       case 3: return 768;
+       case 2: return 384;
+       case 1: return 512;
+       default: return 256;
+       }
+}
+
+/* Write RCLK of I2S (in multiples of LRCLK) */
+static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
+{
+       u32 mod = readl(i2s->addr + I2SMOD);
+
+       mod &= ~MOD_RCLK_MASK;
+
+       switch (rfs) {
+       case 768:
+               mod |= MOD_RCLK_768FS;
+               break;
+       case 512:
+               mod |= MOD_RCLK_512FS;
+               break;
+       case 384:
+               mod |= MOD_RCLK_384FS;
+               break;
+       default:
+               mod |= MOD_RCLK_256FS;
+               break;
+       }
+
+       writel(mod, i2s->addr + I2SMOD);
+}
+
+/* Read Bit-Clock of I2S (in multiples of LRCLK) */
+static inline unsigned get_bfs(struct i2s_dai *i2s)
+{
+       u32 bfs = (readl(i2s->addr + I2SMOD) >> 1) & 0x3;
+
+       switch (bfs) {
+       case 3: return 24;
+       case 2: return 16;
+       case 1: return 48;
+       default: return 32;
+       }
+}
+
+/* Write Bit-Clock of I2S (in multiples of LRCLK) */
+static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs)
+{
+       u32 mod = readl(i2s->addr + I2SMOD);
+
+       mod &= ~MOD_BCLK_MASK;
+
+       switch (bfs) {
+       case 48:
+               mod |= MOD_BCLK_48FS;
+               break;
+       case 32:
+               mod |= MOD_BCLK_32FS;
+               break;
+       case 24:
+               mod |= MOD_BCLK_24FS;
+               break;
+       case 16:
+               mod |= MOD_BCLK_16FS;
+               break;
+       default:
+               dev_err(&i2s->pdev->dev, "Wrong BCLK Divider!\n");
+               return;
+       }
+
+       writel(mod, i2s->addr + I2SMOD);
+}
+
+/* Sample-Size */
+static inline int get_blc(struct i2s_dai *i2s)
+{
+       int blc = readl(i2s->addr + I2SMOD);
+
+       blc = (blc >> 13) & 0x3;
+
+       switch (blc) {
+       case 2: return 24;
+       case 1: return 8;
+       default: return 16;
+       }
+}
+
+/* TX Channel Control */
+static void i2s_txctrl(struct i2s_dai *i2s, int on)
+{
+       void __iomem *addr = i2s->addr;
+       u32 con = readl(addr + I2SCON);
+       u32 mod = readl(addr + I2SMOD) & ~MOD_MASK;
+
+       if (on) {
+               con |= CON_ACTIVE;
+               con &= ~CON_TXCH_PAUSE;
+
+               if (is_secondary(i2s)) {
+                       con |= CON_TXSDMA_ACTIVE;
+                       con &= ~CON_TXSDMA_PAUSE;
+               } else {
+                       con |= CON_TXDMA_ACTIVE;
+                       con &= ~CON_TXDMA_PAUSE;
+               }
+
+               if (any_rx_active(i2s))
+                       mod |= MOD_TXRX;
+               else
+                       mod |= MOD_TXONLY;
+       } else {
+               if (is_secondary(i2s)) {
+                       con |=  CON_TXSDMA_PAUSE;
+                       con &= ~CON_TXSDMA_ACTIVE;
+               } else {
+                       con |=  CON_TXDMA_PAUSE;
+                       con &= ~CON_TXDMA_ACTIVE;
+               }
+
+               if (other_tx_active(i2s)) {
+                       writel(con, addr + I2SCON);
+                       return;
+               }
+
+               con |=  CON_TXCH_PAUSE;
+
+               if (any_rx_active(i2s))
+                       mod |= MOD_RXONLY;
+               else
+                       con &= ~CON_ACTIVE;
+       }
+
+       writel(mod, addr + I2SMOD);
+       writel(con, addr + I2SCON);
+}
+
+/* RX Channel Control */
+static void i2s_rxctrl(struct i2s_dai *i2s, int on)
+{
+       void __iomem *addr = i2s->addr;
+       u32 con = readl(addr + I2SCON);
+       u32 mod = readl(addr + I2SMOD) & ~MOD_MASK;
+
+       if (on) {
+               con |= CON_RXDMA_ACTIVE | CON_ACTIVE;
+               con &= ~(CON_RXDMA_PAUSE | CON_RXCH_PAUSE);
+
+               if (any_tx_active(i2s))
+                       mod |= MOD_TXRX;
+               else
+                       mod |= MOD_RXONLY;
+       } else {
+               con |=  CON_RXDMA_PAUSE | CON_RXCH_PAUSE;
+               con &= ~CON_RXDMA_ACTIVE;
+
+               if (any_tx_active(i2s))
+                       mod |= MOD_TXONLY;
+               else
+                       con &= ~CON_ACTIVE;
+       }
+
+       writel(mod, addr + I2SMOD);
+       writel(con, addr + I2SCON);
+}
+
+/* Flush FIFO of an interface */
+static inline void i2s_fifo(struct i2s_dai *i2s, u32 flush)
+{
+       void __iomem *fic;
+       u32 val;
+
+       if (!i2s)
+               return;
+
+       if (is_secondary(i2s))
+               fic = i2s->addr + I2SFICS;
+       else
+               fic = i2s->addr + I2SFIC;
+
+       /* Flush the FIFO */
+       writel(readl(fic) | flush, fic);
+
+       /* Be patient */
+       val = msecs_to_loops(1) / 1000; /* 1 usec */
+       while (--val)
+               cpu_relax();
+
+       writel(readl(fic) & ~flush, fic);
+}
+
+static int i2s_set_sysclk(struct snd_soc_dai *dai,
+         int clk_id, unsigned int rfs, int dir)
+{
+       struct i2s_dai *i2s = to_info(dai);
+       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+       u32 mod = readl(i2s->addr + I2SMOD);
+
+       switch (clk_id) {
+       case SAMSUNG_I2S_CDCLK:
+               /* Shouldn't matter in GATING(CLOCK_IN) mode */
+               if (dir == SND_SOC_CLOCK_IN)
+                       rfs = 0;
+
+               if ((rfs && other->rfs && (other->rfs != rfs)) ||
+                               (any_active(i2s) &&
+                               (((dir == SND_SOC_CLOCK_IN)
+                                       && !(mod & MOD_CDCLKCON)) ||
+                               ((dir == SND_SOC_CLOCK_OUT)
+                                       && (mod & MOD_CDCLKCON))))) {
+                       dev_err(&i2s->pdev->dev,
+                               "%s:%d Other DAI busy\n", __func__, __LINE__);
+                       return -EAGAIN;
+               }
+
+               if (dir == SND_SOC_CLOCK_IN)
+                       mod |= MOD_CDCLKCON;
+               else
+                       mod &= ~MOD_CDCLKCON;
+
+               i2s->rfs = rfs;
+               break;
+
+       case SAMSUNG_I2S_RCLKSRC_0: /* clock corrsponding to IISMOD[10] := 0 */
+       case SAMSUNG_I2S_RCLKSRC_1: /* clock corrsponding to IISMOD[10] := 1 */
+               if ((i2s->quirks & QUIRK_NO_MUXPSR)
+                               || (clk_id == SAMSUNG_I2S_RCLKSRC_0))
+                       clk_id = 0;
+               else
+                       clk_id = 1;
+
+               if (!any_active(i2s)) {
+                       if (i2s->op_clk) {
+                               if ((clk_id && !(mod & MOD_IMS_SYSMUX)) ||
+                                       (!clk_id && (mod & MOD_IMS_SYSMUX))) {
+                                       clk_disable(i2s->op_clk);
+                                       clk_put(i2s->op_clk);
+                               } else {
+                                       i2s->rclk_srcrate =
+                                               clk_get_rate(i2s->op_clk);
+                                       return 0;
+                               }
+                       }
+
+                       i2s->op_clk = clk_get(&i2s->pdev->dev,
+                                               i2s->src_clk[clk_id]);
+                       clk_enable(i2s->op_clk);
+                       i2s->rclk_srcrate = clk_get_rate(i2s->op_clk);
+
+                       /* Over-ride the other's */
+                       if (other) {
+                               other->op_clk = i2s->op_clk;
+                               other->rclk_srcrate = i2s->rclk_srcrate;
+                       }
+               } else if ((!clk_id && (mod & MOD_IMS_SYSMUX))
+                               || (clk_id && !(mod & MOD_IMS_SYSMUX))) {
+                       dev_err(&i2s->pdev->dev,
+                               "%s:%d Other DAI busy\n", __func__, __LINE__);
+                       return -EAGAIN;
+               } else {
+                       /* Call can't be on the active DAI */
+                       i2s->op_clk = other->op_clk;
+                       i2s->rclk_srcrate = other->rclk_srcrate;
+                       return 0;
+               }
+
+               if (clk_id == 0)
+                       mod &= ~MOD_IMS_SYSMUX;
+               else
+                       mod |= MOD_IMS_SYSMUX;
+               break;
+
+       default:
+               dev_err(&i2s->pdev->dev, "We don't serve that!\n");
+               return -EINVAL;
+       }
+
+       writel(mod, i2s->addr + I2SMOD);
+
+       return 0;
+}
+
+static int i2s_set_fmt(struct snd_soc_dai *dai,
+       unsigned int fmt)
+{
+       struct i2s_dai *i2s = to_info(dai);
+       u32 mod = readl(i2s->addr + I2SMOD);
+       u32 tmp = 0;
+
+       /* Format is priority */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_RIGHT_J:
+               tmp |= MOD_LR_RLOW;
+               tmp |= MOD_SDF_MSB;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               tmp |= MOD_LR_RLOW;
+               tmp |= MOD_SDF_LSB;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               tmp |= MOD_SDF_IIS;
+               break;
+       default:
+               dev_err(&i2s->pdev->dev, "Format not supported\n");
+               return -EINVAL;
+       }
+
+       /*
+        * INV flag is relative to the FORMAT flag - if set it simply
+        * flips the polarity specified by the Standard
+        */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               if (tmp & MOD_LR_RLOW)
+                       tmp &= ~MOD_LR_RLOW;
+               else
+                       tmp |= MOD_LR_RLOW;
+               break;
+       default:
+               dev_err(&i2s->pdev->dev, "Polarity not supported\n");
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               tmp |= MOD_SLAVE;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               /* Set default source clock in Master mode */
+               if (i2s->rclk_srcrate == 0)
+                       i2s_set_sysclk(dai, SAMSUNG_I2S_RCLKSRC_0,
+                                                       0, SND_SOC_CLOCK_IN);
+               break;
+       default:
+               dev_err(&i2s->pdev->dev, "master/slave format not supported\n");
+               return -EINVAL;
+       }
+
+       if (any_active(i2s) &&
+                       ((mod & (MOD_SDF_MASK | MOD_LR_RLOW
+                               | MOD_SLAVE)) != tmp)) {
+               dev_err(&i2s->pdev->dev,
+                               "%s:%d Other DAI busy\n", __func__, __LINE__);
+               return -EAGAIN;
+       }
+
+       mod &= ~(MOD_SDF_MASK | MOD_LR_RLOW | MOD_SLAVE);
+       mod |= tmp;
+       writel(mod, i2s->addr + I2SMOD);
+
+       return 0;
+}
+
+static int i2s_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+       struct i2s_dai *i2s = to_info(dai);
+       u32 mod = readl(i2s->addr + I2SMOD);
+
+       if (!is_secondary(i2s))
+               mod &= ~(MOD_DC2_EN | MOD_DC1_EN);
+
+       switch (params_channels(params)) {
+       case 6:
+               mod |= MOD_DC2_EN;
+       case 4:
+               mod |= MOD_DC1_EN;
+               break;
+       case 2:
+               break;
+       default:
+               dev_err(&i2s->pdev->dev, "%d channels not supported\n",
+                               params_channels(params));
+               return -EINVAL;
+       }
+
+       if (is_secondary(i2s))
+               mod &= ~MOD_BLCS_MASK;
+       else
+               mod &= ~MOD_BLCP_MASK;
+
+       if (is_manager(i2s))
+               mod &= ~MOD_BLC_MASK;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S8:
+               if (is_secondary(i2s))
+                       mod |= MOD_BLCS_8BIT;
+               else
+                       mod |= MOD_BLCP_8BIT;
+               if (is_manager(i2s))
+                       mod |= MOD_BLC_8BIT;
+               break;
+       case SNDRV_PCM_FORMAT_S16_LE:
+               if (is_secondary(i2s))
+                       mod |= MOD_BLCS_16BIT;
+               else
+                       mod |= MOD_BLCP_16BIT;
+               if (is_manager(i2s))
+                       mod |= MOD_BLC_16BIT;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               if (is_secondary(i2s))
+                       mod |= MOD_BLCS_24BIT;
+               else
+                       mod |= MOD_BLCP_24BIT;
+               if (is_manager(i2s))
+                       mod |= MOD_BLC_24BIT;
+               break;
+       default:
+               dev_err(&i2s->pdev->dev, "Format(%d) not supported\n",
+                               params_format(params));
+               return -EINVAL;
+       }
+       writel(mod, i2s->addr + I2SMOD);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               snd_soc_dai_set_dma_data(dai, substream,
+                       (void *)&i2s->dma_playback);
+       else
+               snd_soc_dai_set_dma_data(dai, substream,
+                       (void *)&i2s->dma_capture);
+
+       i2s->frmclk = params_rate(params);
+
+       return 0;
+}
+
+/* We set constraints on the substream acc to the version of I2S */
+static int i2s_startup(struct snd_pcm_substream *substream,
+         struct snd_soc_dai *dai)
+{
+       struct i2s_dai *i2s = to_info(dai);
+       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+       unsigned long flags;
+
+       spin_lock_irqsave(&lock, flags);
+
+       i2s->mode |= DAI_OPENED;
+
+       if (is_manager(other))
+               i2s->mode &= ~DAI_MANAGER;
+       else
+               i2s->mode |= DAI_MANAGER;
+
+       /* Enforce set_sysclk in Master mode */
+       i2s->rclk_srcrate = 0;
+
+       spin_unlock_irqrestore(&lock, flags);
+
+       return 0;
+}
+
+static void i2s_shutdown(struct snd_pcm_substream *substream,
+       struct snd_soc_dai *dai)
+{
+       struct i2s_dai *i2s = to_info(dai);
+       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+       unsigned long flags;
+
+       spin_lock_irqsave(&lock, flags);
+
+       i2s->mode &= ~DAI_OPENED;
+       i2s->mode &= ~DAI_MANAGER;
+
+       if (is_opened(other))
+               other->mode |= DAI_MANAGER;
+
+       /* Reset any constraint on RFS and BFS */
+       i2s->rfs = 0;
+       i2s->bfs = 0;
+
+       spin_unlock_irqrestore(&lock, flags);
+
+       /* Gate CDCLK by default */
+       if (!is_opened(other))
+               i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
+                               0, SND_SOC_CLOCK_IN);
+}
+
+static int config_setup(struct i2s_dai *i2s)
+{
+       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+       unsigned rfs, bfs, blc;
+       u32 psr;
+
+       blc = get_blc(i2s);
+
+       bfs = i2s->bfs;
+
+       if (!bfs && other)
+               bfs = other->bfs;
+
+       /* Select least possible multiple(2) if no constraint set */
+       if (!bfs)
+               bfs = blc * 2;
+
+       rfs = i2s->rfs;
+
+       if (!rfs && other)
+               rfs = other->rfs;
+
+       if ((rfs == 256 || rfs == 512) && (blc == 24)) {
+               dev_err(&i2s->pdev->dev,
+                       "%d-RFS not supported for 24-blc\n", rfs);
+               return -EINVAL;
+       }
+
+       if (!rfs) {
+               if (bfs == 16 || bfs == 32)
+                       rfs = 256;
+               else
+                       rfs = 384;
+       }
+
+       /* If already setup and running */
+       if (any_active(i2s) && (get_rfs(i2s) != rfs || get_bfs(i2s) != bfs)) {
+               dev_err(&i2s->pdev->dev,
+                               "%s:%d Other DAI busy\n", __func__, __LINE__);
+               return -EAGAIN;
+       }
+
+       /* Don't bother RFS, BFS & PSR in Slave mode */
+       if (is_slave(i2s))
+               return 0;
+
+       set_bfs(i2s, bfs);
+       set_rfs(i2s, rfs);
+
+       if (!(i2s->quirks & QUIRK_NO_MUXPSR)) {
+               psr = i2s->rclk_srcrate / i2s->frmclk / rfs;
+               writel(((psr - 1) << 8) | PSR_PSREN, i2s->addr + I2SPSR);
+               dev_dbg(&i2s->pdev->dev,
+                       "RCLK_SRC=%luHz PSR=%u, RCLK=%dfs, BCLK=%dfs\n",
+                               i2s->rclk_srcrate, psr, rfs, bfs);
+       }
+
+       return 0;
+}
+
+static int i2s_trigger(struct snd_pcm_substream *substream,
+       int cmd, struct snd_soc_dai *dai)
+{
+       int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct i2s_dai *i2s = to_info(rtd->cpu_dai);
+       unsigned long flags;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               local_irq_save(flags);
+
+               if (config_setup(i2s)) {
+                       local_irq_restore(flags);
+                       return -EINVAL;
+               }
+
+               if (capture)
+                       i2s_rxctrl(i2s, 1);
+               else
+                       i2s_txctrl(i2s, 1);
+
+               local_irq_restore(flags);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               local_irq_save(flags);
+
+               if (capture)
+                       i2s_rxctrl(i2s, 0);
+               else
+                       i2s_txctrl(i2s, 0);
+
+               if (capture)
+                       i2s_fifo(i2s, FIC_RXFLUSH);
+               else
+                       i2s_fifo(i2s, FIC_TXFLUSH);
+
+               local_irq_restore(flags);
+               break;
+       }
+
+       return 0;
+}
+
+static int i2s_set_clkdiv(struct snd_soc_dai *dai,
+       int div_id, int div)
+{
+       struct i2s_dai *i2s = to_info(dai);
+       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+
+       switch (div_id) {
+       case SAMSUNG_I2S_DIV_BCLK:
+               if ((any_active(i2s) && div && (get_bfs(i2s) != div))
+                       || (other && other->bfs && (other->bfs != div))) {
+                       dev_err(&i2s->pdev->dev,
+                               "%s:%d Other DAI busy\n", __func__, __LINE__);
+                       return -EAGAIN;
+               }
+               i2s->bfs = div;
+               break;
+       default:
+               dev_err(&i2s->pdev->dev,
+                       "Invalid clock divider(%d)\n", div_id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static snd_pcm_sframes_t
+i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+       struct i2s_dai *i2s = to_info(dai);
+       u32 reg = readl(i2s->addr + I2SFIC);
+       snd_pcm_sframes_t delay;
+
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+               delay = FIC_RXCOUNT(reg);
+       else if (is_secondary(i2s))
+               delay = FICS_TXCOUNT(readl(i2s->addr + I2SFICS));
+       else
+               delay = FIC_TXCOUNT(reg);
+
+       return delay;
+}
+
+#ifdef CONFIG_PM
+static int i2s_suspend(struct snd_soc_dai *dai)
+{
+       struct i2s_dai *i2s = to_info(dai);
+
+       if (dai->active) {
+               i2s->suspend_i2smod = readl(i2s->addr + I2SMOD);
+               i2s->suspend_i2scon = readl(i2s->addr + I2SCON);
+               i2s->suspend_i2spsr = readl(i2s->addr + I2SPSR);
+       }
+
+       return 0;
+}
+
+static int i2s_resume(struct snd_soc_dai *dai)
+{
+       struct i2s_dai *i2s = to_info(dai);
+
+       if (dai->active) {
+               writel(i2s->suspend_i2scon, i2s->addr + I2SCON);
+               writel(i2s->suspend_i2smod, i2s->addr + I2SMOD);
+               writel(i2s->suspend_i2spsr, i2s->addr + I2SPSR);
+       }
+
+       return 0;
+}
+#else
+#define i2s_suspend NULL
+#define i2s_resume  NULL
+#endif
+
+static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+       struct i2s_dai *i2s = to_info(dai);
+       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+
+       if (other && other->clk) /* If this is probe on secondary */
+               goto probe_exit;
+
+       i2s->addr = ioremap(i2s->base, 0x100);
+       if (i2s->addr == NULL) {
+               dev_err(&i2s->pdev->dev, "cannot ioremap registers\n");
+               return -ENXIO;
+       }
+
+       i2s->clk = clk_get(&i2s->pdev->dev, "iis");
+       if (IS_ERR(i2s->clk)) {
+               dev_err(&i2s->pdev->dev, "failed to get i2s_clock\n");
+               iounmap(i2s->addr);
+               return -ENOENT;
+       }
+       clk_enable(i2s->clk);
+
+       if (other) {
+               other->addr = i2s->addr;
+               other->clk = i2s->clk;
+       }
+
+       if (i2s->quirks & QUIRK_NEED_RSTCLR)
+               writel(CON_RSTCLR, i2s->addr + I2SCON);
+
+probe_exit:
+       /* Reset any constraint on RFS and BFS */
+       i2s->rfs = 0;
+       i2s->bfs = 0;
+       i2s_txctrl(i2s, 0);
+       i2s_rxctrl(i2s, 0);
+       i2s_fifo(i2s, FIC_TXFLUSH);
+       i2s_fifo(other, FIC_TXFLUSH);
+       i2s_fifo(i2s, FIC_RXFLUSH);
+
+       /* Gate CDCLK by default */
+       if (!is_opened(other))
+               i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
+                               0, SND_SOC_CLOCK_IN);
+
+       return 0;
+}
+
+static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)
+{
+       struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai);
+       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+
+       if (!other || !other->clk) {
+
+               if (i2s->quirks & QUIRK_NEED_RSTCLR)
+                       writel(0, i2s->addr + I2SCON);
+
+               clk_disable(i2s->clk);
+               clk_put(i2s->clk);
+
+               iounmap(i2s->addr);
+       }
+
+       i2s->clk = NULL;
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops samsung_i2s_dai_ops = {
+       .trigger = i2s_trigger,
+       .hw_params = i2s_hw_params,
+       .set_fmt = i2s_set_fmt,
+       .set_clkdiv = i2s_set_clkdiv,
+       .set_sysclk = i2s_set_sysclk,
+       .startup = i2s_startup,
+       .shutdown = i2s_shutdown,
+       .delay = i2s_delay,
+};
+
+#define SAMSUNG_I2S_RATES      SNDRV_PCM_RATE_8000_96000
+
+#define SAMSUNG_I2S_FMTS       (SNDRV_PCM_FMTBIT_S8 | \
+                                       SNDRV_PCM_FMTBIT_S16_LE | \
+                                       SNDRV_PCM_FMTBIT_S24_LE)
+
+static __devinit
+struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
+{
+       struct i2s_dai *i2s;
+
+       i2s = kzalloc(sizeof(struct i2s_dai), GFP_KERNEL);
+       if (i2s == NULL)
+               return NULL;
+
+       i2s->pdev = pdev;
+       i2s->pri_dai = NULL;
+       i2s->sec_dai = NULL;
+       i2s->i2s_dai_drv.symmetric_rates = 1;
+       i2s->i2s_dai_drv.probe = samsung_i2s_dai_probe;
+       i2s->i2s_dai_drv.remove = samsung_i2s_dai_remove;
+       i2s->i2s_dai_drv.ops = &samsung_i2s_dai_ops;
+       i2s->i2s_dai_drv.suspend = i2s_suspend;
+       i2s->i2s_dai_drv.resume = i2s_resume;
+       i2s->i2s_dai_drv.playback.channels_min = 2;
+       i2s->i2s_dai_drv.playback.channels_max = 2;
+       i2s->i2s_dai_drv.playback.rates = SAMSUNG_I2S_RATES;
+       i2s->i2s_dai_drv.playback.formats = SAMSUNG_I2S_FMTS;
+
+       if (!sec) {
+               i2s->i2s_dai_drv.capture.channels_min = 2;
+               i2s->i2s_dai_drv.capture.channels_max = 2;
+               i2s->i2s_dai_drv.capture.rates = SAMSUNG_I2S_RATES;
+               i2s->i2s_dai_drv.capture.formats = SAMSUNG_I2S_FMTS;
+       } else {        /* Create a new platform_device for Secondary */
+               i2s->pdev = platform_device_register_resndata(NULL,
+                               pdev->name, pdev->id + SAMSUNG_I2S_SECOFF,
+                               NULL, 0, NULL, 0);
+               if (IS_ERR(i2s->pdev)) {
+                       kfree(i2s);
+                       return NULL;
+               }
+       }
+
+       /* Pre-assign snd_soc_dai_set_drvdata */
+       dev_set_drvdata(&i2s->pdev->dev, i2s);
+
+       return i2s;
+}
+
+static __devinit int samsung_i2s_probe(struct platform_device *pdev)
+{
+       u32 dma_pl_chan, dma_cp_chan, dma_pl_sec_chan;
+       struct i2s_dai *pri_dai, *sec_dai = NULL;
+       struct s3c_audio_pdata *i2s_pdata;
+       struct samsung_i2s *i2s_cfg;
+       struct resource *res;
+       u32 regs_base, quirks;
+       int ret = 0;
+
+       /* Call during Seconday interface registration */
+       if (pdev->id >= SAMSUNG_I2S_SECOFF) {
+               sec_dai = dev_get_drvdata(&pdev->dev);
+               snd_soc_register_dai(&sec_dai->pdev->dev,
+                       &sec_dai->i2s_dai_drv);
+               return 0;
+       }
+
+       i2s_pdata = pdev->dev.platform_data;
+       if (i2s_pdata == NULL) {
+               dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n");
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n");
+               return -ENXIO;
+       }
+       dma_pl_chan = res->start;
+
+       res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+       if (!res) {
+               dev_err(&pdev->dev, "Unable to get I2S-RX dma resource\n");
+               return -ENXIO;
+       }
+       dma_cp_chan = res->start;
+
+       res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
+       if (res)
+               dma_pl_sec_chan = res->start;
+       else
+               dma_pl_sec_chan = 0;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "Unable to get I2S SFR address\n");
+               return -ENXIO;
+       }
+
+       if (!request_mem_region(res->start, resource_size(res),
+                                                       "samsung-i2s")) {
+               dev_err(&pdev->dev, "Unable to request SFR region\n");
+               return -EBUSY;
+       }
+       regs_base = res->start;
+
+       i2s_cfg = &i2s_pdata->type.i2s;
+       quirks = i2s_cfg->quirks;
+
+       pri_dai = i2s_alloc_dai(pdev, false);
+       if (!pri_dai) {
+               dev_err(&pdev->dev, "Unable to alloc I2S_pri\n");
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       pri_dai->dma_playback.dma_addr = regs_base + I2STXD;
+       pri_dai->dma_capture.dma_addr = regs_base + I2SRXD;
+       pri_dai->dma_playback.client =
+               (struct s3c2410_dma_client *)&pri_dai->dma_playback;
+       pri_dai->dma_capture.client =
+               (struct s3c2410_dma_client *)&pri_dai->dma_capture;
+       pri_dai->dma_playback.channel = dma_pl_chan;
+       pri_dai->dma_capture.channel = dma_cp_chan;
+       pri_dai->src_clk = i2s_cfg->src_clk;
+       pri_dai->dma_playback.dma_size = 4;
+       pri_dai->dma_capture.dma_size = 4;
+       pri_dai->base = regs_base;
+       pri_dai->quirks = quirks;
+
+       if (quirks & QUIRK_PRI_6CHAN)
+               pri_dai->i2s_dai_drv.playback.channels_max = 6;
+
+       if (quirks & QUIRK_SEC_DAI) {
+               sec_dai = i2s_alloc_dai(pdev, true);
+               if (!sec_dai) {
+                       dev_err(&pdev->dev, "Unable to alloc I2S_sec\n");
+                       ret = -ENOMEM;
+                       goto err2;
+               }
+               sec_dai->dma_playback.dma_addr = regs_base + I2STXDS;
+               sec_dai->dma_playback.client =
+                       (struct s3c2410_dma_client *)&sec_dai->dma_playback;
+               /* Use iDMA always if SysDMA not provided */
+               sec_dai->dma_playback.channel = dma_pl_sec_chan ? : -1;
+               sec_dai->src_clk = i2s_cfg->src_clk;
+               sec_dai->dma_playback.dma_size = 4;
+               sec_dai->base = regs_base;
+               sec_dai->quirks = quirks;
+               sec_dai->pri_dai = pri_dai;
+               pri_dai->sec_dai = sec_dai;
+       }
+
+       if (i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
+               dev_err(&pdev->dev, "Unable to configure gpio\n");
+               ret = -EINVAL;
+               goto err3;
+       }
+
+       snd_soc_register_dai(&pri_dai->pdev->dev, &pri_dai->i2s_dai_drv);
+
+       return 0;
+err3:
+       kfree(sec_dai);
+err2:
+       kfree(pri_dai);
+err1:
+       release_mem_region(regs_base, resource_size(res));
+
+       return ret;
+}
+
+static __devexit int samsung_i2s_remove(struct platform_device *pdev)
+{
+       struct i2s_dai *i2s, *other;
+
+       i2s = dev_get_drvdata(&pdev->dev);
+       other = i2s->pri_dai ? : i2s->sec_dai;
+
+       if (other) {
+               other->pri_dai = NULL;
+               other->sec_dai = NULL;
+       } else {
+               struct resource *res;
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               if (res)
+                       release_mem_region(res->start, resource_size(res));
+       }
+
+       i2s->pri_dai = NULL;
+       i2s->sec_dai = NULL;
+
+       kfree(i2s);
+
+       snd_soc_unregister_dai(&pdev->dev);
+
+       return 0;
+}
+
+static struct platform_driver samsung_i2s_driver = {
+       .probe  = samsung_i2s_probe,
+       .remove = samsung_i2s_remove,
+       .driver = {
+               .name = "samsung-i2s",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init samsung_i2s_init(void)
+{
+       return platform_driver_register(&samsung_i2s_driver);
+}
+module_init(samsung_i2s_init);
+
+static void __exit samsung_i2s_exit(void)
+{
+       platform_driver_unregister(&samsung_i2s_driver);
+}
+module_exit(samsung_i2s_exit);
+
+/* Module information */
+MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
+MODULE_DESCRIPTION("Samsung I2S Interface");
+MODULE_ALIAS("platform:samsung-i2s");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/i2s.h b/sound/soc/samsung/i2s.h
new file mode 100644 (file)
index 0000000..8e15f6a
--- /dev/null
@@ -0,0 +1,29 @@
+/* sound/soc/samsung/i2s.h
+ *
+ * ALSA SoC Audio Layer - Samsung I2S Controller driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd.
+ *     Jaswinder Singh <jassi.brar@samsung.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 __SND_SOC_SAMSUNG_I2S_H
+#define __SND_SOC_SAMSUNG_I2S_H
+
+/*
+ * Maximum number of I2S blocks that any SoC can have.
+ * The secondary interface of a CPU dai(if there exists any),
+ * is indexed at [cpu-dai's ID + SAMSUNG_I2S_SECOFF]
+ */
+#define SAMSUNG_I2S_SECOFF     4
+
+#define SAMSUNG_I2S_DIV_BCLK   1
+
+#define SAMSUNG_I2S_RCLKSRC_0  0
+#define SAMSUNG_I2S_RCLKSRC_1  1
+#define SAMSUNG_I2S_CDCLK              2
+
+#endif /* __SND_SOC_SAMSUNG_I2S_H */
diff --git a/sound/soc/samsung/jive_wm8750.c b/sound/soc/samsung/jive_wm8750.c
new file mode 100644 (file)
index 0000000..0880252
--- /dev/null
@@ -0,0 +1,191 @@
+/* sound/soc/samsung/jive_wm8750.c
+ *
+ * Copyright 2007,2008 Simtec Electronics
+ *
+ * Based on sound/soc/pxa/spitz.c
+ *     Copyright 2005 Wolfson Microelectronics PLC.
+ *     Copyright 2005 Openedhand Ltd.
+ *
+ * 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/clk.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <asm/mach-types.h>
+
+#include "dma.h"
+#include "s3c2412-i2s.h"
+
+#include "../codecs/wm8750.h"
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       { "Headphone Jack", NULL, "LOUT1" },
+       { "Headphone Jack", NULL, "ROUT1" },
+       { "Internal Speaker", NULL, "LOUT2" },
+       { "Internal Speaker", NULL, "ROUT2" },
+       { "LINPUT1", NULL, "Line Input" },
+       { "RINPUT1", NULL, "Line Input" },
+};
+
+static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_SPK("Internal Speaker", NULL),
+       SND_SOC_DAPM_LINE("Line In", NULL),
+};
+
+static int jive_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;
+       struct s3c_i2sv2_rate_calc div;
+       unsigned int clk = 0;
+       int ret = 0;
+
+       switch (params_rate(params)) {
+       case 8000:
+       case 16000:
+       case 48000:
+       case 96000:
+               clk = 12288000;
+               break;
+       case 11025:
+       case 22050:
+       case 44100:
+               clk = 11289600;
+               break;
+       }
+
+       s3c_i2sv2_iis_calc_rate(&div, NULL, params_rate(params),
+                               s3c_i2sv2_get_clock(cpu_dai));
+
+       /* set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+                                 SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* set cpu DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+                                 SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec system clock for DAC and ADC */
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
+                                    SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_RCLK, div.fs_div);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_PRESCALER,
+                                    div.clk_div - 1);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_ops jive_ops = {
+       .hw_params      = jive_hw_params,
+};
+
+static int jive_wm8750_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       int err;
+
+       /* These endpoints are not being used. */
+       snd_soc_dapm_nc_pin(dapm, "LINPUT2");
+       snd_soc_dapm_nc_pin(dapm, "RINPUT2");
+       snd_soc_dapm_nc_pin(dapm, "LINPUT3");
+       snd_soc_dapm_nc_pin(dapm, "RINPUT3");
+       snd_soc_dapm_nc_pin(dapm, "OUT3");
+       snd_soc_dapm_nc_pin(dapm, "MONO");
+
+       /* Add jive specific widgets */
+       err = snd_soc_dapm_new_controls(dapm, wm8750_dapm_widgets,
+                                       ARRAY_SIZE(wm8750_dapm_widgets));
+       if (err) {
+               printk(KERN_ERR "%s: failed to add widgets (%d)\n",
+                      __func__, err);
+               return err;
+       }
+
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_sync(dapm);
+
+       return 0;
+}
+
+static struct snd_soc_dai_link jive_dai = {
+       .name           = "wm8750",
+       .stream_name    = "WM8750",
+       .cpu_dai_name   = "s3c2412-i2s",
+       .codec_dai_name = "wm8750-hifi",
+       .platform_name  = "samsung-audio",
+       .codec_name     = "wm8750-codec.0-0x1a",
+       .init           = jive_wm8750_init,
+       .ops            = &jive_ops,
+};
+
+/* jive audio machine driver */
+static struct snd_soc_card snd_soc_machine_jive = {
+       .name           = "Jive",
+       .dai_link       = &jive_dai,
+       .num_links      = 1,
+};
+
+static struct platform_device *jive_snd_device;
+
+static int __init jive_init(void)
+{
+       int ret;
+
+       if (!machine_is_jive())
+               return 0;
+
+       printk("JIVE WM8750 Audio support\n");
+
+       jive_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!jive_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(jive_snd_device, &snd_soc_machine_jive);
+       ret = platform_device_add(jive_snd_device);
+
+       if (ret)
+               platform_device_put(jive_snd_device);
+
+       return ret;
+}
+
+static void __exit jive_exit(void)
+{
+       platform_device_unregister(jive_snd_device);
+}
+
+module_init(jive_init);
+module_exit(jive_exit);
+
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("ALSA SoC Jive Audio support");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/lm4857.h b/sound/soc/samsung/lm4857.h
new file mode 100644 (file)
index 0000000..0cf5b70
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * lm4857.h  --  ALSA Soc Audio Layer
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  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.
+ *
+ *  Revision history
+ *    18th Jun 2007   Initial version.
+ */
+
+#ifndef LM4857_H_
+#define LM4857_H_
+
+/* The register offsets in the cache array */
+#define LM4857_MVOL 0
+#define LM4857_LVOL 1
+#define LM4857_RVOL 2
+#define LM4857_CTRL 3
+
+/* the shifts required to set these bits */
+#define LM4857_3D 5
+#define LM4857_WAKEUP 5
+#define LM4857_EPGAIN 4
+
+#endif /*LM4857_H_*/
+
diff --git a/sound/soc/samsung/ln2440sbc_alc650.c b/sound/soc/samsung/ln2440sbc_alc650.c
new file mode 100644 (file)
index 0000000..a2bb34d
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * SoC audio for ln2440sbc
+ *
+ * Copyright 2007 KonekTel, a.s.
+ * Author: Ivan Kuten
+ *         ivan.kuten@promwad.com
+ *
+ * Heavily based on smdk2443_wm9710.c
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.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/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include "dma.h"
+#include "ac97.h"
+
+static struct snd_soc_card ln2440sbc;
+
+static struct snd_soc_dai_link ln2440sbc_dai[] = {
+{
+       .name = "AC97",
+       .stream_name = "AC97 HiFi",
+       .cpu_dai_name = "samsung-ac97",
+       .codec_dai_name = "ac97-hifi",
+       .codec_name = "ac97-codec",
+       .platform_name = "samsung-audio",
+},
+};
+
+static struct snd_soc_card ln2440sbc = {
+       .name = "LN2440SBC",
+       .dai_link = ln2440sbc_dai,
+       .num_links = ARRAY_SIZE(ln2440sbc_dai),
+};
+
+static struct platform_device *ln2440sbc_snd_ac97_device;
+
+static int __init ln2440sbc_init(void)
+{
+       int ret;
+
+       ln2440sbc_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+       if (!ln2440sbc_snd_ac97_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(ln2440sbc_snd_ac97_device, &ln2440sbc);
+       ret = platform_device_add(ln2440sbc_snd_ac97_device);
+
+       if (ret)
+               platform_device_put(ln2440sbc_snd_ac97_device);
+
+       return ret;
+}
+
+static void __exit ln2440sbc_exit(void)
+{
+       platform_device_unregister(ln2440sbc_snd_ac97_device);
+}
+
+module_init(ln2440sbc_init);
+module_exit(ln2440sbc_exit);
+
+/* Module information */
+MODULE_AUTHOR("Ivan Kuten");
+MODULE_DESCRIPTION("ALSA SoC ALC650 LN2440SBC");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/neo1973_gta02_wm8753.c b/sound/soc/samsung/neo1973_gta02_wm8753.c
new file mode 100644 (file)
index 0000000..3eec610
--- /dev/null
@@ -0,0 +1,504 @@
+/*
+ * neo1973_gta02_wm8753.c  --  SoC audio for Openmoko Freerunner(GTA02)
+ *
+ * Copyright 2007 Openmoko Inc
+ * Author: Graeme Gregory <graeme@openmoko.org>
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory <linux@wolfsonmicro.com>
+ * Copyright 2009 Wolfson Microelectronics
+ *
+ *  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/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/mach-types.h>
+
+#include <plat/regs-iis.h>
+
+#include <mach/regs-clock.h>
+#include <asm/io.h>
+#include <mach/gta02.h>
+#include "../codecs/wm8753.h"
+#include "dma.h"
+#include "s3c24xx-i2s.h"
+
+static struct snd_soc_card neo1973_gta02;
+
+static int neo1973_gta02_hifi_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;
+       unsigned int pll_out = 0, bclk = 0;
+       int ret = 0;
+       unsigned long iis_clkrate;
+
+       iis_clkrate = s3c24xx_i2s_get_clockrate();
+
+       switch (params_rate(params)) {
+       case 8000:
+       case 16000:
+               pll_out = 12288000;
+               break;
+       case 48000:
+               bclk = WM8753_BCLK_DIV_4;
+               pll_out = 12288000;
+               break;
+       case 96000:
+               bclk = WM8753_BCLK_DIV_2;
+               pll_out = 12288000;
+               break;
+       case 11025:
+               bclk = WM8753_BCLK_DIV_16;
+               pll_out = 11289600;
+               break;
+       case 22050:
+               bclk = WM8753_BCLK_DIV_8;
+               pll_out = 11289600;
+               break;
+       case 44100:
+               bclk = WM8753_BCLK_DIV_4;
+               pll_out = 11289600;
+               break;
+       case 88200:
+               bclk = WM8753_BCLK_DIV_2;
+               pll_out = 11289600;
+               break;
+       }
+
+       /* set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai,
+               SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+               SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       /* set cpu DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai,
+               SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+               SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec system clock for DAC and ADC */
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
+               SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       /* set MCLK division for sample rate */
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
+               S3C2410_IISMOD_32FS);
+       if (ret < 0)
+               return ret;
+
+       /* set codec BCLK division for sample rate */
+       ret = snd_soc_dai_set_clkdiv(codec_dai,
+                                       WM8753_BCLKDIV, bclk);
+       if (ret < 0)
+               return ret;
+
+       /* set prescaler division for sample rate */
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+               S3C24XX_PRESCALE(4, 4));
+       if (ret < 0)
+               return ret;
+
+       /* codec PLL input is PCLK/4 */
+       ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
+               iis_clkrate / 4, pll_out);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+       /* disable the PLL */
+       return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
+}
+
+/*
+ * Neo1973 WM8753 HiFi DAI opserations.
+ */
+static struct snd_soc_ops neo1973_gta02_hifi_ops = {
+       .hw_params = neo1973_gta02_hifi_hw_params,
+       .hw_free = neo1973_gta02_hifi_hw_free,
+};
+
+static int neo1973_gta02_voice_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;
+       unsigned int pcmdiv = 0;
+       int ret = 0;
+       unsigned long iis_clkrate;
+
+       iis_clkrate = s3c24xx_i2s_get_clockrate();
+
+       if (params_rate(params) != 8000)
+               return -EINVAL;
+       if (params_channels(params) != 1)
+               return -EINVAL;
+
+       pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
+
+       /* todo: gg check mode (DSP_B) against CSR datasheet */
+       /* set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec system clock for DAC and ADC */
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK,
+               12288000, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       /* set codec PCM division for sample rate */
+       ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV,
+                                       pcmdiv);
+       if (ret < 0)
+               return ret;
+
+       /* configure and enable PLL for 12.288MHz output */
+       ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
+               iis_clkrate / 4, 12288000);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+       /* disable the PLL */
+       return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
+}
+
+static struct snd_soc_ops neo1973_gta02_voice_ops = {
+       .hw_params = neo1973_gta02_voice_hw_params,
+       .hw_free = neo1973_gta02_voice_hw_free,
+};
+
+#define LM4853_AMP 1
+#define LM4853_SPK 2
+
+static u8 lm4853_state;
+
+/* This has no effect, it exists only to maintain compatibility with
+ * existing ALSA state files.
+ */
+static int lm4853_set_state(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       int val = ucontrol->value.integer.value[0];
+
+       if (val)
+               lm4853_state |= LM4853_AMP;
+       else
+               lm4853_state &= ~LM4853_AMP;
+
+       return 0;
+}
+
+static int lm4853_get_state(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = lm4853_state & LM4853_AMP;
+
+       return 0;
+}
+
+static int lm4853_set_spk(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       int val = ucontrol->value.integer.value[0];
+
+       if (val) {
+               lm4853_state |= LM4853_SPK;
+               gpio_set_value(GTA02_GPIO_HP_IN, 0);
+       } else {
+               lm4853_state &= ~LM4853_SPK;
+               gpio_set_value(GTA02_GPIO_HP_IN, 1);
+       }
+
+       return 0;
+}
+
+static int lm4853_get_spk(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = (lm4853_state & LM4853_SPK) >> 1;
+
+       return 0;
+}
+
+static int lm4853_event(struct snd_soc_dapm_widget *w,
+                       struct snd_kcontrol *k,
+                       int event)
+{
+       gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event));
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
+       SND_SOC_DAPM_SPK("Stereo Out", lm4853_event),
+       SND_SOC_DAPM_LINE("GSM Line Out", NULL),
+       SND_SOC_DAPM_LINE("GSM Line In", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Handset Mic", NULL),
+       SND_SOC_DAPM_SPK("Handset Spk", NULL),
+};
+
+
+/* example machine audio_mapnections */
+static const struct snd_soc_dapm_route audio_map[] = {
+
+       /* Connections to the lm4853 amp */
+       {"Stereo Out", NULL, "LOUT1"},
+       {"Stereo Out", NULL, "ROUT1"},
+
+       /* Connections to the GSM Module */
+       {"GSM Line Out", NULL, "MONO1"},
+       {"GSM Line Out", NULL, "MONO2"},
+       {"RXP", NULL, "GSM Line In"},
+       {"RXN", NULL, "GSM Line In"},
+
+       /* Connections to Headset */
+       {"MIC1", NULL, "Mic Bias"},
+       {"Mic Bias", NULL, "Headset Mic"},
+
+       /* Call Mic */
+       {"MIC2", NULL, "Mic Bias"},
+       {"MIC2N", NULL, "Mic Bias"},
+       {"Mic Bias", NULL, "Handset Mic"},
+
+       /* Call Speaker */
+       {"Handset Spk", NULL, "LOUT2"},
+       {"Handset Spk", NULL, "ROUT2"},
+
+       /* Connect the ALC pins */
+       {"ACIN", NULL, "ACOP"},
+};
+
+static const struct snd_kcontrol_new wm8753_neo1973_gta02_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Stereo Out"),
+       SOC_DAPM_PIN_SWITCH("GSM Line Out"),
+       SOC_DAPM_PIN_SWITCH("GSM Line In"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Handset Mic"),
+       SOC_DAPM_PIN_SWITCH("Handset Spk"),
+
+       /* This has no effect, it exists only to maintain compatibility with
+        * existing ALSA state files.
+        */
+       SOC_SINGLE_EXT("Amp State Switch", 6, 0, 1, 0,
+               lm4853_get_state,
+               lm4853_set_state),
+       SOC_SINGLE_EXT("Amp Spk Switch", 7, 0, 1, 0,
+               lm4853_get_spk,
+               lm4853_set_spk),
+};
+
+/*
+ * This is an example machine initialisation for a wm8753 connected to a
+ * neo1973 GTA02.
+ */
+static int neo1973_gta02_wm8753_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       int err;
+
+       /* set up NC codec pins */
+       snd_soc_dapm_nc_pin(dapm, "OUT3");
+       snd_soc_dapm_nc_pin(dapm, "OUT4");
+       snd_soc_dapm_nc_pin(dapm, "LINE1");
+       snd_soc_dapm_nc_pin(dapm, "LINE2");
+
+       /* Add neo1973 gta02 specific widgets */
+       snd_soc_dapm_new_controls(dapm, wm8753_dapm_widgets,
+                                 ARRAY_SIZE(wm8753_dapm_widgets));
+
+       /* add neo1973 gta02 specific controls */
+       err = snd_soc_add_controls(codec, wm8753_neo1973_gta02_controls,
+               ARRAY_SIZE(wm8753_neo1973_gta02_controls));
+
+       if (err < 0)
+               return err;
+
+       /* set up neo1973 gta02 specific audio path audio_map */
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+
+       /* set endpoints to default off mode */
+       snd_soc_dapm_disable_pin(dapm, "Stereo Out");
+       snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
+       snd_soc_dapm_disable_pin(dapm, "GSM Line In");
+       snd_soc_dapm_disable_pin(dapm, "Headset Mic");
+       snd_soc_dapm_disable_pin(dapm, "Handset Mic");
+       snd_soc_dapm_disable_pin(dapm, "Handset Spk");
+
+       /* allow audio paths from the GSM modem to run during suspend */
+       snd_soc_dapm_ignore_suspend(dapm, "Stereo Out");
+       snd_soc_dapm_ignore_suspend(dapm, "GSM Line Out");
+       snd_soc_dapm_ignore_suspend(dapm, "GSM Line In");
+       snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
+       snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
+       snd_soc_dapm_ignore_suspend(dapm, "Handset Spk");
+
+       snd_soc_dapm_sync(dapm);
+
+       return 0;
+}
+
+/*
+ * BT Codec DAI
+ */
+static struct snd_soc_dai_driver bt_dai = {
+       .name = "bluetooth-dai",
+       .playback = {
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+};
+
+static struct snd_soc_dai_link neo1973_gta02_dai[] = {
+{ /* Hifi Playback - for similatious use with voice below */
+       .name = "WM8753",
+       .stream_name = "WM8753 HiFi",
+       .cpu_dai_name = "s3c24xx-i2s",
+       .codec_dai_name = "wm8753-hifi",
+       .init = neo1973_gta02_wm8753_init,
+       .platform_name = "samsung-audio",
+       .codec_name = "wm8753-codec.0-0x1a",
+       .ops = &neo1973_gta02_hifi_ops,
+},
+{ /* Voice via BT */
+       .name = "Bluetooth",
+       .stream_name = "Voice",
+       .cpu_dai_name = "bluetooth-dai",
+       .codec_dai_name = "wm8753-voice",
+       .ops = &neo1973_gta02_voice_ops,
+       .codec_name = "wm8753-codec.0-0x1a",
+       .platform_name = "samsung-audio",
+},
+};
+
+static struct snd_soc_card neo1973_gta02 = {
+       .name = "neo1973-gta02",
+       .dai_link = neo1973_gta02_dai,
+       .num_links = ARRAY_SIZE(neo1973_gta02_dai),
+};
+
+static struct platform_device *neo1973_gta02_snd_device;
+
+static int __init neo1973_gta02_init(void)
+{
+       int ret;
+
+       if (!machine_is_neo1973_gta02()) {
+               printk(KERN_INFO
+                      "Only GTA02 is supported by this ASoC driver\n");
+               return -ENODEV;
+       }
+
+       neo1973_gta02_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!neo1973_gta02_snd_device)
+               return -ENOMEM;
+
+       /* register bluetooth DAI here */
+       ret = snd_soc_register_dai(&neo1973_gta02_snd_device->dev, &bt_dai);
+       if (ret)
+               goto err_put_device;
+
+       platform_set_drvdata(neo1973_gta02_snd_device, &neo1973_gta02);
+       ret = platform_device_add(neo1973_gta02_snd_device);
+
+       if (ret)
+               goto err_unregister_dai;
+
+       /* Initialise GPIOs used by amp */
+       ret = gpio_request(GTA02_GPIO_HP_IN, "GTA02_HP_IN");
+       if (ret) {
+               pr_err("gta02_wm8753: Failed to register GPIO %d\n", GTA02_GPIO_HP_IN);
+               goto err_del_device;
+       }
+
+       ret = gpio_direction_output(GTA02_GPIO_HP_IN, 1);
+       if (ret) {
+               pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_HP_IN);
+               goto err_free_gpio_hp_in;
+       }
+
+       ret = gpio_request(GTA02_GPIO_AMP_SHUT, "GTA02_AMP_SHUT");
+       if (ret) {
+               pr_err("gta02_wm8753: Failed to register GPIO %d\n", GTA02_GPIO_AMP_SHUT);
+               goto err_free_gpio_hp_in;
+       }
+
+       ret = gpio_direction_output(GTA02_GPIO_AMP_SHUT, 1);
+       if (ret) {
+               pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_AMP_SHUT);
+               goto err_free_gpio_amp_shut;
+       }
+
+       return 0;
+
+err_free_gpio_amp_shut:
+       gpio_free(GTA02_GPIO_AMP_SHUT);
+err_free_gpio_hp_in:
+       gpio_free(GTA02_GPIO_HP_IN);
+err_del_device:
+       platform_device_del(neo1973_gta02_snd_device);
+err_unregister_dai:
+       snd_soc_unregister_dai(&neo1973_gta02_snd_device->dev);
+err_put_device:
+       platform_device_put(neo1973_gta02_snd_device);
+       return ret;
+}
+module_init(neo1973_gta02_init);
+
+static void __exit neo1973_gta02_exit(void)
+{
+       snd_soc_unregister_dai(&neo1973_gta02_snd_device->dev);
+       platform_device_unregister(neo1973_gta02_snd_device);
+       gpio_free(GTA02_GPIO_HP_IN);
+       gpio_free(GTA02_GPIO_AMP_SHUT);
+}
+module_exit(neo1973_gta02_exit);
+
+/* Module information */
+MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org");
+MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 GTA02");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c
new file mode 100644 (file)
index 0000000..c7a2451
--- /dev/null
@@ -0,0 +1,706 @@
+/*
+ * neo1973_wm8753.c  --  SoC audio for Neo1973
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  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/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware/scoop.h>
+#include <mach/regs-clock.h>
+#include <mach/regs-gpio.h>
+#include <mach/hardware.h>
+#include <linux/io.h>
+#include <mach/spi-gpio.h>
+
+#include <plat/regs-iis.h>
+
+#include "../codecs/wm8753.h"
+#include "lm4857.h"
+#include "dma.h"
+#include "s3c24xx-i2s.h"
+
+/* define the scenarios */
+#define NEO_AUDIO_OFF                  0
+#define NEO_GSM_CALL_AUDIO_HANDSET     1
+#define NEO_GSM_CALL_AUDIO_HEADSET     2
+#define NEO_GSM_CALL_AUDIO_BLUETOOTH   3
+#define NEO_STEREO_TO_SPEAKERS         4
+#define NEO_STEREO_TO_HEADPHONES       5
+#define NEO_CAPTURE_HANDSET            6
+#define NEO_CAPTURE_HEADSET            7
+#define NEO_CAPTURE_BLUETOOTH          8
+
+static struct snd_soc_card neo1973;
+static struct i2c_client *i2c;
+
+static int neo1973_hifi_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;
+       unsigned int pll_out = 0, bclk = 0;
+       int ret = 0;
+       unsigned long iis_clkrate;
+
+       pr_debug("Entered %s\n", __func__);
+
+       iis_clkrate = s3c24xx_i2s_get_clockrate();
+
+       switch (params_rate(params)) {
+       case 8000:
+       case 16000:
+               pll_out = 12288000;
+               break;
+       case 48000:
+               bclk = WM8753_BCLK_DIV_4;
+               pll_out = 12288000;
+               break;
+       case 96000:
+               bclk = WM8753_BCLK_DIV_2;
+               pll_out = 12288000;
+               break;
+       case 11025:
+               bclk = WM8753_BCLK_DIV_16;
+               pll_out = 11289600;
+               break;
+       case 22050:
+               bclk = WM8753_BCLK_DIV_8;
+               pll_out = 11289600;
+               break;
+       case 44100:
+               bclk = WM8753_BCLK_DIV_4;
+               pll_out = 11289600;
+               break;
+       case 88200:
+               bclk = WM8753_BCLK_DIV_2;
+               pll_out = 11289600;
+               break;
+       }
+
+       /* set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai,
+               SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+               SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       /* set cpu DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai,
+               SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+               SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec system clock for DAC and ADC */
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
+               SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       /* set MCLK division for sample rate */
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
+               S3C2410_IISMOD_32FS);
+       if (ret < 0)
+               return ret;
+
+       /* set codec BCLK division for sample rate */
+       ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
+       if (ret < 0)
+               return ret;
+
+       /* set prescaler division for sample rate */
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+               S3C24XX_PRESCALE(4, 4));
+       if (ret < 0)
+               return ret;
+
+       /* codec PLL input is PCLK/4 */
+       ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
+               iis_clkrate / 4, pll_out);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+       pr_debug("Entered %s\n", __func__);
+
+       /* disable the PLL */
+       return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
+}
+
+/*
+ * Neo1973 WM8753 HiFi DAI opserations.
+ */
+static struct snd_soc_ops neo1973_hifi_ops = {
+       .hw_params = neo1973_hifi_hw_params,
+       .hw_free = neo1973_hifi_hw_free,
+};
+
+static int neo1973_voice_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;
+       unsigned int pcmdiv = 0;
+       int ret = 0;
+       unsigned long iis_clkrate;
+
+       pr_debug("Entered %s\n", __func__);
+
+       iis_clkrate = s3c24xx_i2s_get_clockrate();
+
+       if (params_rate(params) != 8000)
+               return -EINVAL;
+       if (params_channels(params) != 1)
+               return -EINVAL;
+
+       pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
+
+       /* todo: gg check mode (DSP_B) against CSR datasheet */
+       /* set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec system clock for DAC and ADC */
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
+               SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       /* set codec PCM division for sample rate */
+       ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
+       if (ret < 0)
+               return ret;
+
+       /* configure and enable PLL for 12.288MHz output */
+       ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
+               iis_clkrate / 4, 12288000);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+       pr_debug("Entered %s\n", __func__);
+
+       /* disable the PLL */
+       return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
+}
+
+static struct snd_soc_ops neo1973_voice_ops = {
+       .hw_params = neo1973_voice_hw_params,
+       .hw_free = neo1973_voice_hw_free,
+};
+
+static int neo1973_scenario;
+
+static int neo1973_get_scenario(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = neo1973_scenario;
+       return 0;
+}
+
+static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario)
+{
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       pr_debug("Entered %s\n", __func__);
+
+       switch (neo1973_scenario) {
+       case NEO_AUDIO_OFF:
+               snd_soc_dapm_disable_pin(dapm, "Audio Out");
+               snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
+               snd_soc_dapm_disable_pin(dapm, "GSM Line In");
+               snd_soc_dapm_disable_pin(dapm, "Headset Mic");
+               snd_soc_dapm_disable_pin(dapm, "Call Mic");
+               break;
+       case NEO_GSM_CALL_AUDIO_HANDSET:
+               snd_soc_dapm_enable_pin(dapm, "Audio Out");
+               snd_soc_dapm_enable_pin(dapm, "GSM Line Out");
+               snd_soc_dapm_enable_pin(dapm, "GSM Line In");
+               snd_soc_dapm_disable_pin(dapm, "Headset Mic");
+               snd_soc_dapm_enable_pin(dapm, "Call Mic");
+               break;
+       case NEO_GSM_CALL_AUDIO_HEADSET:
+               snd_soc_dapm_enable_pin(dapm, "Audio Out");
+               snd_soc_dapm_enable_pin(dapm, "GSM Line Out");
+               snd_soc_dapm_enable_pin(dapm, "GSM Line In");
+               snd_soc_dapm_enable_pin(dapm, "Headset Mic");
+               snd_soc_dapm_disable_pin(dapm, "Call Mic");
+               break;
+       case NEO_GSM_CALL_AUDIO_BLUETOOTH:
+               snd_soc_dapm_disable_pin(dapm, "Audio Out");
+               snd_soc_dapm_enable_pin(dapm, "GSM Line Out");
+               snd_soc_dapm_enable_pin(dapm, "GSM Line In");
+               snd_soc_dapm_disable_pin(dapm, "Headset Mic");
+               snd_soc_dapm_disable_pin(dapm, "Call Mic");
+               break;
+       case NEO_STEREO_TO_SPEAKERS:
+               snd_soc_dapm_enable_pin(dapm, "Audio Out");
+               snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
+               snd_soc_dapm_disable_pin(dapm, "GSM Line In");
+               snd_soc_dapm_disable_pin(dapm, "Headset Mic");
+               snd_soc_dapm_disable_pin(dapm, "Call Mic");
+               break;
+       case NEO_STEREO_TO_HEADPHONES:
+               snd_soc_dapm_enable_pin(dapm, "Audio Out");
+               snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
+               snd_soc_dapm_disable_pin(dapm, "GSM Line In");
+               snd_soc_dapm_disable_pin(dapm, "Headset Mic");
+               snd_soc_dapm_disable_pin(dapm, "Call Mic");
+               break;
+       case NEO_CAPTURE_HANDSET:
+               snd_soc_dapm_disable_pin(dapm, "Audio Out");
+               snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
+               snd_soc_dapm_disable_pin(dapm, "GSM Line In");
+               snd_soc_dapm_disable_pin(dapm, "Headset Mic");
+               snd_soc_dapm_enable_pin(dapm, "Call Mic");
+               break;
+       case NEO_CAPTURE_HEADSET:
+               snd_soc_dapm_disable_pin(dapm, "Audio Out");
+               snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
+               snd_soc_dapm_disable_pin(dapm, "GSM Line In");
+               snd_soc_dapm_enable_pin(dapm, "Headset Mic");
+               snd_soc_dapm_disable_pin(dapm, "Call Mic");
+               break;
+       case NEO_CAPTURE_BLUETOOTH:
+               snd_soc_dapm_disable_pin(dapm, "Audio Out");
+               snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
+               snd_soc_dapm_disable_pin(dapm, "GSM Line In");
+               snd_soc_dapm_disable_pin(dapm, "Headset Mic");
+               snd_soc_dapm_disable_pin(dapm, "Call Mic");
+               break;
+       default:
+               snd_soc_dapm_disable_pin(dapm, "Audio Out");
+               snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
+               snd_soc_dapm_disable_pin(dapm, "GSM Line In");
+               snd_soc_dapm_disable_pin(dapm, "Headset Mic");
+               snd_soc_dapm_disable_pin(dapm, "Call Mic");
+       }
+
+       snd_soc_dapm_sync(dapm);
+
+       return 0;
+}
+
+static int neo1973_set_scenario(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+       pr_debug("Entered %s\n", __func__);
+
+       if (neo1973_scenario == ucontrol->value.integer.value[0])
+               return 0;
+
+       neo1973_scenario = ucontrol->value.integer.value[0];
+       set_scenario_endpoints(codec, neo1973_scenario);
+       return 1;
+}
+
+static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0};
+
+static void lm4857_write_regs(void)
+{
+       pr_debug("Entered %s\n", __func__);
+
+       if (i2c_master_send(i2c, lm4857_regs, 4) != 4)
+               printk(KERN_ERR "lm4857: i2c write failed\n");
+}
+
+static int lm4857_get_reg(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       int reg = mc->reg;
+       int shift = mc->shift;
+       int mask = mc->max;
+
+       pr_debug("Entered %s\n", __func__);
+
+       ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask;
+       return 0;
+}
+
+static int lm4857_set_reg(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       int reg = mc->reg;
+       int shift = mc->shift;
+       int mask = mc->max;
+
+       if (((lm4857_regs[reg] >> shift) & mask) ==
+               ucontrol->value.integer.value[0])
+               return 0;
+
+       lm4857_regs[reg] &= ~(mask << shift);
+       lm4857_regs[reg] |= ucontrol->value.integer.value[0] << shift;
+       lm4857_write_regs();
+       return 1;
+}
+
+static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       u8 value = lm4857_regs[LM4857_CTRL] & 0x0F;
+
+       pr_debug("Entered %s\n", __func__);
+
+       if (value)
+               value -= 5;
+
+       ucontrol->value.integer.value[0] = value;
+       return 0;
+}
+
+static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       u8 value = ucontrol->value.integer.value[0];
+
+       pr_debug("Entered %s\n", __func__);
+
+       if (value)
+               value += 5;
+
+       if ((lm4857_regs[LM4857_CTRL] & 0x0F) == value)
+               return 0;
+
+       lm4857_regs[LM4857_CTRL] &= 0xF0;
+       lm4857_regs[LM4857_CTRL] |= value;
+       lm4857_write_regs();
+       return 1;
+}
+
+static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
+       SND_SOC_DAPM_LINE("Audio Out", NULL),
+       SND_SOC_DAPM_LINE("GSM Line Out", NULL),
+       SND_SOC_DAPM_LINE("GSM Line In", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Call Mic", NULL),
+};
+
+
+static const struct snd_soc_dapm_route dapm_routes[] = {
+
+       /* Connections to the lm4857 amp */
+       {"Audio Out", NULL, "LOUT1"},
+       {"Audio Out", NULL, "ROUT1"},
+
+       /* Connections to the GSM Module */
+       {"GSM Line Out", NULL, "MONO1"},
+       {"GSM Line Out", NULL, "MONO2"},
+       {"RXP", NULL, "GSM Line In"},
+       {"RXN", NULL, "GSM Line In"},
+
+       /* Connections to Headset */
+       {"MIC1", NULL, "Mic Bias"},
+       {"Mic Bias", NULL, "Headset Mic"},
+
+       /* Call Mic */
+       {"MIC2", NULL, "Mic Bias"},
+       {"MIC2N", NULL, "Mic Bias"},
+       {"Mic Bias", NULL, "Call Mic"},
+
+       /* Connect the ALC pins */
+       {"ACIN", NULL, "ACOP"},
+};
+
+static const char *lm4857_mode[] = {
+       "Off",
+       "Call Speaker",
+       "Stereo Speakers",
+       "Stereo Speakers + Headphones",
+       "Headphones"
+};
+
+static const struct soc_enum lm4857_mode_enum[] = {
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode),
+};
+
+static const char *neo_scenarios[] = {
+       "Off",
+       "GSM Handset",
+       "GSM Headset",
+       "GSM Bluetooth",
+       "Speakers",
+       "Headphones",
+       "Capture Handset",
+       "Capture Headset",
+       "Capture Bluetooth"
+};
+
+static const struct soc_enum neo_scenario_enum[] = {
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios), neo_scenarios),
+};
+
+static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0);
+static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0);
+
+static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
+       SOC_SINGLE_EXT_TLV("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0,
+               lm4857_get_reg, lm4857_set_reg, stereo_tlv),
+       SOC_SINGLE_EXT_TLV("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0,
+               lm4857_get_reg, lm4857_set_reg, stereo_tlv),
+       SOC_SINGLE_EXT_TLV("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0,
+               lm4857_get_reg, lm4857_set_reg, mono_tlv),
+       SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0],
+               lm4857_get_mode, lm4857_set_mode),
+       SOC_ENUM_EXT("Neo Mode", neo_scenario_enum[0],
+               neo1973_get_scenario, neo1973_set_scenario),
+       SOC_SINGLE_EXT("Amp Spk 3D Playback Switch", LM4857_LVOL, 5, 1, 0,
+               lm4857_get_reg, lm4857_set_reg),
+       SOC_SINGLE_EXT("Amp HP 3d Playback Switch", LM4857_RVOL, 5, 1, 0,
+               lm4857_get_reg, lm4857_set_reg),
+       SOC_SINGLE_EXT("Amp Fast Wakeup Playback Switch", LM4857_CTRL, 5, 1, 0,
+               lm4857_get_reg, lm4857_set_reg),
+       SOC_SINGLE_EXT("Amp Earpiece 6dB Playback Switch", LM4857_CTRL, 4, 1, 0,
+               lm4857_get_reg, lm4857_set_reg),
+};
+
+/*
+ * This is an example machine initialisation for a wm8753 connected to a
+ * neo1973 II. It is missing logic to detect hp/mic insertions and logic
+ * to re-route the audio in such an event.
+ */
+static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       int err;
+
+       pr_debug("Entered %s\n", __func__);
+
+       /* set up NC codec pins */
+       snd_soc_dapm_nc_pin(dapm, "LOUT2");
+       snd_soc_dapm_nc_pin(dapm, "ROUT2");
+       snd_soc_dapm_nc_pin(dapm, "OUT3");
+       snd_soc_dapm_nc_pin(dapm, "OUT4");
+       snd_soc_dapm_nc_pin(dapm, "LINE1");
+       snd_soc_dapm_nc_pin(dapm, "LINE2");
+
+       /* Add neo1973 specific widgets */
+       snd_soc_dapm_new_controls(dapm, wm8753_dapm_widgets,
+                                 ARRAY_SIZE(wm8753_dapm_widgets));
+
+       /* set endpoints to default mode */
+       set_scenario_endpoints(codec, NEO_AUDIO_OFF);
+
+       /* add neo1973 specific controls */
+       err = snd_soc_add_controls(codec, wm8753_neo1973_controls,
+                               ARRAY_SIZE(8753_neo1973_controls));
+       if (err < 0)
+               return err;
+
+       /* set up neo1973 specific audio routes */
+       err = snd_soc_dapm_add_routes(dapm, dapm_routes,
+                                     ARRAY_SIZE(dapm_routes));
+
+       snd_soc_dapm_sync(dapm);
+       return 0;
+}
+
+/*
+ * BT Codec DAI
+ */
+static struct snd_soc_dai bt_dai = {
+       .name = "bluetooth-dai",
+       .playback = {
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+};
+
+static struct snd_soc_dai_link neo1973_dai[] = {
+{ /* Hifi Playback - for similatious use with voice below */
+       .name = "WM8753",
+       .stream_name = "WM8753 HiFi",
+       .platform_name = "samsung-audio",
+       .cpu_dai_name = "s3c24xx-i2s",
+       .codec_dai_name = "wm8753-hifi",
+       .codec_name = "wm8753-codec.0-0x1a",
+       .init = neo1973_wm8753_init,
+       .ops = &neo1973_hifi_ops,
+},
+{ /* Voice via BT */
+       .name = "Bluetooth",
+       .stream_name = "Voice",
+       .platform_name = "samsung-audio",
+       .cpu_dai_name = "bluetooth-dai",
+       .codec_dai_name = "wm8753-voice",
+       .codec_name = "wm8753-codec.0-0x1a",
+       .ops = &neo1973_voice_ops,
+},
+};
+
+static struct snd_soc_card neo1973 = {
+       .name = "neo1973",
+       .dai_link = neo1973_dai,
+       .num_links = ARRAY_SIZE(neo1973_dai),
+};
+
+static int lm4857_i2c_probe(struct i2c_client *client,
+                           const struct i2c_device_id *id)
+{
+       pr_debug("Entered %s\n", __func__);
+
+       i2c = client;
+
+       lm4857_write_regs();
+       return 0;
+}
+
+static int lm4857_i2c_remove(struct i2c_client *client)
+{
+       pr_debug("Entered %s\n", __func__);
+
+       i2c = NULL;
+
+       return 0;
+}
+
+static u8 lm4857_state;
+
+static int lm4857_suspend(struct i2c_client *dev, pm_message_t state)
+{
+       pr_debug("Entered %s\n", __func__);
+
+       dev_dbg(&dev->dev, "lm4857_suspend\n");
+       lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf;
+       if (lm4857_state) {
+               lm4857_regs[LM4857_CTRL] &= 0xf0;
+               lm4857_write_regs();
+       }
+       return 0;
+}
+
+static int lm4857_resume(struct i2c_client *dev)
+{
+       pr_debug("Entered %s\n", __func__);
+
+       if (lm4857_state) {
+               lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f);
+               lm4857_write_regs();
+       }
+       return 0;
+}
+
+static void lm4857_shutdown(struct i2c_client *dev)
+{
+       pr_debug("Entered %s\n", __func__);
+
+       dev_dbg(&dev->dev, "lm4857_shutdown\n");
+       lm4857_regs[LM4857_CTRL] &= 0xf0;
+       lm4857_write_regs();
+}
+
+static const struct i2c_device_id lm4857_i2c_id[] = {
+       { "neo1973_lm4857", 0 },
+       { }
+};
+
+static struct i2c_driver lm4857_i2c_driver = {
+       .driver = {
+               .name = "LM4857 I2C Amp",
+               .owner = THIS_MODULE,
+       },
+       .suspend =        lm4857_suspend,
+       .resume =         lm4857_resume,
+       .shutdown =       lm4857_shutdown,
+       .probe =          lm4857_i2c_probe,
+       .remove =         lm4857_i2c_remove,
+       .id_table =       lm4857_i2c_id,
+};
+
+static struct platform_device *neo1973_snd_device;
+
+static int __init neo1973_init(void)
+{
+       int ret;
+
+       pr_debug("Entered %s\n", __func__);
+
+       if (!machine_is_neo1973_gta01()) {
+               printk(KERN_INFO
+                       "Only GTA01 hardware supported by ASoC driver\n");
+               return -ENODEV;
+       }
+
+       neo1973_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!neo1973_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(neo1973_snd_device, &neo1973);
+       ret = platform_device_add(neo1973_snd_device);
+
+       if (ret) {
+               platform_device_put(neo1973_snd_device);
+               return ret;
+       }
+
+       ret = i2c_add_driver(&lm4857_i2c_driver);
+
+       if (ret != 0)
+               platform_device_unregister(neo1973_snd_device);
+
+       return ret;
+}
+
+static void __exit neo1973_exit(void)
+{
+       pr_debug("Entered %s\n", __func__);
+
+       i2c_del_driver(&lm4857_i2c_driver);
+       platform_device_unregister(neo1973_snd_device);
+}
+
+module_init(neo1973_init);
+module_exit(neo1973_exit);
+
+/* Module information */
+MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org");
+MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
new file mode 100644 (file)
index 0000000..48d0b75
--- /dev/null
@@ -0,0 +1,552 @@
+/* sound/soc/samsung/pcm.c
+ *
+ * ALSA SoC Audio Layer - S3C PCM-Controller driver
+ *
+ * Copyright (c) 2009 Samsung Electronics Co. Ltd
+ * Author: Jaswinder Singh <jassi.brar@samsung.com>
+ * based upon I2S drivers by Ben Dooks.
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <plat/audio.h>
+#include <plat/dma.h>
+
+#include "dma.h"
+#include "pcm.h"
+
+static struct s3c2410_dma_client s3c_pcm_dma_client_out = {
+       .name           = "PCM Stereo out"
+};
+
+static struct s3c2410_dma_client s3c_pcm_dma_client_in = {
+       .name           = "PCM Stereo in"
+};
+
+static struct s3c_dma_params s3c_pcm_stereo_out[] = {
+       [0] = {
+               .client         = &s3c_pcm_dma_client_out,
+               .dma_size       = 4,
+       },
+       [1] = {
+               .client         = &s3c_pcm_dma_client_out,
+               .dma_size       = 4,
+       },
+};
+
+static struct s3c_dma_params s3c_pcm_stereo_in[] = {
+       [0] = {
+               .client         = &s3c_pcm_dma_client_in,
+               .dma_size       = 4,
+       },
+       [1] = {
+               .client         = &s3c_pcm_dma_client_in,
+               .dma_size       = 4,
+       },
+};
+
+static struct s3c_pcm_info s3c_pcm[2];
+
+static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on)
+{
+       void __iomem *regs = pcm->regs;
+       u32 ctl, clkctl;
+
+       clkctl = readl(regs + S3C_PCM_CLKCTL);
+       ctl = readl(regs + S3C_PCM_CTL);
+       ctl &= ~(S3C_PCM_CTL_TXDIPSTICK_MASK
+                        << S3C_PCM_CTL_TXDIPSTICK_SHIFT);
+
+       if (on) {
+               ctl |= S3C_PCM_CTL_TXDMA_EN;
+               ctl |= S3C_PCM_CTL_TXFIFO_EN;
+               ctl |= S3C_PCM_CTL_ENABLE;
+               ctl |= (0x4<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
+               clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
+       } else {
+               ctl &= ~S3C_PCM_CTL_TXDMA_EN;
+               ctl &= ~S3C_PCM_CTL_TXFIFO_EN;
+
+               if (!(ctl & S3C_PCM_CTL_RXFIFO_EN)) {
+                       ctl &= ~S3C_PCM_CTL_ENABLE;
+                       if (!pcm->idleclk)
+                               clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
+               }
+       }
+
+       writel(clkctl, regs + S3C_PCM_CLKCTL);
+       writel(ctl, regs + S3C_PCM_CTL);
+}
+
+static void s3c_pcm_snd_rxctrl(struct s3c_pcm_info *pcm, int on)
+{
+       void __iomem *regs = pcm->regs;
+       u32 ctl, clkctl;
+
+       ctl = readl(regs + S3C_PCM_CTL);
+       clkctl = readl(regs + S3C_PCM_CLKCTL);
+       ctl &= ~(S3C_PCM_CTL_RXDIPSTICK_MASK
+                        << S3C_PCM_CTL_RXDIPSTICK_SHIFT);
+
+       if (on) {
+               ctl |= S3C_PCM_CTL_RXDMA_EN;
+               ctl |= S3C_PCM_CTL_RXFIFO_EN;
+               ctl |= S3C_PCM_CTL_ENABLE;
+               ctl |= (0x20<<S3C_PCM_CTL_RXDIPSTICK_SHIFT);
+               clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
+       } else {
+               ctl &= ~S3C_PCM_CTL_RXDMA_EN;
+               ctl &= ~S3C_PCM_CTL_RXFIFO_EN;
+
+               if (!(ctl & S3C_PCM_CTL_TXFIFO_EN)) {
+                       ctl &= ~S3C_PCM_CTL_ENABLE;
+                       if (!pcm->idleclk)
+                               clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
+               }
+       }
+
+       writel(clkctl, regs + S3C_PCM_CLKCTL);
+       writel(ctl, regs + S3C_PCM_CTL);
+}
+
+static int s3c_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+       unsigned long flags;
+
+       dev_dbg(pcm->dev, "Entered %s\n", __func__);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               spin_lock_irqsave(&pcm->lock, flags);
+
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+                       s3c_pcm_snd_rxctrl(pcm, 1);
+               else
+                       s3c_pcm_snd_txctrl(pcm, 1);
+
+               spin_unlock_irqrestore(&pcm->lock, flags);
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               spin_lock_irqsave(&pcm->lock, flags);
+
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+                       s3c_pcm_snd_rxctrl(pcm, 0);
+               else
+                       s3c_pcm_snd_txctrl(pcm, 0);
+
+               spin_unlock_irqrestore(&pcm->lock, flags);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *socdai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+       struct s3c_dma_params *dma_data;
+       void __iomem *regs = pcm->regs;
+       struct clk *clk;
+       int sclk_div, sync_div;
+       unsigned long flags;
+       u32 clkctl;
+
+       dev_dbg(pcm->dev, "Entered %s\n", __func__);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dma_data = pcm->dma_playback;
+       else
+               dma_data = pcm->dma_capture;
+
+       snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
+
+       /* Strictly check for sample size */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&pcm->lock, flags);
+
+       /* Get hold of the PCMSOURCE_CLK */
+       clkctl = readl(regs + S3C_PCM_CLKCTL);
+       if (clkctl & S3C_PCM_CLKCTL_SERCLKSEL_PCLK)
+               clk = pcm->pclk;
+       else
+               clk = pcm->cclk;
+
+       /* Set the SCLK divider */
+       sclk_div = clk_get_rate(clk) / pcm->sclk_per_fs /
+                                       params_rate(params) / 2 - 1;
+
+       clkctl &= ~(S3C_PCM_CLKCTL_SCLKDIV_MASK
+                       << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
+       clkctl |= ((sclk_div & S3C_PCM_CLKCTL_SCLKDIV_MASK)
+                       << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
+
+       /* Set the SYNC divider */
+       sync_div = pcm->sclk_per_fs - 1;
+
+       clkctl &= ~(S3C_PCM_CLKCTL_SYNCDIV_MASK
+                               << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
+       clkctl |= ((sync_div & S3C_PCM_CLKCTL_SYNCDIV_MASK)
+                               << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
+
+       writel(clkctl, regs + S3C_PCM_CLKCTL);
+
+       spin_unlock_irqrestore(&pcm->lock, flags);
+
+       dev_dbg(pcm->dev, "PCMSOURCE_CLK-%lu SCLK=%ufs SCLK_DIV=%d SYNC_DIV=%d\n",
+                               clk_get_rate(clk), pcm->sclk_per_fs,
+                               sclk_div, sync_div);
+
+       return 0;
+}
+
+static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai,
+                              unsigned int fmt)
+{
+       struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
+       void __iomem *regs = pcm->regs;
+       unsigned long flags;
+       int ret = 0;
+       u32 ctl;
+
+       dev_dbg(pcm->dev, "Entered %s\n", __func__);
+
+       spin_lock_irqsave(&pcm->lock, flags);
+
+       ctl = readl(regs + S3C_PCM_CTL);
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               /* Nothing to do, NB_NF by default */
+               break;
+       default:
+               dev_err(pcm->dev, "Unsupported clock inversion!\n");
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               /* Nothing to do, Master by default */
+               break;
+       default:
+               dev_err(pcm->dev, "Unsupported master/slave format!\n");
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
+       case SND_SOC_DAIFMT_CONT:
+               pcm->idleclk = 1;
+               break;
+       case SND_SOC_DAIFMT_GATED:
+               pcm->idleclk = 0;
+               break;
+       default:
+               dev_err(pcm->dev, "Invalid Clock gating request!\n");
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+               ctl |= S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
+               ctl |= S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               ctl &= ~S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
+               ctl &= ~S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
+               break;
+       default:
+               dev_err(pcm->dev, "Unsupported data format!\n");
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       writel(ctl, regs + S3C_PCM_CTL);
+
+exit:
+       spin_unlock_irqrestore(&pcm->lock, flags);
+
+       return ret;
+}
+
+static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai,
+                                               int div_id, int div)
+{
+       struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
+
+       switch (div_id) {
+       case S3C_PCM_SCLK_PER_FS:
+               pcm->sclk_per_fs = div;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai,
+                                 int clk_id, unsigned int freq, int dir)
+{
+       struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
+       void __iomem *regs = pcm->regs;
+       u32 clkctl = readl(regs + S3C_PCM_CLKCTL);
+
+       switch (clk_id) {
+       case S3C_PCM_CLKSRC_PCLK:
+               clkctl |= S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
+               break;
+
+       case S3C_PCM_CLKSRC_MUX:
+               clkctl &= ~S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
+
+               if (clk_get_rate(pcm->cclk) != freq)
+                       clk_set_rate(pcm->cclk, freq);
+
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       writel(clkctl, regs + S3C_PCM_CLKCTL);
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
+       .set_sysclk     = s3c_pcm_set_sysclk,
+       .set_clkdiv     = s3c_pcm_set_clkdiv,
+       .trigger        = s3c_pcm_trigger,
+       .hw_params      = s3c_pcm_hw_params,
+       .set_fmt        = s3c_pcm_set_fmt,
+};
+
+#define S3C_PCM_RATES  SNDRV_PCM_RATE_8000_96000
+
+#define S3C_PCM_DAI_DECLARE                    \
+       .symmetric_rates = 1,                                   \
+       .ops = &s3c_pcm_dai_ops,                                \
+       .playback = {                                           \
+               .channels_min   = 2,                            \
+               .channels_max   = 2,                            \
+               .rates          = S3C_PCM_RATES,                \
+               .formats        = SNDRV_PCM_FMTBIT_S16_LE,      \
+       },                                                      \
+       .capture = {                                            \
+               .channels_min   = 2,                            \
+               .channels_max   = 2,                            \
+               .rates          = S3C_PCM_RATES,                \
+               .formats        = SNDRV_PCM_FMTBIT_S16_LE,      \
+       }
+
+struct snd_soc_dai_driver s3c_pcm_dai[] = {
+       [0] = {
+               .name   = "samsung-pcm.0",
+               S3C_PCM_DAI_DECLARE,
+       },
+       [1] = {
+               .name   = "samsung-pcm.1",
+               S3C_PCM_DAI_DECLARE,
+       },
+};
+EXPORT_SYMBOL_GPL(s3c_pcm_dai);
+
+static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
+{
+       struct s3c_pcm_info *pcm;
+       struct resource *mem_res, *dmatx_res, *dmarx_res;
+       struct s3c_audio_pdata *pcm_pdata;
+       int ret;
+
+       /* Check for valid device index */
+       if ((pdev->id < 0) || pdev->id >= ARRAY_SIZE(s3c_pcm)) {
+               dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
+               return -EINVAL;
+       }
+
+       pcm_pdata = pdev->dev.platform_data;
+
+       /* Check for availability of necessary resource */
+       dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!dmatx_res) {
+               dev_err(&pdev->dev, "Unable to get PCM-TX dma resource\n");
+               return -ENXIO;
+       }
+
+       dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+       if (!dmarx_res) {
+               dev_err(&pdev->dev, "Unable to get PCM-RX dma resource\n");
+               return -ENXIO;
+       }
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem_res) {
+               dev_err(&pdev->dev, "Unable to get register resource\n");
+               return -ENXIO;
+       }
+
+       if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) {
+               dev_err(&pdev->dev, "Unable to configure gpio\n");
+               return -EINVAL;
+       }
+
+       pcm = &s3c_pcm[pdev->id];
+       pcm->dev = &pdev->dev;
+
+       spin_lock_init(&pcm->lock);
+
+       /* Default is 128fs */
+       pcm->sclk_per_fs = 128;
+
+       pcm->cclk = clk_get(&pdev->dev, "audio-bus");
+       if (IS_ERR(pcm->cclk)) {
+               dev_err(&pdev->dev, "failed to get audio-bus\n");
+               ret = PTR_ERR(pcm->cclk);
+               goto err1;
+       }
+       clk_enable(pcm->cclk);
+
+       /* record our pcm structure for later use in the callbacks */
+       dev_set_drvdata(&pdev->dev, pcm);
+
+       if (!request_mem_region(mem_res->start,
+                               resource_size(mem_res), "samsung-pcm")) {
+               dev_err(&pdev->dev, "Unable to request register region\n");
+               ret = -EBUSY;
+               goto err2;
+       }
+
+       pcm->regs = ioremap(mem_res->start, 0x100);
+       if (pcm->regs == NULL) {
+               dev_err(&pdev->dev, "cannot ioremap registers\n");
+               ret = -ENXIO;
+               goto err3;
+       }
+
+       pcm->pclk = clk_get(&pdev->dev, "pcm");
+       if (IS_ERR(pcm->pclk)) {
+               dev_err(&pdev->dev, "failed to get pcm_clock\n");
+               ret = -ENOENT;
+               goto err4;
+       }
+       clk_enable(pcm->pclk);
+
+       ret = snd_soc_register_dai(&pdev->dev, &s3c_pcm_dai[pdev->id]);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "failed to get pcm_clock\n");
+               goto err5;
+       }
+
+       s3c_pcm_stereo_in[pdev->id].dma_addr = mem_res->start
+                                                       + S3C_PCM_RXFIFO;
+       s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start
+                                                       + S3C_PCM_TXFIFO;
+
+       s3c_pcm_stereo_in[pdev->id].channel = dmarx_res->start;
+       s3c_pcm_stereo_out[pdev->id].channel = dmatx_res->start;
+
+       pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id];
+       pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id];
+
+       return 0;
+
+err5:
+       clk_disable(pcm->pclk);
+       clk_put(pcm->pclk);
+err4:
+       iounmap(pcm->regs);
+err3:
+       release_mem_region(mem_res->start, resource_size(mem_res));
+err2:
+       clk_disable(pcm->cclk);
+       clk_put(pcm->cclk);
+err1:
+       return ret;
+}
+
+static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev)
+{
+       struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id];
+       struct resource *mem_res;
+
+       snd_soc_unregister_dai(&pdev->dev);
+
+       iounmap(pcm->regs);
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(mem_res->start, resource_size(mem_res));
+
+       clk_disable(pcm->cclk);
+       clk_disable(pcm->pclk);
+       clk_put(pcm->pclk);
+       clk_put(pcm->cclk);
+
+       return 0;
+}
+
+static struct platform_driver s3c_pcm_driver = {
+       .probe  = s3c_pcm_dev_probe,
+       .remove = s3c_pcm_dev_remove,
+       .driver = {
+               .name = "samsung-pcm",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init s3c_pcm_init(void)
+{
+       return platform_driver_register(&s3c_pcm_driver);
+}
+module_init(s3c_pcm_init);
+
+static void __exit s3c_pcm_exit(void)
+{
+       platform_driver_unregister(&s3c_pcm_driver);
+}
+module_exit(s3c_pcm_exit);
+
+/* Module information */
+MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
+MODULE_DESCRIPTION("S3C PCM Controller Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-pcm");
diff --git a/sound/soc/samsung/pcm.h b/sound/soc/samsung/pcm.h
new file mode 100644 (file)
index 0000000..03393dc
--- /dev/null
@@ -0,0 +1,124 @@
+/*  sound/soc/samsung/pcm.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 __S3C_PCM_H
+#define __S3C_PCM_H __FILE__
+
+/*Register Offsets */
+#define S3C_PCM_CTL    (0x00)
+#define S3C_PCM_CLKCTL (0x04)
+#define S3C_PCM_TXFIFO (0x08)
+#define S3C_PCM_RXFIFO (0x0C)
+#define S3C_PCM_IRQCTL (0x10)
+#define S3C_PCM_IRQSTAT        (0x14)
+#define S3C_PCM_FIFOSTAT       (0x18)
+#define S3C_PCM_CLRINT (0x20)
+
+/* PCM_CTL Bit-Fields */
+#define S3C_PCM_CTL_TXDIPSTICK_MASK            (0x3f)
+#define S3C_PCM_CTL_TXDIPSTICK_SHIFT   (13)
+#define S3C_PCM_CTL_RXDIPSTICK_MASK            (0x3f)
+#define S3C_PCM_CTL_RXDIPSTICK_SHIFT   (7)
+#define S3C_PCM_CTL_TXDMA_EN           (0x1<<6)
+#define S3C_PCM_CTL_RXDMA_EN           (0x1<<5)
+#define S3C_PCM_CTL_TXMSB_AFTER_FSYNC  (0x1<<4)
+#define S3C_PCM_CTL_RXMSB_AFTER_FSYNC  (0x1<<3)
+#define S3C_PCM_CTL_TXFIFO_EN          (0x1<<2)
+#define S3C_PCM_CTL_RXFIFO_EN          (0x1<<1)
+#define S3C_PCM_CTL_ENABLE                     (0x1<<0)
+
+/* PCM_CLKCTL Bit-Fields */
+#define S3C_PCM_CLKCTL_SERCLK_EN               (0x1<<19)
+#define S3C_PCM_CLKCTL_SERCLKSEL_PCLK  (0x1<<18)
+#define S3C_PCM_CLKCTL_SCLKDIV_MASK            (0x1ff)
+#define S3C_PCM_CLKCTL_SYNCDIV_MASK            (0x1ff)
+#define S3C_PCM_CLKCTL_SCLKDIV_SHIFT   (9)
+#define S3C_PCM_CLKCTL_SYNCDIV_SHIFT   (0)
+
+/* PCM_TXFIFO Bit-Fields */
+#define S3C_PCM_TXFIFO_DVALID  (0x1<<16)
+#define S3C_PCM_TXFIFO_DATA_MSK        (0xffff<<0)
+
+/* PCM_RXFIFO Bit-Fields */
+#define S3C_PCM_RXFIFO_DVALID  (0x1<<16)
+#define S3C_PCM_RXFIFO_DATA_MSK        (0xffff<<0)
+
+/* PCM_IRQCTL Bit-Fields */
+#define S3C_PCM_IRQCTL_IRQEN           (0x1<<14)
+#define S3C_PCM_IRQCTL_WRDEN           (0x1<<12)
+#define S3C_PCM_IRQCTL_TXEMPTYEN               (0x1<<11)
+#define S3C_PCM_IRQCTL_TXALMSTEMPTYEN  (0x1<<10)
+#define S3C_PCM_IRQCTL_TXFULLEN                (0x1<<9)
+#define S3C_PCM_IRQCTL_TXALMSTFULLEN   (0x1<<8)
+#define S3C_PCM_IRQCTL_TXSTARVEN               (0x1<<7)
+#define S3C_PCM_IRQCTL_TXERROVRFLEN            (0x1<<6)
+#define S3C_PCM_IRQCTL_RXEMPTEN                (0x1<<5)
+#define S3C_PCM_IRQCTL_RXALMSTEMPTEN   (0x1<<4)
+#define S3C_PCM_IRQCTL_RXFULLEN                (0x1<<3)
+#define S3C_PCM_IRQCTL_RXALMSTFULLEN   (0x1<<2)
+#define S3C_PCM_IRQCTL_RXSTARVEN               (0x1<<1)
+#define S3C_PCM_IRQCTL_RXERROVRFLEN            (0x1<<0)
+
+/* PCM_IRQSTAT Bit-Fields */
+#define S3C_PCM_IRQSTAT_IRQPND         (0x1<<13)
+#define S3C_PCM_IRQSTAT_WRD_XFER               (0x1<<12)
+#define S3C_PCM_IRQSTAT_TXEMPTY                (0x1<<11)
+#define S3C_PCM_IRQSTAT_TXALMSTEMPTY   (0x1<<10)
+#define S3C_PCM_IRQSTAT_TXFULL         (0x1<<9)
+#define S3C_PCM_IRQSTAT_TXALMSTFULL            (0x1<<8)
+#define S3C_PCM_IRQSTAT_TXSTARV                (0x1<<7)
+#define S3C_PCM_IRQSTAT_TXERROVRFL             (0x1<<6)
+#define S3C_PCM_IRQSTAT_RXEMPT         (0x1<<5)
+#define S3C_PCM_IRQSTAT_RXALMSTEMPT            (0x1<<4)
+#define S3C_PCM_IRQSTAT_RXFULL         (0x1<<3)
+#define S3C_PCM_IRQSTAT_RXALMSTFULL            (0x1<<2)
+#define S3C_PCM_IRQSTAT_RXSTARV                (0x1<<1)
+#define S3C_PCM_IRQSTAT_RXERROVRFL             (0x1<<0)
+
+/* PCM_FIFOSTAT Bit-Fields */
+#define S3C_PCM_FIFOSTAT_TXCNT_MSK             (0x3f<<14)
+#define S3C_PCM_FIFOSTAT_TXFIFOEMPTY   (0x1<<13)
+#define S3C_PCM_FIFOSTAT_TXFIFOALMSTEMPTY      (0x1<<12)
+#define S3C_PCM_FIFOSTAT_TXFIFOFULL            (0x1<<11)
+#define S3C_PCM_FIFOSTAT_TXFIFOALMSTFULL       (0x1<<10)
+#define S3C_PCM_FIFOSTAT_RXCNT_MSK             (0x3f<<4)
+#define S3C_PCM_FIFOSTAT_RXFIFOEMPTY   (0x1<<3)
+#define S3C_PCM_FIFOSTAT_RXFIFOALMSTEMPTY      (0x1<<2)
+#define S3C_PCM_FIFOSTAT_RXFIFOFULL            (0x1<<1)
+#define S3C_PCM_FIFOSTAT_RXFIFOALMSTFULL       (0x1<<0)
+
+#define S3C_PCM_CLKSRC_PCLK    0
+#define S3C_PCM_CLKSRC_MUX     1
+
+#define S3C_PCM_SCLK_PER_FS    0
+
+/**
+ * struct s3c_pcm_info - S3C PCM Controller information
+ * @dev: The parent device passed to use from the probe.
+ * @regs: The pointer to the device register block.
+ * @dma_playback: DMA information for playback channel.
+ * @dma_capture: DMA information for capture channel.
+ */
+struct s3c_pcm_info {
+       spinlock_t lock;
+       struct device   *dev;
+       void __iomem    *regs;
+
+       unsigned int sclk_per_fs;
+
+       /* Whether to keep PCMSCLK enabled even when idle(no active xfer) */
+       unsigned int idleclk;
+
+       struct clk      *pclk;
+       struct clk      *cclk;
+
+       struct s3c_dma_params   *dma_playback;
+       struct s3c_dma_params   *dma_capture;
+};
+
+#endif /* __S3C_PCM_H */
diff --git a/sound/soc/samsung/regs-i2s-v2.h b/sound/soc/samsung/regs-i2s-v2.h
new file mode 100644 (file)
index 0000000..5e5e568
--- /dev/null
@@ -0,0 +1,115 @@
+/* linux/include/asm-arm/plat-s3c24xx/regs-s3c2412-iis.h
+ *
+ * Copyright 2007 Simtec Electronics <linux@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * 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.
+ *
+ * S3C2412 IIS register definition
+*/
+
+#ifndef __ASM_ARCH_REGS_S3C2412_IIS_H
+#define __ASM_ARCH_REGS_S3C2412_IIS_H
+
+#define S3C2412_IISCON                 (0x00)
+#define S3C2412_IISMOD                 (0x04)
+#define S3C2412_IISFIC                 (0x08)
+#define S3C2412_IISPSR                 (0x0C)
+#define S3C2412_IISTXD                 (0x10)
+#define S3C2412_IISRXD                 (0x14)
+
+#define S5PC1XX_IISFICS                0x18
+#define S5PC1XX_IISTXDS                0x1C
+
+#define S5PC1XX_IISCON_SW_RST          (1 << 31)
+#define S5PC1XX_IISCON_FRXOFSTATUS     (1 << 26)
+#define S5PC1XX_IISCON_FRXORINTEN      (1 << 25)
+#define S5PC1XX_IISCON_FTXSURSTAT      (1 << 24)
+#define S5PC1XX_IISCON_FTXSURINTEN     (1 << 23)
+#define S5PC1XX_IISCON_TXSDMAPAUSE     (1 << 20)
+#define S5PC1XX_IISCON_TXSDMACTIVE     (1 << 18)
+
+#define S3C64XX_IISCON_FTXURSTATUS     (1 << 17)
+#define S3C64XX_IISCON_FTXURINTEN      (1 << 16)
+#define S3C64XX_IISCON_TXFIFO2_EMPTY   (1 << 15)
+#define S3C64XX_IISCON_TXFIFO1_EMPTY   (1 << 14)
+#define S3C64XX_IISCON_TXFIFO2_FULL    (1 << 13)
+#define S3C64XX_IISCON_TXFIFO1_FULL    (1 << 12)
+
+#define S3C2412_IISCON_LRINDEX         (1 << 11)
+#define S3C2412_IISCON_TXFIFO_EMPTY    (1 << 10)
+#define S3C2412_IISCON_RXFIFO_EMPTY    (1 << 9)
+#define S3C2412_IISCON_TXFIFO_FULL     (1 << 8)
+#define S3C2412_IISCON_RXFIFO_FULL     (1 << 7)
+#define S3C2412_IISCON_TXDMA_PAUSE     (1 << 6)
+#define S3C2412_IISCON_RXDMA_PAUSE     (1 << 5)
+#define S3C2412_IISCON_TXCH_PAUSE      (1 << 4)
+#define S3C2412_IISCON_RXCH_PAUSE      (1 << 3)
+#define S3C2412_IISCON_TXDMA_ACTIVE    (1 << 2)
+#define S3C2412_IISCON_RXDMA_ACTIVE    (1 << 1)
+#define S3C2412_IISCON_IIS_ACTIVE      (1 << 0)
+
+#define S5PC1XX_IISMOD_OPCLK_CDCLK_OUT (0 << 30)
+#define S5PC1XX_IISMOD_OPCLK_CDCLK_IN  (1 << 30)
+#define S5PC1XX_IISMOD_OPCLK_BCLK_OUT  (2 << 30)
+#define S5PC1XX_IISMOD_OPCLK_PCLK      (3 << 30)
+#define S5PC1XX_IISMOD_OPCLK_MASK      (3 << 30)
+#define S5PC1XX_IISMOD_TXS_IDMA                (1 << 28) /* Sec_TXFIFO use I-DMA */
+#define S5PC1XX_IISMOD_BLCS_MASK       0x3
+#define S5PC1XX_IISMOD_BLCS_SHIFT      26
+#define S5PC1XX_IISMOD_BLCP_MASK       0x3
+#define S5PC1XX_IISMOD_BLCP_SHIFT      24
+
+#define S3C64XX_IISMOD_C2DD_HHALF      (1 << 21) /* Discard Higher-half */
+#define S3C64XX_IISMOD_C2DD_LHALF      (1 << 20) /* Discard Lower-half */
+#define S3C64XX_IISMOD_C1DD_HHALF      (1 << 19)
+#define S3C64XX_IISMOD_C1DD_LHALF      (1 << 18)
+#define S3C64XX_IISMOD_DC2_EN          (1 << 17)
+#define S3C64XX_IISMOD_DC1_EN          (1 << 16)
+#define S3C64XX_IISMOD_BLC_16BIT       (0 << 13)
+#define S3C64XX_IISMOD_BLC_8BIT                (1 << 13)
+#define S3C64XX_IISMOD_BLC_24BIT       (2 << 13)
+#define S3C64XX_IISMOD_BLC_MASK                (3 << 13)
+
+#define S3C2412_IISMOD_IMS_SYSMUX      (1 << 10)
+#define S3C2412_IISMOD_SLAVE           (1 << 11)
+#define S3C2412_IISMOD_MODE_TXONLY     (0 << 8)
+#define S3C2412_IISMOD_MODE_RXONLY     (1 << 8)
+#define S3C2412_IISMOD_MODE_TXRX       (2 << 8)
+#define S3C2412_IISMOD_MODE_MASK       (3 << 8)
+#define S3C2412_IISMOD_LR_LLOW         (0 << 7)
+#define S3C2412_IISMOD_LR_RLOW         (1 << 7)
+#define S3C2412_IISMOD_SDF_IIS         (0 << 5)
+#define S3C2412_IISMOD_SDF_MSB         (1 << 5)
+#define S3C2412_IISMOD_SDF_LSB         (2 << 5)
+#define S3C2412_IISMOD_SDF_MASK                (3 << 5)
+#define S3C2412_IISMOD_RCLK_256FS      (0 << 3)
+#define S3C2412_IISMOD_RCLK_512FS      (1 << 3)
+#define S3C2412_IISMOD_RCLK_384FS      (2 << 3)
+#define S3C2412_IISMOD_RCLK_768FS      (3 << 3)
+#define S3C2412_IISMOD_RCLK_MASK       (3 << 3)
+#define S3C2412_IISMOD_BCLK_32FS       (0 << 1)
+#define S3C2412_IISMOD_BCLK_48FS       (1 << 1)
+#define S3C2412_IISMOD_BCLK_16FS       (2 << 1)
+#define S3C2412_IISMOD_BCLK_24FS       (3 << 1)
+#define S3C2412_IISMOD_BCLK_MASK       (3 << 1)
+#define S3C2412_IISMOD_8BIT            (1 << 0)
+
+#define S3C64XX_IISMOD_CDCLKCON                (1 << 12)
+
+#define S3C2412_IISPSR_PSREN           (1 << 15)
+
+#define S3C64XX_IISFIC_TX2COUNT(x)     (((x) >>  24) & 0xf)
+#define S3C64XX_IISFIC_TX1COUNT(x)     (((x) >>  16) & 0xf)
+
+#define S3C2412_IISFIC_TXFLUSH         (1 << 15)
+#define S3C2412_IISFIC_RXFLUSH         (1 << 7)
+#define S3C2412_IISFIC_TXCOUNT(x)      (((x) >>  8) & 0xf)
+#define S3C2412_IISFIC_RXCOUNT(x)      (((x) >>  0) & 0xf)
+
+#define S5PC1XX_IISFICS_TXFLUSH                (1 << 15)
+#define S5PC1XX_IISFICS_TXCOUNT(x)     (((x) >>  8) & 0x7f)
+
+#endif /* __ASM_ARCH_REGS_S3C2412_IIS_H */
diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c
new file mode 100644 (file)
index 0000000..f400274
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * rx1950.c  --  ALSA Soc Audio Layer
+ *
+ * Copyright (c) 2010 Vasily Khoruzhick <anarsoul@gmail.com>
+ *
+ * Based on smdk2440.c and magician.c
+ *
+ * Authors: Graeme Gregory graeme.gregory@wolfsonmicro.com
+ *          Philipp Zabel <philipp.zabel@gmail.com>
+ *          Denis Grigoriev <dgreenday@gmail.com>
+ *          Vasily Khoruzhick <anarsoul@gmail.com>
+ *
+ *  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/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+
+#include <sound/soc.h>
+#include <sound/uda1380.h>
+#include <sound/jack.h>
+
+#include <plat/regs-iis.h>
+
+#include <mach/regs-clock.h>
+
+#include <asm/mach-types.h>
+
+#include "dma.h"
+#include "s3c24xx-i2s.h"
+#include "../codecs/uda1380.h"
+
+static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd);
+static int rx1950_startup(struct snd_pcm_substream *substream);
+static int rx1950_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params);
+static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol, int event);
+
+static unsigned int rates[] = {
+       16000,
+       44100,
+       48000,
+};
+
+static struct snd_pcm_hw_constraint_list hw_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list = rates,
+       .mask = 0,
+};
+
+static struct snd_soc_jack hp_jack;
+
+static struct snd_soc_jack_pin hp_jack_pins[] = {
+       {
+               .pin    = "Headphone Jack",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+       {
+               .pin    = "Speaker",
+               .mask   = SND_JACK_HEADPHONE,
+               .invert = 1,
+       },
+};
+
+static struct snd_soc_jack_gpio hp_jack_gpios[] = {
+       [0] = {
+               .gpio                   = S3C2410_GPG(12),
+               .name                   = "hp-gpio",
+               .report                 = SND_JACK_HEADPHONE,
+               .invert                 = 1,
+               .debounce_time          = 200,
+       },
+};
+
+static struct snd_soc_ops rx1950_ops = {
+       .startup        = rx1950_startup,
+       .hw_params      = rx1950_hw_params,
+};
+
+/* s3c24xx digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link rx1950_uda1380_dai[] = {
+       {
+               .name           = "uda1380",
+               .stream_name    = "UDA1380 Duplex",
+               .cpu_dai_name   = "s3c24xx-iis",
+               .codec_dai_name = "uda1380-hifi",
+               .init           = rx1950_uda1380_init,
+               .platform_name  = "samsung-audio",
+               .codec_name     = "uda1380-codec.0-001a",
+               .ops            = &rx1950_ops,
+       },
+};
+
+static struct snd_soc_card rx1950_asoc = {
+       .name = "rx1950",
+       .dai_link = rx1950_uda1380_dai,
+       .num_links = ARRAY_SIZE(rx1950_uda1380_dai),
+};
+
+/* rx1950 machine dapm widgets */
+static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+       SND_SOC_DAPM_SPK("Speaker", rx1950_spk_power),
+};
+
+/* rx1950 machine audio_map */
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* headphone connected to VOUTLHP, VOUTRHP */
+       {"Headphone Jack", NULL, "VOUTLHP"},
+       {"Headphone Jack", NULL, "VOUTRHP"},
+
+       /* ext speaker connected to VOUTL, VOUTR  */
+       {"Speaker", NULL, "VOUTL"},
+       {"Speaker", NULL, "VOUTR"},
+
+       /* mic is connected to VINM */
+       {"VINM", NULL, "Mic Jack"},
+};
+
+static struct platform_device *s3c24xx_snd_device;
+
+static int rx1950_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       runtime->hw.rate_min = hw_rates.list[0];
+       runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1];
+       runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
+
+       return snd_pcm_hw_constraint_list(runtime, 0,
+                                       SNDRV_PCM_HW_PARAM_RATE,
+                                       &hw_rates);
+}
+
+static int rx1950_spk_power(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *kcontrol, int event)
+{
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               gpio_set_value(S3C2410_GPA(1), 1);
+       else
+               gpio_set_value(S3C2410_GPA(1), 0);
+
+       return 0;
+}
+
+static int rx1950_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;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int div;
+       int ret;
+       unsigned int rate = params_rate(params);
+       int clk_source, fs_mode;
+
+       switch (rate) {
+       case 16000:
+       case 48000:
+               clk_source = S3C24XX_CLKSRC_PCLK;
+               fs_mode = S3C2410_IISMOD_256FS;
+               div = s3c24xx_i2s_get_clockrate() / (256 * rate);
+               if (s3c24xx_i2s_get_clockrate() % (256 * rate) > (128 * rate))
+                       div++;
+               break;
+       case 44100:
+       case 88200:
+               clk_source = S3C24XX_CLKSRC_MPLL;
+               fs_mode = S3C2410_IISMOD_384FS;
+               div = 1;
+               break;
+       default:
+               printk(KERN_ERR "%s: rate %d is not supported\n",
+                       __func__, rate);
+               return -EINVAL;
+       }
+
+       /* set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* set cpu DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* select clock source */
+       ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source, rate,
+                       SND_SOC_CLOCK_OUT);
+       if (ret < 0)
+               return ret;
+
+       /* set MCLK division for sample rate */
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
+               fs_mode);
+       if (ret < 0)
+               return ret;
+
+       /* set BCLK division for sample rate */
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
+               S3C2410_IISMOD_32FS);
+       if (ret < 0)
+               return ret;
+
+       /* set prescaler division for sample rate */
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+               S3C24XX_PRESCALE(div, div));
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       int err;
+
+       /* Add rx1950 specific widgets */
+       err = snd_soc_dapm_new_controls(dapm, uda1380_dapm_widgets,
+                                 ARRAY_SIZE(uda1380_dapm_widgets));
+
+       if (err)
+               return err;
+
+       /* Set up rx1950 specific audio path audio_mapnects */
+       err = snd_soc_dapm_add_routes(dapm, audio_map,
+                                     ARRAY_SIZE(audio_map));
+
+       if (err)
+               return err;
+
+       snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+       snd_soc_dapm_enable_pin(dapm, "Speaker");
+       snd_soc_dapm_enable_pin(dapm, "Mic Jack");
+
+       snd_soc_dapm_sync(dapm);
+
+       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
+               &hp_jack);
+
+       snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
+               hp_jack_pins);
+
+       snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
+               hp_jack_gpios);
+
+       return 0;
+}
+
+static int __init rx1950_init(void)
+{
+       int ret;
+
+       if (!machine_is_rx1950())
+               return -ENODEV;
+
+       /* configure some gpios */
+       ret = gpio_request(S3C2410_GPA(1), "speaker-power");
+       if (ret)
+               goto err_gpio;
+
+       ret = gpio_direction_output(S3C2410_GPA(1), 0);
+       if (ret)
+               goto err_gpio_conf;
+
+       s3c24xx_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!s3c24xx_snd_device) {
+               ret = -ENOMEM;
+               goto err_plat_alloc;
+       }
+
+       platform_set_drvdata(s3c24xx_snd_device, &rx1950_asoc);
+       ret = platform_device_add(s3c24xx_snd_device);
+
+       if (ret) {
+               platform_device_put(s3c24xx_snd_device);
+               goto err_plat_add;
+       }
+
+       return 0;
+
+err_plat_add:
+err_plat_alloc:
+err_gpio_conf:
+       gpio_free(S3C2410_GPA(1));
+
+err_gpio:
+       return ret;
+}
+
+static void __exit rx1950_exit(void)
+{
+       platform_device_unregister(s3c24xx_snd_device);
+       snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios),
+               hp_jack_gpios);
+       gpio_free(S3C2410_GPA(1));
+}
+
+module_init(rx1950_init);
+module_exit(rx1950_exit);
+
+/* Module information */
+MODULE_AUTHOR("Vasily Khoruzhick");
+MODULE_DESCRIPTION("ALSA SoC RX1950");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c
new file mode 100644 (file)
index 0000000..094f36e
--- /dev/null
@@ -0,0 +1,757 @@
+/* sound/soc/samsung/s3c-i2c-v2.c
+ *
+ * ALSA Soc Audio Layer - I2S core for newer Samsung SoCs.
+ *
+ * Copyright (c) 2006 Wolfson Microelectronics PLC.
+ *     Graeme Gregory graeme.gregory@wolfsonmicro.com
+ *     linux@wolfsonmicro.com
+ *
+ * Copyright (c) 2008, 2007, 2004-2005 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * 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/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <mach/dma.h>
+
+#include "regs-i2s-v2.h"
+#include "s3c-i2s-v2.h"
+#include "dma.h"
+
+#undef S3C_IIS_V2_SUPPORTED
+
+#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) \
+       || defined(CONFIG_CPU_S5PV210)
+#define S3C_IIS_V2_SUPPORTED
+#endif
+
+#ifdef CONFIG_PLAT_S3C64XX
+#define S3C_IIS_V2_SUPPORTED
+#endif
+
+#ifndef S3C_IIS_V2_SUPPORTED
+#error Unsupported CPU model
+#endif
+
+#define S3C2412_I2S_DEBUG_CON 0
+
+static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
+{
+       return snd_soc_dai_get_drvdata(cpu_dai);
+}
+
+#define bit_set(v, b) (((v) & (b)) ? 1 : 0)
+
+#if S3C2412_I2S_DEBUG_CON
+static void dbg_showcon(const char *fn, u32 con)
+{
+       printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn,
+              bit_set(con, S3C2412_IISCON_LRINDEX),
+              bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY),
+              bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY),
+              bit_set(con, S3C2412_IISCON_TXFIFO_FULL),
+              bit_set(con, S3C2412_IISCON_RXFIFO_FULL));
+
+       printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n",
+              fn,
+              bit_set(con, S3C2412_IISCON_TXDMA_PAUSE),
+              bit_set(con, S3C2412_IISCON_RXDMA_PAUSE),
+              bit_set(con, S3C2412_IISCON_TXCH_PAUSE),
+              bit_set(con, S3C2412_IISCON_RXCH_PAUSE));
+       printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn,
+              bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE),
+              bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE),
+              bit_set(con, S3C2412_IISCON_IIS_ACTIVE));
+}
+#else
+static inline void dbg_showcon(const char *fn, u32 con)
+{
+}
+#endif
+
+
+/* Turn on or off the transmission path. */
+static void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on)
+{
+       void __iomem *regs = i2s->regs;
+       u32 fic, con, mod;
+
+       pr_debug("%s(%d)\n", __func__, on);
+
+       fic = readl(regs + S3C2412_IISFIC);
+       con = readl(regs + S3C2412_IISCON);
+       mod = readl(regs + S3C2412_IISMOD);
+
+       pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
+
+       if (on) {
+               con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
+               con &= ~S3C2412_IISCON_TXDMA_PAUSE;
+               con &= ~S3C2412_IISCON_TXCH_PAUSE;
+
+               switch (mod & S3C2412_IISMOD_MODE_MASK) {
+               case S3C2412_IISMOD_MODE_TXONLY:
+               case S3C2412_IISMOD_MODE_TXRX:
+                       /* do nothing, we are in the right mode */
+                       break;
+
+               case S3C2412_IISMOD_MODE_RXONLY:
+                       mod &= ~S3C2412_IISMOD_MODE_MASK;
+                       mod |= S3C2412_IISMOD_MODE_TXRX;
+                       break;
+
+               default:
+                       dev_err(i2s->dev, "TXEN: Invalid MODE %x in IISMOD\n",
+                               mod & S3C2412_IISMOD_MODE_MASK);
+                       break;
+               }
+
+               writel(con, regs + S3C2412_IISCON);
+               writel(mod, regs + S3C2412_IISMOD);
+       } else {
+               /* Note, we do not have any indication that the FIFO problems
+                * tha the S3C2410/2440 had apply here, so we should be able
+                * to disable the DMA and TX without resetting the FIFOS.
+                */
+
+               con |=  S3C2412_IISCON_TXDMA_PAUSE;
+               con |=  S3C2412_IISCON_TXCH_PAUSE;
+               con &= ~S3C2412_IISCON_TXDMA_ACTIVE;
+
+               switch (mod & S3C2412_IISMOD_MODE_MASK) {
+               case S3C2412_IISMOD_MODE_TXRX:
+                       mod &= ~S3C2412_IISMOD_MODE_MASK;
+                       mod |= S3C2412_IISMOD_MODE_RXONLY;
+                       break;
+
+               case S3C2412_IISMOD_MODE_TXONLY:
+                       mod &= ~S3C2412_IISMOD_MODE_MASK;
+                       con &= ~S3C2412_IISCON_IIS_ACTIVE;
+                       break;
+
+               default:
+                       dev_err(i2s->dev, "TXDIS: Invalid MODE %x in IISMOD\n",
+                               mod & S3C2412_IISMOD_MODE_MASK);
+                       break;
+               }
+
+               writel(mod, regs + S3C2412_IISMOD);
+               writel(con, regs + S3C2412_IISCON);
+       }
+
+       fic = readl(regs + S3C2412_IISFIC);
+       dbg_showcon(__func__, con);
+       pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
+}
+
+static void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on)
+{
+       void __iomem *regs = i2s->regs;
+       u32 fic, con, mod;
+
+       pr_debug("%s(%d)\n", __func__, on);
+
+       fic = readl(regs + S3C2412_IISFIC);
+       con = readl(regs + S3C2412_IISCON);
+       mod = readl(regs + S3C2412_IISMOD);
+
+       pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
+
+       if (on) {
+               con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
+               con &= ~S3C2412_IISCON_RXDMA_PAUSE;
+               con &= ~S3C2412_IISCON_RXCH_PAUSE;
+
+               switch (mod & S3C2412_IISMOD_MODE_MASK) {
+               case S3C2412_IISMOD_MODE_TXRX:
+               case S3C2412_IISMOD_MODE_RXONLY:
+                       /* do nothing, we are in the right mode */
+                       break;
+
+               case S3C2412_IISMOD_MODE_TXONLY:
+                       mod &= ~S3C2412_IISMOD_MODE_MASK;
+                       mod |= S3C2412_IISMOD_MODE_TXRX;
+                       break;
+
+               default:
+                       dev_err(i2s->dev, "RXEN: Invalid MODE %x in IISMOD\n",
+                               mod & S3C2412_IISMOD_MODE_MASK);
+               }
+
+               writel(mod, regs + S3C2412_IISMOD);
+               writel(con, regs + S3C2412_IISCON);
+       } else {
+               /* See txctrl notes on FIFOs. */
+
+               con &= ~S3C2412_IISCON_RXDMA_ACTIVE;
+               con |=  S3C2412_IISCON_RXDMA_PAUSE;
+               con |=  S3C2412_IISCON_RXCH_PAUSE;
+
+               switch (mod & S3C2412_IISMOD_MODE_MASK) {
+               case S3C2412_IISMOD_MODE_RXONLY:
+                       con &= ~S3C2412_IISCON_IIS_ACTIVE;
+                       mod &= ~S3C2412_IISMOD_MODE_MASK;
+                       break;
+
+               case S3C2412_IISMOD_MODE_TXRX:
+                       mod &= ~S3C2412_IISMOD_MODE_MASK;
+                       mod |= S3C2412_IISMOD_MODE_TXONLY;
+                       break;
+
+               default:
+                       dev_err(i2s->dev, "RXDIS: Invalid MODE %x in IISMOD\n",
+                               mod & S3C2412_IISMOD_MODE_MASK);
+               }
+
+               writel(con, regs + S3C2412_IISCON);
+               writel(mod, regs + S3C2412_IISMOD);
+       }
+
+       fic = readl(regs + S3C2412_IISFIC);
+       pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
+}
+
+#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
+
+/*
+ * Wait for the LR signal to allow synchronisation to the L/R clock
+ * from the codec. May only be needed for slave mode.
+ */
+static int s3c2412_snd_lrsync(struct s3c_i2sv2_info *i2s)
+{
+       u32 iiscon;
+       unsigned long loops = msecs_to_loops(5);
+
+       pr_debug("Entered %s\n", __func__);
+
+       while (--loops) {
+               iiscon = readl(i2s->regs + S3C2412_IISCON);
+               if (iiscon & S3C2412_IISCON_LRINDEX)
+                       break;
+
+               cpu_relax();
+       }
+
+       if (!loops) {
+               printk(KERN_ERR "%s: timeout\n", __func__);
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+/*
+ * Set S3C2412 I2S DAI format
+ */
+static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
+                              unsigned int fmt)
+{
+       struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+       u32 iismod;
+
+       pr_debug("Entered %s\n", __func__);
+
+       iismod = readl(i2s->regs + S3C2412_IISMOD);
+       pr_debug("hw_params r: IISMOD: %x \n", iismod);
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               i2s->master = 0;
+               iismod |= S3C2412_IISMOD_SLAVE;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               i2s->master = 1;
+               iismod &= ~S3C2412_IISMOD_SLAVE;
+               break;
+       default:
+               pr_err("unknwon master/slave format\n");
+               return -EINVAL;
+       }
+
+       iismod &= ~S3C2412_IISMOD_SDF_MASK;
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_RIGHT_J:
+               iismod |= S3C2412_IISMOD_LR_RLOW;
+               iismod |= S3C2412_IISMOD_SDF_MSB;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iismod |= S3C2412_IISMOD_LR_RLOW;
+               iismod |= S3C2412_IISMOD_SDF_LSB;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               iismod &= ~S3C2412_IISMOD_LR_RLOW;
+               iismod |= S3C2412_IISMOD_SDF_IIS;
+               break;
+       default:
+               pr_err("Unknown data format\n");
+               return -EINVAL;
+       }
+
+       writel(iismod, i2s->regs + S3C2412_IISMOD);
+       pr_debug("hw_params w: IISMOD: %x \n", iismod);
+       return 0;
+}
+
+static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *dai)
+{
+       struct s3c_i2sv2_info *i2s = to_info(dai);
+       struct s3c_dma_params *dma_data;
+       u32 iismod;
+
+       pr_debug("Entered %s\n", __func__);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dma_data = i2s->dma_playback;
+       else
+               dma_data = i2s->dma_capture;
+
+       snd_soc_dai_set_dma_data(dai, substream, dma_data);
+
+       /* Working copies of register */
+       iismod = readl(i2s->regs + S3C2412_IISMOD);
+       pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
+
+       iismod &= ~S3C64XX_IISMOD_BLC_MASK;
+       /* Sample size */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S8:
+               iismod |= S3C64XX_IISMOD_BLC_8BIT;
+               break;
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               iismod |= S3C64XX_IISMOD_BLC_24BIT;
+               break;
+       }
+
+       writel(iismod, i2s->regs + S3C2412_IISMOD);
+       pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
+
+       return 0;
+}
+
+static int s3c_i2sv2_set_sysclk(struct snd_soc_dai *cpu_dai,
+                                 int clk_id, unsigned int freq, int dir)
+{
+       struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+       u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
+
+       pr_debug("Entered %s\n", __func__);
+       pr_debug("%s r: IISMOD: %x\n", __func__, iismod);
+
+       switch (clk_id) {
+       case S3C_I2SV2_CLKSRC_PCLK:
+               iismod &= ~S3C2412_IISMOD_IMS_SYSMUX;
+               break;
+
+       case S3C_I2SV2_CLKSRC_AUDIOBUS:
+               iismod |= S3C2412_IISMOD_IMS_SYSMUX;
+               break;
+
+       case S3C_I2SV2_CLKSRC_CDCLK:
+               /* Error if controller doesn't have the CDCLKCON bit */
+               if (!(i2s->feature & S3C_FEATURE_CDCLKCON))
+                       return -EINVAL;
+
+               switch (dir) {
+               case SND_SOC_CLOCK_IN:
+                       iismod |= S3C64XX_IISMOD_CDCLKCON;
+                       break;
+               case SND_SOC_CLOCK_OUT:
+                       iismod &= ~S3C64XX_IISMOD_CDCLKCON;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       writel(iismod, i2s->regs + S3C2412_IISMOD);
+       pr_debug("%s w: IISMOD: %x\n", __func__, iismod);
+
+       return 0;
+}
+
+static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct s3c_i2sv2_info *i2s = to_info(rtd->cpu_dai);
+       int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+       unsigned long irqs;
+       int ret = 0;
+       struct s3c_dma_params *dma_data =
+               snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+       pr_debug("Entered %s\n", __func__);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               /* On start, ensure that the FIFOs are cleared and reset. */
+
+               writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH,
+                      i2s->regs + S3C2412_IISFIC);
+
+               /* clear again, just in case */
+               writel(0x0, i2s->regs + S3C2412_IISFIC);
+
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (!i2s->master) {
+                       ret = s3c2412_snd_lrsync(i2s);
+                       if (ret)
+                               goto exit_err;
+               }
+
+               local_irq_save(irqs);
+
+               if (capture)
+                       s3c2412_snd_rxctrl(i2s, 1);
+               else
+                       s3c2412_snd_txctrl(i2s, 1);
+
+               local_irq_restore(irqs);
+
+               /*
+                * Load the next buffer to DMA to meet the reqirement
+                * of the auto reload mechanism of S3C24XX.
+                * This call won't bother S3C64XX.
+                */
+               s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
+
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               local_irq_save(irqs);
+
+               if (capture)
+                       s3c2412_snd_rxctrl(i2s, 0);
+               else
+                       s3c2412_snd_txctrl(i2s, 0);
+
+               local_irq_restore(irqs);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+exit_err:
+       return ret;
+}
+
+/*
+ * Set S3C2412 Clock dividers
+ */
+static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
+                                 int div_id, int div)
+{
+       struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+       u32 reg;
+
+       pr_debug("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
+
+       switch (div_id) {
+       case S3C_I2SV2_DIV_BCLK:
+               switch (div) {
+               case 16:
+                       div = S3C2412_IISMOD_BCLK_16FS;
+                       break;
+
+               case 32:
+                       div = S3C2412_IISMOD_BCLK_32FS;
+                       break;
+
+               case 24:
+                       div = S3C2412_IISMOD_BCLK_24FS;
+                       break;
+
+               case 48:
+                       div = S3C2412_IISMOD_BCLK_48FS;
+                       break;
+
+               default:
+                       return -EINVAL;
+               }
+
+               reg = readl(i2s->regs + S3C2412_IISMOD);
+               reg &= ~S3C2412_IISMOD_BCLK_MASK;
+               writel(reg | div, i2s->regs + S3C2412_IISMOD);
+
+               pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
+               break;
+
+       case S3C_I2SV2_DIV_RCLK:
+               switch (div) {
+               case 256:
+                       div = S3C2412_IISMOD_RCLK_256FS;
+                       break;
+
+               case 384:
+                       div = S3C2412_IISMOD_RCLK_384FS;
+                       break;
+
+               case 512:
+                       div = S3C2412_IISMOD_RCLK_512FS;
+                       break;
+
+               case 768:
+                       div = S3C2412_IISMOD_RCLK_768FS;
+                       break;
+
+               default:
+                       return -EINVAL;
+               }
+
+               reg = readl(i2s->regs + S3C2412_IISMOD);
+               reg &= ~S3C2412_IISMOD_RCLK_MASK;
+               writel(reg | div, i2s->regs + S3C2412_IISMOD);
+               pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
+               break;
+
+       case S3C_I2SV2_DIV_PRESCALER:
+               if (div >= 0) {
+                       writel((div << 8) | S3C2412_IISPSR_PSREN,
+                              i2s->regs + S3C2412_IISPSR);
+               } else {
+                       writel(0x0, i2s->regs + S3C2412_IISPSR);
+               }
+               pr_debug("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR));
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static snd_pcm_sframes_t s3c2412_i2s_delay(struct snd_pcm_substream *substream,
+                                          struct snd_soc_dai *dai)
+{
+       struct s3c_i2sv2_info *i2s = to_info(dai);
+       u32 reg = readl(i2s->regs + S3C2412_IISFIC);
+       snd_pcm_sframes_t delay;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               delay = S3C2412_IISFIC_TXCOUNT(reg);
+       else
+               delay = S3C2412_IISFIC_RXCOUNT(reg);
+
+       return delay;
+}
+
+struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai)
+{
+       struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+       u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
+
+       if (iismod & S3C2412_IISMOD_IMS_SYSMUX)
+               return i2s->iis_cclk;
+       else
+               return i2s->iis_pclk;
+}
+EXPORT_SYMBOL_GPL(s3c_i2sv2_get_clock);
+
+/* default table of all avaialable root fs divisors */
+static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 };
+
+int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
+                           unsigned int *fstab,
+                           unsigned int rate, struct clk *clk)
+{
+       unsigned long clkrate = clk_get_rate(clk);
+       unsigned int div;
+       unsigned int fsclk;
+       unsigned int actual;
+       unsigned int fs;
+       unsigned int fsdiv;
+       signed int deviation = 0;
+       unsigned int best_fs = 0;
+       unsigned int best_div = 0;
+       unsigned int best_rate = 0;
+       unsigned int best_deviation = INT_MAX;
+
+       pr_debug("Input clock rate %ldHz\n", clkrate);
+
+       if (fstab == NULL)
+               fstab = iis_fs_tab;
+
+       for (fs = 0; fs < ARRAY_SIZE(iis_fs_tab); fs++) {
+               fsdiv = iis_fs_tab[fs];
+
+               fsclk = clkrate / fsdiv;
+               div = fsclk / rate;
+
+               if ((fsclk % rate) > (rate / 2))
+                       div++;
+
+               if (div <= 1)
+                       continue;
+
+               actual = clkrate / (fsdiv * div);
+               deviation = actual - rate;
+
+               printk(KERN_DEBUG "%ufs: div %u => result %u, deviation %d\n",
+                      fsdiv, div, actual, deviation);
+
+               deviation = abs(deviation);
+
+               if (deviation < best_deviation) {
+                       best_fs = fsdiv;
+                       best_div = div;
+                       best_rate = actual;
+                       best_deviation = deviation;
+               }
+
+               if (deviation == 0)
+                       break;
+       }
+
+       printk(KERN_DEBUG "best: fs=%u, div=%u, rate=%u\n",
+              best_fs, best_div, best_rate);
+
+       info->fs_div = best_fs;
+       info->clk_div = best_div;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(s3c_i2sv2_iis_calc_rate);
+
+int s3c_i2sv2_probe(struct snd_soc_dai *dai,
+                   struct s3c_i2sv2_info *i2s,
+                   unsigned long base)
+{
+       struct device *dev = dai->dev;
+       unsigned int iismod;
+
+       i2s->dev = dev;
+
+       /* record our i2s structure for later use in the callbacks */
+       snd_soc_dai_set_drvdata(dai, i2s);
+
+       i2s->regs = ioremap(base, 0x100);
+       if (i2s->regs == NULL) {
+               dev_err(dev, "cannot ioremap registers\n");
+               return -ENXIO;
+       }
+
+       i2s->iis_pclk = clk_get(dev, "iis");
+       if (IS_ERR(i2s->iis_pclk)) {
+               dev_err(dev, "failed to get iis_clock\n");
+               iounmap(i2s->regs);
+               return -ENOENT;
+       }
+
+       clk_enable(i2s->iis_pclk);
+
+       /* Mark ourselves as in TXRX mode so we can run through our cleanup
+        * process without warnings. */
+       iismod = readl(i2s->regs + S3C2412_IISMOD);
+       iismod |= S3C2412_IISMOD_MODE_TXRX;
+       writel(iismod, i2s->regs + S3C2412_IISMOD);
+       s3c2412_snd_txctrl(i2s, 0);
+       s3c2412_snd_rxctrl(i2s, 0);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(s3c_i2sv2_probe);
+
+#ifdef CONFIG_PM
+static int s3c2412_i2s_suspend(struct snd_soc_dai *dai)
+{
+       struct s3c_i2sv2_info *i2s = to_info(dai);
+       u32 iismod;
+
+       if (dai->active) {
+               i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD);
+               i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON);
+               i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR);
+
+               /* some basic suspend checks */
+
+               iismod = readl(i2s->regs + S3C2412_IISMOD);
+
+               if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
+                       pr_warning("%s: RXDMA active?\n", __func__);
+
+               if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
+                       pr_warning("%s: TXDMA active?\n", __func__);
+
+               if (iismod & S3C2412_IISCON_IIS_ACTIVE)
+                       pr_warning("%s: IIS active\n", __func__);
+       }
+
+       return 0;
+}
+
+static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
+{
+       struct s3c_i2sv2_info *i2s = to_info(dai);
+
+       pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n",
+               dai->active, i2s->suspend_iismod, i2s->suspend_iiscon);
+
+       if (dai->active) {
+               writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
+               writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD);
+               writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR);
+
+               writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH,
+                      i2s->regs + S3C2412_IISFIC);
+
+               ndelay(250);
+               writel(0x0, i2s->regs + S3C2412_IISFIC);
+       }
+
+       return 0;
+}
+#else
+#define s3c2412_i2s_suspend NULL
+#define s3c2412_i2s_resume  NULL
+#endif
+
+int s3c_i2sv2_register_dai(struct device *dev, int id,
+               struct snd_soc_dai_driver *drv)
+{
+       struct snd_soc_dai_ops *ops = drv->ops;
+
+       ops->trigger = s3c2412_i2s_trigger;
+       if (!ops->hw_params)
+               ops->hw_params = s3c_i2sv2_hw_params;
+       ops->set_fmt = s3c2412_i2s_set_fmt;
+       ops->set_clkdiv = s3c2412_i2s_set_clkdiv;
+       ops->set_sysclk = s3c_i2sv2_set_sysclk;
+
+       /* Allow overriding by (for example) IISv4 */
+       if (!ops->delay)
+               ops->delay = s3c2412_i2s_delay;
+
+       drv->suspend = s3c2412_i2s_suspend;
+       drv->resume = s3c2412_i2s_resume;
+
+       return snd_soc_register_dai(dev, drv);
+}
+EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai);
+
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/s3c-i2s-v2.h b/sound/soc/samsung/s3c-i2s-v2.h
new file mode 100644 (file)
index 0000000..f8297d9
--- /dev/null
@@ -0,0 +1,106 @@
+/* sound/soc/samsung/s3c-i2s-v2.h
+ *
+ * ALSA Soc Audio Layer - S3C_I2SV2 I2S driver
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ *  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 code is the core support for the I2S block found in a number of
+ * Samsung SoC devices which is unofficially named I2S-V2. Currently the
+ * S3C2412 and the S3C64XX series use this block to provide 1 or 2 I2S
+ * channels via configurable GPIO.
+ */
+
+#ifndef __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H
+#define __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H __FILE__
+
+#define S3C_I2SV2_DIV_BCLK     (1)
+#define S3C_I2SV2_DIV_RCLK     (2)
+#define S3C_I2SV2_DIV_PRESCALER        (3)
+
+#define S3C_I2SV2_CLKSRC_PCLK          0
+#define S3C_I2SV2_CLKSRC_AUDIOBUS      1
+#define S3C_I2SV2_CLKSRC_CDCLK         2
+
+/* Set this flag for I2S controllers that have the bit IISMOD[12]
+ * bridge/break RCLK signal and external Xi2sCDCLK pin.
+ */
+#define S3C_FEATURE_CDCLKCON   (1 << 0)
+
+/**
+ * struct s3c_i2sv2_info - S3C I2S-V2 information
+ * @dev: The parent device passed to use from the probe.
+ * @regs: The pointer to the device registe block.
+ * @feature: Set of bit-flags indicating features of the controller.
+ * @master: True if the I2S core is the I2S bit clock master.
+ * @dma_playback: DMA information for playback channel.
+ * @dma_capture: DMA information for capture channel.
+ * @suspend_iismod: PM save for the IISMOD register.
+ * @suspend_iiscon: PM save for the IISCON register.
+ * @suspend_iispsr: PM save for the IISPSR register.
+ *
+ * This is the private codec state for the hardware associated with an
+ * I2S channel such as the register mappings and clock sources.
+ */
+struct s3c_i2sv2_info {
+       struct device   *dev;
+       void __iomem    *regs;
+
+       u32             feature;
+
+       struct clk      *iis_pclk;
+       struct clk      *iis_cclk;
+
+       unsigned char    master;
+
+       struct s3c_dma_params   *dma_playback;
+       struct s3c_dma_params   *dma_capture;
+
+       u32              suspend_iismod;
+       u32              suspend_iiscon;
+       u32              suspend_iispsr;
+
+       unsigned long   base;
+};
+
+extern struct clk *s3c_i2sv2_get_clock(struct snd_soc_dai *cpu_dai);
+
+struct s3c_i2sv2_rate_calc {
+       unsigned int    clk_div;        /* for prescaler */
+       unsigned int    fs_div;         /* for root frame clock */
+};
+
+extern int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
+                                  unsigned int *fstab,
+                                  unsigned int rate, struct clk *clk);
+
+/**
+ * s3c_i2sv2_probe - probe for i2s device helper
+ * @dai: The ASoC DAI structure supplied to the original probe.
+ * @i2s: Our local i2s structure to fill in.
+ * @base: The base address for the registers.
+ */
+extern int s3c_i2sv2_probe(struct snd_soc_dai *dai,
+                          struct s3c_i2sv2_info *i2s,
+                          unsigned long base);
+
+/**
+ * s3c_i2sv2_register_dai - register dai with soc core
+ * @dev: DAI device
+ * @id: DAI ID
+ * @drv: The driver structure to register
+ *
+ * Fill in any missing fields and then register the given dai with the
+ * soc core.
+ */
+extern int s3c_i2sv2_register_dai(struct device *dev, int id,
+               struct snd_soc_dai_driver *drv);
+
+#endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */
diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c
new file mode 100644 (file)
index 0000000..7ea8378
--- /dev/null
@@ -0,0 +1,212 @@
+/* sound/soc/samsung/s3c2412-i2s.c
+ *
+ * ALSA Soc Audio Layer - S3C2412 I2S driver
+ *
+ * Copyright (c) 2006 Wolfson Microelectronics PLC.
+ *     Graeme Gregory graeme.gregory@wolfsonmicro.com
+ *     linux@wolfsonmicro.com
+ *
+ * Copyright (c) 2007, 2004-2005 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <mach/hardware.h>
+
+#include <mach/regs-gpio.h>
+#include <mach/dma.h>
+
+#include "dma.h"
+#include "regs-i2s-v2.h"
+#include "s3c2412-i2s.h"
+
+#define S3C2412_I2S_DEBUG 0
+
+static struct s3c2410_dma_client s3c2412_dma_client_out = {
+       .name           = "I2S PCM Stereo out"
+};
+
+static struct s3c2410_dma_client s3c2412_dma_client_in = {
+       .name           = "I2S PCM Stereo in"
+};
+
+static struct s3c_dma_params s3c2412_i2s_pcm_stereo_out = {
+       .client         = &s3c2412_dma_client_out,
+       .channel        = DMACH_I2S_OUT,
+       .dma_addr       = S3C2410_PA_IIS + S3C2412_IISTXD,
+       .dma_size       = 4,
+};
+
+static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = {
+       .client         = &s3c2412_dma_client_in,
+       .channel        = DMACH_I2S_IN,
+       .dma_addr       = S3C2410_PA_IIS + S3C2412_IISRXD,
+       .dma_size       = 4,
+};
+
+static struct s3c_i2sv2_info s3c2412_i2s;
+
+static int s3c2412_i2s_probe(struct snd_soc_dai *dai)
+{
+       int ret;
+
+       pr_debug("Entered %s\n", __func__);
+
+       ret = s3c_i2sv2_probe(dai, &s3c2412_i2s, S3C2410_PA_IIS);
+       if (ret)
+               return ret;
+
+       s3c2412_i2s.dma_capture = &s3c2412_i2s_pcm_stereo_in;
+       s3c2412_i2s.dma_playback = &s3c2412_i2s_pcm_stereo_out;
+
+       s3c2412_i2s.iis_cclk = clk_get(dai->dev, "i2sclk");
+       if (s3c2412_i2s.iis_cclk == NULL) {
+               pr_err("failed to get i2sclk clock\n");
+               iounmap(s3c2412_i2s.regs);
+               return -ENODEV;
+       }
+
+       /* Set MPLL as the source for IIS CLK */
+
+       clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll"));
+       clk_enable(s3c2412_i2s.iis_cclk);
+
+       s3c2412_i2s.iis_cclk = s3c2412_i2s.iis_pclk;
+
+       /* Configure the I2S pins in correct mode */
+       s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK);
+       s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK);
+       s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK);
+       s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);
+       s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);
+
+       return 0;
+}
+
+static int s3c2412_i2s_remove(struct snd_soc_dai *dai)
+{
+       clk_disable(s3c2412_i2s.iis_cclk);
+       clk_put(s3c2412_i2s.iis_cclk);
+       iounmap(s3c2412_i2s.regs);
+
+       return 0;
+}
+
+static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *cpu_dai)
+{
+       struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(cpu_dai);
+       struct s3c_dma_params *dma_data;
+       u32 iismod;
+
+       pr_debug("Entered %s\n", __func__);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dma_data = i2s->dma_playback;
+       else
+               dma_data = i2s->dma_capture;
+
+       snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
+
+       iismod = readl(i2s->regs + S3C2412_IISMOD);
+       pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S8:
+               iismod |= S3C2412_IISMOD_8BIT;
+               break;
+       case SNDRV_PCM_FORMAT_S16_LE:
+               iismod &= ~S3C2412_IISMOD_8BIT;
+               break;
+       }
+
+       writel(iismod, i2s->regs + S3C2412_IISMOD);
+       pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
+
+       return 0;
+}
+
+#define S3C2412_I2S_RATES \
+       (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
+       SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+       SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+static struct snd_soc_dai_ops s3c2412_i2s_dai_ops = {
+       .hw_params      = s3c2412_i2s_hw_params,
+};
+
+static struct snd_soc_dai_driver s3c2412_i2s_dai = {
+       .probe          = s3c2412_i2s_probe,
+       .remove = s3c2412_i2s_remove,
+       .playback = {
+               .channels_min   = 2,
+               .channels_max   = 2,
+               .rates          = S3C2412_I2S_RATES,
+               .formats        = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .channels_min   = 2,
+               .channels_max   = 2,
+               .rates          = S3C2412_I2S_RATES,
+               .formats        = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .ops = &s3c2412_i2s_dai_ops,
+};
+
+static __devinit int s3c2412_iis_dev_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_dai(&pdev->dev, &s3c2412_i2s_dai);
+}
+
+static __devexit int s3c2412_iis_dev_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver s3c2412_iis_driver = {
+       .probe  = s3c2412_iis_dev_probe,
+       .remove = s3c2412_iis_dev_remove,
+       .driver = {
+               .name = "s3c2412-iis",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init s3c2412_i2s_init(void)
+{
+       return platform_driver_register(&s3c2412_iis_driver);
+}
+module_init(s3c2412_i2s_init);
+
+static void __exit s3c2412_i2s_exit(void)
+{
+       platform_driver_unregister(&s3c2412_iis_driver);
+}
+module_exit(s3c2412_i2s_exit);
+
+/* Module information */
+MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("S3C2412 I2S SoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c2412-iis");
diff --git a/sound/soc/samsung/s3c2412-i2s.h b/sound/soc/samsung/s3c2412-i2s.h
new file mode 100644 (file)
index 0000000..02ad579
--- /dev/null
@@ -0,0 +1,27 @@
+/* sound/soc/samsung/s3c2412-i2s.c
+ *
+ * ALSA Soc Audio Layer - S3C2412 I2S driver
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ *  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 __SND_SOC_S3C24XX_S3C2412_I2S_H
+#define __SND_SOC_S3C24XX_S3C2412_I2S_H __FILE__
+
+#include "s3c-i2s-v2.h"
+
+#define S3C2412_DIV_BCLK       S3C_I2SV2_DIV_BCLK
+#define S3C2412_DIV_RCLK       S3C_I2SV2_DIV_RCLK
+#define S3C2412_DIV_PRESCALER  S3C_I2SV2_DIV_PRESCALER
+
+#define S3C2412_CLKSRC_PCLK    S3C_I2SV2_CLKSRC_PCLK
+#define S3C2412_CLKSRC_I2SCLK  S3C_I2SV2_CLKSRC_AUDIOBUS
+
+#endif /* __SND_SOC_S3C24XX_S3C2412_I2S_H */
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c
new file mode 100644 (file)
index 0000000..13e41ed
--- /dev/null
@@ -0,0 +1,519 @@
+/*
+ * s3c24xx-i2s.c  --  ALSA Soc Audio Layer
+ *
+ * (c) 2006 Wolfson Microelectronics PLC.
+ * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ * Copyright 2004-2005 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ *  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/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/jiffies.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+
+#include <asm/dma.h>
+#include <mach/dma.h>
+
+#include <plat/regs-iis.h>
+
+#include "dma.h"
+#include "s3c24xx-i2s.h"
+
+static struct s3c2410_dma_client s3c24xx_dma_client_out = {
+       .name = "I2S PCM Stereo out"
+};
+
+static struct s3c2410_dma_client s3c24xx_dma_client_in = {
+       .name = "I2S PCM Stereo in"
+};
+
+static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_out = {
+       .client         = &s3c24xx_dma_client_out,
+       .channel        = DMACH_I2S_OUT,
+       .dma_addr       = S3C2410_PA_IIS + S3C2410_IISFIFO,
+       .dma_size       = 2,
+};
+
+static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_in = {
+       .client         = &s3c24xx_dma_client_in,
+       .channel        = DMACH_I2S_IN,
+       .dma_addr       = S3C2410_PA_IIS + S3C2410_IISFIFO,
+       .dma_size       = 2,
+};
+
+struct s3c24xx_i2s_info {
+       void __iomem    *regs;
+       struct clk      *iis_clk;
+       u32             iiscon;
+       u32             iismod;
+       u32             iisfcon;
+       u32             iispsr;
+};
+static struct s3c24xx_i2s_info s3c24xx_i2s;
+
+static void s3c24xx_snd_txctrl(int on)
+{
+       u32 iisfcon;
+       u32 iiscon;
+       u32 iismod;
+
+       pr_debug("Entered %s\n", __func__);
+
+       iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
+       iiscon  = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
+       iismod  = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
+
+       pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
+
+       if (on) {
+               iisfcon |= S3C2410_IISFCON_TXDMA | S3C2410_IISFCON_TXENABLE;
+               iiscon  |= S3C2410_IISCON_TXDMAEN | S3C2410_IISCON_IISEN;
+               iiscon  &= ~S3C2410_IISCON_TXIDLE;
+               iismod  |= S3C2410_IISMOD_TXMODE;
+
+               writel(iismod,  s3c24xx_i2s.regs + S3C2410_IISMOD);
+               writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
+               writel(iiscon,  s3c24xx_i2s.regs + S3C2410_IISCON);
+       } else {
+               /* note, we have to disable the FIFOs otherwise bad things
+                * seem to happen when the DMA stops. According to the
+                * Samsung supplied kernel, this should allow the DMA
+                * engine and FIFOs to reset. If this isn't allowed, the
+                * DMA engine will simply freeze randomly.
+                */
+
+               iisfcon &= ~S3C2410_IISFCON_TXENABLE;
+               iisfcon &= ~S3C2410_IISFCON_TXDMA;
+               iiscon  |=  S3C2410_IISCON_TXIDLE;
+               iiscon  &= ~S3C2410_IISCON_TXDMAEN;
+               iismod  &= ~S3C2410_IISMOD_TXMODE;
+
+               writel(iiscon,  s3c24xx_i2s.regs + S3C2410_IISCON);
+               writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
+               writel(iismod,  s3c24xx_i2s.regs + S3C2410_IISMOD);
+       }
+
+       pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
+}
+
+static void s3c24xx_snd_rxctrl(int on)
+{
+       u32 iisfcon;
+       u32 iiscon;
+       u32 iismod;
+
+       pr_debug("Entered %s\n", __func__);
+
+       iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
+       iiscon  = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
+       iismod  = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
+
+       pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
+
+       if (on) {
+               iisfcon |= S3C2410_IISFCON_RXDMA | S3C2410_IISFCON_RXENABLE;
+               iiscon  |= S3C2410_IISCON_RXDMAEN | S3C2410_IISCON_IISEN;
+               iiscon  &= ~S3C2410_IISCON_RXIDLE;
+               iismod  |= S3C2410_IISMOD_RXMODE;
+
+               writel(iismod,  s3c24xx_i2s.regs + S3C2410_IISMOD);
+               writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
+               writel(iiscon,  s3c24xx_i2s.regs + S3C2410_IISCON);
+       } else {
+               /* note, we have to disable the FIFOs otherwise bad things
+                * seem to happen when the DMA stops. According to the
+                * Samsung supplied kernel, this should allow the DMA
+                * engine and FIFOs to reset. If this isn't allowed, the
+                * DMA engine will simply freeze randomly.
+                */
+
+               iisfcon &= ~S3C2410_IISFCON_RXENABLE;
+               iisfcon &= ~S3C2410_IISFCON_RXDMA;
+               iiscon  |= S3C2410_IISCON_RXIDLE;
+               iiscon  &= ~S3C2410_IISCON_RXDMAEN;
+               iismod  &= ~S3C2410_IISMOD_RXMODE;
+
+               writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
+               writel(iiscon,  s3c24xx_i2s.regs + S3C2410_IISCON);
+               writel(iismod,  s3c24xx_i2s.regs + S3C2410_IISMOD);
+       }
+
+       pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
+}
+
+/*
+ * Wait for the LR signal to allow synchronisation to the L/R clock
+ * from the codec. May only be needed for slave mode.
+ */
+static int s3c24xx_snd_lrsync(void)
+{
+       u32 iiscon;
+       int timeout = 50; /* 5ms */
+
+       pr_debug("Entered %s\n", __func__);
+
+       while (1) {
+               iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
+               if (iiscon & S3C2410_IISCON_LRINDEX)
+                       break;
+
+               if (!timeout--)
+                       return -ETIMEDOUT;
+               udelay(100);
+       }
+
+       return 0;
+}
+
+/*
+ * Check whether CPU is the master or slave
+ */
+static inline int s3c24xx_snd_is_clkmaster(void)
+{
+       pr_debug("Entered %s\n", __func__);
+
+       return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1;
+}
+
+/*
+ * Set S3C24xx I2S DAI format
+ */
+static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
+               unsigned int fmt)
+{
+       u32 iismod;
+
+       pr_debug("Entered %s\n", __func__);
+
+       iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
+       pr_debug("hw_params r: IISMOD: %x \n", iismod);
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               iismod |= S3C2410_IISMOD_SLAVE;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               iismod &= ~S3C2410_IISMOD_SLAVE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_LEFT_J:
+               iismod |= S3C2410_IISMOD_MSB;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               iismod &= ~S3C2410_IISMOD_MSB;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
+       pr_debug("hw_params w: IISMOD: %x \n", iismod);
+       return 0;
+}
+
+static int s3c24xx_i2s_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 s3c_dma_params *dma_data;
+       u32 iismod;
+
+       pr_debug("Entered %s\n", __func__);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dma_data = &s3c24xx_i2s_pcm_stereo_out;
+       else
+               dma_data = &s3c24xx_i2s_pcm_stereo_in;
+
+       snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
+
+       /* Working copies of register */
+       iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
+       pr_debug("hw_params r: IISMOD: %x\n", iismod);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S8:
+               iismod &= ~S3C2410_IISMOD_16BIT;
+               dma_data->dma_size = 1;
+               break;
+       case SNDRV_PCM_FORMAT_S16_LE:
+               iismod |= S3C2410_IISMOD_16BIT;
+               dma_data->dma_size = 2;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
+       pr_debug("hw_params w: IISMOD: %x\n", iismod);
+       return 0;
+}
+
+static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+                              struct snd_soc_dai *dai)
+{
+       int ret = 0;
+       struct s3c_dma_params *dma_data =
+               snd_soc_dai_get_dma_data(dai, substream);
+
+       pr_debug("Entered %s\n", __func__);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (!s3c24xx_snd_is_clkmaster()) {
+                       ret = s3c24xx_snd_lrsync();
+                       if (ret)
+                               goto exit_err;
+               }
+
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+                       s3c24xx_snd_rxctrl(1);
+               else
+                       s3c24xx_snd_txctrl(1);
+
+               s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+                       s3c24xx_snd_rxctrl(0);
+               else
+                       s3c24xx_snd_txctrl(0);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+exit_err:
+       return ret;
+}
+
+/*
+ * Set S3C24xx Clock source
+ */
+static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
+       int clk_id, unsigned int freq, int dir)
+{
+       u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
+
+       pr_debug("Entered %s\n", __func__);
+
+       iismod &= ~S3C2440_IISMOD_MPLL;
+
+       switch (clk_id) {
+       case S3C24XX_CLKSRC_PCLK:
+               break;
+       case S3C24XX_CLKSRC_MPLL:
+               iismod |= S3C2440_IISMOD_MPLL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
+       return 0;
+}
+
+/*
+ * Set S3C24xx Clock dividers
+ */
+static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
+       int div_id, int div)
+{
+       u32 reg;
+
+       pr_debug("Entered %s\n", __func__);
+
+       switch (div_id) {
+       case S3C24XX_DIV_BCLK:
+               reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~S3C2410_IISMOD_FS_MASK;
+               writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
+               break;
+       case S3C24XX_DIV_MCLK:
+               reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~(S3C2410_IISMOD_384FS);
+               writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
+               break;
+       case S3C24XX_DIV_PRESCALER:
+               writel(div, s3c24xx_i2s.regs + S3C2410_IISPSR);
+               reg = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
+               writel(reg | S3C2410_IISCON_PSCEN, s3c24xx_i2s.regs + S3C2410_IISCON);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * To avoid duplicating clock code, allow machine driver to
+ * get the clockrate from here.
+ */
+u32 s3c24xx_i2s_get_clockrate(void)
+{
+       return clk_get_rate(s3c24xx_i2s.iis_clk);
+}
+EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
+
+static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
+{
+       pr_debug("Entered %s\n", __func__);
+
+       s3c24xx_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100);
+       if (s3c24xx_i2s.regs == NULL)
+               return -ENXIO;
+
+       s3c24xx_i2s.iis_clk = clk_get(dai->dev, "iis");
+       if (s3c24xx_i2s.iis_clk == NULL) {
+               pr_err("failed to get iis_clock\n");
+               iounmap(s3c24xx_i2s.regs);
+               return -ENODEV;
+       }
+       clk_enable(s3c24xx_i2s.iis_clk);
+
+       /* Configure the I2S pins in correct mode */
+       s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK);
+       s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK);
+       s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK);
+       s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);
+       s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);
+
+       writel(S3C2410_IISCON_IISEN, s3c24xx_i2s.regs + S3C2410_IISCON);
+
+       s3c24xx_snd_txctrl(0);
+       s3c24xx_snd_rxctrl(0);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)
+{
+       pr_debug("Entered %s\n", __func__);
+
+       s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
+       s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
+       s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
+       s3c24xx_i2s.iispsr = readl(s3c24xx_i2s.regs + S3C2410_IISPSR);
+
+       clk_disable(s3c24xx_i2s.iis_clk);
+
+       return 0;
+}
+
+static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)
+{
+       pr_debug("Entered %s\n", __func__);
+       clk_enable(s3c24xx_i2s.iis_clk);
+
+       writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
+       writel(s3c24xx_i2s.iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
+       writel(s3c24xx_i2s.iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
+       writel(s3c24xx_i2s.iispsr, s3c24xx_i2s.regs + S3C2410_IISPSR);
+
+       return 0;
+}
+#else
+#define s3c24xx_i2s_suspend NULL
+#define s3c24xx_i2s_resume NULL
+#endif
+
+
+#define S3C24XX_I2S_RATES \
+       (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
+       SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+       SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+static struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = {
+       .trigger        = s3c24xx_i2s_trigger,
+       .hw_params      = s3c24xx_i2s_hw_params,
+       .set_fmt        = s3c24xx_i2s_set_fmt,
+       .set_clkdiv     = s3c24xx_i2s_set_clkdiv,
+       .set_sysclk     = s3c24xx_i2s_set_sysclk,
+};
+
+static struct snd_soc_dai_driver s3c24xx_i2s_dai = {
+       .probe = s3c24xx_i2s_probe,
+       .suspend = s3c24xx_i2s_suspend,
+       .resume = s3c24xx_i2s_resume,
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = S3C24XX_I2S_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = S3C24XX_I2S_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
+       .ops = &s3c24xx_i2s_dai_ops,
+};
+
+static __devinit int s3c24xx_iis_dev_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai);
+}
+
+static __devexit int s3c24xx_iis_dev_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver s3c24xx_iis_driver = {
+       .probe  = s3c24xx_iis_dev_probe,
+       .remove = s3c24xx_iis_dev_remove,
+       .driver = {
+               .name = "s3c24xx-iis",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init s3c24xx_i2s_init(void)
+{
+       return platform_driver_register(&s3c24xx_iis_driver);
+}
+module_init(s3c24xx_i2s_init);
+
+static void __exit s3c24xx_i2s_exit(void)
+{
+       platform_driver_unregister(&s3c24xx_iis_driver);
+}
+module_exit(s3c24xx_i2s_exit);
+
+/* Module information */
+MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("s3c24xx I2S SoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c24xx-iis");
diff --git a/sound/soc/samsung/s3c24xx-i2s.h b/sound/soc/samsung/s3c24xx-i2s.h
new file mode 100644 (file)
index 0000000..f9ca04e
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * s3c24xx-i2s.c  --  ALSA Soc Audio Layer
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  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.
+ *
+ *  Revision history
+ *    10th Nov 2006   Initial version.
+ */
+
+#ifndef S3C24XXI2S_H_
+#define S3C24XXI2S_H_
+
+/* clock sources */
+#define S3C24XX_CLKSRC_PCLK 0
+#define S3C24XX_CLKSRC_MPLL 1
+
+/* Clock dividers */
+#define S3C24XX_DIV_MCLK       0
+#define S3C24XX_DIV_BCLK       1
+#define S3C24XX_DIV_PRESCALER  2
+
+/* prescaler */
+#define S3C24XX_PRESCALE(a,b) \
+       (((a - 1) << S3C2410_IISPSR_INTSHIFT) | ((b - 1) << S3C2410_IISPSR_EXTSHFIT))
+
+u32 s3c24xx_i2s_get_clockrate(void);
+
+#endif /*S3C24XXI2S_H_*/
diff --git a/sound/soc/samsung/s3c24xx_simtec.c b/sound/soc/samsung/s3c24xx_simtec.c
new file mode 100644 (file)
index 0000000..a434032
--- /dev/null
@@ -0,0 +1,394 @@
+/* sound/soc/samsung/s3c24xx_simtec.c
+ *
+ * Copyright 2009 Simtec Electronics
+ *
+ * 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/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <plat/audio-simtec.h>
+
+#include "dma.h"
+#include "s3c24xx-i2s.h"
+#include "s3c24xx_simtec.h"
+
+static struct s3c24xx_audio_simtec_pdata *pdata;
+static struct clk *xtal_clk;
+
+static int spk_gain;
+static int spk_unmute;
+
+/**
+ * speaker_gain_get - read the speaker gain setting.
+ * @kcontrol: The control for the speaker gain.
+ * @ucontrol: The value that needs to be updated.
+ *
+ * Read the value for the AMP gain control.
+ */
+static int speaker_gain_get(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = spk_gain;
+       return 0;
+}
+
+/**
+ * speaker_gain_set - set the value of the speaker amp gain
+ * @value: The value to write.
+ */
+static void speaker_gain_set(int value)
+{
+       gpio_set_value_cansleep(pdata->amp_gain[0], value & 1);
+       gpio_set_value_cansleep(pdata->amp_gain[1], value >> 1);
+}
+
+/**
+ * speaker_gain_put - set the speaker gain setting.
+ * @kcontrol: The control for the speaker gain.
+ * @ucontrol: The value that needs to be set.
+ *
+ * Set the value of the speaker gain from the specified
+ * @ucontrol setting.
+ *
+ * Note, if the speaker amp is muted, then we do not set a gain value
+ * as at-least one of the ICs that is fitted will try and power up even
+ * if the main control is set to off.
+ */
+static int speaker_gain_put(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       int value = ucontrol->value.integer.value[0];
+
+       spk_gain = value;
+
+       if (!spk_unmute)
+               speaker_gain_set(value);
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new amp_gain_controls[] = {
+       SOC_SINGLE_EXT("Speaker Gain", 0, 0, 3, 0,
+                      speaker_gain_get, speaker_gain_put),
+};
+
+/**
+ * spk_unmute_state - set the unmute state of the speaker
+ * @to: zero to unmute, non-zero to ununmute.
+ */
+static void spk_unmute_state(int to)
+{
+       pr_debug("%s: to=%d\n", __func__, to);
+
+       spk_unmute = to;
+       gpio_set_value(pdata->amp_gpio, to);
+
+       /* if we're umuting, also re-set the gain */
+       if (to && pdata->amp_gain[0] > 0)
+               speaker_gain_set(spk_gain);
+}
+
+/**
+ * speaker_unmute_get - read the speaker unmute setting.
+ * @kcontrol: The control for the speaker gain.
+ * @ucontrol: The value that needs to be updated.
+ *
+ * Read the value for the AMP gain control.
+ */
+static int speaker_unmute_get(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = spk_unmute;
+       return 0;
+}
+
+/**
+ * speaker_unmute_put - set the speaker unmute setting.
+ * @kcontrol: The control for the speaker gain.
+ * @ucontrol: The value that needs to be set.
+ *
+ * Set the value of the speaker gain from the specified
+ * @ucontrol setting.
+ */
+static int speaker_unmute_put(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       spk_unmute_state(ucontrol->value.integer.value[0]);
+       return 0;
+}
+
+/* This is added as a manual control as the speaker amps create clicks
+ * when their power state is changed, which are far more noticeable than
+ * anything produced by the CODEC itself.
+ */
+static const struct snd_kcontrol_new amp_unmute_controls[] = {
+       SOC_SINGLE_EXT("Speaker Switch", 0, 0, 1, 0,
+                      speaker_unmute_get, speaker_unmute_put),
+};
+
+void simtec_audio_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+
+       if (pdata->amp_gpio > 0) {
+               pr_debug("%s: adding amp routes\n", __func__);
+
+               snd_soc_add_controls(codec, amp_unmute_controls,
+                                    ARRAY_SIZE(amp_unmute_controls));
+       }
+
+       if (pdata->amp_gain[0] > 0) {
+               pr_debug("%s: adding amp controls\n", __func__);
+               snd_soc_add_controls(codec, amp_gain_controls,
+                                    ARRAY_SIZE(amp_gain_controls));
+       }
+}
+EXPORT_SYMBOL_GPL(simtec_audio_init);
+
+#define CODEC_CLOCK 12000000
+
+/**
+ * simtec_hw_params - update hardware parameters
+ * @substream: The audio substream instance.
+ * @params: The parameters requested.
+ *
+ * Update the codec data routing and configuration  settings
+ * from the supplied data.
+ */
+static int simtec_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       int ret;
+
+       /* Set the CODEC as the bus clock master, I2S */
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+                                 SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBM_CFM);
+       if (ret) {
+               pr_err("%s: failed set cpu dai format\n", __func__);
+               return ret;
+       }
+
+       /* Set the CODEC as the bus clock master */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+                                 SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBM_CFM);
+       if (ret) {
+               pr_err("%s: failed set codec dai format\n", __func__);
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0,
+                                    CODEC_CLOCK, SND_SOC_CLOCK_IN);
+       if (ret) {
+               pr_err( "%s: failed setting codec sysclk\n", __func__);
+               return ret;
+       }
+
+       if (pdata->use_mpllin) {
+               ret = snd_soc_dai_set_sysclk(cpu_dai, S3C24XX_CLKSRC_MPLL,
+                                            0, SND_SOC_CLOCK_OUT);
+
+               if (ret) {
+                       pr_err("%s: failed to set MPLLin as clksrc\n",
+                              __func__);
+                       return ret;
+               }
+       }
+
+       if (pdata->output_cdclk) {
+               int cdclk_scale;
+
+               cdclk_scale = clk_get_rate(xtal_clk) / CODEC_CLOCK;
+               cdclk_scale--;
+
+               ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+                                            cdclk_scale);
+       }
+
+       return 0;
+}
+
+static int simtec_call_startup(struct s3c24xx_audio_simtec_pdata *pd)
+{
+       /* call any board supplied startup code, this currently only
+        * covers the bast/vr1000 which have a CPLD in the way of the
+        * LRCLK */
+       if (pd->startup)
+               pd->startup();
+
+       return 0;
+}
+
+static struct snd_soc_ops simtec_snd_ops = {
+       .hw_params      = simtec_hw_params,
+};
+
+/**
+ * attach_gpio_amp - get and configure the necessary gpios
+ * @dev: The device we're probing.
+ * @pd: The platform data supplied by the board.
+ *
+ * If there is a GPIO based amplifier attached to the board, claim
+ * the necessary GPIO lines for it, and set default values.
+ */
+static int attach_gpio_amp(struct device *dev,
+                          struct s3c24xx_audio_simtec_pdata *pd)
+{
+       int ret;
+
+       /* attach gpio amp gain (if any) */
+       if (pdata->amp_gain[0] > 0) {
+               ret = gpio_request(pd->amp_gain[0], "gpio-amp-gain0");
+               if (ret) {
+                       dev_err(dev, "cannot get amp gpio gain0\n");
+                       return ret;
+               }
+
+               ret = gpio_request(pd->amp_gain[1], "gpio-amp-gain1");
+               if (ret) {
+                       dev_err(dev, "cannot get amp gpio gain1\n");
+                       gpio_free(pdata->amp_gain[0]);
+                       return ret;
+               }
+
+               gpio_direction_output(pd->amp_gain[0], 0);
+               gpio_direction_output(pd->amp_gain[1], 0);
+       }
+
+       /* note, currently we assume GPA0 isn't valid amp */
+       if (pdata->amp_gpio > 0) {
+               ret = gpio_request(pd->amp_gpio, "gpio-amp");
+               if (ret) {
+                       dev_err(dev, "cannot get amp gpio %d (%d)\n",
+                               pd->amp_gpio, ret);
+                       goto err_amp;
+               }
+
+               /* set the amp off at startup */
+               spk_unmute_state(0);
+       }
+
+       return 0;
+
+err_amp:
+       if (pd->amp_gain[0] > 0) {
+               gpio_free(pd->amp_gain[0]);
+               gpio_free(pd->amp_gain[1]);
+       }
+
+       return ret;
+}
+
+static void detach_gpio_amp(struct s3c24xx_audio_simtec_pdata *pd)
+{
+       if (pd->amp_gain[0] > 0) {
+               gpio_free(pd->amp_gain[0]);
+               gpio_free(pd->amp_gain[1]);
+       }
+
+       if (pd->amp_gpio > 0)
+               gpio_free(pd->amp_gpio);
+}
+
+#ifdef CONFIG_PM
+int simtec_audio_resume(struct device *dev)
+{
+       simtec_call_startup(pdata);
+       return 0;
+}
+
+const struct dev_pm_ops simtec_audio_pmops = {
+       .resume = simtec_audio_resume,
+};
+EXPORT_SYMBOL_GPL(simtec_audio_pmops);
+#endif
+
+int __devinit simtec_audio_core_probe(struct platform_device *pdev,
+                                     struct snd_soc_card *card)
+{
+       struct platform_device *snd_dev;
+       int ret;
+
+       card->dai_link->ops = &simtec_snd_ops;
+
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
+               dev_err(&pdev->dev, "no platform data supplied\n");
+               return -EINVAL;
+       }
+
+       simtec_call_startup(pdata);
+
+       xtal_clk = clk_get(&pdev->dev, "xtal");
+       if (IS_ERR(xtal_clk)) {
+               dev_err(&pdev->dev, "could not get clkout0\n");
+               return -EINVAL;
+       }
+
+       dev_info(&pdev->dev, "xtal rate is %ld\n", clk_get_rate(xtal_clk));
+
+       ret = attach_gpio_amp(&pdev->dev, pdata);
+       if (ret)
+               goto err_clk;
+
+       snd_dev = platform_device_alloc("soc-audio", -1);
+       if (!snd_dev) {
+               dev_err(&pdev->dev, "failed to alloc soc-audio devicec\n");
+               ret = -ENOMEM;
+               goto err_gpio;
+       }
+
+       platform_set_drvdata(snd_dev, card);
+
+       ret = platform_device_add(snd_dev);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to add soc-audio dev\n");
+               goto err_pdev;
+       }
+
+       platform_set_drvdata(pdev, snd_dev);
+       return 0;
+
+err_pdev:
+       platform_device_put(snd_dev);
+
+err_gpio:
+       detach_gpio_amp(pdata);
+
+err_clk:
+       clk_put(xtal_clk);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(simtec_audio_core_probe);
+
+int __devexit simtec_audio_remove(struct platform_device *pdev)
+{
+       struct platform_device *snd_dev = platform_get_drvdata(pdev);
+
+       platform_device_unregister(snd_dev);
+
+       detach_gpio_amp(pdata);
+       clk_put(xtal_clk);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(simtec_audio_remove);
+
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("ALSA SoC Simtec Audio common support");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/s3c24xx_simtec.h b/sound/soc/samsung/s3c24xx_simtec.h
new file mode 100644 (file)
index 0000000..8270748
--- /dev/null
@@ -0,0 +1,22 @@
+/* sound/soc/samsung/s3c24xx_simtec.h
+ *
+ * Copyright 2009 Simtec Electronics
+ *
+ * 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.
+*/
+
+extern void simtec_audio_init(struct snd_soc_pcm_runtime *rtd);
+
+extern int simtec_audio_core_probe(struct platform_device *pdev,
+                                  struct snd_soc_card *card);
+
+extern int simtec_audio_remove(struct platform_device *pdev);
+
+#ifdef CONFIG_PM
+extern const struct dev_pm_ops simtec_audio_pmops;
+#define simtec_audio_pm &simtec_audio_pmops
+#else
+#define simtec_audio_pm NULL
+#endif
diff --git a/sound/soc/samsung/s3c24xx_simtec_hermes.c b/sound/soc/samsung/s3c24xx_simtec_hermes.c
new file mode 100644 (file)
index 0000000..bb4292e
--- /dev/null
@@ -0,0 +1,144 @@
+/* sound/soc/samsung/s3c24xx_simtec_hermes.c
+ *
+ * Copyright 2009 Simtec Electronics
+ *
+ * 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/clk.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <plat/audio-simtec.h>
+
+#include "dma.h"
+#include "s3c24xx-i2s.h"
+#include "s3c24xx_simtec.h"
+
+static const struct snd_soc_dapm_widget dapm_widgets[] = {
+       SND_SOC_DAPM_LINE("GSM Out", NULL),
+       SND_SOC_DAPM_LINE("GSM In", NULL),
+       SND_SOC_DAPM_LINE("Line In", NULL),
+       SND_SOC_DAPM_LINE("Line Out", NULL),
+       SND_SOC_DAPM_LINE("ZV", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route base_map[] = {
+       /* Headphone connected to HP{L,R}OUT and HP{L,R}COM */
+
+       { "Headphone Jack", NULL, "HPLOUT" },
+       { "Headphone Jack", NULL, "HPLCOM" },
+       { "Headphone Jack", NULL, "HPROUT" },
+       { "Headphone Jack", NULL, "HPRCOM" },
+
+       /* ZV connected to Line1 */
+
+       { "LINE1L", NULL, "ZV" },
+       { "LINE1R", NULL, "ZV" },
+
+       /* Line In connected to Line2 */
+
+       { "LINE2L", NULL, "Line In" },
+       { "LINE2R", NULL, "Line In" },
+
+       /* Microphone connected to MIC3R and MIC_BIAS */
+
+       { "MIC3L", NULL, "Mic Jack" },
+
+       /* GSM connected to MONO_LOUT and MIC3L (in) */
+
+       { "GSM Out", NULL, "MONO_LOUT" },
+       { "MIC3L", NULL, "GSM In" },
+
+       /* Speaker is connected to LINEOUT{LN,LP,RN,RP}, however we are
+        * not using the DAPM to power it up and down as there it makes
+        * a click when powering up. */
+};
+
+/**
+ * simtec_hermes_init - initialise and add controls
+ * @codec; The codec instance to attach to.
+ *
+ * Attach our controls and configure the necessary codec
+ * mappings for our sound card instance.
+*/
+static int simtec_hermes_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       snd_soc_dapm_new_controls(dapm, dapm_widgets,
+                                 ARRAY_SIZE(dapm_widgets));
+
+       snd_soc_dapm_add_routes(dapm, base_map, ARRAY_SIZE(base_map));
+
+       snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+       snd_soc_dapm_enable_pin(dapm, "Line In");
+       snd_soc_dapm_enable_pin(dapm, "Line Out");
+       snd_soc_dapm_enable_pin(dapm, "Mic Jack");
+
+       simtec_audio_init(rtd);
+       snd_soc_dapm_sync(dapm);
+
+       return 0;
+}
+
+static struct snd_soc_dai_link simtec_dai_aic33 = {
+       .name           = "tlv320aic33",
+       .stream_name    = "TLV320AIC33",
+       .codec_name     = "tlv320aic3x-codec.0-0x1a",
+       .cpu_dai_name   = "s3c24xx-i2s",
+       .codec_dai_name = "tlv320aic3x-hifi",
+       .platform_name  = "samsung-audio",
+       .init           = simtec_hermes_init,
+};
+
+/* simtec audio machine driver */
+static struct snd_soc_card snd_soc_machine_simtec_aic33 = {
+       .name           = "Simtec-Hermes",
+       .dai_link       = &simtec_dai_aic33,
+       .num_links      = 1,
+};
+
+static int __devinit simtec_audio_hermes_probe(struct platform_device *pd)
+{
+       dev_info(&pd->dev, "probing....\n");
+       return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic33);
+}
+
+static struct platform_driver simtec_audio_hermes_platdrv = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "s3c24xx-simtec-hermes-snd",
+               .pm     = simtec_audio_pm,
+       },
+       .probe  = simtec_audio_hermes_probe,
+       .remove = __devexit_p(simtec_audio_remove),
+};
+
+MODULE_ALIAS("platform:s3c24xx-simtec-hermes-snd");
+
+static int __init simtec_hermes_modinit(void)
+{
+       return platform_driver_register(&simtec_audio_hermes_platdrv);
+}
+
+static void __exit simtec_hermes_modexit(void)
+{
+       platform_driver_unregister(&simtec_audio_hermes_platdrv);
+}
+
+module_init(simtec_hermes_modinit);
+module_exit(simtec_hermes_modexit);
+
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("ALSA SoC Simtec Audio support");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
new file mode 100644 (file)
index 0000000..fbba4e3
--- /dev/null
@@ -0,0 +1,134 @@
+/* sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
+ *
+ * Copyright 2009 Simtec Electronics
+ *
+ * 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/clk.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <plat/audio-simtec.h>
+
+#include "dma.h"
+#include "s3c24xx-i2s.h"
+#include "s3c24xx_simtec.h"
+
+#include "../codecs/tlv320aic23.h"
+
+/* supported machines:
+ *
+ * Machine     Connections             AMP
+ * -------     -----------             ---
+ * BAST                MIC, HPOUT, LOUT, LIN   TPA2001D1 (HPOUTL,R) (gain hardwired)
+ * VR1000      HPOUT, LIN              None
+ * VR2000      LIN, LOUT, MIC, HP      LM4871 (HPOUTL,R)
+ * DePicture   LIN, LOUT, MIC, HP      LM4871 (HPOUTL,R)
+ * Anubis      LIN, LOUT, MIC, HP      TPA2001D1 (HPOUTL,R)
+ */
+
+static const struct snd_soc_dapm_widget dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_LINE("Line In", NULL),
+       SND_SOC_DAPM_LINE("Line Out", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route base_map[] = {
+       { "Headphone Jack", NULL, "LHPOUT"},
+       { "Headphone Jack", NULL, "RHPOUT"},
+
+       { "Line Out", NULL, "LOUT" },
+       { "Line Out", NULL, "ROUT" },
+
+       { "LLINEIN", NULL, "Line In"},
+       { "RLINEIN", NULL, "Line In"},
+
+       { "MICIN", NULL, "Mic Jack"},
+};
+
+/**
+ * simtec_tlv320aic23_init - initialise and add controls
+ * @codec; The codec instance to attach to.
+ *
+ * Attach our controls and configure the necessary codec
+ * mappings for our sound card instance.
+*/
+static int simtec_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       snd_soc_dapm_new_controls(dapm, dapm_widgets,
+                                 ARRAY_SIZE(dapm_widgets));
+
+       snd_soc_dapm_add_routes(dapm, base_map, ARRAY_SIZE(base_map));
+
+       snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+       snd_soc_dapm_enable_pin(dapm, "Line In");
+       snd_soc_dapm_enable_pin(dapm, "Line Out");
+       snd_soc_dapm_enable_pin(dapm, "Mic Jack");
+
+       simtec_audio_init(rtd);
+       snd_soc_dapm_sync(dapm);
+
+       return 0;
+}
+
+static struct snd_soc_dai_link simtec_dai_aic23 = {
+       .name           = "tlv320aic23",
+       .stream_name    = "TLV320AIC23",
+       .codec_name     = "tlv320aic3x-codec.0-0x1a",
+       .cpu_dai_name   = "s3c24xx-i2s",
+       .codec_dai_name = "tlv320aic3x-hifi",
+       .platform_name  = "samsung-audio",
+       .init           = simtec_tlv320aic23_init,
+};
+
+/* simtec audio machine driver */
+static struct snd_soc_card snd_soc_machine_simtec_aic23 = {
+       .name           = "Simtec",
+       .dai_link       = &simtec_dai_aic23,
+       .num_links      = 1,
+};
+
+static int __devinit simtec_audio_tlv320aic23_probe(struct platform_device *pd)
+{
+       return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic23);
+}
+
+static struct platform_driver simtec_audio_tlv320aic23_platdrv = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "s3c24xx-simtec-tlv320aic23",
+               .pm     = simtec_audio_pm,
+       },
+       .probe  = simtec_audio_tlv320aic23_probe,
+       .remove = __devexit_p(simtec_audio_remove),
+};
+
+MODULE_ALIAS("platform:s3c24xx-simtec-tlv320aic23");
+
+static int __init simtec_tlv320aic23_modinit(void)
+{
+       return platform_driver_register(&simtec_audio_tlv320aic23_platdrv);
+}
+
+static void __exit simtec_tlv320aic23_modexit(void)
+{
+       platform_driver_unregister(&simtec_audio_tlv320aic23_platdrv);
+}
+
+module_init(simtec_tlv320aic23_modinit);
+module_exit(simtec_tlv320aic23_modexit);
+
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("ALSA SoC Simtec Audio support");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c
new file mode 100644 (file)
index 0000000..cdc8ecb
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * Modifications by Christian Pellegrin <chripell@evolware.org>
+ *
+ * s3c24xx_uda134x.c  --  S3C24XX_UDA134X ALSA SoC Audio board driver
+ *
+ * Copyright 2007 Dension Audio Systems Ltd.
+ * Author: Zoltan Devai
+ *
+ * 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/clk.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/s3c24xx_uda134x.h>
+#include <sound/uda134x.h>
+
+#include <plat/regs-iis.h>
+
+#include "dma.h"
+#include "s3c24xx-i2s.h"
+#include "../codecs/uda134x.h"
+
+
+/* #define ENFORCE_RATES 1 */
+/*
+  Unfortunately the S3C24XX in master mode has a limited capacity of
+  generating the clock for the codec. If you define this only rates
+  that are really available will be enforced. But be careful, most
+  user level application just want the usual sampling frequencies (8,
+  11.025, 22.050, 44.1 kHz) and anyway resampling is a costly
+  operation for embedded systems. So if you aren't very lucky or your
+  hardware engineer wasn't very forward-looking it's better to leave
+  this undefined. If you do so an approximate value for the requested
+  sampling rate in the range -/+ 5% will be chosen. If this in not
+  possible an error will be returned.
+*/
+
+static struct clk *xtal;
+static struct clk *pclk;
+/* this is need because we don't have a place where to keep the
+ * pointers to the clocks in each substream. We get the clocks only
+ * when we are actually using them so we don't block stuff like
+ * frequency change or oscillator power-off */
+static int clk_users;
+static DEFINE_MUTEX(clk_lock);
+
+static unsigned int rates[33 * 2];
+#ifdef ENFORCE_RATES
+static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
+       .count  = ARRAY_SIZE(rates),
+       .list   = rates,
+       .mask   = 0,
+};
+#endif
+
+static struct platform_device *s3c24xx_uda134x_snd_device;
+
+static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
+{
+       int ret = 0;
+#ifdef ENFORCE_RATES
+       struct snd_pcm_runtime *runtime = substream->runtime;
+#endif
+
+       mutex_lock(&clk_lock);
+       pr_debug("%s %d\n", __func__, clk_users);
+       if (clk_users == 0) {
+               xtal = clk_get(&s3c24xx_uda134x_snd_device->dev, "xtal");
+               if (!xtal) {
+                       printk(KERN_ERR "%s cannot get xtal\n", __func__);
+                       ret = -EBUSY;
+               } else {
+                       pclk = clk_get(&s3c24xx_uda134x_snd_device->dev,
+                                      "pclk");
+                       if (!pclk) {
+                               printk(KERN_ERR "%s cannot get pclk\n",
+                                      __func__);
+                               clk_put(xtal);
+                               ret = -EBUSY;
+                       }
+               }
+               if (!ret) {
+                       int i, j;
+
+                       for (i = 0; i < 2; i++) {
+                               int fs = i ? 256 : 384;
+
+                               rates[i*33] = clk_get_rate(xtal) / fs;
+                               for (j = 1; j < 33; j++)
+                                       rates[i*33 + j] = clk_get_rate(pclk) /
+                                               (j * fs);
+                       }
+               }
+       }
+       clk_users += 1;
+       mutex_unlock(&clk_lock);
+       if (!ret) {
+#ifdef ENFORCE_RATES
+               ret = snd_pcm_hw_constraint_list(runtime, 0,
+                                                SNDRV_PCM_HW_PARAM_RATE,
+                                                &hw_constraints_rates);
+               if (ret < 0)
+                       printk(KERN_ERR "%s cannot set constraints\n",
+                              __func__);
+#endif
+       }
+       return ret;
+}
+
+static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream)
+{
+       mutex_lock(&clk_lock);
+       pr_debug("%s %d\n", __func__, clk_users);
+       clk_users -= 1;
+       if (clk_users == 0) {
+               clk_put(xtal);
+               xtal = NULL;
+               clk_put(pclk);
+               pclk = NULL;
+       }
+       mutex_unlock(&clk_lock);
+}
+
+static int s3c24xx_uda134x_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;
+       unsigned int clk = 0;
+       int ret = 0;
+       int clk_source, fs_mode;
+       unsigned long rate = params_rate(params);
+       long err, cerr;
+       unsigned int div;
+       int i, bi;
+
+       err = 999999;
+       bi = 0;
+       for (i = 0; i < 2*33; i++) {
+               cerr = rates[i] - rate;
+               if (cerr < 0)
+                       cerr = -cerr;
+               if (cerr < err) {
+                       err = cerr;
+                       bi = i;
+               }
+       }
+       if (bi / 33 == 1)
+               fs_mode = S3C2410_IISMOD_256FS;
+       else
+               fs_mode = S3C2410_IISMOD_384FS;
+       if (bi % 33 == 0) {
+               clk_source = S3C24XX_CLKSRC_MPLL;
+               div = 1;
+       } else {
+               clk_source = S3C24XX_CLKSRC_PCLK;
+               div = bi % 33;
+       }
+       pr_debug("%s desired rate %lu, %d\n", __func__, rate, bi);
+
+       clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate;
+       pr_debug("%s will use: %s %s %d sysclk %d err %ld\n", __func__,
+                fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS",
+                clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK",
+                div, clk, err);
+
+       if ((err * 100 / rate) > 5) {
+               printk(KERN_ERR "S3C24XX_UDA134X: effective frequency "
+                      "too different from desired (%ld%%)\n",
+                      err * 100 / rate);
+               return -EINVAL;
+       }
+
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk,
+                       SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, fs_mode);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
+                       S3C2410_IISMOD_32FS);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+                       S3C24XX_PRESCALE(div, div));
+       if (ret < 0)
+               return ret;
+
+       /* set the codec system clock for DAC and ADC */
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
+                       SND_SOC_CLOCK_OUT);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static struct snd_soc_ops s3c24xx_uda134x_ops = {
+       .startup = s3c24xx_uda134x_startup,
+       .shutdown = s3c24xx_uda134x_shutdown,
+       .hw_params = s3c24xx_uda134x_hw_params,
+};
+
+static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
+       .name = "UDA134X",
+       .stream_name = "UDA134X",
+       .codec_name = "uda134x-hifi",
+       .codec_dai_name = "uda134x-hifi",
+       .cpu_dai_name = "s3c24xx-i2s",
+       .ops = &s3c24xx_uda134x_ops,
+       .platform_name  = "samsung-audio",
+};
+
+static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
+       .name = "S3C24XX_UDA134X",
+       .dai_link = &s3c24xx_uda134x_dai_link,
+       .num_links = 1,
+};
+
+static struct s3c24xx_uda134x_platform_data *s3c24xx_uda134x_l3_pins;
+
+static void setdat(int v)
+{
+       gpio_set_value(s3c24xx_uda134x_l3_pins->l3_data, v > 0);
+}
+
+static void setclk(int v)
+{
+       gpio_set_value(s3c24xx_uda134x_l3_pins->l3_clk, v > 0);
+}
+
+static void setmode(int v)
+{
+       gpio_set_value(s3c24xx_uda134x_l3_pins->l3_mode, v > 0);
+}
+
+/* FIXME - This must be codec platform data but in which board file ?? */
+static struct uda134x_platform_data s3c24xx_uda134x = {
+       .l3 = {
+               .setdat = setdat,
+               .setclk = setclk,
+               .setmode = setmode,
+               .data_hold = 1,
+               .data_setup = 1,
+               .clock_high = 1,
+               .mode_hold = 1,
+               .mode = 1,
+               .mode_setup = 1,
+       },
+};
+
+static int s3c24xx_uda134x_setup_pin(int pin, char *fun)
+{
+       if (gpio_request(pin, "s3c24xx_uda134x") < 0) {
+               printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
+                      "l3 %s pin already in use", fun);
+               return -EBUSY;
+       }
+       gpio_direction_output(pin, 0);
+       return 0;
+}
+
+static int s3c24xx_uda134x_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       printk(KERN_INFO "S3C24XX_UDA134X SoC Audio driver\n");
+
+       s3c24xx_uda134x_l3_pins = pdev->dev.platform_data;
+       if (s3c24xx_uda134x_l3_pins == NULL) {
+               printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
+                      "unable to find platform data\n");
+               return -ENODEV;
+       }
+       s3c24xx_uda134x.power = s3c24xx_uda134x_l3_pins->power;
+       s3c24xx_uda134x.model = s3c24xx_uda134x_l3_pins->model;
+
+       if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_data,
+                                     "data") < 0)
+               return -EBUSY;
+       if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_clk,
+                                     "clk") < 0) {
+               gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
+               return -EBUSY;
+       }
+       if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_mode,
+                                     "mode") < 0) {
+               gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
+               gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
+               return -EBUSY;
+       }
+
+       s3c24xx_uda134x_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!s3c24xx_uda134x_snd_device) {
+               printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
+                      "Unable to register\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(s3c24xx_uda134x_snd_device,
+                            &snd_soc_s3c24xx_uda134x);
+       ret = platform_device_add(s3c24xx_uda134x_snd_device);
+       if (ret) {
+               printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n");
+               platform_device_put(s3c24xx_uda134x_snd_device);
+       }
+
+       return ret;
+}
+
+static int s3c24xx_uda134x_remove(struct platform_device *pdev)
+{
+       platform_device_unregister(s3c24xx_uda134x_snd_device);
+       gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
+       gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
+       gpio_free(s3c24xx_uda134x_l3_pins->l3_mode);
+       return 0;
+}
+
+static struct platform_driver s3c24xx_uda134x_driver = {
+       .probe  = s3c24xx_uda134x_probe,
+       .remove = s3c24xx_uda134x_remove,
+       .driver = {
+               .name = "s3c24xx_uda134x",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init s3c24xx_uda134x_init(void)
+{
+       return platform_driver_register(&s3c24xx_uda134x_driver);
+}
+
+static void __exit s3c24xx_uda134x_exit(void)
+{
+       platform_driver_unregister(&s3c24xx_uda134x_driver);
+}
+
+
+module_init(s3c24xx_uda134x_init);
+module_exit(s3c24xx_uda134x_exit);
+
+MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
+MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c
new file mode 100644 (file)
index 0000000..61e2b52
--- /dev/null
@@ -0,0 +1,290 @@
+/* sound/soc/samsung/smartq_wm8987.c
+ *
+ * Copyright 2010 Maurus Cuelenaere <mcuelenaere@gmail.com>
+ *
+ * Based on smdk6410_wm8987.c
+ *     Copyright 2007 Wolfson Microelectronics PLC. - linux@wolfsonmicro.com
+ *     Graeme Gregory - graeme.gregory@wolfsonmicro.com
+ *
+ *  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/platform_device.h>
+#include <linux/gpio.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+#include <asm/mach-types.h>
+
+#include "dma.h"
+#include "i2s.h"
+
+#include "../codecs/wm8750.h"
+
+/*
+ * WM8987 is register compatible with WM8750, so using that as base driver.
+ */
+
+static struct snd_soc_card snd_soc_smartq;
+
+static int smartq_hifi_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;
+       unsigned int clk = 0;
+       int ret;
+
+       switch (params_rate(params)) {
+       case 8000:
+       case 16000:
+       case 32000:
+       case 48000:
+       case 96000:
+               clk = 12288000;
+               break;
+       case 11025:
+       case 22050:
+       case 44100:
+       case 88200:
+               clk = 11289600;
+               break;
+       }
+
+       /* set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+                                            SND_SOC_DAIFMT_NB_NF |
+                                            SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* set cpu DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+                                          SND_SOC_DAIFMT_NB_NF |
+                                          SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* Use PCLK for I2S signal generation */
+       ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0,
+                                       0, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       /* Gate the RCLK output on PAD */
+       ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK,
+                                       0, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec system clock for DAC and ADC */
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
+                                    SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+/*
+ * SmartQ WM8987 HiFi DAI operations.
+ */
+static struct snd_soc_ops smartq_hifi_ops = {
+       .hw_params = smartq_hifi_hw_params,
+};
+
+static struct snd_soc_jack smartq_jack;
+
+static struct snd_soc_jack_pin smartq_jack_pins[] = {
+       /* Disable speaker when headphone is plugged in */
+       {
+               .pin    = "Internal Speaker",
+               .mask   = SND_JACK_HEADPHONE,
+       },
+};
+
+static struct snd_soc_jack_gpio smartq_jack_gpios[] = {
+       {
+               .gpio           = S3C64XX_GPL(12),
+               .name           = "headphone detect",
+               .report         = SND_JACK_HEADPHONE,
+               .debounce_time  = 200,
+       },
+};
+
+static const struct snd_kcontrol_new wm8987_smartq_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Internal Speaker"),
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+       SOC_DAPM_PIN_SWITCH("Internal Mic"),
+};
+
+static int smartq_speaker_event(struct snd_soc_dapm_widget *w,
+                               struct snd_kcontrol *k,
+                               int event)
+{
+       gpio_set_value(S3C64XX_GPK(12), SND_SOC_DAPM_EVENT_OFF(event));
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget wm8987_dapm_widgets[] = {
+       SND_SOC_DAPM_SPK("Internal Speaker", smartq_speaker_event),
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Internal Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       {"Headphone Jack", NULL, "LOUT2"},
+       {"Headphone Jack", NULL, "ROUT2"},
+
+       {"Internal Speaker", NULL, "LOUT2"},
+       {"Internal Speaker", NULL, "ROUT2"},
+
+       {"Mic Bias", NULL, "Internal Mic"},
+       {"LINPUT2", NULL, "Mic Bias"},
+};
+
+static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       int err = 0;
+
+       /* Add SmartQ specific widgets */
+       snd_soc_dapm_new_controls(dapm, wm8987_dapm_widgets,
+                                 ARRAY_SIZE(wm8987_dapm_widgets));
+
+       /* add SmartQ specific controls */
+       err = snd_soc_add_controls(codec, wm8987_smartq_controls,
+                                  ARRAY_SIZE(wm8987_smartq_controls));
+
+       if (err < 0)
+               return err;
+
+       /* setup SmartQ specific audio path */
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+
+       /* set endpoints to not connected */
+       snd_soc_dapm_nc_pin(dapm, "LINPUT1");
+       snd_soc_dapm_nc_pin(dapm, "RINPUT1");
+       snd_soc_dapm_nc_pin(dapm, "OUT3");
+       snd_soc_dapm_nc_pin(dapm, "ROUT1");
+
+       /* set endpoints to default off mode */
+       snd_soc_dapm_enable_pin(dapm, "Internal Speaker");
+       snd_soc_dapm_enable_pin(dapm, "Internal Mic");
+       snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+
+       err = snd_soc_dapm_sync(dapm);
+       if (err)
+               return err;
+
+       /* Headphone jack detection */
+       err = snd_soc_jack_new(codec, "Headphone Jack",
+                              SND_JACK_HEADPHONE, &smartq_jack);
+       if (err)
+               return err;
+
+       err = snd_soc_jack_add_pins(&smartq_jack, ARRAY_SIZE(smartq_jack_pins),
+                                   smartq_jack_pins);
+       if (err)
+               return err;
+
+       err = snd_soc_jack_add_gpios(&smartq_jack,
+                                    ARRAY_SIZE(smartq_jack_gpios),
+                                    smartq_jack_gpios);
+
+       return err;
+}
+
+static struct snd_soc_dai_link smartq_dai[] = {
+       {
+               .name           = "wm8987",
+               .stream_name    = "SmartQ Hi-Fi",
+               .cpu_dai_name   = "samsung-i2s.0",
+               .codec_dai_name = "wm8750-hifi",
+               .platform_name  = "samsung-audio",
+               .codec_name     = "wm8750-codec.0-0x1a",
+               .init           = smartq_wm8987_init,
+               .ops            = &smartq_hifi_ops,
+       },
+};
+
+static struct snd_soc_card snd_soc_smartq = {
+       .name = "SmartQ",
+       .dai_link = smartq_dai,
+       .num_links = ARRAY_SIZE(smartq_dai),
+};
+
+static struct platform_device *smartq_snd_device;
+
+static int __init smartq_init(void)
+{
+       int ret;
+
+       if (!machine_is_smartq7() && !machine_is_smartq5()) {
+               pr_info("Only SmartQ is supported by this ASoC driver\n");
+               return -ENODEV;
+       }
+
+       smartq_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!smartq_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(smartq_snd_device, &snd_soc_smartq);
+
+       ret = platform_device_add(smartq_snd_device);
+       if (ret) {
+               platform_device_put(smartq_snd_device);
+               return ret;
+       }
+
+       /* Initialise GPIOs used by amplifiers */
+       ret = gpio_request(S3C64XX_GPK(12), "amplifiers shutdown");
+       if (ret) {
+               dev_err(&smartq_snd_device->dev, "Failed to register GPK12\n");
+               goto err_unregister_device;
+       }
+
+       /* Disable amplifiers */
+       ret = gpio_direction_output(S3C64XX_GPK(12), 1);
+       if (ret) {
+               dev_err(&smartq_snd_device->dev, "Failed to configure GPK12\n");
+               goto err_free_gpio_amp_shut;
+       }
+
+       return 0;
+
+err_free_gpio_amp_shut:
+       gpio_free(S3C64XX_GPK(12));
+err_unregister_device:
+       platform_device_unregister(smartq_snd_device);
+
+       return ret;
+}
+
+static void __exit smartq_exit(void)
+{
+       gpio_free(S3C64XX_GPK(12));
+       snd_soc_jack_free_gpios(&smartq_jack, ARRAY_SIZE(smartq_jack_gpios),
+                               smartq_jack_gpios);
+
+       platform_device_unregister(smartq_snd_device);
+}
+
+module_init(smartq_init);
+module_exit(smartq_exit);
+
+/* Module information */
+MODULE_AUTHOR("Maurus Cuelenaere <mcuelenaere@gmail.com>");
+MODULE_DESCRIPTION("ALSA SoC SmartQ WM8987");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/smdk2443_wm9710.c b/sound/soc/samsung/smdk2443_wm9710.c
new file mode 100644 (file)
index 0000000..3be7e7e
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * smdk2443_wm9710.c  --  SoC audio for smdk2443
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  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/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include "dma.h"
+#include "ac97.h"
+
+static struct snd_soc_card smdk2443;
+
+static struct snd_soc_dai_link smdk2443_dai[] = {
+{
+       .name = "AC97",
+       .stream_name = "AC97 HiFi",
+       .cpu_dai_name = "samsung-ac97",
+       .codec_dai_name = "ac97-hifi",
+       .codec_name = "ac97-codec",
+       .platform_name = "samsung-audio",
+},
+};
+
+static struct snd_soc_card smdk2443 = {
+       .name = "SMDK2443",
+       .dai_link = smdk2443_dai,
+       .num_links = ARRAY_SIZE(smdk2443_dai),
+};
+
+static struct platform_device *smdk2443_snd_ac97_device;
+
+static int __init smdk2443_init(void)
+{
+       int ret;
+
+       smdk2443_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+       if (!smdk2443_snd_ac97_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(smdk2443_snd_ac97_device, &smdk2443);
+       ret = platform_device_add(smdk2443_snd_ac97_device);
+
+       if (ret)
+               platform_device_put(smdk2443_snd_ac97_device);
+
+       return ret;
+}
+
+static void __exit smdk2443_exit(void)
+{
+       platform_device_unregister(smdk2443_snd_ac97_device);
+}
+
+module_init(smdk2443_init);
+module_exit(smdk2443_exit);
+
+/* Module information */
+MODULE_AUTHOR("Graeme Gregory, graeme.gregory@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC WM9710 SMDK2443");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/smdk_spdif.c b/sound/soc/samsung/smdk_spdif.c
new file mode 100644 (file)
index 0000000..b5c3fad
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * smdk_spdif.c  --  S/PDIF audio for SMDK
+ *
+ * Copyright 2010 Samsung Electronics Co. Ltd.
+ *
+ * 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/device.h>
+#include <linux/clk.h>
+
+#include <plat/devs.h>
+
+#include <sound/soc.h>
+
+#include "dma.h"
+#include "spdif.h"
+
+/* Audio clock settings are belonged to board specific part. Every
+ * board can set audio source clock setting which is matched with H/W
+ * like this function-'set_audio_clock_heirachy'.
+ */
+static int set_audio_clock_heirachy(struct platform_device *pdev)
+{
+       struct clk *fout_epll, *mout_epll, *sclk_audio0, *sclk_spdif;
+       int ret = 0;
+
+       fout_epll = clk_get(NULL, "fout_epll");
+       if (IS_ERR(fout_epll)) {
+               printk(KERN_WARNING "%s: Cannot find fout_epll.\n",
+                               __func__);
+               return -EINVAL;
+       }
+
+       mout_epll = clk_get(NULL, "mout_epll");
+       if (IS_ERR(mout_epll)) {
+               printk(KERN_WARNING "%s: Cannot find mout_epll.\n",
+                               __func__);
+               ret = -EINVAL;
+               goto out1;
+       }
+
+       sclk_audio0 = clk_get(&pdev->dev, "sclk_audio");
+       if (IS_ERR(sclk_audio0)) {
+               printk(KERN_WARNING "%s: Cannot find sclk_audio.\n",
+                               __func__);
+               ret = -EINVAL;
+               goto out2;
+       }
+
+       sclk_spdif = clk_get(NULL, "sclk_spdif");
+       if (IS_ERR(sclk_spdif)) {
+               printk(KERN_WARNING "%s: Cannot find sclk_spdif.\n",
+                               __func__);
+               ret = -EINVAL;
+               goto out3;
+       }
+
+       /* Set audio clock hierarchy for S/PDIF */
+       clk_set_parent(mout_epll, fout_epll);
+       clk_set_parent(sclk_audio0, mout_epll);
+       clk_set_parent(sclk_spdif, sclk_audio0);
+
+       clk_put(sclk_spdif);
+out3:
+       clk_put(sclk_audio0);
+out2:
+       clk_put(mout_epll);
+out1:
+       clk_put(fout_epll);
+
+       return ret;
+}
+
+/* We should haved to set clock directly on this part because of clock
+ * scheme of Samsudng SoCs did not support to set rates from abstrct
+ * clock of it's hierarchy.
+ */
+static int set_audio_clock_rate(unsigned long epll_rate,
+                               unsigned long audio_rate)
+{
+       struct clk *fout_epll, *sclk_spdif;
+
+       fout_epll = clk_get(NULL, "fout_epll");
+       if (IS_ERR(fout_epll)) {
+               printk(KERN_ERR "%s: failed to get fout_epll\n", __func__);
+               return -ENOENT;
+       }
+
+       clk_set_rate(fout_epll, epll_rate);
+       clk_put(fout_epll);
+
+       sclk_spdif = clk_get(NULL, "sclk_spdif");
+       if (IS_ERR(sclk_spdif)) {
+               printk(KERN_ERR "%s: failed to get sclk_spdif\n", __func__);
+               return -ENOENT;
+       }
+
+       clk_set_rate(sclk_spdif, audio_rate);
+       clk_put(sclk_spdif);
+
+       return 0;
+}
+
+static int smdk_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;
+       unsigned long pll_out, rclk_rate;
+       int ret, ratio;
+
+       switch (params_rate(params)) {
+       case 44100:
+               pll_out = 45158400;
+               break;
+       case 32000:
+       case 48000:
+       case 96000:
+               pll_out = 49152000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Setting ratio to 512fs helps to use S/PDIF with HDMI without
+        * modify S/PDIF ASoC machine driver.
+        */
+       ratio = 512;
+       rclk_rate = params_rate(params) * ratio;
+
+       /* Set audio source clock rates */
+       ret = set_audio_clock_rate(pll_out, rclk_rate);
+       if (ret < 0)
+               return ret;
+
+       /* Set S/PDIF uses internal source clock */
+       ret = snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK,
+                                       rclk_rate, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       return ret;
+}
+
+static struct snd_soc_ops smdk_spdif_ops = {
+       .hw_params = smdk_hw_params,
+};
+
+static struct snd_soc_dai_link smdk_dai = {
+       .name = "S/PDIF",
+       .stream_name = "S/PDIF PCM Playback",
+       .platform_name = "samsung-audio",
+       .cpu_dai_name = "samsung-spdif",
+       .codec_dai_name = "dit-hifi",
+       .codec_name = "spdif-dit",
+       .ops = &smdk_spdif_ops,
+};
+
+static struct snd_soc_card smdk = {
+       .name = "SMDK-S/PDIF",
+       .dai_link = &smdk_dai,
+       .num_links = 1,
+};
+
+static struct platform_device *smdk_snd_spdif_dit_device;
+static struct platform_device *smdk_snd_spdif_device;
+
+static int __init smdk_init(void)
+{
+       int ret;
+
+       smdk_snd_spdif_dit_device = platform_device_alloc("spdif-dit", -1);
+       if (!smdk_snd_spdif_dit_device)
+               return -ENOMEM;
+
+       ret = platform_device_add(smdk_snd_spdif_dit_device);
+       if (ret)
+               goto err1;
+
+       smdk_snd_spdif_device = platform_device_alloc("soc-audio", -1);
+       if (!smdk_snd_spdif_device) {
+               ret = -ENOMEM;
+               goto err2;
+       }
+
+       platform_set_drvdata(smdk_snd_spdif_device, &smdk);
+
+       ret = platform_device_add(smdk_snd_spdif_device);
+       if (ret)
+               goto err3;
+
+       /* Set audio clock hierarchy manually */
+       ret = set_audio_clock_heirachy(smdk_snd_spdif_device);
+       if (ret)
+               goto err4;
+
+       return 0;
+err4:
+       platform_device_del(smdk_snd_spdif_device);
+err3:
+       platform_device_put(smdk_snd_spdif_device);
+err2:
+       platform_device_del(smdk_snd_spdif_dit_device);
+err1:
+       platform_device_put(smdk_snd_spdif_dit_device);
+       return ret;
+}
+
+static void __exit smdk_exit(void)
+{
+       platform_device_unregister(smdk_snd_spdif_device);
+       platform_device_unregister(smdk_snd_spdif_dit_device);
+}
+
+module_init(smdk_init);
+module_exit(smdk_exit);
+
+MODULE_AUTHOR("Seungwhan Youn, <sw.youn@samsung.com>");
+MODULE_DESCRIPTION("ALSA SoC SMDK+S/PDIF");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c
new file mode 100644 (file)
index 0000000..b2cff1a
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ *  smdk_wm8580.c
+ *
+ *  Copyright (c) 2009 Samsung Electronics Co. Ltd
+ *  Author: Jaswinder Singh <jassi.brar@samsung.com>
+ *
+ *  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/platform_device.h>
+#include <linux/clk.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/wm8580.h"
+#include "dma.h"
+#include "i2s.h"
+
+/*
+ * Default CFG switch settings to use this driver:
+ *
+ *   SMDK6410: Set CFG1 1-3 Off, CFG2 1-4 On
+ */
+
+/* SMDK has a 12MHZ crystal attached to WM8580 */
+#define SMDK_WM8580_FREQ 12000000
+
+static int smdk_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;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       unsigned int pll_out;
+       int bfs, rfs, ret;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_U8:
+       case SNDRV_PCM_FORMAT_S8:
+               bfs = 16;
+               break;
+       case SNDRV_PCM_FORMAT_U16_LE:
+       case SNDRV_PCM_FORMAT_S16_LE:
+               bfs = 32;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* The Fvco for WM8580 PLLs must fall within [90,100]MHz.
+        * This criterion can't be met if we request PLL output
+        * as {8000x256, 64000x256, 11025x256}Hz.
+        * As a wayout, we rather change rfs to a minimum value that
+        * results in (params_rate(params) * rfs), and itself, acceptable
+        * to both - the CODEC and the CPU.
+        */
+       switch (params_rate(params)) {
+       case 16000:
+       case 22050:
+       case 32000:
+       case 44100:
+       case 48000:
+       case 88200:
+       case 96000:
+               rfs = 256;
+               break;
+       case 64000:
+               rfs = 384;
+               break;
+       case 8000:
+       case 11025:
+               rfs = 512;
+               break;
+       default:
+               return -EINVAL;
+       }
+       pll_out = params_rate(params) * rfs;
+
+       /* Set the Codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
+                                        | SND_SOC_DAIFMT_NB_NF
+                                        | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       /* Set the AP DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
+                                        | SND_SOC_DAIFMT_NB_NF
+                                        | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       /* Set WM8580 to drive MCLK from its PLLA */
+       ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
+                                       WM8580_CLKSRC_PLLA);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
+                                       SMDK_WM8580_FREQ, pll_out);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA,
+                                    pll_out, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+/*
+ * SMDK WM8580 DAI operations.
+ */
+static struct snd_soc_ops smdk_ops = {
+       .hw_params = smdk_hw_params,
+};
+
+/* SMDK Playback widgets */
+static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = {
+       SND_SOC_DAPM_HP("Front", NULL),
+       SND_SOC_DAPM_HP("Center+Sub", NULL),
+       SND_SOC_DAPM_HP("Rear", NULL),
+};
+
+/* SMDK Capture widgets */
+static const struct snd_soc_dapm_widget wm8580_dapm_widgets_cpt[] = {
+       SND_SOC_DAPM_MIC("MicIn", NULL),
+       SND_SOC_DAPM_LINE("LineIn", NULL),
+};
+
+/* SMDK-PAIFTX connections */
+static const struct snd_soc_dapm_route audio_map_tx[] = {
+       /* MicIn feeds AINL */
+       {"AINL", NULL, "MicIn"},
+
+       /* LineIn feeds AINL/R */
+       {"AINL", NULL, "LineIn"},
+       {"AINR", NULL, "LineIn"},
+};
+
+/* SMDK-PAIFRX connections */
+static const struct snd_soc_dapm_route audio_map_rx[] = {
+       /* Front Left/Right are fed VOUT1L/R */
+       {"Front", NULL, "VOUT1L"},
+       {"Front", NULL, "VOUT1R"},
+
+       /* Center/Sub are fed VOUT2L/R */
+       {"Center+Sub", NULL, "VOUT2L"},
+       {"Center+Sub", NULL, "VOUT2R"},
+
+       /* Rear Left/Right are fed VOUT3L/R */
+       {"Rear", NULL, "VOUT3L"},
+       {"Rear", NULL, "VOUT3R"},
+};
+
+static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       /* Add smdk specific Capture widgets */
+       snd_soc_dapm_new_controls(dapm, wm8580_dapm_widgets_cpt,
+                                 ARRAY_SIZE(wm8580_dapm_widgets_cpt));
+
+       /* Set up PAIFTX audio path */
+       snd_soc_dapm_add_routes(dapm, audio_map_tx, ARRAY_SIZE(audio_map_tx));
+
+       /* Enabling the microphone requires the fitting of a 0R
+        * resistor to connect the line from the microphone jack.
+        */
+       snd_soc_dapm_disable_pin(dapm, "MicIn");
+
+       /* signal a DAPM event */
+       snd_soc_dapm_sync(dapm);
+
+       return 0;
+}
+
+static int smdk_wm8580_init_paifrx(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       /* Add smdk specific Playback widgets */
+       snd_soc_dapm_new_controls(dapm, wm8580_dapm_widgets_pbk,
+                                 ARRAY_SIZE(wm8580_dapm_widgets_pbk));
+
+       /* Set up PAIFRX audio path */
+       snd_soc_dapm_add_routes(dapm, audio_map_rx, ARRAY_SIZE(audio_map_rx));
+
+       /* signal a DAPM event */
+       snd_soc_dapm_sync(dapm);
+
+       return 0;
+}
+
+enum {
+       PRI_PLAYBACK = 0,
+       PRI_CAPTURE,
+       SEC_PLAYBACK,
+};
+
+static struct snd_soc_dai_link smdk_dai[] = {
+       [PRI_PLAYBACK] = { /* Primary Playback i/f */
+               .name = "WM8580 PAIF RX",
+               .stream_name = "Playback",
+               .cpu_dai_name = "samsung-i2s.0",
+               .codec_dai_name = "wm8580-hifi-playback",
+               .platform_name = "samsung-audio",
+               .codec_name = "wm8580-codec.0-001b",
+               .init = smdk_wm8580_init_paifrx,
+               .ops = &smdk_ops,
+       },
+       [PRI_CAPTURE] = { /* Primary Capture i/f */
+               .name = "WM8580 PAIF TX",
+               .stream_name = "Capture",
+               .cpu_dai_name = "samsung-i2s.0",
+               .codec_dai_name = "wm8580-hifi-capture",
+               .platform_name = "samsung-audio",
+               .codec_name = "wm8580-codec.0-001b",
+               .init = smdk_wm8580_init_paiftx,
+               .ops = &smdk_ops,
+       },
+       [SEC_PLAYBACK] = { /* Sec_Fifo Playback i/f */
+               .name = "Sec_FIFO TX",
+               .stream_name = "Playback",
+               .cpu_dai_name = "samsung-i2s.x",
+               .codec_dai_name = "wm8580-hifi-playback",
+               .platform_name = "samsung-audio",
+               .codec_name = "wm8580-codec.0-001b",
+               .init = smdk_wm8580_init_paifrx,
+               .ops = &smdk_ops,
+       },
+};
+
+static struct snd_soc_card smdk = {
+       .name = "SMDK-I2S",
+       .dai_link = smdk_dai,
+       .num_links = 2,
+};
+
+static struct platform_device *smdk_snd_device;
+
+static int __init smdk_audio_init(void)
+{
+       int ret;
+       char *str;
+
+       if (machine_is_smdkc100() || machine_is_smdk6442()
+                       || machine_is_smdkv210() || machine_is_smdkc110()) {
+               smdk.num_links = 3;
+               /* Secondary is at offset SAMSUNG_I2S_SECOFF from Primary */
+               str = (char *)smdk_dai[SEC_PLAYBACK].cpu_dai_name;
+               str[strlen(str) - 1] = '0' + SAMSUNG_I2S_SECOFF;
+       } else if (machine_is_smdk6410()) {
+               str = (char *)smdk_dai[PRI_PLAYBACK].cpu_dai_name;
+               str[strlen(str) - 1] = '2';
+               str = (char *)smdk_dai[PRI_CAPTURE].cpu_dai_name;
+               str[strlen(str) - 1] = '2';
+       }
+
+       smdk_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!smdk_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(smdk_snd_device, &smdk);
+       ret = platform_device_add(smdk_snd_device);
+
+       if (ret)
+               platform_device_put(smdk_snd_device);
+
+       return ret;
+}
+module_init(smdk_audio_init);
+
+static void __exit smdk_audio_exit(void)
+{
+       platform_device_unregister(smdk_snd_device);
+}
+module_exit(smdk_audio_exit);
+
+MODULE_AUTHOR("Jaswinder Singh, jassi.brar@samsung.com");
+MODULE_DESCRIPTION("ALSA SoC SMDK WM8580");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c
new file mode 100644 (file)
index 0000000..e7c1009
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ *  smdk_wm8994.c
+ *
+ *  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 "../codecs/wm8994.h"
+
+ /*
+  * Default CFG switch settings to use this driver:
+  *    SMDKV310: CFG5-1000, CFG7-111111
+  */
+
+ /*
+  * Configure audio route as :-
+  * $ amixer sset 'DAC1' on,on
+  * $ amixer sset 'Right Headphone Mux' 'DAC'
+  * $ amixer sset 'Left Headphone Mux' 'DAC'
+  * $ amixer sset 'DAC1R Mixer AIF1.1' on
+  * $ amixer sset 'DAC1L Mixer AIF1.1' on
+  * $ amixer sset 'IN2L' on
+  * $ amixer sset 'IN2L PGA IN2LN' on
+  * $ amixer sset 'MIXINL IN2L' on
+  * $ amixer sset 'AIF1ADC1L Mixer ADC/DMIC' on
+  * $ amixer sset 'IN2R' on
+  * $ amixer sset 'IN2R PGA IN2RN' on
+  * $ amixer sset 'MIXINR IN2R' on
+  * $ amixer sset 'AIF1ADC1R Mixer ADC/DMIC' on
+  */
+
+/* SMDK has a 16.934MHZ crystal attached to WM8994 */
+#define SMDK_WM8994_FREQ 16934000
+
+static int smdk_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;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       unsigned int pll_out;
+       int ret;
+
+       /* AIF1CLK should be >=3MHz for optimal performance */
+       if (params_rate(params) == 8000 || params_rate(params) == 11025)
+               pll_out = params_rate(params) * 512;
+       else
+               pll_out = params_rate(params) * 256;
+
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
+                                        | SND_SOC_DAIFMT_NB_NF
+                                        | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
+                                        | SND_SOC_DAIFMT_NB_NF
+                                        | SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1,
+                                       SMDK_WM8994_FREQ, pll_out);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
+                                       pll_out, SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+/*
+ * SMDK WM8994 DAI operations.
+ */
+static struct snd_soc_ops smdk_ops = {
+       .hw_params = smdk_hw_params,
+};
+
+static int smdk_wm8994_init_paiftx(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+       /* HeadPhone */
+       snd_soc_dapm_enable_pin(dapm, "HPOUT1R");
+       snd_soc_dapm_enable_pin(dapm, "HPOUT1L");
+
+       /* MicIn */
+       snd_soc_dapm_enable_pin(dapm, "IN1LN");
+       snd_soc_dapm_enable_pin(dapm, "IN1RN");
+
+       /* LineIn */
+       snd_soc_dapm_enable_pin(dapm, "IN2LN");
+       snd_soc_dapm_enable_pin(dapm, "IN2RN");
+
+       /* Other pins NC */
+       snd_soc_dapm_nc_pin(dapm, "HPOUT2P");
+       snd_soc_dapm_nc_pin(dapm, "HPOUT2N");
+       snd_soc_dapm_nc_pin(dapm, "SPKOUTLN");
+       snd_soc_dapm_nc_pin(dapm, "SPKOUTLP");
+       snd_soc_dapm_nc_pin(dapm, "SPKOUTRP");
+       snd_soc_dapm_nc_pin(dapm, "SPKOUTRN");
+       snd_soc_dapm_nc_pin(dapm, "LINEOUT1N");
+       snd_soc_dapm_nc_pin(dapm, "LINEOUT1P");
+       snd_soc_dapm_nc_pin(dapm, "LINEOUT2N");
+       snd_soc_dapm_nc_pin(dapm, "LINEOUT2P");
+       snd_soc_dapm_nc_pin(dapm, "IN1LP");
+       snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN");
+       snd_soc_dapm_nc_pin(dapm, "IN1RP");
+       snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP");
+
+       snd_soc_dapm_sync(dapm);
+
+       return 0;
+}
+
+static struct snd_soc_dai_link smdk_dai[] = {
+       { /* Primary DAI i/f */
+               .name = "WM8994 AIF1",
+               .stream_name = "Pri_Dai",
+               .cpu_dai_name = "samsung-i2s.0",
+               .codec_dai_name = "wm8994-aif1",
+               .platform_name = "samsung-audio",
+               .codec_name = "wm8994-codec",
+               .init = smdk_wm8994_init_paiftx,
+               .ops = &smdk_ops,
+       }, { /* Sec_Fifo Playback i/f */
+               .name = "Sec_FIFO TX",
+               .stream_name = "Sec_Dai",
+               .cpu_dai_name = "samsung-i2s.4",
+               .codec_dai_name = "wm8994-aif1",
+               .platform_name = "samsung-audio",
+               .codec_name = "wm8994-codec",
+               .ops = &smdk_ops,
+       },
+};
+
+static struct snd_soc_card smdk = {
+       .name = "SMDK-I2S",
+       .dai_link = smdk_dai,
+       .num_links = ARRAY_SIZE(smdk_dai),
+};
+
+static struct platform_device *smdk_snd_device;
+
+static int __init smdk_audio_init(void)
+{
+       int ret;
+
+       smdk_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!smdk_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(smdk_snd_device, &smdk);
+
+       ret = platform_device_add(smdk_snd_device);
+       if (ret)
+               platform_device_put(smdk_snd_device);
+
+       return ret;
+}
+module_init(smdk_audio_init);
+
+static void __exit smdk_audio_exit(void)
+{
+       platform_device_unregister(smdk_snd_device);
+}
+module_exit(smdk_audio_exit);
+
+MODULE_DESCRIPTION("ALSA SoC SMDK WM8994");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/smdk_wm9713.c b/sound/soc/samsung/smdk_wm9713.c
new file mode 100644 (file)
index 0000000..ae5fed6
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * smdk_wm9713.c  --  SoC audio for SMDK
+ *
+ * Copyright 2010 Samsung Electronics Co. Ltd.
+ * Author: Jaswinder Singh Brar <jassi.brar@samsung.com>
+ *
+ * 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/device.h>
+#include <sound/soc.h>
+
+#include "dma.h"
+#include "ac97.h"
+
+static struct snd_soc_card smdk;
+
+/*
+ * Default CFG switch settings to use this driver:
+ *
+ *   SMDK6410: Set CFG1 1-3 On, CFG2 1-4 Off
+ *   SMDKC100: Set CFG6 1-3 On, CFG7 1   On
+ *   SMDKC110: Set CFGB10 1-2 Off, CFGB12 1-3 On
+ *   SMDKV210: Set CFGB10 1-2 Off, CFGB12 1-3 On
+ *   SMDKV310: Set CFG2 1-2 Off, CFG4 All On, CFG7 All Off, CFG8 1-On
+ */
+
+/*
+ Playback (HeadPhone):-
+       $ amixer sset 'Headphone' unmute
+       $ amixer sset 'Right Headphone Out Mux' 'Headphone'
+       $ amixer sset 'Left Headphone Out Mux' 'Headphone'
+       $ amixer sset 'Right HP Mixer PCM' unmute
+       $ amixer sset 'Left HP Mixer PCM' unmute
+
+ Capture (LineIn):-
+       $ amixer sset 'Right Capture Source' 'Line'
+       $ amixer sset 'Left Capture Source' 'Line'
+*/
+
+static struct snd_soc_dai_link smdk_dai = {
+       .name = "AC97",
+       .stream_name = "AC97 PCM",
+       .platform_name = "samsung-audio",
+       .cpu_dai_name = "samsung-ac97",
+       .codec_dai_name = "wm9713-hifi",
+       .codec_name = "wm9713-codec",
+};
+
+static struct snd_soc_card smdk = {
+       .name = "SMDK WM9713",
+       .dai_link = &smdk_dai,
+       .num_links = 1,
+};
+
+static struct platform_device *smdk_snd_wm9713_device;
+static struct platform_device *smdk_snd_ac97_device;
+
+static int __init smdk_init(void)
+{
+       int ret;
+
+       smdk_snd_wm9713_device = platform_device_alloc("wm9713-codec", -1);
+       if (!smdk_snd_wm9713_device)
+               return -ENOMEM;
+
+       ret = platform_device_add(smdk_snd_wm9713_device);
+       if (ret)
+               goto err1;
+
+       smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+       if (!smdk_snd_ac97_device) {
+               ret = -ENOMEM;
+               goto err2;
+       }
+
+       platform_set_drvdata(smdk_snd_ac97_device, &smdk);
+
+       ret = platform_device_add(smdk_snd_ac97_device);
+       if (ret)
+               goto err3;
+
+       return 0;
+
+err3:
+       platform_device_put(smdk_snd_ac97_device);
+err2:
+       platform_device_del(smdk_snd_wm9713_device);
+err1:
+       platform_device_put(smdk_snd_wm9713_device);
+       return ret;
+}
+
+static void __exit smdk_exit(void)
+{
+       platform_device_unregister(smdk_snd_ac97_device);
+       platform_device_unregister(smdk_snd_wm9713_device);
+}
+
+module_init(smdk_init);
+module_exit(smdk_exit);
+
+/* Module information */
+MODULE_AUTHOR("Jaswinder Singh Brar, jassi.brar@samsung.com");
+MODULE_DESCRIPTION("ALSA SoC SMDK+WM9713");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c
new file mode 100644 (file)
index 0000000..f081640
--- /dev/null
@@ -0,0 +1,501 @@
+/* sound/soc/samsung/spdif.c
+ *
+ * ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ *             http://www.samsung.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/clk.h>
+#include <linux/io.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <plat/audio.h>
+#include <mach/dma.h>
+
+#include "dma.h"
+#include "spdif.h"
+
+/* Registers */
+#define CLKCON                         0x00
+#define CON                            0x04
+#define BSTAS                          0x08
+#define CSTAS                          0x0C
+#define DATA_OUTBUF                    0x10
+#define DCNT                           0x14
+#define BSTAS_S                                0x18
+#define DCNT_S                         0x1C
+
+#define CLKCTL_MASK                    0x7
+#define CLKCTL_MCLK_EXT                        (0x1 << 2)
+#define CLKCTL_PWR_ON                  (0x1 << 0)
+
+#define CON_MASK                       0x3ffffff
+#define CON_FIFO_TH_SHIFT              19
+#define CON_FIFO_TH_MASK               (0x7 << 19)
+#define CON_USERDATA_23RDBIT           (0x1 << 12)
+
+#define CON_SW_RESET                   (0x1 << 5)
+
+#define CON_MCLKDIV_MASK               (0x3 << 3)
+#define CON_MCLKDIV_256FS              (0x0 << 3)
+#define CON_MCLKDIV_384FS              (0x1 << 3)
+#define CON_MCLKDIV_512FS              (0x2 << 3)
+
+#define CON_PCM_MASK                   (0x3 << 1)
+#define CON_PCM_16BIT                  (0x0 << 1)
+#define CON_PCM_20BIT                  (0x1 << 1)
+#define CON_PCM_24BIT                  (0x2 << 1)
+
+#define CON_PCM_DATA                   (0x1 << 0)
+
+#define CSTAS_MASK                     0x3fffffff
+#define CSTAS_SAMP_FREQ_MASK           (0xF << 24)
+#define CSTAS_SAMP_FREQ_44             (0x0 << 24)
+#define CSTAS_SAMP_FREQ_48             (0x2 << 24)
+#define CSTAS_SAMP_FREQ_32             (0x3 << 24)
+#define CSTAS_SAMP_FREQ_96             (0xA << 24)
+
+#define CSTAS_CATEGORY_MASK            (0xFF << 8)
+#define CSTAS_CATEGORY_CODE_CDP                (0x01 << 8)
+
+#define CSTAS_NO_COPYRIGHT             (0x1 << 2)
+
+/**
+ * struct samsung_spdif_info - Samsung S/PDIF Controller information
+ * @lock: Spin lock for S/PDIF.
+ * @dev: The parent device passed to use from the probe.
+ * @regs: The pointer to the device register block.
+ * @clk_rate: Current clock rate for calcurate ratio.
+ * @pclk: The peri-clock pointer for spdif master operation.
+ * @sclk: The source clock pointer for making sync signals.
+ * @save_clkcon: Backup clkcon reg. in suspend.
+ * @save_con: Backup con reg. in suspend.
+ * @save_cstas: Backup cstas reg. in suspend.
+ * @dma_playback: DMA information for playback channel.
+ */
+struct samsung_spdif_info {
+       spinlock_t      lock;
+       struct device   *dev;
+       void __iomem    *regs;
+       unsigned long   clk_rate;
+       struct clk      *pclk;
+       struct clk      *sclk;
+       u32             saved_clkcon;
+       u32             saved_con;
+       u32             saved_cstas;
+       struct s3c_dma_params   *dma_playback;
+};
+
+static struct s3c2410_dma_client spdif_dma_client_out = {
+       .name           = "S/PDIF Stereo out",
+};
+
+static struct s3c_dma_params spdif_stereo_out;
+static struct samsung_spdif_info spdif_info;
+
+static inline struct samsung_spdif_info *to_info(struct snd_soc_dai *cpu_dai)
+{
+       return snd_soc_dai_get_drvdata(cpu_dai);
+}
+
+static void spdif_snd_txctrl(struct samsung_spdif_info *spdif, int on)
+{
+       void __iomem *regs = spdif->regs;
+       u32 clkcon;
+
+       dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+       clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
+       if (on)
+               writel(clkcon | CLKCTL_PWR_ON, regs + CLKCON);
+       else
+               writel(clkcon & ~CLKCTL_PWR_ON, regs + CLKCON);
+}
+
+static int spdif_set_sysclk(struct snd_soc_dai *cpu_dai,
+                               int clk_id, unsigned int freq, int dir)
+{
+       struct samsung_spdif_info *spdif = to_info(cpu_dai);
+       u32 clkcon;
+
+       dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+       clkcon = readl(spdif->regs + CLKCON);
+
+       if (clk_id == SND_SOC_SPDIF_INT_MCLK)
+               clkcon &= ~CLKCTL_MCLK_EXT;
+       else
+               clkcon |= CLKCTL_MCLK_EXT;
+
+       writel(clkcon, spdif->regs + CLKCON);
+
+       spdif->clk_rate = freq;
+
+       return 0;
+}
+
+static int spdif_trigger(struct snd_pcm_substream *substream, int cmd,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
+       unsigned long flags;
+
+       dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               spin_lock_irqsave(&spdif->lock, flags);
+               spdif_snd_txctrl(spdif, 1);
+               spin_unlock_irqrestore(&spdif->lock, flags);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               spin_lock_irqsave(&spdif->lock, flags);
+               spdif_snd_txctrl(spdif, 0);
+               spin_unlock_irqrestore(&spdif->lock, flags);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int spdif_sysclk_ratios[] = {
+       512, 384, 256,
+};
+
+static int spdif_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *socdai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
+       void __iomem *regs = spdif->regs;
+       struct s3c_dma_params *dma_data;
+       u32 con, clkcon, cstas;
+       unsigned long flags;
+       int i, ratio;
+
+       dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dma_data = spdif->dma_playback;
+       else {
+               dev_err(spdif->dev, "Capture is not supported\n");
+               return -EINVAL;
+       }
+
+       snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
+
+       spin_lock_irqsave(&spdif->lock, flags);
+
+       con = readl(regs + CON) & CON_MASK;
+       cstas = readl(regs + CSTAS) & CSTAS_MASK;
+       clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
+
+       con &= ~CON_FIFO_TH_MASK;
+       con |= (0x7 << CON_FIFO_TH_SHIFT);
+       con |= CON_USERDATA_23RDBIT;
+       con |= CON_PCM_DATA;
+
+       con &= ~CON_PCM_MASK;
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               con |= CON_PCM_16BIT;
+               break;
+       default:
+               dev_err(spdif->dev, "Unsupported data size.\n");
+               goto err;
+       }
+
+       ratio = spdif->clk_rate / params_rate(params);
+       for (i = 0; i < ARRAY_SIZE(spdif_sysclk_ratios); i++)
+               if (ratio == spdif_sysclk_ratios[i])
+                       break;
+       if (i == ARRAY_SIZE(spdif_sysclk_ratios)) {
+               dev_err(spdif->dev, "Invalid clock ratio %ld/%d\n",
+                               spdif->clk_rate, params_rate(params));
+               goto err;
+       }
+
+       con &= ~CON_MCLKDIV_MASK;
+       switch (ratio) {
+       case 256:
+               con |= CON_MCLKDIV_256FS;
+               break;
+       case 384:
+               con |= CON_MCLKDIV_384FS;
+               break;
+       case 512:
+               con |= CON_MCLKDIV_512FS;
+               break;
+       }
+
+       cstas &= ~CSTAS_SAMP_FREQ_MASK;
+       switch (params_rate(params)) {
+       case 44100:
+               cstas |= CSTAS_SAMP_FREQ_44;
+               break;
+       case 48000:
+               cstas |= CSTAS_SAMP_FREQ_48;
+               break;
+       case 32000:
+               cstas |= CSTAS_SAMP_FREQ_32;
+               break;
+       case 96000:
+               cstas |= CSTAS_SAMP_FREQ_96;
+               break;
+       default:
+               dev_err(spdif->dev, "Invalid sampling rate %d\n",
+                               params_rate(params));
+               goto err;
+       }
+
+       cstas &= ~CSTAS_CATEGORY_MASK;
+       cstas |= CSTAS_CATEGORY_CODE_CDP;
+       cstas |= CSTAS_NO_COPYRIGHT;
+
+       writel(con, regs + CON);
+       writel(cstas, regs + CSTAS);
+       writel(clkcon, regs + CLKCON);
+
+       spin_unlock_irqrestore(&spdif->lock, flags);
+
+       return 0;
+err:
+       spin_unlock_irqrestore(&spdif->lock, flags);
+       return -EINVAL;
+}
+
+static void spdif_shutdown(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct samsung_spdif_info *spdif = to_info(rtd->cpu_dai);
+       void __iomem *regs = spdif->regs;
+       u32 con, clkcon;
+
+       dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+       con = readl(regs + CON) & CON_MASK;
+       clkcon = readl(regs + CLKCON) & CLKCTL_MASK;
+
+       writel(con | CON_SW_RESET, regs + CON);
+       cpu_relax();
+
+       writel(clkcon & ~CLKCTL_PWR_ON, regs + CLKCON);
+}
+
+#ifdef CONFIG_PM
+static int spdif_suspend(struct snd_soc_dai *cpu_dai)
+{
+       struct samsung_spdif_info *spdif = to_info(cpu_dai);
+       u32 con = spdif->saved_con;
+
+       dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+       spdif->saved_clkcon = readl(spdif->regs + CLKCON) & CLKCTL_MASK;
+       spdif->saved_con = readl(spdif->regs + CON) & CON_MASK;
+       spdif->saved_cstas = readl(spdif->regs + CSTAS) & CSTAS_MASK;
+
+       writel(con | CON_SW_RESET, spdif->regs + CON);
+       cpu_relax();
+
+       return 0;
+}
+
+static int spdif_resume(struct snd_soc_dai *cpu_dai)
+{
+       struct samsung_spdif_info *spdif = to_info(cpu_dai);
+
+       dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+       writel(spdif->saved_clkcon, spdif->regs + CLKCON);
+       writel(spdif->saved_con, spdif->regs + CON);
+       writel(spdif->saved_cstas, spdif->regs + CSTAS);
+
+       return 0;
+}
+#else
+#define spdif_suspend NULL
+#define spdif_resume NULL
+#endif
+
+static struct snd_soc_dai_ops spdif_dai_ops = {
+       .set_sysclk     = spdif_set_sysclk,
+       .trigger        = spdif_trigger,
+       .hw_params      = spdif_hw_params,
+       .shutdown       = spdif_shutdown,
+};
+
+struct snd_soc_dai_driver samsung_spdif_dai = {
+       .name = "samsung-spdif",
+       .playback = {
+               .stream_name = "S/PDIF Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = (SNDRV_PCM_RATE_32000 |
+                               SNDRV_PCM_RATE_44100 |
+                               SNDRV_PCM_RATE_48000 |
+                               SNDRV_PCM_RATE_96000),
+               .formats = SNDRV_PCM_FMTBIT_S16_LE, },
+       .ops = &spdif_dai_ops,
+       .suspend = spdif_suspend,
+       .resume = spdif_resume,
+};
+
+static __devinit int spdif_probe(struct platform_device *pdev)
+{
+       struct s3c_audio_pdata *spdif_pdata;
+       struct resource *mem_res, *dma_res;
+       struct samsung_spdif_info *spdif;
+       int ret;
+
+       spdif_pdata = pdev->dev.platform_data;
+
+       dev_dbg(&pdev->dev, "Entered %s\n", __func__);
+
+       dma_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (!dma_res) {
+               dev_err(&pdev->dev, "Unable to get dma resource.\n");
+               return -ENXIO;
+       }
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem_res) {
+               dev_err(&pdev->dev, "Unable to get register resource.\n");
+               return -ENXIO;
+       }
+
+       if (spdif_pdata && spdif_pdata->cfg_gpio
+                       && spdif_pdata->cfg_gpio(pdev)) {
+               dev_err(&pdev->dev, "Unable to configure GPIO pins\n");
+               return -EINVAL;
+       }
+
+       spdif = &spdif_info;
+       spdif->dev = &pdev->dev;
+
+       spin_lock_init(&spdif->lock);
+
+       spdif->pclk = clk_get(&pdev->dev, "spdif");
+       if (IS_ERR(spdif->pclk)) {
+               dev_err(&pdev->dev, "failed to get peri-clock\n");
+               ret = -ENOENT;
+               goto err0;
+       }
+       clk_enable(spdif->pclk);
+
+       spdif->sclk = clk_get(&pdev->dev, "sclk_spdif");
+       if (IS_ERR(spdif->sclk)) {
+               dev_err(&pdev->dev, "failed to get internal source clock\n");
+               ret = -ENOENT;
+               goto err1;
+       }
+       clk_enable(spdif->sclk);
+
+       /* Request S/PDIF Register's memory region */
+       if (!request_mem_region(mem_res->start,
+                               resource_size(mem_res), "samsung-spdif")) {
+               dev_err(&pdev->dev, "Unable to request register region\n");
+               ret = -EBUSY;
+               goto err2;
+       }
+
+       spdif->regs = ioremap(mem_res->start, 0x100);
+       if (spdif->regs == NULL) {
+               dev_err(&pdev->dev, "Cannot ioremap registers\n");
+               ret = -ENXIO;
+               goto err3;
+       }
+
+       dev_set_drvdata(&pdev->dev, spdif);
+
+       ret = snd_soc_register_dai(&pdev->dev, &samsung_spdif_dai);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "fail to register dai\n");
+               goto err4;
+       }
+
+       spdif_stereo_out.dma_size = 2;
+       spdif_stereo_out.client = &spdif_dma_client_out;
+       spdif_stereo_out.dma_addr = mem_res->start + DATA_OUTBUF;
+       spdif_stereo_out.channel = dma_res->start;
+
+       spdif->dma_playback = &spdif_stereo_out;
+
+       return 0;
+
+err4:
+       iounmap(spdif->regs);
+err3:
+       release_mem_region(mem_res->start, resource_size(mem_res));
+err2:
+       clk_disable(spdif->sclk);
+       clk_put(spdif->sclk);
+err1:
+       clk_disable(spdif->pclk);
+       clk_put(spdif->pclk);
+err0:
+       return ret;
+}
+
+static __devexit int spdif_remove(struct platform_device *pdev)
+{
+       struct samsung_spdif_info *spdif = &spdif_info;
+       struct resource *mem_res;
+
+       snd_soc_unregister_dai(&pdev->dev);
+
+       iounmap(spdif->regs);
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (mem_res)
+               release_mem_region(mem_res->start, resource_size(mem_res));
+
+       clk_disable(spdif->sclk);
+       clk_put(spdif->sclk);
+       clk_disable(spdif->pclk);
+       clk_put(spdif->pclk);
+
+       return 0;
+}
+
+static struct platform_driver samsung_spdif_driver = {
+       .probe  = spdif_probe,
+       .remove = spdif_remove,
+       .driver = {
+               .name   = "samsung-spdif",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init spdif_init(void)
+{
+       return platform_driver_register(&samsung_spdif_driver);
+}
+module_init(spdif_init);
+
+static void __exit spdif_exit(void)
+{
+       platform_driver_unregister(&samsung_spdif_driver);
+}
+module_exit(spdif_exit);
+
+MODULE_AUTHOR("Seungwhan Youn, <sw.youn@samsung.com>");
+MODULE_DESCRIPTION("Samsung S/PDIF Controller Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-spdif");
diff --git a/sound/soc/samsung/spdif.h b/sound/soc/samsung/spdif.h
new file mode 100644 (file)
index 0000000..4f72cb4
--- /dev/null
@@ -0,0 +1,19 @@
+/* sound/soc/samsung/spdif.h
+ *
+ * ALSA SoC Audio Layer - Samsung S/PDIF Controller driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ *             http://www.samsung.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 __SND_SOC_SAMSUNG_SPDIF_H
+#define __SND_SOC_SAMSUNG_SPDIF_H      __FILE__
+
+#define SND_SOC_SPDIF_INT_MCLK         0
+#define SND_SOC_SPDIF_EXT_MCLK         1
+
+#endif /* __SND_SOC_SAMSUNG_SPDIF_H */
index 7f0a496..d8e06a6 100644 (file)
@@ -48,7 +48,7 @@ config SND_SH7760_AC97
 
 config SND_FSI_AK4642
        tristate "FSI-AK4642 sound support"
-       depends on SND_SOC_SH4_FSI && I2C_SH_MOBILE
+       depends on SND_SOC_SH4_FSI && I2C
        select SND_SOC_AK4642
        help
          This option enables generic sound support for the
@@ -56,7 +56,7 @@ config SND_FSI_AK4642
 
 config SND_FSI_DA7210
        tristate "FSI-DA7210 sound support"
-       depends on SND_SOC_SH4_FSI && I2C_SH_MOBILE
+       depends on SND_SOC_SH4_FSI && I2C
        select SND_SOC_DA7210
        help
          This option enables generic sound support for the
index d96602d..a14820a 100644 (file)
 #include <linux/platform_device.h>
 #include <sound/sh_fsi.h>
 
+struct fsi_ak4642_data {
+       const char *name;
+       const char *card;
+       const char *cpu_dai;
+       const char *codec;
+       const char *platform;
+};
+
 static int fsi_ak4642_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_dai *dai = rtd->codec_dai;
@@ -27,37 +35,42 @@ static int fsi_ak4642_dai_init(struct snd_soc_pcm_runtime *rtd)
 }
 
 static struct snd_soc_dai_link fsi_dai_link = {
-       .name           = "AK4642",
-       .stream_name    = "AK4642",
-       .cpu_dai_name   = "fsia-dai", /* fsi A */
        .codec_dai_name = "ak4642-hifi",
-#ifdef CONFIG_MACH_AP4EVB
-       .platform_name  = "sh_fsi2",
-       .codec_name     = "ak4642-codec.0-0013",
-#else
-       .platform_name  = "sh_fsi.0",
-       .codec_name     = "ak4642-codec.0-0012",
-#endif
        .init           = fsi_ak4642_dai_init,
-       .ops            = NULL,
 };
 
 static struct snd_soc_card fsi_soc_card  = {
-       .name           = "FSI (AK4642)",
        .dai_link       = &fsi_dai_link,
        .num_links      = 1,
 };
 
 static struct platform_device *fsi_snd_device;
 
-static int __init fsi_ak4642_init(void)
+static int fsi_ak4642_probe(struct platform_device *pdev)
 {
        int ret = -ENOMEM;
+       const struct platform_device_id *id_entry;
+       struct fsi_ak4642_data *pdata;
+
+       id_entry = pdev->id_entry;
+       if (!id_entry) {
+               dev_err(&pdev->dev, "unknown fsi ak4642\n");
+               return -ENODEV;
+       }
+
+       pdata = (struct fsi_ak4642_data *)id_entry->driver_data;
 
        fsi_snd_device = platform_device_alloc("soc-audio", FSI_PORT_A);
        if (!fsi_snd_device)
                goto out;
 
+       fsi_dai_link.name               = pdata->name;
+       fsi_dai_link.stream_name        = pdata->name;
+       fsi_dai_link.cpu_dai_name       = pdata->cpu_dai;
+       fsi_dai_link.platform_name      = pdata->platform;
+       fsi_dai_link.codec_name         = pdata->codec;
+       fsi_soc_card.name               = pdata->card;
+
        platform_set_drvdata(fsi_snd_device, &fsi_soc_card);
        ret = platform_device_add(fsi_snd_device);
 
@@ -68,9 +81,108 @@ out:
        return ret;
 }
 
-static void __exit fsi_ak4642_exit(void)
+static int fsi_ak4642_remove(struct platform_device *pdev)
 {
        platform_device_unregister(fsi_snd_device);
+       return 0;
+}
+
+static struct fsi_ak4642_data fsi_a_ak4642 = {
+       .name           = "AK4642",
+       .card           = "FSIA (AK4642)",
+       .cpu_dai        = "fsia-dai",
+       .codec          = "ak4642-codec.0-0012",
+       .platform       = "sh_fsi.0",
+};
+
+static struct fsi_ak4642_data fsi_b_ak4642 = {
+       .name           = "AK4642",
+       .card           = "FSIB (AK4642)",
+       .cpu_dai        = "fsib-dai",
+       .codec          = "ak4642-codec.0-0012",
+       .platform       = "sh_fsi.0",
+};
+
+static struct fsi_ak4642_data fsi_a_ak4643 = {
+       .name           = "AK4643",
+       .card           = "FSIA (AK4643)",
+       .cpu_dai        = "fsia-dai",
+       .codec          = "ak4642-codec.0-0013",
+       .platform       = "sh_fsi.0",
+};
+
+static struct fsi_ak4642_data fsi_b_ak4643 = {
+       .name           = "AK4643",
+       .card           = "FSIB (AK4643)",
+       .cpu_dai        = "fsib-dai",
+       .codec          = "ak4642-codec.0-0013",
+       .platform       = "sh_fsi.0",
+};
+
+static struct fsi_ak4642_data fsi2_a_ak4642 = {
+       .name           = "AK4642",
+       .card           = "FSI2A (AK4642)",
+       .cpu_dai        = "fsia-dai",
+       .codec          = "ak4642-codec.0-0012",
+       .platform       = "sh_fsi2",
+};
+
+static struct fsi_ak4642_data fsi2_b_ak4642 = {
+       .name           = "AK4642",
+       .card           = "FSI2B (AK4642)",
+       .cpu_dai        = "fsib-dai",
+       .codec          = "ak4642-codec.0-0012",
+       .platform       = "sh_fsi2",
+};
+
+static struct fsi_ak4642_data fsi2_a_ak4643 = {
+       .name           = "AK4643",
+       .card           = "FSI2A (AK4643)",
+       .cpu_dai        = "fsia-dai",
+       .codec          = "ak4642-codec.0-0013",
+       .platform       = "sh_fsi2",
+};
+
+static struct fsi_ak4642_data fsi2_b_ak4643 = {
+       .name           = "AK4643",
+       .card           = "FSI2B (AK4643)",
+       .cpu_dai        = "fsib-dai",
+       .codec          = "ak4642-codec.0-0013",
+       .platform       = "sh_fsi2",
+};
+
+static struct platform_device_id fsi_id_table[] = {
+       /* FSI */
+       { "sh_fsi_a_ak4642",    (kernel_ulong_t)&fsi_a_ak4642 },
+       { "sh_fsi_b_ak4642",    (kernel_ulong_t)&fsi_b_ak4642 },
+       { "sh_fsi_a_ak4643",    (kernel_ulong_t)&fsi_a_ak4643 },
+       { "sh_fsi_b_ak4643",    (kernel_ulong_t)&fsi_b_ak4643 },
+
+       /* FSI 2 */
+       { "sh_fsi2_a_ak4642",   (kernel_ulong_t)&fsi2_a_ak4642 },
+       { "sh_fsi2_b_ak4642",   (kernel_ulong_t)&fsi2_b_ak4642 },
+       { "sh_fsi2_a_ak4643",   (kernel_ulong_t)&fsi2_a_ak4643 },
+       { "sh_fsi2_b_ak4643",   (kernel_ulong_t)&fsi2_b_ak4643 },
+       {},
+};
+
+static struct platform_driver fsi_ak4642 = {
+       .driver = {
+               .name   = "fsi-ak4642-audio",
+       },
+       .probe          = fsi_ak4642_probe,
+       .remove         = fsi_ak4642_remove,
+       .id_table       = fsi_id_table,
+};
+
+static int __init fsi_ak4642_init(void)
+{
+       return platform_driver_register(&fsi_ak4642);
+}
+
+static void __exit fsi_ak4642_exit(void)
+{
+       platform_driver_unregister(&fsi_ak4642);
 }
 
 module_init(fsi_ak4642_init);
index a6adb6e..e8df9da 100644 (file)
@@ -18,7 +18,7 @@ static int fsi_da7210_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_dai *dai = rtd->codec_dai;
 
        return snd_soc_dai_set_fmt(dai,
-                                  SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                                  SND_SOC_DAIFMT_I2S |
                                   SND_SOC_DAIFMT_CBM_CFM);
 }
 
index 4c2404b..2b06402 100644 (file)
 #include <sound/soc.h>
 #include <sound/sh_fsi.h>
 
-#define DO_FMT         0x0000
-#define DOFF_CTL       0x0004
-#define DOFF_ST                0x0008
-#define DI_FMT         0x000C
-#define DIFF_CTL       0x0010
-#define DIFF_ST                0x0014
-#define CKG1           0x0018
-#define CKG2           0x001C
-#define DIDT           0x0020
-#define DODT           0x0024
-#define MUTE_ST                0x0028
-#define OUT_SEL                0x0030
-#define REG_END                OUT_SEL
-
+/* PortA/PortB register */
+#define REG_DO_FMT     0x0000
+#define REG_DOFF_CTL   0x0004
+#define REG_DOFF_ST    0x0008
+#define REG_DI_FMT     0x000C
+#define REG_DIFF_CTL   0x0010
+#define REG_DIFF_ST    0x0014
+#define REG_CKG1       0x0018
+#define REG_CKG2       0x001C
+#define REG_DIDT       0x0020
+#define REG_DODT       0x0024
+#define REG_MUTE_ST    0x0028
+#define REG_OUT_SEL    0x0030
+
+/* master register */
+#define MST_CLK_RST    0x0210
+#define MST_SOFT_RST   0x0214
+#define MST_FIFO_SZ    0x0218
+
+/* core register (depend on FSI version) */
 #define A_MST_CTLR     0x0180
 #define B_MST_CTLR     0x01A0
 #define CPU_INT_ST     0x01F4
 #define INT_ST         0x0200
 #define IEMSK          0x0204
 #define IMSK           0x0208
-#define MUTE           0x020C
-#define CLK_RST                0x0210
-#define SOFT_RST       0x0214
-#define FIFO_SZ                0x0218
-#define MREG_START     A_MST_CTLR
-#define MREG_END       FIFO_SZ
 
 /* DO_FMT */
 /* DI_FMT */
+#define CR_BWS_24      (0x0 << 20) /* FSI2 */
+#define CR_BWS_16      (0x1 << 20) /* FSI2 */
+#define CR_BWS_20      (0x2 << 20) /* FSI2 */
+
+#define CR_DTMD_PCM            (0x0 << 8) /* FSI2 */
+#define CR_DTMD_SPDIF_PCM      (0x1 << 8) /* FSI2 */
+#define CR_DTMD_SPDIF_STREAM   (0x2 << 8) /* FSI2 */
+
 #define CR_MONO                (0x0 << 4)
 #define CR_MONO_D      (0x1 << 4)
 #define CR_PCM         (0x2 << 4)
 #define CR_I2S         (0x3 << 4)
 #define CR_TDM         (0x4 << 4)
 #define CR_TDM_D       (0x5 << 4)
-#define CR_SPDIF       0x00100120
 
 /* DOFF_CTL */
 /* DIFF_CTL */
 #define IR             (1 <<  4) /* Interrupt Reset */
 #define FSISR          (1 <<  0) /* Software Reset */
 
+/* OUT_SEL (FSI2) */
+#define DMMD           (1 << 4) /* SPDIF output timing 0: Biphase only */
+                                /*                     1: Biphase and serial */
+
 /* FIFO_SZ */
 #define FIFO_SZ_MASK   0x7
 
@@ -123,6 +134,9 @@ struct fsi_stream {
        int buff_len;
        int period_len;
        int period_num;
+
+       int uerr_num;
+       int oerr_num;
 };
 
 struct fsi_priv {
@@ -133,8 +147,6 @@ struct fsi_priv {
        struct fsi_stream capture;
 
        long rate;
-
-       u32 mst_ctrl;
 };
 
 struct fsi_core {
@@ -143,6 +155,8 @@ struct fsi_core {
        u32 int_st;
        u32 iemsk;
        u32 imsk;
+       u32 a_mclk;
+       u32 b_mclk;
 };
 
 struct fsi_master {
@@ -182,62 +196,22 @@ static void __fsi_reg_mask_set(u32 reg, u32 mask, u32 data)
        __fsi_reg_write(reg, val);
 }
 
-static void fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data)
-{
-       if (reg > REG_END) {
-               pr_err("fsi: register access err (%s)\n", __func__);
-               return;
-       }
+#define fsi_reg_write(p, r, d)\
+       __fsi_reg_write((u32)(p->base + REG_##r), d)
 
-       __fsi_reg_write((u32)(fsi->base + reg), data);
-}
+#define fsi_reg_read(p, r)\
+       __fsi_reg_read((u32)(p->base + REG_##r))
 
-static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg)
-{
-       if (reg > REG_END) {
-               pr_err("fsi: register access err (%s)\n", __func__);
-               return 0;
-       }
+#define fsi_reg_mask_set(p, r, m, d)\
+       __fsi_reg_mask_set((u32)(p->base + REG_##r), m, d)
 
-       return __fsi_reg_read((u32)(fsi->base + reg));
-}
-
-static void fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data)
-{
-       if (reg > REG_END) {
-               pr_err("fsi: register access err (%s)\n", __func__);
-               return;
-       }
-
-       __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data);
-}
-
-static void fsi_master_write(struct fsi_master *master, u32 reg, u32 data)
-{
-       unsigned long flags;
-
-       if ((reg < MREG_START) ||
-           (reg > MREG_END)) {
-               pr_err("fsi: register access err (%s)\n", __func__);
-               return;
-       }
-
-       spin_lock_irqsave(&master->lock, flags);
-       __fsi_reg_write((u32)(master->base + reg), data);
-       spin_unlock_irqrestore(&master->lock, flags);
-}
-
-static u32 fsi_master_read(struct fsi_master *master, u32 reg)
+#define fsi_master_read(p, r) _fsi_master_read(p, MST_##r)
+#define fsi_core_read(p, r)   _fsi_master_read(p, p->core->r)
+static u32 _fsi_master_read(struct fsi_master *master, u32 reg)
 {
        u32 ret;
        unsigned long flags;
 
-       if ((reg < MREG_START) ||
-           (reg > MREG_END)) {
-               pr_err("fsi: register access err (%s)\n", __func__);
-               return 0;
-       }
-
        spin_lock_irqsave(&master->lock, flags);
        ret = __fsi_reg_read((u32)(master->base + reg));
        spin_unlock_irqrestore(&master->lock, flags);
@@ -245,17 +219,13 @@ static u32 fsi_master_read(struct fsi_master *master, u32 reg)
        return ret;
 }
 
-static void fsi_master_mask_set(struct fsi_master *master,
+#define fsi_master_mask_set(p, r, m, d) _fsi_master_mask_set(p, MST_##r, m, d)
+#define fsi_core_mask_set(p, r, m, d)  _fsi_master_mask_set(p, p->core->r, m, d)
+static void _fsi_master_mask_set(struct fsi_master *master,
                               u32 reg, u32 mask, u32 data)
 {
        unsigned long flags;
 
-       if ((reg < MREG_START) ||
-           (reg > MREG_END)) {
-               pr_err("fsi: register access err (%s)\n", __func__);
-               return;
-       }
-
        spin_lock_irqsave(&master->lock, flags);
        __fsi_reg_mask_set((u32)(master->base + reg), mask, data);
        spin_unlock_irqrestore(&master->lock, flags);
@@ -359,27 +329,41 @@ static void fsi_stream_push(struct fsi_priv *fsi,
        io->buff_offset = 0;
        io->period_len  = period_len;
        io->period_num  = 0;
+       io->oerr_num    = -1; /* ignore 1st err */
+       io->uerr_num    = -1; /* ignore 1st err */
 }
 
 static void fsi_stream_pop(struct fsi_priv *fsi, int is_play)
 {
        struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+       struct snd_soc_dai *dai = fsi_get_dai(io->substream);
+
+
+       if (io->oerr_num > 0)
+               dev_err(dai->dev, "over_run = %d\n", io->oerr_num);
+
+       if (io->uerr_num > 0)
+               dev_err(dai->dev, "under_run = %d\n", io->uerr_num);
 
        io->substream   = NULL;
        io->buff_len    = 0;
        io->buff_offset = 0;
        io->period_len  = 0;
        io->period_num  = 0;
+       io->oerr_num    = 0;
+       io->uerr_num    = 0;
 }
 
 static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play)
 {
        u32 status;
-       u32 reg = is_play ? DOFF_ST : DIFF_ST;
        struct fsi_stream *io = fsi_get_stream(fsi, is_play);
        int data_num;
 
-       status = fsi_reg_read(fsi, reg);
+       status = is_play ?
+               fsi_reg_read(fsi, DOFF_ST) :
+               fsi_reg_read(fsi, DIFF_ST);
+
        data_num = 0x1ff & (status >> 8);
        data_num *= io->chan_num;
 
@@ -406,6 +390,27 @@ static int fsi_get_frame_width(struct fsi_priv *fsi, int is_play)
        return frames_to_bytes(runtime, 1) / io->chan_num;
 }
 
+static void fsi_count_fifo_err(struct fsi_priv *fsi)
+{
+       u32 ostatus = fsi_reg_read(fsi, DOFF_ST);
+       u32 istatus = fsi_reg_read(fsi, DIFF_ST);
+
+       if (ostatus & ERR_OVER)
+               fsi->playback.oerr_num++;
+
+       if (ostatus & ERR_UNDER)
+               fsi->playback.uerr_num++;
+
+       if (istatus & ERR_OVER)
+               fsi->capture.oerr_num++;
+
+       if (istatus & ERR_UNDER)
+               fsi->capture.uerr_num++;
+
+       fsi_reg_write(fsi, DOFF_ST, 0);
+       fsi_reg_write(fsi, DIFF_ST, 0);
+}
+
 /*
  *             dma function
  */
@@ -473,8 +478,8 @@ static void fsi_irq_enable(struct fsi_priv *fsi, int is_play)
        u32 data = AB_IO(1, fsi_get_port_shift(fsi, is_play));
        struct fsi_master *master = fsi_get_master(fsi);
 
-       fsi_master_mask_set(master, master->core->imsk,  data, data);
-       fsi_master_mask_set(master, master->core->iemsk, data, data);
+       fsi_core_mask_set(master, imsk,  data, data);
+       fsi_core_mask_set(master, iemsk, data, data);
 }
 
 static void fsi_irq_disable(struct fsi_priv *fsi, int is_play)
@@ -482,18 +487,13 @@ static void fsi_irq_disable(struct fsi_priv *fsi, int is_play)
        u32 data = AB_IO(1, fsi_get_port_shift(fsi, is_play));
        struct fsi_master *master = fsi_get_master(fsi);
 
-       fsi_master_mask_set(master, master->core->imsk,  data, 0);
-       fsi_master_mask_set(master, master->core->iemsk, data, 0);
+       fsi_core_mask_set(master, imsk,  data, 0);
+       fsi_core_mask_set(master, iemsk, data, 0);
 }
 
 static u32 fsi_irq_get_status(struct fsi_master *master)
 {
-       return fsi_master_read(master, master->core->int_st);
-}
-
-static void fsi_irq_clear_all_status(struct fsi_master *master)
-{
-       fsi_master_write(master, master->core->int_st, 0);
+       return fsi_core_read(master, int_st);
 }
 
 static void fsi_irq_clear_status(struct fsi_priv *fsi)
@@ -505,7 +505,7 @@ static void fsi_irq_clear_status(struct fsi_priv *fsi)
        data |= AB_IO(1, fsi_get_port_shift(fsi, 1));
 
        /* clear interrupt factor */
-       fsi_master_mask_set(master, master->core->int_st, data, 0);
+       fsi_core_mask_set(master, int_st, data, 0);
 }
 
 /*
@@ -516,17 +516,19 @@ static void fsi_irq_clear_status(struct fsi_priv *fsi)
 static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
 {
        struct fsi_master *master = fsi_get_master(fsi);
-       u32 val = BP | SE;
+       u32 mask, val;
 
        if (master->core->ver < 2) {
                pr_err("fsi: register access err (%s)\n", __func__);
                return;
        }
 
-       if (enable)
-               fsi_master_mask_set(master, fsi->mst_ctrl, val, val);
-       else
-               fsi_master_mask_set(master, fsi->mst_ctrl, val, 0);
+       mask = BP | SE;
+       val = enable ? mask : 0;
+
+       fsi_is_port_a(fsi) ?
+               fsi_core_mask_set(master, a_mclk, mask, val) :
+               fsi_core_mask_set(master, b_mclk, mask, val);
 }
 
 /*
@@ -550,7 +552,7 @@ static void fsi_fifo_init(struct fsi_priv *fsi,
 {
        struct fsi_master *master = fsi_get_master(fsi);
        struct fsi_stream *io = fsi_get_stream(fsi, is_play);
-       u32 ctrl, shift, i;
+       u32 shift, i;
 
        /* get on-chip RAM capacity */
        shift = fsi_master_read(master, FIFO_SZ);
@@ -583,13 +585,17 @@ static void fsi_fifo_init(struct fsi_priv *fsi,
        dev_dbg(dai->dev, "%d channel %d store\n",
                io->chan_num, io->fifo_max_num);
 
-       ctrl = is_play ? DOFF_CTL : DIFF_CTL;
-
-       /* set interrupt generation factor */
-       fsi_reg_write(fsi, ctrl, IRQ_HALF);
-
-       /* clear FIFO */
-       fsi_reg_mask_set(fsi, ctrl, FIFO_CLR, FIFO_CLR);
+       /*
+        * set interrupt generation factor
+        * clear FIFO
+        */
+       if (is_play) {
+               fsi_reg_write(fsi,      DOFF_CTL, IRQ_HALF);
+               fsi_reg_mask_set(fsi,   DOFF_CTL, FIFO_CLR, FIFO_CLR);
+       } else {
+               fsi_reg_write(fsi,      DIFF_CTL, IRQ_HALF);
+               fsi_reg_mask_set(fsi,   DIFF_CTL, FIFO_CLR, FIFO_CLR);
+       }
 }
 
 static void fsi_soft_all_reset(struct fsi_master *master)
@@ -604,13 +610,12 @@ static void fsi_soft_all_reset(struct fsi_master *master)
        mdelay(10);
 }
 
-static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int startup, int stream)
+static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream)
 {
        struct snd_pcm_runtime *runtime;
        struct snd_pcm_substream *substream = NULL;
        int is_play = fsi_stream_is_play(stream);
        struct fsi_stream *io = fsi_get_stream(fsi, is_play);
-       u32 status_reg = is_play ? DOFF_ST : DIFF_ST;
        int data_residue_num;
        int data_num;
        int data_num_max;
@@ -698,35 +703,20 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int startup, int stream)
        /* update buff_offset */
        io->buff_offset += fsi_num2offset(data_num, ch_width);
 
-       /* check fifo status */
-       if (!startup) {
-               struct snd_soc_dai *dai = fsi_get_dai(substream);
-               u32 status = fsi_reg_read(fsi, status_reg);
-
-               if (status & ERR_OVER)
-                       dev_err(dai->dev, "over run\n");
-               if (status & ERR_UNDER)
-                       dev_err(dai->dev, "under run\n");
-       }
-       fsi_reg_write(fsi, status_reg, 0);
-
-       /* re-enable irq */
-       fsi_irq_enable(fsi, is_play);
-
        if (over_period)
                snd_pcm_period_elapsed(substream);
 
        return 0;
 }
 
-static int fsi_data_pop(struct fsi_priv *fsi, int startup)
+static int fsi_data_pop(struct fsi_priv *fsi)
 {
-       return fsi_fifo_data_ctrl(fsi, startup, SNDRV_PCM_STREAM_CAPTURE);
+       return fsi_fifo_data_ctrl(fsi, SNDRV_PCM_STREAM_CAPTURE);
 }
 
-static int fsi_data_push(struct fsi_priv *fsi, int startup)
+static int fsi_data_push(struct fsi_priv *fsi)
 {
-       return fsi_fifo_data_ctrl(fsi, startup, SNDRV_PCM_STREAM_PLAYBACK);
+       return fsi_fifo_data_ctrl(fsi, SNDRV_PCM_STREAM_PLAYBACK);
 }
 
 static irqreturn_t fsi_interrupt(int irq, void *data)
@@ -739,15 +729,19 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
        fsi_master_mask_set(master, SOFT_RST, IR, IR);
 
        if (int_st & AB_IO(1, AO_SHIFT))
-               fsi_data_push(&master->fsia, 0);
+               fsi_data_push(&master->fsia);
        if (int_st & AB_IO(1, BO_SHIFT))
-               fsi_data_push(&master->fsib, 0);
+               fsi_data_push(&master->fsib);
        if (int_st & AB_IO(1, AI_SHIFT))
-               fsi_data_pop(&master->fsia, 0);
+               fsi_data_pop(&master->fsia);
        if (int_st & AB_IO(1, BI_SHIFT))
-               fsi_data_pop(&master->fsib, 0);
+               fsi_data_pop(&master->fsib);
+
+       fsi_count_fifo_err(&master->fsia);
+       fsi_count_fifo_err(&master->fsib);
 
-       fsi_irq_clear_all_status(master);
+       fsi_irq_clear_status(&master->fsia);
+       fsi_irq_clear_status(&master->fsib);
 
        return IRQ_HANDLED;
 }
@@ -764,7 +758,6 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
        struct fsi_stream *io;
        u32 flags = fsi_get_info_flags(fsi);
        u32 fmt;
-       u32 reg;
        u32 data;
        int is_play = fsi_is_play(substream);
        int is_master;
@@ -796,7 +789,6 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
 
        /* do fmt, di fmt */
        data = 0;
-       reg = is_play ? DO_FMT : DI_FMT;
        fmt = is_play ? SH_FSI_GET_OFMT(flags) : SH_FSI_GET_IFMT(flags);
        switch (fmt) {
        case SH_FSI_FMT_MONO:
@@ -830,16 +822,18 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
                        dev_err(dai->dev, "This FSI can not use SPDIF\n");
                        return -EINVAL;
                }
-               data = CR_SPDIF;
+               data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM;
                io->chan_num = 2;
                fsi_spdif_clk_ctrl(fsi, 1);
-               fsi_reg_mask_set(fsi, OUT_SEL, 0x0010, 0x0010);
+               fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD);
                break;
        default:
                dev_err(dai->dev, "unknown format.\n");
                return -EINVAL;
        }
-       fsi_reg_write(fsi, reg, data);
+       is_play ?
+               fsi_reg_write(fsi, DO_FMT, data) :
+               fsi_reg_write(fsi, DI_FMT, data);
 
        /* irq clear */
        fsi_irq_disable(fsi, is_play);
@@ -883,7 +877,8 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
                fsi_stream_push(fsi, is_play, substream,
                                frames_to_bytes(runtime, runtime->buffer_size),
                                frames_to_bytes(runtime, runtime->period_size));
-               ret = is_play ? fsi_data_push(fsi, 1) : fsi_data_pop(fsi, 1);
+               ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi);
+               fsi_irq_enable(fsi, is_play);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
                fsi_irq_disable(fsi, is_play);
@@ -1174,12 +1169,10 @@ static int fsi_probe(struct platform_device *pdev)
        /* FSI A setting */
        master->fsia.base       = master->base;
        master->fsia.master     = master;
-       master->fsia.mst_ctrl   = A_MST_CTLR;
 
        /* FSI B setting */
        master->fsib.base       = master->base + 0x40;
        master->fsib.master     = master;
-       master->fsib.mst_ctrl   = B_MST_CTLR;
 
        pm_runtime_enable(&pdev->dev);
        pm_runtime_resume(&pdev->dev);
@@ -1266,6 +1259,8 @@ static struct fsi_core fsi2_core = {
        .int_st = CPU_INT_ST,
        .iemsk  = CPU_IEMSK,
        .imsk   = CPU_IMSK,
+       .a_mclk = A_MST_CTLR,
+       .b_mclk = B_MST_CTLR,
 };
 
 static struct platform_device_id fsi_id_table[] = {
index ac6c49c..6088a6a 100644 (file)
@@ -8,11 +8,11 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/clkdev.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
 #include <linux/module.h>
 
-#include <asm/clkdev.h>
 #include <asm/clock.h>
 
 #include <cpu/sh7722.h>
@@ -20,7 +20,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 
 #include "../codecs/wm8978.h"
 #include "siu.h"
@@ -140,11 +139,12 @@ static const struct snd_soc_dapm_route audio_map[] = {
 static int migor_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
 
-       snd_soc_dapm_new_controls(codec, migor_dapm_widgets,
+       snd_soc_dapm_new_controls(dapm, migor_dapm_widgets,
                                  ARRAY_SIZE(migor_dapm_widgets));
 
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
 }
index f8e0ab8..917d3ce 100644 (file)
@@ -12,7 +12,6 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <asm/io.h>
 
 #define IPSEL 0xFE400034
@@ -23,7 +22,7 @@ extern struct snd_soc_platform_driver sh7760_soc_platform;
 
 static int machine_init(struct snd_soc_pcm_runtime *rtd)
 {
-       snd_soc_dapm_sync(rtd->codec);
+       snd_soc_dapm_sync(&rtd->codec->dapm);
        return 0;
 }
 
index 9f4dcb9..83c3430 100644 (file)
@@ -75,7 +75,7 @@ struct siu_firmware {
 
 #include <sound/core.h>
 #include <sound/pcm.h>
-#include <sound/soc-dai.h>
+#include <sound/soc.h>
 
 #define SIU_PERIOD_BYTES_MAX   8192            /* DMA transfer/period size */
 #define SIU_PERIOD_BYTES_MIN   256             /* DMA transfer/period size */
index af53b64..4973c29 100644 (file)
@@ -28,7 +28,7 @@
 #include <asm/siu.h>
 
 #include <sound/control.h>
-#include <sound/soc-dai.h>
+#include <sound/soc.h>
 
 #include "siu.h"
 
index ed29c9e..a423bab 100644 (file)
@@ -29,7 +29,7 @@
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
-#include <sound/soc-dai.h>
+#include <sound/soc.h>
 
 #include <asm/siu.h>
 
index d214f02..8c2a21a 100644 (file)
 #include <linux/i2c.h>
 #include <linux/spi/spi.h>
 #include <sound/soc.h>
+#include <linux/lzo.h>
+#include <linux/bitmap.h>
+#include <linux/rbtree.h>
 
 static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
                                     unsigned int reg)
 {
-       u16 *cache = codec->reg_cache;
+       int ret;
+       unsigned int val;
 
        if (reg >= codec->driver->reg_cache_size ||
                snd_soc_codec_volatile_register(codec, reg)) {
                        if (codec->cache_only)
                                return -1;
 
+                       BUG_ON(!codec->hw_read);
                        return codec->hw_read(codec, reg);
        }
 
-       return cache[reg];
+       ret = snd_soc_cache_read(codec, reg, &val);
+       if (ret < 0)
+               return -1;
+       return val;
 }
 
 static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
                             unsigned int value)
 {
-       u16 *cache = codec->reg_cache;
        u8 data[2];
        int ret;
 
@@ -42,16 +49,17 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
        data[1] = value & 0x00ff;
 
        if (!snd_soc_codec_volatile_register(codec, reg) &&
-               reg < codec->driver->reg_cache_size)
-                       cache[reg] = value;
+               reg < codec->driver->reg_cache_size) {
+               ret = snd_soc_cache_write(codec, reg, value);
+               if (ret < 0)
+                       return -1;
+       }
 
        if (codec->cache_only) {
                codec->cache_sync = 1;
                return 0;
        }
 
-       dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value);
-
        ret = codec->hw_write(codec->control_data, data, 2);
        if (ret == 2)
                return 0;
@@ -77,7 +85,7 @@ static int snd_soc_4_12_spi_write(void *control_data, const char *data,
        msg[1] = data[0];
 
        spi_message_init(&m);
-       memset(&t, 0, (sizeof t));
+       memset(&t, 0, sizeof t);
 
        t.tx_buf = &msg[0];
        t.len = len;
@@ -94,23 +102,27 @@ static int snd_soc_4_12_spi_write(void *control_data, const char *data,
 static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
                                     unsigned int reg)
 {
-       u16 *cache = codec->reg_cache;
+       int ret;
+       unsigned int val;
 
        if (reg >= codec->driver->reg_cache_size ||
                snd_soc_codec_volatile_register(codec, reg)) {
                        if (codec->cache_only)
                                return -1;
 
+                       BUG_ON(!codec->hw_read);
                        return codec->hw_read(codec, reg);
        }
 
-       return cache[reg];
+       ret = snd_soc_cache_read(codec, reg, &val);
+       if (ret < 0)
+               return -1;
+       return val;
 }
 
 static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
                             unsigned int value)
 {
-       u16 *cache = codec->reg_cache;
        u8 data[2];
        int ret;
 
@@ -118,16 +130,17 @@ static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
        data[1] = value & 0x00ff;
 
        if (!snd_soc_codec_volatile_register(codec, reg) &&
-               reg < codec->driver->reg_cache_size)
-                       cache[reg] = value;
+               reg < codec->driver->reg_cache_size) {
+               ret = snd_soc_cache_write(codec, reg, value);
+               if (ret < 0)
+                       return -1;
+       }
 
        if (codec->cache_only) {
                codec->cache_sync = 1;
                return 0;
        }
 
-       dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value);
-
        ret = codec->hw_write(codec->control_data, data, 2);
        if (ret == 2)
                return 0;
@@ -153,7 +166,7 @@ static int snd_soc_7_9_spi_write(void *control_data, const char *data,
        msg[1] = data[1];
 
        spi_message_init(&m);
-       memset(&t, 0, (sizeof t));
+       memset(&t, 0, sizeof t);
 
        t.tx_buf = &msg[0];
        t.len = len;
@@ -170,24 +183,25 @@ static int snd_soc_7_9_spi_write(void *control_data, const char *data,
 static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
                             unsigned int value)
 {
-       u8 *cache = codec->reg_cache;
        u8 data[2];
+       int ret;
 
        reg &= 0xff;
        data[0] = reg;
        data[1] = value & 0xff;
 
        if (!snd_soc_codec_volatile_register(codec, reg) &&
-               reg < codec->driver->reg_cache_size)
-                       cache[reg] = value;
+               reg < codec->driver->reg_cache_size) {
+               ret = snd_soc_cache_write(codec, reg, value);
+               if (ret < 0)
+                       return -1;
+       }
 
        if (codec->cache_only) {
                codec->cache_sync = 1;
                return 0;
        }
 
-       dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value);
-
        if (codec->hw_write(codec->control_data, data, 2) == 2)
                return 0;
        else
@@ -197,7 +211,8 @@ static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
 static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
                                     unsigned int reg)
 {
-       u8 *cache = codec->reg_cache;
+       int ret;
+       unsigned int val;
 
        reg &= 0xff;
        if (reg >= codec->driver->reg_cache_size ||
@@ -205,10 +220,14 @@ static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
                        if (codec->cache_only)
                                return -1;
 
+                       BUG_ON(!codec->hw_read);
                        return codec->hw_read(codec, reg);
        }
 
-       return cache[reg];
+       ret = snd_soc_cache_read(codec, reg, &val);
+       if (ret < 0)
+               return -1;
+       return val;
 }
 
 #if defined(CONFIG_SPI_MASTER)
@@ -227,7 +246,7 @@ static int snd_soc_8_8_spi_write(void *control_data, const char *data,
        msg[1] = data[1];
 
        spi_message_init(&m);
-       memset(&t, 0, (sizeof t));
+       memset(&t, 0, sizeof t);
 
        t.tx_buf = &msg[0];
        t.len = len;
@@ -244,24 +263,25 @@ static int snd_soc_8_8_spi_write(void *control_data, const char *data,
 static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
                              unsigned int value)
 {
-       u16 *reg_cache = codec->reg_cache;
        u8 data[3];
+       int ret;
 
        data[0] = reg;
        data[1] = (value >> 8) & 0xff;
        data[2] = value & 0xff;
 
        if (!snd_soc_codec_volatile_register(codec, reg) &&
-           reg < codec->driver->reg_cache_size)
-               reg_cache[reg] = value;
+               reg < codec->driver->reg_cache_size) {
+               ret = snd_soc_cache_write(codec, reg, value);
+               if (ret < 0)
+                       return -1;
+       }
 
        if (codec->cache_only) {
                codec->cache_sync = 1;
                return 0;
        }
 
-       dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value);
-
        if (codec->hw_write(codec->control_data, data, 3) == 3)
                return 0;
        else
@@ -271,17 +291,22 @@ static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
 static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
                                      unsigned int reg)
 {
-       u16 *cache = codec->reg_cache;
+       int ret;
+       unsigned int val;
 
        if (reg >= codec->driver->reg_cache_size ||
            snd_soc_codec_volatile_register(codec, reg)) {
                if (codec->cache_only)
                        return -1;
 
+               BUG_ON(!codec->hw_read);
                return codec->hw_read(codec, reg);
-       } else {
-               return cache[reg];
        }
+
+       ret = snd_soc_cache_read(codec, reg, &val);
+       if (ret < 0)
+               return -1;
+       return val;
 }
 
 #if defined(CONFIG_SPI_MASTER)
@@ -301,7 +326,7 @@ static int snd_soc_8_16_spi_write(void *control_data, const char *data,
        msg[2] = data[2];
 
        spi_message_init(&m);
-       memset(&t, 0, (sizeof t));
+       memset(&t, 0, sizeof t);
 
        t.tx_buf = &msg[0];
        t.len = len;
@@ -420,7 +445,8 @@ static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
 static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
                                     unsigned int reg)
 {
-       u8 *cache = codec->reg_cache;
+       int ret;
+       unsigned int val;
 
        reg &= 0xff;
        if (reg >= codec->driver->reg_cache_size ||
@@ -428,16 +454,19 @@ static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
                        if (codec->cache_only)
                                return -1;
 
+                       BUG_ON(!codec->hw_read);
                        return codec->hw_read(codec, reg);
        }
 
-       return cache[reg];
+       ret = snd_soc_cache_read(codec, reg, &val);
+       if (ret < 0)
+               return -1;
+       return val;
 }
 
 static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
                             unsigned int value)
 {
-       u8 *cache = codec->reg_cache;
        u8 data[3];
        int ret;
 
@@ -447,16 +476,17 @@ static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
 
        reg &= 0xff;
        if (!snd_soc_codec_volatile_register(codec, reg) &&
-               reg < codec->driver->reg_cache_size)
-                       cache[reg] = value;
+               reg < codec->driver->reg_cache_size) {
+               ret = snd_soc_cache_write(codec, reg, value);
+               if (ret < 0)
+                       return -1;
+       }
 
        if (codec->cache_only) {
                codec->cache_sync = 1;
                return 0;
        }
 
-       dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value);
-
        ret = codec->hw_write(codec->control_data, data, 3);
        if (ret == 3)
                return 0;
@@ -483,7 +513,7 @@ static int snd_soc_16_8_spi_write(void *control_data, const char *data,
        msg[2] = data[2];
 
        spi_message_init(&m);
-       memset(&t, 0, (sizeof t));
+       memset(&t, 0, sizeof t);
 
        t.tx_buf = &msg[0];
        t.len = len;
@@ -534,23 +564,28 @@ static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
 static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
                                       unsigned int reg)
 {
-       u16 *cache = codec->reg_cache;
+       int ret;
+       unsigned int val;
 
        if (reg >= codec->driver->reg_cache_size ||
            snd_soc_codec_volatile_register(codec, reg)) {
                if (codec->cache_only)
                        return -1;
 
+               BUG_ON(!codec->hw_read);
                return codec->hw_read(codec, reg);
        }
 
-       return cache[reg];
+       ret = snd_soc_cache_read(codec, reg, &val);
+       if (ret < 0)
+               return -1;
+
+       return val;
 }
 
 static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
                               unsigned int value)
 {
-       u16 *cache = codec->reg_cache;
        u8 data[4];
        int ret;
 
@@ -560,16 +595,17 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
        data[3] = value & 0xff;
 
        if (!snd_soc_codec_volatile_register(codec, reg) &&
-               reg < codec->driver->reg_cache_size)
-                       cache[reg] = value;
+               reg < codec->driver->reg_cache_size) {
+               ret = snd_soc_cache_write(codec, reg, value);
+               if (ret < 0)
+                       return -1;
+       }
 
        if (codec->cache_only) {
                codec->cache_sync = 1;
                return 0;
        }
 
-       dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value);
-
        ret = codec->hw_write(codec->control_data, data, 4);
        if (ret == 4)
                return 0;
@@ -597,7 +633,7 @@ static int snd_soc_16_16_spi_write(void *control_data, const char *data,
        msg[3] = data[3];
 
        spi_message_init(&m);
-       memset(&t, 0, (sizeof t));
+       memset(&t, 0, sizeof t);
 
        t.tx_buf = &msg[0];
        t.len = len;
@@ -692,8 +728,8 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
                return -EINVAL;
        }
 
-       codec->driver->write = io_types[i].write;
-       codec->driver->read = io_types[i].read;
+       codec->write = io_types[i].write;
+       codec->read = io_types[i].read;
 
        switch (control) {
        case SND_SOC_CUSTOM:
@@ -724,3 +760,930 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
+
+struct snd_soc_rbtree_node {
+       struct rb_node node;
+       unsigned int reg;
+       unsigned int value;
+       unsigned int defval;
+} __attribute__ ((packed));
+
+struct snd_soc_rbtree_ctx {
+       struct rb_root root;
+};
+
+static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup(
+       struct rb_root *root, unsigned int reg)
+{
+       struct rb_node *node;
+       struct snd_soc_rbtree_node *rbnode;
+
+       node = root->rb_node;
+       while (node) {
+               rbnode = container_of(node, struct snd_soc_rbtree_node, node);
+               if (rbnode->reg < reg)
+                       node = node->rb_left;
+               else if (rbnode->reg > reg)
+                       node = node->rb_right;
+               else
+                       return rbnode;
+       }
+
+       return NULL;
+}
+
+static int snd_soc_rbtree_insert(struct rb_root *root,
+                                struct snd_soc_rbtree_node *rbnode)
+{
+       struct rb_node **new, *parent;
+       struct snd_soc_rbtree_node *rbnode_tmp;
+
+       parent = NULL;
+       new = &root->rb_node;
+       while (*new) {
+               rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node,
+                                         node);
+               parent = *new;
+               if (rbnode_tmp->reg < rbnode->reg)
+                       new = &((*new)->rb_left);
+               else if (rbnode_tmp->reg > rbnode->reg)
+                       new = &((*new)->rb_right);
+               else
+                       return 0;
+       }
+
+       /* insert the node into the rbtree */
+       rb_link_node(&rbnode->node, parent, new);
+       rb_insert_color(&rbnode->node, root);
+
+       return 1;
+}
+
+static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
+{
+       struct snd_soc_rbtree_ctx *rbtree_ctx;
+       struct rb_node *node;
+       struct snd_soc_rbtree_node *rbnode;
+       unsigned int val;
+       int ret;
+
+       rbtree_ctx = codec->reg_cache;
+       for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
+               rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
+               if (rbnode->value == rbnode->defval)
+                       continue;
+               ret = snd_soc_cache_read(codec, rbnode->reg, &val);
+               if (ret)
+                       return ret;
+               ret = snd_soc_write(codec, rbnode->reg, val);
+               if (ret)
+                       return ret;
+               dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
+                       rbnode->reg, val);
+       }
+
+       return 0;
+}
+
+static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec,
+                                     unsigned int reg, unsigned int value)
+{
+       struct snd_soc_rbtree_ctx *rbtree_ctx;
+       struct snd_soc_rbtree_node *rbnode;
+
+       rbtree_ctx = codec->reg_cache;
+       rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
+       if (rbnode) {
+               if (rbnode->value == value)
+                       return 0;
+               rbnode->value = value;
+       } else {
+               /* bail out early, no need to create the rbnode yet */
+               if (!value)
+                       return 0;
+               /*
+                * for uninitialized registers whose value is changed
+                * from the default zero, create an rbnode and insert
+                * it into the tree.
+                */
+               rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
+               if (!rbnode)
+                       return -ENOMEM;
+               rbnode->reg = reg;
+               rbnode->value = value;
+               snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode);
+       }
+
+       return 0;
+}
+
+static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec,
+                                    unsigned int reg, unsigned int *value)
+{
+       struct snd_soc_rbtree_ctx *rbtree_ctx;
+       struct snd_soc_rbtree_node *rbnode;
+
+       rbtree_ctx = codec->reg_cache;
+       rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
+       if (rbnode) {
+               *value = rbnode->value;
+       } else {
+               /* uninitialized registers default to 0 */
+               *value = 0;
+       }
+
+       return 0;
+}
+
+static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
+{
+       struct rb_node *next;
+       struct snd_soc_rbtree_ctx *rbtree_ctx;
+       struct snd_soc_rbtree_node *rbtree_node;
+
+       /* if we've already been called then just return */
+       rbtree_ctx = codec->reg_cache;
+       if (!rbtree_ctx)
+               return 0;
+
+       /* free up the rbtree */
+       next = rb_first(&rbtree_ctx->root);
+       while (next) {
+               rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node);
+               next = rb_next(&rbtree_node->node);
+               rb_erase(&rbtree_node->node, &rbtree_ctx->root);
+               kfree(rbtree_node);
+       }
+
+       /* release the resources */
+       kfree(codec->reg_cache);
+       codec->reg_cache = NULL;
+
+       return 0;
+}
+
+static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
+{
+       struct snd_soc_rbtree_ctx *rbtree_ctx;
+
+       codec->reg_cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL);
+       if (!codec->reg_cache)
+               return -ENOMEM;
+
+       rbtree_ctx = codec->reg_cache;
+       rbtree_ctx->root = RB_ROOT;
+
+       if (!codec->reg_def_copy)
+               return 0;
+
+/*
+ * populate the rbtree with the initialized registers.  All other
+ * registers will be inserted into the tree when they are first written.
+ *
+ * The reasoning behind this, is that we need to step through and
+ * dereference the cache in u8/u16 increments without sacrificing
+ * portability.  This could also be done using memcpy() but that would
+ * be slightly more cryptic.
+ */
+#define snd_soc_rbtree_populate(cache)                                 \
+({                                                                     \
+       int ret, i;                                                     \
+       struct snd_soc_rbtree_node *rbtree_node;                        \
+                                                                       \
+       ret = 0;                                                        \
+       cache = codec->reg_def_copy;                                    \
+       for (i = 0; i < codec->driver->reg_cache_size; ++i) {           \
+               if (!cache[i])                                          \
+                       continue;                                       \
+               rbtree_node = kzalloc(sizeof *rbtree_node, GFP_KERNEL); \
+               if (!rbtree_node) {                                     \
+                       ret = -ENOMEM;                                  \
+                       snd_soc_cache_exit(codec);                      \
+                       break;                                          \
+               }                                                       \
+               rbtree_node->reg = i;                                   \
+               rbtree_node->value = cache[i];                          \
+               rbtree_node->defval = cache[i];                         \
+               snd_soc_rbtree_insert(&rbtree_ctx->root,                \
+                                     rbtree_node);                     \
+       }                                                               \
+       ret;                                                            \
+})
+
+       switch (codec->driver->reg_word_size) {
+       case 1: {
+               const u8 *cache;
+
+               return snd_soc_rbtree_populate(cache);
+       }
+       case 2: {
+               const u16 *cache;
+
+               return snd_soc_rbtree_populate(cache);
+       }
+       default:
+               BUG();
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_SND_SOC_CACHE_LZO
+struct snd_soc_lzo_ctx {
+       void *wmem;
+       void *dst;
+       const void *src;
+       size_t src_len;
+       size_t dst_len;
+       size_t decompressed_size;
+       unsigned long *sync_bmp;
+       int sync_bmp_nbits;
+};
+
+#define LZO_BLOCK_NUM 8
+static int snd_soc_lzo_block_count(void)
+{
+       return LZO_BLOCK_NUM;
+}
+
+static int snd_soc_lzo_prepare(struct snd_soc_lzo_ctx *lzo_ctx)
+{
+       lzo_ctx->wmem = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
+       if (!lzo_ctx->wmem)
+               return -ENOMEM;
+       return 0;
+}
+
+static int snd_soc_lzo_compress(struct snd_soc_lzo_ctx *lzo_ctx)
+{
+       size_t compress_size;
+       int ret;
+
+       ret = lzo1x_1_compress(lzo_ctx->src, lzo_ctx->src_len,
+                              lzo_ctx->dst, &compress_size, lzo_ctx->wmem);
+       if (ret != LZO_E_OK || compress_size > lzo_ctx->dst_len)
+               return -EINVAL;
+       lzo_ctx->dst_len = compress_size;
+       return 0;
+}
+
+static int snd_soc_lzo_decompress(struct snd_soc_lzo_ctx *lzo_ctx)
+{
+       size_t dst_len;
+       int ret;
+
+       dst_len = lzo_ctx->dst_len;
+       ret = lzo1x_decompress_safe(lzo_ctx->src, lzo_ctx->src_len,
+                                   lzo_ctx->dst, &dst_len);
+       if (ret != LZO_E_OK || dst_len != lzo_ctx->dst_len)
+               return -EINVAL;
+       return 0;
+}
+
+static int snd_soc_lzo_compress_cache_block(struct snd_soc_codec *codec,
+               struct snd_soc_lzo_ctx *lzo_ctx)
+{
+       int ret;
+
+       lzo_ctx->dst_len = lzo1x_worst_compress(PAGE_SIZE);
+       lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
+       if (!lzo_ctx->dst) {
+               lzo_ctx->dst_len = 0;
+               return -ENOMEM;
+       }
+
+       ret = snd_soc_lzo_compress(lzo_ctx);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+static int snd_soc_lzo_decompress_cache_block(struct snd_soc_codec *codec,
+               struct snd_soc_lzo_ctx *lzo_ctx)
+{
+       int ret;
+
+       lzo_ctx->dst_len = lzo_ctx->decompressed_size;
+       lzo_ctx->dst = kmalloc(lzo_ctx->dst_len, GFP_KERNEL);
+       if (!lzo_ctx->dst) {
+               lzo_ctx->dst_len = 0;
+               return -ENOMEM;
+       }
+
+       ret = snd_soc_lzo_decompress(lzo_ctx);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+static inline int snd_soc_lzo_get_blkindex(struct snd_soc_codec *codec,
+               unsigned int reg)
+{
+       const struct snd_soc_codec_driver *codec_drv;
+       size_t reg_size;
+
+       codec_drv = codec->driver;
+       reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
+       return (reg * codec_drv->reg_word_size) /
+              DIV_ROUND_UP(reg_size, snd_soc_lzo_block_count());
+}
+
+static inline int snd_soc_lzo_get_blkpos(struct snd_soc_codec *codec,
+               unsigned int reg)
+{
+       const struct snd_soc_codec_driver *codec_drv;
+       size_t reg_size;
+
+       codec_drv = codec->driver;
+       reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
+       return reg % (DIV_ROUND_UP(reg_size, snd_soc_lzo_block_count()) /
+                     codec_drv->reg_word_size);
+}
+
+static inline int snd_soc_lzo_get_blksize(struct snd_soc_codec *codec)
+{
+       const struct snd_soc_codec_driver *codec_drv;
+       size_t reg_size;
+
+       codec_drv = codec->driver;
+       reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
+       return DIV_ROUND_UP(reg_size, snd_soc_lzo_block_count());
+}
+
+static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec)
+{
+       struct snd_soc_lzo_ctx **lzo_blocks;
+       unsigned int val;
+       int i;
+       int ret;
+
+       lzo_blocks = codec->reg_cache;
+       for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
+               ret = snd_soc_cache_read(codec, i, &val);
+               if (ret)
+                       return ret;
+               ret = snd_soc_write(codec, i, val);
+               if (ret)
+                       return ret;
+               dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
+                       i, val);
+       }
+
+       return 0;
+}
+
+static int snd_soc_lzo_cache_write(struct snd_soc_codec *codec,
+                                  unsigned int reg, unsigned int value)
+{
+       struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks;
+       int ret, blkindex, blkpos;
+       size_t blksize, tmp_dst_len;
+       void *tmp_dst;
+
+       /* index of the compressed lzo block */
+       blkindex = snd_soc_lzo_get_blkindex(codec, reg);
+       /* register index within the decompressed block */
+       blkpos = snd_soc_lzo_get_blkpos(codec, reg);
+       /* size of the compressed block */
+       blksize = snd_soc_lzo_get_blksize(codec);
+       lzo_blocks = codec->reg_cache;
+       lzo_block = lzo_blocks[blkindex];
+
+       /* save the pointer and length of the compressed block */
+       tmp_dst = lzo_block->dst;
+       tmp_dst_len = lzo_block->dst_len;
+
+       /* prepare the source to be the compressed block */
+       lzo_block->src = lzo_block->dst;
+       lzo_block->src_len = lzo_block->dst_len;
+
+       /* decompress the block */
+       ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
+       if (ret < 0) {
+               kfree(lzo_block->dst);
+               goto out;
+       }
+
+       /* write the new value to the cache */
+       switch (codec->driver->reg_word_size) {
+       case 1: {
+               u8 *cache;
+               cache = lzo_block->dst;
+               if (cache[blkpos] == value) {
+                       kfree(lzo_block->dst);
+                       goto out;
+               }
+               cache[blkpos] = value;
+       }
+       break;
+       case 2: {
+               u16 *cache;
+               cache = lzo_block->dst;
+               if (cache[blkpos] == value) {
+                       kfree(lzo_block->dst);
+                       goto out;
+               }
+               cache[blkpos] = value;
+       }
+       break;
+       default:
+               BUG();
+       }
+
+       /* prepare the source to be the decompressed block */
+       lzo_block->src = lzo_block->dst;
+       lzo_block->src_len = lzo_block->dst_len;
+
+       /* compress the block */
+       ret = snd_soc_lzo_compress_cache_block(codec, lzo_block);
+       if (ret < 0) {
+               kfree(lzo_block->dst);
+               kfree(lzo_block->src);
+               goto out;
+       }
+
+       /* set the bit so we know we have to sync this register */
+       set_bit(reg, lzo_block->sync_bmp);
+       kfree(tmp_dst);
+       kfree(lzo_block->src);
+       return 0;
+out:
+       lzo_block->dst = tmp_dst;
+       lzo_block->dst_len = tmp_dst_len;
+       return ret;
+}
+
+static int snd_soc_lzo_cache_read(struct snd_soc_codec *codec,
+                                 unsigned int reg, unsigned int *value)
+{
+       struct snd_soc_lzo_ctx *lzo_block, **lzo_blocks;
+       int ret, blkindex, blkpos;
+       size_t blksize, tmp_dst_len;
+       void *tmp_dst;
+
+       *value = 0;
+       /* index of the compressed lzo block */
+       blkindex = snd_soc_lzo_get_blkindex(codec, reg);
+       /* register index within the decompressed block */
+       blkpos = snd_soc_lzo_get_blkpos(codec, reg);
+       /* size of the compressed block */
+       blksize = snd_soc_lzo_get_blksize(codec);
+       lzo_blocks = codec->reg_cache;
+       lzo_block = lzo_blocks[blkindex];
+
+       /* save the pointer and length of the compressed block */
+       tmp_dst = lzo_block->dst;
+       tmp_dst_len = lzo_block->dst_len;
+
+       /* prepare the source to be the compressed block */
+       lzo_block->src = lzo_block->dst;
+       lzo_block->src_len = lzo_block->dst_len;
+
+       /* decompress the block */
+       ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block);
+       if (ret >= 0) {
+               /* fetch the value from the cache */
+               switch (codec->driver->reg_word_size) {
+               case 1: {
+                       u8 *cache;
+                       cache = lzo_block->dst;
+                       *value = cache[blkpos];
+               }
+               break;
+               case 2: {
+                       u16 *cache;
+                       cache = lzo_block->dst;
+                       *value = cache[blkpos];
+               }
+               break;
+               default:
+                       BUG();
+               }
+       }
+
+       kfree(lzo_block->dst);
+       /* restore the pointer and length of the compressed block */
+       lzo_block->dst = tmp_dst;
+       lzo_block->dst_len = tmp_dst_len;
+       return 0;
+}
+
+static int snd_soc_lzo_cache_exit(struct snd_soc_codec *codec)
+{
+       struct snd_soc_lzo_ctx **lzo_blocks;
+       int i, blkcount;
+
+       lzo_blocks = codec->reg_cache;
+       if (!lzo_blocks)
+               return 0;
+
+       blkcount = snd_soc_lzo_block_count();
+       /*
+        * the pointer to the bitmap used for syncing the cache
+        * is shared amongst all lzo_blocks.  Ensure it is freed
+        * only once.
+        */
+       if (lzo_blocks[0])
+               kfree(lzo_blocks[0]->sync_bmp);
+       for (i = 0; i < blkcount; ++i) {
+               if (lzo_blocks[i]) {
+                       kfree(lzo_blocks[i]->wmem);
+                       kfree(lzo_blocks[i]->dst);
+               }
+               /* each lzo_block is a pointer returned by kmalloc or NULL */
+               kfree(lzo_blocks[i]);
+       }
+       kfree(lzo_blocks);
+       codec->reg_cache = NULL;
+       return 0;
+}
+
+static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec)
+{
+       struct snd_soc_lzo_ctx **lzo_blocks;
+       size_t reg_size, bmp_size;
+       const struct snd_soc_codec_driver *codec_drv;
+       int ret, tofree, i, blksize, blkcount;
+       const char *p, *end;
+       unsigned long *sync_bmp;
+
+       ret = 0;
+       codec_drv = codec->driver;
+       reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
+
+       /*
+        * If we have not been given a default register cache
+        * then allocate a dummy zero-ed out region, compress it
+        * and remember to free it afterwards.
+        */
+       tofree = 0;
+       if (!codec->reg_def_copy)
+               tofree = 1;
+
+       if (!codec->reg_def_copy) {
+               codec->reg_def_copy = kzalloc(reg_size,
+                                                      GFP_KERNEL);
+               if (!codec->reg_def_copy)
+                       return -ENOMEM;
+       }
+
+       blkcount = snd_soc_lzo_block_count();
+       codec->reg_cache = kzalloc(blkcount * sizeof *lzo_blocks,
+                                  GFP_KERNEL);
+       if (!codec->reg_cache) {
+               ret = -ENOMEM;
+               goto err_tofree;
+       }
+       lzo_blocks = codec->reg_cache;
+
+       /*
+        * allocate a bitmap to be used when syncing the cache with
+        * the hardware.  Each time a register is modified, the corresponding
+        * bit is set in the bitmap, so we know that we have to sync
+        * that register.
+        */
+       bmp_size = codec_drv->reg_cache_size;
+       sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long),
+                          GFP_KERNEL);
+       if (!sync_bmp) {
+               ret = -ENOMEM;
+               goto err;
+       }
+       bitmap_zero(sync_bmp, bmp_size);
+
+       /* allocate the lzo blocks and initialize them */
+       for (i = 0; i < blkcount; ++i) {
+               lzo_blocks[i] = kzalloc(sizeof **lzo_blocks,
+                                       GFP_KERNEL);
+               if (!lzo_blocks[i]) {
+                       kfree(sync_bmp);
+                       ret = -ENOMEM;
+                       goto err;
+               }
+               lzo_blocks[i]->sync_bmp = sync_bmp;
+               lzo_blocks[i]->sync_bmp_nbits = bmp_size;
+               /* alloc the working space for the compressed block */
+               ret = snd_soc_lzo_prepare(lzo_blocks[i]);
+               if (ret < 0)
+                       goto err;
+       }
+
+       blksize = snd_soc_lzo_get_blksize(codec);
+       p = codec->reg_def_copy;
+       end = codec->reg_def_copy + reg_size;
+       /* compress the register map and fill the lzo blocks */
+       for (i = 0; i < blkcount; ++i, p += blksize) {
+               lzo_blocks[i]->src = p;
+               if (p + blksize > end)
+                       lzo_blocks[i]->src_len = end - p;
+               else
+                       lzo_blocks[i]->src_len = blksize;
+               ret = snd_soc_lzo_compress_cache_block(codec,
+                                                      lzo_blocks[i]);
+               if (ret < 0)
+                       goto err;
+               lzo_blocks[i]->decompressed_size =
+                       lzo_blocks[i]->src_len;
+       }
+
+       if (tofree) {
+               kfree(codec->reg_def_copy);
+               codec->reg_def_copy = NULL;
+       }
+       return 0;
+err:
+       snd_soc_cache_exit(codec);
+err_tofree:
+       if (tofree) {
+               kfree(codec->reg_def_copy);
+               codec->reg_def_copy = NULL;
+       }
+       return ret;
+}
+#endif
+
+static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
+{
+       int i;
+       int ret;
+       const struct snd_soc_codec_driver *codec_drv;
+       unsigned int val;
+
+       codec_drv = codec->driver;
+       for (i = 0; i < codec_drv->reg_cache_size; ++i) {
+               ret = snd_soc_cache_read(codec, i, &val);
+               if (ret)
+                       return ret;
+               if (codec_drv->reg_cache_default) {
+                       switch (codec_drv->reg_word_size) {
+                       case 1: {
+                               const u8 *cache;
+
+                               cache = codec_drv->reg_cache_default;
+                               if (cache[i] == val)
+                                       continue;
+                       }
+                       break;
+                       case 2: {
+                               const u16 *cache;
+
+                               cache = codec_drv->reg_cache_default;
+                               if (cache[i] == val)
+                                       continue;
+                       }
+                       break;
+                       default:
+                               BUG();
+                       }
+               }
+               ret = snd_soc_write(codec, i, val);
+               if (ret)
+                       return ret;
+               dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
+                       i, val);
+       }
+       return 0;
+}
+
+static int snd_soc_flat_cache_write(struct snd_soc_codec *codec,
+                                   unsigned int reg, unsigned int value)
+{
+       switch (codec->driver->reg_word_size) {
+       case 1: {
+               u8 *cache;
+
+               cache = codec->reg_cache;
+               cache[reg] = value;
+       }
+       break;
+       case 2: {
+               u16 *cache;
+
+               cache = codec->reg_cache;
+               cache[reg] = value;
+       }
+       break;
+       default:
+               BUG();
+       }
+
+       return 0;
+}
+
+static int snd_soc_flat_cache_read(struct snd_soc_codec *codec,
+                                  unsigned int reg, unsigned int *value)
+{
+       switch (codec->driver->reg_word_size) {
+       case 1: {
+               u8 *cache;
+
+               cache = codec->reg_cache;
+               *value = cache[reg];
+       }
+       break;
+       case 2: {
+               u16 *cache;
+
+               cache = codec->reg_cache;
+               *value = cache[reg];
+       }
+       break;
+       default:
+               BUG();
+       }
+
+       return 0;
+}
+
+static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec)
+{
+       if (!codec->reg_cache)
+               return 0;
+       kfree(codec->reg_cache);
+       codec->reg_cache = NULL;
+       return 0;
+}
+
+static int snd_soc_flat_cache_init(struct snd_soc_codec *codec)
+{
+       const struct snd_soc_codec_driver *codec_drv;
+       size_t reg_size;
+
+       codec_drv = codec->driver;
+       reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
+
+       /*
+        * for flat compression, we don't need to keep a copy of the
+        * original defaults register cache as it will definitely not
+        * be marked as __devinitconst
+        */
+       kfree(codec->reg_def_copy);
+       codec->reg_def_copy = NULL;
+
+       if (codec_drv->reg_cache_default)
+               codec->reg_cache = kmemdup(codec_drv->reg_cache_default,
+                                          reg_size, GFP_KERNEL);
+       else
+               codec->reg_cache = kzalloc(reg_size, GFP_KERNEL);
+       if (!codec->reg_cache)
+               return -ENOMEM;
+
+       return 0;
+}
+
+/* an array of all supported compression types */
+static const struct snd_soc_cache_ops cache_types[] = {
+       /* Flat *must* be the first entry for fallback */
+       {
+               .id = SND_SOC_FLAT_COMPRESSION,
+               .name = "flat",
+               .init = snd_soc_flat_cache_init,
+               .exit = snd_soc_flat_cache_exit,
+               .read = snd_soc_flat_cache_read,
+               .write = snd_soc_flat_cache_write,
+               .sync = snd_soc_flat_cache_sync
+       },
+#ifdef CONFIG_SND_SOC_CACHE_LZO
+       {
+               .id = SND_SOC_LZO_COMPRESSION,
+               .name = "LZO",
+               .init = snd_soc_lzo_cache_init,
+               .exit = snd_soc_lzo_cache_exit,
+               .read = snd_soc_lzo_cache_read,
+               .write = snd_soc_lzo_cache_write,
+               .sync = snd_soc_lzo_cache_sync
+       },
+#endif
+       {
+               .id = SND_SOC_RBTREE_COMPRESSION,
+               .name = "rbtree",
+               .init = snd_soc_rbtree_cache_init,
+               .exit = snd_soc_rbtree_cache_exit,
+               .read = snd_soc_rbtree_cache_read,
+               .write = snd_soc_rbtree_cache_write,
+               .sync = snd_soc_rbtree_cache_sync
+       }
+};
+
+int snd_soc_cache_init(struct snd_soc_codec *codec)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(cache_types); ++i)
+               if (cache_types[i].id == codec->compress_type)
+                       break;
+
+       /* Fall back to flat compression */
+       if (i == ARRAY_SIZE(cache_types)) {
+               dev_warn(codec->dev, "Could not match compress type: %d\n",
+                        codec->compress_type);
+               i = 0;
+       }
+
+       mutex_init(&codec->cache_rw_mutex);
+       codec->cache_ops = &cache_types[i];
+
+       if (codec->cache_ops->init) {
+               if (codec->cache_ops->name)
+                       dev_dbg(codec->dev, "Initializing %s cache for %s codec\n",
+                               codec->cache_ops->name, codec->name);
+               return codec->cache_ops->init(codec);
+       }
+       return -EINVAL;
+}
+
+/*
+ * NOTE: keep in mind that this function might be called
+ * multiple times.
+ */
+int snd_soc_cache_exit(struct snd_soc_codec *codec)
+{
+       if (codec->cache_ops && codec->cache_ops->exit) {
+               if (codec->cache_ops->name)
+                       dev_dbg(codec->dev, "Destroying %s cache for %s codec\n",
+                               codec->cache_ops->name, codec->name);
+               return codec->cache_ops->exit(codec);
+       }
+       return -EINVAL;
+}
+
+/**
+ * snd_soc_cache_read: Fetch the value of a given register from the cache.
+ *
+ * @codec: CODEC to configure.
+ * @reg: The register index.
+ * @value: The value to be returned.
+ */
+int snd_soc_cache_read(struct snd_soc_codec *codec,
+                      unsigned int reg, unsigned int *value)
+{
+       int ret;
+
+       mutex_lock(&codec->cache_rw_mutex);
+
+       if (value && codec->cache_ops && codec->cache_ops->read) {
+               ret = codec->cache_ops->read(codec, reg, value);
+               mutex_unlock(&codec->cache_rw_mutex);
+               return ret;
+       }
+
+       mutex_unlock(&codec->cache_rw_mutex);
+       return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_cache_read);
+
+/**
+ * snd_soc_cache_write: Set the value of a given register in the cache.
+ *
+ * @codec: CODEC to configure.
+ * @reg: The register index.
+ * @value: The new register value.
+ */
+int snd_soc_cache_write(struct snd_soc_codec *codec,
+                       unsigned int reg, unsigned int value)
+{
+       int ret;
+
+       mutex_lock(&codec->cache_rw_mutex);
+
+       if (codec->cache_ops && codec->cache_ops->write) {
+               ret = codec->cache_ops->write(codec, reg, value);
+               mutex_unlock(&codec->cache_rw_mutex);
+               return ret;
+       }
+
+       mutex_unlock(&codec->cache_rw_mutex);
+       return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_cache_write);
+
+/**
+ * snd_soc_cache_sync: Sync the register cache with the hardware.
+ *
+ * @codec: CODEC to configure.
+ *
+ * Any registers that should not be synced should be marked as
+ * volatile.  In general drivers can choose not to use the provided
+ * syncing functionality if they so require.
+ */
+int snd_soc_cache_sync(struct snd_soc_codec *codec)
+{
+       int ret;
+
+       if (!codec->cache_sync) {
+               return 0;
+       }
+
+       if (codec->cache_ops && codec->cache_ops->sync) {
+               if (codec->cache_ops->name)
+                       dev_dbg(codec->dev, "Syncing %s cache for %s codec\n",
+                               codec->cache_ops->name, codec->name);
+               ret = codec->cache_ops->sync(codec);
+               if (!ret)
+                       codec->cache_sync = 0;
+               return ret;
+       }
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_cache_sync);
index 85b7d54..bac7291 100644 (file)
 #include <linux/slab.h>
 #include <sound/ac97_codec.h>
 #include <sound/core.h>
+#include <sound/jack.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <sound/initval.h>
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/asoc.h>
+
 #define NAME_SIZE      32
 
 static DEFINE_MUTEX(pcm_mutex);
@@ -67,25 +70,6 @@ static int pmdown_time = 5000;
 module_param(pmdown_time, int, 0);
 MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)");
 
-/*
- * This function forces any delayed work to be queued and run.
- */
-static int run_delayed_work(struct delayed_work *dwork)
-{
-       int ret;
-
-       /* cancel any work waiting to be queued. */
-       ret = cancel_delayed_work(dwork);
-
-       /* if there was any work waiting then we run it now and
-        * wait for it's completion */
-       if (ret) {
-               schedule_delayed_work(dwork, 0);
-               flush_scheduled_work();
-       }
-       return ret;
-}
-
 /* codec register dump */
 static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
 {
@@ -114,7 +98,7 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
                         * the register being volatile and the device being
                         * powered off.
                         */
-                       ret = codec->driver->read(codec, i);
+                       ret = snd_soc_read(codec, i);
                        if (ret >= 0)
                                count += snprintf(buf + count,
                                                  PAGE_SIZE - count,
@@ -225,7 +209,7 @@ static ssize_t codec_reg_write_file(struct file *file,
                start++;
        if (strict_strtoul(start, 16, &value))
                return -EINVAL;
-       codec->driver->write(codec, reg, value);
+       snd_soc_write(codec, reg, value);
        return buf_size;
 }
 
@@ -238,8 +222,10 @@ static const struct file_operations codec_reg_fops = {
 
 static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
 {
-       codec->debugfs_codec_root = debugfs_create_dir(codec->name ,
-                                                      debugfs_root);
+       struct dentry *debugfs_card_root = codec->card->debugfs_card_root;
+
+       codec->debugfs_codec_root = debugfs_create_dir(codec->name,
+                                                      debugfs_card_root);
        if (!codec->debugfs_codec_root) {
                printk(KERN_WARNING
                       "ASoC: Failed to create codec debugfs directory\n");
@@ -253,20 +239,13 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
                printk(KERN_WARNING
                       "ASoC: Failed to create codec register debugfs file\n");
 
-       codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0644,
-                                                    codec->debugfs_codec_root,
-                                                    &codec->pop_time);
-       if (!codec->debugfs_pop_time)
-               printk(KERN_WARNING
-                      "Failed to create pop time debugfs file\n");
-
-       codec->debugfs_dapm = debugfs_create_dir("dapm",
+       codec->dapm.debugfs_dapm = debugfs_create_dir("dapm",
                                                 codec->debugfs_codec_root);
-       if (!codec->debugfs_dapm)
+       if (!codec->dapm.debugfs_dapm)
                printk(KERN_WARNING
                       "Failed to create DAPM debugfs directory\n");
 
-       snd_soc_dapm_debugfs_init(codec);
+       snd_soc_dapm_debugfs_init(&codec->dapm);
 }
 
 static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
@@ -374,6 +353,29 @@ static const struct file_operations platform_list_fops = {
        .llseek = default_llseek,/* read accesses f_pos */
 };
 
+static void soc_init_card_debugfs(struct snd_soc_card *card)
+{
+       card->debugfs_card_root = debugfs_create_dir(card->name,
+                                                    debugfs_root);
+       if (!card->debugfs_card_root) {
+               dev_warn(card->dev,
+                        "ASoC: Failed to create codec debugfs directory\n");
+               return;
+       }
+
+       card->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0644,
+                                                   card->debugfs_card_root,
+                                                   &card->pop_time);
+       if (!card->debugfs_pop_time)
+               dev_warn(card->dev,
+                      "Failed to create pop time debugfs file\n");
+}
+
+static void soc_cleanup_card_debugfs(struct snd_soc_card *card)
+{
+       debugfs_remove_recursive(card->debugfs_card_root);
+}
+
 #else
 
 static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec)
@@ -383,6 +385,14 @@ static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec)
 static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
 {
 }
+
+static inline void soc_init_card_debugfs(struct snd_soc_card *card)
+{
+}
+
+static inline void soc_cleanup_card_debugfs(struct snd_soc_card *card)
+{
+}
 #endif
 
 #ifdef CONFIG_SND_SOC_AC97_BUS
@@ -497,7 +507,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                }
        }
 
-       /* Check that the codec and cpu DAI's are compatible */
+       /* 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,
@@ -846,7 +856,7 @@ codec_err:
 }
 
 /*
- * Free's resources allocated by hw_params, can be called multiple times
+ * Frees resources allocated by hw_params, can be called multiple times
  */
 static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
 {
@@ -870,7 +880,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
        if (platform->driver->ops->hw_free)
                platform->driver->ops->hw_free(substream);
 
-       /* now free hw params for the DAI's  */
+       /* now free hw params for the DAIs  */
        if (codec_dai->driver->ops->hw_free)
                codec_dai->driver->ops->hw_free(substream, codec_dai);
 
@@ -958,6 +968,7 @@ static int soc_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
        int i;
 
        /* If the initialization of this soc device failed, there is no codec
@@ -976,7 +987,7 @@ static int soc_suspend(struct device *dev)
        /* we're going to block userspace touching us until resume completes */
        snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot);
 
-       /* mute any active DAC's */
+       /* mute any active DACs */
        for (i = 0; i < card->num_rtd; i++) {
                struct snd_soc_dai *dai = card->rtd[i].codec_dai;
                struct snd_soc_dai_driver *drv = dai->driver;
@@ -1016,8 +1027,8 @@ static int soc_suspend(struct device *dev)
 
        /* close any waiting streams and save state */
        for (i = 0; i < card->num_rtd; i++) {
-               run_delayed_work(&card->rtd[i].delayed_work);
-               card->rtd[i].codec->suspend_bias_level = card->rtd[i].codec->bias_level;
+               flush_delayed_work_sync(&card->rtd[i].delayed_work);
+               card->rtd[i].codec->dapm.suspend_bias_level = card->rtd[i].codec->dapm.bias_level;
        }
 
        for (i = 0; i < card->num_rtd; i++) {
@@ -1036,12 +1047,11 @@ static int soc_suspend(struct device *dev)
        }
 
        /* suspend all CODECs */
-       for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_codec *codec = card->rtd[i].codec;
+       list_for_each_entry(codec, &card->codec_dev_list, card_list) {
                /* If there are paths active then the CODEC will be held with
                 * bias _ON and should not be suspended. */
                if (!codec->suspended && codec->driver->suspend) {
-                       switch (codec->bias_level) {
+                       switch (codec->dapm.bias_level) {
                        case SND_SOC_BIAS_STANDBY:
                        case SND_SOC_BIAS_OFF:
                                codec->driver->suspend(codec, PMSG_SUSPEND);
@@ -1078,6 +1088,7 @@ static void soc_resume_deferred(struct work_struct *work)
        struct snd_soc_card *card =
                        container_of(work, struct snd_soc_card, deferred_resume_work);
        struct platform_device *pdev = to_platform_device(card->dev);
+       struct snd_soc_codec *codec;
        int i;
 
        /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
@@ -1103,14 +1114,13 @@ static void soc_resume_deferred(struct work_struct *work)
                        cpu_dai->driver->resume(cpu_dai);
        }
 
-       for (i = 0; i < card->num_rtd; i++) {
-               struct snd_soc_codec *codec = card->rtd[i].codec;
+       list_for_each_entry(codec, &card->codec_dev_list, card_list) {
                /* If the CODEC was idle over suspend then it will have been
                 * left with bias OFF or STANDBY and suspended so we must now
                 * resume.  Otherwise the suspend was suppressed.
                 */
                if (codec->driver->resume && codec->suspended) {
-                       switch (codec->bias_level) {
+                       switch (codec->dapm.bias_level) {
                        case SND_SOC_BIAS_STANDBY:
                        case SND_SOC_BIAS_OFF:
                                codec->driver->resume(codec);
@@ -1249,9 +1259,6 @@ find_codec:
                if (!strcmp(codec->name, dai_link->codec_name)) {
                        rtd->codec = codec;
 
-                       if (!try_module_get(codec->dev->driver->owner))
-                               return -ENODEV;
-
                        /* CODEC found, so find CODEC DAI from registered DAIs from this CODEC*/
                        list_for_each_entry(codec_dai, &dai_list, list) {
                                if (codec->dev == codec_dai->dev &&
@@ -1277,10 +1284,6 @@ find_platform:
        /* no, then find CPU DAI from registered DAIs*/
        list_for_each_entry(platform, &platform_list, list) {
                if (!strcmp(platform->name, dai_link->platform_name)) {
-
-                       if (!try_module_get(platform->dev->driver->owner))
-                               return -ENODEV;
-
                        rtd->platform = platform;
                        goto out;
                }
@@ -1299,6 +1302,27 @@ out:
        return 1;
 }
 
+static void soc_remove_codec(struct snd_soc_codec *codec)
+{
+       int err;
+
+       if (codec->driver->remove) {
+               err = codec->driver->remove(codec);
+               if (err < 0)
+                       dev_err(codec->dev,
+                               "asoc: failed to remove %s: %d\n",
+                               codec->name, err);
+       }
+
+       /* Make sure all DAPM widgets are freed */
+       snd_soc_dapm_free(&codec->dapm);
+
+       soc_cleanup_codec_debugfs(codec);
+       codec->probed = 0;
+       list_del(&codec->card_list);
+       module_put(codec->dev->driver->owner);
+}
+
 static void soc_remove_dai_link(struct snd_soc_card *card, int num)
 {
        struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
@@ -1310,6 +1334,7 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num)
        /* unregister the rtd device */
        if (rtd->dev_registered) {
                device_remove_file(&rtd->dev, &dev_attr_pmdown_time);
+               device_remove_file(&rtd->dev, &dev_attr_codec_reg);
                device_unregister(&rtd->dev);
                rtd->dev_registered = 0;
        }
@@ -1338,22 +1363,8 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num)
        }
 
        /* remove the CODEC */
-       if (codec && codec->probed) {
-               if (codec->driver->remove) {
-                       err = codec->driver->remove(codec);
-                       if (err < 0)
-                               printk(KERN_ERR "asoc: failed to remove %s\n", codec->name);
-               }
-
-               /* Make sure all DAPM widgets are freed */
-               snd_soc_dapm_free(codec);
-
-               soc_cleanup_codec_debugfs(codec);
-               device_remove_file(&rtd->dev, &dev_attr_codec_reg);
-               codec->probed = 0;
-               list_del(&codec->card_list);
-               module_put(codec->dev->driver->owner);
-       }
+       if (codec && codec->probed)
+               soc_remove_codec(codec);
 
        /* remove the cpu_dai */
        if (cpu_dai && cpu_dai->probed) {
@@ -1368,8 +1379,126 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num)
        }
 }
 
+static void soc_set_name_prefix(struct snd_soc_card *card,
+                               struct snd_soc_codec *codec)
+{
+       int i;
+
+       if (card->codec_conf == NULL)
+               return;
+
+       for (i = 0; i < card->num_configs; i++) {
+               struct snd_soc_codec_conf *map = &card->codec_conf[i];
+               if (map->dev_name && !strcmp(codec->name, map->dev_name)) {
+                       codec->name_prefix = map->name_prefix;
+                       break;
+               }
+       }
+}
+
+static int soc_probe_codec(struct snd_soc_card *card,
+                          struct snd_soc_codec *codec)
+{
+       int ret = 0;
+
+       codec->card = card;
+       codec->dapm.card = card;
+       soc_set_name_prefix(card, codec);
+
+       if (codec->driver->probe) {
+               ret = codec->driver->probe(codec);
+               if (ret < 0) {
+                       dev_err(codec->dev,
+                               "asoc: failed to probe CODEC %s: %d\n",
+                               codec->name, ret);
+                       return ret;
+               }
+       }
+
+       soc_init_codec_debugfs(codec);
+
+       /* mark codec as probed and add to card codec list */
+       if (!try_module_get(codec->dev->driver->owner))
+               return -ENODEV;
+
+       codec->probed = 1;
+       list_add(&codec->card_list, &card->codec_dev_list);
+       list_add(&codec->dapm.list, &card->dapm_list);
+
+       return ret;
+}
+
 static void rtd_release(struct device *dev) {}
 
+static int soc_post_component_init(struct snd_soc_card *card,
+                                  struct snd_soc_codec *codec,
+                                  int num, int dailess)
+{
+       struct snd_soc_dai_link *dai_link = NULL;
+       struct snd_soc_aux_dev *aux_dev = NULL;
+       struct snd_soc_pcm_runtime *rtd;
+       const char *temp, *name;
+       int ret = 0;
+
+       if (!dailess) {
+               dai_link = &card->dai_link[num];
+               rtd = &card->rtd[num];
+               name = dai_link->name;
+       } else {
+               aux_dev = &card->aux_dev[num];
+               rtd = &card->rtd_aux[num];
+               name = aux_dev->name;
+       }
+
+       /* machine controls, routes and widgets are not prefixed */
+       temp = codec->name_prefix;
+       codec->name_prefix = NULL;
+
+       /* do machine specific initialization */
+       if (!dailess && dai_link->init)
+               ret = dai_link->init(rtd);
+       else if (dailess && aux_dev->init)
+               ret = aux_dev->init(&codec->dapm);
+       if (ret < 0) {
+               dev_err(card->dev, "asoc: failed to init %s: %d\n", name, ret);
+               return ret;
+       }
+       codec->name_prefix = temp;
+
+       /* Make sure all DAPM widgets are instantiated */
+       snd_soc_dapm_new_widgets(&codec->dapm);
+       snd_soc_dapm_sync(&codec->dapm);
+
+       /* register the rtd device */
+       rtd->codec = codec;
+       rtd->card = card;
+       rtd->dev.parent = card->dev;
+       rtd->dev.release = rtd_release;
+       rtd->dev.init_name = name;
+       ret = device_register(&rtd->dev);
+       if (ret < 0) {
+               dev_err(card->dev,
+                       "asoc: failed to register runtime device: %d\n", ret);
+               return ret;
+       }
+       rtd->dev_registered = 1;
+
+       /* add DAPM sysfs entries for this codec */
+       ret = snd_soc_dapm_sys_add(&rtd->dev);
+       if (ret < 0)
+               dev_err(codec->dev,
+                       "asoc: failed to add codec dapm sysfs entries: %d\n",
+                       ret);
+
+       /* add codec sysfs entries */
+       ret = device_create_file(&rtd->dev, &dev_attr_codec_reg);
+       if (ret < 0)
+               dev_err(codec->dev,
+                       "asoc: failed to add codec sysfs files: %d\n", ret);
+
+       return 0;
+}
+
 static int soc_probe_dai_link(struct snd_soc_card *card, int num)
 {
        struct snd_soc_dai_link *dai_link = &card->dai_link[num];
@@ -1383,10 +1512,7 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
 
        /* config components */
        codec_dai->codec = codec;
-       codec->card = card;
        cpu_dai->platform = platform;
-       rtd->card = card;
-       rtd->dev.parent = card->dev;
        codec_dai->card = card;
        cpu_dai->card = card;
 
@@ -1410,20 +1536,9 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
 
        /* probe the CODEC */
        if (!codec->probed) {
-               if (codec->driver->probe) {
-                       ret = codec->driver->probe(codec);
-                       if (ret < 0) {
-                               printk(KERN_ERR "asoc: failed to probe CODEC %s\n",
-                                               codec->name);
-                               return ret;
-                       }
-               }
-
-               soc_init_codec_debugfs(codec);
-
-               /* mark codec as probed and add to card codec list */
-               codec->probed = 1;
-               list_add(&codec->card_list, &card->codec_dev_list);
+               ret = soc_probe_codec(card, codec);
+               if (ret < 0)
+                       return ret;
        }
 
        /* probe the platform */
@@ -1437,6 +1552,10 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
                        }
                }
                /* mark platform as probed and add to card platform list */
+
+               if (!try_module_get(platform->dev->driver->owner))
+                       return -ENODEV;
+
                platform->probed = 1;
                list_add(&platform->card_list, &card->platform_dev_list);
        }
@@ -1460,43 +1579,14 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num)
        /* DAPM dai link stream work */
        INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
 
-       /* now that all clients have probed, initialise the DAI link */
-       if (dai_link->init) {
-               ret = dai_link->init(rtd);
-               if (ret < 0) {
-                       printk(KERN_ERR "asoc: failed to init %s\n", dai_link->stream_name);
-                       return ret;
-               }
-       }
-
-       /* Make sure all DAPM widgets are instantiated */
-       snd_soc_dapm_new_widgets(codec);
-       snd_soc_dapm_sync(codec);
-
-       /* register the rtd device */
-       rtd->dev.release = rtd_release;
-       rtd->dev.init_name = dai_link->name;
-       ret = device_register(&rtd->dev);
-       if (ret < 0) {
-               printk(KERN_ERR "asoc: failed to register DAI runtime device %d\n", ret);
+       ret = soc_post_component_init(card, codec, num, 0);
+       if (ret)
                return ret;
-       }
 
-       rtd->dev_registered = 1;
        ret = device_create_file(&rtd->dev, &dev_attr_pmdown_time);
        if (ret < 0)
                printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs\n");
 
-       /* add DAPM sysfs entries for this codec */
-       ret = snd_soc_dapm_sys_add(&rtd->dev);
-       if (ret < 0)
-               printk(KERN_WARNING "asoc: failed to add codec dapm sysfs entries\n");
-
-       /* add codec sysfs entries */
-       ret = device_create_file(&rtd->dev, &dev_attr_codec_reg);
-       if (ret < 0)
-               printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
-
        /* create the pcm */
        ret = soc_new_pcm(rtd, num);
        if (ret < 0) {
@@ -1551,9 +1641,85 @@ static void soc_unregister_ac97_dai_link(struct snd_soc_codec *codec)
 }
 #endif
 
+static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
+{
+       struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
+       struct snd_soc_codec *codec;
+       int ret = -ENODEV;
+
+       /* find CODEC from registered CODECs*/
+       list_for_each_entry(codec, &codec_list, list) {
+               if (!strcmp(codec->name, aux_dev->codec_name)) {
+                       if (codec->probed) {
+                               dev_err(codec->dev,
+                                       "asoc: codec already probed");
+                               ret = -EBUSY;
+                               goto out;
+                       }
+                       goto found;
+               }
+       }
+       /* codec not found */
+       dev_err(card->dev, "asoc: codec %s not found", aux_dev->codec_name);
+       goto out;
+
+found:
+       if (!try_module_get(codec->dev->driver->owner))
+               return -ENODEV;
+
+       ret = soc_probe_codec(card, codec);
+       if (ret < 0)
+               return ret;
+
+       ret = soc_post_component_init(card, codec, num, 1);
+
+out:
+       return ret;
+}
+
+static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
+{
+       struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
+       struct snd_soc_codec *codec = rtd->codec;
+
+       /* unregister the rtd device */
+       if (rtd->dev_registered) {
+               device_remove_file(&rtd->dev, &dev_attr_codec_reg);
+               device_unregister(&rtd->dev);
+               rtd->dev_registered = 0;
+       }
+
+       if (codec && codec->probed)
+               soc_remove_codec(codec);
+}
+
+static int snd_soc_init_codec_cache(struct snd_soc_codec *codec,
+                                   enum snd_soc_compress_type compress_type)
+{
+       int ret;
+
+       if (codec->cache_init)
+               return 0;
+
+       /* override the compress_type if necessary */
+       if (compress_type && codec->compress_type != compress_type)
+               codec->compress_type = compress_type;
+       ret = snd_soc_cache_init(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache compression type: %d\n",
+                       ret);
+               return ret;
+       }
+       codec->cache_init = 1;
+       return 0;
+}
+
 static void snd_soc_instantiate_card(struct snd_soc_card *card)
 {
        struct platform_device *pdev = to_platform_device(card->dev);
+       struct snd_soc_codec *codec;
+       struct snd_soc_codec_conf *codec_conf;
+       enum snd_soc_compress_type compress_type;
        int ret, i;
 
        mutex_lock(&card->mutex);
@@ -1573,6 +1739,39 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
                return;
        }
 
+       /* initialize the register cache for each available codec */
+       list_for_each_entry(codec, &codec_list, list) {
+               if (codec->cache_init)
+                       continue;
+               /* check to see if we need to override the compress_type */
+               for (i = 0; i < card->num_configs; ++i) {
+                       codec_conf = &card->codec_conf[i];
+                       if (!strcmp(codec->name, codec_conf->dev_name)) {
+                               compress_type = codec_conf->compress_type;
+                               if (compress_type && compress_type
+                                   != codec->compress_type)
+                                       break;
+                       }
+               }
+               if (i == card->num_configs) {
+                       /* no need to override the compress_type so
+                        * go ahead and do the standard thing */
+                       ret = snd_soc_init_codec_cache(codec, 0);
+                       if (ret < 0) {
+                               mutex_unlock(&card->mutex);
+                               return;
+                       }
+                       continue;
+               }
+               /* override the compress_type with the one supplied in
+                * the machine driver */
+               ret = snd_soc_init_codec_cache(codec, compress_type);
+               if (ret < 0) {
+                       mutex_unlock(&card->mutex);
+                       return;
+               }
+       }
+
        /* card bind complete so register a sound card */
        ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
                        card->owner, 0, &card->snd_card);
@@ -1605,6 +1804,15 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
                }
        }
 
+       for (i = 0; i < card->num_aux_devs; i++) {
+               ret = soc_probe_aux_dev(card, i);
+               if (ret < 0) {
+                       pr_err("asoc: failed to add auxiliary devices %s: %d\n",
+                              card->name, ret);
+                       goto probe_aux_dev_err;
+               }
+       }
+
        snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
                 "%s",  card->name);
        snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
@@ -1613,7 +1821,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
        ret = snd_card_register(card->snd_card);
        if (ret < 0) {
                printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name);
-               goto probe_dai_err;
+               goto probe_aux_dev_err;
        }
 
 #ifdef CONFIG_SND_SOC_AC97_BUS
@@ -1623,8 +1831,8 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
                if (ret < 0) {
                        printk(KERN_ERR "asoc: failed to register AC97 %s\n", card->name);
                        while (--i >= 0)
-                               soc_unregister_ac97_dai_link(&card->rtd[i]);
-                       goto probe_dai_err;
+                               soc_unregister_ac97_dai_link(card->rtd[i].codec);
+                       goto probe_aux_dev_err;
                }
        }
 #endif
@@ -1633,6 +1841,10 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
        mutex_unlock(&card->mutex);
        return;
 
+probe_aux_dev_err:
+       for (i = 0; i < card->num_aux_devs; i++)
+               soc_remove_aux_dev(card, i);
+
 probe_dai_err:
        for (i = 0; i < card->num_links; i++)
                soc_remove_dai_link(card, i);
@@ -1668,6 +1880,11 @@ static int soc_probe(struct platform_device *pdev)
        INIT_LIST_HEAD(&card->dai_dev_list);
        INIT_LIST_HEAD(&card->codec_dev_list);
        INIT_LIST_HEAD(&card->platform_dev_list);
+       INIT_LIST_HEAD(&card->widgets);
+       INIT_LIST_HEAD(&card->paths);
+       INIT_LIST_HEAD(&card->dapm_list);
+
+       soc_init_card_debugfs(card);
 
        ret = snd_soc_register_card(card);
        if (ret != 0) {
@@ -1689,13 +1906,19 @@ static int soc_remove(struct platform_device *pdev)
                /* make sure any delayed work runs */
                for (i = 0; i < card->num_rtd; i++) {
                        struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
-                       run_delayed_work(&rtd->delayed_work);
+                       flush_delayed_work_sync(&rtd->delayed_work);
                }
 
+               /* remove auxiliary devices */
+               for (i = 0; i < card->num_aux_devs; i++)
+                       soc_remove_aux_dev(card, i);
+
                /* remove and free each DAI */
                for (i = 0; i < card->num_rtd; i++)
                        soc_remove_dai_link(card, i);
 
+               soc_cleanup_card_debugfs(card);
+
                /* remove the card */
                if (card->remove)
                        card->remove(pdev);
@@ -1720,7 +1943,7 @@ static int soc_poweroff(struct device *dev)
         * now, we're shutting down so no imminent restart. */
        for (i = 0; i < card->num_rtd; i++) {
                struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
-               run_delayed_work(&rtd->delayed_work);
+               flush_delayed_work_sync(&rtd->delayed_work);
        }
 
        snd_soc_dapm_shutdown(card);
@@ -1879,6 +2102,27 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)
 }
 EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
 
+unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+       unsigned int ret;
+
+       ret = codec->read(codec, reg);
+       dev_dbg(codec->dev, "read %x => %x\n", reg, ret);
+       trace_snd_soc_reg_read(codec, reg, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_read);
+
+unsigned int snd_soc_write(struct snd_soc_codec *codec,
+                          unsigned int reg, unsigned int val)
+{
+       dev_dbg(codec->dev, "write %x = %x\n", reg, val);
+       trace_snd_soc_reg_write(codec, reg, val);
+       return codec->write(codec, reg, val);
+}
+EXPORT_SYMBOL_GPL(snd_soc_write);
+
 /**
  * snd_soc_update_bits - update codec register bits
  * @codec: audio codec
@@ -2019,14 +2263,22 @@ int snd_soc_add_controls(struct snd_soc_codec *codec,
        const struct snd_kcontrol_new *controls, int num_controls)
 {
        struct snd_card *card = codec->card->snd_card;
+       char prefixed_name[44], *name;
        int err, i;
 
        for (i = 0; i < num_controls; i++) {
                const struct snd_kcontrol_new *control = &controls[i];
-               err = snd_ctl_add(card, snd_soc_cnew(control, codec, NULL));
+               if (codec->name_prefix) {
+                       snprintf(prefixed_name, sizeof(prefixed_name), "%s %s",
+                                codec->name_prefix, control->name);
+                       name = prefixed_name;
+               } else {
+                       name = control->name;
+               }
+               err = snd_ctl_add(card, snd_soc_cnew(control, codec, name));
                if (err < 0) {
                        dev_err(codec->dev, "%s: Failed to add %s: %d\n",
-                               codec->name, control->name, err);
+                               codec->name, name, err);
                        return err;
                }
        }
@@ -2863,10 +3115,12 @@ static int snd_soc_register_card(struct snd_soc_card *card)
        if (!card->name || !card->dev)
                return -EINVAL;
 
-       card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) * card->num_links,
-                       GFP_KERNEL);
+       card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) *
+                           (card->num_links + card->num_aux_devs),
+                           GFP_KERNEL);
        if (card->rtd == NULL)
                return -ENOMEM;
+       card->rtd_aux = &card->rtd[card->num_links];
 
        for (i = 0; i < card->num_links; i++)
                card->rtd[i].dai_link = &card->dai_link[i];
@@ -2908,7 +3162,7 @@ static int snd_soc_unregister_card(struct snd_soc_card *card)
  * Simplify DAI link configuration by removing ".-1" from device names
  * and sanitizing names.
  */
-static inline char *fmt_single_name(struct device *dev, int *id)
+static char *fmt_single_name(struct device *dev, int *id)
 {
        char *found, name[NAME_SIZE];
        int id1, id2;
@@ -2916,7 +3170,7 @@ static inline char *fmt_single_name(struct device *dev, int *id)
        if (dev_name(dev) == NULL)
                return NULL;
 
-       strncpy(name, dev_name(dev), NAME_SIZE);
+       strlcpy(name, dev_name(dev), NAME_SIZE);
 
        /* are we a "%s.%d" name (platform and SPI components) */
        found = strstr(name, dev->driver->name);
@@ -2939,7 +3193,7 @@ static inline char *fmt_single_name(struct device *dev, int *id)
 
                        /* sanitize component name for DAI link creation */
                        snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, name);
-                       strncpy(name, tmp, NAME_SIZE);
+                       strlcpy(name, tmp, NAME_SIZE);
                } else
                        *id = 0;
        }
@@ -3204,9 +3458,11 @@ static void fixup_codec_formats(struct snd_soc_pcm_stream *stream)
  * @codec: codec to register
  */
 int snd_soc_register_codec(struct device *dev,
-               struct snd_soc_codec_driver *codec_drv,
-               struct snd_soc_dai_driver *dai_drv, int num_dai)
+                          const struct snd_soc_codec_driver *codec_drv,
+                          struct snd_soc_dai_driver *dai_drv,
+                          int num_dai)
 {
+       size_t reg_size;
        struct snd_soc_codec *codec;
        int ret, i;
 
@@ -3223,30 +3479,37 @@ int snd_soc_register_codec(struct device *dev,
                return -ENOMEM;
        }
 
-       /* allocate CODEC register cache */
-       if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
-
-               if (codec_drv->reg_cache_default)
-                       codec->reg_cache = kmemdup(codec_drv->reg_cache_default,
-                               codec_drv->reg_cache_size * codec_drv->reg_word_size, GFP_KERNEL);
-               else
-                       codec->reg_cache = kzalloc(codec_drv->reg_cache_size *
-                               codec_drv->reg_word_size, GFP_KERNEL);
-
-               if (codec->reg_cache == NULL) {
-                       kfree(codec->name);
-                       kfree(codec);
-                       return -ENOMEM;
-               }
-       }
+       if (codec_drv->compress_type)
+               codec->compress_type = codec_drv->compress_type;
+       else
+               codec->compress_type = SND_SOC_FLAT_COMPRESSION;
 
+       codec->write = codec_drv->write;
+       codec->read = codec_drv->read;
+       codec->dapm.bias_level = SND_SOC_BIAS_OFF;
+       codec->dapm.dev = dev;
+       codec->dapm.codec = codec;
        codec->dev = dev;
        codec->driver = codec_drv;
-       codec->bias_level = SND_SOC_BIAS_OFF;
        codec->num_dai = num_dai;
        mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       /* allocate CODEC register cache */
+       if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
+               reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
+               /* it is necessary to make a copy of the default register cache
+                * because in the case of using a compression type that requires
+                * the default register cache to be marked as __devinitconst the
+                * kernel might have freed the array by the time we initialize
+                * the cache.
+                */
+               codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default,
+                                             reg_size, GFP_KERNEL);
+               if (!codec->reg_def_copy) {
+                       ret = -ENOMEM;
+                       goto fail;
+               }
+       }
 
        for (i = 0; i < num_dai; i++) {
                fixup_codec_formats(&dai_drv[i].playback);
@@ -3257,7 +3520,7 @@ int snd_soc_register_codec(struct device *dev,
        if (num_dai) {
                ret = snd_soc_register_dais(dev, dai_drv, num_dai);
                if (ret < 0)
-                       goto error;
+                       goto fail;
        }
 
        mutex_lock(&client_mutex);
@@ -3268,9 +3531,9 @@ int snd_soc_register_codec(struct device *dev,
        pr_debug("Registered codec '%s'\n", codec->name);
        return 0;
 
-error:
-       if (codec->reg_cache)
-               kfree(codec->reg_cache);
+fail:
+       kfree(codec->reg_def_copy);
+       codec->reg_def_copy = NULL;
        kfree(codec->name);
        kfree(codec);
        return ret;
@@ -3304,8 +3567,8 @@ found:
 
        pr_debug("Unregistered codec '%s'\n", codec->name);
 
-       if (codec->reg_cache)
-               kfree(codec->reg_cache);
+       snd_soc_cache_exit(codec);
+       kfree(codec->reg_def_copy);
        kfree(codec->name);
        kfree(codec);
 }
index c721502..499730a 100644 (file)
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
-#include <sound/soc-dapm.h>
+#include <sound/soc.h>
 #include <sound/initval.h>
 
+#include <trace/events/asoc.h>
+
 /* dapm power sequences - make this per codec in the future */
 static int dapm_up_seq[] = {
        [snd_soc_dapm_pre] = 0,
@@ -54,12 +56,14 @@ static int dapm_up_seq[] = {
        [snd_soc_dapm_aif_out] = 3,
        [snd_soc_dapm_mic] = 4,
        [snd_soc_dapm_mux] = 5,
+       [snd_soc_dapm_virt_mux] = 5,
        [snd_soc_dapm_value_mux] = 5,
        [snd_soc_dapm_dac] = 6,
        [snd_soc_dapm_mixer] = 7,
        [snd_soc_dapm_mixer_named_ctl] = 7,
        [snd_soc_dapm_pga] = 8,
        [snd_soc_dapm_adc] = 9,
+       [snd_soc_dapm_out_drv] = 10,
        [snd_soc_dapm_hp] = 10,
        [snd_soc_dapm_spk] = 10,
        [snd_soc_dapm_post] = 11,
@@ -70,6 +74,7 @@ static int dapm_down_seq[] = {
        [snd_soc_dapm_adc] = 1,
        [snd_soc_dapm_hp] = 2,
        [snd_soc_dapm_spk] = 2,
+       [snd_soc_dapm_out_drv] = 2,
        [snd_soc_dapm_pga] = 4,
        [snd_soc_dapm_mixer_named_ctl] = 5,
        [snd_soc_dapm_mixer] = 5,
@@ -77,6 +82,7 @@ static int dapm_down_seq[] = {
        [snd_soc_dapm_mic] = 7,
        [snd_soc_dapm_micbias] = 8,
        [snd_soc_dapm_mux] = 9,
+       [snd_soc_dapm_virt_mux] = 9,
        [snd_soc_dapm_value_mux] = 9,
        [snd_soc_dapm_aif_in] = 10,
        [snd_soc_dapm_aif_out] = 10,
@@ -90,17 +96,24 @@ static void pop_wait(u32 pop_time)
                schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
 }
 
-static void pop_dbg(u32 pop_time, const char *fmt, ...)
+static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...)
 {
        va_list args;
+       char *buf;
 
-       va_start(args, fmt);
+       if (!pop_time)
+               return;
 
-       if (pop_time) {
-               vprintk(fmt, args);
-       }
+       buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (buf == NULL)
+               return;
 
+       va_start(args, fmt);
+       vsnprintf(buf, PAGE_SIZE, fmt, args);
+       dev_info(dev, "%s", buf);
        va_end(args);
+
+       kfree(buf);
 }
 
 /* create a new dapm widget */
@@ -120,36 +133,45 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
  * Returns 0 for success else error.
  */
 static int snd_soc_dapm_set_bias_level(struct snd_soc_card *card,
-               struct snd_soc_codec *codec, enum snd_soc_bias_level level)
+                                      struct snd_soc_dapm_context *dapm,
+                                      enum snd_soc_bias_level level)
 {
        int ret = 0;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               dev_dbg(codec->dev, "Setting full bias\n");
+               dev_dbg(dapm->dev, "Setting full bias\n");
                break;
        case SND_SOC_BIAS_PREPARE:
-               dev_dbg(codec->dev, "Setting bias prepare\n");
+               dev_dbg(dapm->dev, "Setting bias prepare\n");
                break;
        case SND_SOC_BIAS_STANDBY:
-               dev_dbg(codec->dev, "Setting standby bias\n");
+               dev_dbg(dapm->dev, "Setting standby bias\n");
                break;
        case SND_SOC_BIAS_OFF:
-               dev_dbg(codec->dev, "Setting bias off\n");
+               dev_dbg(dapm->dev, "Setting bias off\n");
                break;
        default:
-               dev_err(codec->dev, "Setting invalid bias %d\n", level);
+               dev_err(dapm->dev, "Setting invalid bias %d\n", level);
                return -EINVAL;
        }
 
+       trace_snd_soc_bias_level_start(card, level);
+
        if (card && card->set_bias_level)
                ret = card->set_bias_level(card, level);
        if (ret == 0) {
-               if (codec->driver->set_bias_level)
-                       ret = codec->driver->set_bias_level(codec, level);
+               if (dapm->codec && dapm->codec->driver->set_bias_level)
+                       ret = dapm->codec->driver->set_bias_level(dapm->codec, level);
                else
-                       codec->bias_level = level;
+                       dapm->bias_level = level;
        }
+       if (ret == 0) {
+               if (card && card->set_bias_level_post)
+                       ret = card->set_bias_level_post(card, level);
+       }
+
+       trace_snd_soc_bias_level_done(card, level);
 
        return ret;
 }
@@ -196,6 +218,20 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
                }
        }
        break;
+       case snd_soc_dapm_virt_mux: {
+               struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value;
+
+               p->connect = 0;
+               /* since a virtual mux has no backing registers to
+                * decide which path to connect, it will try to match
+                * with the first enumeration.  This is to ensure
+                * that the default mux choice (the first) will be
+                * correctly powered up during initialization.
+                */
+               if (!strcmp(p->name, e->texts[0]))
+                       p->connect = 1;
+       }
+       break;
        case snd_soc_dapm_value_mux: {
                struct soc_enum *e = (struct soc_enum *)
                        w->kcontrols[i].private_value;
@@ -217,6 +253,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
        break;
        /* does not effect routing - always connected */
        case snd_soc_dapm_pga:
+       case snd_soc_dapm_out_drv:
        case snd_soc_dapm_output:
        case snd_soc_dapm_adc:
        case snd_soc_dapm_input:
@@ -241,7 +278,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
 }
 
 /* connect mux widget to its interconnecting audio paths */
-static int dapm_connect_mux(struct snd_soc_codec *codec,
+static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
        struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
        struct snd_soc_dapm_path *path, const char *control_name,
        const struct snd_kcontrol_new *kcontrol)
@@ -251,7 +288,7 @@ static int dapm_connect_mux(struct snd_soc_codec *codec,
 
        for (i = 0; i < e->max; i++) {
                if (!(strcmp(control_name, e->texts[i]))) {
-                       list_add(&path->list, &codec->dapm_paths);
+                       list_add(&path->list, &dapm->card->paths);
                        list_add(&path->list_sink, &dest->sources);
                        list_add(&path->list_source, &src->sinks);
                        path->name = (char*)e->texts[i];
@@ -264,7 +301,7 @@ static int dapm_connect_mux(struct snd_soc_codec *codec,
 }
 
 /* connect mixer widget to its interconnecting audio paths */
-static int dapm_connect_mixer(struct snd_soc_codec *codec,
+static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
        struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
        struct snd_soc_dapm_path *path, const char *control_name)
 {
@@ -273,7 +310,7 @@ static int dapm_connect_mixer(struct snd_soc_codec *codec,
        /* search for mixer kcontrol */
        for (i = 0; i < dest->num_kcontrols; i++) {
                if (!strcmp(control_name, dest->kcontrols[i].name)) {
-                       list_add(&path->list, &codec->dapm_paths);
+                       list_add(&path->list, &dapm->card->paths);
                        list_add(&path->list_sink, &dest->sources);
                        list_add(&path->list_source, &src->sinks);
                        path->name = dest->kcontrols[i].name;
@@ -290,6 +327,8 @@ static int dapm_update_bits(struct snd_soc_dapm_widget *widget)
        int change, power;
        unsigned int old, new;
        struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_dapm_context *dapm = widget->dapm;
+       struct snd_soc_card *card = dapm->card;
 
        /* check for valid widgets */
        if (widget->reg < 0 || widget->id == snd_soc_dapm_input ||
@@ -309,24 +348,26 @@ static int dapm_update_bits(struct snd_soc_dapm_widget *widget)
 
        change = old != new;
        if (change) {
-               pop_dbg(codec->pop_time, "pop test %s : %s in %d ms\n",
+               pop_dbg(dapm->dev, card->pop_time,
+                       "pop test %s : %s in %d ms\n",
                        widget->name, widget->power ? "on" : "off",
-                       codec->pop_time);
-               pop_wait(codec->pop_time);
+                       card->pop_time);
+               pop_wait(card->pop_time);
                snd_soc_write(codec, widget->reg, new);
        }
-       pr_debug("reg %x old %x new %x change %d\n", widget->reg,
-                old, new, change);
+       dev_dbg(dapm->dev, "reg %x old %x new %x change %d\n", widget->reg,
+               old, new, change);
        return change;
 }
 
 /* create new dapm mixer control */
-static int dapm_new_mixer(struct snd_soc_codec *codec,
+static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
        struct snd_soc_dapm_widget *w)
 {
        int i, ret = 0;
        size_t name_len;
        struct snd_soc_dapm_path *path;
+       struct snd_card *card = dapm->codec->card->snd_card;
 
        /* add kcontrol */
        for (i = 0; i < w->num_kcontrols; i++) {
@@ -368,11 +409,11 @@ static int dapm_new_mixer(struct snd_soc_codec *codec,
 
                        path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w,
                                path->long_name);
-                       ret = snd_ctl_add(codec->card->snd_card, path->kcontrol);
+                       ret = snd_ctl_add(card, path->kcontrol);
                        if (ret < 0) {
-                               printk(KERN_ERR "asoc: failed to add dapm kcontrol %s: %d\n",
-                                      path->long_name,
-                                      ret);
+                               dev_err(dapm->dev,
+                                       "asoc: failed to add dapm kcontrol %s: %d\n",
+                                       path->long_name, ret);
                                kfree(path->long_name);
                                path->long_name = NULL;
                                return ret;
@@ -383,20 +424,22 @@ static int dapm_new_mixer(struct snd_soc_codec *codec,
 }
 
 /* create new dapm mux control */
-static int dapm_new_mux(struct snd_soc_codec *codec,
+static int dapm_new_mux(struct snd_soc_dapm_context *dapm,
        struct snd_soc_dapm_widget *w)
 {
        struct snd_soc_dapm_path *path = NULL;
        struct snd_kcontrol *kcontrol;
+       struct snd_card *card = dapm->codec->card->snd_card;
        int ret = 0;
 
        if (!w->num_kcontrols) {
-               printk(KERN_ERR "asoc: mux %s has no controls\n", w->name);
+               dev_err(dapm->dev, "asoc: mux %s has no controls\n", w->name);
                return -EINVAL;
        }
 
        kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name);
-       ret = snd_ctl_add(codec->card->snd_card, kcontrol);
+       ret = snd_ctl_add(card, kcontrol);
+
        if (ret < 0)
                goto err;
 
@@ -406,26 +449,27 @@ static int dapm_new_mux(struct snd_soc_codec *codec,
        return ret;
 
 err:
-       printk(KERN_ERR "asoc: failed to add kcontrol %s\n", w->name);
+       dev_err(dapm->dev, "asoc: failed to add kcontrol %s\n", w->name);
        return ret;
 }
 
 /* create new dapm volume control */
-static int dapm_new_pga(struct snd_soc_codec *codec,
+static int dapm_new_pga(struct snd_soc_dapm_context *dapm,
        struct snd_soc_dapm_widget *w)
 {
        if (w->num_kcontrols)
-               pr_err("asoc: PGA controls not supported: '%s'\n", w->name);
+               dev_err(w->dapm->dev,
+                       "asoc: PGA controls not supported: '%s'\n", w->name);
 
        return 0;
 }
 
 /* reset 'walked' bit for each dapm path */
-static inline void dapm_clear_walk(struct snd_soc_codec *codec)
+static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm)
 {
        struct snd_soc_dapm_path *p;
 
-       list_for_each_entry(p, &codec->dapm_paths, list)
+       list_for_each_entry(p, &dapm->card->paths, list)
                p->walked = 0;
 }
 
@@ -435,13 +479,14 @@ static inline void dapm_clear_walk(struct snd_soc_codec *codec)
  */
 static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
 {
-       int level = snd_power_get_state(widget->codec->card->snd_card);
+       int level = snd_power_get_state(widget->dapm->codec->card->snd_card);
 
        switch (level) {
        case SNDRV_CTL_POWER_D3hot:
        case SNDRV_CTL_POWER_D3cold:
                if (widget->ignore_suspend)
-                       pr_debug("%s ignoring suspend\n", widget->name);
+                       dev_dbg(widget->dapm->dev, "%s ignoring suspend\n",
+                               widget->name);
                return widget->ignore_suspend;
        default:
                return 1;
@@ -572,7 +617,7 @@ static int dapm_generic_apply_power(struct snd_soc_dapm_widget *w)
 
        /* call any power change event handlers */
        if (w->event)
-               pr_debug("power %s event for %s flags %x\n",
+               dev_dbg(w->dapm->dev, "power %s event for %s flags %x\n",
                         w->power ? "on" : "off",
                         w->name, w->event_flags);
 
@@ -621,9 +666,9 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
        int in, out;
 
        in = is_connected_input_ep(w);
-       dapm_clear_walk(w->codec);
+       dapm_clear_walk(w->dapm);
        out = is_connected_output_ep(w);
-       dapm_clear_walk(w->codec);
+       dapm_clear_walk(w->dapm);
        return out != 0 && in != 0;
 }
 
@@ -634,7 +679,7 @@ static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
 
        if (w->active) {
                in = is_connected_input_ep(w);
-               dapm_clear_walk(w->codec);
+               dapm_clear_walk(w->dapm);
                return in != 0;
        } else {
                return dapm_generic_check_power(w);
@@ -648,7 +693,7 @@ static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
 
        if (w->active) {
                out = is_connected_output_ep(w);
-               dapm_clear_walk(w->codec);
+               dapm_clear_walk(w->dapm);
                return out != 0;
        } else {
                return dapm_generic_check_power(w);
@@ -674,7 +719,7 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
                }
        }
 
-       dapm_clear_walk(w->codec);
+       dapm_clear_walk(w->dapm);
 
        return power;
 }
@@ -687,8 +732,8 @@ static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
                return sort[a->id] - sort[b->id];
        if (a->reg != b->reg)
                return a->reg - b->reg;
-       if (a->codec != b->codec)
-               return (unsigned long)a->codec - (unsigned long)b->codec;
+       if (a->dapm != b->dapm)
+               return (unsigned long)a->dapm - (unsigned long)b->dapm;
 
        return 0;
 }
@@ -709,12 +754,57 @@ static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
        list_add_tail(&new_widget->power_list, list);
 }
 
+static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm,
+                                struct snd_soc_dapm_widget *w, int event)
+{
+       struct snd_soc_card *card = dapm->card;
+       const char *ev_name;
+       int power, ret;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               ev_name = "PRE_PMU";
+               power = 1;
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               ev_name = "POST_PMU";
+               power = 1;
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               ev_name = "PRE_PMD";
+               power = 0;
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               ev_name = "POST_PMD";
+               power = 0;
+               break;
+       default:
+               BUG();
+               return;
+       }
+
+       if (w->power != power)
+               return;
+
+       if (w->event && (w->event_flags & event)) {
+               pop_dbg(dapm->dev, card->pop_time, "pop test : %s %s\n",
+                       w->name, ev_name);
+               trace_snd_soc_dapm_widget_event_start(w, event);
+               ret = w->event(w, NULL, event);
+               trace_snd_soc_dapm_widget_event_done(w, event);
+               if (ret < 0)
+                       pr_err("%s: %s event failed: %d\n",
+                              ev_name, w->name, ret);
+       }
+}
+
 /* Apply the coalesced changes from a DAPM sequence */
-static void dapm_seq_run_coalesced(struct snd_soc_codec *codec,
+static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
                                   struct list_head *pending)
 {
+       struct snd_soc_card *card = dapm->card;
        struct snd_soc_dapm_widget *w;
-       int reg, power, ret;
+       int reg, power;
        unsigned int value = 0;
        unsigned int mask = 0;
        unsigned int cur_mask;
@@ -735,64 +825,26 @@ static void dapm_seq_run_coalesced(struct snd_soc_codec *codec,
                if (power)
                        value |= cur_mask;
 
-               pop_dbg(codec->pop_time,
+               pop_dbg(dapm->dev, card->pop_time,
                        "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
                        w->name, reg, value, mask);
 
-               /* power up pre event */
-               if (w->power && w->event &&
-                   (w->event_flags & SND_SOC_DAPM_PRE_PMU)) {
-                       pop_dbg(codec->pop_time, "pop test : %s PRE_PMU\n",
-                               w->name);
-                       ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU);
-                       if (ret < 0)
-                               pr_err("%s: pre event failed: %d\n",
-                                      w->name, ret);
-               }
-
-               /* power down pre event */
-               if (!w->power && w->event &&
-                   (w->event_flags & SND_SOC_DAPM_PRE_PMD)) {
-                       pop_dbg(codec->pop_time, "pop test : %s PRE_PMD\n",
-                               w->name);
-                       ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD);
-                       if (ret < 0)
-                               pr_err("%s: pre event failed: %d\n",
-                                      w->name, ret);
-               }
+               /* Check for events */
+               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMU);
+               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMD);
        }
 
        if (reg >= 0) {
-               pop_dbg(codec->pop_time,
+               pop_dbg(dapm->dev, card->pop_time,
                        "pop test : Applying 0x%x/0x%x to %x in %dms\n",
-                       value, mask, reg, codec->pop_time);
-               pop_wait(codec->pop_time);
-               snd_soc_update_bits(codec, reg, mask, value);
+                       value, mask, reg, card->pop_time);
+               pop_wait(card->pop_time);
+               snd_soc_update_bits(dapm->codec, reg, mask, value);
        }
 
        list_for_each_entry(w, pending, power_list) {
-               /* power up post event */
-               if (w->power && w->event &&
-                   (w->event_flags & SND_SOC_DAPM_POST_PMU)) {
-                       pop_dbg(codec->pop_time, "pop test : %s POST_PMU\n",
-                               w->name);
-                       ret = w->event(w,
-                                      NULL, SND_SOC_DAPM_POST_PMU);
-                       if (ret < 0)
-                               pr_err("%s: post event failed: %d\n",
-                                      w->name, ret);
-               }
-
-               /* power down post event */
-               if (!w->power && w->event &&
-                   (w->event_flags & SND_SOC_DAPM_POST_PMD)) {
-                       pop_dbg(codec->pop_time, "pop test : %s POST_PMD\n",
-                               w->name);
-                       ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD);
-                       if (ret < 0)
-                               pr_err("%s: post event failed: %d\n",
-                                      w->name, ret);
-               }
+               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMU);
+               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMD);
        }
 }
 
@@ -804,26 +856,29 @@ static void dapm_seq_run_coalesced(struct snd_soc_codec *codec,
  * Currently anything that requires more than a single write is not
  * handled.
  */
-static void dapm_seq_run(struct snd_soc_codec *codec, struct list_head *list,
-                        int event, int sort[])
+static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
+                        struct list_head *list, int event, int sort[])
 {
        struct snd_soc_dapm_widget *w, *n;
        LIST_HEAD(pending);
        int cur_sort = -1;
        int cur_reg = SND_SOC_NOPM;
+       struct snd_soc_dapm_context *cur_dapm = NULL;
        int ret;
 
        list_for_each_entry_safe(w, n, list, power_list) {
                ret = 0;
 
                /* Do we need to apply any queued changes? */
-               if (sort[w->id] != cur_sort || w->reg != cur_reg) {
+               if (sort[w->id] != cur_sort || w->reg != cur_reg ||
+                   w->dapm != cur_dapm) {
                        if (!list_empty(&pending))
-                               dapm_seq_run_coalesced(codec, &pending);
+                               dapm_seq_run_coalesced(cur_dapm, &pending);
 
                        INIT_LIST_HEAD(&pending);
                        cur_sort = -1;
                        cur_reg = SND_SOC_NOPM;
+                       cur_dapm = NULL;
                }
 
                switch (w->id) {
@@ -867,19 +922,55 @@ static void dapm_seq_run(struct snd_soc_codec *codec, struct list_head *list,
                        /* Queue it up for application */
                        cur_sort = sort[w->id];
                        cur_reg = w->reg;
+                       cur_dapm = w->dapm;
                        list_move(&w->power_list, &pending);
                        break;
                }
 
                if (ret < 0)
-                       pr_err("Failed to apply widget power: %d\n",
-                              ret);
+                       dev_err(w->dapm->dev,
+                               "Failed to apply widget power: %d\n", ret);
        }
 
        if (!list_empty(&pending))
-               dapm_seq_run_coalesced(codec, &pending);
+               dapm_seq_run_coalesced(dapm, &pending);
+}
+
+static void dapm_widget_update(struct snd_soc_dapm_context *dapm)
+{
+       struct snd_soc_dapm_update *update = dapm->update;
+       struct snd_soc_dapm_widget *w;
+       int ret;
+
+       if (!update)
+               return;
+
+       w = update->widget;
+
+       if (w->event &&
+           (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
+               ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
+               if (ret != 0)
+                       pr_err("%s DAPM pre-event failed: %d\n",
+                              w->name, ret);
+       }
+
+       ret = snd_soc_update_bits(w->codec, update->reg, update->mask,
+                                 update->val);
+       if (ret < 0)
+               pr_err("%s DAPM update failed: %d\n", w->name, ret);
+
+       if (w->event &&
+           (w->event_flags & SND_SOC_DAPM_POST_REG)) {
+               ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
+               if (ret != 0)
+                       pr_err("%s DAPM post-event failed: %d\n",
+                              w->name, ret);
+       }
 }
 
+
+
 /*
  * Scan each dapm widget for complete audio path.
  * A complete path is a route that has valid endpoints i.e.:-
@@ -889,20 +980,26 @@ static void dapm_seq_run(struct snd_soc_codec *codec, struct list_head *list,
  *  o Input pin to Output pin (bypass, sidetone)
  *  o DAC to ADC (loopback).
  */
-static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
+static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
 {
-       struct snd_soc_card *card = codec->card;
+       struct snd_soc_card *card = dapm->codec->card;
        struct snd_soc_dapm_widget *w;
+       struct snd_soc_dapm_context *d;
        LIST_HEAD(up_list);
        LIST_HEAD(down_list);
        int ret = 0;
        int power;
-       int sys_power = 0;
+
+       trace_snd_soc_dapm_start(card);
+
+       list_for_each_entry(d, &card->dapm_list, list)
+               if (d->n_widgets)
+                       d->dev_power = 0;
 
        /* Check which widgets we need to power and store them in
         * lists indicating if they should be powered up or down.
         */
-       list_for_each_entry(w, &codec->dapm_widgets, list) {
+       list_for_each_entry(w, &card->widgets, list) {
                switch (w->id) {
                case snd_soc_dapm_pre:
                        dapm_seq_insert(w, &down_list, dapm_down_seq);
@@ -920,11 +1017,13 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
                        else
                                power = 1;
                        if (power)
-                               sys_power = 1;
+                               w->dapm->dev_power = 1;
 
                        if (w->power == power)
                                continue;
 
+                       trace_snd_soc_dapm_widget_power(w, power);
+
                        if (power)
                                dapm_seq_insert(w, &up_list, dapm_up_seq);
                        else
@@ -938,26 +1037,26 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
        /* If there are no DAPM widgets then try to figure out power from the
         * event type.
         */
-       if (list_empty(&codec->dapm_widgets)) {
+       if (!dapm->n_widgets) {
                switch (event) {
                case SND_SOC_DAPM_STREAM_START:
                case SND_SOC_DAPM_STREAM_RESUME:
-                       sys_power = 1;
+                       dapm->dev_power = 1;
                        break;
                case SND_SOC_DAPM_STREAM_STOP:
-                       sys_power = !!codec->active;
+                       dapm->dev_power = !!dapm->codec->active;
                        break;
                case SND_SOC_DAPM_STREAM_SUSPEND:
-                       sys_power = 0;
+                       dapm->dev_power = 0;
                        break;
                case SND_SOC_DAPM_STREAM_NOP:
-                       switch (codec->bias_level) {
+                       switch (dapm->bias_level) {
                                case SND_SOC_BIAS_STANDBY:
                                case SND_SOC_BIAS_OFF:
-                                       sys_power = 0;
+                                       dapm->dev_power = 0;
                                        break;
                                default:
-                                       sys_power = 1;
+                                       dapm->dev_power = 1;
                                        break;
                        }
                        break;
@@ -966,52 +1065,71 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
                }
        }
 
-       if (sys_power && codec->bias_level == SND_SOC_BIAS_OFF) {
-               ret = snd_soc_dapm_set_bias_level(card, codec,
-                                                 SND_SOC_BIAS_STANDBY);
-               if (ret != 0)
-                       pr_err("Failed to turn on bias: %d\n", ret);
-       }
+       list_for_each_entry(d, &dapm->card->dapm_list, list) {
+               if (d->dev_power && d->bias_level == SND_SOC_BIAS_OFF) {
+                       ret = snd_soc_dapm_set_bias_level(card, d,
+                                                         SND_SOC_BIAS_STANDBY);
+                       if (ret != 0)
+                               dev_err(d->dev,
+                                       "Failed to turn on bias: %d\n", ret);
+               }
 
-       /* If we're changing to all on or all off then prepare */
-       if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) ||
-           (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) {
-               ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_PREPARE);
-               if (ret != 0)
-                       pr_err("Failed to prepare bias: %d\n", ret);
+               /* If we're changing to all on or all off then prepare */
+               if ((d->dev_power && d->bias_level == SND_SOC_BIAS_STANDBY) ||
+                   (!d->dev_power && d->bias_level == SND_SOC_BIAS_ON)) {
+                       ret = snd_soc_dapm_set_bias_level(card, d,
+                                                         SND_SOC_BIAS_PREPARE);
+                       if (ret != 0)
+                               dev_err(d->dev,
+                                       "Failed to prepare bias: %d\n", ret);
+               }
        }
 
        /* Power down widgets first; try to avoid amplifying pops. */
-       dapm_seq_run(codec, &down_list, event, dapm_down_seq);
+       dapm_seq_run(dapm, &down_list, event, dapm_down_seq);
+
+       dapm_widget_update(dapm);
 
        /* Now power up. */
-       dapm_seq_run(codec, &up_list, event, dapm_up_seq);
+       dapm_seq_run(dapm, &up_list, event, dapm_up_seq);
+
+       list_for_each_entry(d, &dapm->card->dapm_list, list) {
+               /* If we just powered the last thing off drop to standby bias */
+               if (d->bias_level == SND_SOC_BIAS_PREPARE && !d->dev_power) {
+                       ret = snd_soc_dapm_set_bias_level(card, d,
+                                                         SND_SOC_BIAS_STANDBY);
+                       if (ret != 0)
+                               dev_err(d->dev,
+                                       "Failed to apply standby bias: %d\n",
+                                       ret);
+               }
 
-       /* If we just powered the last thing off drop to standby bias */
-       if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) {
-               ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_STANDBY);
-               if (ret != 0)
-                       pr_err("Failed to apply standby bias: %d\n", ret);
-       }
+               /* If we're in standby and can support bias off then do that */
+               if (d->bias_level == SND_SOC_BIAS_STANDBY &&
+                   d->idle_bias_off) {
+                       ret = snd_soc_dapm_set_bias_level(card, d,
+                                                         SND_SOC_BIAS_OFF);
+                       if (ret != 0)
+                               dev_err(d->dev,
+                                       "Failed to turn off bias: %d\n", ret);
+               }
 
-       /* If we're in standby and can support bias off then do that */
-       if (codec->bias_level == SND_SOC_BIAS_STANDBY &&
-           codec->idle_bias_off) {
-               ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_OFF);
-               if (ret != 0)
-                       pr_err("Failed to turn off bias: %d\n", ret);
+               /* If we just powered up then move to active bias */
+               if (d->bias_level == SND_SOC_BIAS_PREPARE && d->dev_power) {
+                       ret = snd_soc_dapm_set_bias_level(card, d,
+                                                         SND_SOC_BIAS_ON);
+                       if (ret != 0)
+                               dev_err(d->dev,
+                                       "Failed to apply active bias: %d\n",
+                                       ret);
+               }
        }
 
-       /* If we just powered up then move to active bias */
-       if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) {
-               ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_ON);
-               if (ret != 0)
-                       pr_err("Failed to apply active bias: %d\n", ret);
-       }
+       pop_dbg(dapm->dev, card->pop_time,
+               "DAPM sequencing finished, waiting %dms\n", card->pop_time);
+       pop_wait(card->pop_time);
 
-       pop_dbg(codec->pop_time, "DAPM sequencing finished, waiting %dms\n",
-               codec->pop_time);
-       pop_wait(codec->pop_time);
+       trace_snd_soc_dapm_done(card);
 
        return 0;
 }
@@ -1038,9 +1156,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
                return -ENOMEM;
 
        in = is_connected_input_ep(w);
-       dapm_clear_walk(w->codec);
+       dapm_clear_walk(w->dapm);
        out = is_connected_output_ep(w);
-       dapm_clear_walk(w->codec);
+       dapm_clear_walk(w->dapm);
 
        ret = snprintf(buf, PAGE_SIZE, "%s: %s  in %d out %d",
                       w->name, w->power ? "On" : "Off", in, out);
@@ -1090,29 +1208,29 @@ static const struct file_operations dapm_widget_power_fops = {
        .llseek = default_llseek,
 };
 
-void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec)
+void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm)
 {
        struct snd_soc_dapm_widget *w;
        struct dentry *d;
 
-       if (!codec->debugfs_dapm)
+       if (!dapm->debugfs_dapm)
                return;
 
-       list_for_each_entry(w, &codec->dapm_widgets, list) {
-               if (!w->name)
+       list_for_each_entry(w, &dapm->card->widgets, list) {
+               if (!w->name || w->dapm != dapm)
                        continue;
 
                d = debugfs_create_file(w->name, 0444,
-                                       codec->debugfs_dapm, w,
+                                       dapm->debugfs_dapm, w,
                                        &dapm_widget_power_fops);
                if (!d)
-                       printk(KERN_WARNING
-                              "ASoC: Failed to create %s debugfs file\n",
-                              w->name);
+                       dev_warn(w->dapm->dev,
+                               "ASoC: Failed to create %s debugfs file\n",
+                               w->name);
        }
 }
 #else
-void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec)
+void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm)
 {
 }
 #endif
@@ -1126,6 +1244,7 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
        int found = 0;
 
        if (widget->id != snd_soc_dapm_mux &&
+           widget->id != snd_soc_dapm_virt_mux &&
            widget->id != snd_soc_dapm_value_mux)
                return -ENODEV;
 
@@ -1133,7 +1252,7 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
                return 0;
 
        /* find dapm widget path assoc with kcontrol */
-       list_for_each_entry(path, &widget->codec->dapm_paths, list) {
+       list_for_each_entry(path, &widget->dapm->card->paths, list) {
                if (path->kcontrol != kcontrol)
                        continue;
 
@@ -1149,7 +1268,7 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
        }
 
        if (found)
-               dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
+               dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
 
        return 0;
 }
@@ -1167,7 +1286,7 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
                return -ENODEV;
 
        /* find dapm widget path assoc with kcontrol */
-       list_for_each_entry(path, &widget->codec->dapm_paths, list) {
+       list_for_each_entry(path, &widget->dapm->card->paths, list) {
                if (path->kcontrol != kcontrol)
                        continue;
 
@@ -1178,7 +1297,7 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
        }
 
        if (found)
-               dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
+               dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
 
        return 0;
 }
@@ -1194,7 +1313,9 @@ static ssize_t dapm_widget_show(struct device *dev,
        int count = 0;
        char *state = "not set";
 
-       list_for_each_entry(w, &codec->dapm_widgets, list) {
+       list_for_each_entry(w, &codec->card->widgets, list) {
+               if (w->dapm != &codec->dapm)
+                       continue;
 
                /* only display widgets that burnm power */
                switch (w->id) {
@@ -1206,6 +1327,7 @@ static ssize_t dapm_widget_show(struct device *dev,
                case snd_soc_dapm_dac:
                case snd_soc_dapm_adc:
                case snd_soc_dapm_pga:
+               case snd_soc_dapm_out_drv:
                case snd_soc_dapm_mixer:
                case snd_soc_dapm_mixer_named_ctl:
                case snd_soc_dapm_supply:
@@ -1218,7 +1340,7 @@ static ssize_t dapm_widget_show(struct device *dev,
                }
        }
 
-       switch (codec->bias_level) {
+       switch (codec->dapm.bias_level) {
        case SND_SOC_BIAS_ON:
                state = "On";
                break;
@@ -1250,31 +1372,50 @@ static void snd_soc_dapm_sys_remove(struct device *dev)
 }
 
 /* free all dapm widgets and resources */
-static void dapm_free_widgets(struct snd_soc_codec *codec)
+static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
 {
        struct snd_soc_dapm_widget *w, *next_w;
        struct snd_soc_dapm_path *p, *next_p;
 
-       list_for_each_entry_safe(w, next_w, &codec->dapm_widgets, list) {
+       list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
+               if (w->dapm != dapm)
+                       continue;
                list_del(&w->list);
+               /*
+                * remove source and sink paths associated to this widget.
+                * 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);
+               }
+               kfree(w->name);
                kfree(w);
        }
-
-       list_for_each_entry_safe(p, next_p, &codec->dapm_paths, list) {
-               list_del(&p->list);
-               kfree(p->long_name);
-               kfree(p);
-       }
 }
 
-static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec,
+static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
                                const char *pin, int status)
 {
        struct snd_soc_dapm_widget *w;
 
-       list_for_each_entry(w, &codec->dapm_widgets, list) {
+       list_for_each_entry(w, &dapm->card->widgets, list) {
+               if (w->dapm != dapm)
+                       continue;
                if (!strcmp(w->name, pin)) {
-                       pr_debug("dapm: %s: pin %s\n", codec->name, pin);
+                       dev_dbg(w->dapm->dev, "dapm: pin %s = %d\n",
+                               pin, status);
                        w->connected = status;
                        /* Allow disabling of forced pins */
                        if (status == 0)
@@ -1283,46 +1424,72 @@ static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec,
                }
        }
 
-       pr_err("dapm: %s: configuring unknown pin %s\n", codec->name, pin);
+       dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
        return -EINVAL;
 }
 
 /**
  * snd_soc_dapm_sync - scan and power dapm paths
- * @codec: audio codec
+ * @dapm: DAPM context
  *
  * Walks all dapm audio paths and powers widgets according to their
  * stream or path usage.
  *
  * Returns 0 for success.
  */
-int snd_soc_dapm_sync(struct snd_soc_codec *codec)
+int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
 {
-       return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
+       return dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
 
-static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
+static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
                                  const struct snd_soc_dapm_route *route)
 {
        struct snd_soc_dapm_path *path;
        struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
-       const char *sink = route->sink;
+       struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
+       const char *sink;
        const char *control = route->control;
-       const char *source = route->source;
+       const char *source;
+       char prefixed_sink[80];
+       char prefixed_source[80];
        int ret = 0;
 
-       /* find src and dest widgets */
-       list_for_each_entry(w, &codec->dapm_widgets, list) {
+       if (dapm->codec->name_prefix) {
+               snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
+                        dapm->codec->name_prefix, route->sink);
+               sink = prefixed_sink;
+               snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
+                        dapm->codec->name_prefix, route->source);
+               source = prefixed_source;
+       } else {
+               sink = route->sink;
+               source = route->source;
+       }
 
+       /*
+        * find src and dest widgets over all widgets but favor a widget from
+        * current DAPM context
+        */
+       list_for_each_entry(w, &dapm->card->widgets, list) {
                if (!wsink && !(strcmp(w->name, sink))) {
-                       wsink = w;
+                       wtsink = w;
+                       if (w->dapm == dapm)
+                               wsink = w;
                        continue;
                }
                if (!wsource && !(strcmp(w->name, source))) {
-                       wsource = w;
+                       wtsource = w;
+                       if (w->dapm == dapm)
+                               wsource = w;
                }
        }
+       /* use widget from another DAPM context if not found from this */
+       if (!wsink)
+               wsink = wtsink;
+       if (!wsource)
+               wsource = wtsource;
 
        if (wsource == NULL || wsink == NULL)
                return -ENODEV;
@@ -1356,7 +1523,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
 
        /* connect static paths */
        if (control == NULL) {
-               list_add(&path->list, &codec->dapm_paths);
+               list_add(&path->list, &dapm->card->paths);
                list_add(&path->list_sink, &wsink->sources);
                list_add(&path->list_source, &wsource->sinks);
                path->connect = 1;
@@ -1368,6 +1535,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
        case snd_soc_dapm_adc:
        case snd_soc_dapm_dac:
        case snd_soc_dapm_pga:
+       case snd_soc_dapm_out_drv:
        case snd_soc_dapm_input:
        case snd_soc_dapm_output:
        case snd_soc_dapm_micbias:
@@ -1377,14 +1545,15 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
        case snd_soc_dapm_supply:
        case snd_soc_dapm_aif_in:
        case snd_soc_dapm_aif_out:
-               list_add(&path->list, &codec->dapm_paths);
+               list_add(&path->list, &dapm->card->paths);
                list_add(&path->list_sink, &wsink->sources);
                list_add(&path->list_source, &wsource->sinks);
                path->connect = 1;
                return 0;
        case snd_soc_dapm_mux:
+       case snd_soc_dapm_virt_mux:
        case snd_soc_dapm_value_mux:
-               ret = dapm_connect_mux(codec, wsource, wsink, path, control,
+               ret = dapm_connect_mux(dapm, wsource, wsink, path, control,
                        &wsink->kcontrols[0]);
                if (ret != 0)
                        goto err;
@@ -1392,7 +1561,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
        case snd_soc_dapm_switch:
        case snd_soc_dapm_mixer:
        case snd_soc_dapm_mixer_named_ctl:
-               ret = dapm_connect_mixer(codec, wsource, wsink, path, control);
+               ret = dapm_connect_mixer(dapm, wsource, wsink, path, control);
                if (ret != 0)
                        goto err;
                break;
@@ -1400,7 +1569,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
        case snd_soc_dapm_mic:
        case snd_soc_dapm_line:
        case snd_soc_dapm_spk:
-               list_add(&path->list, &codec->dapm_paths);
+               list_add(&path->list, &dapm->card->paths);
                list_add(&path->list_sink, &wsink->sources);
                list_add(&path->list_source, &wsource->sinks);
                path->connect = 0;
@@ -1409,15 +1578,15 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
        return 0;
 
 err:
-       printk(KERN_WARNING "asoc: no dapm match for %s --> %s --> %s\n", source,
-               control, sink);
+       dev_warn(dapm->dev, "asoc: no dapm match for %s --> %s --> %s\n",
+                source, control, sink);
        kfree(path);
        return ret;
 }
 
 /**
  * snd_soc_dapm_add_routes - Add routes between DAPM widgets
- * @codec: codec
+ * @dapm: DAPM context
  * @route: audio routes
  * @num: number of routes
  *
@@ -1428,17 +1597,16 @@ err:
  * Returns 0 for success else error. On error all resources can be freed
  * with a call to snd_soc_card_free().
  */
-int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
+int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
                            const struct snd_soc_dapm_route *route, int num)
 {
        int i, ret;
 
        for (i = 0; i < num; i++) {
-               ret = snd_soc_dapm_add_route(codec, route);
+               ret = snd_soc_dapm_add_route(dapm, route);
                if (ret < 0) {
-                       printk(KERN_ERR "Failed to add route %s->%s\n",
-                              route->source,
-                              route->sink);
+                       dev_err(dapm->dev, "Failed to add route %s->%s\n",
+                               route->source, route->sink);
                        return ret;
                }
                route++;
@@ -1450,17 +1618,17 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
 
 /**
  * snd_soc_dapm_new_widgets - add new dapm widgets
- * @codec: audio codec
+ * @dapm: DAPM context
  *
  * Checks the codec for any new dapm widgets and creates them if found.
  *
  * Returns 0 for success.
  */
-int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
+int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
 {
        struct snd_soc_dapm_widget *w;
 
-       list_for_each_entry(w, &codec->dapm_widgets, list)
+       list_for_each_entry(w, &dapm->card->widgets, list)
        {
                if (w->new)
                        continue;
@@ -1470,12 +1638,13 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
                case snd_soc_dapm_mixer:
                case snd_soc_dapm_mixer_named_ctl:
                        w->power_check = dapm_generic_check_power;
-                       dapm_new_mixer(codec, w);
+                       dapm_new_mixer(dapm, w);
                        break;
                case snd_soc_dapm_mux:
+               case snd_soc_dapm_virt_mux:
                case snd_soc_dapm_value_mux:
                        w->power_check = dapm_generic_check_power;
-                       dapm_new_mux(codec, w);
+                       dapm_new_mux(dapm, w);
                        break;
                case snd_soc_dapm_adc:
                case snd_soc_dapm_aif_out:
@@ -1486,8 +1655,9 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
                        w->power_check = dapm_dac_check_power;
                        break;
                case snd_soc_dapm_pga:
+               case snd_soc_dapm_out_drv:
                        w->power_check = dapm_generic_check_power;
-                       dapm_new_pga(codec, w);
+                       dapm_new_pga(dapm, w);
                        break;
                case snd_soc_dapm_input:
                case snd_soc_dapm_output:
@@ -1508,7 +1678,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
                w->new = 1;
        }
 
-       dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
+       dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
@@ -1569,13 +1739,12 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int reg = mc->reg;
        unsigned int shift = mc->shift;
-       unsigned int rshift = mc->rshift;
        int max = mc->max;
        unsigned int mask = (1 << fls(max)) - 1;
        unsigned int invert = mc->invert;
-       unsigned int val, val2, val_mask;
-       int connect;
-       int ret;
+       unsigned int val, val_mask;
+       int connect, change;
+       struct snd_soc_dapm_update update;
 
        val = (ucontrol->value.integer.value[0] & mask);
 
@@ -1583,18 +1752,12 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
                val = max - val;
        val_mask = mask << shift;
        val = val << shift;
-       if (shift != rshift) {
-               val2 = (ucontrol->value.integer.value[1] & mask);
-               if (invert)
-                       val2 = max - val2;
-               val_mask |= mask << rshift;
-               val |= val2 << rshift;
-       }
 
        mutex_lock(&widget->codec->mutex);
        widget->value = val;
 
-       if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) {
+       change = snd_soc_test_bits(widget->codec, reg, val_mask, val);
+       if (change) {
                if (val)
                        /* new connection */
                        connect = invert ? 0:1;
@@ -1602,28 +1765,20 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
                        /* old connection must be powered down */
                        connect = invert ? 1:0;
 
+               update.kcontrol = kcontrol;
+               update.widget = widget;
+               update.reg = reg;
+               update.mask = mask;
+               update.val = val;
+               widget->dapm->update = &update;
+
                dapm_mixer_update_power(widget, kcontrol, connect);
+
+               widget->dapm->update = NULL;
        }
 
-       if (widget->event) {
-               if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
-                       ret = widget->event(widget, kcontrol,
-                                               SND_SOC_DAPM_PRE_REG);
-                       if (ret < 0) {
-                               ret = 1;
-                               goto out;
-                       }
-               }
-               ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
-               if (widget->event_flags & SND_SOC_DAPM_POST_REG)
-                       ret = widget->event(widget, kcontrol,
-                                               SND_SOC_DAPM_POST_REG);
-       } else
-               ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
-
-out:
        mutex_unlock(&widget->codec->mutex);
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
 
@@ -1671,7 +1826,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val, mux, change;
        unsigned int mask, bitmask;
-       int ret = 0;
+       struct snd_soc_dapm_update update;
 
        for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
                ;
@@ -1690,24 +1845,20 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
        mutex_lock(&widget->codec->mutex);
        widget->value = val;
        change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
-       dapm_mux_update_power(widget, kcontrol, change, mux, e);
 
-       if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
-               ret = widget->event(widget,
-                                   kcontrol, SND_SOC_DAPM_PRE_REG);
-               if (ret < 0)
-                       goto out;
-       }
+       update.kcontrol = kcontrol;
+       update.widget = widget;
+       update.reg = e->reg;
+       update.mask = mask;
+       update.val = val;
+       widget->dapm->update = &update;
 
-       ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
+       dapm_mux_update_power(widget, kcontrol, change, mux, e);
 
-       if (widget->event_flags & SND_SOC_DAPM_POST_REG)
-               ret = widget->event(widget,
-                                   kcontrol, SND_SOC_DAPM_POST_REG);
+       widget->dapm->update = NULL;
 
-out:
        mutex_unlock(&widget->codec->mutex);
-       return ret;
+       return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
 
@@ -1819,7 +1970,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val, mux, change;
        unsigned int mask;
-       int ret = 0;
+       struct snd_soc_dapm_update update;
 
        if (ucontrol->value.enumerated.item[0] > e->max - 1)
                return -EINVAL;
@@ -1836,24 +1987,20 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
        mutex_lock(&widget->codec->mutex);
        widget->value = val;
        change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
-       dapm_mux_update_power(widget, kcontrol, change, mux, e);
 
-       if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
-               ret = widget->event(widget,
-                                   kcontrol, SND_SOC_DAPM_PRE_REG);
-               if (ret < 0)
-                       goto out;
-       }
+       update.kcontrol = kcontrol;
+       update.widget = widget;
+       update.reg = e->reg;
+       update.mask = mask;
+       update.val = val;
+       widget->dapm->update = &update;
 
-       ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
+       dapm_mux_update_power(widget, kcontrol, change, mux, e);
 
-       if (widget->event_flags & SND_SOC_DAPM_POST_REG)
-               ret = widget->event(widget,
-                                   kcontrol, SND_SOC_DAPM_POST_REG);
+       widget->dapm->update = NULL;
 
-out:
        mutex_unlock(&widget->codec->mutex);
-       return ret;
+       return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
 
@@ -1892,7 +2039,7 @@ int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
        mutex_lock(&codec->mutex);
 
        ucontrol->value.integer.value[0] =
-               snd_soc_dapm_get_pin_status(codec, pin);
+               snd_soc_dapm_get_pin_status(&codec->dapm, pin);
 
        mutex_unlock(&codec->mutex);
 
@@ -1915,11 +2062,11 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
        mutex_lock(&codec->mutex);
 
        if (ucontrol->value.integer.value[0])
-               snd_soc_dapm_enable_pin(codec, pin);
+               snd_soc_dapm_enable_pin(&codec->dapm, pin);
        else
-               snd_soc_dapm_disable_pin(codec, pin);
+               snd_soc_dapm_disable_pin(&codec->dapm, pin);
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(&codec->dapm);
 
        mutex_unlock(&codec->mutex);
 
@@ -1929,26 +2076,43 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
 
 /**
  * snd_soc_dapm_new_control - create new dapm control
- * @codec: audio codec
+ * @dapm: DAPM context
  * @widget: widget template
  *
  * Creates a new dapm control based upon the template.
  *
  * Returns 0 for success else error.
  */
-int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
+int 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;
 
        if ((w = dapm_cnew_widget(widget)) == NULL)
                return -ENOMEM;
 
-       w->codec = codec;
+       name_len = strlen(widget->name) + 1;
+       if (dapm->codec->name_prefix)
+               name_len += 1 + strlen(dapm->codec->name_prefix);
+       w->name = kmalloc(name_len, GFP_KERNEL);
+       if (w->name == NULL) {
+               kfree(w);
+               return -ENOMEM;
+       }
+       if (dapm->codec->name_prefix)
+               snprintf(w->name, name_len, "%s %s",
+                       dapm->codec->name_prefix, widget->name);
+       else
+               snprintf(w->name, name_len, "%s", widget->name);
+
+       dapm->n_widgets++;
+       w->dapm = dapm;
+       w->codec = dapm->codec;
        INIT_LIST_HEAD(&w->sources);
        INIT_LIST_HEAD(&w->sinks);
        INIT_LIST_HEAD(&w->list);
-       list_add(&w->list, &codec->dapm_widgets);
+       list_add(&w->list, &dapm->card->widgets);
 
        /* machine layer set ups unconnected pins and insertions */
        w->connected = 1;
@@ -1958,7 +2122,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
 
 /**
  * snd_soc_dapm_new_controls - create new dapm controls
- * @codec: audio codec
+ * @dapm: DAPM context
  * @widget: widget array
  * @num: number of widgets
  *
@@ -1966,18 +2130,18 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
  *
  * Returns 0 for success else error.
  */
-int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
+int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
        const struct snd_soc_dapm_widget *widget,
        int num)
 {
        int i, ret;
 
        for (i = 0; i < num; i++) {
-               ret = snd_soc_dapm_new_control(codec, widget);
+               ret = snd_soc_dapm_new_control(dapm, widget);
                if (ret < 0) {
-                       printk(KERN_ERR
-                              "ASoC: Failed to create DAPM control %s: %d\n",
-                              widget->name, ret);
+                       dev_err(dapm->dev,
+                               "ASoC: Failed to create DAPM control %s: %d\n",
+                               widget->name, ret);
                        return ret;
                }
                widget++;
@@ -1986,34 +2150,17 @@ int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
 
-
-/**
- * snd_soc_dapm_stream_event - send a stream event to the dapm core
- * @codec: audio codec
- * @stream: stream name
- * @event: stream event
- *
- * Sends a stream event to the dapm core. The core then makes any
- * necessary widget power changes.
- *
- * Returns 0 for success else error.
- */
-int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
+static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
        const char *stream, int event)
 {
-       struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dapm_widget *w;
 
-       if (stream == NULL)
-               return 0;
-
-       mutex_lock(&codec->mutex);
-       list_for_each_entry(w, &codec->dapm_widgets, list)
+       list_for_each_entry(w, &dapm->card->widgets, list)
        {
-               if (!w->sname)
+               if (!w->sname || w->dapm != dapm)
                        continue;
-               pr_debug("widget %s\n %s stream %s event %d\n",
-                        w->name, w->sname, stream, event);
+               dev_dbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n",
+                       w->name, w->sname, stream, event);
                if (strstr(w->sname, stream)) {
                        switch(event) {
                        case SND_SOC_DAPM_STREAM_START:
@@ -2031,7 +2178,30 @@ int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
                }
        }
 
-       dapm_power_widgets(codec, event);
+       dapm_power_widgets(dapm, event);
+}
+
+/**
+ * snd_soc_dapm_stream_event - send a stream event to the dapm core
+ * @rtd: PCM runtime data
+ * @stream: stream name
+ * @event: stream event
+ *
+ * Sends a stream event to the dapm core. The core then makes any
+ * necessary widget power changes.
+ *
+ * Returns 0 for success else error.
+ */
+int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
+       const char *stream, int event)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+
+       if (stream == NULL)
+               return 0;
+
+       mutex_lock(&codec->mutex);
+       soc_dapm_stream_event(&codec->dapm, stream, event);
        mutex_unlock(&codec->mutex);
        return 0;
 }
@@ -2039,7 +2209,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
 
 /**
  * snd_soc_dapm_enable_pin - enable pin.
- * @codec: SoC codec
+ * @dapm: DAPM context
  * @pin: pin name
  *
  * Enables input/output pin and its parents or children widgets iff there is
@@ -2047,15 +2217,15 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
  * do any widget power switching.
  */
-int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, const char *pin)
+int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
 {
-       return snd_soc_dapm_set_pin(codec, pin, 1);
+       return snd_soc_dapm_set_pin(dapm, pin, 1);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
 
 /**
  * snd_soc_dapm_force_enable_pin - force a pin to be enabled
- * @codec: SoC codec
+ * @dapm: DAPM context
  * @pin: pin name
  *
  * Enables input/output pin regardless of any other state.  This is
@@ -2065,42 +2235,47 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
  * do any widget power switching.
  */
-int snd_soc_dapm_force_enable_pin(struct snd_soc_codec *codec, const char *pin)
+int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
+                                 const char *pin)
 {
        struct snd_soc_dapm_widget *w;
 
-       list_for_each_entry(w, &codec->dapm_widgets, list) {
+       list_for_each_entry(w, &dapm->card->widgets, list) {
+               if (w->dapm != dapm)
+                       continue;
                if (!strcmp(w->name, pin)) {
-                       pr_debug("dapm: %s: pin %s\n", codec->name, pin);
+                       dev_dbg(w->dapm->dev,
+                               "dapm: force enable pin %s\n", pin);
                        w->connected = 1;
                        w->force = 1;
                        return 0;
                }
        }
 
-       pr_err("dapm: %s: configuring unknown pin %s\n", codec->name, pin);
+       dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
        return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
 
 /**
  * snd_soc_dapm_disable_pin - disable pin.
- * @codec: SoC codec
+ * @dapm: DAPM context
  * @pin: pin name
  *
  * Disables input/output pin and its parents or children widgets.
  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
  * do any widget power switching.
  */
-int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, const char *pin)
+int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
+                            const char *pin)
 {
-       return snd_soc_dapm_set_pin(codec, pin, 0);
+       return snd_soc_dapm_set_pin(dapm, pin, 0);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
 
 /**
  * snd_soc_dapm_nc_pin - permanently disable pin.
- * @codec: SoC codec
+ * @dapm: DAPM context
  * @pin: pin name
  *
  * Marks the specified pin as being not connected, disabling it along
@@ -2112,26 +2287,29 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
  * do any widget power switching.
  */
-int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, const char *pin)
+int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
 {
-       return snd_soc_dapm_set_pin(codec, pin, 0);
+       return snd_soc_dapm_set_pin(dapm, pin, 0);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
 
 /**
  * snd_soc_dapm_get_pin_status - get audio pin status
- * @codec: audio codec
+ * @dapm: DAPM context
  * @pin: audio signal pin endpoint (or start point)
  *
  * Get audio pin status - connected or disconnected.
  *
  * Returns 1 for connected otherwise 0.
  */
-int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, const char *pin)
+int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
+                               const char *pin)
 {
        struct snd_soc_dapm_widget *w;
 
-       list_for_each_entry(w, &codec->dapm_widgets, list) {
+       list_for_each_entry(w, &dapm->card->widgets, list) {
+               if (w->dapm != dapm)
+                       continue;
                if (!strcmp(w->name, pin))
                        return w->connected;
        }
@@ -2142,7 +2320,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
 
 /**
  * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint
- * @codec: audio codec
+ * @dapm: DAPM context
  * @pin: audio signal pin endpoint (or start point)
  *
  * Mark the given endpoint or pin as ignoring suspend.  When the
@@ -2151,18 +2329,21 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
  * normal means at suspend time, it will not be turned on if it was not
  * already enabled.
  */
-int snd_soc_dapm_ignore_suspend(struct snd_soc_codec *codec, const char *pin)
+int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
+                               const char *pin)
 {
        struct snd_soc_dapm_widget *w;
 
-       list_for_each_entry(w, &codec->dapm_widgets, list) {
+       list_for_each_entry(w, &dapm->card->widgets, list) {
+               if (w->dapm != dapm)
+                       continue;
                if (!strcmp(w->name, pin)) {
                        w->ignore_suspend = 1;
                        return 0;
                }
        }
 
-       pr_err("Unknown DAPM pin: %s\n", pin);
+       dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
        return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
@@ -2173,20 +2354,23 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
  *
  * Free all dapm widgets and resources.
  */
-void snd_soc_dapm_free(struct snd_soc_codec *codec)
+void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
 {
-       snd_soc_dapm_sys_remove(codec->dev);
-       dapm_free_widgets(codec);
+       snd_soc_dapm_sys_remove(dapm->dev);
+       dapm_free_widgets(dapm);
+       list_del(&dapm->list);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
 
-static void soc_dapm_shutdown_codec(struct snd_soc_codec *codec)
+static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
 {
        struct snd_soc_dapm_widget *w;
        LIST_HEAD(down_list);
        int powerdown = 0;
 
-       list_for_each_entry(w, &codec->dapm_widgets, list) {
+       list_for_each_entry(w, &dapm->card->widgets, list) {
+               if (w->dapm != dapm)
+                       continue;
                if (w->power) {
                        dapm_seq_insert(w, &down_list, dapm_down_seq);
                        w->power = 0;
@@ -2198,9 +2382,9 @@ static void soc_dapm_shutdown_codec(struct snd_soc_codec *codec)
         * standby.
         */
        if (powerdown) {
-               snd_soc_dapm_set_bias_level(NULL, codec, SND_SOC_BIAS_PREPARE);
-               dapm_seq_run(codec, &down_list, 0, dapm_down_seq);
-               snd_soc_dapm_set_bias_level(NULL, codec, SND_SOC_BIAS_STANDBY);
+               snd_soc_dapm_set_bias_level(NULL, dapm, SND_SOC_BIAS_PREPARE);
+               dapm_seq_run(dapm, &down_list, 0, dapm_down_seq);
+               snd_soc_dapm_set_bias_level(NULL, dapm, SND_SOC_BIAS_STANDBY);
        }
 }
 
@@ -2211,10 +2395,10 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card)
 {
        struct snd_soc_codec *codec;
 
-       list_for_each_entry(codec, &card->codec_dev_list, list)
-               soc_dapm_shutdown_codec(codec);
-
-       snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_OFF);
+       list_for_each_entry(codec, &card->codec_dev_list, list) {
+               soc_dapm_shutdown_codec(&codec->dapm);
+               snd_soc_dapm_set_bias_level(card, &codec->dapm, SND_SOC_BIAS_OFF);
+       }
 }
 
 /* Module information */
index 8a0a920..ac5a5bc 100644 (file)
 
 #include <sound/jack.h>
 #include <sound/soc.h>
-#include <sound/soc-dapm.h>
 #include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/workqueue.h>
 #include <linux/delay.h>
+#include <trace/events/asoc.h>
 
 /**
  * snd_soc_jack_new - Create a new jack
@@ -60,14 +60,18 @@ EXPORT_SYMBOL_GPL(snd_soc_jack_new);
 void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
 {
        struct snd_soc_codec *codec;
+       struct snd_soc_dapm_context *dapm;
        struct snd_soc_jack_pin *pin;
        int enable;
        int oldstatus;
 
+       trace_snd_soc_jack_report(jack, mask, status);
+
        if (!jack)
                return;
 
        codec = jack->codec;
+       dapm =  &codec->dapm;
 
        mutex_lock(&codec->mutex);
 
@@ -81,6 +85,8 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
        if (mask && (jack->status == oldstatus))
                goto out;
 
+       trace_snd_soc_jack_notify(jack, status);
+
        list_for_each_entry(pin, &jack->pins, list) {
                enable = pin->mask & jack->status;
 
@@ -88,15 +94,15 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
                        enable = !enable;
 
                if (enable)
-                       snd_soc_dapm_enable_pin(codec, pin->pin);
+                       snd_soc_dapm_enable_pin(dapm, pin->pin);
                else
-                       snd_soc_dapm_disable_pin(codec, pin->pin);
+                       snd_soc_dapm_disable_pin(dapm, pin->pin);
        }
 
        /* Report before the DAPM sync to help users updating micbias status */
        blocking_notifier_call_chain(&jack->notifier, status, NULL);
 
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(dapm);
 
        snd_jack_report(jack->jack, status);
 
@@ -207,6 +213,12 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
 static irqreturn_t gpio_handler(int irq, void *data)
 {
        struct snd_soc_jack_gpio *gpio = data;
+       struct device *dev = gpio->jack->codec->card->dev;
+
+       trace_snd_soc_jack_irq(gpio->name);
+
+       if (device_may_wakeup(dev))
+               pm_wakeup_event(dev, gpio->debounce_time + 50);
 
        schedule_delayed_work(&gpio->work,
                              msecs_to_jiffies(gpio->debounce_time));
@@ -263,11 +275,12 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
                INIT_DELAYED_WORK(&gpios[i].work, gpio_work);
                gpios[i].jack = jack;
 
-               ret = request_irq(gpio_to_irq(gpios[i].gpio),
-                               gpio_handler,
-                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                               jack->codec->dev->driver->name,
-                               &gpios[i]);
+               ret = request_any_context_irq(gpio_to_irq(gpios[i].gpio),
+                                             gpio_handler,
+                                             IRQF_TRIGGER_RISING |
+                                             IRQF_TRIGGER_FALLING,
+                                             jack->codec->dev->driver->name,
+                                             &gpios[i]);
                if (ret)
                        goto err;
 
index 6914821..5b792d2 100644 (file)
@@ -76,7 +76,10 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
                format = 1 << UAC_FORMAT_TYPE_I_PCM;
        }
        if (format & (1 << UAC_FORMAT_TYPE_I_PCM)) {
-               if (sample_width > sample_bytes * 8) {
+               if (chip->usb_id == USB_ID(0x0582, 0x0016) /* Edirol SD-90 */ &&
+                   sample_width == 24 && sample_bytes == 2)
+                       sample_bytes = 3;
+               else if (sample_width > sample_bytes * 8) {
                        snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n",
                                   chip->dev->devnum, fp->iface, fp->altsetting,
                                   sample_width, sample_bytes);
index 25bce7e..db2dc5f 100644 (file)
@@ -850,8 +850,8 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep,
                return;
        }
 
-       memset(urb->transfer_buffer + count, 0xFD, 9 - count);
-       urb->transfer_buffer_length = count;
+       memset(urb->transfer_buffer + count, 0xFD, ep->max_transfer - count);
+       urb->transfer_buffer_length = ep->max_transfer;
 }
 
 static struct usb_protocol_ops snd_usbmidi_122l_ops = {
@@ -1295,6 +1295,13 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi,
        case USB_ID(0x1a86, 0x752d): /* QinHeng CH345 "USB2.0-MIDI" */
                ep->max_transfer = 4;
                break;
+               /*
+                * Some devices only work with 9 bytes packet size:
+                */
+       case USB_ID(0x0644, 0x800E): /* Tascam US-122L */
+       case USB_ID(0x0644, 0x800F): /* Tascam US-144 */
+               ep->max_transfer = 9;
+               break;
        }
        for (i = 0; i < OUTPUT_URBS; ++i) {
                buffer = usb_alloc_coherent(umidi->dev,
@@ -1729,13 +1736,7 @@ static int roland_load_info(struct snd_kcontrol *kcontrol,
 {
        static const char *const names[] = { "High Load", "Light Load" };
 
-       info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       info->count = 1;
-       info->value.enumerated.items = 2;
-       if (info->value.enumerated.item > 1)
-               info->value.enumerated.item = 1;
-       strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
-       return 0;
+       return snd_ctl_enum_info(info, 1, 2, names);
 }
 
 static int roland_load_get(struct snd_kcontrol *kcontrol,
index f2d74d6..7df89b3 100644 (file)
@@ -1633,18 +1633,11 @@ static int parse_audio_extension_unit(struct mixer_build *state, int unitid, voi
 static int mixer_ctl_selector_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
        struct usb_mixer_elem_info *cval = kcontrol->private_data;
-       char **itemlist = (char **)kcontrol->private_value;
+       const char **itemlist = (const char **)kcontrol->private_value;
 
        if (snd_BUG_ON(!itemlist))
                return -EINVAL;
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = cval->max;
-       if (uinfo->value.enumerated.item >= cval->max)
-               uinfo->value.enumerated.item = cval->max - 1;
-       strlcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item],
-               sizeof(uinfo->value.enumerated.name));
-       return 0;
+       return snd_ctl_enum_info(uinfo, 1, cval->max, itemlist);
 }
 
 /* get callback for selector unit */
index ad7079d..3599987 100644 (file)
@@ -705,11 +705,11 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                .data = (const struct snd_usb_audio_quirk[]) {
                        {
                                .ifnum = 0,
-                               .type = QUIRK_IGNORE_INTERFACE
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
                        },
                        {
                                .ifnum = 1,
-                               .type = QUIRK_IGNORE_INTERFACE
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
                        },
                        {
                                .ifnum = 2,
index 6ef68e4..084e6fc 100644 (file)
@@ -273,29 +273,26 @@ static unsigned int usb_stream_hwdep_poll(struct snd_hwdep *hw,
                                          struct file *file, poll_table *wait)
 {
        struct us122l   *us122l = hw->private_data;
-       struct usb_stream *s = us122l->sk.s;
        unsigned        *polled;
        unsigned int    mask;
 
        poll_wait(file, &us122l->sk.sleep, wait);
 
-       switch (s->state) {
-       case usb_stream_ready:
-               if (us122l->first == file)
-                       polled = &s->periods_polled;
-               else
-                       polled = &us122l->second_periods_polled;
-               if (*polled != s->periods_done) {
-                       *polled = s->periods_done;
-                       mask = POLLIN | POLLOUT | POLLWRNORM;
-                       break;
+       mask = POLLIN | POLLOUT | POLLWRNORM | POLLERR;
+       if (mutex_trylock(&us122l->mutex)) {
+               struct usb_stream *s = us122l->sk.s;
+               if (s && s->state == usb_stream_ready) {
+                       if (us122l->first == file)
+                               polled = &s->periods_polled;
+                       else
+                               polled = &us122l->second_periods_polled;
+                       if (*polled != s->periods_done) {
+                               *polled = s->periods_done;
+                               mask = POLLIN | POLLOUT | POLLWRNORM;
+                       } else
+                               mask = 0;
                }
-               /* Fall through */
-               mask = 0;
-               break;
-       default:
-               mask = POLLIN | POLLOUT | POLLWRNORM | POLLERR;
-               break;
+               mutex_unlock(&us122l->mutex);
        }
        return mask;
 }
@@ -381,6 +378,7 @@ static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
 {
        struct usb_stream_config *cfg;
        struct us122l *us122l = hw->private_data;
+       struct usb_stream *s;
        unsigned min_period_frames;
        int err = 0;
        bool high_speed;
@@ -426,18 +424,18 @@ static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
        snd_power_wait(hw->card, SNDRV_CTL_POWER_D0);
 
        mutex_lock(&us122l->mutex);
+       s = us122l->sk.s;
        if (!us122l->master)
                us122l->master = file;
        else if (us122l->master != file) {
-               if (memcmp(cfg, &us122l->sk.s->cfg, sizeof(*cfg))) {
+               if (!s || memcmp(cfg, &s->cfg, sizeof(*cfg))) {
                        err = -EIO;
                        goto unlock;
                }
                us122l->slave = file;
        }
-       if (!us122l->sk.s ||
-           memcmp(cfg, &us122l->sk.s->cfg, sizeof(*cfg)) ||
-           us122l->sk.s->state == usb_stream_xrun) {
+       if (!s || memcmp(cfg, &s->cfg, sizeof(*cfg)) ||
+           s->state == usb_stream_xrun) {
                us122l_stop(us122l);
                if (!us122l_start(us122l, cfg->sample_rate, cfg->period_frames))
                        err = -EIO;
@@ -448,6 +446,7 @@ unlock:
        mutex_unlock(&us122l->mutex);
 free:
        kfree(cfg);
+       wake_up_all(&us122l->sk.sleep);
        return err;
 }