]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 25 Oct 2010 15:32:05 +0000 (08:32 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 25 Oct 2010 15:32:05 +0000 (08:32 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (365 commits)
  ALSA: hda - Disable sticky PCM stream assignment for AD codecs
  ALSA: usb - Creative USB X-Fi volume knob support
  ALSA: ca0106: Use card specific dac id for mute controls.
  ALSA: ca0106: Allow different sound cards to use different SPI channel mappings.
  ALSA: ca0106: Create a nice spot for mapping channels to dacs.
  ALSA: ca0106: Move enabling of front dac out of hardcoded setup sequence.
  ALSA: ca0106: Pull out dac powering routine into separate function.
  ALSA: ca0106 - add Sound Blaster 5.1vx info.
  ASoC: tlv320dac33: Use usleep_range for delays
  ALSA: usb-audio: add Novation Launchpad support
  ALSA: hda - Add workarounds for CT-IBG controllers
  ALSA: hda - Fix wrong TLV mute bit for STAC/IDT codecs
  ASoC: tpa6130a2: Error handling for broken chip
  ASoC: max98088: Staticise m98088_eq_band
  ASoC: soc-core: Fix codec->name memory leak
  ALSA: hda - Apply ideapad quirk to Acer laptops with Cxt5066
  ALSA: hda - Add some workarounds for Creative IBG
  ALSA: hda - Fix wrong SPDIF NID assignment for CA0110
  ALSA: hda - Fix codec rename rules for ALC662-compatible codecs
  ALSA: hda - Add alc_init_jacks() call to other codecs
  ...

479 files changed:
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/HD-Audio.txt
arch/arm/mach-davinci/devices.c
arch/arm/mach-ep93xx/core.c
arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
arch/arm/mach-ep93xx/include/mach/platform.h
arch/arm/mach-ep93xx/simone.c
arch/arm/mach-kirkwood/common.c
arch/arm/mach-omap1/devices.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/board-zoom-peripherals.c
arch/arm/mach-omap2/board-zoom2.c
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/include/mach/board-zoom.h
arch/arm/mach-pxa/devices.c
arch/arm/mach-pxa/devices.h
arch/arm/mach-pxa/pxa27x.c
arch/arm/mach-pxa/pxa3xx.c
arch/arm/mach-pxa/zylonite.c
arch/arm/mach-s3c64xx/dev-audio.c
arch/arm/mach-s3c64xx/mach-smdk6410.c
arch/arm/plat-omap/include/plat/mcbsp.h
arch/arm/plat-s3c24xx/devs.c
arch/arm/plat-samsung/include/plat/devs.h
arch/mips/alchemy/devboards/db1200/platform.c
arch/powerpc/boot/dts/mpc8610_hpcd.dts
arch/powerpc/configs/mpc85xx_defconfig
arch/powerpc/configs/mpc85xx_smp_defconfig
arch/powerpc/include/asm/fsl_guts.h [moved from arch/powerpc/include/asm/immap_86xx.h with 66% similarity]
arch/powerpc/platforms/85xx/p1022_ds.c
arch/sh/kernel/cpu/sh4a/setup-sh7722.c
drivers/input/misc/twl4030-vibra.c
drivers/mfd/twl-core.c
drivers/mfd/twl4030-codec.c
drivers/staging/xgifb/TODO
drivers/video/Kconfig
drivers/video/sh_mobile_hdmi.c
include/linux/i2c/twl.h
include/sound/core.h
include/sound/emu10k1.h
include/sound/jack.h
include/sound/max98088.h [new file with mode: 0644]
include/sound/pcm.h
include/sound/sh_fsi.h
include/sound/soc-dai.h
include/sound/soc-dapm.h
include/sound/soc-of-simple.h [deleted file]
include/sound/soc.h
include/sound/tlv.h
include/sound/tlv320aic3x.h
include/sound/wm8962.h [new file with mode: 0644]
include/video/sh_mobile_hdmi.h
sound/core/init.c
sound/core/oss/mixer_oss.c
sound/core/pcm.c
sound/core/pcm_lib.c
sound/core/pcm_native.c
sound/drivers/Kconfig
sound/drivers/Makefile
sound/drivers/aloop.c [new file with mode: 0644]
sound/drivers/virmidi.c
sound/i2c/other/ak4xxx-adda.c
sound/isa/Kconfig
sound/isa/Makefile
sound/isa/ad1816a/ad1816a.c
sound/isa/azt2320.c
sound/isa/galaxy/Makefile [new file with mode: 0644]
sound/isa/galaxy/azt1605.c [new file with mode: 0644]
sound/isa/galaxy/azt2316.c [new file with mode: 0644]
sound/isa/galaxy/galaxy.c [new file with mode: 0644]
sound/isa/gus/gusmax.c
sound/isa/sb/sb8.c
sound/isa/sgalaxy.c [deleted file]
sound/oss/Kconfig
sound/oss/Makefile
sound/oss/au1550_ac97.c
sound/oss/dmasound/dmasound_core.c
sound/oss/msnd_pinnacle.c
sound/oss/sh_dac_audio.c [deleted file]
sound/oss/soundcard.c
sound/oss/swarm_cs4297a.c
sound/oss/vwsnd.c
sound/pci/Kconfig
sound/pci/au88x0/au88x0_mixer.c
sound/pci/ca0106/ca0106.h
sound/pci/ca0106/ca0106_main.c
sound/pci/ca0106/ca0106_mixer.c
sound/pci/emu10k1/emumpu401.c
sound/pci/hda/Kconfig
sound/pci/hda/Makefile
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_eld.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_local.h
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_atihdmi.c [deleted file]
sound/pci/hda/patch_ca0110.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_intelhdmi.c [deleted file]
sound/pci/hda/patch_nvhdmi.c [deleted file]
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/ice1712/pontis.c
sound/pci/ice1712/prodigy192.c
sound/pci/oxygen/oxygen.c
sound/pci/oxygen/oxygen.h
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/virtuoso.c
sound/pci/oxygen/xonar_cs43xx.c
sound/pci/oxygen/xonar_pcm179x.c
sound/pci/oxygen/xonar_wm87x6.c
sound/pci/rme96.c
sound/pci/rme9652/hdsp.c
sound/ppc/tumbler.c
sound/soc/atmel/atmel-pcm.c
sound/soc/atmel/atmel-pcm.h
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/atmel/atmel_ssc_dai.h
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/au1x/dbdma2.c
sound/soc/au1x/psc-ac97.c
sound/soc/au1x/psc-i2s.c
sound/soc/au1x/psc.h
sound/soc/blackfin/bf5xx-ac97-pcm.c
sound/soc/blackfin/bf5xx-ac97-pcm.h
sound/soc/blackfin/bf5xx-ac97.c
sound/soc/blackfin/bf5xx-ac97.h
sound/soc/blackfin/bf5xx-ad1836.c
sound/soc/blackfin/bf5xx-ad193x.c
sound/soc/blackfin/bf5xx-ad1980.c
sound/soc/blackfin/bf5xx-ad73311.c
sound/soc/blackfin/bf5xx-i2s-pcm.c
sound/soc/blackfin/bf5xx-i2s-pcm.h
sound/soc/blackfin/bf5xx-i2s.c
sound/soc/blackfin/bf5xx-i2s.h [deleted file]
sound/soc/blackfin/bf5xx-ssm2602.c
sound/soc/blackfin/bf5xx-tdm-pcm.c
sound/soc/blackfin/bf5xx-tdm-pcm.h
sound/soc/blackfin/bf5xx-tdm.c
sound/soc/blackfin/bf5xx-tdm.h
sound/soc/codecs/88pm860x-codec.c [new file with mode: 0644]
sound/soc/codecs/88pm860x-codec.h [new file with mode: 0644]
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ac97.c
sound/soc/codecs/ac97.h [deleted file]
sound/soc/codecs/ad1836.c
sound/soc/codecs/ad1836.h
sound/soc/codecs/ad193x.c
sound/soc/codecs/ad193x.h
sound/soc/codecs/ad1980.c
sound/soc/codecs/ad1980.h
sound/soc/codecs/ad73311.c
sound/soc/codecs/ad73311.h
sound/soc/codecs/ads117x.c
sound/soc/codecs/ads117x.h
sound/soc/codecs/ak4104.c
sound/soc/codecs/ak4104.h [deleted file]
sound/soc/codecs/ak4535.c
sound/soc/codecs/ak4535.h
sound/soc/codecs/ak4642.c
sound/soc/codecs/ak4642.h [deleted file]
sound/soc/codecs/ak4671.c
sound/soc/codecs/ak4671.h
sound/soc/codecs/cq93vc.c
sound/soc/codecs/cq93vc.h [deleted file]
sound/soc/codecs/cs4270.c
sound/soc/codecs/cs4270.h [deleted file]
sound/soc/codecs/cs42l51.c
sound/soc/codecs/cs42l51.h
sound/soc/codecs/cx20442.c
sound/soc/codecs/cx20442.h
sound/soc/codecs/da7210.c
sound/soc/codecs/da7210.h [deleted file]
sound/soc/codecs/jz4740.c
sound/soc/codecs/jz4740.h [deleted file]
sound/soc/codecs/max98088.c [new file with mode: 0644]
sound/soc/codecs/max98088.h [new file with mode: 0644]
sound/soc/codecs/pcm3008.c
sound/soc/codecs/pcm3008.h
sound/soc/codecs/spdif_transciever.c
sound/soc/codecs/spdif_transciever.h [deleted file]
sound/soc/codecs/ssm2602.c
sound/soc/codecs/ssm2602.h
sound/soc/codecs/stac9766.c
sound/soc/codecs/stac9766.h
sound/soc/codecs/tlv320aic23.c
sound/soc/codecs/tlv320aic23.h
sound/soc/codecs/tlv320aic26.c
sound/soc/codecs/tlv320aic26.h
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320aic3x.h
sound/soc/codecs/tlv320dac33.c
sound/soc/codecs/tlv320dac33.h
sound/soc/codecs/tpa6130a2.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/twl4030.h [deleted file]
sound/soc/codecs/twl6040.c
sound/soc/codecs/twl6040.h
sound/soc/codecs/uda134x.c
sound/soc/codecs/uda134x.h
sound/soc/codecs/uda1380.c
sound/soc/codecs/uda1380.h
sound/soc/codecs/wl1273.c [new file with mode: 0644]
sound/soc/codecs/wl1273.h [new file with mode: 0644]
sound/soc/codecs/wm2000.h
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8350.h
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8400.h
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8510.h
sound/soc/codecs/wm8523.c
sound/soc/codecs/wm8523.h
sound/soc/codecs/wm8580.c
sound/soc/codecs/wm8580.h
sound/soc/codecs/wm8711.c
sound/soc/codecs/wm8711.h
sound/soc/codecs/wm8727.c
sound/soc/codecs/wm8727.h [deleted file]
sound/soc/codecs/wm8728.c
sound/soc/codecs/wm8728.h
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8731.h
sound/soc/codecs/wm8741.c
sound/soc/codecs/wm8741.h
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8750.h
sound/soc/codecs/wm8753.c
sound/soc/codecs/wm8753.h
sound/soc/codecs/wm8776.c
sound/soc/codecs/wm8776.h
sound/soc/codecs/wm8804.c [new file with mode: 0644]
sound/soc/codecs/wm8804.h [new file with mode: 0644]
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8900.h
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8903.h
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8904.h
sound/soc/codecs/wm8940.c
sound/soc/codecs/wm8940.h
sound/soc/codecs/wm8955.c
sound/soc/codecs/wm8955.h
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8960.h
sound/soc/codecs/wm8961.c
sound/soc/codecs/wm8961.h
sound/soc/codecs/wm8962.c [new file with mode: 0644]
sound/soc/codecs/wm8962.h [new file with mode: 0644]
sound/soc/codecs/wm8971.c
sound/soc/codecs/wm8971.h
sound/soc/codecs/wm8974.c
sound/soc/codecs/wm8974.h
sound/soc/codecs/wm8978.c
sound/soc/codecs/wm8978.h
sound/soc/codecs/wm8985.c [new file with mode: 0644]
sound/soc/codecs/wm8985.h [new file with mode: 0644]
sound/soc/codecs/wm8988.c
sound/soc/codecs/wm8988.h
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm8990.h
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm8993.h
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8994.h
sound/soc/codecs/wm9081.c
sound/soc/codecs/wm9081.h
sound/soc/codecs/wm9090.c
sound/soc/codecs/wm9090.h
sound/soc/codecs/wm9705.c
sound/soc/codecs/wm9705.h
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9712.h
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm9713.h
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-i2s.c
sound/soc/davinci/davinci-i2s.h
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/davinci-mcasp.h
sound/soc/davinci/davinci-pcm.c
sound/soc/davinci/davinci-pcm.h
sound/soc/davinci/davinci-sffsdr.c
sound/soc/davinci/davinci-vcif.c
sound/soc/davinci/davinci-vcif.h [deleted file]
sound/soc/ep93xx/Kconfig
sound/soc/ep93xx/Makefile
sound/soc/ep93xx/ep93xx-ac97.c [new file with mode: 0644]
sound/soc/ep93xx/ep93xx-i2s.c
sound/soc/ep93xx/ep93xx-i2s.h [deleted file]
sound/soc/ep93xx/ep93xx-pcm.c
sound/soc/ep93xx/ep93xx-pcm.h
sound/soc/ep93xx/simone.c [new file with mode: 0644]
sound/soc/ep93xx/snappercl15.c
sound/soc/fsl/Kconfig
sound/soc/fsl/Makefile
sound/soc/fsl/efika-audio-fabric.c
sound/soc/fsl/fsl_dma.c
sound/soc/fsl/fsl_dma.h
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/fsl_ssi.h
sound/soc/fsl/mpc5200_dma.c
sound/soc/fsl/mpc5200_dma.h
sound/soc/fsl/mpc5200_psc_ac97.c
sound/soc/fsl/mpc5200_psc_ac97.h
sound/soc/fsl/mpc5200_psc_i2s.c
sound/soc/fsl/mpc8610_hpcd.c
sound/soc/fsl/p1022_ds.c [new file with mode: 0644]
sound/soc/fsl/pcm030-audio-fabric.c
sound/soc/fsl/soc-of-simple.c [deleted file]
sound/soc/imx/Kconfig
sound/soc/imx/Makefile
sound/soc/imx/eukrea-tlv320.c
sound/soc/imx/imx-pcm-dma-mx2.c
sound/soc/imx/imx-pcm-fiq.c
sound/soc/imx/imx-ssi.c
sound/soc/imx/imx-ssi.h
sound/soc/imx/phycore-ac97.c
sound/soc/imx/wm1133-ev1.c
sound/soc/jz4740/jz4740-i2s.c
sound/soc/jz4740/jz4740-i2s.h
sound/soc/jz4740/jz4740-pcm.c
sound/soc/jz4740/jz4740-pcm.h
sound/soc/jz4740/qi_lb60.c
sound/soc/kirkwood/kirkwood-dma.c
sound/soc/kirkwood/kirkwood-dma.h [deleted file]
sound/soc/kirkwood/kirkwood-i2s.c
sound/soc/kirkwood/kirkwood-i2s.h [deleted file]
sound/soc/kirkwood/kirkwood-openrd.c
sound/soc/nuc900/nuc900-ac97.c
sound/soc/nuc900/nuc900-audio.c
sound/soc/nuc900/nuc900-audio.h
sound/soc/nuc900/nuc900-pcm.c
sound/soc/omap/am3517evm.c
sound/soc/omap/ams-delta.c
sound/soc/omap/igep0020.c
sound/soc/omap/mcpdm.c
sound/soc/omap/mcpdm.h
sound/soc/omap/n810.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-mcbsp.h
sound/soc/omap/omap-mcpdm.c
sound/soc/omap/omap-mcpdm.h [deleted file]
sound/soc/omap/omap-pcm.c
sound/soc/omap/omap-pcm.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/Kconfig
sound/soc/pxa/Makefile
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/imote2.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/pxa-ssp.c
sound/soc/pxa/pxa-ssp.h
sound/soc/pxa/pxa2xx-ac97.c
sound/soc/pxa/pxa2xx-ac97.h
sound/soc/pxa/pxa2xx-i2s.c
sound/soc/pxa/pxa2xx-i2s.h
sound/soc/pxa/pxa2xx-pcm.c
sound/soc/pxa/pxa2xx-pcm.h [deleted file]
sound/soc/pxa/raumfeld.c
sound/soc/pxa/saarb.c [new file with mode: 0644]
sound/soc/pxa/spitz.c
sound/soc/pxa/tavorevb3.c [new file with mode: 0644]
sound/soc/pxa/tosa.c
sound/soc/pxa/z2.c
sound/soc/pxa/zylonite.c
sound/soc/s3c24xx/Kconfig
sound/soc/s3c24xx/Makefile
sound/soc/s3c24xx/aquila_wm8994.c [new file with mode: 0644]
sound/soc/s3c24xx/goni_wm8994.c [new file with mode: 0644]
sound/soc/s3c24xx/jive_wm8750.c
sound/soc/s3c24xx/ln2440sbc_alc650.c
sound/soc/s3c24xx/neo1973_gta02_wm8753.c
sound/soc/s3c24xx/neo1973_wm8753.c
sound/soc/s3c24xx/rx1950_uda1380.c [new file with mode: 0644]
sound/soc/s3c24xx/s3c-ac97.c
sound/soc/s3c24xx/s3c-ac97.h
sound/soc/s3c24xx/s3c-dma.c
sound/soc/s3c24xx/s3c-dma.h
sound/soc/s3c24xx/s3c-i2s-v2.c
sound/soc/s3c24xx/s3c-i2s-v2.h
sound/soc/s3c24xx/s3c-pcm.c
sound/soc/s3c24xx/s3c-pcm.h
sound/soc/s3c24xx/s3c2412-i2s.c
sound/soc/s3c24xx/s3c2412-i2s.h
sound/soc/s3c24xx/s3c24xx-i2s.c
sound/soc/s3c24xx/s3c24xx-i2s.h
sound/soc/s3c24xx/s3c24xx_simtec.c
sound/soc/s3c24xx/s3c24xx_simtec.h
sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
sound/soc/s3c24xx/s3c24xx_uda134x.c
sound/soc/s3c24xx/s3c64xx-i2s-v4.c
sound/soc/s3c24xx/s3c64xx-i2s.c
sound/soc/s3c24xx/s3c64xx-i2s.h
sound/soc/s3c24xx/smartq_wm8987.c
sound/soc/s3c24xx/smdk2443_wm9710.c
sound/soc/s3c24xx/smdk64xx_wm8580.c
sound/soc/s3c24xx/smdk_spdif.c [new file with mode: 0644]
sound/soc/s3c24xx/smdk_wm9713.c
sound/soc/s3c24xx/spdif.c [new file with mode: 0644]
sound/soc/s3c24xx/spdif.h [new file with mode: 0644]
sound/soc/s6000/s6000-i2s.c
sound/soc/s6000/s6000-i2s.h
sound/soc/s6000/s6000-pcm.c
sound/soc/s6000/s6000-pcm.h
sound/soc/s6000/s6105-ipcam.c
sound/soc/sh/Kconfig
sound/soc/sh/Makefile
sound/soc/sh/dma-sh7760.c
sound/soc/sh/fsi-ak4642.c
sound/soc/sh/fsi-da7210.c
sound/soc/sh/fsi-hdmi.c [new file with mode: 0644]
sound/soc/sh/fsi.c
sound/soc/sh/hac.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/sh/ssi.c
sound/soc/soc-cache.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-jack.c
sound/soc/txx9/txx9aclc-ac97.c
sound/soc/txx9/txx9aclc-generic.c
sound/soc/txx9/txx9aclc.c
sound/soc/txx9/txx9aclc.h
sound/synth/emux/emux_hwdep.c
sound/usb/Kconfig
sound/usb/caiaq/audio.c
sound/usb/caiaq/control.c
sound/usb/caiaq/device.c
sound/usb/caiaq/device.h
sound/usb/caiaq/input.c
sound/usb/card.c
sound/usb/endpoint.c
sound/usb/helper.c
sound/usb/midi.c
sound/usb/mixer.c
sound/usb/mixer_quirks.c
sound/usb/pcm.c
sound/usb/proc.c
sound/usb/quirks-table.h
sound/usb/quirks.c
sound/usb/urb.c
sound/usb/usbaudio.h
sound/usb/usx2y/usx2yhwdeppcm.c

index 7f4dcebda9c62d75fa7a3d23709fc77dbb42cf77..d0eb696d32e8ade011a695a401fdfc51e42d7be5 100644 (file)
@@ -300,6 +300,74 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
            control correctly. If you have problems regarding this, try
            another ALSA compliant mixer (alsamixer works).
 
+  Module snd-azt1605
+  ------------------
+
+    Module for Aztech Sound Galaxy soundcards based on the Aztech AZT1605
+    chipset.
+
+    port       - port # for BASE (0x220,0x240,0x260,0x280)
+    wss_port   - port # for WSS (0x530,0x604,0xe80,0xf40)
+    irq                - IRQ # for WSS (7,9,10,11)
+    dma1       - DMA # for WSS playback (0,1,3)
+    dma2       - DMA # for WSS capture (0,1), -1 = disabled (default)
+    mpu_port   - port # for MPU-401 UART (0x300,0x330), -1 = disabled (default)
+    mpu_irq    - IRQ # for MPU-401 UART (3,5,7,9), -1 = disabled (default)
+    fm_port    - port # for OPL3 (0x388), -1 = disabled (default)
+
+    This module supports multiple cards. It does not support autoprobe: port,
+    wss_port, irq and dma1 have to be specified. The other values are
+    optional.
+
+    "port" needs to match the BASE ADDRESS jumper on the card (0x220 or 0x240)
+    or the value stored in the card's EEPROM for cards that have an EEPROM and
+    their "CONFIG MODE" jumper set to "EEPROM SETTING". The other values can
+    be choosen freely from the options enumerated above.
+
+    If dma2 is specified and different from dma1, the card will operate in
+    full-duplex mode. When dma1=3, only dma2=0 is valid and the only way to
+    enable capture since only channels 0 and 1 are available for capture.
+
+    Generic settings are "port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0
+    mpu_port=0x330 mpu_irq=9 fm_port=0x388".
+
+    Whatever IRQ and DMA channels you pick, be sure to reserve them for
+    legacy ISA in your BIOS.
+
+  Module snd-azt2316
+  ------------------
+
+    Module for Aztech Sound Galaxy soundcards based on the Aztech AZT2316
+    chipset.
+
+    port       - port # for BASE (0x220,0x240,0x260,0x280)
+    wss_port   - port # for WSS (0x530,0x604,0xe80,0xf40)
+    irq                - IRQ # for WSS (7,9,10,11)
+    dma1       - DMA # for WSS playback (0,1,3)
+    dma2       - DMA # for WSS capture (0,1), -1 = disabled (default)
+    mpu_port   - port # for MPU-401 UART (0x300,0x330), -1 = disabled (default)
+    mpu_irq    - IRQ # for MPU-401 UART (5,7,9,10), -1 = disabled (default)
+    fm_port    - port # for OPL3 (0x388), -1 = disabled (default)
+
+    This module supports multiple cards. It does not support autoprobe: port,
+    wss_port, irq and dma1 have to be specified. The other values are
+    optional.
+
+    "port" needs to match the BASE ADDRESS jumper on the card (0x220 or 0x240)
+    or the value stored in the card's EEPROM for cards that have an EEPROM and
+    their "CONFIG MODE" jumper set to "EEPROM SETTING". The other values can
+    be choosen freely from the options enumerated above.
+
+    If dma2 is specified and different from dma1, the card will operate in
+    full-duplex mode. When dma1=3, only dma2=0 is valid and the only way to
+    enable capture since only channels 0 and 1 are available for capture.
+
+    Generic settings are "port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0
+    mpu_port=0x330 mpu_irq=9 fm_port=0x388".
+
+    Whatever IRQ and DMA channels you pick, be sure to reserve them for
+    legacy ISA in your BIOS.
+
   Module snd-aw2
   --------------
 
@@ -1641,20 +1709,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     This card is also known as Audio Excel DSP 16 or Zoltrix AV302.
 
-  Module snd-sgalaxy
-  ------------------
-
-    Module for Aztech Sound Galaxy sound card.
-
-    sbport     - Port # for SB16 interface (0x220,0x240)
-    wssport    - Port # for WSS interface (0x530,0xe80,0xf40,0x604)
-    irq                - IRQ # (7,9,10,11)
-    dma1       - DMA #
-
-    This module supports multiple cards.
-
-    The power-management is supported.
-
   Module snd-sscape
   -----------------
 
index 278cc2122ea056797aa3c6ae04c77b4052f5f5f9..c82beb0076341856ca13b1e1dd125cc440ed439c 100644 (file)
@@ -57,9 +57,11 @@ dead.  However, this detection isn't perfect on some devices.  In such
 a case, you can change the default method via `position_fix` option.
 
 `position_fix=1` means to use LPIB method explicitly.
-`position_fix=2` means to use the position-buffer.  0 is the default
-value, the automatic check and fallback to LPIB as described in the
-above.  If you get a problem of repeated sounds, this option might
+`position_fix=2` means to use the position-buffer.
+`position_fix=3` means to use a combination of both methods, needed
+for some VIA and ATI controllers.  0 is the default value for all other
+controllers, the automatic check and fallback to LPIB as described in
+the above.  If you get a problem of repeated sounds, this option might
 help.
 
 In addition to that, every controller is known to be broken regarding
index 8b7201e4c79c6aabd616a11a696bf183357a911b..de40e9c787e1621b12ccaf98313f70a32d4c9839 100644 (file)
@@ -295,6 +295,18 @@ static void davinci_init_wdt(void)
 
 /*-------------------------------------------------------------------------*/
 
+struct platform_device davinci_pcm_device = {
+       .name           = "davinci-pcm-audio",
+       .id             = -1,
+};
+
+static void davinci_init_pcm(void)
+{
+       platform_device_register(&davinci_pcm_device);
+}
+
+/*-------------------------------------------------------------------------*/
+
 struct davinci_timer_instance davinci_timer_instance[2] = {
        {
                .base           = DAVINCI_TIMER0_BASE,
@@ -315,6 +327,7 @@ static int __init davinci_init_devices(void)
        /* please keep these calls, and their implementations above,
         * in alphabetical order so they're easier to sort through.
         */
+       davinci_init_pcm();
        davinci_init_wdt();
 
        return 0;
index 4cb55d3902ff675e4fb5e3ed59d6244eb20f181d..ffdf87be295855e93a5e74734c86d060e28b4022 100644 (file)
@@ -776,9 +776,15 @@ static struct platform_device ep93xx_i2s_device = {
        .resource       = ep93xx_i2s_resource,
 };
 
+static struct platform_device ep93xx_pcm_device = {
+       .name           = "ep93xx-pcm-audio",
+       .id             = -1,
+};
+
 void __init ep93xx_register_i2s(void)
 {
        platform_device_register(&ep93xx_i2s_device);
+       platform_device_register(&ep93xx_pcm_device);
 }
 
 #define EP93XX_SYSCON_DEVCFG_I2S_MASK  (EP93XX_SYSCON_DEVCFG_I2SONSSP | \
@@ -826,6 +832,40 @@ void ep93xx_i2s_release(void)
 }
 EXPORT_SYMBOL(ep93xx_i2s_release);
 
+/*************************************************************************
+ * EP93xx AC97 audio peripheral handling
+ *************************************************************************/
+static struct resource ep93xx_ac97_resources[] = {
+       {
+               .start  = EP93XX_AAC_PHYS_BASE,
+               .end    = EP93XX_AAC_PHYS_BASE + 0xb0 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = IRQ_EP93XX_AACINTR,
+               .end    = IRQ_EP93XX_AACINTR,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device ep93xx_ac97_device = {
+       .name           = "ep93xx-ac97",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(ep93xx_ac97_resources),
+       .resource       = ep93xx_ac97_resources,
+};
+
+void __init ep93xx_register_ac97(void)
+{
+       /*
+        * Make sure that the AC97 pins are not used by I2S.
+        */
+       ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONAC97);
+
+       platform_device_register(&ep93xx_ac97_device);
+       platform_device_register(&ep93xx_pcm_device);
+}
+
 extern void ep93xx_gpio_init(void);
 
 void __init ep93xx_init_devices(void)
index c54b3e56ba635a6c3edfc599dcf9154f27c5d43c..9ac4d105509727ef7968fedd488a9f121f73a6b0 100644 (file)
 #define EP93XX_GPIO_B_INT_STATUS       EP93XX_GPIO_REG(0xbc)
 #define EP93XX_GPIO_EEDRIVE            EP93XX_GPIO_REG(0xc8)
 
+#define EP93XX_AAC_PHYS_BASE           EP93XX_APB_PHYS(0x00080000)
 #define EP93XX_AAC_BASE                        EP93XX_APB_IOMEM(0x00080000)
 
 #define EP93XX_SPI_PHYS_BASE           EP93XX_APB_PHYS(0x000a0000)
index 3330b36d79e6a0838a88b0960db3ee436e0edc33..50660455b1d8bbaca6f221e8a8f7aa1710816057 100644 (file)
@@ -61,6 +61,7 @@ void ep93xx_keypad_release_gpio(struct platform_device *pdev);
 void ep93xx_register_i2s(void);
 int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config);
 void ep93xx_i2s_release(void);
+void ep93xx_register_ac97(void);
 
 void ep93xx_init_devices(void);
 extern struct sys_timer ep93xx_timer;
index f22ce8db7947b616f7f45cf7fe6cf7eeebec62f2..d96dc1c5da20a26c0f3b4017d2411d16ceacadd7 100644 (file)
@@ -61,6 +61,7 @@ static void __init simone_init_machine(void)
        ep93xx_register_fb(&simone_fb_info);
        ep93xx_register_i2c(&simone_i2c_gpio_data, simone_i2c_board_info,
                            ARRAY_SIZE(simone_i2c_board_info));
+       ep93xx_register_ac97();
 }
 
 MACHINE_START(SIM_ONE, "Simplemachines Sim.One Board")
index 1c82d4290dad6f6e593022fb318e4f67b5694fb6..51ff23b72d3a3e8d6982b031dd36df0c3c1cc711 100644 (file)
@@ -903,10 +903,16 @@ static struct platform_device kirkwood_i2s_device = {
        },
 };
 
+static struct platform_device kirkwood_pcm_device = {
+       .name           = "kirkwood-pcm-audio",
+       .id             = -1,
+};
+
 void __init kirkwood_audio_init(void)
 {
        kirkwood_clk_ctrl |= CGC_AUDIO;
        platform_device_register(&kirkwood_i2s_device);
+       platform_device_register(&kirkwood_pcm_device);
 }
 
 /*****************************************************************************
index aa0725608fb17ec51e15cc077f0f3198a19018ab..b583121b04b9ff221dbf3b859c833d674e9fcbde 100644 (file)
@@ -25,6 +25,7 @@
 #include <mach/gpio.h>
 #include <plat/mmc.h>
 #include <plat/omap7xx.h>
+#include <plat/mcbsp.h>
 
 /*-------------------------------------------------------------------------*/
 
@@ -195,6 +196,30 @@ static inline void omap_init_spi100k(void)
 
 static inline void omap_init_sti(void) {}
 
+#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE)
+
+static struct platform_device omap_pcm = {
+       .name   = "omap-pcm-audio",
+       .id     = -1,
+};
+
+OMAP_MCBSP_PLATFORM_DEVICE(1);
+OMAP_MCBSP_PLATFORM_DEVICE(2);
+OMAP_MCBSP_PLATFORM_DEVICE(3);
+
+static void omap_init_audio(void)
+{
+       platform_device_register(&omap_mcbsp1);
+       platform_device_register(&omap_mcbsp2);
+       if (!cpu_is_omap7xx())
+               platform_device_register(&omap_mcbsp3);
+       platform_device_register(&omap_pcm);
+}
+
+#else
+static inline void omap_init_audio(void) {}
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -227,6 +252,7 @@ static int __init omap1_init_devices(void)
        omap_init_rtc();
        omap_init_spi100k();
        omap_init_sti();
+       omap_init_audio();
 
        return 0;
 }
index ce28a851dcd3f06f954ccd64a03e72c30e229854..63d786bccb67f60f9f9366b690de20f928236b59 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/mmc/host.h>
+#include <sound/tlv320aic3x.h>
 
 #include <plat/mcspi.h>
 #include <plat/board.h>
@@ -689,7 +690,6 @@ static struct twl4030_power_data rx51_t2scripts_data __initdata = {
 };
 
 
-
 static struct twl4030_platform_data rx51_twldata __initdata = {
        .irq_base               = TWL4030_IRQ_BASE,
        .irq_end                = TWL4030_IRQ_END,
@@ -710,10 +710,6 @@ static struct twl4030_platform_data rx51_twldata __initdata = {
        .vio                    = &rx51_vio,
 };
 
-static struct aic3x_pdata rx51_aic3x_data __initdata = {
-       .gpio_reset             = 60,
-};
-
 static struct tpa6130a2_platform_data rx51_tpa6130a2_data __initdata = {
        .id                     = TPA6130A2,
        .power_gpio             = 98,
@@ -728,6 +724,17 @@ static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_1[] = {
        },
 };
 
+/* Audio setup data */
+static struct aic3x_setup_data rx51_aic34_setup = {
+       .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
+       .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
+};
+
+static struct aic3x_pdata rx51_aic3x_data = {
+       .setup = &rx51_aic34_setup,
+       .gpio_reset = 60,
+};
+
 static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_2[] = {
        {
                I2C_BOARD_INFO("tlv320aic3x", 0x18),
index 189a6d1600b208ef448ea210139d2d3faa056e29..bc8232845d7ade22e219b4c4ddf01ef08acf24df 100644 (file)
@@ -26,6 +26,8 @@
 #include <plat/common.h>
 #include <plat/usb.h>
 
+#include <mach/board-zoom.h>
+
 #include "mux.h"
 #include "hsmmc.h"
 
@@ -238,6 +240,11 @@ static int zoom_twl_gpio_setup(struct device *dev,
        return 0;
 }
 
+/* EXTMUTE callback function */
+void zoom2_set_hs_extmute(int mute)
+{
+       gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute);
+}
 
 static int zoom_batt_table[] = {
 /* 0 C*/
@@ -307,6 +314,11 @@ static struct i2c_board_info __initdata zoom_i2c_boardinfo[] = {
 
 static int __init omap_i2c_init(void)
 {
+       if (machine_is_omap_zoom2()) {
+               zoom_audio_data.ramp_delay_value = 3;   /* 161 ms */
+               zoom_audio_data.hs_extmute = 1;
+               zoom_audio_data.set_hs_extmute = zoom2_set_hs_extmute;
+       }
        omap_register_i2c_bus(1, 2400, zoom_i2c_boardinfo,
                        ARRAY_SIZE(zoom_i2c_boardinfo));
        omap_register_i2c_bus(2, 400, NULL, 0);
index 24bbd0def64ff4b3e6617dc01910c491a7b557c8..4ccbc32386a079acf5202ee75a98c078f010702c 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/platform_device.h>
 #include <linux/input.h>
 #include <linux/gpio.h>
+#include <linux/i2c/twl.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -34,41 +35,6 @@ static void __init omap_zoom2_init_irq(void)
        omap_gpio_init();
 }
 
-/* REVISIT: These audio entries can be removed once MFD code is merged */
-#if 0
-
-static struct twl4030_madc_platform_data zoom2_madc_data = {
-       .irq_line       = 1,
-};
-
-static struct twl4030_codec_audio_data zoom2_audio_data = {
-       .audio_mclk = 26000000,
-};
-
-static struct twl4030_codec_data zoom2_codec_data = {
-       .audio_mclk = 26000000,
-       .audio = &zoom2_audio_data,
-};
-
-static struct twl4030_platform_data zoom2_twldata = {
-       .irq_base       = TWL4030_IRQ_BASE,
-       .irq_end        = TWL4030_IRQ_END,
-
-       /* platform_data for children goes here */
-       .bci            = &zoom2_bci_data,
-       .madc           = &zoom2_madc_data,
-       .usb            = &zoom2_usb_data,
-       .gpio           = &zoom2_gpio_data,
-       .keypad         = &zoom2_kp_twl4030_data,
-       .codec          = &zoom2_codec_data,
-       .vmmc1          = &zoom2_vmmc1,
-       .vmmc2          = &zoom2_vmmc2,
-       .vsim           = &zoom2_vsim,
-
-};
-
-#endif
-
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
        /* WLAN IRQ - GPIO 162 */
index b27e7cbb3f2936187692b0dcc8066477afd68ba5..c5cf1ba08a6f525732c9e76b4e5b109a1b495aca 100644 (file)
@@ -25,6 +25,7 @@
 #include <plat/control.h>
 #include <plat/tc.h>
 #include <plat/board.h>
+#include <plat/mcbsp.h>
 #include <mach/gpio.h>
 #include <plat/mmc.h>
 #include <plat/dma.h>
@@ -235,6 +236,43 @@ static inline void omap_init_mbox(void) { }
 
 static inline void omap_init_sti(void) {}
 
+#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE)
+
+static struct platform_device omap_pcm = {
+       .name   = "omap-pcm-audio",
+       .id     = -1,
+};
+
+/*
+ * OMAP2420 has 2 McBSP ports
+ * OMAP2430 has 5 McBSP ports
+ * OMAP3 has 5 McBSP ports
+ * OMAP4 has 4 McBSP ports
+ */
+OMAP_MCBSP_PLATFORM_DEVICE(1);
+OMAP_MCBSP_PLATFORM_DEVICE(2);
+OMAP_MCBSP_PLATFORM_DEVICE(3);
+OMAP_MCBSP_PLATFORM_DEVICE(4);
+OMAP_MCBSP_PLATFORM_DEVICE(5);
+
+static void omap_init_audio(void)
+{
+       platform_device_register(&omap_mcbsp1);
+       platform_device_register(&omap_mcbsp2);
+       if (cpu_is_omap243x() || cpu_is_omap34xx() || cpu_is_omap44xx()) {
+               platform_device_register(&omap_mcbsp3);
+               platform_device_register(&omap_mcbsp4);
+       }
+       if (cpu_is_omap243x() || cpu_is_omap34xx())
+               platform_device_register(&omap_mcbsp5);
+
+       platform_device_register(&omap_pcm);
+}
+
+#else
+static inline void omap_init_audio(void) {}
+#endif
+
 #if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
 
 #include <plat/mcspi.h>
@@ -917,6 +955,7 @@ static int __init omap2_init_devices(void)
         * in alphabetical order so they're easier to sort through.
         */
        omap_hsmmc_reset();
+       omap_init_audio();
        omap_init_camera();
        omap_init_mbox();
        omap_init_mcspi();
index 3af69d2c3dcde626a6f74cdff393cc3be7926201..80591fda8f8f7732a992d991280a744614445ce3 100644 (file)
@@ -9,3 +9,5 @@
 extern void __init board_nand_init(struct mtd_partition *, u8 nr_parts, u8 cs);
 extern int __init zoom_debugboard_init(void);
 extern void __init zoom_peripherals_init(void);
+
+#define ZOOM2_HEADSET_EXTMUTE_GPIO     153
index 08b410343870ae2518afb4303110d5807dfc12d1..aaa1166df9640a925e50c822cd3ddd777080b4d6 100644 (file)
@@ -382,6 +382,31 @@ struct platform_device pxa_device_i2s = {
        .num_resources  = ARRAY_SIZE(pxai2s_resources),
 };
 
+struct platform_device pxa_device_asoc_ssp1 = {
+       .name           = "pxa-ssp-dai",
+       .id             = 0,
+};
+
+struct platform_device pxa_device_asoc_ssp2= {
+       .name           = "pxa-ssp-dai",
+       .id             = 1,
+};
+
+struct platform_device pxa_device_asoc_ssp3 = {
+       .name           = "pxa-ssp-dai",
+       .id             = 2,
+};
+
+struct platform_device pxa_device_asoc_ssp4 = {
+       .name           = "pxa-ssp-dai",
+       .id             = 3,
+};
+
+struct platform_device pxa_device_asoc_platform = {
+       .name           = "pxa-pcm-audio",
+       .id             = -1,
+};
+
 static u64 pxaficp_dmamask = ~(u32)0;
 
 struct platform_device pxa_device_ficp = {
index 715e8bd02e248930e449c4e6c2c169054c837c6e..2fd5a8b35757ac5463303b278d3970d7d4df9d02 100644 (file)
@@ -39,4 +39,10 @@ extern struct platform_device pxa3xx_device_i2c_power;
 
 extern struct platform_device pxa3xx_device_gcu;
 
+extern struct platform_device pxa_device_asoc_platform;
+extern struct platform_device pxa_device_asoc_ssp1;
+extern struct platform_device pxa_device_asoc_ssp2;
+extern struct platform_device pxa_device_asoc_ssp3;
+extern struct platform_device pxa_device_asoc_ssp4;
+
 void __init pxa_register_device(struct platform_device *dev, void *data);
index 12e5b9f01e6f6271f73623aa47f5be826b86bd2a..d1fbf29d561c5cbe4b49e634ccb9953f6b1a4f27 100644 (file)
@@ -385,6 +385,10 @@ static struct platform_device *devices[] __initdata = {
        &pxa27x_device_udc,
        &pxa_device_pmu,
        &pxa_device_i2s,
+       &pxa_device_asoc_ssp1,
+       &pxa_device_asoc_ssp2,
+       &pxa_device_asoc_ssp3,
+       &pxa_device_asoc_platform,
        &sa1100_device_rtc,
        &pxa_device_rtc,
        &pxa27x_device_ssp1,
index c85c3a7abd314f84cce570a79d4f38ecce21ecce..d1c747cdacf879f32f947c54795e86ba06435efc 100644 (file)
@@ -593,6 +593,11 @@ static struct platform_device *devices[] __initdata = {
        &pxa27x_device_udc,
        &pxa_device_pmu,
        &pxa_device_i2s,
+       &pxa_device_asoc_ssp1,
+       &pxa_device_asoc_ssp2,
+       &pxa_device_asoc_ssp3,
+       &pxa_device_asoc_ssp4,
+       &pxa_device_asoc_platform,
        &sa1100_device_rtc,
        &pxa_device_rtc,
        &pxa27x_device_ssp1,
index f25fb6245bd787bc93636163b241f8fefe9f0210..702f7a68e87d593f18bb60ef54091cec561726c1 100644 (file)
@@ -45,6 +45,16 @@ int wm9713_irq;
 int lcd_id;
 int lcd_orientation;
 
+struct platform_device pxa_device_wm9713_audio = {
+       .name           = "wm9713-codec",
+       .id             = -1,
+};
+
+static void __init zylonite_init_wm9713_audio(void)
+{
+       platform_device_register(&pxa_device_wm9713_audio);
+}
+
 static struct resource smc91x_resources[] = {
        [0] = {
                .start  = ZYLONITE_ETH_PHYS + 0x300,
@@ -408,6 +418,7 @@ static void __init zylonite_init(void)
        zylonite_init_nand();
        zylonite_init_leds();
        zylonite_init_ohci();
+       zylonite_init_wm9713_audio();
 }
 
 MACHINE_START(ZYLONITE, "PXA3xx Platform Development Kit (aka Zylonite)")
index 9648fbc36eecd391f6e7a14f005e0645fa824af5..3838335f125b65067d9e771b7e48af8ca1b07218 100644 (file)
@@ -43,8 +43,10 @@ static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev)
                s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_I2S1_LRCLK);
                s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI);
                s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0);
+               break;
        default:
-               printk(KERN_DEBUG "Invalid I2S Controller number!");
+               printk(KERN_DEBUG "Invalid I2S Controller number: %d\n",
+                       pdev->id);
                return -EINVAL;
        }
 
@@ -184,7 +186,8 @@ static int s3c64xx_pcm_cfg_gpio(struct platform_device *pdev)
                s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_PCM1_SOUT);
                break;
        default:
-               printk(KERN_DEBUG "Invalid PCM Controller number!");
+               printk(KERN_DEBUG "Invalid PCM Controller number: %d\n",
+                       pdev->id);
                return -EINVAL;
        }
 
@@ -333,3 +336,16 @@ 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 ec8865c03a1965d0ae51c7f64251fd8e0a08beae..77488facfe4cab45ad9c8c9ea996e06138ec0074 100644 (file)
@@ -283,6 +283,7 @@ static struct platform_device *smdk6410_devices[] __initdata = {
        &s3c_device_fb,
        &s3c_device_ohci,
        &s3c_device_usb_hsotg,
+       &s3c_device_pcm,
        &s3c64xx_device_iisv4,
        &samsung_device_keypad,
 
index b4ff6a11a8f2862dbc2f0daf1c70167b50284145..5b20103e68eb176672e09743545bae1a9b346ddf 100644 (file)
 #include <mach/hardware.h>
 #include <plat/clock.h>
 
+/* macro for building platform_device for McBSP ports */
+#define OMAP_MCBSP_PLATFORM_DEVICE(port_nr)            \
+static struct platform_device omap_mcbsp##port_nr = {  \
+       .name   = "omap-mcbsp-dai",                     \
+       .id     = OMAP_MCBSP##port_nr,                  \
+}
+
 #define OMAP7XX_MCBSP1_BASE    0xfffb1000
 #define OMAP7XX_MCBSP2_BASE    0xfffb1800
 
index 452e18438b41b21546e5ae52c7b0b25e74078032..2f91057a0c02380841db092f087ea9f6731efca6 100644 (file)
@@ -247,7 +247,7 @@ static struct resource s3c_iis_resource[] = {
 static u64 s3c_device_iis_dmamask = 0xffffffffUL;
 
 struct platform_device s3c_device_iis = {
-       .name             = "s3c2410-iis",
+       .name             = "s3c24xx-iis",
        .id               = -1,
        .num_resources    = ARRAY_SIZE(s3c_iis_resource),
        .resource         = s3c_iis_resource,
@@ -259,6 +259,21 @@ 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[] = {
@@ -481,19 +496,30 @@ static struct resource s3c_ac97_resource[] = {
        },
 };
 
-static u64 s3c_device_ac97_dmamask = 0xffffffffUL;
-
 struct platform_device s3c_device_ac97 = {
        .name             = "s3c-ac97",
        .id               = -1,
        .num_resources    = ARRAY_SIZE(s3c_ac97_resource),
        .resource         = s3c_ac97_resource,
        .dev              = {
-               .dma_mask = &s3c_device_ac97_dmamask,
+               .dma_mask = &s3c_device_audio_dmamask,
                .coherent_dma_mask = 0xffffffffUL
        }
 };
 
 EXPORT_SYMBOL(s3c_device_ac97);
 
+/* ASoC I2S */
+
+struct platform_device s3c2412_device_iis = {
+       .name             = "s3c2412-iis",
+       .id               = -1,
+       .dev              = {
+               .dma_mask = &s3c_device_audio_dmamask,
+               .coherent_dma_mask = 0xffffffffUL
+       }
+};
+
+EXPORT_SYMBOL(s3c2412_device_iis);
+
 #endif // CONFIG_CPU_S32440
index 7d448e13879241c8a62da6f26604ea00ecc1a3d1..c8b94279bad101037553659e73a4886aa44148bb 100644 (file)
@@ -32,6 +32,8 @@ 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 s3c64xx_device_pcm0;
 extern struct platform_device s3c64xx_device_pcm1;
 
index 3fa34c3abc0408a04d668c262e03360506b4d861..fbb55935b99e71ee3be1475657ca8fdfdf981ee5 100644 (file)
@@ -429,6 +429,11 @@ static struct platform_device db1200_audio_dev = {
        .resource       = au1200_psc1_res,
 };
 
+static struct platform_device db1200_stac_dev = {
+       .name           = "ac97-codec",
+       .id             = 1,    /* on PSC1 */
+};
+
 static struct platform_device *db1200_devs[] __initdata = {
        NULL,           /* PSC0, selected by S6.8 */
        &db1200_ide_dev,
@@ -436,6 +441,7 @@ static struct platform_device *db1200_devs[] __initdata = {
        &db1200_rtc_dev,
        &db1200_nand_dev,
        &db1200_audio_dev,
+       &db1200_stac_dev,
 };
 
 static int __init db1200_dev_init(void)
index 9535ce68caaee41331554d2a330a783b503e6eb1..83c3218cb4da2717b9a375ab904ddc8879e9b038 100644 (file)
 
                ssi@16100 {
                        compatible = "fsl,mpc8610-ssi";
+                       status = "disabled";
                        cell-index = <1>;
                        reg = <0x16100 0x100>;
                        interrupt-parent = <&mpic>;
index c3b113b2ca318ce8c25badd717d9f122b6157398..3aeb5949cfef6da423f675b4a2bb9249fd0e6bb4 100644 (file)
@@ -124,6 +124,9 @@ CONFIG_I2C_CPM=m
 CONFIG_I2C_MPC=y
 # CONFIG_HWMON is not set
 CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FB_FSL_DIU=y
+# CONFIG_VGA_CONSOLE is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
 # CONFIG_SND_SUPPORT_OLD_API is not set
index a075da2ea3fbdbffb06623234a92493269dbe901..d62c8016f4bcaf7cd603856a917dac4382a64901 100644 (file)
@@ -126,6 +126,9 @@ CONFIG_I2C_CPM=m
 CONFIG_I2C_MPC=y
 # CONFIG_HWMON is not set
 CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FB_FSL_DIU=y
+# CONFIG_VGA_CONSOLE is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
 # CONFIG_SND_SUPPORT_OLD_API is not set
similarity index 66%
rename from arch/powerpc/include/asm/immap_86xx.h
rename to arch/powerpc/include/asm/fsl_guts.h
index 0f165e59c32689e90e78239f5e4da9515197f9f0..bebd12463ec9e1375548aca2fd96e01eb7fc3334 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * MPC86xx Internal Memory Map
+ * Freecale 85xx and 86xx Global Utilties register set
  *
  * Authors: Jeff Brown
  *          Timur Tabi <timur@freescale.com>
  * 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 header file defines structures for various 86xx SOC devices that are
- * used by multiple source files.
  */
 
-#ifndef __ASM_POWERPC_IMMAP_86XX_H__
-#define __ASM_POWERPC_IMMAP_86XX_H__
+#ifndef __ASM_POWERPC_FSL_GUTS_H__
+#define __ASM_POWERPC_FSL_GUTS_H__
 #ifdef __KERNEL__
 
-/* Global Utility Registers */
-struct ccsr_guts {
+/*
+ * These #ifdefs are safe because it's not possible to build a kernel that
+ * runs on e500 and e600 cores.
+ */
+
+#if !defined(CONFIG_PPC_85xx) && !defined(CONFIG_PPC_86xx)
+#error Only 85xx and 86xx SOCs are supported
+#endif
+
+/**
+ * Global Utility Registers.
+ *
+ * Not all registers defined in this structure are available on all chips, so
+ * you are expected to know whether a given register actually exists on your
+ * chip before you access it.
+ *
+ * Also, some registers are similar on different chips but have slightly
+ * different names.  In these cases, one name is chosen to avoid extraneous
+ * #ifdefs.
+ */
+#ifdef CONFIG_PPC_85xx
+struct ccsr_guts_85xx {
+#else
+struct ccsr_guts_86xx {
+#endif
        __be32  porpllsr;       /* 0x.0000 - POR PLL Ratio Status Register */
        __be32  porbmsr;        /* 0x.0004 - POR Boot Mode Status Register */
        __be32  porimpscr;      /* 0x.0008 - POR I/O Impedance Status and Control Register */
        __be32  pordevsr;       /* 0x.000c - POR I/O Device Status Register */
        __be32  pordbgmsr;      /* 0x.0010 - POR Debug Mode Status Register */
-       u8      res1[0x20 - 0x14];
+       __be32  pordevsr2;      /* 0x.0014 - POR device status register 2 */
+       u8      res018[0x20 - 0x18];
        __be32  porcir;         /* 0x.0020 - POR Configuration Information Register */
-       u8      res2[0x30 - 0x24];
+       u8      res024[0x30 - 0x24];
        __be32  gpiocr;         /* 0x.0030 - GPIO Control Register */
-       u8      res3[0x40 - 0x34];
+       u8      res034[0x40 - 0x34];
        __be32  gpoutdr;        /* 0x.0040 - General-Purpose Output Data Register */
-       u8      res4[0x50 - 0x44];
+       u8      res044[0x50 - 0x44];
        __be32  gpindr;         /* 0x.0050 - General-Purpose Input Data Register */
-       u8      res5[0x60 - 0x54];
+       u8      res054[0x60 - 0x54];
        __be32  pmuxcr;         /* 0x.0060 - Alternate Function Signal Multiplex Control */
-       u8      res6[0x70 - 0x64];
+        __be32  pmuxcr2;       /* 0x.0064 - Alternate function signal multiplex control 2 */
+        __be32  dmuxcr;                /* 0x.0068 - DMA Mux Control Register */
+        u8     res06c[0x70 - 0x6c];
        __be32  devdisr;        /* 0x.0070 - Device Disable Control */
        __be32  devdisr2;       /* 0x.0074 - Device Disable Control 2 */
-       u8      res7[0x80 - 0x78];
+       u8      res078[0x7c - 0x78];
+       __be32  pmjcr;          /* 0x.007c - 4 Power Management Jog Control Register */
        __be32  powmgtcsr;      /* 0x.0080 - Power Management Status and Control Register */
-       u8      res8[0x90 - 0x84];
+       __be32  pmrccr;         /* 0x.0084 - Power Management Reset Counter Configuration Register */
+       __be32  pmpdccr;        /* 0x.0088 - Power Management Power Down Counter Configuration Register */
+       __be32  pmcdr;          /* 0x.008c - 4Power management clock disable register */
        __be32  mcpsumr;        /* 0x.0090 - Machine Check Summary Register */
        __be32  rstrscr;        /* 0x.0094 - Reset Request Status and Control Register */
-       u8      res9[0xA0 - 0x98];
+       __be32  ectrstcr;       /* 0x.0098 - Exception reset control register */
+       __be32  autorstsr;      /* 0x.009c - Automatic reset status register */
        __be32  pvr;            /* 0x.00a0 - Processor Version Register */
        __be32  svr;            /* 0x.00a4 - System Version Register */
-       u8      res10[0xB0 - 0xA8];
+       u8      res0a8[0xb0 - 0xa8];
        __be32  rstcr;          /* 0x.00b0 - Reset Control Register */
-       u8      res11[0xC0 - 0xB4];
+       u8      res0b4[0xc0 - 0xb4];
+#ifdef CONFIG_PPC_85xx
+       __be32  iovselsr;       /* 0x.00c0 - I/O voltage select status register */
+#else
        __be32  elbcvselcr;     /* 0x.00c0 - eLBC Voltage Select Ctrl Reg */
-       u8      res12[0x800 - 0xC4];
+#endif
+       u8      res0c4[0x224 - 0xc4];
+       __be32  iodelay1;       /* 0x.0224 - IO delay control register 1 */
+       __be32  iodelay2;       /* 0x.0228 - IO delay control register 2 */
+       u8      res22c[0x800 - 0x22c];
        __be32  clkdvdr;        /* 0x.0800 - Clock Divide Register */
-       u8      res13[0x900 - 0x804];
+       u8      res804[0x900 - 0x804];
        __be32  ircr;           /* 0x.0900 - Infrared Control Register */
-       u8      res14[0x908 - 0x904];
+       u8      res904[0x908 - 0x904];
        __be32  dmacr;          /* 0x.0908 - DMA Control Register */
-       u8      res15[0x914 - 0x90C];
+       u8      res90c[0x914 - 0x90c];
        __be32  elbccr;         /* 0x.0914 - eLBC Control Register */
-       u8      res16[0xB20 - 0x918];
+       u8      res918[0xb20 - 0x918];
        __be32  ddr1clkdr;      /* 0x.0b20 - DDR1 Clock Disable Register */
        __be32  ddr2clkdr;      /* 0x.0b24 - DDR2 Clock Disable Register */
        __be32  ddrclkdr;       /* 0x.0b28 - DDR Clock Disable Register */
-       u8      res17[0xE00 - 0xB2C];
+       u8      resb2c[0xe00 - 0xb2c];
        __be32  clkocr;         /* 0x.0e00 - Clock Out Select Register */
-       u8      res18[0xE10 - 0xE04];
+       u8      rese04[0xe10 - 0xe04];
        __be32  ddrdllcr;       /* 0x.0e10 - DDR DLL Control Register */
-       u8      res19[0xE20 - 0xE14];
+       u8      rese14[0xe20 - 0xe14];
        __be32  lbcdllcr;       /* 0x.0e20 - LBC DLL Control Register */
-       u8      res20[0xF04 - 0xE24];
+       __be32  cpfor;          /* 0x.0e24 - L2 charge pump fuse override register */
+       u8      rese28[0xf04 - 0xe28];
        __be32  srds1cr0;       /* 0x.0f04 - SerDes1 Control Register 0 */
        __be32  srds1cr1;       /* 0x.0f08 - SerDes1 Control Register 0 */
-       u8      res21[0xF40 - 0xF0C];
-       __be32  srds2cr0;       /* 0x.0f40 - SerDes1 Control Register 0 */
-       __be32  srds2cr1;       /* 0x.0f44 - SerDes1 Control Register 0 */
+       u8      resf0c[0xf2c - 0xf0c];
+       __be32  itcr;           /* 0x.0f2c - Internal transaction control register */
+       u8      resf30[0xf40 - 0xf30];
+       __be32  srds2cr0;       /* 0x.0f40 - SerDes2 Control Register 0 */
+       __be32  srds2cr1;       /* 0x.0f44 - SerDes2 Control Register 0 */
 } __attribute__ ((packed));
 
+#ifdef CONFIG_PPC_86xx
+
 #define CCSR_GUTS_DMACR_DEV_SSI        0       /* DMA controller/channel set to SSI */
 #define CCSR_GUTS_DMACR_DEV_IR 1       /* DMA controller/channel set to IR */
 
@@ -93,7 +132,7 @@ struct ccsr_guts {
  * ch: The channel on the DMA controller (0, 1, 2, or 3)
  * device: The device to set as the source (CCSR_GUTS_DMACR_DEV_xx)
  */
-static inline void guts_set_dmacr(struct ccsr_guts __iomem *guts,
+static inline void guts_set_dmacr(struct ccsr_guts_86xx __iomem *guts,
        unsigned int co, unsigned int ch, unsigned int device)
 {
        unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch));
@@ -129,7 +168,7 @@ static inline void guts_set_dmacr(struct ccsr_guts __iomem *guts,
  * ch: The channel on the DMA controller (0, 1, 2, or 3)
  * value: the new value for the bit (0 or 1)
  */
-static inline void guts_set_pmuxcr_dma(struct ccsr_guts __iomem *guts,
+static inline void guts_set_pmuxcr_dma(struct ccsr_guts_86xx __iomem *guts,
        unsigned int co, unsigned int ch, unsigned int value)
 {
        if ((ch == 0) || (ch == 3)) {
@@ -152,5 +191,7 @@ static inline void guts_set_pmuxcr_dma(struct ccsr_guts __iomem *guts,
 #define CCSR_GUTS_CLKDVDR_SSICLK_MASK  0x000000FF
 #define CCSR_GUTS_CLKDVDR_SSICLK(x) ((x) & CCSR_GUTS_CLKDVDR_SSICLK_MASK)
 
-#endif /* __ASM_POWERPC_IMMAP_86XX_H__ */
-#endif /* __KERNEL__ */
+#endif
+
+#endif
+#endif
index 2b390d19a1d179bfd1d1c0d58498f693ed1f4c27..7eb5c40c069fafb296b436c99241b721be33895f 100644 (file)
@@ -8,7 +8,6 @@
  * Copyright 2010 Freescale Semiconductor, Inc.
  *
  * This file is taken from the Freescale P1022DS BSP, with modifications:
- * 1) No DIU support (pending rewrite of DIU code)
  * 2) No AMP support
  * 3) No PCI endpoint support
  *
 #include <linux/pci.h>
 #include <linux/of_platform.h>
 #include <linux/memblock.h>
-
+#include <asm/div64.h>
 #include <asm/mpic.h>
 #include <asm/swiotlb.h>
 
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
+#include <asm/fsl_guts.h>
+
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+
+/*
+ * Board-specific initialization of the DIU.  This code should probably be
+ * executed when the DIU is opened, rather than in arch code, but the DIU
+ * driver does not have a mechanism for this (yet).
+ *
+ * This is especially problematic on the P1022DS because the local bus (eLBC)
+ * and the DIU video signals share the same pins, which means that enabling the
+ * DIU will disable access to NOR flash.
+ */
+
+/* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */
+#define CLKDVDR_PXCKEN         0x80000000
+#define CLKDVDR_PXCKINV                0x10000000
+#define CLKDVDR_PXCKDLY                0x06000000
+#define CLKDVDR_PXCLK_MASK     0x00FF0000
+
+/* Some ngPIXIS register definitions */
+#define PX_BRDCFG1_DVIEN       0x80
+#define PX_BRDCFG1_DFPEN       0x40
+#define PX_BRDCFG1_BACKLIGHT   0x20
+#define PX_BRDCFG1_DDCEN       0x10
+
+/*
+ * DIU Area Descriptor
+ *
+ * Note that we need to byte-swap the value before it's written to the AD
+ * register.  So even though the registers don't look like they're in the same
+ * bit positions as they are on the MPC8610, the same value is written to the
+ * AD register on the MPC8610 and on the P1022.
+ */
+#define AD_BYTE_F              0x10000000
+#define AD_ALPHA_C_MASK                0x0E000000
+#define AD_ALPHA_C_SHIFT       25
+#define AD_BLUE_C_MASK         0x01800000
+#define AD_BLUE_C_SHIFT                23
+#define AD_GREEN_C_MASK                0x00600000
+#define AD_GREEN_C_SHIFT       21
+#define AD_RED_C_MASK          0x00180000
+#define AD_RED_C_SHIFT         19
+#define AD_PALETTE             0x00040000
+#define AD_PIXEL_S_MASK                0x00030000
+#define AD_PIXEL_S_SHIFT       16
+#define AD_COMP_3_MASK         0x0000F000
+#define AD_COMP_3_SHIFT                12
+#define AD_COMP_2_MASK         0x00000F00
+#define AD_COMP_2_SHIFT                8
+#define AD_COMP_1_MASK         0x000000F0
+#define AD_COMP_1_SHIFT                4
+#define AD_COMP_0_MASK         0x0000000F
+#define AD_COMP_0_SHIFT                0
+
+#define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \
+       cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \
+       (blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \
+       (red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \
+       (c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \
+       (c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT))
+
+/**
+ * p1022ds_get_pixel_format: return the Area Descriptor for a given pixel depth
+ *
+ * The Area Descriptor is a 32-bit value that determine which bits in each
+ * pixel are to be used for each color.
+ */
+static unsigned int p1022ds_get_pixel_format(unsigned int bits_per_pixel,
+       int monitor_port)
+{
+       switch (bits_per_pixel) {
+       case 32:
+               /* 0x88883316 */
+               return MAKE_AD(3, 2, 0, 1, 3, 8, 8, 8, 8);
+       case 24:
+               /* 0x88082219 */
+               return MAKE_AD(4, 0, 1, 2, 2, 0, 8, 8, 8);
+       case 16:
+               /* 0x65053118 */
+               return MAKE_AD(4, 2, 1, 0, 1, 5, 6, 5, 0);
+       default:
+               pr_err("fsl-diu: unsupported pixel depth %u\n", bits_per_pixel);
+               return 0;
+       }
+}
+
+/**
+ * p1022ds_set_gamma_table: update the gamma table, if necessary
+ *
+ * On some boards, the gamma table for some ports may need to be modified.
+ * This is not the case on the P1022DS, so we do nothing.
+*/
+static void p1022ds_set_gamma_table(int monitor_port, char *gamma_table_base)
+{
+}
+
+/**
+ * p1022ds_set_monitor_port: switch the output to a different monitor port
+ *
+ */
+static void p1022ds_set_monitor_port(int monitor_port)
+{
+       struct device_node *pixis_node;
+       u8 __iomem *brdcfg1;
+
+       pixis_node = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-pixis");
+       if (!pixis_node) {
+               pr_err("p1022ds: missing ngPIXIS node\n");
+               return;
+       }
+
+       brdcfg1 = of_iomap(pixis_node, 0);
+       if (!brdcfg1) {
+               pr_err("p1022ds: could not map ngPIXIS registers\n");
+               return;
+       }
+       brdcfg1 += 9;   /* BRDCFG1 is at offset 9 in the ngPIXIS */
+
+       switch (monitor_port) {
+       case 0: /* DVI */
+               /* Enable the DVI port, disable the DFP and the backlight */
+               clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT,
+                            PX_BRDCFG1_DVIEN);
+               break;
+       case 1: /* Single link LVDS */
+               /* Enable the DFP port, disable the DVI and the backlight */
+               clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT,
+                            PX_BRDCFG1_DFPEN);
+               break;
+       default:
+               pr_err("p1022ds: unsupported monitor port %i\n", monitor_port);
+       }
+}
+
+/**
+ * p1022ds_set_pixel_clock: program the DIU's clock
+ *
+ * @pixclock: the wavelength, in picoseconds, of the clock
+ */
+void p1022ds_set_pixel_clock(unsigned int pixclock)
+{
+       struct device_node *guts_np = NULL;
+       struct ccsr_guts_85xx __iomem *guts;
+       unsigned long freq;
+       u64 temp;
+       u32 pxclk;
+
+       /* Map the global utilities registers. */
+       guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
+       if (!guts_np) {
+               pr_err("p1022ds: missing global utilties device node\n");
+               return;
+       }
+
+       guts = of_iomap(guts_np, 0);
+       of_node_put(guts_np);
+       if (!guts) {
+               pr_err("p1022ds: could not map global utilties device\n");
+               return;
+       }
+
+       /* Convert pixclock from a wavelength to a frequency */
+       temp = 1000000000000ULL;
+       do_div(temp, pixclock);
+       freq = temp;
+
+       /* pixclk is the ratio of the platform clock to the pixel clock */
+       pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq);
+
+       /* Disable the pixel clock, and set it to non-inverted and no delay */
+       clrbits32(&guts->clkdvdr,
+                 CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK);
+
+       /* Enable the clock and set the pxclk */
+       setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16));
+}
+
+/**
+ * p1022ds_show_monitor_port: show the current monitor
+ *
+ * This function returns a string indicating whether the current monitor is
+ * set to DVI or LVDS.
+ */
+ssize_t p1022ds_show_monitor_port(int monitor_port, char *buf)
+{
+       return sprintf(buf, "%c0 - DVI\n%c1 - Single link LVDS\n",
+               monitor_port == 0 ? '*' : ' ', monitor_port == 1 ? '*' : ' ');
+}
+
+/**
+ * p1022ds_set_sysfs_monitor_port: set the monitor port for sysfs
+ */
+int p1022ds_set_sysfs_monitor_port(int val)
+{
+       return val < 2 ? val : 0;
+}
+
+#endif
 
 void __init p1022_ds_pic_init(void)
 {
@@ -92,6 +290,15 @@ static void __init p1022_ds_setup_arch(void)
        }
 #endif
 
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+       diu_ops.get_pixel_format        = p1022ds_get_pixel_format;
+       diu_ops.set_gamma_table         = p1022ds_set_gamma_table;
+       diu_ops.set_monitor_port        = p1022ds_set_monitor_port;
+       diu_ops.set_pixel_clock         = p1022ds_set_pixel_clock;
+       diu_ops.show_monitor_port       = p1022ds_show_monitor_port;
+       diu_ops.set_sysfs_monitor_port  = p1022ds_set_sysfs_monitor_port;
+#endif
+
 #ifdef CONFIG_SMP
        mpc85xx_smp_init();
 #endif
index 156ccc9600155f159c7f84baed82990e16ed6292..d551ed8dea954600216cc1d5ec418d389fd45a70 100644 (file)
@@ -551,7 +551,7 @@ static struct resource siu_resources[] = {
 };
 
 static struct platform_device siu_device = {
-       .name           = "sh_siu",
+       .name           = "siu-pcm-audio",
        .id             = -1,
        .dev = {
                .platform_data  = &siu_platform_data,
index 4f9b2afc24e820d75b819555f7f667f94bd73f69..014dd4ad0d4fecede04221e5348fc78e023d76e2 100644 (file)
@@ -271,7 +271,7 @@ static struct platform_driver twl4030_vibra_driver = {
        .probe          = twl4030_vibra_probe,
        .remove         = __devexit_p(twl4030_vibra_remove),
        .driver         = {
-               .name   = "twl4030_codec_vibra",
+               .name   = "twl4030-vibra",
                .owner  = THIS_MODULE,
 #ifdef CONFIG_PM
                .pm     = &twl4030_vibra_pm_ops,
@@ -291,7 +291,7 @@ static void __exit twl4030_vibra_exit(void)
 }
 module_exit(twl4030_vibra_exit);
 
-MODULE_ALIAS("platform:twl4030_codec_vibra");
+MODULE_ALIAS("platform:twl4030-vibra");
 
 MODULE_DESCRIPTION("TWL4030 Vibra driver");
 MODULE_LICENSE("GPL");
index 720e099e506df1297a5e71a2047fe9fae52fe98a..5d0fb60a4c147138833506588d6329b1e716e1ae 100644 (file)
@@ -698,17 +698,17 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 
        if (twl_has_codec() && pdata->codec && twl_class_is_4030()) {
                sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
-               child = add_child(sub_chip_id, "twl4030_codec",
+               child = add_child(sub_chip_id, "twl4030-audio",
                                pdata->codec, sizeof(*pdata->codec),
                                false, 0, 0);
                if (IS_ERR(child))
                        return PTR_ERR(child);
        }
 
-       /* Phoenix*/
+       /* Phoenix codec driver is probed directly atm */
        if (twl_has_codec() && pdata->codec && twl_class_is_6030()) {
                sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
-               child = add_child(sub_chip_id, "twl6040_codec",
+               child = add_child(sub_chip_id, "twl6040-codec",
                                pdata->codec, sizeof(*pdata->codec),
                                false, 0, 0);
                if (IS_ERR(child))
index add6f67d80323a42824709337958fe90df55e443..9a4b196d6deb64751d8e4981bb81de8074f5e231 100644 (file)
@@ -207,14 +207,14 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
 
        if (pdata->audio) {
                cell = &codec->cells[childs];
-               cell->name = "twl4030_codec_audio";
+               cell->name = "twl4030-codec";
                cell->platform_data = pdata->audio;
                cell->data_size = sizeof(*pdata->audio);
                childs++;
        }
        if (pdata->vibra) {
                cell = &codec->cells[childs];
-               cell->name = "twl4030_codec_vibra";
+               cell->name = "twl4030-vibra";
                cell->platform_data = pdata->vibra;
                cell->data_size = sizeof(*pdata->vibra);
                childs++;
@@ -249,14 +249,14 @@ static int __devexit twl4030_codec_remove(struct platform_device *pdev)
        return 0;
 }
 
-MODULE_ALIAS("platform:twl4030_codec");
+MODULE_ALIAS("platform:twl4030-audio");
 
 static struct platform_driver twl4030_codec_driver = {
        .probe          = twl4030_codec_probe,
        .remove         = __devexit_p(twl4030_codec_remove),
        .driver         = {
                .owner  = THIS_MODULE,
-               .name   = "twl4030_codec",
+               .name   = "twl4030-audio",
        },
 };
 
index 7d71019b84c20685d3ddac4763dc245f15d7cefe..c85ff5e9e70013e53445279a92c831cd1e44957f 100644 (file)
@@ -12,4 +12,4 @@ TODO:
 - get rid of non-linux related stuff
 
 Please send patches to:
-Arnaud Patard <apatard@mandriva.com>
+Arnaud Patard <arnaud.patard@rtp-net.org>
index dc06ff13455921f2d23748be845d6b51e3a92309..596ef6b922bfa4965682179b29fce8c0cd3bfca1 100644 (file)
@@ -1919,6 +1919,9 @@ config FB_SH_MOBILE_HDMI
        tristate "SuperH Mobile HDMI controller support"
        depends on FB_SH_MOBILE_LCDC
        select FB_MODE_HELPERS
+       select SOUND
+       select SND
+       select SND_SOC
        ---help---
          Driver for the on-chip SH-Mobile HDMI controller.
 
index 2fde08cc66bf524f4f72594ee64cf72192f10800..ef989d94511c1fccdae24fbb1482ab986340f7f1 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
 
 #include <video/sh_mobile_hdmi.h>
 #include <video/sh_mobile_lcdc.h>
@@ -222,6 +224,58 @@ static u8 hdmi_read(struct sh_hdmi *hdmi, u8 reg)
        return ioread8(hdmi->base + reg);
 }
 
+/*
+ *     HDMI sound
+ */
+static unsigned int sh_hdmi_snd_read(struct snd_soc_codec *codec,
+                                    unsigned int reg)
+{
+       struct sh_hdmi *hdmi = snd_soc_codec_get_drvdata(codec);
+
+       return hdmi_read(hdmi, reg);
+}
+
+static int sh_hdmi_snd_write(struct snd_soc_codec *codec,
+                            unsigned int reg,
+                            unsigned int value)
+{
+       struct sh_hdmi *hdmi = snd_soc_codec_get_drvdata(codec);
+
+       hdmi_write(hdmi, value, reg);
+       return 0;
+}
+
+static struct snd_soc_dai_driver sh_hdmi_dai = {
+       .name = "sh_mobile_hdmi-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 8,
+               .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100  |
+                        SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200  |
+                        SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+                        SNDRV_PCM_RATE_192000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+       },
+};
+
+static int sh_hdmi_snd_probe(struct snd_soc_codec *codec)
+{
+       dev_info(codec->dev, "SH Mobile HDMI Audio Codec");
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_sh_hdmi = {
+       .probe          = sh_hdmi_snd_probe,
+       .read           = sh_hdmi_snd_read,
+       .write          = sh_hdmi_snd_write,
+};
+
+/*
+ *     HDMI video
+ */
+
 /* External video parameter settings */
 static void hdmi_external_video_param(struct sh_hdmi *hdmi)
 {
@@ -318,6 +372,9 @@ static void sh_hdmi_video_config(struct sh_hdmi *hdmi)
  */
 static void sh_hdmi_audio_config(struct sh_hdmi *hdmi)
 {
+       u8 data;
+       struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
+
        /*
         * [7:4] L/R data swap control
         * [3:0] appropriate N[19:16]
@@ -335,7 +392,23 @@ static void sh_hdmi_audio_config(struct sh_hdmi *hdmi)
         * [6:5] set required down sampling rate if required
         * [4:3] set required audio source
         */
-       hdmi_write(hdmi, 0x00, HDMI_AUDIO_SETTING_1);
+       switch (pdata->flags & HDMI_SND_SRC_MASK) {
+       default:
+               /* fall through */
+       case HDMI_SND_SRC_I2S:
+               data = 0x0 << 3;
+               break;
+       case HDMI_SND_SRC_SPDIF:
+               data = 0x1 << 3;
+               break;
+       case HDMI_SND_SRC_DSD:
+               data = 0x2 << 3;
+               break;
+       case HDMI_SND_SRC_HBR:
+               data = 0x3 << 3;
+               break;
+       }
+       hdmi_write(hdmi, data, HDMI_AUDIO_SETTING_1);
 
        /* [3:0] set sending channel number for channel status */
        hdmi_write(hdmi, 0x40, HDMI_AUDIO_SETTING_2);
@@ -891,6 +964,11 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       ret =  snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_sh_hdmi, &sh_hdmi_dai, 1);
+       if (ret < 0)
+               goto esndreg;
+
        hdmi->dev = &pdev->dev;
 
        hdmi->hdmi_clk = clk_get(&pdev->dev, "ick");
@@ -976,6 +1054,8 @@ eclkenable:
 erate:
        clk_put(hdmi->hdmi_clk);
 egetclk:
+       snd_soc_unregister_codec(&pdev->dev);
+esndreg:
        kfree(hdmi);
 
        return ret;
@@ -988,6 +1068,8 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        int irq = platform_get_irq(pdev, 0);
 
+       snd_soc_unregister_codec(&pdev->dev);
+
        pdata->lcd_chan->board_cfg.display_on = NULL;
        pdata->lcd_chan->board_cfg.display_off = NULL;
        pdata->lcd_chan->board_cfg.board_data = NULL;
index 6de90bfc6acde5a2728cb4d95091ab2dd7115822..4793d8a7f48086e58bac27204e8245dcc40c558d 100644 (file)
@@ -553,8 +553,12 @@ extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
 extern int twl4030_remove_script(u8 flags);
 
 struct twl4030_codec_audio_data {
-       unsigned int    audio_mclk;
+       unsigned int audio_mclk; /* not used, will be removed */
+       unsigned int digimic_delay; /* in ms */
        unsigned int ramp_delay_value;
+       unsigned int offset_cncl_path;
+       unsigned int check_defaults:1;
+       unsigned int reset_registers:1;
        unsigned int hs_extmute:1;
        void (*set_hs_extmute)(int mute);
 };
index df26ebbfa9c697584ec95b429300a5b0d407ccb0..1fa2407c966fdc5240d9853395fd22af6f435724 100644 (file)
@@ -177,7 +177,7 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state);
 #define snd_power_lock(card)           do { (void)(card); } while (0)
 #define snd_power_unlock(card)         do { (void)(card); } while (0)
 static inline int snd_power_wait(struct snd_card *card, unsigned int state) { return 0; }
-#define snd_power_get_state(card)      SNDRV_CTL_POWER_D0
+#define snd_power_get_state(card)      ({ (void)(card); SNDRV_CTL_POWER_D0; })
 #define snd_power_change_state(card, state)    do { (void)(card); } while (0)
 
 #endif /* CONFIG_PM */
index 7dc97d12253c1bdc494b939e5e856b1b1fa6fc2c..4f865df42f0f9daf2e078b6a26c1b108638454ba 100644 (file)
 #define CCCA_CURRADDR_MASK     0x00ffffff      /* Current address of the selected channel              */
 #define CCCA_CURRADDR          0x18000008
 
+/* undefine CCR to avoid conflict with the definition for SH */
+#undef CCR
 #define CCR                    0x09            /* Cache control register                               */
 #define CCR_CACHEINVALIDSIZE   0x07190009
 #define CCR_CACHEINVALIDSIZE_MASK      0xfe000000      /* Number of invalid samples cache for this channel     */
index d90b9fa327074b9e38ad2c3b84063a3d24effd2f..c140fc7cbd3f276470a949c2701c9989e4f9a2f8 100644 (file)
@@ -47,6 +47,9 @@ enum snd_jack_types {
        SND_JACK_BTN_0          = 0x4000,
        SND_JACK_BTN_1          = 0x2000,
        SND_JACK_BTN_2          = 0x1000,
+       SND_JACK_BTN_3          = 0x0800,
+       SND_JACK_BTN_4          = 0x0400,
+       SND_JACK_BTN_5          = 0x0200,
 };
 
 struct snd_jack {
@@ -55,7 +58,7 @@ struct snd_jack {
        int type;
        const char *id;
        char name[100];
-       unsigned int key[3];   /* Keep in sync with definitions above */
+       unsigned int key[6];   /* Keep in sync with definitions above */
        void *private_data;
        void (*private_free)(struct snd_jack *);
 };
diff --git a/include/sound/max98088.h b/include/sound/max98088.h
new file mode 100644 (file)
index 0000000..c3ba823
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Platform data for MAX98088
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ *  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 __SOUND_MAX98088_PDATA_H__
+#define __SOUND_MAX98088_PDATA_H__
+
+/* Equalizer filter response configuration */
+struct max98088_eq_cfg {
+       const char *name;
+       unsigned int rate;
+       u16 band1[5];
+       u16 band2[5];
+       u16 band3[5];
+       u16 band4[5];
+       u16 band5[5];
+};
+
+/* codec platform data */
+struct max98088_pdata {
+
+       /* Equalizers for DAI1 and DAI2 */
+       struct max98088_eq_cfg *eq_cfg;
+       unsigned int eq_cfgcnt;
+
+       /* Receiver output can be configured as power amplifier or LINE out */
+       /* Set receiver_mode to:
+        * 0 = amplifier output, or
+        * 1 = LINE level output
+        */
+       unsigned int receiver_mode:1;
+
+       /* Analog/digital microphone configuration:
+        * 0 = analog microphone input (normal setting)
+        * 1 = digital microphone input
+        */
+       unsigned int digmic_left_mode:1;
+       unsigned int digmic_right_mode:1;
+
+};
+
+#endif
index 85f1c6bf8566944eaa85d6b8742ebef2a06e6ce9..dfd9b76b185306a40fff57df94ad53ab83d2f966 100644 (file)
@@ -278,6 +278,7 @@ struct snd_pcm_runtime {
        snd_pcm_uframes_t hw_ptr_base;  /* Position at buffer restart */
        snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */
        unsigned long hw_ptr_jiffies;   /* Time when hw_ptr is updated */
+       unsigned long hw_ptr_buffer_jiffies; /* buffer time in jiffies */
        snd_pcm_sframes_t delay;        /* extra delay; typically FIFO size */
 
        /* -- HW params -- */
index 9d51d6f358930c68d7c8264e4e0e047a1b15343b..fa60cbda90a4553f69b9b1ce94e51fd7df9fa880 100644 (file)
@@ -114,7 +114,4 @@ struct sh_fsi_platform_info {
        int (*set_rate)(int is_porta, int rate); /* for master mode */
 };
 
-extern struct snd_soc_dai fsi_soc_dai[2];
-extern struct snd_soc_platform fsi_soc_platform;
-
 #endif /* __SOUND_FSI_H */
index 377693a143855fe24a827aaaa035f1c55cccfe61..e7b680248006524012531c0e78d165e01e09ea4b 100644 (file)
@@ -91,15 +91,17 @@ struct snd_pcm_substream;
                                SNDRV_PCM_FMTBIT_S32_LE |\
                                SNDRV_PCM_FMTBIT_S32_BE)
 
-struct snd_soc_dai_ops;
+struct snd_soc_dai_driver;
 struct snd_soc_dai;
 struct snd_ac97_bus_ops;
 
 /* Digital Audio Interface registration */
-int snd_soc_register_dai(struct snd_soc_dai *dai);
-void snd_soc_unregister_dai(struct snd_soc_dai *dai);
-int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count);
-void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count);
+int snd_soc_register_dai(struct device *dev,
+               struct snd_soc_dai_driver *dai_drv);
+void snd_soc_unregister_dai(struct device *dev);
+int snd_soc_register_dais(struct device *dev,
+               struct snd_soc_dai_driver *dai_drv, size_t count);
+void snd_soc_unregister_dais(struct device *dev, size_t count);
 
 /* Digital Audio Interface clocking API.*/
 int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
@@ -126,16 +128,6 @@ int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
 /* Digital Audio Interface mute */
 int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute);
 
-/*
- * Digital Audio Interface.
- *
- * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97
- * operations and capabilities. Codec and platform drivers will register this
- * structure for every DAI they have.
- *
- * This structure covers the clocking, formating and ALSA operations for each
- * interface.
- */
 struct snd_soc_dai_ops {
        /*
         * DAI clocking configuration, all optional.
@@ -191,24 +183,24 @@ struct snd_soc_dai_ops {
 };
 
 /*
- * Digital Audio Interface runtime data.
+ * Digital Audio Interface Driver.
  *
- * Holds runtime data for a DAI.
+ * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97
+ * operations and capabilities. Codec and platform drivers will register this
+ * structure for every DAI they have.
+ *
+ * This structure covers the clocking, formating and ALSA operations for each
+ * interface.
  */
-struct snd_soc_dai {
+struct snd_soc_dai_driver {
        /* DAI description */
-       char *name;
+       const char *name;
        unsigned int id;
        int ac97_control;
 
-       struct device *dev;
-       void *ac97_pdata;       /* platform_data for the ac97 codec */
-
-       /* DAI callbacks */
-       int (*probe)(struct platform_device *pdev,
-                    struct snd_soc_dai *dai);
-       void (*remove)(struct platform_device *pdev,
-                      struct snd_soc_dai *dai);
+       /* DAI driver callbacks */
+       int (*probe)(struct snd_soc_dai *dai);
+       int (*remove)(struct snd_soc_dai *dai);
        int (*suspend)(struct snd_soc_dai *dai);
        int (*resume)(struct snd_soc_dai *dai);
 
@@ -219,26 +211,51 @@ struct snd_soc_dai {
        struct snd_soc_pcm_stream capture;
        struct snd_soc_pcm_stream playback;
        unsigned int symmetric_rates:1;
+};
+
+/*
+ * Digital Audio Interface runtime data.
+ *
+ * Holds runtime data for a DAI.
+ */
+struct snd_soc_dai {
+       const char *name;
+       int id;
+       struct device *dev;
+       void *ac97_pdata;       /* platform_data for the ac97 codec */
+
+       /* driver ops */
+       struct snd_soc_dai_driver *driver;
 
        /* DAI runtime info */
-       struct snd_soc_codec *codec;
+       unsigned int capture_active:1;          /* stream is in use */
+       unsigned int playback_active:1;         /* stream is in use */
+       unsigned int symmetric_rates:1;
+       struct snd_pcm_runtime *runtime;
        unsigned int active;
        unsigned char pop_wait:1;
+       unsigned char probed:1;
 
-       /* DAI private data */
-       void *private_data;
+       /* DAI DMA data */
+       void *playback_dma_data;
+       void *capture_dma_data;
 
-       /* parent platform */
-       struct snd_soc_platform *platform;
+       /* parent platform/codec */
+       union {
+               struct snd_soc_platform *platform;
+               struct snd_soc_codec *codec;
+       };
+       struct snd_soc_card *card;
 
        struct list_head list;
+       struct list_head card_list;
 };
 
 static inline void *snd_soc_dai_get_dma_data(const struct snd_soc_dai *dai,
                                             const struct snd_pcm_substream *ss)
 {
        return (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-               dai->playback.dma_data : dai->capture.dma_data;
+               dai->playback_dma_data : dai->capture_dma_data;
 }
 
 static inline void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai,
@@ -246,9 +263,20 @@ static inline void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai,
                                            void *data)
 {
        if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               dai->playback.dma_data = data;
+               dai->playback_dma_data = data;
        else
-               dai->capture.dma_data = data;
+               dai->capture_dma_data = data;
+}
+
+static inline void snd_soc_dai_set_drvdata(struct snd_soc_dai *dai,
+               void *data)
+{
+       dev_set_drvdata(dai->dev, data);
+}
+
+static inline void *snd_soc_dai_get_drvdata(struct snd_soc_dai *dai)
+{
+       return dev_get_drvdata(dai->dev);
 }
 
 #endif
index c5d9987bc897adc5ec87a06ec57cadf2fd627471..8fd3b41b763f6a90ca60446cfd6cca97a36664aa 100644 (file)
 #define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \
 {      .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
        .reg = wreg, .shift = wshift, .invert = winvert }
+#define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \
+                             wevent, wflags)                           \
+{      .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
+       .reg = wreg, .shift = wshift, .invert = winvert, \
+       .event = wevent, .event_flags = wflags }
 #define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \
 {      .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
        .reg = wreg, .shift = wshift, .invert = winvert }
+#define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \
+                            wevent, wflags)                            \
+{      .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
+       .reg = wreg, .shift = wshift, .invert = winvert, \
+       .event = wevent, .event_flags = wflags }
 #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
 {      .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
        .shift = wshift, .invert = winvert}
@@ -322,14 +332,14 @@ int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
 
 /* dapm path setup */
 int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec);
-void snd_soc_dapm_free(struct snd_soc_device *socdev);
+void snd_soc_dapm_free(struct snd_soc_codec *codec);
 int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
                            const struct snd_soc_dapm_route *route, int num);
 
 /* dapm events */
-int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
-       int event);
-void snd_soc_dapm_shutdown(struct snd_soc_device *socdev);
+int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
+       const char *stream, int event);
+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);
diff --git a/include/sound/soc-of-simple.h b/include/sound/soc-of-simple.h
deleted file mode 100644 (file)
index a064e19..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * OF helpers for ALSA SoC
- *
- * Copyright (C) 2008, Secret Lab Technologies Ltd.
- */
-
-#ifndef _INCLUDE_SOC_OF_H_
-#define _INCLUDE_SOC_OF_H_
-
-#if defined(CONFIG_SND_SOC_OF_SIMPLE) || defined(CONFIG_SND_SOC_OF_SIMPLE_MODULE)
-
-#include <linux/of.h>
-#include <sound/soc.h>
-
-int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
-                             void *codec_data, struct snd_soc_dai *dai,
-                             struct device_node *node);
-
-int of_snd_soc_register_platform(struct snd_soc_platform *platform,
-                                struct device_node *node,
-                                struct snd_soc_dai *cpu_dai);
-
-#endif
-
-#endif /* _INCLUDE_SOC_OF_H_ */
index 65e9d03ed4f5e0c34ca833d6e6570de05fc78125..5c3bce83f28ad1be248a35c89d190dcb1504c36e 100644 (file)
  * @OFF:     Power Off. No restrictions on transition times.
  */
 enum snd_soc_bias_level {
-       SND_SOC_BIAS_ON,
-       SND_SOC_BIAS_PREPARE,
-       SND_SOC_BIAS_STANDBY,
        SND_SOC_BIAS_OFF,
+       SND_SOC_BIAS_STANDBY,
+       SND_SOC_BIAS_PREPARE,
+       SND_SOC_BIAS_ON,
 };
 
 struct snd_jack;
@@ -228,13 +228,17 @@ struct snd_soc_ops;
 struct snd_soc_dai_mode;
 struct snd_soc_pcm_runtime;
 struct snd_soc_dai;
+struct snd_soc_dai_driver;
 struct snd_soc_platform;
 struct snd_soc_dai_link;
+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;
+
 #ifdef CONFIG_GPIOLIB
 struct snd_soc_jack_gpio;
 #endif
@@ -249,19 +253,18 @@ enum snd_soc_control_type {
        SND_SOC_SPI,
 };
 
-int snd_soc_register_platform(struct snd_soc_platform *platform);
-void snd_soc_unregister_platform(struct snd_soc_platform *platform);
-int snd_soc_register_codec(struct snd_soc_codec *codec);
-void snd_soc_unregister_codec(struct snd_soc_codec *codec);
+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,
+               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);
 
-/* pcm <-> DAI connect */
-void snd_soc_free_pcms(struct snd_soc_device *socdev);
-int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid);
-
 /* Utility functions to get clock rates from various things */
 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
 int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
@@ -273,7 +276,7 @@ int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
        const struct snd_pcm_hardware *hw);
 
 /* Jack reporting */
-int snd_soc_jack_new(struct snd_soc_card *card, const char *id, int type,
+int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
                     struct snd_soc_jack *jack);
 void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask);
 int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
@@ -382,7 +385,7 @@ struct snd_soc_jack_gpio {
        int invert;
        int debounce_time;
        struct snd_soc_jack *jack;
-       struct work_struct work;
+       struct delayed_work work;
 
        int (*jack_status_check)(void);
 };
@@ -390,7 +393,7 @@ struct snd_soc_jack_gpio {
 
 struct snd_soc_jack {
        struct snd_jack *jack;
-       struct snd_soc_card *card;
+       struct snd_soc_codec *codec;
        struct list_head pins;
        int status;
        struct blocking_notifier_head notifier;
@@ -398,15 +401,13 @@ struct snd_soc_jack {
 
 /* SoC PCM stream information */
 struct snd_soc_pcm_stream {
-       char *stream_name;
+       const char *stream_name;
        u64 formats;                    /* SNDRV_PCM_FMTBIT_* */
        unsigned int rates;             /* SNDRV_PCM_RATE_* */
        unsigned int rate_min;          /* min rate */
        unsigned int rate_max;          /* max rate */
        unsigned int channels_min;      /* min channels */
        unsigned int channels_max;      /* max channels */
-       unsigned int active;            /* stream is in use */
-       void *dma_data;                 /* used by platform code */
 };
 
 /* SoC audio ops */
@@ -419,44 +420,36 @@ struct snd_soc_ops {
        int (*trigger)(struct snd_pcm_substream *, int);
 };
 
-/* SoC Audio Codec */
+/* SoC Audio Codec device */
 struct snd_soc_codec {
-       char *name;
-       struct module *owner;
-       struct mutex mutex;
+       const char *name;
+       int id;
        struct device *dev;
-       struct snd_soc_device *socdev;
+       struct snd_soc_codec_driver *driver;
 
+       struct mutex mutex;
+       struct snd_soc_card *card;
        struct list_head list;
-
-       /* callbacks */
-       int (*set_bias_level)(struct snd_soc_codec *,
-                             enum snd_soc_bias_level level);
+       struct list_head card_list;
+       int num_dai;
 
        /* runtime */
-       struct snd_card *card;
        struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
        unsigned int active;
-       unsigned int pcm_devs;
-       void *drvdata;
+       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 */
+       unsigned int probed:1; /* Codec has been probed */
+       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 */
 
        /* codec IO */
        void *control_data; /* codec control (i2c/3wire) data */
-       unsigned int (*read)(struct snd_soc_codec *, unsigned int);
-       int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
-       int (*display_register)(struct snd_soc_codec *, char *,
-                               size_t, unsigned int);
-       int (*volatile_register)(unsigned int);
-       int (*readable_register)(unsigned int);
        hw_write_t hw_write;
        unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
        void *reg_cache;
-       short reg_cache_size;
-       short reg_cache_step;
-
-       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 */
 
        /* dapm */
        u32 pop_time;
@@ -466,10 +459,6 @@ struct snd_soc_codec {
        enum snd_soc_bias_level suspend_bias_level;
        struct delayed_work delayed_work;
 
-       /* codec DAI's */
-       struct snd_soc_dai *dai;
-       unsigned int num_dai;
-
 #ifdef CONFIG_DEBUG_FS
        struct dentry *debugfs_codec_root;
        struct dentry *debugfs_reg;
@@ -478,23 +467,40 @@ struct snd_soc_codec {
 #endif
 };
 
-/* codec device */
-struct snd_soc_codec_device {
-       int (*probe)(struct platform_device *pdev);
-       int (*remove)(struct platform_device *pdev);
-       int (*suspend)(struct platform_device *pdev, pm_message_t state);
-       int (*resume)(struct platform_device *pdev);
+/* codec driver */
+struct snd_soc_codec_driver {
+
+       /* driver ops */
+       int (*probe)(struct snd_soc_codec *);
+       int (*remove)(struct snd_soc_codec *);
+       int (*suspend)(struct snd_soc_codec *,
+                       pm_message_t state);
+       int (*resume)(struct snd_soc_codec *);
+
+       /* codec IO */
+       unsigned int (*read)(struct snd_soc_codec *, unsigned int);
+       int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
+       int (*display_register)(struct snd_soc_codec *, char *,
+                               size_t, unsigned int);
+       int (*volatile_register)(unsigned int);
+       int (*readable_register)(unsigned int);
+       short reg_cache_size;
+       short reg_cache_step;
+       short reg_word_size;
+       const void *reg_cache_default;
+
+       /* codec bias level */
+       int (*set_bias_level)(struct snd_soc_codec *,
+                             enum snd_soc_bias_level level);
 };
 
 /* SoC platform interface */
-struct snd_soc_platform {
-       char *name;
-       struct list_head list;
+struct snd_soc_platform_driver {
 
-       int (*probe)(struct platform_device *pdev);
-       int (*remove)(struct platform_device *pdev);
-       int (*suspend)(struct snd_soc_dai_link *dai_link);
-       int (*resume)(struct snd_soc_dai_link *dai_link);
+       int (*probe)(struct snd_soc_platform *);
+       int (*remove)(struct snd_soc_platform *);
+       int (*suspend)(struct snd_soc_dai *dai);
+       int (*resume)(struct snd_soc_dai *dai);
 
        /* pcm creation and destruction */
        int (*pcm_new)(struct snd_card *, struct snd_soc_dai *,
@@ -509,23 +515,31 @@ struct snd_soc_platform {
                struct snd_soc_dai *);
 
        /* platform stream ops */
-       struct snd_pcm_ops *pcm_ops;
+       struct snd_pcm_ops *ops;
 };
 
-/* SoC machine DAI configuration, glues a codec and cpu DAI together */
-struct snd_soc_dai_link  {
-       char *name;                     /* Codec name */
-       char *stream_name;              /* Stream name */
+struct snd_soc_platform {
+       const char *name;
+       int id;
+       struct device *dev;
+       struct snd_soc_platform_driver *driver;
 
-       /* DAI */
-       struct snd_soc_dai *codec_dai;
-       struct snd_soc_dai *cpu_dai;
+       unsigned int suspended:1; /* platform is suspended */
+       unsigned int probed:1;
 
-       /* machine stream operations */
-       struct snd_soc_ops *ops;
+       struct snd_soc_card *card;
+       struct list_head list;
+       struct list_head card_list;
+};
 
-       /* codec/machine specific init - e.g. add machine controls */
-       int (*init)(struct snd_soc_codec *codec);
+struct snd_soc_dai_link {
+       /* config - must be set by machine driver */
+       const char *name;                       /* Codec name */
+       const char *stream_name;                /* Stream name */
+       const char *codec_name;         /* for multi-codec */
+       const char *platform_name;      /* for multi-platform */
+       const char *cpu_dai_name;
+       const char *codec_dai_name;
 
        /* Keep DAI active over suspend */
        unsigned int ignore_suspend:1;
@@ -533,21 +547,24 @@ struct snd_soc_dai_link  {
        /* Symmetry requirements */
        unsigned int symmetric_rates:1;
 
-       /* Symmetry data - only valid if symmetry is being enforced */
-       unsigned int rate;
+       /* codec/machine specific init - e.g. add machine controls */
+       int (*init)(struct snd_soc_pcm_runtime *rtd);
 
-       /* DAI pcm */
-       struct snd_pcm *pcm;
+       /* machine stream operations */
+       struct snd_soc_ops *ops;
 };
 
 /* SoC card */
 struct snd_soc_card {
-       char *name;
+       const char *name;
        struct device *dev;
+       struct snd_card *snd_card;
+       struct module *owner;
 
        struct list_head list;
+       struct mutex mutex;
 
-       int instantiated;
+       bool instantiated;
 
        int (*probe)(struct platform_device *pdev);
        int (*remove)(struct platform_device *pdev);
@@ -568,28 +585,38 @@ struct snd_soc_card {
        /* CPU <--> Codec DAI links  */
        struct snd_soc_dai_link *dai_link;
        int num_links;
+       struct snd_soc_pcm_runtime *rtd;
+       int num_rtd;
 
-       struct snd_soc_device *socdev;
-
-       struct snd_soc_codec *codec;
-
-       struct snd_soc_platform *platform;
-       struct delayed_work delayed_work;
        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;
 };
 
-/* SoC Device - the audio subsystem */
-struct snd_soc_device {
-       struct device *dev;
+/* SoC machine DAI configuration, glues a codec and cpu DAI together */
+struct snd_soc_pcm_runtime  {
+       struct device dev;
        struct snd_soc_card *card;
-       struct snd_soc_codec_device *codec_dev;
-       void *codec_data;
-};
+       struct snd_soc_dai_link *dai_link;
+
+       unsigned int complete:1;
+       unsigned int dev_registered:1;
+
+       /* Symmetry data - only valid if symmetry is being enforced */
+       unsigned int rate;
+       long pmdown_time;
 
-/* runtime channel data */
-struct snd_soc_pcm_runtime {
-       struct snd_soc_dai_link *dai;
-       struct snd_soc_device *socdev;
+       /* runtime devices */
+       struct snd_pcm *pcm;
+       struct snd_soc_codec *codec;
+       struct snd_soc_platform *platform;
+       struct snd_soc_dai *codec_dai;
+       struct snd_soc_dai *cpu_dai;
+
+       struct delayed_work delayed_work;
 };
 
 /* mixer control */
@@ -615,24 +642,48 @@ struct soc_enum {
 static inline unsigned int snd_soc_read(struct snd_soc_codec *codec,
                                        unsigned int reg)
 {
-       return codec->read(codec, 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->write(codec, reg, val);
+       return codec->driver->write(codec, reg, val);
 }
 
+/* device driver data */
+
 static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec,
-                                            void *data)
+               void *data)
 {
-       codec->drvdata = data;
+       dev_set_drvdata(codec->dev, data);
 }
 
 static inline void *snd_soc_codec_get_drvdata(struct snd_soc_codec *codec)
 {
-       return codec->drvdata;
+       return dev_get_drvdata(codec->dev);
+}
+
+static inline void snd_soc_platform_set_drvdata(struct snd_soc_platform *platform,
+               void *data)
+{
+       dev_set_drvdata(platform->dev, data);
+}
+
+static inline void *snd_soc_platform_get_drvdata(struct snd_soc_platform *platform)
+{
+       return dev_get_drvdata(platform->dev);
+}
+
+static inline void snd_soc_pcm_set_drvdata(struct snd_soc_pcm_runtime *rtd,
+               void *data)
+{
+       dev_set_drvdata(&rtd->dev, data);
+}
+
+static inline void *snd_soc_pcm_get_drvdata(struct snd_soc_pcm_runtime *rtd)
+{
+       return dev_get_drvdata(&rtd->dev);
 }
 
 #include <sound/soc-dai.h>
index 9fd5b19ccf5c05a7002440588041e49b3e9a8e18..7067e2dfb0b992abc09840c1c58c23a4d4d7e351 100644 (file)
 #define SNDRV_CTL_TLVT_DB_MINMAX 4     /* dB scale with min/max */
 #define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5        /* dB scale with min/max with mute */
 
+#define TLV_DB_SCALE_MASK      0xffff
+#define TLV_DB_SCALE_MUTE      0x10000
 #define TLV_DB_SCALE_ITEM(min, step, mute)                     \
        SNDRV_CTL_TLVT_DB_SCALE, 2 * sizeof(unsigned int),      \
-       (min), ((step) & 0xffff) | ((mute) ? 0x10000 : 0)
+       (min), ((step) & TLV_DB_SCALE_MASK) | ((mute) ? TLV_DB_SCALE_MUTE : 0)
 #define DECLARE_TLV_DB_SCALE(name, min, step, mute) \
        unsigned int name[] = { TLV_DB_SCALE_ITEM(min, step, mute) }
 
index b1a5f34e5cfad9917cb48ecd3872152eeae6944b..99e0308bf2c2416d3e0864fd1063b53f3f2656c3 100644 (file)
 #ifndef __TLV320AIC3x_H__
 #define __TLV320AIC3x_H__
 
+/* GPIO API */
+enum {
+       AIC3X_GPIO1_FUNC_DISABLED               = 0,
+       AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC      = 1,
+       AIC3X_GPIO1_FUNC_CLOCK_MUX              = 2,
+       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2         = 3,
+       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4         = 4,
+       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8         = 5,
+       AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ      = 6,
+       AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ          = 7,
+       AIC3X_GPIO1_FUNC_INPUT                  = 8,
+       AIC3X_GPIO1_FUNC_OUTPUT                 = 9,
+       AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK     = 10,
+       AIC3X_GPIO1_FUNC_AUDIO_WORDCLK          = 11,
+       AIC3X_GPIO1_FUNC_BUTTON_IRQ             = 12,
+       AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ     = 13,
+       AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ   = 14,
+       AIC3X_GPIO1_FUNC_ALL_IRQ                = 16
+};
+
+enum {
+       AIC3X_GPIO2_FUNC_DISABLED               = 0,
+       AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ     = 2,
+       AIC3X_GPIO2_FUNC_INPUT                  = 3,
+       AIC3X_GPIO2_FUNC_OUTPUT                 = 4,
+       AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT      = 5,
+       AIC3X_GPIO2_FUNC_AUDIO_BITCLK           = 8,
+       AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9,
+       AIC3X_GPIO2_FUNC_ALL_IRQ                = 10,
+       AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11,
+       AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12,
+       AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ      = 13,
+       AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ          = 14,
+       AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ       = 15
+};
+
+struct aic3x_setup_data {
+       unsigned int gpio_func[2];
+};
+
 struct aic3x_pdata {
        int gpio_reset; /* < 0 if not used */
+       struct aic3x_setup_data *setup;
 };
 
-#endif
\ No newline at end of file
+#endif
diff --git a/include/sound/wm8962.h b/include/sound/wm8962.h
new file mode 100644 (file)
index 0000000..2b5306c
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * wm8962.h  --  WM8962 Soc Audio driver platform data
+ *
+ * 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 _WM8962_PDATA_H
+#define _WM8962_PDATA_H
+
+#define WM8962_MAX_GPIO 6
+
+/* Use to set GPIO default values to zero */
+#define WM8962_GPIO_SET 0x10000
+
+struct wm8962_pdata {
+       int gpio_base;
+       u32 gpio_init[WM8962_MAX_GPIO];
+
+       /* Setup for microphone detection, raw value to be written to
+        * R48(0x30) - only microphone related bits will be updated.
+        * Detection may be enabled here for use with signals brought
+        * out on the GPIOs. */
+       u32 mic_cfg;
+
+       bool irq_active_low;
+
+       bool spk_mono;   /* Speaker outputs tied together as mono */
+};
+
+#endif
index 577cf18cce8961ec8a1075b150cb985f0ee63997..1e1aa54ab2e45bad0c1d6841572ba84ff0e912a3 100644 (file)
 struct sh_mobile_lcdc_chan_cfg;
 struct device;
 
+/*
+ * flags format
+ *
+ * 0x0000000A
+ *
+ * A: Audio source select
+ */
+
+/* Audio source select */
+#define HDMI_SND_SRC_MASK      (0xF << 0)
+#define HDMI_SND_SRC_I2S       (0 << 0) /* default */
+#define HDMI_SND_SRC_SPDIF     (1 << 0)
+#define HDMI_SND_SRC_DSD       (2 << 0)
+#define HDMI_SND_SRC_HBR       (3 << 0)
+
 struct sh_mobile_hdmi_info {
        struct sh_mobile_lcdc_chan_cfg  *lcd_chan;
        struct device                   *lcd_dev;
+       unsigned int                     flags;
 };
 
 #endif
index f7c3df8b521b2c85db5771a68acf27f981084aae..57b792e2439a0f9b939c5789d7c23678ff8377bc 100644 (file)
@@ -604,11 +604,16 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr,
                return -EEXIST;
        }
        for (idx = 0; idx < snd_ecards_limit; idx++) {
-               if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1))
-                       goto __exist;
+               if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) {
+                       if (card == snd_cards[idx])
+                               goto __ok;
+                       else
+                               goto __exist;
+               }
        }
        strcpy(card->id, buf1);
        snd_info_card_id_change(card);
+__ok:
        mutex_unlock(&snd_card_mutex);
 
        return count;
index f50ebf20df966a93380d15fd1a3c3e4acd2890e7..822dd56993ca2a54de249d38e5827be11be9b7ac 100644 (file)
@@ -77,7 +77,7 @@ static int snd_mixer_oss_release(struct inode *inode, struct file *file)
        struct snd_mixer_oss_file *fmixer;
 
        if (file->private_data) {
-               fmixer = (struct snd_mixer_oss_file *) file->private_data;
+               fmixer = file->private_data;
                module_put(fmixer->card->module);
                snd_card_file_remove(fmixer->card, file);
                kfree(fmixer);
@@ -368,7 +368,7 @@ static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int
 
 static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       return snd_mixer_oss_ioctl1((struct snd_mixer_oss_file *) file->private_data, cmd, arg);
+       return snd_mixer_oss_ioctl1(file->private_data, cmd, arg);
 }
 
 int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg)
@@ -582,7 +582,7 @@ static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer,
                                     struct snd_mixer_oss_slot *pslot,
                                     int *left, int *right)
 {
-       struct slot *slot = (struct slot *)pslot->private_data;
+       struct slot *slot = pslot->private_data;
        
        *left = *right = 100;
        if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
@@ -618,8 +618,10 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
        if (numid == ID_UNKNOWN)
                return;
        down_read(&card->controls_rwsem);
-       if ((kctl = snd_ctl_find_numid(card, numid)) == NULL)
+       if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
+               up_read(&card->controls_rwsem);
                return;
+       }
        uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
        if (uinfo == NULL || uctl == NULL)
@@ -658,7 +660,7 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
                return;
        down_read(&card->controls_rwsem);
        if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
-               up_read(&fmixer->card->controls_rwsem);
+               up_read(&card->controls_rwsem);
                return;
        }
        uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
@@ -691,7 +693,7 @@ static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
                                     struct snd_mixer_oss_slot *pslot,
                                     int left, int right)
 {
-       struct slot *slot = (struct slot *)pslot->private_data;
+       struct slot *slot = pslot->private_data;
        
        if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
                snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
@@ -740,7 +742,7 @@ static int snd_mixer_oss_get_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
                                        struct snd_mixer_oss_slot *pslot,
                                        int *active)
 {
-       struct slot *slot = (struct slot *)pslot->private_data;
+       struct slot *slot = pslot->private_data;
        int left, right;
        
        left = right = 1;
@@ -753,7 +755,7 @@ static int snd_mixer_oss_get_recsrc1_route(struct snd_mixer_oss_file *fmixer,
                                           struct snd_mixer_oss_slot *pslot,
                                           int *active)
 {
-       struct slot *slot = (struct slot *)pslot->private_data;
+       struct slot *slot = pslot->private_data;
        int left, right;
        
        left = right = 1;
@@ -766,7 +768,7 @@ static int snd_mixer_oss_put_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
                                        struct snd_mixer_oss_slot *pslot,
                                        int active)
 {
-       struct slot *slot = (struct slot *)pslot->private_data;
+       struct slot *slot = pslot->private_data;
        
        snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0);
        return 0;
@@ -776,7 +778,7 @@ static int snd_mixer_oss_put_recsrc1_route(struct snd_mixer_oss_file *fmixer,
                                           struct snd_mixer_oss_slot *pslot,
                                           int active)
 {
-       struct slot *slot = (struct slot *)pslot->private_data;
+       struct slot *slot = pslot->private_data;
        
        snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1);
        return 0;
@@ -797,7 +799,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
        if (uinfo == NULL || uctl == NULL) {
                err = -ENOMEM;
-               goto __unlock;
+               goto __free_only;
        }
        down_read(&card->controls_rwsem);
        kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
@@ -813,7 +815,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
                if (!(mixer->mask_recsrc & (1 << idx)))
                        continue;
                pslot = &mixer->slots[idx];
-               slot = (struct slot *)pslot->private_data;
+               slot = pslot->private_data;
                if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
                        continue;
                if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
@@ -826,6 +828,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
        err = 0;
       __unlock:
        up_read(&card->controls_rwsem);
+      __free_only:
        kfree(uctl);
        kfree(uinfo);
        return err;
@@ -847,7 +850,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
        if (uinfo == NULL || uctl == NULL) {
                err = -ENOMEM;
-               goto __unlock;
+               goto __free_only;
        }
        down_read(&card->controls_rwsem);
        kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
@@ -861,7 +864,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
                if (!(mixer->mask_recsrc & (1 << idx)))
                        continue;
                pslot = &mixer->slots[idx];
-               slot = (struct slot *)pslot->private_data;
+               slot = pslot->private_data;
                if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
                        continue;
                if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
@@ -880,6 +883,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
        err = 0;
       __unlock:
        up_read(&card->controls_rwsem);
+      __free_only:
        kfree(uctl);
        kfree(uinfo);
        return err;
@@ -925,7 +929,7 @@ static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *sl
 
 static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn)
 {
-       struct slot *p = (struct slot *)chn->private_data;
+       struct slot *p = chn->private_data;
        if (p) {
                if (p->allocated && p->assigned) {
                        kfree(p->assigned->name);
index ac242a377aea8068f859bce49aae6825aae5d001..6b4b1287b314455111c5853334a4aded9425edd3 100644 (file)
@@ -364,8 +364,7 @@ static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry,
 static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry,
                                             struct snd_info_buffer *buffer)
 {
-       snd_pcm_proc_info_read((struct snd_pcm_substream *)entry->private_data,
-                              buffer);
+       snd_pcm_proc_info_read(entry->private_data, buffer);
 }
 
 static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
index e23e0e7ab26f9ff5f02204ca62422a14cc674e5e..a1707cca9c6635c8b4cd7e79b5cebe21bffc2d9e 100644 (file)
@@ -334,11 +334,15 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
                /* delta = "expected next hw_ptr" for in_interrupt != 0 */
                delta = runtime->hw_ptr_interrupt + runtime->period_size;
                if (delta > new_hw_ptr) {
-                       hw_base += runtime->buffer_size;
-                       if (hw_base >= runtime->boundary)
-                               hw_base = 0;
-                       new_hw_ptr = hw_base + pos;
-                       goto __delta;
+                       /* check for double acknowledged interrupts */
+                       hdelta = jiffies - runtime->hw_ptr_jiffies;
+                       if (hdelta > runtime->hw_ptr_buffer_jiffies/2) {
+                               hw_base += runtime->buffer_size;
+                               if (hw_base >= runtime->boundary)
+                                       hw_base = 0;
+                               new_hw_ptr = hw_base + pos;
+                               goto __delta;
+                       }
                }
        }
        /* new_hw_ptr might be lower than old_hw_ptr in case when */
index d4eb2ef8078416cc8d06e5d80f3ec3bb467a4f1b..8bc7cb3db33056abce9a03cec36a4266305aa12c 100644 (file)
@@ -142,7 +142,7 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream,
 
 #ifdef RULES_DEBUG
 #define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v
-char *snd_pcm_hw_param_names[] = {
+static const char * const snd_pcm_hw_param_names[] = {
        HW_PARAM(ACCESS),
        HW_PARAM(FORMAT),
        HW_PARAM(SUBFORMAT),
@@ -864,6 +864,8 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state)
        struct snd_pcm_runtime *runtime = substream->runtime;
        snd_pcm_trigger_tstamp(substream);
        runtime->hw_ptr_jiffies = jiffies;
+       runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) / 
+                                                           runtime->rate;
        runtime->status->state = state;
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
            runtime->silence_size > 0)
index 480c38623da80949fded427bcc98ff54e1092872..c8961165277cce21a85147d6571cf014e86bf13d 100644 (file)
@@ -74,6 +74,25 @@ config SND_DUMMY
          To compile this driver as a module, choose M here: the module
          will be called snd-dummy.
 
+config SND_ALOOP
+        tristate "Generic loopback driver (PCM)"
+        select SND_PCM
+        help
+          Say 'Y' or 'M' to include support for the PCM loopback device.
+         This module returns played samples back to the user space using
+         the standard ALSA PCM device. The devices are routed 0->1 and
+          1->0, where first number is the playback PCM device and second
+         number is the capture device. Module creates two PCM devices and
+         configured number of substreams (see the pcm_substreams module
+          parameter).
+
+         The looback device allow time sychronization with an external
+         timing source using the time shift universal control (+-20%
+         of system time).
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-aloop.
+
 config SND_VIRMIDI
        tristate "Virtual MIDI soundcard"
        depends on SND_SEQUENCER
index d4a07f9ff2c7117f018971b37b07ea6950af875a..1a8440c8b1386e5ef4f413c8826b1f80ca93a951 100644 (file)
@@ -4,6 +4,7 @@
 #
 
 snd-dummy-objs := dummy.o
+snd-aloop-objs := aloop.o
 snd-mtpav-objs := mtpav.o
 snd-mts64-objs := mts64.o
 snd-portman2x4-objs := portman2x4.o
@@ -13,6 +14,7 @@ snd-ml403-ac97cr-objs := ml403-ac97cr.o pcm-indirect2.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_DUMMY) += snd-dummy.o
+obj-$(CONFIG_SND_ALOOP) += snd-aloop.o
 obj-$(CONFIG_SND_VIRMIDI) += snd-virmidi.o
 obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o
 obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
new file mode 100644 (file)
index 0000000..12b44b0
--- /dev/null
@@ -0,0 +1,1258 @@
+/*
+ *  Loopback soundcard
+ *
+ *  Original code:
+ *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ *
+ *  More accurate positioning and full-duplex support:
+ *  Copyright (c) Ahmet Ä°nan <ainan at mathematik.uni-freiburg.de>
+ *
+ *  Major (almost complete) rewrite:
+ *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *  A next major update in 2010 (separate timers for playback and capture):
+ *  Copyright (c) Jaroslav Kysela <perex@perex.cz>
+ *
+ *   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/info.h>
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
+MODULE_DESCRIPTION("A loopback soundcard");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{ALSA,Loopback soundcard}}");
+
+#define MAX_PCM_SUBSTREAMS     8
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
+static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
+static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
+static int pcm_notify[SNDRV_CARDS];
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for loopback soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for loopback soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable this loopback soundcard.");
+module_param_array(pcm_substreams, int, NULL, 0444);
+MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver.");
+module_param_array(pcm_notify, int, NULL, 0444);
+MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels changes.");
+
+#define NO_PITCH 100000
+
+struct loopback_pcm;
+
+struct loopback_cable {
+       spinlock_t lock;
+       struct loopback_pcm *streams[2];
+       struct snd_pcm_hardware hw;
+       /* flags */
+       unsigned int valid;
+       unsigned int running;
+       unsigned int pause;
+};
+
+struct loopback_setup {
+       unsigned int notify: 1;
+       unsigned int rate_shift;
+       unsigned int format;
+       unsigned int rate;
+       unsigned int channels;
+       struct snd_ctl_elem_id active_id;
+       struct snd_ctl_elem_id format_id;
+       struct snd_ctl_elem_id rate_id;
+       struct snd_ctl_elem_id channels_id;
+};
+
+struct loopback {
+       struct snd_card *card;
+       struct mutex cable_lock;
+       struct loopback_cable *cables[MAX_PCM_SUBSTREAMS][2];
+       struct snd_pcm *pcm[2];
+       struct loopback_setup setup[MAX_PCM_SUBSTREAMS][2];
+};
+
+struct loopback_pcm {
+       struct loopback *loopback;
+       struct snd_pcm_substream *substream;
+       struct loopback_cable *cable;
+       unsigned int pcm_buffer_size;
+       unsigned int buf_pos;   /* position in buffer */
+       unsigned int silent_size;
+       /* PCM parameters */
+       unsigned int pcm_period_size;
+       unsigned int pcm_bps;           /* bytes per second */
+       unsigned int pcm_salign;        /* bytes per sample * channels */
+       unsigned int pcm_rate_shift;    /* rate shift value */
+       /* flags */
+       unsigned int period_update_pending :1;
+       /* timer stuff */
+       unsigned int irq_pos;           /* fractional IRQ position */
+       unsigned int period_size_frac;
+       unsigned long last_jiffies;
+       struct timer_list timer;
+};
+
+static struct platform_device *devices[SNDRV_CARDS];
+
+static inline unsigned int byte_pos(struct loopback_pcm *dpcm, unsigned int x)
+{
+       if (dpcm->pcm_rate_shift == NO_PITCH) {
+               x /= HZ;
+       } else {
+               x = div_u64(NO_PITCH * (unsigned long long)x,
+                           HZ * (unsigned long long)dpcm->pcm_rate_shift);
+       }
+       return x - (x % dpcm->pcm_salign);
+}
+
+static inline unsigned int frac_pos(struct loopback_pcm *dpcm, unsigned int x)
+{
+       if (dpcm->pcm_rate_shift == NO_PITCH) { /* no pitch */
+               return x * HZ;
+       } else {
+               x = div_u64(dpcm->pcm_rate_shift * (unsigned long long)x * HZ,
+                           NO_PITCH);
+       }
+       return x;
+}
+
+static inline struct loopback_setup *get_setup(struct loopback_pcm *dpcm)
+{
+       int device = dpcm->substream->pstr->pcm->device;
+       
+       if (dpcm->substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               device ^= 1;
+       return &dpcm->loopback->setup[dpcm->substream->number][device];
+}
+
+static inline unsigned int get_notify(struct loopback_pcm *dpcm)
+{
+       return get_setup(dpcm)->notify;
+}
+
+static inline unsigned int get_rate_shift(struct loopback_pcm *dpcm)
+{
+       return get_setup(dpcm)->rate_shift;
+}
+
+static void loopback_timer_start(struct loopback_pcm *dpcm)
+{
+       unsigned long tick;
+       unsigned int rate_shift = get_rate_shift(dpcm);
+
+       if (rate_shift != dpcm->pcm_rate_shift) {
+               dpcm->pcm_rate_shift = rate_shift;
+               dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size);
+       }
+       if (dpcm->period_size_frac <= dpcm->irq_pos) {
+               dpcm->irq_pos %= dpcm->period_size_frac;
+               dpcm->period_update_pending = 1;
+       }
+       tick = dpcm->period_size_frac - dpcm->irq_pos;
+       tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps;
+       dpcm->timer.expires = jiffies + tick;
+       add_timer(&dpcm->timer);
+}
+
+static inline void loopback_timer_stop(struct loopback_pcm *dpcm)
+{
+       del_timer(&dpcm->timer);
+       dpcm->timer.expires = 0;
+}
+
+#define CABLE_VALID_PLAYBACK   (1 << SNDRV_PCM_STREAM_PLAYBACK)
+#define CABLE_VALID_CAPTURE    (1 << SNDRV_PCM_STREAM_CAPTURE)
+#define CABLE_VALID_BOTH       (CABLE_VALID_PLAYBACK|CABLE_VALID_CAPTURE)
+
+static int loopback_check_format(struct loopback_cable *cable, int stream)
+{
+       struct snd_pcm_runtime *runtime, *cruntime;
+       struct loopback_setup *setup;
+       struct snd_card *card;
+       int check;
+
+       if (cable->valid != CABLE_VALID_BOTH) {
+               if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       goto __notify;
+               return 0;
+       }
+       runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
+                                                       substream->runtime;
+       cruntime = cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
+                                                       substream->runtime;
+       check = runtime->format != cruntime->format ||
+               runtime->rate != cruntime->rate ||
+               runtime->channels != cruntime->channels;
+       if (!check)
+               return 0;
+       if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+               return -EIO;
+       } else {
+               snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
+                                       substream, SNDRV_PCM_STATE_DRAINING);
+             __notify:
+               runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
+                                                       substream->runtime;
+               setup = get_setup(cable->streams[SNDRV_PCM_STREAM_PLAYBACK]);
+               card = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->loopback->card;
+               if (setup->format != runtime->format) {
+                       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+                                                       &setup->format_id);
+                       setup->format = runtime->format;
+               }
+               if (setup->rate != runtime->rate) {
+                       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+                                                       &setup->rate_id);
+                       setup->rate = runtime->rate;
+               }
+               if (setup->channels != runtime->channels) {
+                       snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
+                                                       &setup->channels_id);
+                       setup->channels = runtime->channels;
+               }
+       }
+       return 0;
+}
+
+static void loopback_active_notify(struct loopback_pcm *dpcm)
+{
+       snd_ctl_notify(dpcm->loopback->card,
+                      SNDRV_CTL_EVENT_MASK_VALUE,
+                      &get_setup(dpcm)->active_id);
+}
+
+static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct loopback_pcm *dpcm = runtime->private_data;
+       struct loopback_cable *cable = dpcm->cable;
+       int err, stream = 1 << substream->stream;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               err = loopback_check_format(cable, substream->stream);
+               if (err < 0)
+                       return err;
+               dpcm->last_jiffies = jiffies;
+               dpcm->pcm_rate_shift = 0;
+               spin_lock(&cable->lock);        
+               cable->running |= stream;
+               cable->pause &= ~stream;
+               spin_unlock(&cable->lock);
+               loopback_timer_start(dpcm);
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       loopback_active_notify(dpcm);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               spin_lock(&cable->lock);        
+               cable->running &= ~stream;
+               cable->pause &= ~stream;
+               spin_unlock(&cable->lock);
+               loopback_timer_stop(dpcm);
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       loopback_active_notify(dpcm);
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               spin_lock(&cable->lock);        
+               cable->pause |= stream;
+               spin_unlock(&cable->lock);
+               loopback_timer_stop(dpcm);
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               spin_lock(&cable->lock);
+               dpcm->last_jiffies = jiffies;
+               cable->pause &= ~stream;
+               spin_unlock(&cable->lock);
+               loopback_timer_start(dpcm);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static void params_change_substream(struct loopback_pcm *dpcm,
+                                   struct snd_pcm_runtime *runtime)
+{
+       struct snd_pcm_runtime *dst_runtime;
+
+       if (dpcm == NULL || dpcm->substream == NULL)
+               return;
+       dst_runtime = dpcm->substream->runtime;
+       if (dst_runtime == NULL)
+               return;
+       dst_runtime->hw = dpcm->cable->hw;
+}
+
+static void params_change(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct loopback_pcm *dpcm = runtime->private_data;
+       struct loopback_cable *cable = dpcm->cable;
+
+       cable->hw.formats = (1ULL << runtime->format);
+       cable->hw.rate_min = runtime->rate;
+       cable->hw.rate_max = runtime->rate;
+       cable->hw.channels_min = runtime->channels;
+       cable->hw.channels_max = runtime->channels;
+       params_change_substream(cable->streams[SNDRV_PCM_STREAM_PLAYBACK],
+                               runtime);
+       params_change_substream(cable->streams[SNDRV_PCM_STREAM_CAPTURE],
+                               runtime);
+}
+
+static int loopback_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct loopback_pcm *dpcm = runtime->private_data;
+       struct loopback_cable *cable = dpcm->cable;
+       int bps, salign;
+
+       salign = (snd_pcm_format_width(runtime->format) *
+                                               runtime->channels) / 8;
+       bps = salign * runtime->rate;
+       if (bps <= 0 || salign <= 0)
+               return -EINVAL;
+
+       dpcm->buf_pos = 0;
+       dpcm->pcm_buffer_size = frames_to_bytes(runtime, runtime->buffer_size);
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               /* clear capture buffer */
+               dpcm->silent_size = dpcm->pcm_buffer_size;
+               snd_pcm_format_set_silence(runtime->format, runtime->dma_area,
+                                          runtime->buffer_size * runtime->channels);
+       }
+
+       dpcm->irq_pos = 0;
+       dpcm->period_update_pending = 0;
+       dpcm->pcm_bps = bps;
+       dpcm->pcm_salign = salign;
+       dpcm->pcm_period_size = frames_to_bytes(runtime, runtime->period_size);
+
+       mutex_lock(&dpcm->loopback->cable_lock);
+       if (!(cable->valid & ~(1 << substream->stream)) ||
+            (get_setup(dpcm)->notify &&
+            substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
+               params_change(substream);
+       cable->valid |= 1 << substream->stream;
+       mutex_unlock(&dpcm->loopback->cable_lock);
+
+       return 0;
+}
+
+static void clear_capture_buf(struct loopback_pcm *dpcm, unsigned int bytes)
+{
+       struct snd_pcm_runtime *runtime = dpcm->substream->runtime;
+       char *dst = runtime->dma_area;
+       unsigned int dst_off = dpcm->buf_pos;
+
+       if (dpcm->silent_size >= dpcm->pcm_buffer_size)
+               return;
+       if (dpcm->silent_size + bytes > dpcm->pcm_buffer_size)
+               bytes = dpcm->pcm_buffer_size - dpcm->silent_size;
+
+       for (;;) {
+               unsigned int size = bytes;
+               if (dst_off + size > dpcm->pcm_buffer_size)
+                       size = dpcm->pcm_buffer_size - dst_off;
+               snd_pcm_format_set_silence(runtime->format, dst + dst_off,
+                                          bytes_to_frames(runtime, size) *
+                                               runtime->channels);
+               dpcm->silent_size += size;
+               bytes -= size;
+               if (!bytes)
+                       break;
+               dst_off = 0;
+       }
+}
+
+static void copy_play_buf(struct loopback_pcm *play,
+                         struct loopback_pcm *capt,
+                         unsigned int bytes)
+{
+       struct snd_pcm_runtime *runtime = play->substream->runtime;
+       char *src = runtime->dma_area;
+       char *dst = capt->substream->runtime->dma_area;
+       unsigned int src_off = play->buf_pos;
+       unsigned int dst_off = capt->buf_pos;
+       unsigned int clear_bytes = 0;
+
+       /* check if playback is draining, trim the capture copy size
+        * when our pointer is at the end of playback ring buffer */
+       if (runtime->status->state == SNDRV_PCM_STATE_DRAINING &&
+           snd_pcm_playback_hw_avail(runtime) < runtime->buffer_size) { 
+               snd_pcm_uframes_t appl_ptr, appl_ptr1, diff;
+               appl_ptr = appl_ptr1 = runtime->control->appl_ptr;
+               appl_ptr1 -= appl_ptr1 % runtime->buffer_size;
+               appl_ptr1 += play->buf_pos / play->pcm_salign;
+               if (appl_ptr < appl_ptr1)
+                       appl_ptr1 -= runtime->buffer_size;
+               diff = (appl_ptr - appl_ptr1) * play->pcm_salign;
+               if (diff < bytes) {
+                       clear_bytes = bytes - diff;
+                       bytes = diff;
+               }
+       }
+
+       for (;;) {
+               unsigned int size = bytes;
+               if (src_off + size > play->pcm_buffer_size)
+                       size = play->pcm_buffer_size - src_off;
+               if (dst_off + size > capt->pcm_buffer_size)
+                       size = capt->pcm_buffer_size - dst_off;
+               memcpy(dst + dst_off, src + src_off, size);
+               capt->silent_size = 0;
+               bytes -= size;
+               if (!bytes)
+                       break;
+               src_off = (src_off + size) % play->pcm_buffer_size;
+               dst_off = (dst_off + size) % capt->pcm_buffer_size;
+       }
+
+       if (clear_bytes > 0) {
+               clear_capture_buf(capt, clear_bytes);
+               capt->silent_size = 0;
+       }
+}
+
+#define BYTEPOS_UPDATE_POSONLY 0
+#define BYTEPOS_UPDATE_CLEAR   1
+#define BYTEPOS_UPDATE_COPY    2
+
+static void loopback_bytepos_update(struct loopback_pcm *dpcm,
+                                   unsigned int delta,
+                                   unsigned int cmd)
+{
+       unsigned int count;
+       unsigned long last_pos;
+
+       last_pos = byte_pos(dpcm, dpcm->irq_pos);
+       dpcm->irq_pos += delta * dpcm->pcm_bps;
+       count = byte_pos(dpcm, dpcm->irq_pos) - last_pos;
+       if (!count)
+               return;
+       if (cmd == BYTEPOS_UPDATE_CLEAR)
+               clear_capture_buf(dpcm, count);
+       else if (cmd == BYTEPOS_UPDATE_COPY)
+               copy_play_buf(dpcm->cable->streams[SNDRV_PCM_STREAM_PLAYBACK],
+                             dpcm->cable->streams[SNDRV_PCM_STREAM_CAPTURE],
+                             count);
+       dpcm->buf_pos += count;
+       dpcm->buf_pos %= dpcm->pcm_buffer_size;
+       if (dpcm->irq_pos >= dpcm->period_size_frac) {
+               dpcm->irq_pos %= dpcm->period_size_frac;
+               dpcm->period_update_pending = 1;
+       }
+}
+
+static unsigned int loopback_pos_update(struct loopback_cable *cable)
+{
+       struct loopback_pcm *dpcm_play =
+                       cable->streams[SNDRV_PCM_STREAM_PLAYBACK];
+       struct loopback_pcm *dpcm_capt =
+                       cable->streams[SNDRV_PCM_STREAM_CAPTURE];
+       unsigned long delta_play = 0, delta_capt = 0;
+       unsigned int running;
+
+       spin_lock(&cable->lock);        
+       running = cable->running ^ cable->pause;
+       if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) {
+               delta_play = jiffies - dpcm_play->last_jiffies;
+               dpcm_play->last_jiffies += delta_play;
+       }
+
+       if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) {
+               delta_capt = jiffies - dpcm_capt->last_jiffies;
+               dpcm_capt->last_jiffies += delta_capt;
+       }
+
+       if (delta_play == 0 && delta_capt == 0) {
+               spin_unlock(&cable->lock);
+               return running;
+       }
+               
+       if (delta_play > delta_capt) {
+               loopback_bytepos_update(dpcm_play, delta_play - delta_capt,
+                                       BYTEPOS_UPDATE_POSONLY);
+               delta_play = delta_capt;
+       } else if (delta_play < delta_capt) {
+               loopback_bytepos_update(dpcm_capt, delta_capt - delta_play,
+                                       BYTEPOS_UPDATE_CLEAR);
+               delta_capt = delta_play;
+       }
+
+       if (delta_play == 0 && delta_capt == 0) {
+               spin_unlock(&cable->lock);
+               return running;
+       }
+       /* note delta_capt == delta_play at this moment */
+       loopback_bytepos_update(dpcm_capt, delta_capt, BYTEPOS_UPDATE_COPY);
+       loopback_bytepos_update(dpcm_play, delta_play, BYTEPOS_UPDATE_POSONLY);
+       spin_unlock(&cable->lock);
+       return running;
+}
+
+static void loopback_timer_function(unsigned long data)
+{
+       struct loopback_pcm *dpcm = (struct loopback_pcm *)data;
+       unsigned int running;
+
+       running = loopback_pos_update(dpcm->cable);
+       if (running & (1 << dpcm->substream->stream)) {
+               loopback_timer_start(dpcm);
+               if (dpcm->period_update_pending) {
+                       dpcm->period_update_pending = 0;
+                       snd_pcm_period_elapsed(dpcm->substream);
+               }
+       }
+}
+
+static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct loopback_pcm *dpcm = runtime->private_data;
+
+       loopback_pos_update(dpcm->cable);
+       return bytes_to_frames(runtime, dpcm->buf_pos);
+}
+
+static struct snd_pcm_hardware loopback_pcm_hardware =
+{
+       .info =         (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP |
+                        SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE),
+       .formats =      (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
+                        SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |
+                        SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE),
+       .rates =        SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000,
+       .rate_min =             8000,
+       .rate_max =             192000,
+       .channels_min =         1,
+       .channels_max =         32,
+       .buffer_bytes_max =     2 * 1024 * 1024,
+       .period_bytes_min =     64,
+       /* note check overflow in frac_pos() using pcm_rate_shift before
+          changing period_bytes_max value */
+       .period_bytes_max =     1024 * 1024,
+       .periods_min =          1,
+       .periods_max =          1024,
+       .fifo_size =            0,
+};
+
+static void loopback_runtime_free(struct snd_pcm_runtime *runtime)
+{
+       struct loopback_pcm *dpcm = runtime->private_data;
+       kfree(dpcm);
+}
+
+static int loopback_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params)
+{
+       return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+}
+
+static int loopback_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct loopback_pcm *dpcm = runtime->private_data;
+       struct loopback_cable *cable = dpcm->cable;
+
+       mutex_lock(&dpcm->loopback->cable_lock);
+       cable->valid &= ~(1 << substream->stream);
+       mutex_unlock(&dpcm->loopback->cable_lock);
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static unsigned int get_cable_index(struct snd_pcm_substream *substream)
+{
+       if (!substream->pcm->device)
+               return substream->stream;
+       else
+               return !substream->stream;
+}
+
+static int rule_format(struct snd_pcm_hw_params *params,
+                      struct snd_pcm_hw_rule *rule)
+{
+
+       struct snd_pcm_hardware *hw = rule->private;
+       struct snd_mask *maskp = hw_param_mask(params, rule->var);
+
+       maskp->bits[0] &= (u_int32_t)hw->formats;
+       maskp->bits[1] &= (u_int32_t)(hw->formats >> 32);
+       memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */
+       if (! maskp->bits[0] && ! maskp->bits[1])
+               return -EINVAL;
+       return 0;
+}
+
+static int rule_rate(struct snd_pcm_hw_params *params,
+                    struct snd_pcm_hw_rule *rule)
+{
+       struct snd_pcm_hardware *hw = rule->private;
+       struct snd_interval t;
+
+        t.min = hw->rate_min;
+        t.max = hw->rate_max;
+        t.openmin = t.openmax = 0;
+        t.integer = 0;
+       return snd_interval_refine(hw_param_interval(params, rule->var), &t);
+}
+
+static int rule_channels(struct snd_pcm_hw_params *params,
+                        struct snd_pcm_hw_rule *rule)
+{
+       struct snd_pcm_hardware *hw = rule->private;
+       struct snd_interval t;
+
+        t.min = hw->channels_min;
+        t.max = hw->channels_max;
+        t.openmin = t.openmax = 0;
+        t.integer = 0;
+       return snd_interval_refine(hw_param_interval(params, rule->var), &t);
+}
+
+static int loopback_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct loopback *loopback = substream->private_data;
+       struct loopback_pcm *dpcm;
+       struct loopback_cable *cable;
+       int err = 0;
+       int dev = get_cable_index(substream);
+
+       mutex_lock(&loopback->cable_lock);
+       dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
+       if (!dpcm) {
+               err = -ENOMEM;
+               goto unlock;
+       }
+       dpcm->loopback = loopback;
+       dpcm->substream = substream;
+       setup_timer(&dpcm->timer, loopback_timer_function,
+                   (unsigned long)dpcm);
+
+       cable = loopback->cables[substream->number][dev];
+       if (!cable) {
+               cable = kzalloc(sizeof(*cable), GFP_KERNEL);
+               if (!cable) {
+                       kfree(dpcm);
+                       err = -ENOMEM;
+                       goto unlock;
+               }
+               spin_lock_init(&cable->lock);
+               cable->hw = loopback_pcm_hardware;
+               loopback->cables[substream->number][dev] = cable;
+       }
+       dpcm->cable = cable;
+       cable->streams[substream->stream] = dpcm;
+
+       snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+
+       /* use dynamic rules based on actual runtime->hw values */
+       /* note that the default rules created in the PCM midlevel code */
+       /* are cached -> they do not reflect the actual state */
+       err = snd_pcm_hw_rule_add(runtime, 0,
+                                 SNDRV_PCM_HW_PARAM_FORMAT,
+                                 rule_format, &runtime->hw,
+                                 SNDRV_PCM_HW_PARAM_FORMAT, -1);
+       if (err < 0)
+               goto unlock;
+       err = snd_pcm_hw_rule_add(runtime, 0,
+                                 SNDRV_PCM_HW_PARAM_RATE,
+                                 rule_rate, &runtime->hw,
+                                 SNDRV_PCM_HW_PARAM_RATE, -1);
+       if (err < 0)
+               goto unlock;
+       err = snd_pcm_hw_rule_add(runtime, 0,
+                                 SNDRV_PCM_HW_PARAM_CHANNELS,
+                                 rule_channels, &runtime->hw,
+                                 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+       if (err < 0)
+               goto unlock;
+
+       runtime->private_data = dpcm;
+       runtime->private_free = loopback_runtime_free;
+       if (get_notify(dpcm))
+               runtime->hw = loopback_pcm_hardware;
+       else
+               runtime->hw = cable->hw;
+ unlock:
+       mutex_unlock(&loopback->cable_lock);
+       return err;
+}
+
+static int loopback_close(struct snd_pcm_substream *substream)
+{
+       struct loopback *loopback = substream->private_data;
+       struct loopback_pcm *dpcm = substream->runtime->private_data;
+       struct loopback_cable *cable;
+       int dev = get_cable_index(substream);
+
+       loopback_timer_stop(dpcm);
+       mutex_lock(&loopback->cable_lock);
+       cable = loopback->cables[substream->number][dev];
+       if (cable->streams[!substream->stream]) {
+               /* other stream is still alive */
+               cable->streams[substream->stream] = NULL;
+       } else {
+               /* free the cable */
+               loopback->cables[substream->number][dev] = NULL;
+               kfree(cable);
+       }
+       mutex_unlock(&loopback->cable_lock);
+       return 0;
+}
+
+static struct snd_pcm_ops loopback_playback_ops = {
+       .open =         loopback_open,
+       .close =        loopback_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    loopback_hw_params,
+       .hw_free =      loopback_hw_free,
+       .prepare =      loopback_prepare,
+       .trigger =      loopback_trigger,
+       .pointer =      loopback_pointer,
+};
+
+static struct snd_pcm_ops loopback_capture_ops = {
+       .open =         loopback_open,
+       .close =        loopback_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    loopback_hw_params,
+       .hw_free =      loopback_hw_free,
+       .prepare =      loopback_prepare,
+       .trigger =      loopback_trigger,
+       .pointer =      loopback_pointer,
+};
+
+static int __devinit loopback_pcm_new(struct loopback *loopback,
+                                     int device, int substreams)
+{
+       struct snd_pcm *pcm;
+       int err;
+
+       err = snd_pcm_new(loopback->card, "Loopback PCM", device,
+                         substreams, substreams, &pcm);
+       if (err < 0)
+               return err;
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &loopback_playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &loopback_capture_ops);
+
+       pcm->private_data = loopback;
+       pcm->info_flags = 0;
+       strcpy(pcm->name, "Loopback PCM");
+
+       loopback->pcm[device] = pcm;
+
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+                       snd_dma_continuous_data(GFP_KERNEL),
+                       0, 2 * 1024 * 1024);
+       return 0;
+}
+
+static int loopback_rate_shift_info(struct snd_kcontrol *kcontrol,   
+                                   struct snd_ctl_elem_info *uinfo) 
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 80000;
+       uinfo->value.integer.max = 120000;
+       uinfo->value.integer.step = 1;
+       return 0;
+}                                  
+
+static int loopback_rate_shift_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+       
+       ucontrol->value.integer.value[0] =
+               loopback->setup[kcontrol->id.subdevice]
+                              [kcontrol->id.device].rate_shift;
+       return 0;
+}
+
+static int loopback_rate_shift_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+       unsigned int val;
+       int change = 0;
+
+       val = ucontrol->value.integer.value[0];
+       if (val < 80000)
+               val = 80000;
+       if (val > 120000)
+               val = 120000;   
+       mutex_lock(&loopback->cable_lock);
+       if (val != loopback->setup[kcontrol->id.subdevice]
+                                 [kcontrol->id.device].rate_shift) {
+               loopback->setup[kcontrol->id.subdevice]
+                              [kcontrol->id.device].rate_shift = val;
+               change = 1;
+       }
+       mutex_unlock(&loopback->cable_lock);
+       return change;
+}
+
+static int loopback_notify_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+       
+       ucontrol->value.integer.value[0] =
+               loopback->setup[kcontrol->id.subdevice]
+                              [kcontrol->id.device].notify;
+       return 0;
+}
+
+static int loopback_notify_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+       unsigned int val;
+       int change = 0;
+
+       val = ucontrol->value.integer.value[0] ? 1 : 0;
+       if (val != loopback->setup[kcontrol->id.subdevice]
+                               [kcontrol->id.device].notify) {
+               loopback->setup[kcontrol->id.subdevice]
+                       [kcontrol->id.device].notify = val;
+               change = 1;
+       }
+       return change;
+}
+
+static int loopback_active_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+       struct loopback_cable *cable = loopback->cables
+                       [kcontrol->id.subdevice][kcontrol->id.device ^ 1];
+       unsigned int val = 0;
+
+       if (cable != NULL)
+               val = (cable->running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ?
+                                                                       1 : 0;
+       ucontrol->value.integer.value[0] = val;
+       return 0;
+}
+
+static int loopback_format_info(struct snd_kcontrol *kcontrol,   
+                               struct snd_ctl_elem_info *uinfo) 
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = SNDRV_PCM_FORMAT_LAST;
+       uinfo->value.integer.step = 1;
+       return 0;
+}                                  
+
+static int loopback_format_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+       
+       ucontrol->value.integer.value[0] =
+               loopback->setup[kcontrol->id.subdevice]
+                              [kcontrol->id.device].format;
+       return 0;
+}
+
+static int loopback_rate_info(struct snd_kcontrol *kcontrol,   
+                             struct snd_ctl_elem_info *uinfo) 
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 192000;
+       uinfo->value.integer.step = 1;
+       return 0;
+}                                  
+
+static int loopback_rate_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+       
+       ucontrol->value.integer.value[0] =
+               loopback->setup[kcontrol->id.subdevice]
+                              [kcontrol->id.device].rate;
+       return 0;
+}
+
+static int loopback_channels_info(struct snd_kcontrol *kcontrol,   
+                                 struct snd_ctl_elem_info *uinfo) 
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 1;
+       uinfo->value.integer.max = 1024;
+       uinfo->value.integer.step = 1;
+       return 0;
+}                                  
+
+static int loopback_channels_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct loopback *loopback = snd_kcontrol_chip(kcontrol);
+       
+       ucontrol->value.integer.value[0] =
+               loopback->setup[kcontrol->id.subdevice]
+                              [kcontrol->id.device].channels;
+       return 0;
+}
+
+static struct snd_kcontrol_new loopback_controls[]  __devinitdata = {
+{
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "PCM Rate Shift 100000",
+       .info =         loopback_rate_shift_info,
+       .get =          loopback_rate_shift_get,
+       .put =          loopback_rate_shift_put,
+},
+{
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "PCM Notify",
+       .info =         snd_ctl_boolean_mono_info,
+       .get =          loopback_notify_get,
+       .put =          loopback_notify_put,
+},
+#define ACTIVE_IDX 2
+{
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "PCM Slave Active",
+       .info =         snd_ctl_boolean_mono_info,
+       .get =          loopback_active_get,
+},
+#define FORMAT_IDX 3
+{
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "PCM Slave Format",
+       .info =         loopback_format_info,
+       .get =          loopback_format_get
+},
+#define RATE_IDX 4
+{
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "PCM Slave Rate",
+       .info =         loopback_rate_info,
+       .get =          loopback_rate_get
+},
+#define CHANNELS_IDX 5
+{
+       .access =       SNDRV_CTL_ELEM_ACCESS_READ,
+       .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
+       .name =         "PCM Slave Channels",
+       .info =         loopback_channels_info,
+       .get =          loopback_channels_get
+}
+};
+
+static int __devinit loopback_mixer_new(struct loopback *loopback, int notify)
+{
+       struct snd_card *card = loopback->card;
+       struct snd_pcm *pcm;
+       struct snd_kcontrol *kctl;
+       struct loopback_setup *setup;
+       int err, dev, substr, substr_count, idx;
+
+       strcpy(card->mixername, "Loopback Mixer");
+       for (dev = 0; dev < 2; dev++) {
+               pcm = loopback->pcm[dev];
+               substr_count =
+                   pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count;
+               for (substr = 0; substr < substr_count; substr++) {
+                       setup = &loopback->setup[substr][dev];
+                       setup->notify = notify;
+                       setup->rate_shift = NO_PITCH;
+                       setup->format = SNDRV_PCM_FORMAT_S16_LE;
+                       setup->rate = 48000;
+                       setup->channels = 2;
+                       for (idx = 0; idx < ARRAY_SIZE(loopback_controls);
+                                                                       idx++) {
+                               kctl = snd_ctl_new1(&loopback_controls[idx],
+                                                   loopback);
+                               if (!kctl)
+                                       return -ENOMEM;
+                               kctl->id.device = dev;
+                               kctl->id.subdevice = substr;
+                               switch (idx) {
+                               case ACTIVE_IDX:
+                                       setup->active_id = kctl->id;
+                                       break;
+                               case FORMAT_IDX:
+                                       setup->format_id = kctl->id;
+                                       break;
+                               case RATE_IDX:
+                                       setup->rate_id = kctl->id;
+                                       break;
+                               case CHANNELS_IDX:
+                                       setup->channels_id = kctl->id;
+                                       break;
+                               default:
+                                       break;
+                               }
+                               err = snd_ctl_add(card, kctl);
+                               if (err < 0)
+                                       return err;
+                       }
+               }
+       }
+       return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+
+static void print_dpcm_info(struct snd_info_buffer *buffer,
+                           struct loopback_pcm *dpcm,
+                           const char *id)
+{
+       snd_iprintf(buffer, "  %s\n", id);
+       if (dpcm == NULL) {
+               snd_iprintf(buffer, "    inactive\n");
+               return;
+       }
+       snd_iprintf(buffer, "    buffer_size:\t%u\n", dpcm->pcm_buffer_size);
+       snd_iprintf(buffer, "    buffer_pos:\t\t%u\n", dpcm->buf_pos);
+       snd_iprintf(buffer, "    silent_size:\t%u\n", dpcm->silent_size);
+       snd_iprintf(buffer, "    period_size:\t%u\n", dpcm->pcm_period_size);
+       snd_iprintf(buffer, "    bytes_per_sec:\t%u\n", dpcm->pcm_bps);
+       snd_iprintf(buffer, "    sample_align:\t%u\n", dpcm->pcm_salign);
+       snd_iprintf(buffer, "    rate_shift:\t\t%u\n", dpcm->pcm_rate_shift);
+       snd_iprintf(buffer, "    update_pending:\t%u\n",
+                                               dpcm->period_update_pending);
+       snd_iprintf(buffer, "    irq_pos:\t\t%u\n", dpcm->irq_pos);
+       snd_iprintf(buffer, "    period_frac:\t%u\n", dpcm->period_size_frac);
+       snd_iprintf(buffer, "    last_jiffies:\t%lu (%lu)\n",
+                                       dpcm->last_jiffies, jiffies);
+       snd_iprintf(buffer, "    timer_expires:\t%lu\n", dpcm->timer.expires);
+}
+
+static void print_substream_info(struct snd_info_buffer *buffer,
+                                struct loopback *loopback,
+                                int sub,
+                                int num)
+{
+       struct loopback_cable *cable = loopback->cables[sub][num];
+
+       snd_iprintf(buffer, "Cable %i substream %i:\n", num, sub);
+       if (cable == NULL) {
+               snd_iprintf(buffer, "  inactive\n");
+               return;
+       }
+       snd_iprintf(buffer, "  valid: %u\n", cable->valid);
+       snd_iprintf(buffer, "  running: %u\n", cable->running);
+       snd_iprintf(buffer, "  pause: %u\n", cable->pause);
+       print_dpcm_info(buffer, cable->streams[0], "Playback");
+       print_dpcm_info(buffer, cable->streams[1], "Capture");
+}
+
+static void print_cable_info(struct snd_info_entry *entry,
+                            struct snd_info_buffer *buffer)
+{
+       struct loopback *loopback = entry->private_data;
+       int sub, num;
+
+       mutex_lock(&loopback->cable_lock);
+       num = entry->name[strlen(entry->name)-1];
+       num = num == '0' ? 0 : 1;
+       for (sub = 0; sub < MAX_PCM_SUBSTREAMS; sub++)
+               print_substream_info(buffer, loopback, sub, num);
+       mutex_unlock(&loopback->cable_lock);
+}
+
+static int __devinit loopback_proc_new(struct loopback *loopback, int cidx)
+{
+       char name[32];
+       struct snd_info_entry *entry;
+       int err;
+
+       snprintf(name, sizeof(name), "cable#%d", cidx);
+       err = snd_card_proc_new(loopback->card, name, &entry);
+       if (err < 0)
+               return err;
+
+       snd_info_set_text_ops(entry, loopback, print_cable_info);
+       return 0;
+}
+
+#else /* !CONFIG_PROC_FS */
+
+#define loopback_proc_new(loopback, cidx) do { } while (0)
+
+#endif
+
+static int __devinit loopback_probe(struct platform_device *devptr)
+{
+       struct snd_card *card;
+       struct loopback *loopback;
+       int dev = devptr->id;
+       int err;
+
+       err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+                             sizeof(struct loopback), &card);
+       if (err < 0)
+               return err;
+       loopback = card->private_data;
+
+       if (pcm_substreams[dev] < 1)
+               pcm_substreams[dev] = 1;
+       if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS)
+               pcm_substreams[dev] = MAX_PCM_SUBSTREAMS;
+       
+       loopback->card = card;
+       mutex_init(&loopback->cable_lock);
+
+       err = loopback_pcm_new(loopback, 0, pcm_substreams[dev]);
+       if (err < 0)
+               goto __nodev;
+       err = loopback_pcm_new(loopback, 1, pcm_substreams[dev]);
+       if (err < 0)
+               goto __nodev;
+       err = loopback_mixer_new(loopback, pcm_notify[dev] ? 1 : 0);
+       if (err < 0)
+               goto __nodev;
+       loopback_proc_new(loopback, 0);
+       loopback_proc_new(loopback, 1);
+       strcpy(card->driver, "Loopback");
+       strcpy(card->shortname, "Loopback");
+       sprintf(card->longname, "Loopback %i", dev + 1);
+       err = snd_card_register(card);
+       if (!err) {
+               platform_set_drvdata(devptr, card);
+               return 0;
+       }
+      __nodev:
+       snd_card_free(card);
+       return err;
+}
+
+static int __devexit loopback_remove(struct platform_device *devptr)
+{
+       snd_card_free(platform_get_drvdata(devptr));
+       platform_set_drvdata(devptr, NULL);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int loopback_suspend(struct platform_device *pdev,
+                               pm_message_t state)
+{
+       struct snd_card *card = platform_get_drvdata(pdev);
+       struct loopback *loopback = card->private_data;
+
+       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+
+       snd_pcm_suspend_all(loopback->pcm[0]);
+       snd_pcm_suspend_all(loopback->pcm[1]);
+       return 0;
+}
+       
+static int loopback_resume(struct platform_device *pdev)
+{
+       struct snd_card *card = platform_get_drvdata(pdev);
+
+       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+       return 0;
+}
+#endif
+
+#define SND_LOOPBACK_DRIVER    "snd_aloop"
+
+static struct platform_driver loopback_driver = {
+       .probe          = loopback_probe,
+       .remove         = __devexit_p(loopback_remove),
+#ifdef CONFIG_PM
+       .suspend        = loopback_suspend,
+       .resume         = loopback_resume,
+#endif
+       .driver         = {
+               .name   = SND_LOOPBACK_DRIVER
+       },
+};
+
+static void loopback_unregister_all(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(devices); ++i)
+               platform_device_unregister(devices[i]);
+       platform_driver_unregister(&loopback_driver);
+}
+
+static int __init alsa_card_loopback_init(void)
+{
+       int i, err, cards;
+
+       err = platform_driver_register(&loopback_driver);
+       if (err < 0)
+               return err;
+
+
+       cards = 0;
+       for (i = 0; i < SNDRV_CARDS; i++) {
+               struct platform_device *device;
+               if (!enable[i])
+                       continue;
+               device = platform_device_register_simple(SND_LOOPBACK_DRIVER,
+                                                        i, NULL, 0);
+               if (IS_ERR(device))
+                       continue;
+               if (!platform_get_drvdata(device)) {
+                       platform_device_unregister(device);
+                       continue;
+               }
+               devices[i] = device;
+               cards++;
+       }
+       if (!cards) {
+#ifdef MODULE
+               printk(KERN_ERR "aloop: No loopback enabled\n");
+#endif
+               loopback_unregister_all();
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static void __exit alsa_card_loopback_exit(void)
+{
+       loopback_unregister_all();
+}
+
+module_init(alsa_card_loopback_init)
+module_exit(alsa_card_loopback_exit)
index 0e631c3221e3b72f46b2b1b11569d5931ead1097..f4cd49336f336866e36b6814206fdaf0ff9da226 100644 (file)
@@ -94,7 +94,7 @@ static int __devinit snd_virmidi_probe(struct platform_device *devptr)
                              sizeof(struct snd_card_virmidi), &card);
        if (err < 0)
                return err;
-       vmidi = (struct snd_card_virmidi *)card->private_data;
+       vmidi = card->private_data;
        vmidi->card = card;
 
        if (midi_devs[dev] > MAX_MIDI_DEVICES) {
index 42d7844ecd0bfa66ddf3db96527ccc18c79f7485..57ccba88700d68bacc493d01d030175158f40196 100644 (file)
@@ -878,7 +878,7 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
 static void proc_regs_read(struct snd_info_entry *entry,
                struct snd_info_buffer *buffer)
 {
-       struct snd_akm4xxx *ak = (struct snd_akm4xxx *)entry->private_data;
+       struct snd_akm4xxx *ak = entry->private_data;
        int reg, val, chip;
        for (chip = 0; chip < ak->num_chips; chip++) {
                for (reg = 0; reg < ak->total_regs; reg++) {
index c6990c6807969ea948dcd1834dc0fb13f3b97ad2..52064cfa91f3f9d1fa82612b3d6ac50dac51b2a4 100644 (file)
@@ -77,6 +77,32 @@ config SND_ALS100
          To compile this driver as a module, choose M here: the module
          will be called snd-als100.
 
+config SND_AZT1605
+       tristate "Aztech AZT1605 Driver"
+       depends on SND
+       select SND_WSS_LIB
+       select SND_MPU401_UART
+       select SND_OPL3_LIB
+       help
+         Say Y here to include support for Aztech Sound Galaxy cards
+         based on the AZT1605 chipset.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-azt1605.
+
+config SND_AZT2316
+       tristate "Aztech AZT2316 Driver"
+       depends on SND
+       select SND_WSS_LIB
+       select SND_MPU401_UART
+       select SND_OPL3_LIB
+       help
+         Say Y here to include support for Aztech Sound Galaxy cards
+         based on the AZT2316 chipset.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-azt2316.
+
 config SND_AZT2320
        tristate "Aztech Systems AZT2320"
        depends on PNP
@@ -351,16 +377,6 @@ config SND_SB16_CSP
          coprocessor can do variable tasks like various compression and
          decompression algorithms.
 
-config SND_SGALAXY
-       tristate "Aztech Sound Galaxy"
-       select SND_WSS_LIB
-       help
-         Say Y here to include support for Aztech Sound Galaxy
-         soundcards.
-
-         To compile this driver as a module, choose M here: the module
-         will be called snd-sgalaxy.
-
 config SND_SSCAPE
        tristate "Ensoniq SoundScape driver"
        select SND_MPU401_UART
index c73d30c4f46289c982ff793f42f6b3a6828052b8..8d781e419e2ece74797733a4eea86a14ba8ba5d6 100644 (file)
@@ -10,7 +10,6 @@ snd-cmi8330-objs := cmi8330.o
 snd-es18xx-objs := es18xx.o
 snd-opl3sa2-objs := opl3sa2.o
 snd-sc6000-objs := sc6000.o
-snd-sgalaxy-objs := sgalaxy.o
 snd-sscape-objs := sscape.o
 
 # Toplevel Module Dependency
@@ -21,8 +20,7 @@ obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o
 obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o
 obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o
 obj-$(CONFIG_SND_SC6000) += snd-sc6000.o
-obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o
 obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o
 
-obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ msnd/ opti9xx/ \
+obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ galaxy/ gus/ msnd/ opti9xx/ \
                     sb/ wavefront/ wss/
index bbcbf92a8ebea1cb11aa8d164f7651d6ab87d11d..3cb75bc9769927a303974783c7667b728eed798b 100644 (file)
@@ -162,7 +162,7 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
                                sizeof(struct snd_card_ad1816a), &card);
        if (error < 0)
                return error;
-       acard = (struct snd_card_ad1816a *)card->private_data;
+       acard = card->private_data;
 
        if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) {
                snd_card_free(card);
index f7aa637b0d181497fccdf1f48ff7f352b68ad5e2..aac8dc15c2fe6eaf0329b780545068789d38ce6c 100644 (file)
@@ -188,7 +188,7 @@ static int __devinit snd_card_azt2320_probe(int dev,
                                sizeof(struct snd_card_azt2320), &card);
        if (error < 0)
                return error;
-       acard = (struct snd_card_azt2320 *)card->private_data;
+       acard = card->private_data;
 
        if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) {
                snd_card_free(card);
diff --git a/sound/isa/galaxy/Makefile b/sound/isa/galaxy/Makefile
new file mode 100644 (file)
index 0000000..e307066
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for ALSA
+# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
+#
+
+snd-azt1605-objs := azt1605.o
+snd-azt2316-objs := azt2316.o
+
+obj-$(CONFIG_SND_AZT1605) += snd-azt1605.o
+obj-$(CONFIG_SND_AZT2316) += snd-azt2316.o
diff --git a/sound/isa/galaxy/azt1605.c b/sound/isa/galaxy/azt1605.c
new file mode 100644 (file)
index 0000000..9a97643
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Aztech AZT1605 Driver
+ * Copyright (C) 2007,2010  Rene Herman
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#define AZT1605
+
+#define CRD_NAME "Aztech AZT1605"
+#define DRV_NAME "AZT1605"
+#define DEV_NAME "azt1605"
+
+#define GALAXY_DSP_MAJOR               2
+#define GALAXY_DSP_MINOR               1
+
+#define GALAXY_CONFIG_SIZE             3
+
+/*
+ * 24-bit config register
+ */
+
+#define GALAXY_CONFIG_SBA_220          (0 << 0)
+#define GALAXY_CONFIG_SBA_240          (1 << 0)
+#define GALAXY_CONFIG_SBA_260          (2 << 0)
+#define GALAXY_CONFIG_SBA_280          (3 << 0)
+#define GALAXY_CONFIG_SBA_MASK         GALAXY_CONFIG_SBA_280
+
+#define GALAXY_CONFIG_MPUA_300         (0 << 2)
+#define GALAXY_CONFIG_MPUA_330         (1 << 2)
+
+#define GALAXY_CONFIG_MPU_ENABLE       (1 << 3)
+
+#define GALAXY_CONFIG_GAME_ENABLE      (1 << 4)
+
+#define GALAXY_CONFIG_CD_PANASONIC     (1 << 5)
+#define GALAXY_CONFIG_CD_MITSUMI       (1 << 6)
+#define GALAXY_CONFIG_CD_MASK          (\
+       GALAXY_CONFIG_CD_PANASONIC | GALAXY_CONFIG_CD_MITSUMI)
+
+#define GALAXY_CONFIG_UNUSED           (1 << 7)
+#define GALAXY_CONFIG_UNUSED_MASK      GALAXY_CONFIG_UNUSED
+
+#define GALAXY_CONFIG_SBIRQ_2          (1 << 8)
+#define GALAXY_CONFIG_SBIRQ_3          (1 << 9)
+#define GALAXY_CONFIG_SBIRQ_5          (1 << 10)
+#define GALAXY_CONFIG_SBIRQ_7          (1 << 11)
+
+#define GALAXY_CONFIG_MPUIRQ_2         (1 << 12)
+#define GALAXY_CONFIG_MPUIRQ_3         (1 << 13)
+#define GALAXY_CONFIG_MPUIRQ_5         (1 << 14)
+#define GALAXY_CONFIG_MPUIRQ_7         (1 << 15)
+
+#define GALAXY_CONFIG_WSSA_530         (0 << 16)
+#define GALAXY_CONFIG_WSSA_604         (1 << 16)
+#define GALAXY_CONFIG_WSSA_E80         (2 << 16)
+#define GALAXY_CONFIG_WSSA_F40         (3 << 16)
+
+#define GALAXY_CONFIG_WSS_ENABLE       (1 << 18)
+
+#define GALAXY_CONFIG_CDIRQ_11         (1 << 19)
+#define GALAXY_CONFIG_CDIRQ_12         (1 << 20)
+#define GALAXY_CONFIG_CDIRQ_15         (1 << 21)
+#define GALAXY_CONFIG_CDIRQ_MASK       (\
+       GALAXY_CONFIG_CDIRQ_11 | GALAXY_CONFIG_CDIRQ_12 |\
+       GALAXY_CONFIG_CDIRQ_15)
+
+#define GALAXY_CONFIG_CDDMA_DISABLE    (0 << 22)
+#define GALAXY_CONFIG_CDDMA_0          (1 << 22)
+#define GALAXY_CONFIG_CDDMA_1          (2 << 22)
+#define GALAXY_CONFIG_CDDMA_3          (3 << 22)
+#define GALAXY_CONFIG_CDDMA_MASK       GALAXY_CONFIG_CDDMA_3
+
+#define GALAXY_CONFIG_MASK             (\
+       GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CD_MASK |\
+       GALAXY_CONFIG_UNUSED_MASK | GALAXY_CONFIG_CDIRQ_MASK |\
+       GALAXY_CONFIG_CDDMA_MASK)
+
+#include "galaxy.c"
diff --git a/sound/isa/galaxy/azt2316.c b/sound/isa/galaxy/azt2316.c
new file mode 100644 (file)
index 0000000..1894411
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Aztech AZT2316 Driver
+ * Copyright (C) 2007,2010  Rene Herman
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#define AZT2316
+
+#define CRD_NAME "Aztech AZT2316"
+#define DRV_NAME "AZT2316"
+#define DEV_NAME "azt2316"
+
+#define GALAXY_DSP_MAJOR               3
+#define GALAXY_DSP_MINOR               1
+
+#define GALAXY_CONFIG_SIZE             4
+
+/*
+ * 32-bit config register
+ */
+
+#define GALAXY_CONFIG_SBA_220          (0 << 0)
+#define GALAXY_CONFIG_SBA_240          (1 << 0)
+#define GALAXY_CONFIG_SBA_260          (2 << 0)
+#define GALAXY_CONFIG_SBA_280          (3 << 0)
+#define GALAXY_CONFIG_SBA_MASK         GALAXY_CONFIG_SBA_280
+
+#define GALAXY_CONFIG_SBIRQ_2          (1 << 2)
+#define GALAXY_CONFIG_SBIRQ_5          (1 << 3)
+#define GALAXY_CONFIG_SBIRQ_7          (1 << 4)
+#define GALAXY_CONFIG_SBIRQ_10         (1 << 5)
+
+#define GALAXY_CONFIG_SBDMA_DISABLE    (0 << 6)
+#define GALAXY_CONFIG_SBDMA_0          (1 << 6)
+#define GALAXY_CONFIG_SBDMA_1          (2 << 6)
+#define GALAXY_CONFIG_SBDMA_3          (3 << 6)
+
+#define GALAXY_CONFIG_WSSA_530         (0 << 8)
+#define GALAXY_CONFIG_WSSA_604         (1 << 8)
+#define GALAXY_CONFIG_WSSA_E80         (2 << 8)
+#define GALAXY_CONFIG_WSSA_F40         (3 << 8)
+
+#define GALAXY_CONFIG_WSS_ENABLE       (1 << 10)
+
+#define GALAXY_CONFIG_GAME_ENABLE      (1 << 11)
+
+#define GALAXY_CONFIG_MPUA_300         (0 << 12)
+#define GALAXY_CONFIG_MPUA_330         (1 << 12)
+
+#define GALAXY_CONFIG_MPU_ENABLE       (1 << 13)
+
+#define GALAXY_CONFIG_CDA_310          (0 << 14)
+#define GALAXY_CONFIG_CDA_320          (1 << 14)
+#define GALAXY_CONFIG_CDA_340          (2 << 14)
+#define GALAXY_CONFIG_CDA_350          (3 << 14)
+#define GALAXY_CONFIG_CDA_MASK         GALAXY_CONFIG_CDA_350
+
+#define GALAXY_CONFIG_CD_DISABLE       (0 << 16)
+#define GALAXY_CONFIG_CD_PANASONIC     (1 << 16)
+#define GALAXY_CONFIG_CD_SONY          (2 << 16)
+#define GALAXY_CONFIG_CD_MITSUMI       (3 << 16)
+#define GALAXY_CONFIG_CD_AZTECH                (4 << 16)
+#define GALAXY_CONFIG_CD_UNUSED_5      (5 << 16)
+#define GALAXY_CONFIG_CD_UNUSED_6      (6 << 16)
+#define GALAXY_CONFIG_CD_UNUSED_7      (7 << 16)
+#define GALAXY_CONFIG_CD_MASK          GALAXY_CONFIG_CD_UNUSED_7
+
+#define GALAXY_CONFIG_CDDMA8_DISABLE   (0 << 20)
+#define GALAXY_CONFIG_CDDMA8_0         (1 << 20)
+#define GALAXY_CONFIG_CDDMA8_1         (2 << 20)
+#define GALAXY_CONFIG_CDDMA8_3         (3 << 20)
+#define GALAXY_CONFIG_CDDMA8_MASK      GALAXY_CONFIG_CDDMA8_3
+
+#define GALAXY_CONFIG_CDDMA16_DISABLE  (0 << 22)
+#define GALAXY_CONFIG_CDDMA16_5                (1 << 22)
+#define GALAXY_CONFIG_CDDMA16_6                (2 << 22)
+#define GALAXY_CONFIG_CDDMA16_7                (3 << 22)
+#define GALAXY_CONFIG_CDDMA16_MASK     GALAXY_CONFIG_CDDMA16_7
+
+#define GALAXY_CONFIG_MPUIRQ_2         (1 << 24)
+#define GALAXY_CONFIG_MPUIRQ_5         (1 << 25)
+#define GALAXY_CONFIG_MPUIRQ_7         (1 << 26)
+#define GALAXY_CONFIG_MPUIRQ_10                (1 << 27)
+
+#define GALAXY_CONFIG_CDIRQ_5          (1 << 28)
+#define GALAXY_CONFIG_CDIRQ_11         (1 << 29)
+#define GALAXY_CONFIG_CDIRQ_12         (1 << 30)
+#define GALAXY_CONFIG_CDIRQ_15         (1 << 31)
+#define GALAXY_CONFIG_CDIRQ_MASK       (\
+       GALAXY_CONFIG_CDIRQ_5 | GALAXY_CONFIG_CDIRQ_11 |\
+       GALAXY_CONFIG_CDIRQ_12 | GALAXY_CONFIG_CDIRQ_15)
+
+#define GALAXY_CONFIG_MASK             (\
+       GALAXY_CONFIG_SBA_MASK | GALAXY_CONFIG_CDA_MASK |\
+       GALAXY_CONFIG_CD_MASK | GALAXY_CONFIG_CDDMA16_MASK |\
+       GALAXY_CONFIG_CDDMA8_MASK | GALAXY_CONFIG_CDIRQ_MASK)
+
+#include "galaxy.c"
diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c
new file mode 100644 (file)
index 0000000..ee54df0
--- /dev/null
@@ -0,0 +1,652 @@
+/*
+ * Aztech AZT1605/AZT2316 Driver
+ * Copyright (C) 2007,2010  Rene Herman
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/isa.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <asm/processor.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/wss.h>
+#include <sound/mpu401.h>
+#include <sound/opl3.h>
+
+MODULE_DESCRIPTION(CRD_NAME);
+MODULE_AUTHOR("Rene Herman");
+MODULE_LICENSE("GPL");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
+
+static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
+static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+
+module_param_array(port, long, NULL, 0444);
+MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
+module_param_array(wss_port, long, NULL, 0444);
+MODULE_PARM_DESC(wss_port, "WSS port # for " CRD_NAME " driver.");
+module_param_array(mpu_port, long, NULL, 0444);
+MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver.");
+module_param_array(fm_port, long, NULL, 0444);
+MODULE_PARM_DESC(fm_port, "FM port # for " CRD_NAME " driver.");
+module_param_array(irq, int, NULL, 0444);
+MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
+module_param_array(mpu_irq, int, NULL, 0444);
+MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
+module_param_array(dma1, int, NULL, 0444);
+MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver.");
+module_param_array(dma2, int, NULL, 0444);
+MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver.");
+
+/*
+ * Generic SB DSP support routines
+ */
+
+#define DSP_PORT_RESET         0x6
+#define DSP_PORT_READ          0xa
+#define DSP_PORT_COMMAND       0xc
+#define DSP_PORT_STATUS                0xc
+#define DSP_PORT_DATA_AVAIL    0xe
+
+#define DSP_SIGNATURE          0xaa
+
+#define DSP_COMMAND_GET_VERSION        0xe1
+
+static int __devinit dsp_get_byte(void __iomem *port, u8 *val)
+{
+       int loops = 1000;
+
+       while (!(ioread8(port + DSP_PORT_DATA_AVAIL) & 0x80)) {
+               if (!loops--)
+                       return -EIO;
+               cpu_relax();
+       }
+       *val = ioread8(port + DSP_PORT_READ);
+       return 0;
+}
+
+static int __devinit dsp_reset(void __iomem *port)
+{
+       u8 val;
+
+       iowrite8(1, port + DSP_PORT_RESET);
+       udelay(10);
+       iowrite8(0, port + DSP_PORT_RESET);
+
+       if (dsp_get_byte(port, &val) < 0 || val != DSP_SIGNATURE)
+               return -ENODEV;
+
+       return 0;
+}
+
+static int __devinit dsp_command(void __iomem *port, u8 cmd)
+{
+       int loops = 1000;
+
+       while (ioread8(port + DSP_PORT_STATUS) & 0x80) {
+               if (!loops--)
+                       return -EIO;
+               cpu_relax();
+       }
+       iowrite8(cmd, port + DSP_PORT_COMMAND);
+       return 0;
+}
+
+static int __devinit dsp_get_version(void __iomem *port, u8 *major, u8 *minor)
+{
+       int err;
+
+       err = dsp_command(port, DSP_COMMAND_GET_VERSION);
+       if (err < 0)
+               return err;
+
+       err = dsp_get_byte(port, major);
+       if (err < 0)
+               return err;
+
+       err = dsp_get_byte(port, minor);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+/*
+ * Generic WSS support routines
+ */
+
+#define WSS_CONFIG_DMA_0       (1 << 0)
+#define WSS_CONFIG_DMA_1       (2 << 0)
+#define WSS_CONFIG_DMA_3       (3 << 0)
+#define WSS_CONFIG_DUPLEX      (1 << 2)
+#define WSS_CONFIG_IRQ_7       (1 << 3)
+#define WSS_CONFIG_IRQ_9       (2 << 3)
+#define WSS_CONFIG_IRQ_10      (3 << 3)
+#define WSS_CONFIG_IRQ_11      (4 << 3)
+
+#define WSS_PORT_CONFIG                0
+#define WSS_PORT_SIGNATURE     3
+
+#define WSS_SIGNATURE          4
+
+static int __devinit wss_detect(void __iomem *wss_port)
+{
+       if ((ioread8(wss_port + WSS_PORT_SIGNATURE) & 0x3f) != WSS_SIGNATURE)
+               return -ENODEV;
+
+       return 0;
+}
+
+static void wss_set_config(void __iomem *wss_port, u8 wss_config)
+{
+       iowrite8(wss_config, wss_port + WSS_PORT_CONFIG);
+}
+
+/*
+ * Aztech Sound Galaxy specifics
+ */
+
+#define GALAXY_PORT_CONFIG     1024
+#define CONFIG_PORT_SET                4
+
+#define DSP_COMMAND_GALAXY_8   8
+#define GALAXY_COMMAND_GET_TYPE        5
+
+#define DSP_COMMAND_GALAXY_9   9
+#define GALAXY_COMMAND_WSSMODE 0
+#define GALAXY_COMMAND_SB8MODE 1
+
+#define GALAXY_MODE_WSS                GALAXY_COMMAND_WSSMODE
+#define GALAXY_MODE_SB8                GALAXY_COMMAND_SB8MODE
+
+struct snd_galaxy {
+       void __iomem *port;
+       void __iomem *config_port;
+       void __iomem *wss_port;
+       u32 config;
+       struct resource *res_port;
+       struct resource *res_config_port;
+       struct resource *res_wss_port;
+};
+
+static u32 config[SNDRV_CARDS];
+static u8 wss_config[SNDRV_CARDS];
+
+static int __devinit snd_galaxy_match(struct device *dev, unsigned int n)
+{
+       if (!enable[n])
+               return 0;
+
+       switch (port[n]) {
+       case SNDRV_AUTO_PORT:
+               dev_err(dev, "please specify port\n");
+               return 0;
+       case 0x220:
+               config[n] |= GALAXY_CONFIG_SBA_220;
+               break;
+       case 0x240:
+               config[n] |= GALAXY_CONFIG_SBA_240;
+               break;
+       case 0x260:
+               config[n] |= GALAXY_CONFIG_SBA_260;
+               break;
+       case 0x280:
+               config[n] |= GALAXY_CONFIG_SBA_280;
+               break;
+       default:
+               dev_err(dev, "invalid port %#lx\n", port[n]);
+               return 0;
+       }
+
+       switch (wss_port[n]) {
+       case SNDRV_AUTO_PORT:
+               dev_err(dev,  "please specify wss_port\n");
+               return 0;
+       case 0x530:
+               config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_530;
+               break;
+       case 0x604:
+               config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_604;
+               break;
+       case 0xe80:
+               config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_E80;
+               break;
+       case 0xf40:
+               config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_F40;
+               break;
+       default:
+               dev_err(dev, "invalid WSS port %#lx\n", wss_port[n]);
+               return 0;
+       }
+
+       switch (irq[n]) {
+       case SNDRV_AUTO_IRQ:
+               dev_err(dev,  "please specify irq\n");
+               return 0;
+       case 7:
+               wss_config[n] |= WSS_CONFIG_IRQ_7;
+               break;
+       case 2:
+               irq[n] = 9;
+       case 9:
+               wss_config[n] |= WSS_CONFIG_IRQ_9;
+               break;
+       case 10:
+               wss_config[n] |= WSS_CONFIG_IRQ_10;
+               break;
+       case 11:
+               wss_config[n] |= WSS_CONFIG_IRQ_11;
+               break;
+       default:
+               dev_err(dev, "invalid IRQ %d\n", irq[n]);
+               return 0;
+       }
+
+       switch (dma1[n]) {
+       case SNDRV_AUTO_DMA:
+               dev_err(dev,  "please specify dma1\n");
+               return 0;
+       case 0:
+               wss_config[n] |= WSS_CONFIG_DMA_0;
+               break;
+       case 1:
+               wss_config[n] |= WSS_CONFIG_DMA_1;
+               break;
+       case 3:
+               wss_config[n] |= WSS_CONFIG_DMA_3;
+               break;
+       default:
+               dev_err(dev, "invalid playback DMA %d\n", dma1[n]);
+               return 0;
+       }
+
+       if (dma2[n] == SNDRV_AUTO_DMA || dma2[n] == dma1[n]) {
+               dma2[n] = -1;
+               goto mpu;
+       }
+
+       wss_config[n] |= WSS_CONFIG_DUPLEX;
+       switch (dma2[n]) {
+       case 0:
+               break;
+       case 1:
+               if (dma1[n] == 0)
+                       break;
+       default:
+               dev_err(dev, "invalid capture DMA %d\n", dma2[n]);
+               return 0;
+       }
+
+mpu:
+       switch (mpu_port[n]) {
+       case SNDRV_AUTO_PORT:
+               dev_warn(dev, "mpu_port not specified; not using MPU-401\n");
+               mpu_port[n] = -1;
+               goto fm;
+       case 0x300:
+               config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_300;
+               break;
+       case 0x330:
+               config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_330;
+               break;
+       default:
+               dev_err(dev, "invalid MPU port %#lx\n", mpu_port[n]);
+               return 0;
+       }
+
+       switch (mpu_irq[n]) {
+       case SNDRV_AUTO_IRQ:
+               dev_warn(dev, "mpu_irq not specified: using polling mode\n");
+               mpu_irq[n] = -1;
+               break;
+       case 2:
+               mpu_irq[n] = 9;
+       case 9:
+               config[n] |= GALAXY_CONFIG_MPUIRQ_2;
+               break;
+#ifdef AZT1605
+       case 3:
+               config[n] |= GALAXY_CONFIG_MPUIRQ_3;
+               break;
+#endif
+       case 5:
+               config[n] |= GALAXY_CONFIG_MPUIRQ_5;
+               break;
+       case 7:
+               config[n] |= GALAXY_CONFIG_MPUIRQ_7;
+               break;
+#ifdef AZT2316
+       case 10:
+               config[n] |= GALAXY_CONFIG_MPUIRQ_10;
+               break;
+#endif
+       default:
+               dev_err(dev, "invalid MPU IRQ %d\n", mpu_irq[n]);
+               return 0;
+       }
+
+       if (mpu_irq[n] == irq[n]) {
+               dev_err(dev, "cannot share IRQ between WSS and MPU-401\n");
+               return 0;
+       }
+
+fm:
+       switch (fm_port[n]) {
+       case SNDRV_AUTO_PORT:
+               dev_warn(dev, "fm_port not specified: not using OPL3\n");
+               fm_port[n] = -1;
+               break;
+       case 0x388:
+               break;
+       default:
+               dev_err(dev, "illegal FM port %#lx\n", fm_port[n]);
+               return 0;
+       }
+
+       config[n] |= GALAXY_CONFIG_GAME_ENABLE;
+       return 1;
+}
+
+static int __devinit galaxy_init(struct snd_galaxy *galaxy, u8 *type)
+{
+       u8 major;
+       u8 minor;
+       int err;
+
+       err = dsp_reset(galaxy->port);
+       if (err < 0)
+               return err;
+
+       err = dsp_get_version(galaxy->port, &major, &minor);
+       if (err < 0)
+               return err;
+
+       if (major != GALAXY_DSP_MAJOR || minor != GALAXY_DSP_MINOR)
+               return -ENODEV;
+
+       err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_8);
+       if (err < 0)
+               return err;
+
+       err = dsp_command(galaxy->port, GALAXY_COMMAND_GET_TYPE);
+       if (err < 0)
+               return err;
+
+       err = dsp_get_byte(galaxy->port, type);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int __devinit galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode)
+{
+       int err;
+
+       err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_9);
+       if (err < 0)
+               return err;
+
+       err = dsp_command(galaxy->port, mode);
+       if (err < 0)
+               return err;
+
+#ifdef AZT1605
+       /*
+        * Needed for MPU IRQ on AZT1605, but AZT2316 loses WSS again
+        */
+       err = dsp_reset(galaxy->port);
+       if (err < 0)
+               return err;
+#endif
+
+       return 0;
+}
+
+static void galaxy_set_config(struct snd_galaxy *galaxy, u32 config)
+{
+       u8 tmp = ioread8(galaxy->config_port + CONFIG_PORT_SET);
+       int i;
+
+       iowrite8(tmp | 0x80, galaxy->config_port + CONFIG_PORT_SET);
+       for (i = 0; i < GALAXY_CONFIG_SIZE; i++) {
+               iowrite8(config, galaxy->config_port + i);
+               config >>= 8;
+       }
+       iowrite8(tmp & 0x7f, galaxy->config_port + CONFIG_PORT_SET);
+       msleep(10);
+}
+
+static void __devinit galaxy_config(struct snd_galaxy *galaxy, u32 config)
+{
+       int i;
+
+       for (i = GALAXY_CONFIG_SIZE; i; i--) {
+               u8 tmp = ioread8(galaxy->config_port + i - 1);
+               galaxy->config = (galaxy->config << 8) | tmp;
+       }
+       config |= galaxy->config & GALAXY_CONFIG_MASK;
+       galaxy_set_config(galaxy, config);
+}
+
+static int __devinit galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config)
+{
+       int err;
+
+       err = wss_detect(galaxy->wss_port);
+       if (err < 0)
+               return err;
+
+       wss_set_config(galaxy->wss_port, wss_config);
+
+       err = galaxy_set_mode(galaxy, GALAXY_MODE_WSS);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static void snd_galaxy_free(struct snd_card *card)
+{
+       struct snd_galaxy *galaxy = card->private_data;
+
+       if (galaxy->wss_port) {
+               wss_set_config(galaxy->wss_port, 0);
+               ioport_unmap(galaxy->wss_port);
+               release_and_free_resource(galaxy->res_wss_port);
+       }
+       if (galaxy->config_port) {
+               galaxy_set_config(galaxy, galaxy->config);
+               ioport_unmap(galaxy->config_port);
+               release_and_free_resource(galaxy->res_config_port);
+       }
+       if (galaxy->port) {
+               ioport_unmap(galaxy->port);
+               release_and_free_resource(galaxy->res_port);
+       }
+}
+
+static int __devinit snd_galaxy_probe(struct device *dev, unsigned int n)
+{
+       struct snd_galaxy *galaxy;
+       struct snd_wss *chip;
+       struct snd_card *card;
+       u8 type;
+       int err;
+
+       err = snd_card_create(index[n], id[n], THIS_MODULE, sizeof *galaxy,
+                             &card);
+       if (err < 0)
+               return err;
+
+       snd_card_set_dev(card, dev);
+
+       card->private_free = snd_galaxy_free;
+       galaxy = card->private_data;
+
+       galaxy->res_port = request_region(port[n], 16, DRV_NAME);
+       if (!galaxy->res_port) {
+               dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n],
+                       port[n] + 15);
+               err = -EBUSY;
+               goto error;
+       }
+       galaxy->port = ioport_map(port[n], 16);
+
+       err = galaxy_init(galaxy, &type);
+       if (err < 0) {
+               dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]);
+               goto error;
+       }
+       dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]);
+
+       galaxy->res_config_port = request_region(port[n] + GALAXY_PORT_CONFIG,
+                                                16, DRV_NAME);
+       if (!galaxy->res_config_port) {
+               dev_err(dev, "could not grab ports %#lx-%#lx\n",
+                       port[n] + GALAXY_PORT_CONFIG,
+                       port[n] + GALAXY_PORT_CONFIG + 15);
+               err = -EBUSY;
+               goto error;
+       }
+       galaxy->config_port = ioport_map(port[n] + GALAXY_PORT_CONFIG, 16);
+
+       galaxy_config(galaxy, config[n]);
+
+       galaxy->res_wss_port = request_region(wss_port[n], 4, DRV_NAME);
+       if (!galaxy->res_wss_port)  {
+               dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n],
+                       wss_port[n] + 3);
+               err = -EBUSY;
+               goto error;
+       }
+       galaxy->wss_port = ioport_map(wss_port[n], 4);
+
+       err = galaxy_wss_config(galaxy, wss_config[n]);
+       if (err < 0) {
+               dev_err(dev, "could not configure WSS\n");
+               goto error;
+       }
+
+       strcpy(card->driver, DRV_NAME);
+       strcpy(card->shortname, DRV_NAME);
+       sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d",
+               card->shortname, port[n], wss_port[n], irq[n], dma1[n],
+               dma2[n]);
+
+       err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n],
+                            dma2[n], WSS_HW_DETECT, 0, &chip);
+       if (err < 0)
+               goto error;
+
+       err = snd_wss_pcm(chip, 0, NULL);
+       if (err < 0)
+               goto error;
+
+       err = snd_wss_mixer(chip);
+       if (err < 0)
+               goto error;
+
+       err = snd_wss_timer(chip, 0, NULL);
+       if (err < 0)
+               goto error;
+
+       if (mpu_port[n] >= 0) {
+               err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
+                                         mpu_port[n], 0, mpu_irq[n],
+                                         IRQF_DISABLED, NULL);
+               if (err < 0)
+                       goto error;
+       }
+
+       if (fm_port[n] >= 0) {
+               struct snd_opl3 *opl3;
+
+               err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
+                                     OPL3_HW_AUTO, 0, &opl3);
+               if (err < 0) {
+                       dev_err(dev, "no OPL device at %#lx\n", fm_port[n]);
+                       goto error;
+               }
+               err = snd_opl3_timer_new(opl3, 1, 2);
+               if (err < 0)
+                       goto error;
+
+               err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+               if (err < 0)
+                       goto error;
+       }
+
+       err = snd_card_register(card);
+       if (err < 0)
+               goto error;
+
+       dev_set_drvdata(dev, card);
+       return 0;
+
+error:
+       snd_card_free(card);
+       return err;
+}
+
+static int __devexit snd_galaxy_remove(struct device *dev, unsigned int n)
+{
+       snd_card_free(dev_get_drvdata(dev));
+       dev_set_drvdata(dev, NULL);
+       return 0;
+}
+
+static struct isa_driver snd_galaxy_driver = {
+       .match          = snd_galaxy_match,
+       .probe          = snd_galaxy_probe,
+       .remove         = __devexit_p(snd_galaxy_remove),
+
+       .driver         = {
+               .name   = DEV_NAME
+       }
+};
+
+static int __init alsa_card_galaxy_init(void)
+{
+       return isa_register_driver(&snd_galaxy_driver, SNDRV_CARDS);
+}
+
+static void __exit alsa_card_galaxy_exit(void)
+{
+       isa_unregister_driver(&snd_galaxy_driver);
+}
+
+module_init(alsa_card_galaxy_init);
+module_exit(alsa_card_galaxy_exit);
index f26eac8d8110093aed72bfc51dce0340ca972ee9..3e4a58b72913d613e719a9ccc912d0bf75661a0d 100644 (file)
@@ -191,7 +191,7 @@ static int __devinit snd_gusmax_mixer(struct snd_wss *chip)
 
 static void snd_gusmax_free(struct snd_card *card)
 {
-       struct snd_gusmax *maxcard = (struct snd_gusmax *)card->private_data;
+       struct snd_gusmax *maxcard = card->private_data;
        
        if (maxcard == NULL)
                return;
@@ -219,7 +219,7 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev)
        if (err < 0)
                return err;
        card->private_free = snd_gusmax_free;
-       maxcard = (struct snd_gusmax *)card->private_data;
+       maxcard = card->private_data;
        maxcard->card = card;
        maxcard->irq = -1;
        
index 81284a8fa0ceb56db3fc246638a792fffadba88f..2259e3f726a7c257cf6b51ab728cebf8d9e83a2b 100644 (file)
@@ -72,7 +72,7 @@ static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id)
 
 static void snd_sb8_free(struct snd_card *card)
 {
-       struct snd_sb8 *acard = (struct snd_sb8 *)card->private_data;
+       struct snd_sb8 *acard = card->private_data;
 
        if (acard == NULL)
                return;
diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c
deleted file mode 100644 (file)
index 6fe27b9..0000000
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- *  Driver for Aztech Sound Galaxy cards
- *  Copyright (c) by Christopher Butler <chrisb@sandy.force9.co.uk.
- *
- *  I don't have documentation for this card, I based this driver on the
- *  driver for OSS/Free included in the kernel source (drivers/sound/sgalaxy.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.
- *
- *   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/isa.h>
-#include <linux/delay.h>
-#include <linux/time.h>
-#include <linux/interrupt.h>
-#include <linux/moduleparam.h>
-#include <asm/dma.h>
-#include <sound/core.h>
-#include <sound/sb.h>
-#include <sound/wss.h>
-#include <sound/control.h>
-#define SNDRV_LEGACY_FIND_FREE_IRQ
-#define SNDRV_LEGACY_FIND_FREE_DMA
-#include <sound/initval.h>
-
-MODULE_AUTHOR("Christopher Butler <chrisb@sandy.force9.co.uk>");
-MODULE_DESCRIPTION("Aztech Sound Galaxy");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Aztech Systems,Sound Galaxy}}");
-
-static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
-static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
-static long sbport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;  /* 0x220,0x240 */
-static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x530,0xe80,0xf40,0x604 */
-static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;       /* 7,9,10,11 */
-static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;      /* 0,1,3 */
-
-module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for Sound Galaxy soundcard.");
-module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for Sound Galaxy soundcard.");
-module_param_array(sbport, long, NULL, 0444);
-MODULE_PARM_DESC(sbport, "Port # for Sound Galaxy SB driver.");
-module_param_array(wssport, long, NULL, 0444);
-MODULE_PARM_DESC(wssport, "Port # for Sound Galaxy WSS driver.");
-module_param_array(irq, int, NULL, 0444);
-MODULE_PARM_DESC(irq, "IRQ # for Sound Galaxy driver.");
-module_param_array(dma1, int, NULL, 0444);
-MODULE_PARM_DESC(dma1, "DMA1 # for Sound Galaxy driver.");
-
-#define SGALAXY_AUXC_LEFT 18
-#define SGALAXY_AUXC_RIGHT 19
-
-#define PFX    "sgalaxy: "
-
-/*
-
- */
-
-#define AD1848P1( port, x ) ( port + c_d_c_AD1848##x )
-
-/* from lowlevel/sb/sb.c - to avoid having to allocate a struct snd_sb for the */
-/* short time we actually need it.. */
-
-static int snd_sgalaxy_sbdsp_reset(unsigned long port)
-{
-       int i;
-
-       outb(1, SBP1(port, RESET));
-       udelay(10);
-       outb(0, SBP1(port, RESET));
-       udelay(30);
-       for (i = 0; i < 1000 && !(inb(SBP1(port, DATA_AVAIL)) & 0x80); i++);
-       if (inb(SBP1(port, READ)) != 0xaa) {
-               snd_printd("sb_reset: failed at 0x%lx!!!\n", port);
-               return -ENODEV;
-       }
-       return 0;
-}
-
-static int __devinit snd_sgalaxy_sbdsp_command(unsigned long port,
-                                              unsigned char val)
-{
-       int i;
-               
-       for (i = 10000; i; i--)
-               if ((inb(SBP1(port, STATUS)) & 0x80) == 0) {
-                       outb(val, SBP1(port, COMMAND));
-                       return 1;
-               }
-
-       return 0;
-}
-
-static irqreturn_t snd_sgalaxy_dummy_interrupt(int irq, void *dev_id)
-{
-       return IRQ_NONE;
-}
-
-static int __devinit snd_sgalaxy_setup_wss(unsigned long port, int irq, int dma)
-{
-       static int interrupt_bits[] = {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 
-                                      0x10, 0x18, 0x20, -1, -1, -1, -1};
-       static int dma_bits[] = {1, 2, 0, 3};
-       int tmp, tmp1;
-
-       if ((tmp = inb(port + 3)) == 0xff)
-       {
-               snd_printdd("I/O address dead (0x%lx)\n", port);
-               return 0;
-       }
-#if 0
-       snd_printdd("WSS signature = 0x%x\n", tmp);
-#endif
-
-        if ((tmp & 0x3f) != 0x04 &&
-            (tmp & 0x3f) != 0x0f &&
-            (tmp & 0x3f) != 0x00) {
-               snd_printdd("No WSS signature detected on port 0x%lx\n",
-                           port + 3);
-               return 0;
-       }
-
-#if 0
-       snd_printdd(PFX "setting up IRQ/DMA for WSS\n");
-#endif
-
-        /* initialize IRQ for WSS codec */
-        tmp = interrupt_bits[irq % 16];
-        if (tmp < 0)
-                return -EINVAL;
-
-       if (request_irq(irq, snd_sgalaxy_dummy_interrupt, IRQF_DISABLED, "sgalaxy", NULL)) {
-               snd_printk(KERN_ERR "sgalaxy: can't grab irq %d\n", irq);
-               return -EIO;
-       }
-
-        outb(tmp | 0x40, port);
-        tmp1 = dma_bits[dma % 4];
-        outb(tmp | tmp1, port);
-
-       free_irq(irq, NULL);
-
-       return 0;
-}
-
-static int __devinit snd_sgalaxy_detect(int dev, int irq, int dma)
-{
-#if 0
-       snd_printdd(PFX "switching to WSS mode\n");
-#endif
-
-       /* switch to WSS mode */
-       snd_sgalaxy_sbdsp_reset(sbport[dev]);
-
-       snd_sgalaxy_sbdsp_command(sbport[dev], 9);
-       snd_sgalaxy_sbdsp_command(sbport[dev], 0);
-
-       udelay(400);
-       return snd_sgalaxy_setup_wss(wssport[dev], irq, dma);
-}
-
-static struct snd_kcontrol_new snd_sgalaxy_controls[] = {
-WSS_DOUBLE("Aux Playback Switch", 0,
-               SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1),
-WSS_DOUBLE("Aux Playback Volume", 0,
-               SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0)
-};
-
-static int __devinit snd_sgalaxy_mixer(struct snd_wss *chip)
-{
-       struct snd_card *card = chip->card;
-       struct snd_ctl_elem_id id1, id2;
-       unsigned int idx;
-       int err;
-
-       memset(&id1, 0, sizeof(id1));
-       memset(&id2, 0, sizeof(id2));
-       id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
-       /* reassign AUX0 to LINE */
-       strcpy(id1.name, "Aux Playback Switch");
-       strcpy(id2.name, "Line Playback Switch");
-       if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
-               return err;
-       strcpy(id1.name, "Aux Playback Volume");
-       strcpy(id2.name, "Line Playback Volume");
-       if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
-               return err;
-       /* reassign AUX1 to FM */
-       strcpy(id1.name, "Aux Playback Switch"); id1.index = 1;
-       strcpy(id2.name, "FM Playback Switch");
-       if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
-               return err;
-       strcpy(id1.name, "Aux Playback Volume");
-       strcpy(id2.name, "FM Playback Volume");
-       if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0)
-               return err;
-       /* build AUX2 input */
-       for (idx = 0; idx < ARRAY_SIZE(snd_sgalaxy_controls); idx++) {
-               err = snd_ctl_add(card,
-                               snd_ctl_new1(&snd_sgalaxy_controls[idx], chip));
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
-static int __devinit snd_sgalaxy_match(struct device *devptr, unsigned int dev)
-{
-       if (!enable[dev])
-               return 0;
-       if (sbport[dev] == SNDRV_AUTO_PORT) {
-               snd_printk(KERN_ERR PFX "specify SB port\n");
-               return 0;
-       }
-       if (wssport[dev] == SNDRV_AUTO_PORT) {
-               snd_printk(KERN_ERR PFX "specify WSS port\n");
-               return 0;
-       }
-       return 1;
-}
-
-static int __devinit snd_sgalaxy_probe(struct device *devptr, unsigned int dev)
-{
-       static int possible_irqs[] = {7, 9, 10, 11, -1};
-       static int possible_dmas[] = {1, 3, 0, -1};
-       int err, xirq, xdma1;
-       struct snd_card *card;
-       struct snd_wss *chip;
-
-       err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
-       if (err < 0)
-               return err;
-
-       xirq = irq[dev];
-       if (xirq == SNDRV_AUTO_IRQ) {
-               if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
-                       snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
-                       err = -EBUSY;
-                       goto _err;
-               }
-       }
-       xdma1 = dma1[dev];
-        if (xdma1 == SNDRV_AUTO_DMA) {
-               if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
-                       snd_printk(KERN_ERR PFX "unable to find a free DMA\n");
-                       err = -EBUSY;
-                       goto _err;
-               }
-       }
-
-       if ((err = snd_sgalaxy_detect(dev, xirq, xdma1)) < 0)
-               goto _err;
-
-       err = snd_wss_create(card, wssport[dev] + 4, -1,
-                            xirq, xdma1, -1,
-                            WSS_HW_DETECT, 0, &chip);
-       if (err < 0)
-               goto _err;
-       card->private_data = chip;
-
-       err = snd_wss_pcm(chip, 0, NULL);
-       if (err < 0) {
-               snd_printdd(PFX "error creating new WSS PCM device\n");
-               goto _err;
-       }
-       err = snd_wss_mixer(chip);
-       if (err < 0) {
-               snd_printdd(PFX "error creating new WSS mixer\n");
-               goto _err;
-       }
-       if ((err = snd_sgalaxy_mixer(chip)) < 0) {
-               snd_printdd(PFX "the mixer rewrite failed\n");
-               goto _err;
-       }
-
-       strcpy(card->driver, "Sound Galaxy");
-       strcpy(card->shortname, "Sound Galaxy");
-       sprintf(card->longname, "Sound Galaxy at 0x%lx, irq %d, dma %d",
-               wssport[dev], xirq, xdma1);
-
-       snd_card_set_dev(card, devptr);
-
-       if ((err = snd_card_register(card)) < 0)
-               goto _err;
-
-       dev_set_drvdata(devptr, card);
-       return 0;
-
- _err:
-       snd_card_free(card);
-       return err;
-}
-
-static int __devexit snd_sgalaxy_remove(struct device *devptr, unsigned int dev)
-{
-       snd_card_free(dev_get_drvdata(devptr));
-       dev_set_drvdata(devptr, NULL);
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int snd_sgalaxy_suspend(struct device *pdev, unsigned int n,
-                              pm_message_t state)
-{
-       struct snd_card *card = dev_get_drvdata(pdev);
-       struct snd_wss *chip = card->private_data;
-
-       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
-       chip->suspend(chip);
-       return 0;
-}
-
-static int snd_sgalaxy_resume(struct device *pdev, unsigned int n)
-{
-       struct snd_card *card = dev_get_drvdata(pdev);
-       struct snd_wss *chip = card->private_data;
-
-       chip->resume(chip);
-       snd_wss_out(chip, SGALAXY_AUXC_LEFT, chip->image[SGALAXY_AUXC_LEFT]);
-       snd_wss_out(chip, SGALAXY_AUXC_RIGHT, chip->image[SGALAXY_AUXC_RIGHT]);
-
-       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
-       return 0;
-}
-#endif
-
-#define DEV_NAME "sgalaxy"
-
-static struct isa_driver snd_sgalaxy_driver = {
-       .match          = snd_sgalaxy_match,
-       .probe          = snd_sgalaxy_probe,
-       .remove         = __devexit_p(snd_sgalaxy_remove),
-#ifdef CONFIG_PM
-       .suspend        = snd_sgalaxy_suspend,
-       .resume         = snd_sgalaxy_resume,
-#endif
-       .driver         = {
-               .name   = DEV_NAME
-       },
-};
-
-static int __init alsa_card_sgalaxy_init(void)
-{
-       return isa_register_driver(&snd_sgalaxy_driver, SNDRV_CARDS);
-}
-
-static void __exit alsa_card_sgalaxy_exit(void)
-{
-       isa_unregister_driver(&snd_sgalaxy_driver);
-}
-
-module_init(alsa_card_sgalaxy_init)
-module_exit(alsa_card_sgalaxy_exit)
index a513651fa149897061406c166904277ea5f67131..76c09021807325944e3edb8b57bc2525e14b306c 100644 (file)
@@ -545,11 +545,3 @@ config SOUND_KAHLUA
 
 endif  # SOUND_OSS
 
-config SOUND_SH_DAC_AUDIO
-       tristate "SuperH DAC audio support"
-       depends on CPU_SH3 && HIGH_RES_TIMERS
-
-config SOUND_SH_DAC_AUDIO_CHANNEL
-       int "DAC channel"
-       default "1"
-       depends on SOUND_SH_DAC_AUDIO
index 567b8a74178a36bfca43a3f7b1a408a60bfec922..96f14dcd0cd19e73bcf09f1f11321e88fb5829b3 100644 (file)
@@ -9,7 +9,6 @@ obj-$(CONFIG_SOUND_OSS)         += sound.o
 
 # Please leave it as is, cause the link order is significant !
 
-obj-$(CONFIG_SOUND_SH_DAC_AUDIO)       += sh_dac_audio.o
 obj-$(CONFIG_SOUND_AEDSP16)    += aedsp16.o
 obj-$(CONFIG_SOUND_PSS)                += pss.o ad1848.o mpu401.o
 obj-$(CONFIG_SOUND_TRIX)       += trix.o ad1848.o sb_lib.o uart401.o
index c6f2621221baeebb428652df9dd51abfb5628b5b..a8f626d99c5b9245e4a0eaf3bf074718caf1889d 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/sound.h>
 #include <linux/slab.h>
 #include <linux/soundcard.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
@@ -77,6 +76,7 @@
 /* Boot options
  * 0 = no VRA, 1 = use VRA if codec supports it
  */
+static DEFINE_MUTEX(au1550_ac97_mutex);
 static int      vra = 1;
 module_param(vra, bool, 0);
 MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it");
@@ -171,7 +171,7 @@ au1550_delay(int msec)
 static u16
 rdcodec(struct ac97_codec *codec, u8 addr)
 {
-       struct au1550_state *s = (struct au1550_state *)codec->private_data;
+       struct au1550_state *s = codec->private_data;
        unsigned long   flags;
        u32             cmd, val;
        u16             data;
@@ -239,7 +239,7 @@ rdcodec(struct ac97_codec *codec, u8 addr)
 static void
 wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
 {
-       struct au1550_state *s = (struct au1550_state *)codec->private_data;
+       struct au1550_state *s = codec->private_data;
        unsigned long   flags;
        u32             cmd, val;
        int             i;
@@ -798,9 +798,9 @@ au1550_llseek(struct file *file, loff_t offset, int origin)
 static int
 au1550_open_mixdev(struct inode *inode, struct file *file)
 {
-       lock_kernel();
+       mutex_lock(&au1550_ac97_mutex);
        file->private_data = &au1550_state;
-       unlock_kernel();
+       mutex_unlock(&au1550_ac97_mutex);
        return 0;
 }
 
@@ -820,13 +820,13 @@ mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd,
 static long
 au1550_ioctl_mixdev(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct au1550_state *s = (struct au1550_state *)file->private_data;
+       struct au1550_state *s = file->private_data;
        struct ac97_codec *codec = s->codec;
        int ret;
 
-       lock_kernel();
+       mutex_lock(&au1550_ac97_mutex);
        ret = mixdev_ioctl(codec, cmd, arg);
-       unlock_kernel();
+       mutex_unlock(&au1550_ac97_mutex);
 
        return ret;
 }
@@ -1031,7 +1031,7 @@ copy_dmabuf_user(struct dmabuf *db, char* userbuf, int count, int to_user)
 static ssize_t
 au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
-       struct au1550_state *s = (struct au1550_state *)file->private_data;
+       struct au1550_state *s = file->private_data;
        struct dmabuf  *db = &s->dma_adc;
        DECLARE_WAITQUEUE(wait, current);
        ssize_t         ret;
@@ -1111,7 +1111,7 @@ out2:
 static ssize_t
 au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
 {
-       struct au1550_state *s = (struct au1550_state *)file->private_data;
+       struct au1550_state *s = file->private_data;
        struct dmabuf  *db = &s->dma_dac;
        DECLARE_WAITQUEUE(wait, current);
        ssize_t         ret = 0;
@@ -1211,7 +1211,7 @@ out2:
 static unsigned int
 au1550_poll(struct file *file, struct poll_table_struct *wait)
 {
-       struct au1550_state *s = (struct au1550_state *)file->private_data;
+       struct au1550_state *s = file->private_data;
        unsigned long   flags;
        unsigned int    mask = 0;
 
@@ -1250,12 +1250,12 @@ au1550_poll(struct file *file, struct poll_table_struct *wait)
 static int
 au1550_mmap(struct file *file, struct vm_area_struct *vma)
 {
-       struct au1550_state *s = (struct au1550_state *)file->private_data;
+       struct au1550_state *s = file->private_data;
        struct dmabuf  *db;
        unsigned long   size;
        int ret = 0;
 
-       lock_kernel();
+       mutex_lock(&au1550_ac97_mutex);
        mutex_lock(&s->sem);
        if (vma->vm_flags & VM_WRITE)
                db = &s->dma_dac;
@@ -1283,7 +1283,7 @@ au1550_mmap(struct file *file, struct vm_area_struct *vma)
        db->mapped = 1;
 out:
        mutex_unlock(&s->sem);
-       unlock_kernel();
+       mutex_unlock(&au1550_ac97_mutex);
        return ret;
 }
 
@@ -1342,7 +1342,7 @@ dma_count_done(struct dmabuf *db)
 static int
 au1550_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct au1550_state *s = (struct au1550_state *)file->private_data;
+       struct au1550_state *s = file->private_data;
        unsigned long   flags;
        audio_buf_info  abinfo;
        count_info      cinfo;
@@ -1781,9 +1781,9 @@ au1550_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        int ret;
 
-       lock_kernel();
+       mutex_lock(&au1550_ac97_mutex);
        ret = au1550_ioctl(file, cmd, arg);
-       unlock_kernel();
+       mutex_unlock(&au1550_ac97_mutex);
 
        return ret;
 }
@@ -1804,7 +1804,7 @@ au1550_open(struct inode *inode, struct file *file)
 #endif
 
        file->private_data = s;
-       lock_kernel();
+       mutex_lock(&au1550_ac97_mutex);
        /* wait for device to become free */
        mutex_lock(&s->open_mutex);
        while (s->open_mode & file->f_mode) {
@@ -1861,21 +1861,21 @@ au1550_open(struct inode *inode, struct file *file)
 out:
        mutex_unlock(&s->open_mutex);
 out2:
-       unlock_kernel();
+       mutex_unlock(&au1550_ac97_mutex);
        return ret;
 }
 
 static int
 au1550_release(struct inode *inode, struct file *file)
 {
-       struct au1550_state *s = (struct au1550_state *)file->private_data;
+       struct au1550_state *s = file->private_data;
 
-       lock_kernel();
+       mutex_lock(&au1550_ac97_mutex);
 
        if (file->f_mode & FMODE_WRITE) {
-               unlock_kernel();
+               mutex_unlock(&au1550_ac97_mutex);
                drain_dac(s, file->f_flags & O_NONBLOCK);
-               lock_kernel();
+               mutex_lock(&au1550_ac97_mutex);
        }
 
        mutex_lock(&s->open_mutex);
@@ -1892,7 +1892,7 @@ au1550_release(struct inode *inode, struct file *file)
        s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
        mutex_unlock(&s->open_mutex);
        wake_up(&s->open_wait);
-       unlock_kernel();
+       mutex_unlock(&au1550_ac97_mutex);
        return 0;
 }
 
index 6ecd41abb0667fbdfc580c51fb134fcae9fa46f8..87e2c72651f5fa1555f708c743465ee5843134a4 100644 (file)
 #include <linux/init.h>
 #include <linux/soundcard.h>
 #include <linux/poll.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 
      *  Declarations
      */
 
+static DEFINE_MUTEX(dmasound_core_mutex);
 int dmasound_catchRadius = 0;
 module_param(dmasound_catchRadius, int, 0);
 
@@ -323,22 +324,22 @@ static struct {
 
 static int mixer_open(struct inode *inode, struct file *file)
 {
-       lock_kernel();
+       mutex_lock(&dmasound_core_mutex);
        if (!try_module_get(dmasound.mach.owner)) {
-               unlock_kernel();
+               mutex_unlock(&dmasound_core_mutex);
                return -ENODEV;
        }
        mixer.busy = 1;
-       unlock_kernel();
+       mutex_unlock(&dmasound_core_mutex);
        return 0;
 }
 
 static int mixer_release(struct inode *inode, struct file *file)
 {
-       lock_kernel();
+       mutex_lock(&dmasound_core_mutex);
        mixer.busy = 0;
        module_put(dmasound.mach.owner);
-       unlock_kernel();
+       mutex_unlock(&dmasound_core_mutex);
        return 0;
 }
 
@@ -370,9 +371,9 @@ static long mixer_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
 {
        int ret;
 
-       lock_kernel();
+       mutex_lock(&dmasound_core_mutex);
        ret = mixer_ioctl(file, cmd, arg);
-       unlock_kernel();
+       mutex_unlock(&dmasound_core_mutex);
 
        return ret;
 }
@@ -752,9 +753,9 @@ static int sq_open(struct inode *inode, struct file *file)
 {
        int rc;
 
-       lock_kernel();
+       mutex_lock(&dmasound_core_mutex);
        if (!try_module_get(dmasound.mach.owner)) {
-               unlock_kernel();
+               mutex_unlock(&dmasound_core_mutex);
                return -ENODEV;
        }
 
@@ -799,11 +800,11 @@ static int sq_open(struct inode *inode, struct file *file)
                sound_set_format(AFMT_MU_LAW);
        }
 #endif
-       unlock_kernel();
+       mutex_unlock(&dmasound_core_mutex);
        return 0;
  out:
        module_put(dmasound.mach.owner);
-       unlock_kernel();
+       mutex_unlock(&dmasound_core_mutex);
        return rc;
 }
 
@@ -869,7 +870,7 @@ static int sq_release(struct inode *inode, struct file *file)
 {
        int rc = 0;
 
-       lock_kernel();
+       mutex_lock(&dmasound_core_mutex);
 
        if (file->f_mode & FMODE_WRITE) {
                if (write_sq.busy)
@@ -900,7 +901,7 @@ static int sq_release(struct inode *inode, struct file *file)
        write_sq_wake_up(file); /* checks f_mode */
 #endif /* blocking open() */
 
-       unlock_kernel();
+       mutex_unlock(&dmasound_core_mutex);
 
        return rc;
 }
@@ -1141,9 +1142,9 @@ static long sq_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
 {
        int ret;
 
-       lock_kernel();
+       mutex_lock(&dmasound_core_mutex);
        ret = sq_ioctl(file, cmd, arg);
-       unlock_kernel();
+       mutex_unlock(&dmasound_core_mutex);
 
        return ret;
 }
@@ -1257,7 +1258,7 @@ static int state_open(struct inode *inode, struct file *file)
        int len = 0;
        int ret;
 
-       lock_kernel();
+       mutex_lock(&dmasound_core_mutex);
        ret = -EBUSY;
        if (state.busy)
                goto out;
@@ -1329,16 +1330,16 @@ printk("dmasound: stat buffer used %d bytes\n", len) ;
        state.len = len;
        ret = 0;
 out:
-       unlock_kernel();
+       mutex_unlock(&dmasound_core_mutex);
        return ret;
 }
 
 static int state_release(struct inode *inode, struct file *file)
 {
-       lock_kernel();
+       mutex_lock(&dmasound_core_mutex);
        state.busy = 0;
        module_put(dmasound.mach.owner);
-       unlock_kernel();
+       mutex_unlock(&dmasound_core_mutex);
        return 0;
 }
 
index ca942f7cd2313c38c95d091f20c78658b36b36b7..7b5c77b32a90b9a5d4c967dcb58f2cb8e335fd24 100644 (file)
@@ -39,7 +39,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/gfp.h>
 #include <asm/irq.h>
 #include <asm/io.h>
@@ -79,6 +79,7 @@
                                         dev.rec_sample_rate /          \
                                         dev.rec_channels)
 
+static DEFINE_MUTEX(msnd_pinnacle_mutex);
 static multisound_dev_t                        dev;
 
 #ifndef HAVE_DSPCODEH
@@ -651,12 +652,12 @@ static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
        ret = -EINVAL;
 
-       lock_kernel();
+       mutex_lock(&msnd_pinnacle_mutex);
        if (minor == dev.dsp_minor)
                ret = dsp_ioctl(file, cmd, arg);
        else if (minor == dev.mixer_minor)
                ret = mixer_ioctl(cmd, arg);
-       unlock_kernel();
+       mutex_unlock(&msnd_pinnacle_mutex);
 
        return ret;
 }
@@ -761,7 +762,7 @@ static int dev_open(struct inode *inode, struct file *file)
        int minor = iminor(inode);
        int err = 0;
 
-       lock_kernel();
+       mutex_lock(&msnd_pinnacle_mutex);
        if (minor == dev.dsp_minor) {
                if ((file->f_mode & FMODE_WRITE &&
                     test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) ||
@@ -791,7 +792,7 @@ static int dev_open(struct inode *inode, struct file *file)
        } else
                err = -EINVAL;
 out:
-       unlock_kernel();
+       mutex_unlock(&msnd_pinnacle_mutex);
        return err;
 }
 
@@ -800,14 +801,14 @@ static int dev_release(struct inode *inode, struct file *file)
        int minor = iminor(inode);
        int err = 0;
 
-       lock_kernel();
+       mutex_lock(&msnd_pinnacle_mutex);
        if (minor == dev.dsp_minor)
                err = dsp_release(file);
        else if (minor == dev.mixer_minor) {
                /* nothing */
        } else
                err = -EINVAL;
-       unlock_kernel();
+       mutex_unlock(&msnd_pinnacle_mutex);
        return err;
 }
 
diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c
deleted file mode 100644 (file)
index 479e302..0000000
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * sound/oss/sh_dac_audio.c
- *
- * SH DAC based sound :(
- *
- *  Copyright (C) 2004,2005  Andriy Skulysh
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/linkage.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/sound.h>
-#include <linux/smp_lock.h>
-#include <linux/soundcard.h>
-#include <linux/interrupt.h>
-#include <linux/hrtimer.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-#include <asm/delay.h>
-#include <asm/clock.h>
-#include <cpu/dac.h>
-#include <asm/machvec.h>
-#include <mach/hp6xx.h>
-#include <asm/hd64461.h>
-
-#define MODNAME "sh_dac_audio"
-
-#define BUFFER_SIZE 48000
-
-static int rate;
-static int empty;
-static char *data_buffer, *buffer_begin, *buffer_end;
-static int in_use, device_major;
-static struct hrtimer hrtimer;
-static ktime_t wakeups_per_second;
-
-static void dac_audio_start_timer(void)
-{
-       hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL);
-}
-
-static void dac_audio_stop_timer(void)
-{
-       hrtimer_cancel(&hrtimer);
-}
-
-static void dac_audio_reset(void)
-{
-       dac_audio_stop_timer();
-       buffer_begin = buffer_end = data_buffer;
-       empty = 1;
-}
-
-static void dac_audio_sync(void)
-{
-       while (!empty)
-               schedule();
-}
-
-static void dac_audio_start(void)
-{
-       if (mach_is_hp6xx()) {
-               u16 v = __raw_readw(HD64461_GPADR);
-               v &= ~HD64461_GPADR_SPEAKER;
-               __raw_writew(v, HD64461_GPADR);
-       }
-
-       sh_dac_enable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
-}
-static void dac_audio_stop(void)
-{
-       dac_audio_stop_timer();
-
-       if (mach_is_hp6xx()) {
-               u16 v = __raw_readw(HD64461_GPADR);
-               v |= HD64461_GPADR_SPEAKER;
-               __raw_writew(v, HD64461_GPADR);
-       }
-
-       sh_dac_output(0, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
-       sh_dac_disable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
-}
-
-static void dac_audio_set_rate(void)
-{
-       wakeups_per_second = ktime_set(0, 1000000000 / rate);
-}
-
-static int dac_audio_ioctl(struct file *file,
-                          unsigned int cmd, unsigned long arg)
-{
-       int val;
-
-       switch (cmd) {
-       case OSS_GETVERSION:
-               return put_user(SOUND_VERSION, (int *)arg);
-
-       case SNDCTL_DSP_SYNC:
-               dac_audio_sync();
-               return 0;
-
-       case SNDCTL_DSP_RESET:
-               dac_audio_reset();
-               return 0;
-
-       case SNDCTL_DSP_GETFMTS:
-               return put_user(AFMT_U8, (int *)arg);
-
-       case SNDCTL_DSP_SETFMT:
-               return put_user(AFMT_U8, (int *)arg);
-
-       case SNDCTL_DSP_NONBLOCK:
-               spin_lock(&file->f_lock);
-               file->f_flags |= O_NONBLOCK;
-               spin_unlock(&file->f_lock);
-               return 0;
-
-       case SNDCTL_DSP_GETCAPS:
-               return 0;
-
-       case SOUND_PCM_WRITE_RATE:
-               val = *(int *)arg;
-               if (val > 0) {
-                       rate = val;
-                       dac_audio_set_rate();
-               }
-               return put_user(rate, (int *)arg);
-
-       case SNDCTL_DSP_STEREO:
-               return put_user(0, (int *)arg);
-
-       case SOUND_PCM_WRITE_CHANNELS:
-               return put_user(1, (int *)arg);
-
-       case SNDCTL_DSP_SETDUPLEX:
-               return -EINVAL;
-
-       case SNDCTL_DSP_PROFILE:
-               return -EINVAL;
-
-       case SNDCTL_DSP_GETBLKSIZE:
-               return put_user(BUFFER_SIZE, (int *)arg);
-
-       case SNDCTL_DSP_SETFRAGMENT:
-               return 0;
-
-       default:
-               printk(KERN_ERR "sh_dac_audio: unimplemented ioctl=0x%x\n",
-                      cmd);
-               return -EINVAL;
-       }
-       return -EINVAL;
-}
-
-static long dac_audio_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
-{
-       int ret;
-
-       lock_kernel();
-       ret = dac_audio_ioctl(file, cmd, arg);
-       unlock_kernel();
-
-       return ret;
-}
-
-static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count,
-                              loff_t * ppos)
-{
-       int free;
-       int nbytes;
-
-       if (!count) {
-               dac_audio_sync();
-               return 0;
-       }
-
-       free = buffer_begin - buffer_end;
-
-       if (free < 0)
-               free += BUFFER_SIZE;
-       if ((free == 0) && (empty))
-               free = BUFFER_SIZE;
-       if (count > free)
-               count = free;
-       if (buffer_begin > buffer_end) {
-               if (copy_from_user((void *)buffer_end, buf, count))
-                       return -EFAULT;
-
-               buffer_end += count;
-       } else {
-               nbytes = data_buffer + BUFFER_SIZE - buffer_end;
-               if (nbytes > count) {
-                       if (copy_from_user((void *)buffer_end, buf, count))
-                               return -EFAULT;
-                       buffer_end += count;
-               } else {
-                       if (copy_from_user((void *)buffer_end, buf, nbytes))
-                               return -EFAULT;
-                       if (copy_from_user
-                           ((void *)data_buffer, buf + nbytes, count - nbytes))
-                               return -EFAULT;
-                       buffer_end = data_buffer + count - nbytes;
-               }
-       }
-
-       if (empty) {
-               empty = 0;
-               dac_audio_start_timer();
-       }
-
-       return count;
-}
-
-static ssize_t dac_audio_read(struct file *file, char *buf, size_t count,
-                             loff_t * ppos)
-{
-       return -EINVAL;
-}
-
-static int dac_audio_open(struct inode *inode, struct file *file)
-{
-       if (file->f_mode & FMODE_READ)
-               return -ENODEV;
-
-       lock_kernel();
-       if (in_use) {
-               unlock_kernel();
-               return -EBUSY;
-       }
-
-       in_use = 1;
-
-       dac_audio_start();
-       unlock_kernel();
-       return 0;
-}
-
-static int dac_audio_release(struct inode *inode, struct file *file)
-{
-       dac_audio_sync();
-       dac_audio_stop();
-       in_use = 0;
-
-       return 0;
-}
-
-const struct file_operations dac_audio_fops = {
-      .read =          dac_audio_read,
-      .write =         dac_audio_write,
-      .unlocked_ioctl =        dac_audio_unlocked_ioctl,
-      .open =          dac_audio_open,
-      .release =       dac_audio_release,
-};
-
-static enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle)
-{
-       if (!empty) {
-               sh_dac_output(*buffer_begin, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
-               buffer_begin++;
-
-               if (buffer_begin == data_buffer + BUFFER_SIZE)
-                       buffer_begin = data_buffer;
-               if (buffer_begin == buffer_end)
-                       empty = 1;
-       }
-
-       if (!empty)
-               hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL);
-
-       return HRTIMER_NORESTART;
-}
-
-static int __init dac_audio_init(void)
-{
-       if ((device_major = register_sound_dsp(&dac_audio_fops, -1)) < 0) {
-               printk(KERN_ERR "Cannot register dsp device");
-               return device_major;
-       }
-
-       in_use = 0;
-
-       data_buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
-       if (data_buffer == NULL)
-               return -ENOMEM;
-
-       dac_audio_reset();
-       rate = 8000;
-       dac_audio_set_rate();
-
-       /* Today: High Resolution Timer driven DAC playback.
-        * The timer callback gets called once per sample. Ouch.
-        *
-        * Future: A much better approach would be to use the
-        * SH7720 CMT+DMAC+DAC hardware combination like this:
-        * - Program sample rate using CMT0 or CMT1
-        * - Program DMAC to use CMT for timing and output to DAC
-        * - Play sound using DMAC, let CPU sleep.
-        * - While at it, rewrite this driver to use ALSA.
-        */
-
-       hrtimer_init(&hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-       hrtimer.function = sh_dac_audio_timer;
-
-       return 0;
-}
-
-static void __exit dac_audio_exit(void)
-{
-       unregister_sound_dsp(device_major);
-       kfree((void *)data_buffer);
-}
-
-module_init(dac_audio_init);
-module_exit(dac_audio_exit);
-
-MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua");
-MODULE_DESCRIPTION("SH DAC sound driver");
-MODULE_LICENSE("GPL");
index 07f803e6d203a41615db0923cf073f7eadc283b6..46c0d03dbecced68ca318dbbe20df52d1da4ab0b 100644 (file)
@@ -40,7 +40,7 @@
 #include <linux/major.h>
 #include <linux/delay.h>
 #include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/device.h>
@@ -56,6 +56,7 @@
  * Table for permanently allocated memory (used when unloading the module)
  */
 void *          sound_mem_blocks[MAX_MEM_BLOCKS];
+static DEFINE_MUTEX(soundcard_mutex);
 int             sound_nblocks = 0;
 
 /* Persistent DMA buffers */
@@ -151,7 +152,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof
         *      big one anyway, we might as well bandage here..
         */
         
-       lock_kernel();
+       mutex_lock(&soundcard_mutex);
        
        DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count));
        switch (dev & 0x0f) {
@@ -169,7 +170,7 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof
        case SND_DEV_MIDIN:
                ret = MIDIbuf_read(dev, file, buf, count);
        }
-       unlock_kernel();
+       mutex_unlock(&soundcard_mutex);
        return ret;
 }
 
@@ -178,7 +179,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou
        int dev = iminor(file->f_path.dentry->d_inode);
        int ret = -EINVAL;
        
-       lock_kernel();
+       mutex_lock(&soundcard_mutex);
        DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count));
        switch (dev & 0x0f) {
        case SND_DEV_SEQ:
@@ -196,7 +197,7 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou
                ret =  MIDIbuf_write(dev, file, buf, count);
                break;
        }
-       unlock_kernel();
+       mutex_unlock(&soundcard_mutex);
        return ret;
 }
 
@@ -210,7 +211,7 @@ static int sound_open(struct inode *inode, struct file *file)
                printk(KERN_ERR "Invalid minor device %d\n", dev);
                return -ENXIO;
        }
-       lock_kernel();
+       mutex_lock(&soundcard_mutex);
        switch (dev & 0x0f) {
        case SND_DEV_CTL:
                dev >>= 4;
@@ -247,15 +248,15 @@ static int sound_open(struct inode *inode, struct file *file)
                retval = -ENXIO;
        }
 
-       unlock_kernel();
-       return 0;
+       mutex_unlock(&soundcard_mutex);
+       return retval;
 }
 
 static int sound_release(struct inode *inode, struct file *file)
 {
        int dev = iminor(inode);
 
-       lock_kernel();
+       mutex_lock(&soundcard_mutex);
        DEB(printk("sound_release(dev=%d)\n", dev));
        switch (dev & 0x0f) {
        case SND_DEV_CTL:
@@ -280,7 +281,7 @@ static int sound_release(struct inode *inode, struct file *file)
        default:
                printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev);
        }
-       unlock_kernel();
+       mutex_unlock(&soundcard_mutex);
 
        return 0;
 }
@@ -354,7 +355,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        if (cmd == OSS_GETVERSION)
                return __put_user(SOUND_VERSION, (int __user *)p);
        
-       lock_kernel();
+       mutex_lock(&soundcard_mutex);
        if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 &&   /* Mixer ioctl */
            (dev & 0x0f) != SND_DEV_CTL) {              
                dtype = dev & 0x0f;
@@ -369,7 +370,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        ret = sound_mixer_ioctl(dev >> 4, cmd, p);
                        break;
                }
-               unlock_kernel();
+               mutex_unlock(&soundcard_mutex);
                return ret;
        }
 
@@ -399,7 +400,7 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                break;
 
        }
-       unlock_kernel();
+       mutex_unlock(&soundcard_mutex);
        return ret;
 }
 
@@ -439,35 +440,35 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
                printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n");
                return -EINVAL;
        }
-       lock_kernel();
+       mutex_lock(&soundcard_mutex);
        if (vma->vm_flags & VM_WRITE)   /* Map write and read/write to the output buf */
                dmap = audio_devs[dev]->dmap_out;
        else if (vma->vm_flags & VM_READ)
                dmap = audio_devs[dev]->dmap_in;
        else {
                printk(KERN_ERR "Sound: Undefined mmap() access\n");
-               unlock_kernel();
+               mutex_unlock(&soundcard_mutex);
                return -EINVAL;
        }
 
        if (dmap == NULL) {
                printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n");
-               unlock_kernel();
+               mutex_unlock(&soundcard_mutex);
                return -EIO;
        }
        if (dmap->raw_buf == NULL) {
                printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n");
-               unlock_kernel();
+               mutex_unlock(&soundcard_mutex);
                return -EIO;
        }
        if (dmap->mapping_flags) {
                printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n");
-               unlock_kernel();
+               mutex_unlock(&soundcard_mutex);
                return -EIO;
        }
        if (vma->vm_pgoff != 0) {
                printk(KERN_ERR "Sound: mmap() offset must be 0.\n");
-               unlock_kernel();
+               mutex_unlock(&soundcard_mutex);
                return -EINVAL;
        }
        size = vma->vm_end - vma->vm_start;
@@ -478,7 +479,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
        if (remap_pfn_range(vma, vma->vm_start,
                        virt_to_phys(dmap->raw_buf) >> PAGE_SHIFT,
                        vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
-               unlock_kernel();
+               mutex_unlock(&soundcard_mutex);
                return -EAGAIN;
        }
 
@@ -490,7 +491,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
        memset(dmap->raw_buf,
               dmap->neutral_byte,
               dmap->bytes_in_use);
-       unlock_kernel();
+       mutex_unlock(&soundcard_mutex);
        return 0;
 }
 
index b15840ad2527820bc78f9d00c4fe5d20a011b785..44357d877a275a384ff54fea2e1322eaf7ff37a0 100644 (file)
@@ -68,7 +68,6 @@
 #include <linux/delay.h>
 #include <linux/sound.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/soundcard.h>
 #include <linux/ac97_codec.h>
 #include <linux/pci.h>
@@ -94,6 +93,7 @@
 
 struct cs4297a_state;
 
+static DEFINE_MUTEX(swarm_cs4297a_mutex);
 static void stop_dac(struct cs4297a_state *s);
 static void stop_adc(struct cs4297a_state *s);
 static void start_dac(struct cs4297a_state *s);
@@ -1535,7 +1535,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
        CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
                  printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()+\n"));
 
-       lock_kernel();
+       mutex_lock(&swarm_cs4297a_mutex);
        list_for_each(entry, &cs4297a_devs)
        {
                s = list_entry(entry, struct cs4297a_state, list);
@@ -1547,7 +1547,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
                CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
                        printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- -ENODEV\n"));
 
-               unlock_kernel();
+               mutex_unlock(&swarm_cs4297a_mutex);
                return -ENODEV;
        }
        VALIDATE_STATE(s);
@@ -1555,7 +1555,7 @@ static int cs4297a_open_mixdev(struct inode *inode, struct file *file)
 
        CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
                  printk(KERN_INFO "cs4297a: cs4297a_open_mixdev()- 0\n"));
-       unlock_kernel();
+       mutex_unlock(&swarm_cs4297a_mutex);
 
        return nonseekable_open(inode, file);
 }
@@ -1575,10 +1575,10 @@ static int cs4297a_ioctl_mixdev(struct file *file,
                               unsigned int cmd, unsigned long arg)
 {
        int ret;
-       lock_kernel();
+       mutex_lock(&swarm_cs4297a_mutex);
        ret = mixer_ioctl((struct cs4297a_state *) file->private_data, cmd,
                           arg);
-       unlock_kernel();
+       mutex_unlock(&swarm_cs4297a_mutex);
        return ret;
 }
 
@@ -2350,9 +2350,9 @@ static long cs4297a_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
 {
        int ret;
 
-       lock_kernel();
+       mutex_lock(&swarm_cs4297a_mutex);
        ret = cs4297a_ioctl(file, cmd, arg);
-       unlock_kernel();
+       mutex_unlock(&swarm_cs4297a_mutex);
 
        return ret;
 }
@@ -2509,9 +2509,9 @@ static int cs4297a_open(struct inode *inode, struct file *file)
 {
        int ret;
 
-       lock_kernel();
+       mutex_lock(&swarm_cs4297a_mutex);
        ret = cs4297a_open(inode, file);
-       unlock_kernel();
+       mutex_unlock(&swarm_cs4297a_mutex);
 
        return ret;
 }
index 8cd73cdd88afeedbaf90e1bdbab62eb56fc0949e..643f1113b1d8844c4e2850eff613b152aafcb737 100644 (file)
 #include <linux/init.h>
 
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 #include <linux/wait.h>
 #include <linux/interrupt.h>
 #include <linux/mutex.h>
 
 #ifdef VWSND_DEBUG
 
+static DEFINE_MUTEX(vwsnd_mutex);
 static int shut_up = 1;
 
 /*
@@ -2891,11 +2891,11 @@ static long vwsnd_audio_ioctl(struct file *file,
        vwsnd_dev_t *devc = (vwsnd_dev_t *) file->private_data;
        int ret;
 
-       lock_kernel();
+       mutex_lock(&vwsnd_mutex);
        mutex_lock(&devc->io_mutex);
        ret = vwsnd_audio_do_ioctl(file, cmd, arg);
        mutex_unlock(&devc->io_mutex);
-       unlock_kernel();
+       mutex_unlock(&vwsnd_mutex);
 
        return ret;
 }
@@ -2922,7 +2922,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
 
        DBGE("(inode=0x%p, file=0x%p)\n", inode, file);
 
-       lock_kernel();
+       mutex_lock(&vwsnd_mutex);
        INC_USE_COUNT;
        for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
                if ((devc->audio_minor & ~0x0F) == (minor & ~0x0F))
@@ -2930,7 +2930,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
 
        if (devc == NULL) {
                DEC_USE_COUNT;
-               unlock_kernel();
+               mutex_unlock(&vwsnd_mutex);
                return -ENODEV;
        }
 
@@ -2939,13 +2939,13 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
                mutex_unlock(&devc->open_mutex);
                if (file->f_flags & O_NONBLOCK) {
                        DEC_USE_COUNT;
-                       unlock_kernel();
+                       mutex_unlock(&vwsnd_mutex);
                        return -EBUSY;
                }
                interruptible_sleep_on(&devc->open_wait);
                if (signal_pending(current)) {
                        DEC_USE_COUNT;
-                       unlock_kernel();
+                       mutex_unlock(&vwsnd_mutex);
                        return -ERESTARTSYS;
                }
                mutex_lock(&devc->open_mutex);
@@ -2998,7 +2998,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
 
        file->private_data = devc;
        DBGRV();
-       unlock_kernel();
+       mutex_unlock(&vwsnd_mutex);
        return 0;
 }
 
@@ -3012,7 +3012,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file)
        vwsnd_port_t *wport = NULL, *rport = NULL;
        int err = 0;
 
-       lock_kernel();
+       mutex_lock(&vwsnd_mutex);
        mutex_lock(&devc->io_mutex);
        {
                DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
@@ -3040,7 +3040,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file)
        wake_up(&devc->open_wait);
        DEC_USE_COUNT;
        DBGR();
-       unlock_kernel();
+       mutex_unlock(&vwsnd_mutex);
        return err;
 }
 
@@ -3068,18 +3068,18 @@ static int vwsnd_mixer_open(struct inode *inode, struct file *file)
        DBGEV("(inode=0x%p, file=0x%p)\n", inode, file);
 
        INC_USE_COUNT;
-       lock_kernel();
+       mutex_lock(&vwsnd_mutex);
        for (devc = vwsnd_dev_list; devc; devc = devc->next_dev)
                if (devc->mixer_minor == iminor(inode))
                        break;
 
        if (devc == NULL) {
                DEC_USE_COUNT;
-               unlock_kernel();
+               mutex_unlock(&vwsnd_mutex);
                return -ENODEV;
        }
        file->private_data = devc;
-       unlock_kernel();
+       mutex_unlock(&vwsnd_mutex);
        return 0;
 }
 
@@ -3223,7 +3223,7 @@ static long vwsnd_mixer_ioctl(struct file *file,
 
        DBGEV("(devc=0x%p, cmd=0x%x, arg=0x%lx)\n", devc, cmd, arg);
 
-       lock_kernel();
+       mutex_lock(&vwsnd_mutex);
        mutex_lock(&devc->mix_mutex);
        {
                if ((cmd & ~nrmask) == MIXER_READ(0))
@@ -3234,7 +3234,7 @@ static long vwsnd_mixer_ioctl(struct file *file,
                        retval = -EINVAL;
        }
        mutex_unlock(&devc->mix_mutex);
-       unlock_kernel();
+       mutex_unlock(&vwsnd_mutex);
        return retval;
 }
 
index e7a8cd058efb59190851730ee352eca5926d0df7..12e34653b8a842ec5dd04778850438bec4b67aa7 100644 (file)
@@ -207,12 +207,12 @@ config SND_CMIPCI
 
 config SND_OXYGEN_LIB
         tristate
-       select SND_PCM
-       select SND_MPU401_UART
 
 config SND_OXYGEN
        tristate "C-Media 8788 (Oxygen)"
        select SND_OXYGEN_LIB
+       select SND_PCM
+       select SND_MPU401_UART
        help
          Say Y here to include support for sound cards based on the
          C-Media CMI8788 (Oxygen HD Audio) chip:
@@ -581,6 +581,8 @@ config 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.
@@ -815,14 +817,17 @@ config SND_VIA82XX_MODEM
          will be called snd-via82xx-modem.
 
 config SND_VIRTUOSO
-       tristate "Asus Virtuoso 100/200 (Xonar)"
+       tristate "Asus Virtuoso 66/100/200 (Xonar)"
        select SND_OXYGEN_LIB
+       select SND_PCM
+       select SND_MPU401_UART
+       select SND_JACK if INPUT=y || INPUT=SND
        help
          Say Y here to include support for sound cards based on the
-         Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X,
+         Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS,
          Essence ST (Deluxe), and Essence STX.
-         Support for the DS is experimental.
-         Support for the HDAV1.3 (Deluxe) is very experimental.
+         Support for the HDAV1.3 (Deluxe) is incomplete; for the
+         HDAV1.3 Slim and Xense, missing.
 
          To compile this driver as a module, choose M here: the module
          will be called snd-virtuoso.
index c92f493d341e266c36b870f116aaf6adb9ef48a7..557c782ae4fc8caca953c1ec85111b0179066b48 100644 (file)
@@ -23,7 +23,7 @@ static int __devinit snd_vortex_mixer(vortex_t * vortex)
        if ((err = snd_ac97_bus(vortex->card, 0, &ops, NULL, &pbus)) < 0)
                return err;
        memset(&ac97, 0, sizeof(ac97));
-       // Intialize AC97 codec stuff.
+       // Initialize AC97 codec stuff.
        ac97.private_data = vortex;
        ac97.scaps = AC97_SCAP_NO_SPDIF;
        err = snd_ac97_mixer(pbus, &ac97, &vortex->codec);
index 14b8d9a91aae27655439e487aed6aed853b9e426..f19c11077255ddfe5f7d30dbb2543740717c6b43 100644 (file)
@@ -670,8 +670,9 @@ struct snd_ca0106_details {
                           gpio_type = 2 -> shared side-out/line-in. */
        int i2c_adc;    /* with i2c_adc=1, the driver adds some capture volume
                           controls, phone, mic, line-in and aux. */
-       int spi_dac;    /* spi_dac=1 adds the mute switch for each analog
-                          output, front, rear, etc. */
+       u16 spi_dac;    /* spi_dac = 0 -> no spi interface for DACs
+                          spi_dac = 0x<front><rear><center-lfe><side>
+                          -> specifies DAC id for each channel pair. */
 };
 
 // definition of the chip-specific record
index 0a3d3d6e77b4d668bad27a929cda8fa174d1cd1c..d2d12c08f93759bb069f580ece58e1043c00e2af 100644 (file)
@@ -227,7 +227,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
           .name   = "Audigy SE [SB0570]",
           .gpio_type = 1,
           .i2c_adc = 1,
-          .spi_dac = 1 } ,
+          .spi_dac = 0x4021 } ,
         /* New Audigy LS. Has a different DAC. */
         /* SB0570:
          * CTRL:CA0106-DAT
@@ -238,7 +238,17 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
           .name   = "Audigy SE OEM [SB0570a]",
           .gpio_type = 1,
           .i2c_adc = 1,
-          .spi_dac = 1 } ,
+          .spi_dac = 0x4021 } ,
+       /* Sound Blaster 5.1vx
+        * Tested: Playback on front, rear, center/lfe speakers
+        * Not-Tested: Capture
+        */
+       { .serial = 0x10041102,
+         .name   = "Sound Blaster 5.1vx [SB1070]",
+         .gpio_type = 1,
+         .i2c_adc = 0,
+         .spi_dac = 0x0124
+        } ,
         /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */
         /* SB0438
          * CTRL:CA0106-DAT
@@ -254,7 +264,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
           .name   = "MSI K8N Diamond MB",
           .gpio_type = 2,
           .i2c_adc = 1,
-          .spi_dac = 1 } ,
+          .spi_dac = 0x4021 } ,
        /* Giga-byte GA-G1975X mobo
         * Novell bnc#395807
         */
@@ -483,16 +493,18 @@ static void snd_ca0106_pcm_free_substream(struct snd_pcm_runtime *runtime)
 }
 
 static const int spi_dacd_reg[] = {
-       [PCM_FRONT_CHANNEL]     = SPI_DACD4_REG,
-       [PCM_REAR_CHANNEL]      = SPI_DACD0_REG,
-       [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_REG,
-       [PCM_UNKNOWN_CHANNEL]   = SPI_DACD1_REG,
+       SPI_DACD0_REG,
+       SPI_DACD1_REG,
+       SPI_DACD2_REG,
+       0,
+       SPI_DACD4_REG,
 };
 static const int spi_dacd_bit[] = {
-       [PCM_FRONT_CHANNEL]     = SPI_DACD4_BIT,
-       [PCM_REAR_CHANNEL]      = SPI_DACD0_BIT,
-       [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_BIT,
-       [PCM_UNKNOWN_CHANNEL]   = SPI_DACD1_BIT,
+       SPI_DACD0_BIT,
+       SPI_DACD1_BIT,
+       SPI_DACD2_BIT,
+       0,
+       SPI_DACD4_BIT,
 };
 
 static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
@@ -504,6 +516,45 @@ static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
        }
 }
 
+static int snd_ca0106_channel_dac(struct snd_ca0106_details *details,
+                                 int channel_id)
+{
+       switch (channel_id) {
+       case PCM_FRONT_CHANNEL:
+               return (details->spi_dac & 0xf000) >> (4 * 3);
+       case PCM_REAR_CHANNEL:
+               return (details->spi_dac & 0x0f00) >> (4 * 2);
+       case PCM_CENTER_LFE_CHANNEL:
+               return (details->spi_dac & 0x00f0) >> (4 * 1);
+       case PCM_UNKNOWN_CHANNEL:
+               return (details->spi_dac & 0x000f) >> (4 * 0);
+       default:
+               snd_printk(KERN_DEBUG "ca0106: unknown channel_id %d\n",
+                          channel_id);
+       }
+       return 0;
+}
+
+static int snd_ca0106_pcm_power_dac(struct snd_ca0106 *chip, int channel_id,
+                                   int power)
+{
+       if (chip->details->spi_dac) {
+               const int dac = snd_ca0106_channel_dac(chip->details,
+                                                      channel_id);
+               const int reg = spi_dacd_reg[dac];
+               const int bit = spi_dacd_bit[dac];
+
+               if (power)
+                       /* Power up */
+                       chip->spi_dac_reg[reg] &= ~bit;
+               else
+                       /* Power down */
+                       chip->spi_dac_reg[reg] |= bit;
+               return snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+       }
+       return 0;
+}
+
 /* open_playback callback */
 static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream,
                                                int channel_id)
@@ -543,12 +594,9 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr
                 return err;
        snd_pcm_set_sync(substream);
 
-       if (chip->details->spi_dac && channel_id != PCM_FRONT_CHANNEL) {
-               const int reg = spi_dacd_reg[channel_id];
-
-               /* Power up dac */
-               chip->spi_dac_reg[reg] &= ~spi_dacd_bit[channel_id];
-               err = snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+       /* Front channel dac should already be on */
+       if (channel_id != PCM_FRONT_CHANNEL) {
+               err = snd_ca0106_pcm_power_dac(chip, channel_id, 1);
                if (err < 0)
                        return err;
        }
@@ -568,13 +616,14 @@ static int snd_ca0106_pcm_close_playback(struct snd_pcm_substream *substream)
 
        restore_spdif_bits(chip, epcm->channel_id);
 
-       if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) {
-               const int reg = spi_dacd_reg[epcm->channel_id];
-
-               /* Power down DAC */
-               chip->spi_dac_reg[reg] |= spi_dacd_bit[epcm->channel_id];
-               snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+       /* Front channel dac should stay on */
+       if (epcm->channel_id != PCM_FRONT_CHANNEL) {
+               int err;
+               err = snd_ca0106_pcm_power_dac(chip, epcm->channel_id, 0);
+               if (err < 0)
+                       return err;
        }
+
        /* FIXME: maybe zero others */
        return 0;
 }
@@ -1002,29 +1051,27 @@ snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream)
        struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_ca0106_pcm *epcm = runtime->private_data;
-       snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0;
+       unsigned int ptr, prev_ptr;
        int channel = epcm->channel_id;
+       int timeout = 10;
 
        if (!epcm->running)
                return 0;
 
-       ptr3 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
-       ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);
-       ptr4 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
-       if (ptr3 != ptr4) ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);
-       ptr2 = bytes_to_frames(runtime, ptr1);
-       ptr2+= (ptr4 >> 3) * runtime->period_size;
-       ptr=ptr2;
-        if (ptr >= runtime->buffer_size)
-               ptr -= runtime->buffer_size;
-       /*
-       printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
-              "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n",
-              ptr1, ptr2, ptr, (int)runtime->buffer_size,
-              (int)runtime->period_size, (int)runtime->frame_bits,
-              (int)runtime->rate);
-       */
-       return ptr;
+       prev_ptr = -1;
+       do {
+               ptr = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
+               ptr = (ptr >> 3) * runtime->period_size;
+               ptr += bytes_to_frames(runtime,
+                       snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel));
+               if (ptr >= runtime->buffer_size)
+                       ptr -= runtime->buffer_size;
+               if (prev_ptr == ptr)
+                       return ptr;
+               prev_ptr = ptr;
+       } while (--timeout);
+       snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!\n");
+       return 0;
 }
 
 /* pointer_capture callback */
@@ -1362,7 +1409,7 @@ static unsigned int spi_dac_init[] = {
        SPI_REG(12,             0x00),
        SPI_REG(SPI_LDA4_REG,   SPI_DA_BIT_0dB),
        SPI_REG(SPI_RDA4_REG,   SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE),
-       SPI_REG(SPI_DACD4_REG,  0x00),
+       SPI_REG(SPI_DACD4_REG,  SPI_DACD4_BIT),
 };
 
 static unsigned int i2c_adc_init[][2] = {
@@ -1541,7 +1588,7 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
                /* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */
        }
 
-       if (chip->details->spi_dac == 1) {
+       if (chip->details->spi_dac) {
                /* The SB0570 use SPI to control DAC. */
                int size, n;
 
@@ -1553,6 +1600,9 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
                        if (reg < ARRAY_SIZE(chip->spi_dac_reg))
                                chip->spi_dac_reg[reg] = spi_dac_init[n];
                }
+
+               /* Enable front dac only */
+               snd_ca0106_pcm_power_dac(chip, PCM_FRONT_CHANNEL, 1);
        }
 }
 
index 85fd315d99990d6cba86001840d5cd7389975e2a..630aa499818947f79f0bd7aba8f750c3a4942de9 100644 (file)
@@ -676,28 +676,65 @@ static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata =
         I2C_VOLUME("Aux Capture Volume", 3),
 };
 
-#define SPI_SWITCH(xname,reg,bit) \
-{                                                              \
-       .iface  = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,    \
-       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,              \
-       .info   = spi_mute_info,                                \
-       .get    = spi_mute_get,                                 \
-       .put    = spi_mute_put,                                 \
-       .private_value = (reg<<SPI_REG_SHIFT) | (bit)           \
-}
-
-static struct snd_kcontrol_new snd_ca0106_volume_spi_dac_ctls[]
-__devinitdata = {
-       SPI_SWITCH("Analog Front Playback Switch",
-                  SPI_DMUTE4_REG, SPI_DMUTE4_BIT),
-       SPI_SWITCH("Analog Rear Playback Switch",
-                  SPI_DMUTE0_REG, SPI_DMUTE0_BIT),
-       SPI_SWITCH("Analog Center/LFE Playback Switch",
-                  SPI_DMUTE2_REG, SPI_DMUTE2_BIT),
-       SPI_SWITCH("Analog Side Playback Switch",
-                  SPI_DMUTE1_REG, SPI_DMUTE1_BIT),
+static const int spi_dmute_reg[] = {
+       SPI_DMUTE0_REG,
+       SPI_DMUTE1_REG,
+       SPI_DMUTE2_REG,
+       0,
+       SPI_DMUTE4_REG,
+};
+static const int spi_dmute_bit[] = {
+       SPI_DMUTE0_BIT,
+       SPI_DMUTE1_BIT,
+       SPI_DMUTE2_BIT,
+       0,
+       SPI_DMUTE4_BIT,
 };
 
+static struct snd_kcontrol_new __devinit
+snd_ca0106_volume_spi_dac_ctl(struct snd_ca0106_details *details,
+                             int channel_id)
+{
+       struct snd_kcontrol_new spi_switch = {0};
+       int reg, bit;
+       int dac_id;
+
+       spi_switch.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+       spi_switch.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+       spi_switch.info = spi_mute_info;
+       spi_switch.get = spi_mute_get;
+       spi_switch.put = spi_mute_put;
+
+       switch (channel_id) {
+       case PCM_FRONT_CHANNEL:
+               spi_switch.name = "Analog Front Playback Switch";
+               dac_id = (details->spi_dac & 0xf000) >> (4 * 3);
+               break;
+       case PCM_REAR_CHANNEL:
+               spi_switch.name = "Analog Rear Playback Switch";
+               dac_id = (details->spi_dac & 0x0f00) >> (4 * 2);
+               break;
+       case PCM_CENTER_LFE_CHANNEL:
+               spi_switch.name = "Analog Center/LFE Playback Switch";
+               dac_id = (details->spi_dac & 0x00f0) >> (4 * 1);
+               break;
+       case PCM_UNKNOWN_CHANNEL:
+               spi_switch.name = "Analog Side Playback Switch";
+               dac_id = (details->spi_dac & 0x000f) >> (4 * 0);
+               break;
+       default:
+               /* Unused channel */
+               spi_switch.name = NULL;
+               dac_id = 0;
+       }
+       reg = spi_dmute_reg[dac_id];
+       bit = spi_dmute_bit[dac_id];
+
+       spi_switch.private_value = (reg << SPI_REG_SHIFT) | bit;
+
+       return spi_switch;
+}
+
 static int __devinit remove_ctl(struct snd_card *card, const char *name)
 {
        struct snd_ctl_elem_id id;
@@ -832,8 +869,18 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
                if (err < 0)
                        return err;
        }
-       if (emu->details->spi_dac == 1)
-               ADD_CTLS(emu, snd_ca0106_volume_spi_dac_ctls);
+       if (emu->details->spi_dac) {
+               int i;
+               for (i = 0;; i++) {
+                       struct snd_kcontrol_new ctl;
+                       ctl = snd_ca0106_volume_spi_dac_ctl(emu->details, i);
+                       if (!ctl.name)
+                               break;
+                       err = snd_ctl_add(card, snd_ctl_new1(&ctl, emu));
+                       if (err < 0)
+                               return err;
+               }
+       }
 
        /* Create virtual master controls */
        vmaster = snd_ctl_make_virtual_master("Master Playback Volume",
@@ -845,7 +892,7 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
                return err;
        add_slaves(card, vmaster, slave_vols);
 
-       if (emu->details->spi_dac == 1) {
+       if (emu->details->spi_dac) {
                vmaster = snd_ctl_make_virtual_master("Master Playback Switch",
                                                      NULL);
                if (!vmaster)
index 8578c70c61f2b4ee15a7583c47641bd2405d4e78..bab564824efe11ebdf1160e81b568254c3a7fd1c 100644 (file)
@@ -321,7 +321,7 @@ static struct snd_rawmidi_ops snd_emu10k1_midi_input =
 
 static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi)
 {
-       struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)rmidi->private_data;
+       struct snd_emu10k1_midi *midi = rmidi->private_data;
        midi->interrupt = NULL;
        midi->rmidi = NULL;
 }
index 9194c3c1d04adf176a01ff91f3a8990327aab6fc..0ea5cc60ac782f1cd9d05161455b1e1a79d4cd85 100644 (file)
@@ -119,47 +119,20 @@ config SND_HDA_CODEC_VIA
          snd-hda-codec-via.
          This module is automatically loaded at probing.
 
-config SND_HDA_CODEC_ATIHDMI
-       bool "Build ATI HDMI HD-audio codec support"
-       default y
-       help
-         Say Y here to include ATI HDMI HD-audio codec support in
-         snd-hda-intel driver, such as ATI RS600 HDMI.
-
-         When the HD-audio driver is built as a module, the codec
-         support code is also built as another module,
-         snd-hda-codec-atihdmi.
-         This module is automatically loaded at probing.
-
-config SND_HDA_CODEC_NVHDMI
-       bool "Build NVIDIA HDMI HD-audio codec support"
-       default y
-       help
-         Say Y here to include NVIDIA HDMI HD-audio codec support in
-         snd-hda-intel driver, such as NVIDIA MCP78 HDMI.
-
-         When the HD-audio driver is built as a module, the codec
-         support code is also built as another module,
-         snd-hda-codec-nvhdmi.
-         This module is automatically loaded at probing.
-
-config SND_HDA_CODEC_INTELHDMI
-       bool "Build INTEL HDMI HD-audio codec support"
+config SND_HDA_CODEC_HDMI
+       bool "Build HDMI/DisplayPort HD-audio codec support"
        select SND_DYNAMIC_MINORS
        default y
        help
-         Say Y here to include INTEL HDMI HD-audio codec support in
-         snd-hda-intel driver, such as Eaglelake integrated HDMI.
+         Say Y here to include HDMI and DisplayPort HD-audio codec
+         support in snd-hda-intel driver.  This includes all AMD/ATI,
+         Intel and Nvidia HDMI/DisplayPort codecs.
 
          When the HD-audio driver is built as a module, the codec
          support code is also built as another module,
-         snd-hda-codec-intelhdmi.
+         snd-hda-codec-hdmi.
          This module is automatically loaded at probing.
 
-config SND_HDA_ELD
-       def_bool y
-       depends on SND_HDA_CODEC_INTELHDMI || SND_HDA_CODEC_NVHDMI
-
 config SND_HDA_CODEC_CIRRUS
        bool "Build Cirrus Logic codec support"
        depends on SND_HDA_INTEL
index 24bc195b02daef99fa675601712f04cfc6eb73e8..17ef3658f34b72d42d1deede9bc5f4efb1054a27 100644 (file)
@@ -3,7 +3,6 @@ snd-hda-intel-objs := hda_intel.o
 snd-hda-codec-y := hda_codec.o
 snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
 snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
-snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o
 snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
 snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
 
@@ -12,13 +11,11 @@ snd-hda-codec-cmedia-objs :=        patch_cmedia.o
 snd-hda-codec-analog-objs :=   patch_analog.o
 snd-hda-codec-idt-objs :=      patch_sigmatel.o
 snd-hda-codec-si3054-objs :=   patch_si3054.o
-snd-hda-codec-atihdmi-objs :=  patch_atihdmi.o
 snd-hda-codec-cirrus-objs :=   patch_cirrus.o
 snd-hda-codec-ca0110-objs :=   patch_ca0110.o
 snd-hda-codec-conexant-objs := patch_conexant.o
 snd-hda-codec-via-objs :=      patch_via.o
-snd-hda-codec-nvhdmi-objs :=   patch_nvhdmi.o
-snd-hda-codec-intelhdmi-objs :=        patch_intelhdmi.o
+snd-hda-codec-hdmi-objs :=     patch_hdmi.o hda_eld.o
 
 # common driver
 obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o
@@ -39,9 +36,6 @@ endif
 ifdef CONFIG_SND_HDA_CODEC_SI3054
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-si3054.o
 endif
-ifdef CONFIG_SND_HDA_CODEC_ATIHDMI
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o
-endif
 ifdef CONFIG_SND_HDA_CODEC_CIRRUS
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cirrus.o
 endif
@@ -54,11 +48,8 @@ endif
 ifdef CONFIG_SND_HDA_CODEC_VIA
 obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-via.o
 endif
-ifdef CONFIG_SND_HDA_CODEC_NVHDMI
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-nvhdmi.o
-endif
-ifdef CONFIG_SND_HDA_CODEC_INTELHDMI
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-intelhdmi.o
+ifdef CONFIG_SND_HDA_CODEC_HDMI
+obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-hdmi.o
 endif
 
 # this must be the last entry after codec drivers;
index 14829210ef0bf4b1bac018d4f5e31a1d1c4728b9..644e3f14f8ca5aea7af2e465450caab86d2f90cb 100644 (file)
@@ -1216,6 +1216,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
        struct hda_codec *c;
        struct hda_cvt_setup *p;
        unsigned int oldval, newval;
+       int type;
        int i;
 
        if (!nid)
@@ -1254,10 +1255,12 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
        p->dirty = 0;
 
        /* make other inactive cvts with the same stream-tag dirty */
+       type = get_wcaps_type(get_wcaps(codec, nid));
        list_for_each_entry(c, &codec->bus->codec_list, list) {
                for (i = 0; i < c->cvt_setups.used; i++) {
                        p = snd_array_elem(&c->cvt_setups, i);
-                       if (!p->active && p->stream_tag == stream_tag)
+                       if (!p->active && p->stream_tag == stream_tag &&
+                           get_wcaps_type(get_wcaps(codec, p->nid)) == type)
                                p->dirty = 1;
                }
        }
@@ -1281,6 +1284,9 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid,
        if (!nid)
                return;
 
+       if (codec->no_sticky_stream)
+               do_now = 1;
+
        snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid);
        p = get_hda_cvt_setup(codec, nid);
        if (p) {
@@ -1831,6 +1837,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
        hda_nid_t nid = get_amp_nid(kcontrol);
        int dir = get_amp_direction(kcontrol);
        unsigned int ofs = get_amp_offset(kcontrol);
+       bool min_mute = get_amp_min_mute(kcontrol);
        u32 caps, val1, val2;
 
        if (size < 4 * sizeof(unsigned int))
@@ -1841,6 +1848,8 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
        val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT);
        val1 += ofs;
        val1 = ((int)val1) * ((int)val2);
+       if (min_mute)
+               val2 |= TLV_DB_SCALE_MUTE;
        if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv))
                return -EFAULT;
        if (put_user(2 * sizeof(unsigned int), _tlv + 1))
@@ -2228,10 +2237,7 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
                change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
                                                   HDA_AMP_MUTE,
                                                   *valp ? 0 : HDA_AMP_MUTE);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (codec->patch_ops.check_power_status)
-               codec->patch_ops.check_power_status(codec, nid);
-#endif
+       hda_call_check_power_status(codec, nid);
        snd_hda_power_down(codec);
        return change;
 }
@@ -4372,6 +4378,34 @@ static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences,
 }
 
 
+/* add the found input-pin to the cfg->inputs[] table */
+static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid,
+                                  int type)
+{
+       if (cfg->num_inputs < AUTO_CFG_MAX_INS) {
+               cfg->inputs[cfg->num_inputs].pin = nid;
+               cfg->inputs[cfg->num_inputs].type = type;
+               cfg->num_inputs++;
+       }
+}
+
+/* sort inputs in the order of AUTO_PIN_* type */
+static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
+{
+       int i, j;
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               for (j = i + 1; j < cfg->num_inputs; j++) {
+                       if (cfg->inputs[i].type > cfg->inputs[j].type) {
+                               struct auto_pin_cfg_item tmp;
+                               tmp = cfg->inputs[i];
+                               cfg->inputs[i] = cfg->inputs[j];
+                               cfg->inputs[j] = tmp;
+                       }
+               }
+       }
+}
+
 /*
  * Parse all pin widgets and store the useful pin nids to cfg
  *
@@ -4385,7 +4419,7 @@ static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences,
  * output, i.e. to line_out_pins[0].  So, line_outs is always positive
  * if any analog output exists.
  *
- * The analog input pins are assigned to input_pins array.
+ * The analog input pins are assigned to inputs array.
  * The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
  * respectively.
  */
@@ -4398,6 +4432,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
        short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)];
        short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)];
        short sequences_hp[ARRAY_SIZE(cfg->hp_pins)];
+       int i;
 
        memset(cfg, 0, sizeof(*cfg));
 
@@ -4468,33 +4503,17 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                        sequences_hp[cfg->hp_outs] = (assoc << 4) | seq;
                        cfg->hp_outs++;
                        break;
-               case AC_JACK_MIC_IN: {
-                       int preferred, alt;
-                       if (loc == AC_JACK_LOC_FRONT ||
-                           (loc & 0x30) == AC_JACK_LOC_INTERNAL) {
-                               preferred = AUTO_PIN_FRONT_MIC;
-                               alt = AUTO_PIN_MIC;
-                       } else {
-                               preferred = AUTO_PIN_MIC;
-                               alt = AUTO_PIN_FRONT_MIC;
-                       }
-                       if (!cfg->input_pins[preferred])
-                               cfg->input_pins[preferred] = nid;
-                       else if (!cfg->input_pins[alt])
-                               cfg->input_pins[alt] = nid;
+               case AC_JACK_MIC_IN:
+                       add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC);
                        break;
-               }
                case AC_JACK_LINE_IN:
-                       if (loc == AC_JACK_LOC_FRONT)
-                               cfg->input_pins[AUTO_PIN_FRONT_LINE] = nid;
-                       else
-                               cfg->input_pins[AUTO_PIN_LINE] = nid;
+                       add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN);
                        break;
                case AC_JACK_CD:
-                       cfg->input_pins[AUTO_PIN_CD] = nid;
+                       add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD);
                        break;
                case AC_JACK_AUX:
-                       cfg->input_pins[AUTO_PIN_AUX] = nid;
+                       add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX);
                        break;
                case AC_JACK_SPDIF_OUT:
                case AC_JACK_DIG_OTHER_OUT:
@@ -4539,6 +4558,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                        memmove(sequences_hp + i, sequences_hp + i + 1,
                                sizeof(sequences_hp[0]) * (cfg->hp_outs - i));
                }
+               memset(cfg->hp_pins + cfg->hp_outs, 0,
+                      sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs));
        }
 
        /* sort by sequence */
@@ -4549,21 +4570,6 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
        sort_pins_by_sequence(cfg->hp_pins, sequences_hp,
                              cfg->hp_outs);
 
-       /* if we have only one mic, make it AUTO_PIN_MIC */
-       if (!cfg->input_pins[AUTO_PIN_MIC] &&
-           cfg->input_pins[AUTO_PIN_FRONT_MIC]) {
-               cfg->input_pins[AUTO_PIN_MIC] =
-                       cfg->input_pins[AUTO_PIN_FRONT_MIC];
-               cfg->input_pins[AUTO_PIN_FRONT_MIC] = 0;
-       }
-       /* ditto for line-in */
-       if (!cfg->input_pins[AUTO_PIN_LINE] &&
-           cfg->input_pins[AUTO_PIN_FRONT_LINE]) {
-               cfg->input_pins[AUTO_PIN_LINE] =
-                       cfg->input_pins[AUTO_PIN_FRONT_LINE];
-               cfg->input_pins[AUTO_PIN_FRONT_LINE] = 0;
-       }
-
        /*
         * FIX-UP: if no line-outs are detected, try to use speaker or HP pin
         * as a primary output
@@ -4602,6 +4608,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                break;
        }
 
+       sort_autocfg_input_pins(cfg);
+
        /*
         * debug prints of the parsed results
         */
@@ -4621,14 +4629,13 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
        if (cfg->dig_outs)
                snd_printd("   dig-out=0x%x/0x%x\n",
                           cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
-       snd_printd("   inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x,"
-                  " cd=0x%x, aux=0x%x\n",
-                  cfg->input_pins[AUTO_PIN_MIC],
-                  cfg->input_pins[AUTO_PIN_FRONT_MIC],
-                  cfg->input_pins[AUTO_PIN_LINE],
-                  cfg->input_pins[AUTO_PIN_FRONT_LINE],
-                  cfg->input_pins[AUTO_PIN_CD],
-                  cfg->input_pins[AUTO_PIN_AUX]);
+       snd_printd("   inputs:");
+       for (i = 0; i < cfg->num_inputs; i++) {
+               snd_printdd(" %s=0x%x",
+                           hda_get_autocfg_input_label(codec, cfg, i),
+                           cfg->inputs[i].pin);
+       }
+       snd_printd("\n");
        if (cfg->dig_in_pin)
                snd_printd("   dig-in=0x%x\n", cfg->dig_in_pin);
 
@@ -4636,11 +4643,165 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config);
 
-/* labels for input pins */
-const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = {
-       "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux"
-};
-EXPORT_SYMBOL_HDA(auto_pin_cfg_labels);
+int snd_hda_get_input_pin_attr(unsigned int def_conf)
+{
+       unsigned int loc = get_defcfg_location(def_conf);
+       unsigned int conn = get_defcfg_connect(def_conf);
+       if (conn == AC_JACK_PORT_NONE)
+               return INPUT_PIN_ATTR_UNUSED;
+       /* Windows may claim the internal mic to be BOTH, too */
+       if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH)
+               return INPUT_PIN_ATTR_INT;
+       if ((loc & 0x30) == AC_JACK_LOC_INTERNAL)
+               return INPUT_PIN_ATTR_INT;
+       if ((loc & 0x30) == AC_JACK_LOC_SEPARATE)
+               return INPUT_PIN_ATTR_DOCK;
+       if (loc == AC_JACK_LOC_REAR)
+               return INPUT_PIN_ATTR_REAR;
+       if (loc == AC_JACK_LOC_FRONT)
+               return INPUT_PIN_ATTR_FRONT;
+       return INPUT_PIN_ATTR_NORMAL;
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr);
+
+/**
+ * hda_get_input_pin_label - Give a label for the given input pin
+ *
+ * When check_location is true, the function checks the pin location
+ * for mic and line-in pins, and set an appropriate prefix like "Front",
+ * "Rear", "Internal".
+ */
+
+const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
+                                       int check_location)
+{
+       unsigned int def_conf;
+       static const char *mic_names[] = {
+               "Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic",
+       };
+       int attr;
+
+       def_conf = snd_hda_codec_get_pincfg(codec, pin);
+
+       switch (get_defcfg_device(def_conf)) {
+       case AC_JACK_MIC_IN:
+               if (!check_location)
+                       return "Mic";
+               attr = snd_hda_get_input_pin_attr(def_conf);
+               if (!attr)
+                       return "None";
+               return mic_names[attr - 1];
+       case AC_JACK_LINE_IN:
+               if (!check_location)
+                       return "Line";
+               attr = snd_hda_get_input_pin_attr(def_conf);
+               if (!attr)
+                       return "None";
+               if (attr == INPUT_PIN_ATTR_DOCK)
+                       return "Dock Line";
+               return "Line";
+       case AC_JACK_AUX:
+               return "Aux";
+       case AC_JACK_CD:
+               return "CD";
+       case AC_JACK_SPDIF_IN:
+               return "SPDIF In";
+       case AC_JACK_DIG_OTHER_IN:
+               return "Digital In";
+       default:
+               return "Misc";
+       }
+}
+EXPORT_SYMBOL_HDA(hda_get_input_pin_label);
+
+/* Check whether the location prefix needs to be added to the label.
+ * If all mic-jacks are in the same location (e.g. rear panel), we don't
+ * have to put "Front" prefix to each label.  In such a case, returns false.
+ */
+static int check_mic_location_need(struct hda_codec *codec,
+                                  const struct auto_pin_cfg *cfg,
+                                  int input)
+{
+       unsigned int defc;
+       int i, attr, attr2;
+
+       defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin);
+       attr = snd_hda_get_input_pin_attr(defc);
+       /* for internal or docking mics, we need locations */
+       if (attr <= INPUT_PIN_ATTR_NORMAL)
+               return 1;
+
+       attr = 0;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin);
+               attr2 = snd_hda_get_input_pin_attr(defc);
+               if (attr2 >= INPUT_PIN_ATTR_NORMAL) {
+                       if (attr && attr != attr2)
+                               return 1; /* different locations found */
+                       attr = attr2;
+               }
+       }
+       return 0;
+}
+
+/**
+ * hda_get_autocfg_input_label - Get a label for the given input
+ *
+ * Get a label for the given input pin defined by the autocfg item.
+ * Unlike hda_get_input_pin_label(), this function checks all inputs
+ * defined in autocfg and avoids the redundant mic/line prefix as much as
+ * possible.
+ */
+const char *hda_get_autocfg_input_label(struct hda_codec *codec,
+                                       const struct auto_pin_cfg *cfg,
+                                       int input)
+{
+       int type = cfg->inputs[input].type;
+       int has_multiple_pins = 0;
+
+       if ((input > 0 && cfg->inputs[input - 1].type == type) ||
+           (input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type))
+               has_multiple_pins = 1;
+       if (has_multiple_pins && type == AUTO_PIN_MIC)
+               has_multiple_pins &= check_mic_location_need(codec, cfg, input);
+       return hda_get_input_pin_label(codec, cfg->inputs[input].pin,
+                                      has_multiple_pins);
+}
+EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label);
+
+/**
+ * snd_hda_add_imux_item - Add an item to input_mux
+ *
+ * When the same label is used already in the existing items, the number
+ * suffix is appended to the label.  This label index number is stored
+ * to type_idx when non-NULL pointer is given.
+ */
+int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
+                         int index, int *type_idx)
+{
+       int i, label_idx = 0;
+       if (imux->num_items >= HDA_MAX_NUM_INPUTS) {
+               snd_printd(KERN_ERR "hda_codec: Too many imux items!\n");
+               return -EINVAL;
+       }
+       for (i = 0; i < imux->num_items; i++) {
+               if (!strncmp(label, imux->items[i].label, strlen(label)))
+                       label_idx++;
+       }
+       if (type_idx)
+               *type_idx = label_idx;
+       if (label_idx > 0)
+               snprintf(imux->items[imux->num_items].label,
+                        sizeof(imux->items[imux->num_items].label),
+                        "%s %d", label, label_idx);
+       else
+               strlcpy(imux->items[imux->num_items].label, label,
+                       sizeof(imux->items[imux->num_items].label));
+       imux->items[imux->num_items].index = index;
+       imux->num_items++;
+       return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_add_imux_item);
 
 
 #ifdef CONFIG_PM
index 62c70224010808dca1b7a8330e28dfa791bbe61e..fdf8d44f8b6b041fc4a9b1e0e63a31315a9fbe3b 100644 (file)
@@ -850,6 +850,7 @@ struct hda_codec {
        unsigned int pin_amp_workaround:1; /* pin out-amp takes index
                                            * (e.g. Conexant codecs)
                                            */
+       unsigned int no_sticky_stream:1; /* no sticky-PCM stream assignment */
        unsigned int pins_shutup:1;     /* pins are shut up */
        unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
 #ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -989,6 +990,18 @@ int snd_hda_suspend(struct hda_bus *bus);
 int snd_hda_resume(struct hda_bus *bus);
 #endif
 
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static inline
+int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
+{
+       if (codec->patch_ops.check_power_status)
+               return codec->patch_ops.check_power_status(codec, nid);
+       return 0;
+}
+#else  
+#define hda_call_check_power_status(codec, nid)                0
+#endif
+
 /*
  * get widget information
  */
index 26c3ade735838624c9f6d2ca889b4ca724df96db..cb0c23a6b473e07bd9d768f9430e7cde2342639c 100644 (file)
@@ -332,7 +332,6 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
        return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
                                                 AC_DIPSIZE_ELD_BUF);
 }
-EXPORT_SYMBOL_HDA(snd_hdmi_get_eld_size);
 
 int snd_hdmi_get_eld(struct hdmi_eld *eld,
                     struct hda_codec *codec, hda_nid_t nid)
@@ -368,7 +367,6 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
        kfree(buf);
        return ret;
 }
-EXPORT_SYMBOL_HDA(snd_hdmi_get_eld);
 
 static void hdmi_show_short_audio_desc(struct cea_sad *a)
 {
@@ -407,7 +405,6 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen)
        }
        buf[j] = '\0';  /* necessary when j == 0 */
 }
-EXPORT_SYMBOL_HDA(snd_print_channel_allocation);
 
 void snd_hdmi_show_eld(struct hdmi_eld *e)
 {
@@ -426,7 +423,6 @@ void snd_hdmi_show_eld(struct hdmi_eld *e)
        for (i = 0; i < e->sad_count; i++)
                hdmi_show_short_audio_desc(e->sad + i);
 }
-EXPORT_SYMBOL_HDA(snd_hdmi_show_eld);
 
 #ifdef CONFIG_PROC_FS
 
@@ -585,7 +581,6 @@ int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld,
 
        return 0;
 }
-EXPORT_SYMBOL_HDA(snd_hda_eld_proc_new);
 
 void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
 {
@@ -594,7 +589,6 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
                eld->proc_entry = NULL;
        }
 }
-EXPORT_SYMBOL_HDA(snd_hda_eld_proc_free);
 
 #endif /* CONFIG_PROC_FS */
 
@@ -645,4 +639,3 @@ void hdmi_eld_update_pcm_info(struct hdmi_eld *eld, struct hda_pcm_stream *pcm,
        pcm->channels_max = min(pcm->channels_max, codec_pars->channels_max);
        pcm->maxbps = min(pcm->maxbps, codec_pars->maxbps);
 }
-EXPORT_SYMBOL_HDA(hdmi_eld_update_pcm_info);
index 5ea21285ee1f6e700fa320b3710495e47f06aca7..fb0582f8d72503905566f3db047e4f8c65fc7f68 100644 (file)
@@ -61,7 +61,6 @@ struct hda_gspec {
        struct hda_gnode *cap_vol_node; /* Node for capture volume */
        unsigned int cur_cap_src;       /* current capture source */
        struct hda_input_mux input_mux;
-       char cap_labels[HDA_MAX_NUM_INPUTS][16];
 
        unsigned int def_amp_in_caps;
        unsigned int def_amp_out_caps;
@@ -506,11 +505,10 @@ static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl)
  * returns 0 if not found, 1 if found, or a negative error code.
  */
 static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
-                              struct hda_gnode *node)
+                              struct hda_gnode *node, int idx)
 {
        int i, err;
        unsigned int pinctl;
-       char *label;
        const char *type;
 
        if (node->checked)
@@ -523,7 +521,7 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
                        child = hda_get_node(spec, node->conn_list[i]);
                        if (! child)
                                continue;
-                       err = parse_adc_sub_nodes(codec, spec, child);
+                       err = parse_adc_sub_nodes(codec, spec, child, idx);
                        if (err < 0)
                                return err;
                        if (err > 0) {
@@ -564,9 +562,7 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
                        return 0;
                type = "Input";
        }
-       label = spec->cap_labels[spec->input_mux.num_items];
-       strcpy(label, type);
-       spec->input_mux.items[spec->input_mux.num_items].label = label;
+       snd_hda_add_imux_item(&spec->input_mux, type, idx, NULL);
 
        /* unmute the PIN external input */
        unmute_input(codec, node, 0); /* index = 0? */
@@ -577,29 +573,6 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec,
        return 1; /* found */
 }
 
-/* add a capture source element */
-static void add_cap_src(struct hda_gspec *spec, int idx)
-{
-       struct hda_input_mux_item *csrc;
-       char *buf;
-       int num, ocap;
-
-       num = spec->input_mux.num_items;
-       csrc = &spec->input_mux.items[num];
-       buf = spec->cap_labels[num];
-       for (ocap = 0; ocap < num; ocap++) {
-               if (! strcmp(buf, spec->cap_labels[ocap])) {
-                       /* same label already exists,
-                        * put the index number to be unique
-                        */
-                       sprintf(buf, "%s %d", spec->cap_labels[ocap], num);
-                       break;
-               }
-       }
-       csrc->index = idx;
-       spec->input_mux.num_items++;
-}
-
 /*
  * parse input
  */
@@ -624,22 +597,18 @@ static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node)
        for (i = 0; i < adc_node->nconns; i++) {
                node = hda_get_node(spec, adc_node->conn_list[i]);
                if (node && node->type == AC_WID_PIN) {
-                       err = parse_adc_sub_nodes(codec, spec, node);
+                       err = parse_adc_sub_nodes(codec, spec, node, i);
                        if (err < 0)
                                return err;
-                       else if (err > 0)
-                               add_cap_src(spec, i);
                }
        }
        /* ... then check the rests, more complicated connections */
        for (i = 0; i < adc_node->nconns; i++) {
                node = hda_get_node(spec, adc_node->conn_list[i]);
                if (node && node->type != AC_WID_PIN) {
-                       err = parse_adc_sub_nodes(codec, spec, node);
+                       err = parse_adc_sub_nodes(codec, spec, node, i);
                        if (err < 0)
                                return err;
-                       else if (err > 0)
-                               add_cap_src(spec, i);
                }
        }
 
index 34940a07905192590a056efe734e155d66f575f7..21aa9b0e28f6cb466a81a4d1e4c48622c71f89c9 100644 (file)
@@ -78,8 +78,8 @@ MODULE_PARM_DESC(enable, "Enable Intel HD audio interface.");
 module_param_array(model, charp, NULL, 0444);
 MODULE_PARM_DESC(model, "Use the given board model.");
 module_param_array(position_fix, int, NULL, 0444);
-MODULE_PARM_DESC(position_fix, "Fix DMA pointer "
-                "(0 = auto, 1 = none, 2 = POSBUF).");
+MODULE_PARM_DESC(position_fix, "DMA pointer read method."
+                "(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO).");
 module_param_array(bdl_pos_adj, int, NULL, 0644);
 MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
 module_param_array(probe_mask, int, NULL, 0444);
@@ -305,6 +305,7 @@ enum {
        POS_FIX_AUTO,
        POS_FIX_LPIB,
        POS_FIX_POSBUF,
+       POS_FIX_VIACOMBO,
 };
 
 /* Defines for ATI HD Audio support in SB450 south bridge */
@@ -433,7 +434,6 @@ struct azx {
        unsigned int polling_mode :1;
        unsigned int msi :1;
        unsigned int irq_pending_warned :1;
-       unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */
        unsigned int probing :1; /* codec probing phase */
 
        /* for debugging */
@@ -458,6 +458,7 @@ enum {
        AZX_DRIVER_ULI,
        AZX_DRIVER_NVIDIA,
        AZX_DRIVER_TERA,
+       AZX_DRIVER_CTX,
        AZX_DRIVER_GENERIC,
        AZX_NUM_DRIVERS, /* keep this as last entry */
 };
@@ -473,6 +474,7 @@ static char *driver_short_names[] __devinitdata = {
        [AZX_DRIVER_ULI] = "HDA ULI M5461",
        [AZX_DRIVER_NVIDIA] = "HDA NVidia",
        [AZX_DRIVER_TERA] = "HDA Teradici", 
+       [AZX_DRIVER_CTX] = "HDA Creative", 
        [AZX_DRIVER_GENERIC] = "HD-Audio Generic",
 };
 
@@ -563,7 +565,10 @@ static void azx_init_cmd_io(struct azx *chip)
        /* reset the rirb hw write pointer */
        azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST);
        /* set N=1, get RIRB response interrupt for new entry */
-       azx_writew(chip, RINTCNT, 1);
+       if (chip->driver_type == AZX_DRIVER_CTX)
+               azx_writew(chip, RINTCNT, 0xc0);
+       else
+               azx_writew(chip, RINTCNT, 1);
        /* enable rirb dma and response irq */
        azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
        spin_unlock_irq(&chip->reg_lock);
@@ -1136,8 +1141,11 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
        /* clear rirb int */
        status = azx_readb(chip, RIRBSTS);
        if (status & RIRB_INT_MASK) {
-               if (status & RIRB_INT_RESPONSE)
+               if (status & RIRB_INT_RESPONSE) {
+                       if (chip->driver_type == AZX_DRIVER_CTX)
+                               udelay(80);
                        azx_update_rirb(chip);
+               }
                azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
        }
 
@@ -1309,11 +1317,8 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
        azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr));
 
        /* enable the position buffer */
-       if (chip->position_fix[0] == POS_FIX_POSBUF ||
-           chip->position_fix[0] == POS_FIX_AUTO ||
-           chip->position_fix[1] == POS_FIX_POSBUF ||
-           chip->position_fix[1] == POS_FIX_AUTO ||
-           chip->via_dmapos_patch) {
+       if (chip->position_fix[0] != POS_FIX_LPIB ||
+           chip->position_fix[1] != POS_FIX_LPIB) {
                if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
                        azx_writel(chip, DPLBASE,
                                (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
@@ -1647,7 +1652,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
        struct azx_dev *azx_dev = get_azx_dev(substream);
        struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
        struct snd_pcm_runtime *runtime = substream->runtime;
-       unsigned int bufsize, period_bytes, format_val;
+       unsigned int bufsize, period_bytes, format_val, stream_tag;
        int err;
 
        azx_stream_reset(chip, azx_dev);
@@ -1689,7 +1694,12 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
        else
                azx_dev->fifo_size = 0;
 
-       return snd_hda_codec_prepare(apcm->codec, hinfo, azx_dev->stream_tag,
+       stream_tag = azx_dev->stream_tag;
+       /* CA-IBG chips need the playback stream starting from 1 */
+       if (chip->driver_type == AZX_DRIVER_CTX &&
+           stream_tag > chip->capture_streams)
+               stream_tag -= chip->capture_streams;
+       return snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag,
                                     azx_dev->format_val, substream);
 }
 
@@ -1852,20 +1862,21 @@ static unsigned int azx_get_position(struct azx *chip,
                                     struct azx_dev *azx_dev)
 {
        unsigned int pos;
+       int stream = azx_dev->substream->stream;
 
-       if (chip->via_dmapos_patch)
+       switch (chip->position_fix[stream]) {
+       case POS_FIX_LPIB:
+               /* read LPIB */
+               pos = azx_sd_readl(azx_dev, SD_LPIB);
+               break;
+       case POS_FIX_VIACOMBO:
                pos = azx_via_get_position(chip, azx_dev);
-       else {
-               int stream = azx_dev->substream->stream;
-               if (chip->position_fix[stream] == POS_FIX_POSBUF ||
-                   chip->position_fix[stream] == POS_FIX_AUTO) {
-                       /* use the position buffer */
-                       pos = le32_to_cpu(*azx_dev->posbuf);
-               } else {
-                       /* read LPIB */
-                       pos = azx_sd_readl(azx_dev, SD_LPIB);
-               }
+               break;
+       default:
+               /* use the position buffer */
+               pos = le32_to_cpu(*azx_dev->posbuf);
        }
+
        if (pos >= azx_dev->bufsize)
                pos = 0;
        return pos;
@@ -2313,19 +2324,10 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
        switch (fix) {
        case POS_FIX_LPIB:
        case POS_FIX_POSBUF:
+       case POS_FIX_VIACOMBO:
                return fix;
        }
 
-       /* Check VIA/ATI HD Audio Controller exist */
-       switch (chip->driver_type) {
-       case AZX_DRIVER_VIA:
-       case AZX_DRIVER_ATI:
-               chip->via_dmapos_patch = 1;
-               /* Use link position directly, avoid any transfer problem. */
-               return POS_FIX_LPIB;
-       }
-       chip->via_dmapos_patch = 0;
-
        q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
        if (q) {
                printk(KERN_INFO
@@ -2334,6 +2336,15 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
                       q->value, q->subvendor, q->subdevice);
                return q->value;
        }
+
+       /* Check VIA/ATI HD Audio Controller exist */
+       switch (chip->driver_type) {
+       case AZX_DRIVER_VIA:
+       case AZX_DRIVER_ATI:
+               /* Use link position directly, avoid any transfer problem. */
+               return POS_FIX_VIACOMBO;
+       }
+
        return POS_FIX_AUTO;
 }
 
@@ -2735,25 +2746,17 @@ static void __devexit azx_remove(struct pci_dev *pci)
 
 /* PCI IDs */
 static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
-       /* ICH 6..10 */
-       { PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH },
-       { PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH },
-       { PCI_DEVICE(0x8086, 0x269a), .driver_data = AZX_DRIVER_ICH },
-       { PCI_DEVICE(0x8086, 0x284b), .driver_data = AZX_DRIVER_ICH },
-       { PCI_DEVICE(0x8086, 0x2911), .driver_data = AZX_DRIVER_ICH },
-       { PCI_DEVICE(0x8086, 0x293e), .driver_data = AZX_DRIVER_ICH },
-       { PCI_DEVICE(0x8086, 0x293f), .driver_data = AZX_DRIVER_ICH },
-       { PCI_DEVICE(0x8086, 0x3a3e), .driver_data = AZX_DRIVER_ICH },
-       { PCI_DEVICE(0x8086, 0x3a6e), .driver_data = AZX_DRIVER_ICH },
-       /* PCH */
-       { PCI_DEVICE(0x8086, 0x3b56), .driver_data = AZX_DRIVER_ICH },
-       { PCI_DEVICE(0x8086, 0x3b57), .driver_data = AZX_DRIVER_ICH },
        /* CPT */
        { PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH },
        /* PBG */
        { PCI_DEVICE(0x8086, 0x1d20), .driver_data = AZX_DRIVER_PCH },
        /* SCH */
        { PCI_DEVICE(0x8086, 0x811b), .driver_data = AZX_DRIVER_SCH },
+       /* Generic Intel */
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
+         .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
+         .class_mask = 0xffffff,
+         .driver_data = AZX_DRIVER_ICH },
        /* ATI SB 450/600 */
        { PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI },
        { PCI_DEVICE(0x1002, 0x4383), .driver_data = AZX_DRIVER_ATI },
@@ -2794,11 +2797,13 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
          .class_mask = 0xffffff,
-         .driver_data = AZX_DRIVER_GENERIC },
+         .driver_data = AZX_DRIVER_CTX },
 #else
        /* this entry seems still valid -- i.e. without emu20kx chip */
-       { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_GENERIC },
+       { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_CTX },
 #endif
+       /* Vortex86MX */
+       { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
        /* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */
        { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
          .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
index 28ab4aead48fd17db36098f2eb36b306f4a5d534..46bbefe2e4a9465189d2341d42825f1439d17a40 100644 (file)
  */
 #define HDA_COMPOSE_AMP_VAL_OFS(nid,chs,idx,dir,ofs)           \
        ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19) | ((ofs)<<23))
+#define HDA_AMP_VAL_MIN_MUTE (1<<29)
 #define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \
        HDA_COMPOSE_AMP_VAL_OFS(nid, chs, idx, dir, 0)
 /* mono volume with index (index=0,1,...) (channel=1,2) */
-#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
+#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, dir, flags) \
        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx,  \
          .subdevice = HDA_SUBDEV_AMP_FLAG, \
          .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
          .get = snd_hda_mixer_amp_volume_get, \
          .put = snd_hda_mixer_amp_volume_put, \
          .tlv = { .c = snd_hda_mixer_amp_tlv },                \
-         .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) }
+         .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, dir) | flags }
 /* stereo volume with index */
 #define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \
-       HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, 3, xindex, direction)
+       HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, 3, xindex, direction, 0)
 /* mono volume */
 #define HDA_CODEC_VOLUME_MONO(xname, nid, channel, xindex, direction) \
-       HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, channel, xindex, direction)
+       HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, channel, xindex, direction, 0)
 /* stereo volume */
 #define HDA_CODEC_VOLUME(xname, nid, xindex, direction) \
        HDA_CODEC_VOLUME_MONO(xname, nid, 3, xindex, direction)
+/* stereo volume with min=mute */
+#define HDA_CODEC_VOLUME_MIN_MUTE(xname, nid, xindex, direction) \
+       HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, 3, xindex, direction, \
+                                 HDA_AMP_VAL_MIN_MUTE)
 /* mono mute switch with index (index=0,1,...) (channel=1,2) */
 #define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
        { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
@@ -215,7 +220,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid);
  */
 #define HDA_MAX_NUM_INPUTS     16
 struct hda_input_mux_item {
-       const char *label;
+       char label[32];
        unsigned int index;
 };
 struct hda_input_mux {
@@ -366,9 +371,7 @@ struct hda_bus_unsolicited {
 
 enum {
        AUTO_PIN_MIC,
-       AUTO_PIN_FRONT_MIC,
-       AUTO_PIN_LINE,
-       AUTO_PIN_FRONT_LINE,
+       AUTO_PIN_LINE_IN,
        AUTO_PIN_CD,
        AUTO_PIN_AUX,
        AUTO_PIN_LAST
@@ -380,9 +383,33 @@ enum {
        AUTO_PIN_HP_OUT
 };
 
-extern const char *auto_pin_cfg_labels[AUTO_PIN_LAST];
-
 #define AUTO_CFG_MAX_OUTS      5
+#define AUTO_CFG_MAX_INS       8
+
+struct auto_pin_cfg_item {
+       hda_nid_t pin;
+       int type;
+};
+
+struct auto_pin_cfg;
+const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
+                                   int check_location);
+const char *hda_get_autocfg_input_label(struct hda_codec *codec,
+                                       const struct auto_pin_cfg *cfg,
+                                       int input);
+int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
+                         int index, int *type_index_ret);
+
+enum {
+       INPUT_PIN_ATTR_UNUSED,  /* pin not connected */
+       INPUT_PIN_ATTR_INT,     /* internal mic/line-in */
+       INPUT_PIN_ATTR_DOCK,    /* docking mic/line-in */
+       INPUT_PIN_ATTR_NORMAL,  /* mic/line-in jack */
+       INPUT_PIN_ATTR_FRONT,   /* mic/line-in jack in front */
+       INPUT_PIN_ATTR_REAR,    /* mic/line-in jack in rear */
+};
+
+int snd_hda_get_input_pin_attr(unsigned int def_conf);
 
 struct auto_pin_cfg {
        int line_outs;
@@ -393,7 +420,8 @@ struct auto_pin_cfg {
        int hp_outs;
        int line_out_type;      /* AUTO_PIN_XXX_OUT */
        hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
-       hda_nid_t input_pins[AUTO_PIN_LAST];
+       int num_inputs;
+       struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS];
        int dig_outs;
        hda_nid_t dig_out_pins[2];
        hda_nid_t dig_in_pin;
@@ -558,6 +586,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
 #define get_amp_direction(kc)  (((kc)->private_value >> 18) & 0x1)
 #define get_amp_index(kc)      (((kc)->private_value >> 19) & 0xf)
 #define get_amp_offset(kc)     (((kc)->private_value >> 23) & 0x3f)
+#define get_amp_min_mute(kc)   (((kc)->private_value >> 29) & 0x1)
 
 /*
  * CEA Short Audio Descriptor data
index 10bbbaf6ebc3d2b0531ba2fb1ab7e3f2be1f8994..f7ff3f7ccb8e938e7f074afea766495907bc7e1e 100644 (file)
@@ -1276,6 +1276,7 @@ static int patch_ad1986a(struct hda_codec *codec)
        spec->multiout.no_share_stream = 1;
 
        codec->no_trigger_sense = 1;
+       codec->no_sticky_stream = 1;
 
        return 0;
 }
@@ -1463,6 +1464,7 @@ static int patch_ad1983(struct hda_codec *codec)
        codec->patch_ops = ad198x_patch_ops;
 
        codec->no_trigger_sense = 1;
+       codec->no_sticky_stream = 1;
 
        return 0;
 }
@@ -1917,6 +1919,7 @@ static int patch_ad1981(struct hda_codec *codec)
        }
 
        codec->no_trigger_sense = 1;
+       codec->no_sticky_stream = 1;
 
        return 0;
 }
@@ -2880,7 +2883,7 @@ static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
 
 /* create input playback/capture controls for the given pin */
 static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
-                           const char *ctlname, int boost)
+                           const char *ctlname, int ctlidx, int boost)
 {
        char name[32];
        int err, idx;
@@ -2909,25 +2912,27 @@ static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
 }
 
 /* create playback/capture controls for input pins */
-static int ad1988_auto_create_analog_input_ctls(struct ad198x_spec *spec,
+static int ad1988_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
+       struct ad198x_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux;
-       int i, err;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               err = new_analog_input(spec, cfg->input_pins[i],
-                                      auto_pin_cfg_labels[i],
-                                      i <= AUTO_PIN_FRONT_MIC);
+       int i, err, type, type_idx;
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               const char *label;
+               type = cfg->inputs[i].type;
+               label = hda_get_autocfg_input_label(codec, cfg, i);
+               snd_hda_add_imux_item(imux, label,
+                                     ad1988_pin_to_adc_idx(cfg->inputs[i].pin),
+                                     &type_idx);
+               err = new_analog_input(spec, cfg->inputs[i].pin,
+                                      label, type_idx,
+                                      type == AUTO_PIN_MIC);
                if (err < 0)
                        return err;
-               imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
-               imux->items[imux->num_items].index = ad1988_pin_to_adc_idx(cfg->input_pins[i]);
-               imux->num_items++;
        }
-       imux->items[imux->num_items].label = "Mix";
-       imux->items[imux->num_items].index = 9;
-       imux->num_items++;
+       snd_hda_add_imux_item(imux, "Mix", 9, NULL);
 
        if ((err = add_control(spec, AD_CTL_WIDGET_VOL,
                               "Analog Mix Playback Volume",
@@ -2994,12 +2999,11 @@ static void ad1988_auto_init_extra_out(struct hda_codec *codec)
 static void ad1988_auto_init_analog_input(struct hda_codec *codec)
 {
        struct ad198x_spec *spec = codec->spec;
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
        int i, idx;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = spec->autocfg.input_pins[i];
-               if (! nid)
-                       continue;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
                switch (nid) {
                case 0x15: /* port-C */
                        snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
@@ -3009,7 +3013,7 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec)
                        break;
                }
                snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                   i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN);
+                                   i == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN);
                if (nid != AD1988_PIN_CD_NID)
                        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
                                            AMP_OUT_MUTE);
@@ -3040,7 +3044,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
                                                "Speaker")) < 0 ||
            (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
                                                "Headphone")) < 0 ||
-           (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
+           (err = ad1988_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
                return err;
 
        spec->multiout.max_channels = spec->multiout.num_dacs * 2;
@@ -3235,6 +3239,7 @@ static int patch_ad1988(struct hda_codec *codec)
        spec->vmaster_nid = 0x04;
 
        codec->no_trigger_sense = 1;
+       codec->no_sticky_stream = 1;
 
        return 0;
 }
@@ -3449,6 +3454,7 @@ static int patch_ad1884(struct hda_codec *codec)
        codec->patch_ops = ad198x_patch_ops;
 
        codec->no_trigger_sense = 1;
+       codec->no_sticky_stream = 1;
 
        return 0;
 }
@@ -4422,6 +4428,7 @@ static int patch_ad1884a(struct hda_codec *codec)
        }
 
        codec->no_trigger_sense = 1;
+       codec->no_sticky_stream = 1;
 
        return 0;
 }
@@ -4761,6 +4768,7 @@ static int patch_ad1882(struct hda_codec *codec)
        }
 
        codec->no_trigger_sense = 1;
+       codec->no_sticky_stream = 1;
 
        return 0;
 }
diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c
deleted file mode 100644 (file)
index fb684f0..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Universal Interface for Intel High Definition Audio Codec
- *
- * HD audio interface patch for ATI HDMI codecs
- *
- * Copyright (c) 2006 ATI Technologies Inc.
- *
- *
- *  This driver 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 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 program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include "hda_codec.h"
-#include "hda_local.h"
-
-struct atihdmi_spec {
-       struct hda_multi_out multiout;
-
-       struct hda_pcm pcm_rec;
-};
-
-#define CVT_NID                0x02    /* audio converter */
-#define PIN_NID                0x03    /* HDMI output pin */
-
-static struct hda_verb atihdmi_basic_init[] = {
-       /* enable digital output on pin widget */
-       { 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
-       {} /* terminator */
-};
-
-/*
- * Controls
- */
-static int atihdmi_build_controls(struct hda_codec *codec)
-{
-       struct atihdmi_spec *spec = codec->spec;
-       int err;
-
-       err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
-       if (err < 0)
-               return err;
-
-       return 0;
-}
-
-static int atihdmi_init(struct hda_codec *codec)
-{
-       snd_hda_sequence_write(codec, atihdmi_basic_init);
-       /* SI codec requires to unmute the pin */
-       if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP)
-               snd_hda_codec_write(codec, PIN_NID, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE,
-                                   AMP_OUT_UNMUTE);
-       return 0;
-}
-
-/*
- * Digital out
- */
-static int atihdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
-                                    struct hda_codec *codec,
-                                    struct snd_pcm_substream *substream)
-{
-       struct atihdmi_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
-}
-
-static int atihdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
-                                     struct hda_codec *codec,
-                                     struct snd_pcm_substream *substream)
-{
-       struct atihdmi_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-static int atihdmi_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                           struct hda_codec *codec,
-                                           unsigned int stream_tag,
-                                           unsigned int format,
-                                           struct snd_pcm_substream *substream)
-{
-       struct atihdmi_spec *spec = codec->spec;
-       int chans = substream->runtime->channels;
-       int i, err;
-
-       err = snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
-                                           format, substream);
-       if (err < 0)
-               return err;
-       snd_hda_codec_write(codec, CVT_NID, 0, AC_VERB_SET_CVT_CHAN_COUNT,
-                           chans - 1);
-       /* FIXME: XXX */
-       for (i = 0; i < chans; i++) {
-               snd_hda_codec_write(codec, CVT_NID, 0,
-                                   AC_VERB_SET_HDMI_CHAN_SLOT,
-                                   (i << 4) | i);
-       }
-       return 0;
-}
-
-static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = CVT_NID, /* NID to query formats and rates and setup streams */
-       .ops = {
-               .open = atihdmi_dig_playback_pcm_open,
-               .close = atihdmi_dig_playback_pcm_close,
-               .prepare = atihdmi_dig_playback_pcm_prepare
-       },
-};
-
-static int atihdmi_build_pcms(struct hda_codec *codec)
-{
-       struct atihdmi_spec *spec = codec->spec;
-       struct hda_pcm *info = &spec->pcm_rec;
-       unsigned int chans;
-
-       codec->num_pcms = 1;
-       codec->pcm_info = info;
-
-       info->name = "ATI HDMI";
-       info->pcm_type = HDA_PCM_TYPE_HDMI;
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback;
-
-       /* FIXME: we must check ELD and change the PCM parameters dynamically
-        */
-       chans = get_wcaps(codec, CVT_NID);
-       chans = get_wcaps_channels(chans);
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
-
-       return 0;
-}
-
-static void atihdmi_free(struct hda_codec *codec)
-{
-       kfree(codec->spec);
-}
-
-static struct hda_codec_ops atihdmi_patch_ops = {
-       .build_controls = atihdmi_build_controls,
-       .build_pcms = atihdmi_build_pcms,
-       .init = atihdmi_init,
-       .free = atihdmi_free,
-};
-
-static int patch_atihdmi(struct hda_codec *codec)
-{
-       struct atihdmi_spec *spec;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
-
-       spec->multiout.num_dacs = 0;      /* no analog */
-       spec->multiout.max_channels = 2;
-       /* NID for copying analog to digital,
-        * seems to be unused in pure-digital
-        * case.
-        */
-       spec->multiout.dig_out_nid = CVT_NID;
-
-       codec->patch_ops = atihdmi_patch_ops;
-
-       return 0;
-}
-
-/*
- * patch entries
- */
-static struct hda_codec_preset snd_hda_preset_atihdmi[] = {
-       { .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 = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_atihdmi },
-       { .id = 0x17e80047, .name = "Chrontel HDMI",  .patch = patch_atihdmi },
-       {} /* terminator */
-};
-
-MODULE_ALIAS("snd-hda-codec-id:1002793c");
-MODULE_ALIAS("snd-hda-codec-id:10027919");
-MODULE_ALIAS("snd-hda-codec-id:1002791a");
-MODULE_ALIAS("snd-hda-codec-id:1002aa01");
-MODULE_ALIAS("snd-hda-codec-id:10951390");
-MODULE_ALIAS("snd-hda-codec-id:17e80047");
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("ATI HDMI HD-audio codec");
-
-static struct hda_codec_preset_list atihdmi_list = {
-       .preset = snd_hda_preset_atihdmi,
-       .owner = THIS_MODULE,
-};
-
-static int __init patch_atihdmi_init(void)
-{
-       return snd_hda_add_codec_preset(&atihdmi_list);
-}
-
-static void __exit patch_atihdmi_exit(void)
-{
-       snd_hda_delete_codec_preset(&atihdmi_list);
-}
-
-module_init(patch_atihdmi_init)
-module_exit(patch_atihdmi_exit)
index af478019088eea787528f115df7a5f7e4270f701..46c8bf48c31fb7c0dfeea8881d1ff4784697a564 100644 (file)
@@ -468,13 +468,13 @@ static void parse_input(struct hda_codec *codec)
                        spec->dig_in = nid;
                        continue;
                }
-               for (j = 0; j < AUTO_PIN_LAST; j++)
-                       if (cfg->input_pins[j] == pin)
+               for (j = 0; j < cfg->num_inputs; j++)
+                       if (cfg->inputs[j].pin == pin)
                                break;
-               if (j >= AUTO_PIN_LAST)
+               if (j >= cfg->num_inputs)
                        continue;
                spec->input_pins[n] = pin;
-               spec->input_labels[n] = auto_pin_cfg_labels[j];
+               spec->input_labels[n] = hda_get_input_pin_label(codec, pin, 1);
                spec->adcs[n] = nid;
                n++;
        }
@@ -489,7 +489,7 @@ static void parse_digital(struct hda_codec *codec)
        if (cfg->dig_outs &&
            snd_hda_get_connections(codec, cfg->dig_out_pins[0],
                                    &spec->dig_out, 1) == 1)
-               spec->multiout.dig_out_nid = cfg->dig_out_pins[0];
+               spec->multiout.dig_out_nid = spec->dig_out;
 }
 
 static int ca0110_parse_auto_config(struct hda_codec *codec)
index 488fd9ade1ba2bf7b306bf6e48ae106ef823294b..460fb2ef7e394614a4045a51d4306c429e818d6a 100644 (file)
@@ -65,6 +65,7 @@ struct cs_spec {
 
 /* available models */
 enum {
+       CS420X_MBP53,
        CS420X_MBP55,
        CS420X_IMAC27,
        CS420X_AUTO,
@@ -329,12 +330,12 @@ static int is_ext_mic(struct hda_codec *codec, unsigned int idx)
 {
        struct cs_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
-       hda_nid_t pin = cfg->input_pins[idx];
+       hda_nid_t pin = cfg->inputs[idx].pin;
        unsigned int val = snd_hda_query_pin_caps(codec, pin);
        if (!(val & AC_PINCAP_PRES_DETECT))
                return 0;
        val = snd_hda_codec_get_pincfg(codec, pin);
-       return (get_defcfg_connect(val) == AC_JACK_PORT_COMPLEX);
+       return (snd_hda_get_input_pin_attr(val) != INPUT_PIN_ATTR_INT);
 }
 
 static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin,
@@ -424,10 +425,8 @@ static int parse_input(struct hda_codec *codec)
        struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t pin = cfg->input_pins[i];
-               if (!pin)
-                       continue;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t pin = cfg->inputs[i].pin;
                spec->input_idx[spec->num_inputs] = i;
                spec->capsrc_idx[i] = spec->num_inputs++;
                spec->cur_input = i;
@@ -438,16 +437,17 @@ static int parse_input(struct hda_codec *codec)
 
        /* check whether the automatic mic switch is available */
        if (spec->num_inputs == 2 &&
-           spec->adc_nid[AUTO_PIN_MIC] && spec->adc_nid[AUTO_PIN_FRONT_MIC]) {
-               if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_FRONT_MIC])) {
-                       if (!is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) {
+           cfg->inputs[0].type == AUTO_PIN_MIC &&
+           cfg->inputs[1].type == AUTO_PIN_MIC) {
+               if (is_ext_mic(codec, cfg->inputs[0].pin)) {
+                       if (!is_ext_mic(codec, cfg->inputs[1].pin)) {
                                spec->mic_detect = 1;
-                               spec->automic_idx = AUTO_PIN_FRONT_MIC;
+                               spec->automic_idx = 0;
                        }
                } else {
-                       if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) {
+                       if (is_ext_mic(codec, cfg->inputs[1].pin)) {
                                spec->mic_detect = 1;
-                               spec->automic_idx = AUTO_PIN_MIC;
+                               spec->automic_idx = 1;
                        }
                }
        }
@@ -674,6 +674,7 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct cs_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
        unsigned int idx;
 
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
@@ -682,7 +683,8 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol,
        if (uinfo->value.enumerated.item >= spec->num_inputs)
                uinfo->value.enumerated.item = spec->num_inputs - 1;
        idx = spec->input_idx[uinfo->value.enumerated.item];
-       strcpy(uinfo->value.enumerated.name, auto_pin_cfg_labels[idx]);
+       strcpy(uinfo->value.enumerated.name,
+              hda_get_input_pin_label(codec, cfg->inputs[idx].pin, 1));
        return 0;
 }
 
@@ -740,6 +742,27 @@ static struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec,
        return bind;
 }
 
+/* add a (input-boost) volume control to the given input pin */
+static int add_input_volume_control(struct hda_codec *codec,
+                                   struct auto_pin_cfg *cfg,
+                                   int item)
+{
+       hda_nid_t pin = cfg->inputs[item].pin;
+       u32 caps;
+       const char *label;
+       struct snd_kcontrol *kctl;
+               
+       if (!(get_wcaps(codec, pin) & AC_WCAP_IN_AMP))
+               return 0;
+       caps = query_amp_caps(codec, pin, HDA_INPUT);
+       caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
+       if (caps <= 1)
+               return 0;
+       label = hda_get_autocfg_input_label(codec, cfg, item);
+       return add_volume(codec, label, 0,
+                         HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT), 1, &kctl);
+}
+
 static int build_input(struct hda_codec *codec)
 {
        struct cs_spec *spec = codec->spec;
@@ -779,6 +802,12 @@ static int build_input(struct hda_codec *codec)
                        return err;
        }
 
+       for (i = 0; i < spec->num_inputs; i++) {
+               err = add_input_volume_control(codec, &spec->autocfg, i);
+               if (err < 0)
+                       return err;
+       }
+
        return 0;
 }
 
@@ -838,7 +867,8 @@ static void cs_automute(struct hda_codec *codec)
                                    AC_VERB_SET_PIN_WIDGET_CONTROL,
                                    hp_present ? 0 : PIN_OUT);
        }
-       if (spec->board_config == CS420X_MBP55 ||
+       if (spec->board_config == CS420X_MBP53 ||
+           spec->board_config == CS420X_MBP55 ||
            spec->board_config == CS420X_IMAC27) {
                unsigned int gpio = hp_present ? 0x02 : 0x08;
                snd_hda_codec_write(codec, 0x01, 0,
@@ -853,15 +883,12 @@ static void cs_automic(struct hda_codec *codec)
        hda_nid_t nid;
        unsigned int present;
        
-       nid = cfg->input_pins[spec->automic_idx];
+       nid = cfg->inputs[spec->automic_idx].pin;
        present = snd_hda_jack_detect(codec, nid);
        if (present)
                change_cur_input(codec, spec->automic_idx, 0);
-       else {
-               unsigned int imic = (spec->automic_idx == AUTO_PIN_MIC) ?
-                       AUTO_PIN_FRONT_MIC : AUTO_PIN_MIC;
-               change_cur_input(codec, imic, 0);
-       }
+       else
+               change_cur_input(codec, !spec->automic_idx, 0);
 }
 
 /*
@@ -918,14 +945,14 @@ static void init_input(struct hda_codec *codec)
        unsigned int coef;
        int i;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
+       for (i = 0; i < cfg->num_inputs; i++) {
                unsigned int ctl;
-               hda_nid_t pin = cfg->input_pins[i];
-               if (!pin || !spec->adc_nid[i])
+               hda_nid_t pin = cfg->inputs[i].pin;
+               if (!spec->adc_nid[i])
                        continue;
                /* set appropriate pin control and mute first */
                ctl = PIN_IN;
-               if (i <= AUTO_PIN_FRONT_MIC) {
+               if (cfg->inputs[i].type == AUTO_PIN_MIC) {
                        unsigned int caps = snd_hda_query_pin_caps(codec, pin);
                        caps >>= AC_PINCAP_VREF_SHIFT;
                        if (caps & AC_PINCAP_VREF_80)
@@ -1130,6 +1157,7 @@ static int cs_parse_auto_config(struct hda_codec *codec)
 }
 
 static const char *cs420x_models[CS420X_MODELS] = {
+       [CS420X_MBP53] = "mbp53",
        [CS420X_MBP55] = "mbp55",
        [CS420X_IMAC27] = "imac27",
        [CS420X_AUTO] = "auto",
@@ -1137,7 +1165,9 @@ static const char *cs420x_models[CS420X_MODELS] = {
 
 
 static struct snd_pci_quirk cs420x_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
        SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
+       SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
        SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),
        {} /* terminator */
 };
@@ -1147,6 +1177,20 @@ struct cs_pincfg {
        u32 val;
 };
 
+static struct cs_pincfg mbp53_pincfgs[] = {
+       { 0x09, 0x012b4050 },
+       { 0x0a, 0x90100141 },
+       { 0x0b, 0x90100140 },
+       { 0x0c, 0x018b3020 },
+       { 0x0d, 0x90a00110 },
+       { 0x0e, 0x400000f0 },
+       { 0x0f, 0x01cbe030 },
+       { 0x10, 0x014be060 },
+       { 0x12, 0x400000f0 },
+       { 0x15, 0x400000f0 },
+       {} /* terminator */
+};
+
 static struct cs_pincfg mbp55_pincfgs[] = {
        { 0x09, 0x012b4030 },
        { 0x0a, 0x90100121 },
@@ -1176,6 +1220,7 @@ static struct cs_pincfg imac27_pincfgs[] = {
 };
 
 static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = {
+       [CS420X_MBP53] = mbp53_pincfgs,
        [CS420X_MBP55] = mbp55_pincfgs,
        [CS420X_IMAC27] = imac27_pincfgs,
 };
@@ -1208,6 +1253,7 @@ static int patch_cs420x(struct hda_codec *codec)
 
        switch (spec->board_config) {
        case CS420X_IMAC27:
+       case CS420X_MBP53:
        case CS420X_MBP55:
                /* GPIO1 = headphones */
                /* GPIO3 = speakers */
index 972e7c453b3d6c8320d58b6aebe6ef41fc259920..6361f752b5f35cfddff7f8423f0d5d185a9003d8 100644 (file)
@@ -57,6 +57,12 @@ struct conexant_jack {
 
 };
 
+struct pin_dac_pair {
+       hda_nid_t pin;
+       hda_nid_t dac;
+       int type;
+};
+
 struct conexant_spec {
 
        struct snd_kcontrol_new *mixers[5];
@@ -77,6 +83,7 @@ struct conexant_spec {
        unsigned int cur_eapd;
        unsigned int hp_present;
        unsigned int auto_mic;
+       int auto_mic_ext;               /* autocfg.inputs[] index for ext mic */
        unsigned int need_dac_fix;
 
        /* capture */
@@ -110,9 +117,12 @@ struct conexant_spec {
        struct auto_pin_cfg autocfg;
        struct hda_input_mux private_imux;
        hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
+       struct pin_dac_pair dac_info[8];
+       int dac_info_filled;
 
-       unsigned int dell_automute;
        unsigned int port_d_mode;
+       unsigned int auto_mute:1;       /* used in auto-parser */
+       unsigned int dell_automute:1;
        unsigned int dell_vostro:1;
        unsigned int ideapad:1;
        unsigned int thinkpad:1;
@@ -3065,7 +3075,7 @@ enum {
        CXT5066_LAPTOP,         /* Laptops w/ EAPD support */
        CXT5066_DELL_LAPTOP,    /* Dell Laptop */
        CXT5066_OLPC_XO_1_5,    /* OLPC XO 1.5 */
-       CXT5066_DELL_VOSTO,     /* Dell Vostro 1015i */
+       CXT5066_DELL_VOSTRO,    /* Dell Vostro 1015i */
        CXT5066_IDEAPAD,        /* Lenovo IdeaPad U150 */
        CXT5066_THINKPAD,       /* Lenovo ThinkPad T410s, others? */
        CXT5066_HP_LAPTOP,      /* HP Laptop */
@@ -3076,25 +3086,26 @@ static const char *cxt5066_models[CXT5066_MODELS] = {
        [CXT5066_LAPTOP]        = "laptop",
        [CXT5066_DELL_LAPTOP]   = "dell-laptop",
        [CXT5066_OLPC_XO_1_5]   = "olpc-xo-1_5",
-       [CXT5066_DELL_VOSTO]    = "dell-vostro",
+       [CXT5066_DELL_VOSTRO]   = "dell-vostro",
        [CXT5066_IDEAPAD]       = "ideapad",
        [CXT5066_THINKPAD]      = "thinkpad",
        [CXT5066_HP_LAPTOP]     = "hp-laptop",
 };
 
 static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
-                     CXT5066_LAPTOP),
+       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",
                      CXT5066_DELL_LAPTOP),
-       SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
-       SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTO),
-       SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO),
+       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),
        SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5),
        SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5),
+       SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
+                     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, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD),
@@ -3196,7 +3207,7 @@ static int patch_cxt5066(struct hda_codec *codec)
                spec->capture_prepare = cxt5066_olpc_capture_prepare;
                spec->capture_cleanup = cxt5066_olpc_capture_cleanup;
                break;
-       case CXT5066_DELL_VOSTO:
+       case CXT5066_DELL_VOSTRO:
                codec->patch_ops.init = cxt5066_init;
                codec->patch_ops.unsol_event = cxt5066_vostro_event;
                spec->init_verbs[0] = cxt5066_init_verbs_vostro;
@@ -3253,6 +3264,604 @@ static int patch_cxt5066(struct hda_codec *codec)
        return 0;
 }
 
+/*
+ * Automatic parser for CX20641 & co
+ */
+
+static hda_nid_t cx_auto_adc_nids[] = { 0x14 };
+
+/* get the connection index of @nid in the widget @mux */
+static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
+                               hda_nid_t nid)
+{
+       hda_nid_t conn[HDA_MAX_NUM_INPUTS];
+       int i, nums;
+
+       nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
+       for (i = 0; i < nums; i++)
+               if (conn[i] == nid)
+                       return i;
+       return -1;
+}
+
+/* get an unassigned DAC from the given list.
+ * Return the nid if found and reduce the DAC list, or return zero if
+ * not found
+ */
+static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t pin,
+                                   hda_nid_t *dacs, int *num_dacs)
+{
+       int i, nums = *num_dacs;
+       hda_nid_t ret = 0;
+
+       for (i = 0; i < nums; i++) {
+               if (get_connection_index(codec, pin, dacs[i]) >= 0) {
+                       ret = dacs[i];
+                       break;
+               }
+       }
+       if (!ret)
+               return 0;
+       if (--nums > 0)
+               memmove(dacs, dacs + 1, nums * sizeof(hda_nid_t));
+       *num_dacs = nums;
+       return ret;
+}
+
+#define MAX_AUTO_DACS  5
+
+/* fill analog DAC list from the widget tree */
+static int fill_cx_auto_dacs(struct hda_codec *codec, hda_nid_t *dacs)
+{
+       hda_nid_t nid, end_nid;
+       int nums = 0;
+
+       end_nid = codec->start_nid + codec->num_nodes;
+       for (nid = codec->start_nid; nid < end_nid; nid++) {
+               unsigned int wcaps = get_wcaps(codec, nid);
+               unsigned int type = get_wcaps_type(wcaps);
+               if (type == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL)) {
+                       dacs[nums++] = nid;
+                       if (nums >= MAX_AUTO_DACS)
+                               break;
+               }
+       }
+       return nums;
+}
+
+/* fill pin_dac_pair list from the pin and dac list */
+static int fill_dacs_for_pins(struct hda_codec *codec, hda_nid_t *pins,
+                             int num_pins, hda_nid_t *dacs, int *rest,
+                             struct pin_dac_pair *filled, int type)
+{
+       int i, nums;
+
+       nums = 0;
+       for (i = 0; i < num_pins; i++) {
+               filled[nums].pin = pins[i];
+               filled[nums].type = type;
+               filled[nums].dac = get_unassigned_dac(codec, pins[i], dacs, rest);
+               nums++;
+       }
+       return nums;
+}
+
+/* parse analog output paths */
+static void cx_auto_parse_output(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       hda_nid_t dacs[MAX_AUTO_DACS];
+       int i, j, nums, rest;
+
+       rest = fill_cx_auto_dacs(codec, dacs);
+       /* parse all analog output pins */
+       nums = fill_dacs_for_pins(codec, cfg->line_out_pins, cfg->line_outs,
+                                 dacs, &rest, spec->dac_info,
+                                 AUTO_PIN_LINE_OUT);
+       nums += fill_dacs_for_pins(codec, cfg->hp_pins, cfg->hp_outs,
+                                 dacs, &rest, spec->dac_info + nums,
+                                 AUTO_PIN_HP_OUT);
+       nums += fill_dacs_for_pins(codec, cfg->speaker_pins, cfg->speaker_outs,
+                                 dacs, &rest, spec->dac_info + nums,
+                                 AUTO_PIN_SPEAKER_OUT);
+       spec->dac_info_filled = nums;
+       /* fill multiout struct */
+       for (i = 0; i < nums; i++) {
+               hda_nid_t dac = spec->dac_info[i].dac;
+               if (!dac)
+                       continue;
+               switch (spec->dac_info[i].type) {
+               case AUTO_PIN_LINE_OUT:
+                       spec->private_dac_nids[spec->multiout.num_dacs] = dac;
+                       spec->multiout.num_dacs++;
+                       break;
+               case AUTO_PIN_HP_OUT:
+               case AUTO_PIN_SPEAKER_OUT:
+                       if (!spec->multiout.hp_nid) {
+                               spec->multiout.hp_nid = dac;
+                               break;
+                       }
+                       for (j = 0; j < ARRAY_SIZE(spec->multiout.extra_out_nid); j++)
+                               if (!spec->multiout.extra_out_nid[j]) {
+                                       spec->multiout.extra_out_nid[j] = dac;
+                                       break;
+                               }
+                       break;
+               }
+       }
+       spec->multiout.dac_nids = spec->private_dac_nids;
+       spec->multiout.max_channels = nums * 2;
+
+       if (cfg->hp_outs > 0)
+               spec->auto_mute = 1;
+       spec->vmaster_nid = spec->private_dac_nids[0];
+}
+
+/* auto-mute/unmute speaker and line outs according to headphone jack */
+static void cx_auto_hp_automute(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i, present;
+
+       if (!spec->auto_mute)
+               return;
+       present = 0;
+       for (i = 0; i < cfg->hp_outs; i++) {
+               if (snd_hda_jack_detect(codec, cfg->hp_pins[i])) {
+                       present = 1;
+                       break;
+               }
+       }
+       for (i = 0; i < cfg->line_outs; i++) {
+               snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                   present ? 0 : PIN_OUT);
+       }
+       for (i = 0; i < cfg->speaker_outs; i++) {
+               snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                   present ? 0 : PIN_OUT);
+       }
+}
+
+/* automatic switch internal and external mic */
+static void cx_auto_automic(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       struct hda_input_mux *imux = &spec->private_imux;
+       int ext_idx = spec->auto_mic_ext;
+
+       if (!spec->auto_mic)
+               return;
+       if (snd_hda_jack_detect(codec, cfg->inputs[ext_idx].pin)) {
+               snd_hda_codec_write(codec, spec->adc_nids[0], 0,
+                                   AC_VERB_SET_CONNECT_SEL,
+                                   imux->items[ext_idx].index);
+       } else {
+               snd_hda_codec_write(codec, spec->adc_nids[0], 0,
+                                   AC_VERB_SET_CONNECT_SEL,
+                                   imux->items[!ext_idx].index);
+       }
+}
+
+static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+       int nid = (res & AC_UNSOL_RES_SUBTAG) >> 20;
+       switch (res >> 26) {
+       case CONEXANT_HP_EVENT:
+               cx_auto_hp_automute(codec);
+               conexant_report_jack(codec, nid);
+               break;
+       case CONEXANT_MIC_EVENT:
+               cx_auto_automic(codec);
+               conexant_report_jack(codec, nid);
+               break;
+       }
+}
+
+/* return true if it's an internal-mic pin */
+static int is_int_mic(struct hda_codec *codec, hda_nid_t pin)
+{
+       unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin);
+       return get_defcfg_device(def_conf) == AC_JACK_MIC_IN &&
+               snd_hda_get_input_pin_attr(def_conf) == INPUT_PIN_ATTR_INT;
+}
+
+/* return true if it's an external-mic pin */
+static int is_ext_mic(struct hda_codec *codec, hda_nid_t pin)
+{
+       unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin);
+       return get_defcfg_device(def_conf) == AC_JACK_MIC_IN &&
+               snd_hda_get_input_pin_attr(def_conf) >= INPUT_PIN_ATTR_NORMAL &&
+               (snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_PRES_DETECT);
+}
+
+/* check whether the pin config is suitable for auto-mic switching;
+ * auto-mic is enabled only when one int-mic and one-ext mic exist
+ */
+static void cx_auto_check_auto_mic(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+
+       if (is_ext_mic(codec, cfg->inputs[0].pin) &&
+           is_int_mic(codec, cfg->inputs[1].pin)) {
+               spec->auto_mic = 1;
+               spec->auto_mic_ext = 1;
+               return;
+       }
+       if (is_int_mic(codec, cfg->inputs[1].pin) &&
+           is_ext_mic(codec, cfg->inputs[0].pin)) {
+               spec->auto_mic = 1;
+               spec->auto_mic_ext = 0;
+               return;
+       }
+}
+
+static void cx_auto_parse_input(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       struct hda_input_mux *imux;
+       int i;
+
+       imux = &spec->private_imux;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               int idx = get_connection_index(codec, spec->adc_nids[0],
+                                              cfg->inputs[i].pin);
+               if (idx >= 0) {
+                       const char *label;
+                       label = hda_get_autocfg_input_label(codec, cfg, i);
+                       snd_hda_add_imux_item(imux, label, idx, NULL);
+               }
+       }
+       if (imux->num_items == 2 && cfg->num_inputs == 2)
+               cx_auto_check_auto_mic(codec);
+       if (imux->num_items > 1 && !spec->auto_mic)
+               spec->input_mux = imux;
+}
+
+/* get digital-input audio widget corresponding to the given pin */
+static hda_nid_t cx_auto_get_dig_in(struct hda_codec *codec, hda_nid_t pin)
+{
+       hda_nid_t nid, end_nid;
+
+       end_nid = codec->start_nid + codec->num_nodes;
+       for (nid = codec->start_nid; nid < end_nid; nid++) {
+               unsigned int wcaps = get_wcaps(codec, nid);
+               unsigned int type = get_wcaps_type(wcaps);
+               if (type == AC_WID_AUD_IN && (wcaps & AC_WCAP_DIGITAL)) {
+                       if (get_connection_index(codec, nid, pin) >= 0)
+                               return nid;
+               }
+       }
+       return 0;
+}
+
+static void cx_auto_parse_digital(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       hda_nid_t nid;
+
+       if (cfg->dig_outs &&
+           snd_hda_get_connections(codec, cfg->dig_out_pins[0], &nid, 1) == 1)
+               spec->multiout.dig_out_nid = nid;
+       if (cfg->dig_in_pin)
+               spec->dig_in_nid = cx_auto_get_dig_in(codec, cfg->dig_in_pin);
+}
+
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+static void cx_auto_parse_beep(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       hda_nid_t nid, end_nid;
+
+       end_nid = codec->start_nid + codec->num_nodes;
+       for (nid = codec->start_nid; nid < end_nid; nid++)
+               if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) {
+                       set_beep_amp(spec, nid, 0, HDA_OUTPUT);
+                       break;
+               }
+}
+#else
+#define cx_auto_parse_beep(codec)
+#endif
+
+static int cx_auto_parse_auto_config(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       int err;
+
+       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+       if (err < 0)
+               return err;
+
+       cx_auto_parse_output(codec);
+       cx_auto_parse_input(codec);
+       cx_auto_parse_digital(codec);
+       cx_auto_parse_beep(codec);
+       return 0;
+}
+
+static void cx_auto_turn_on_eapd(struct hda_codec *codec, int num_pins,
+                                hda_nid_t *pins)
+{
+       int i;
+       for (i = 0; i < num_pins; i++) {
+               if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD)
+                       snd_hda_codec_write(codec, pins[i], 0,
+                                           AC_VERB_SET_EAPD_BTLENABLE, 0x02);
+       }
+}
+
+static void select_connection(struct hda_codec *codec, hda_nid_t pin,
+                             hda_nid_t src)
+{
+       int idx = get_connection_index(codec, pin, src);
+       if (idx >= 0)
+               snd_hda_codec_write(codec, pin, 0,
+                                   AC_VERB_SET_CONNECT_SEL, idx);
+}
+
+static void cx_auto_init_output(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       hda_nid_t nid;
+       int i;
+
+       for (i = 0; i < spec->multiout.num_dacs; i++)
+               snd_hda_codec_write(codec, spec->multiout.dac_nids[i], 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+       for (i = 0; i < cfg->hp_outs; i++)
+               snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+       if (spec->auto_mute) {
+               for (i = 0; i < cfg->hp_outs; i++) {
+                       snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
+                                   AC_VERB_SET_UNSOLICITED_ENABLE,
+                                   AC_USRSP_EN | CONEXANT_HP_EVENT);
+               }
+               cx_auto_hp_automute(codec);
+       } else {
+               for (i = 0; i < cfg->line_outs; i++)
+                       snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+               for (i = 0; i < cfg->speaker_outs; i++)
+                       snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+       }
+
+       for (i = 0; i < spec->dac_info_filled; i++) {
+               nid = spec->dac_info[i].dac;
+               if (!nid)
+                       nid = spec->multiout.dac_nids[0];
+               select_connection(codec, spec->dac_info[i].pin, nid);
+       }
+
+       /* turn on EAPD */
+       cx_auto_turn_on_eapd(codec, cfg->line_outs, cfg->line_out_pins);
+       cx_auto_turn_on_eapd(codec, cfg->hp_outs, cfg->hp_pins);
+       cx_auto_turn_on_eapd(codec, cfg->speaker_outs, cfg->speaker_pins);
+}
+
+static void cx_auto_init_input(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
+
+       for (i = 0; i < spec->num_adc_nids; i++)
+               snd_hda_codec_write(codec, spec->adc_nids[i], 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0));
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               unsigned int type;
+               if (cfg->inputs[i].type == AUTO_PIN_MIC)
+                       type = PIN_VREF80;
+               else
+                       type = PIN_IN;
+               snd_hda_codec_write(codec, cfg->inputs[i].pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, type);
+       }
+
+       if (spec->auto_mic) {
+               int ext_idx = spec->auto_mic_ext;
+               snd_hda_codec_write(codec, cfg->inputs[ext_idx].pin, 0,
+                                   AC_VERB_SET_UNSOLICITED_ENABLE,
+                                   AC_USRSP_EN | CONEXANT_MIC_EVENT);
+               cx_auto_automic(codec);
+       } else {
+               for (i = 0; i < spec->num_adc_nids; i++) {
+                       snd_hda_codec_write(codec, spec->adc_nids[i], 0,
+                                           AC_VERB_SET_CONNECT_SEL,
+                                           spec->private_imux.items[0].index);
+               }
+       }
+}
+
+static void cx_auto_init_digital(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+
+       if (spec->multiout.dig_out_nid)
+               snd_hda_codec_write(codec, cfg->dig_out_pins[0], 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+       if (spec->dig_in_nid)
+               snd_hda_codec_write(codec, cfg->dig_in_pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
+}
+
+static int cx_auto_init(struct hda_codec *codec)
+{
+       /*snd_hda_sequence_write(codec, cx_auto_init_verbs);*/
+       cx_auto_init_output(codec);
+       cx_auto_init_input(codec);
+       cx_auto_init_digital(codec);
+       return 0;
+}
+
+static int cx_auto_add_volume(struct hda_codec *codec, const char *basename,
+                             const char *dir, int cidx,
+                             hda_nid_t nid, int hda_dir)
+{
+       static char name[32];
+       static struct snd_kcontrol_new knew[] = {
+               HDA_CODEC_VOLUME(name, 0, 0, 0),
+               HDA_CODEC_MUTE(name, 0, 0, 0),
+       };
+       static char *sfx[2] = { "Volume", "Switch" };
+       int i, err;
+
+       for (i = 0; i < 2; i++) {
+               struct snd_kcontrol *kctl;
+               knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, hda_dir);
+               knew[i].subdevice = HDA_SUBDEV_AMP_FLAG;
+               knew[i].index = cidx;
+               snprintf(name, sizeof(name), "%s%s %s", basename, dir, sfx[i]);
+               kctl = snd_ctl_new1(&knew[i], codec);
+               if (!kctl)
+                       return -ENOMEM;
+               err = snd_hda_ctl_add(codec, nid, kctl);
+               if (err < 0)
+                       return err;
+               if (!(query_amp_caps(codec, nid, hda_dir) & AC_AMPCAP_MUTE))
+                       break;
+       }
+       return 0;
+}
+
+#define cx_auto_add_pb_volume(codec, nid, str, idx)                    \
+       cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
+
+static int cx_auto_build_output_controls(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       int i, err;
+       int num_line = 0, num_hp = 0, num_spk = 0;
+       static const char *texts[3] = { "Front", "Surround", "CLFE" };
+
+       if (spec->dac_info_filled == 1)
+               return cx_auto_add_pb_volume(codec, spec->dac_info[0].dac,
+                                            "Master", 0);
+       for (i = 0; i < spec->dac_info_filled; i++) {
+               const char *label;
+               int idx, type;
+               if (!spec->dac_info[i].dac)
+                       continue;
+               type = spec->dac_info[i].type;
+               if (type == AUTO_PIN_LINE_OUT)
+                       type = spec->autocfg.line_out_type;
+               switch (type) {
+               case AUTO_PIN_LINE_OUT:
+               default:
+                       label = texts[num_line++];
+                       idx = 0;
+                       break;
+               case AUTO_PIN_HP_OUT:
+                       label = "Headphone";
+                       idx = num_hp++;
+                       break;
+               case AUTO_PIN_SPEAKER_OUT:
+                       label = "Speaker";
+                       idx = num_spk++;
+                       break;
+               }
+               err = cx_auto_add_pb_volume(codec, spec->dac_info[i].dac,
+                                           label, idx);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+static int cx_auto_build_input_controls(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       static const char *prev_label;
+       int i, err, cidx;
+
+       err = cx_auto_add_volume(codec, "Capture", "", 0, spec->adc_nids[0],
+                                HDA_INPUT);
+       if (err < 0)
+               return err;
+       prev_label = NULL;
+       cidx = 0;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               const char *label;
+               if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP))
+                       continue;
+               label = hda_get_autocfg_input_label(codec, cfg, i);
+               if (label == prev_label)
+                       cidx++;
+               else
+                       cidx = 0;
+               prev_label = label;
+               err = cx_auto_add_volume(codec, label, " Capture", cidx,
+                                        nid, HDA_INPUT);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+static int cx_auto_build_controls(struct hda_codec *codec)
+{
+       int err;
+
+       err = cx_auto_build_output_controls(codec);
+       if (err < 0)
+               return err;
+       err = cx_auto_build_input_controls(codec);
+       if (err < 0)
+               return err;
+       return conexant_build_controls(codec);
+}
+
+static struct hda_codec_ops cx_auto_patch_ops = {
+       .build_controls = cx_auto_build_controls,
+       .build_pcms = conexant_build_pcms,
+       .init = cx_auto_init,
+       .free = conexant_free,
+       .unsol_event = cx_auto_unsol_event,
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       .suspend = conexant_suspend,
+#endif
+       .reboot_notify = snd_hda_shutup_pins,
+};
+
+static int patch_conexant_auto(struct hda_codec *codec)
+{
+       struct conexant_spec *spec;
+       int err;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       codec->spec = spec;
+       spec->adc_nids = cx_auto_adc_nids;
+       spec->num_adc_nids = ARRAY_SIZE(cx_auto_adc_nids);
+       spec->capsrc_nids = spec->adc_nids;
+       err = cx_auto_parse_auto_config(codec);
+       if (err < 0) {
+               kfree(codec->spec);
+               codec->spec = NULL;
+               return err;
+       }
+       codec->patch_ops = cx_auto_patch_ops;
+       if (spec->beep_amp)
+               snd_hda_attach_beep_device(codec, spec->beep_amp);
+       return 0;
+}
+
 /*
  */
 
@@ -3271,6 +3880,22 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = {
          .patch = patch_cxt5066 },
        { .id = 0x14f15069, .name = "CX20585",
          .patch = patch_cxt5066 },
+       { .id = 0x14f15097, .name = "CX20631",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f15098, .name = "CX20632",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f150a1, .name = "CX20641",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f150a2, .name = "CX20642",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f150ab, .name = "CX20651",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f150ac, .name = "CX20652",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f150b8, .name = "CX20664",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f150b9, .name = "CX20665",
+         .patch = patch_conexant_auto },
        {} /* terminator */
 };
 
@@ -3281,6 +3906,14 @@ MODULE_ALIAS("snd-hda-codec-id:14f15066");
 MODULE_ALIAS("snd-hda-codec-id:14f15067");
 MODULE_ALIAS("snd-hda-codec-id:14f15068");
 MODULE_ALIAS("snd-hda-codec-id:14f15069");
+MODULE_ALIAS("snd-hda-codec-id:14f15097");
+MODULE_ALIAS("snd-hda-codec-id:14f15098");
+MODULE_ALIAS("snd-hda-codec-id:14f150a1");
+MODULE_ALIAS("snd-hda-codec-id:14f150a2");
+MODULE_ALIAS("snd-hda-codec-id:14f150ab");
+MODULE_ALIAS("snd-hda-codec-id:14f150ac");
+MODULE_ALIAS("snd-hda-codec-id:14f150b8");
+MODULE_ALIAS("snd-hda-codec-id:14f150b9");
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Conexant HD-audio codec");
index afd6022a96a75bda3b24b652973dccbe591c625f..d3e49aa5b9ecd42f6db6f5892319e6602ad9b7ab 100644 (file)
@@ -3,6 +3,9 @@
  *  patch_hdmi.c - routines for HDMI/DisplayPort codecs
  *
  *  Copyright(c) 2008-2010 Intel Corporation. All rights reserved.
+ *  Copyright (c) 2006 ATI Technologies Inc.
+ *  Copyright (c) 2008 NVIDIA Corp.  All rights reserved.
+ *  Copyright (c) 2008 Wei Ni <wni@nvidia.com>
  *
  *  Authors:
  *                     Wu Fengguang <wfg@linux.intel.com>
  *  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+/*
+ * 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
+ * more ports (DVI, HDMI or DisplayPort).
+ *
+ * The HDA correspondence of pipes/ports are converter/pin nodes.
+ */
+#define MAX_HDMI_CVTS  3
+#define MAX_HDMI_PINS  3
 
 struct hdmi_spec {
        int num_cvts;
@@ -49,10 +68,10 @@ struct hdmi_spec {
        struct hda_pcm_stream codec_pcm_pars[MAX_HDMI_CVTS];
 
        /*
-        * nvhdmi specific
+        * ati/nvhdmi specific
         */
        struct hda_multi_out multiout;
-       unsigned int codec_type;
+       struct hda_pcm_stream *pcm_playback;
 
        /* misc flags */
        /* PD bit indicates only the update, not the current state */
@@ -65,13 +84,25 @@ struct hdmi_audio_infoframe {
        u8 ver;  /* 0x01 */
        u8 len;  /* 0x0a */
 
-       u8 checksum;    /* PB0 */
+       u8 checksum;
+
        u8 CC02_CT47;   /* CC in bits 0:2, CT in 4:7 */
        u8 SS01_SF24;
        u8 CXT04;
        u8 CA;
        u8 LFEPBL01_LSV36_DM_INH7;
-       u8 reserved[5]; /* PB6 - PB10 */
+};
+
+struct dp_audio_infoframe {
+       u8 type; /* 0x84 */
+       u8 len;  /* 0x1b */
+       u8 ver;  /* 0x11 << 2 */
+
+       u8 CC02_CT47;   /* match with HDMI infoframe from this on */
+       u8 SS01_SF24;
+       u8 CXT04;
+       u8 CA;
+       u8 LFEPBL01_LSV36_DM_INH7;
 };
 
 /*
@@ -162,7 +193,7 @@ static int hdmi_channel_mapping[0x32][8] = {
        /* 4ch */
        [0x03] = { 0x00, 0x11, 0x23, 0x32, 0x44, 0xf5, 0xf6, 0xf7 },
        /* surround41 */
-       [0x09] = { 0x00, 0x11, 0x24, 0x34, 0x43, 0xf2, 0xf6, 0xf7 },
+       [0x09] = { 0x00, 0x11, 0x24, 0x35, 0x42, 0xf3, 0xf6, 0xf7 },
        /* surround50 */
        [0x0a] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0xf2, 0xf6, 0xf7 },
        /* surround51 */
@@ -175,7 +206,7 @@ static int hdmi_channel_mapping[0x32][8] = {
  * This is an ordered list!
  *
  * The preceding ones have better chances to be selected by
- * hdmi_setup_channel_allocation().
+ * hdmi_channel_allocation().
  */
 static struct cea_channel_speaker_allocation channel_allocations[] = {
 /*                       channel:   7     6    5    4    3     2    1    0  */
@@ -352,14 +383,14 @@ static void init_channel_allocations(void)
  *
  * TODO: it could select the wrong CA from multiple candidates.
 */
-static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
-                                        struct hdmi_audio_infoframe *ai)
+static int hdmi_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
+                                  int channels)
 {
        struct hdmi_spec *spec = codec->spec;
        struct hdmi_eld *eld;
        int i;
+       int ca = 0;
        int spk_mask = 0;
-       int channels = 1 + (ai->CC02_CT47 & 0x7);
        char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
 
        /*
@@ -397,16 +428,16 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid,
                if (channels == channel_allocations[i].channels &&
                    (spk_mask & channel_allocations[i].spk_mask) ==
                                channel_allocations[i].spk_mask) {
-                       ai->CA = channel_allocations[i].ca_index;
+                       ca = channel_allocations[i].ca_index;
                        break;
                }
        }
 
        snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf));
        snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n",
-                   ai->CA, channels, buf);
+                   ca, channels, buf);
 
-       return ai->CA;
+       return ca;
 }
 
 static void hdmi_debug_channel_mapping(struct hda_codec *codec,
@@ -428,10 +459,9 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec,
 
 static void hdmi_setup_channel_mapping(struct hda_codec *codec,
                                       hda_nid_t pin_nid,
-                                      struct hdmi_audio_infoframe *ai)
+                                      int ca)
 {
        int i;
-       int ca = ai->CA;
        int err;
 
        if (hdmi_channel_mapping[ca][1] == 0) {
@@ -528,41 +558,37 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid)
 #endif
 }
 
-static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *ai)
+static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *hdmi_ai)
 {
-       u8 *bytes = (u8 *)ai;
+       u8 *bytes = (u8 *)hdmi_ai;
        u8 sum = 0;
        int i;
 
-       ai->checksum = 0;
+       hdmi_ai->checksum = 0;
 
-       for (i = 0; i < sizeof(*ai); i++)
+       for (i = 0; i < sizeof(*hdmi_ai); i++)
                sum += bytes[i];
 
-       ai->checksum = -sum;
+       hdmi_ai->checksum = -sum;
 }
 
 static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
                                      hda_nid_t pin_nid,
-                                     struct hdmi_audio_infoframe *ai)
+                                     u8 *dip, int size)
 {
-       u8 *bytes = (u8 *)ai;
        int i;
 
        hdmi_debug_dip_size(codec, pin_nid);
        hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */
 
-       hdmi_checksum_audio_infoframe(ai);
-
        hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
-       for (i = 0; i < sizeof(*ai); i++)
-               hdmi_write_dip_byte(codec, pin_nid, bytes[i]);
+       for (i = 0; i < size; i++)
+               hdmi_write_dip_byte(codec, pin_nid, dip[i]);
 }
 
 static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
-                                   struct hdmi_audio_infoframe *ai)
+                                   u8 *dip, int size)
 {
-       u8 *bytes = (u8 *)ai;
        u8 val;
        int i;
 
@@ -571,10 +597,10 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
                return false;
 
        hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
-       for (i = 0; i < sizeof(*ai); i++) {
+       for (i = 0; i < size; i++) {
                val = snd_hda_codec_read(codec, pin_nid, 0,
                                         AC_VERB_GET_HDMI_DIP_DATA, 0);
-               if (val != bytes[i])
+               if (val != dip[i])
                        return false;
        }
 
@@ -586,15 +612,13 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
 {
        struct hdmi_spec *spec = codec->spec;
        hda_nid_t pin_nid;
+       int channels = substream->runtime->channels;
+       int ca;
        int i;
-       struct hdmi_audio_infoframe ai = {
-               .type           = 0x84,
-               .ver            = 0x01,
-               .len            = 0x0a,
-               .CC02_CT47      = substream->runtime->channels - 1,
-       };
+       u8 ai[max(sizeof(struct hdmi_audio_infoframe),
+                 sizeof(struct dp_audio_infoframe))];
 
-       hdmi_setup_channel_allocation(codec, nid, &ai);
+       ca = hdmi_channel_allocation(codec, nid, channels);
 
        for (i = 0; i < spec->num_pins; i++) {
                if (spec->pin_cvt[i] != nid)
@@ -603,14 +627,45 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid,
                        continue;
 
                pin_nid = spec->pin[i];
-               if (!hdmi_infoframe_uptodate(codec, pin_nid, &ai)) {
+
+               memset(ai, 0, sizeof(ai));
+               if (spec->sink_eld[i].conn_type == 0) { /* HDMI */
+                       struct hdmi_audio_infoframe *hdmi_ai;
+
+                       hdmi_ai = (struct hdmi_audio_infoframe *)ai;
+                       hdmi_ai->type           = 0x84;
+                       hdmi_ai->ver            = 0x01;
+                       hdmi_ai->len            = 0x0a;
+                       hdmi_ai->CC02_CT47      = channels - 1;
+                       hdmi_checksum_audio_infoframe(hdmi_ai);
+               } else if (spec->sink_eld[i].conn_type == 1) { /* DisplayPort */
+                       struct dp_audio_infoframe *dp_ai;
+
+                       dp_ai = (struct dp_audio_infoframe *)ai;
+                       dp_ai->type             = 0x84;
+                       dp_ai->len              = 0x1b;
+                       dp_ai->ver              = 0x11 << 2;
+                       dp_ai->CC02_CT47        = channels - 1;
+               } else {
+                       snd_printd("HDMI: unknown connection type at pin %d\n",
+                                  pin_nid);
+                       continue;
+               }
+
+               /*
+                * sizeof(ai) is used instead of sizeof(*hdmi_ai) or
+                * sizeof(*dp_ai) to avoid partial match/update problems when
+                * the user switches between HDMI/DP monitors.
+                */
+               if (!hdmi_infoframe_uptodate(codec, pin_nid, ai, sizeof(ai))) {
                        snd_printdd("hdmi_setup_audio_infoframe: "
                                    "cvt=%d pin=%d channels=%d\n",
                                    nid, pin_nid,
-                                   substream->runtime->channels);
-                       hdmi_setup_channel_mapping(codec, pin_nid, &ai);
+                                   channels);
+                       hdmi_setup_channel_mapping(codec, pin_nid, ca);
                        hdmi_stop_infoframe_trans(codec, pin_nid);
-                       hdmi_fill_audio_infoframe(codec, pin_nid, &ai);
+                       hdmi_fill_audio_infoframe(codec, pin_nid,
+                                                 ai, sizeof(ai));
                        hdmi_start_infoframe_trans(codec, pin_nid);
                }
        }
@@ -791,7 +846,6 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
 /*
  * HDA/HDMI auto parsing
  */
-
 static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid)
 {
        struct hdmi_spec *spec = codec->spec;
@@ -922,3 +976,664 @@ static int hdmi_parse_codec(struct hda_codec *codec)
        return 0;
 }
 
+/*
+ */
+static char *generic_hdmi_pcm_names[MAX_HDMI_CVTS] = {
+       "HDMI 0",
+       "HDMI 1",
+       "HDMI 2",
+};
+
+/*
+ * HDMI callbacks
+ */
+
+static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                          struct hda_codec *codec,
+                                          unsigned int stream_tag,
+                                          unsigned int format,
+                                          struct snd_pcm_substream *substream)
+{
+       hdmi_set_channel_count(codec, hinfo->nid,
+                              substream->runtime->channels);
+
+       hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
+
+       return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
+}
+
+static struct hda_pcm_stream generic_hdmi_pcm_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .ops = {
+               .open = hdmi_pcm_open,
+               .prepare = generic_hdmi_playback_pcm_prepare,
+       },
+};
+
+static int generic_hdmi_build_pcms(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct hda_pcm *info = spec->pcm_rec;
+       int i;
+
+       codec->num_pcms = spec->num_cvts;
+       codec->pcm_info = info;
+
+       for (i = 0; i < codec->num_pcms; i++, info++) {
+               unsigned int chans;
+               struct hda_pcm_stream *pstr;
+
+               chans = get_wcaps(codec, spec->cvt[i]);
+               chans = get_wcaps_channels(chans);
+
+               info->name = generic_hdmi_pcm_names[i];
+               info->pcm_type = HDA_PCM_TYPE_HDMI;
+               pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
+               if (spec->pcm_playback)
+                       *pstr = *spec->pcm_playback;
+               else
+                       *pstr = generic_hdmi_pcm_playback;
+               pstr->nid = spec->cvt[i];
+               if (pstr->channels_max <= 2 && chans && chans <= 16)
+                       pstr->channels_max = chans;
+       }
+
+       return 0;
+}
+
+static int generic_hdmi_build_controls(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int err;
+       int i;
+
+       for (i = 0; i < codec->num_pcms; i++) {
+               err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int generic_hdmi_init(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int i;
+
+       for (i = 0; spec->pin[i]; i++) {
+               hdmi_enable_output(codec, spec->pin[i]);
+               snd_hda_codec_write(codec, spec->pin[i], 0,
+                                   AC_VERB_SET_UNSOLICITED_ENABLE,
+                                   AC_USRSP_EN | spec->pin[i]);
+       }
+       return 0;
+}
+
+static void generic_hdmi_free(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int i;
+
+       for (i = 0; i < spec->num_pins; i++)
+               snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
+
+       kfree(spec);
+}
+
+static struct hda_codec_ops generic_hdmi_patch_ops = {
+       .init                   = generic_hdmi_init,
+       .free                   = generic_hdmi_free,
+       .build_pcms             = generic_hdmi_build_pcms,
+       .build_controls         = generic_hdmi_build_controls,
+       .unsol_event            = hdmi_unsol_event,
+};
+
+static int patch_generic_hdmi(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+       int i;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+       if (hdmi_parse_codec(codec) < 0) {
+               codec->spec = NULL;
+               kfree(spec);
+               return -EINVAL;
+       }
+       codec->patch_ops = generic_hdmi_patch_ops;
+
+       for (i = 0; i < spec->num_pins; i++)
+               snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i);
+
+       init_channel_allocations();
+
+       return 0;
+}
+
+/*
+ * Nvidia specific implementations
+ */
+
+#define Nv_VERB_SET_Channel_Allocation          0xF79
+#define Nv_VERB_SET_Info_Frame_Checksum         0xF7A
+#define Nv_VERB_SET_Audio_Protection_On         0xF98
+#define Nv_VERB_SET_Audio_Protection_Off        0xF99
+
+#define nvhdmi_master_con_nid_7x       0x04
+#define nvhdmi_master_pin_nid_7x       0x05
+
+static hda_nid_t nvhdmi_con_nids_7x[4] = {
+       /*front, rear, clfe, rear_surr */
+       0x6, 0x8, 0xa, 0xc,
+};
+
+static struct hda_verb nvhdmi_basic_init_7x[] = {
+       /* set audio protect on */
+       { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
+       /* enable digital output on pin widget */
+       { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+       { 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+       { 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+       { 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+       { 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+       {} /* terminator */
+};
+
+#ifdef LIMITED_RATE_FMT_SUPPORT
+/* support only the safe format and rate */
+#define SUPPORTED_RATES                SNDRV_PCM_RATE_48000
+#define SUPPORTED_MAXBPS       16
+#define SUPPORTED_FORMATS      SNDRV_PCM_FMTBIT_S16_LE
+#else
+/* support all rates and formats */
+#define SUPPORTED_RATES \
+       (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
+       SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
+        SNDRV_PCM_RATE_192000)
+#define SUPPORTED_MAXBPS       24
+#define SUPPORTED_FORMATS \
+       (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
+#endif
+
+static int nvhdmi_7x_init(struct hda_codec *codec)
+{
+       snd_hda_sequence_write(codec, nvhdmi_basic_init_7x);
+       return 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;
+       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int simple_playback_pcm_close(struct hda_pcm_stream *hinfo,
+                                    struct hda_codec *codec,
+                                    struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int simple_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                      struct hda_codec *codec,
+                                      unsigned int stream_tag,
+                                      unsigned int format,
+                                      struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
+                                            stream_tag, format, substream);
+}
+
+static int nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream *hinfo,
+                                  struct hda_codec *codec,
+                                  struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int i;
+
+       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x,
+                       0, AC_VERB_SET_CHANNEL_STREAMID, 0);
+       for (i = 0; i < 4; i++) {
+               /* set the stream id */
+               snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
+                               AC_VERB_SET_CHANNEL_STREAMID, 0);
+               /* set the stream format */
+               snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
+                               AC_VERB_SET_STREAM_FORMAT, 0);
+       }
+
+       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                    struct hda_codec *codec,
+                                    unsigned int stream_tag,
+                                    unsigned int format,
+                                    struct snd_pcm_substream *substream)
+{
+       int chs;
+       unsigned int dataDCC1, dataDCC2, chan, chanmask, channel_id;
+       int i;
+
+       mutex_lock(&codec->spdif_mutex);
+
+       chs = substream->runtime->channels;
+       chan = chs ? (chs - 1) : 1;
+
+       switch (chs) {
+       default:
+       case 0:
+       case 2:
+               chanmask = 0x00;
+               break;
+       case 4:
+               chanmask = 0x08;
+               break;
+       case 6:
+               chanmask = 0x0b;
+               break;
+       case 8:
+               chanmask = 0x13;
+               break;
+       }
+       dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT;
+       dataDCC2 = 0x2;
+
+       /* set the Audio InforFrame Channel Allocation */
+       snd_hda_codec_write(codec, 0x1, 0,
+                       Nv_VERB_SET_Channel_Allocation, chanmask);
+
+       /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
+       if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
+               snd_hda_codec_write(codec,
+                               nvhdmi_master_con_nid_7x,
+                               0,
+                               AC_VERB_SET_DIGI_CONVERT_1,
+                               codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
+
+       /* set the stream id */
+       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
+                       AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
+
+       /* set the stream format */
+       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
+                       AC_VERB_SET_STREAM_FORMAT, format);
+
+       /* turn on again (if needed) */
+       /* enable and set the channel status audio/data flag */
+       if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) {
+               snd_hda_codec_write(codec,
+                               nvhdmi_master_con_nid_7x,
+                               0,
+                               AC_VERB_SET_DIGI_CONVERT_1,
+                               codec->spdif_ctls & 0xff);
+               snd_hda_codec_write(codec,
+                               nvhdmi_master_con_nid_7x,
+                               0,
+                               AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
+       }
+
+       for (i = 0; i < 4; i++) {
+               if (chs == 2)
+                       channel_id = 0;
+               else
+                       channel_id = i * 2;
+
+               /* turn off SPDIF once;
+                *otherwise the IEC958 bits won't be updated
+                */
+               if (codec->spdif_status_reset &&
+               (codec->spdif_ctls & AC_DIG1_ENABLE))
+                       snd_hda_codec_write(codec,
+                               nvhdmi_con_nids_7x[i],
+                               0,
+                               AC_VERB_SET_DIGI_CONVERT_1,
+                               codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
+               /* set the stream id */
+               snd_hda_codec_write(codec,
+                               nvhdmi_con_nids_7x[i],
+                               0,
+                               AC_VERB_SET_CHANNEL_STREAMID,
+                               (stream_tag << 4) | channel_id);
+               /* set the stream format */
+               snd_hda_codec_write(codec,
+                               nvhdmi_con_nids_7x[i],
+                               0,
+                               AC_VERB_SET_STREAM_FORMAT,
+                               format);
+               /* turn on again (if needed) */
+               /* enable and set the channel status audio/data flag */
+               if (codec->spdif_status_reset &&
+               (codec->spdif_ctls & AC_DIG1_ENABLE)) {
+                       snd_hda_codec_write(codec,
+                                       nvhdmi_con_nids_7x[i],
+                                       0,
+                                       AC_VERB_SET_DIGI_CONVERT_1,
+                                       codec->spdif_ctls & 0xff);
+                       snd_hda_codec_write(codec,
+                                       nvhdmi_con_nids_7x[i],
+                                       0,
+                                       AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
+               }
+       }
+
+       /* set the Audio Info Frame Checksum */
+       snd_hda_codec_write(codec, 0x1, 0,
+                       Nv_VERB_SET_Info_Frame_Checksum,
+                       (0x71 - chan - chanmask));
+
+       mutex_unlock(&codec->spdif_mutex);
+       return 0;
+}
+
+static struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 8,
+       .nid = nvhdmi_master_con_nid_7x,
+       .rates = SUPPORTED_RATES,
+       .maxbps = SUPPORTED_MAXBPS,
+       .formats = SUPPORTED_FORMATS,
+       .ops = {
+               .open = simple_playback_pcm_open,
+               .close = nvhdmi_8ch_7x_pcm_close,
+               .prepare = nvhdmi_8ch_7x_pcm_prepare
+       },
+};
+
+static struct hda_pcm_stream nvhdmi_pcm_playback_2ch = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = nvhdmi_master_con_nid_7x,
+       .rates = SUPPORTED_RATES,
+       .maxbps = SUPPORTED_MAXBPS,
+       .formats = SUPPORTED_FORMATS,
+       .ops = {
+               .open = simple_playback_pcm_open,
+               .close = simple_playback_pcm_close,
+               .prepare = simple_playback_pcm_prepare
+       },
+};
+
+static struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = {
+       .build_controls = generic_hdmi_build_controls,
+       .build_pcms = generic_hdmi_build_pcms,
+       .init = nvhdmi_7x_init,
+       .free = generic_hdmi_free,
+};
+
+static struct hda_codec_ops nvhdmi_patch_ops_2ch = {
+       .build_controls = generic_hdmi_build_controls,
+       .build_pcms = generic_hdmi_build_pcms,
+       .init = nvhdmi_7x_init,
+       .free = generic_hdmi_free,
+};
+
+static int patch_nvhdmi_8ch_89(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+       int err = patch_generic_hdmi(codec);
+
+       if (err < 0)
+               return err;
+       spec = codec->spec;
+       spec->old_pin_detect = 1;
+       return 0;
+}
+
+static int patch_nvhdmi_2ch(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       spec->multiout.num_dacs = 0;  /* no analog */
+       spec->multiout.max_channels = 2;
+       spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
+       spec->old_pin_detect = 1;
+       spec->num_cvts = 1;
+       spec->cvt[0] = nvhdmi_master_con_nid_7x;
+       spec->pcm_playback = &nvhdmi_pcm_playback_2ch;
+
+       codec->patch_ops = nvhdmi_patch_ops_2ch;
+
+       return 0;
+}
+
+static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+       int err = patch_nvhdmi_2ch(codec);
+
+       if (err < 0)
+               return err;
+       spec = codec->spec;
+       spec->multiout.max_channels = 8;
+       spec->pcm_playback = &nvhdmi_pcm_playback_8ch_7x;
+       codec->patch_ops = nvhdmi_patch_ops_8ch_7x;
+       return 0;
+}
+
+/*
+ * ATI-specific implementations
+ *
+ * FIXME: we may omit the whole this and use the generic code once after
+ * it's confirmed to work.
+ */
+
+#define ATIHDMI_CVT_NID                0x02    /* audio converter */
+#define ATIHDMI_PIN_NID                0x03    /* HDMI output pin */
+
+static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                       struct hda_codec *codec,
+                                       unsigned int stream_tag,
+                                       unsigned int format,
+                                       struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int chans = substream->runtime->channels;
+       int i, err;
+
+       err = simple_playback_pcm_prepare(hinfo, codec, stream_tag, format,
+                                         substream);
+       if (err < 0)
+               return err;
+       snd_hda_codec_write(codec, spec->cvt[0], 0, AC_VERB_SET_CVT_CHAN_COUNT,
+                           chans - 1);
+       /* FIXME: XXX */
+       for (i = 0; i < chans; i++) {
+               snd_hda_codec_write(codec, spec->cvt[0], 0,
+                                   AC_VERB_SET_HDMI_CHAN_SLOT,
+                                   (i << 4) | i);
+       }
+       return 0;
+}
+
+static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = ATIHDMI_CVT_NID,
+       .ops = {
+               .open = simple_playback_pcm_open,
+               .close = simple_playback_pcm_close,
+               .prepare = atihdmi_playback_pcm_prepare
+       },
+};
+
+static struct hda_verb atihdmi_basic_init[] = {
+       /* enable digital output on pin widget */
+       { 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       {} /* terminator */
+};
+
+static int atihdmi_init(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+
+       snd_hda_sequence_write(codec, atihdmi_basic_init);
+       /* SI codec requires to unmute the pin */
+       if (get_wcaps(codec, spec->pin[0]) & AC_WCAP_OUT_AMP)
+               snd_hda_codec_write(codec, spec->pin[0], 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE,
+                                   AMP_OUT_UNMUTE);
+       return 0;
+}
+
+static struct hda_codec_ops atihdmi_patch_ops = {
+       .build_controls = generic_hdmi_build_controls,
+       .build_pcms = generic_hdmi_build_pcms,
+       .init = atihdmi_init,
+       .free = generic_hdmi_free,
+};
+
+
+static int patch_atihdmi(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       spec->multiout.num_dacs = 0;      /* no analog */
+       spec->multiout.max_channels = 2;
+       spec->multiout.dig_out_nid = ATIHDMI_CVT_NID;
+       spec->num_cvts = 1;
+       spec->cvt[0] = ATIHDMI_CVT_NID;
+       spec->pin[0] = ATIHDMI_PIN_NID;
+       spec->pcm_playback = &atihdmi_pcm_digital_playback;
+
+       codec->patch_ops = atihdmi_patch_ops;
+
+       return 0;
+}
+
+
+/*
+ * patch entries
+ */
+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 = 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 },
+{ .id = 0x10de0002, .name = "MCP77/78 HDMI",   .patch = patch_nvhdmi_8ch_7x },
+{ .id = 0x10de0003, .name = "MCP77/78 HDMI",   .patch = patch_nvhdmi_8ch_7x },
+{ .id = 0x10de0005, .name = "MCP77/78 HDMI",   .patch = patch_nvhdmi_8ch_7x },
+{ .id = 0x10de0006, .name = "MCP77/78 HDMI",   .patch = patch_nvhdmi_8ch_7x },
+{ .id = 0x10de0007, .name = "MCP79/7A HDMI",   .patch = patch_nvhdmi_8ch_7x },
+{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de000c, .name = "MCP89 HDMI",      .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP",  .patch = patch_nvhdmi_8ch_89 },
+{ .id = 0x10de0067, .name = "MCP67 HDMI",      .patch = patch_nvhdmi_2ch },
+{ .id = 0x10de8001, .name = "MCP73 HDMI",      .patch = patch_nvhdmi_2ch },
+{ .id = 0x80860054, .name = "IbexPeak HDMI",   .patch = patch_generic_hdmi },
+{ .id = 0x80862801, .name = "Bearlake HDMI",   .patch = patch_generic_hdmi },
+{ .id = 0x80862802, .name = "Cantiga HDMI",    .patch = patch_generic_hdmi },
+{ .id = 0x80862803, .name = "Eaglelake HDMI",  .patch = patch_generic_hdmi },
+{ .id = 0x80862804, .name = "IbexPeak HDMI",   .patch = patch_generic_hdmi },
+{ .id = 0x80862805, .name = "CougarPoint HDMI",        .patch = patch_generic_hdmi },
+{ .id = 0x808629fb, .name = "Crestline HDMI",  .patch = patch_generic_hdmi },
+{} /* terminator */
+};
+
+MODULE_ALIAS("snd-hda-codec-id:1002793c");
+MODULE_ALIAS("snd-hda-codec-id:10027919");
+MODULE_ALIAS("snd-hda-codec-id:1002791a");
+MODULE_ALIAS("snd-hda-codec-id:1002aa01");
+MODULE_ALIAS("snd-hda-codec-id:10951390");
+MODULE_ALIAS("snd-hda-codec-id:10951392");
+MODULE_ALIAS("snd-hda-codec-id:10de0002");
+MODULE_ALIAS("snd-hda-codec-id:10de0003");
+MODULE_ALIAS("snd-hda-codec-id:10de0005");
+MODULE_ALIAS("snd-hda-codec-id:10de0006");
+MODULE_ALIAS("snd-hda-codec-id:10de0007");
+MODULE_ALIAS("snd-hda-codec-id:10de000a");
+MODULE_ALIAS("snd-hda-codec-id:10de000b");
+MODULE_ALIAS("snd-hda-codec-id:10de000c");
+MODULE_ALIAS("snd-hda-codec-id:10de000d");
+MODULE_ALIAS("snd-hda-codec-id:10de0010");
+MODULE_ALIAS("snd-hda-codec-id:10de0011");
+MODULE_ALIAS("snd-hda-codec-id:10de0012");
+MODULE_ALIAS("snd-hda-codec-id:10de0013");
+MODULE_ALIAS("snd-hda-codec-id:10de0014");
+MODULE_ALIAS("snd-hda-codec-id:10de0018");
+MODULE_ALIAS("snd-hda-codec-id:10de0019");
+MODULE_ALIAS("snd-hda-codec-id:10de001a");
+MODULE_ALIAS("snd-hda-codec-id:10de001b");
+MODULE_ALIAS("snd-hda-codec-id:10de001c");
+MODULE_ALIAS("snd-hda-codec-id:10de0040");
+MODULE_ALIAS("snd-hda-codec-id:10de0041");
+MODULE_ALIAS("snd-hda-codec-id:10de0042");
+MODULE_ALIAS("snd-hda-codec-id:10de0043");
+MODULE_ALIAS("snd-hda-codec-id:10de0044");
+MODULE_ALIAS("snd-hda-codec-id:10de0067");
+MODULE_ALIAS("snd-hda-codec-id:10de8001");
+MODULE_ALIAS("snd-hda-codec-id:17e80047");
+MODULE_ALIAS("snd-hda-codec-id:80860054");
+MODULE_ALIAS("snd-hda-codec-id:80862801");
+MODULE_ALIAS("snd-hda-codec-id:80862802");
+MODULE_ALIAS("snd-hda-codec-id:80862803");
+MODULE_ALIAS("snd-hda-codec-id:80862804");
+MODULE_ALIAS("snd-hda-codec-id:80862805");
+MODULE_ALIAS("snd-hda-codec-id:808629fb");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("HDMI HD-audio codec");
+MODULE_ALIAS("snd-hda-codec-intelhdmi");
+MODULE_ALIAS("snd-hda-codec-nvhdmi");
+MODULE_ALIAS("snd-hda-codec-atihdmi");
+
+static struct hda_codec_preset_list intel_list = {
+       .preset = snd_hda_preset_hdmi,
+       .owner = THIS_MODULE,
+};
+
+static int __init patch_hdmi_init(void)
+{
+       return snd_hda_add_codec_preset(&intel_list);
+}
+
+static void __exit patch_hdmi_exit(void)
+{
+       snd_hda_delete_codec_preset(&intel_list);
+}
+
+module_init(patch_hdmi_init)
+module_exit(patch_hdmi_exit)
diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c
deleted file mode 100644 (file)
index 36a9b83..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- *
- *  patch_intelhdmi.c - Patch for Intel HDMI codecs
- *
- *  Copyright(c) 2008 Intel Corporation. All rights reserved.
- *
- *  Authors:
- *                     Jiang Zhe <zhe.jiang@intel.com>
- *                     Wu Fengguang <wfg@linux.intel.com>
- *
- *  Maintained by:
- *                     Wu Fengguang <wfg@linux.intel.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include "hda_codec.h"
-#include "hda_local.h"
-
-/*
- * 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
- * more ports (DVI, HDMI or DisplayPort).
- *
- * The HDA correspondence of pipes/ports are converter/pin nodes.
- */
-#define MAX_HDMI_CVTS  3
-#define MAX_HDMI_PINS  3
-
-#include "patch_hdmi.c"
-
-static char *intel_hdmi_pcm_names[MAX_HDMI_CVTS] = {
-       "INTEL HDMI 0",
-       "INTEL HDMI 1",
-       "INTEL HDMI 2",
-};
-
-/*
- * HDMI callbacks
- */
-
-static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                          struct hda_codec *codec,
-                                          unsigned int stream_tag,
-                                          unsigned int format,
-                                          struct snd_pcm_substream *substream)
-{
-       hdmi_set_channel_count(codec, hinfo->nid,
-                              substream->runtime->channels);
-
-       hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
-
-       return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
-}
-
-static struct hda_pcm_stream intel_hdmi_pcm_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .ops = {
-               .open = hdmi_pcm_open,
-               .prepare = intel_hdmi_playback_pcm_prepare,
-       },
-};
-
-static int intel_hdmi_build_pcms(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct hda_pcm *info = spec->pcm_rec;
-       int i;
-
-       codec->num_pcms = spec->num_cvts;
-       codec->pcm_info = info;
-
-       for (i = 0; i < codec->num_pcms; i++, info++) {
-               unsigned int chans;
-
-               chans = get_wcaps(codec, spec->cvt[i]);
-               chans = get_wcaps_channels(chans);
-
-               info->name = intel_hdmi_pcm_names[i];
-               info->pcm_type = HDA_PCM_TYPE_HDMI;
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
-                                                       intel_hdmi_pcm_playback;
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i];
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
-       }
-
-       return 0;
-}
-
-static int intel_hdmi_build_controls(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int err;
-       int i;
-
-       for (i = 0; i < codec->num_pcms; i++) {
-               err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]);
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
-static int intel_hdmi_init(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; spec->pin[i]; i++) {
-               hdmi_enable_output(codec, spec->pin[i]);
-               snd_hda_codec_write(codec, spec->pin[i], 0,
-                                   AC_VERB_SET_UNSOLICITED_ENABLE,
-                                   AC_USRSP_EN | spec->pin[i]);
-       }
-       return 0;
-}
-
-static void intel_hdmi_free(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < spec->num_pins; i++)
-               snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
-
-       kfree(spec);
-}
-
-static struct hda_codec_ops intel_hdmi_patch_ops = {
-       .init                   = intel_hdmi_init,
-       .free                   = intel_hdmi_free,
-       .build_pcms             = intel_hdmi_build_pcms,
-       .build_controls         = intel_hdmi_build_controls,
-       .unsol_event            = hdmi_unsol_event,
-};
-
-static int patch_intel_hdmi(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec;
-       int i;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
-       if (hdmi_parse_codec(codec) < 0) {
-               codec->spec = NULL;
-               kfree(spec);
-               return -EINVAL;
-       }
-       codec->patch_ops = intel_hdmi_patch_ops;
-
-       for (i = 0; i < spec->num_pins; i++)
-               snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i);
-
-       init_channel_allocations();
-
-       return 0;
-}
-
-static struct hda_codec_preset snd_hda_preset_intelhdmi[] = {
-{ .id = 0x808629fb, .name = "Crestline HDMI",  .patch = patch_intel_hdmi },
-{ .id = 0x80862801, .name = "Bearlake HDMI",   .patch = patch_intel_hdmi },
-{ .id = 0x80862802, .name = "Cantiga HDMI",    .patch = patch_intel_hdmi },
-{ .id = 0x80862803, .name = "Eaglelake HDMI",  .patch = patch_intel_hdmi },
-{ .id = 0x80862804, .name = "IbexPeak HDMI",   .patch = patch_intel_hdmi },
-{ .id = 0x80860054, .name = "IbexPeak HDMI",   .patch = patch_intel_hdmi },
-{ .id = 0x80862805, .name = "CougarPoint HDMI",        .patch = patch_intel_hdmi },
-{ .id = 0x10951392, .name = "SiI1392 HDMI",    .patch = patch_intel_hdmi },
-{} /* terminator */
-};
-
-MODULE_ALIAS("snd-hda-codec-id:808629fb");
-MODULE_ALIAS("snd-hda-codec-id:80862801");
-MODULE_ALIAS("snd-hda-codec-id:80862802");
-MODULE_ALIAS("snd-hda-codec-id:80862803");
-MODULE_ALIAS("snd-hda-codec-id:80862804");
-MODULE_ALIAS("snd-hda-codec-id:80862805");
-MODULE_ALIAS("snd-hda-codec-id:80860054");
-MODULE_ALIAS("snd-hda-codec-id:10951392");
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Intel HDMI HD-audio codec");
-
-static struct hda_codec_preset_list intel_list = {
-       .preset = snd_hda_preset_intelhdmi,
-       .owner = THIS_MODULE,
-};
-
-static int __init patch_intelhdmi_init(void)
-{
-       return snd_hda_add_codec_preset(&intel_list);
-}
-
-static void __exit patch_intelhdmi_exit(void)
-{
-       snd_hda_delete_codec_preset(&intel_list);
-}
-
-module_init(patch_intelhdmi_init)
-module_exit(patch_intelhdmi_exit)
diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c
deleted file mode 100644 (file)
index baa108b..0000000
+++ /dev/null
@@ -1,608 +0,0 @@
-/*
- * Universal Interface for Intel High Definition Audio Codec
- *
- * HD audio interface patch for NVIDIA HDMI codecs
- *
- * Copyright (c) 2008 NVIDIA Corp.  All rights reserved.
- * Copyright (c) 2008 Wei Ni <wni@nvidia.com>
- *
- *
- *  This driver 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 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 program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include "hda_codec.h"
-#include "hda_local.h"
-
-#define MAX_HDMI_CVTS  1
-#define MAX_HDMI_PINS  1
-
-#include "patch_hdmi.c"
-
-static char *nvhdmi_pcm_names[MAX_HDMI_CVTS] = {
-       "NVIDIA HDMI",
-};
-
-/* define below to restrict the supported rates and formats */
-/* #define LIMITED_RATE_FMT_SUPPORT */
-
-enum HDACodec {
-       HDA_CODEC_NVIDIA_MCP7X,
-       HDA_CODEC_NVIDIA_MCP89,
-       HDA_CODEC_NVIDIA_GT21X,
-       HDA_CODEC_INVALID
-};
-
-#define Nv_VERB_SET_Channel_Allocation          0xF79
-#define Nv_VERB_SET_Info_Frame_Checksum         0xF7A
-#define Nv_VERB_SET_Audio_Protection_On         0xF98
-#define Nv_VERB_SET_Audio_Protection_Off        0xF99
-
-#define nvhdmi_master_con_nid_7x       0x04
-#define nvhdmi_master_pin_nid_7x       0x05
-
-#define nvhdmi_master_con_nid_89       0x04
-#define nvhdmi_master_pin_nid_89       0x05
-
-static hda_nid_t nvhdmi_con_nids_7x[4] = {
-       /*front, rear, clfe, rear_surr */
-       0x6, 0x8, 0xa, 0xc,
-};
-
-static struct hda_verb nvhdmi_basic_init_7x[] = {
-       /* set audio protect on */
-       { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
-       /* enable digital output on pin widget */
-       { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-       { 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-       { 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-       { 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-       { 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-       {} /* terminator */
-};
-
-#ifdef LIMITED_RATE_FMT_SUPPORT
-/* support only the safe format and rate */
-#define SUPPORTED_RATES                SNDRV_PCM_RATE_48000
-#define SUPPORTED_MAXBPS       16
-#define SUPPORTED_FORMATS      SNDRV_PCM_FMTBIT_S16_LE
-#else
-/* support all rates and formats */
-#define SUPPORTED_RATES \
-       (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
-       SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
-        SNDRV_PCM_RATE_192000)
-#define SUPPORTED_MAXBPS       24
-#define SUPPORTED_FORMATS \
-       (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
-#endif
-
-/*
- * Controls
- */
-static int nvhdmi_build_controls(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int err;
-       int i;
-
-       if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89)
-       || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) {
-               for (i = 0; i < codec->num_pcms; i++) {
-                       err = snd_hda_create_spdif_out_ctls(codec,
-                                                           spec->cvt[i]);
-                       if (err < 0)
-                               return err;
-               }
-       } else {
-               err = snd_hda_create_spdif_out_ctls(codec,
-                                                   spec->multiout.dig_out_nid);
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
-static int nvhdmi_init(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int i;
-       if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89)
-       || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) {
-               for (i = 0; spec->pin[i]; i++) {
-                       hdmi_enable_output(codec, spec->pin[i]);
-                       snd_hda_codec_write(codec, spec->pin[i], 0,
-                                           AC_VERB_SET_UNSOLICITED_ENABLE,
-                                           AC_USRSP_EN | spec->pin[i]);
-               }
-       } else {
-               snd_hda_sequence_write(codec, nvhdmi_basic_init_7x);
-       }
-       return 0;
-}
-
-static void nvhdmi_free(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int i;
-
-       if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89)
-       || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) {
-               for (i = 0; i < spec->num_pins; i++)
-                       snd_hda_eld_proc_free(codec, &spec->sink_eld[i]);
-       }
-
-       kfree(spec);
-}
-
-/*
- * Digital out
- */
-static int nvhdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
-                                       struct hda_codec *codec,
-                                       struct snd_pcm_substream *substream)
-{
-       struct hdmi_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
-}
-
-static int nvhdmi_dig_playback_pcm_close_8ch_7x(struct hda_pcm_stream *hinfo,
-                                       struct hda_codec *codec,
-                                       struct snd_pcm_substream *substream)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int i;
-
-       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x,
-                       0, AC_VERB_SET_CHANNEL_STREAMID, 0);
-       for (i = 0; i < 4; i++) {
-               /* set the stream id */
-               snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
-                               AC_VERB_SET_CHANNEL_STREAMID, 0);
-               /* set the stream format */
-               snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
-                               AC_VERB_SET_STREAM_FORMAT, 0);
-       }
-
-       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-static int nvhdmi_dig_playback_pcm_close_2ch(struct hda_pcm_stream *hinfo,
-                                       struct hda_codec *codec,
-                                       struct snd_pcm_substream *substream)
-{
-       struct hdmi_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-static int nvhdmi_dig_playback_pcm_prepare_8ch_89(struct hda_pcm_stream *hinfo,
-                                       struct hda_codec *codec,
-                                       unsigned int stream_tag,
-                                       unsigned int format,
-                                       struct snd_pcm_substream *substream)
-{
-       hdmi_set_channel_count(codec, hinfo->nid,
-                              substream->runtime->channels);
-
-       hdmi_setup_audio_infoframe(codec, hinfo->nid, substream);
-
-       return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format);
-}
-
-static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo,
-                                       struct hda_codec *codec,
-                                       unsigned int stream_tag,
-                                       unsigned int format,
-                                       struct snd_pcm_substream *substream)
-{
-       int chs;
-       unsigned int dataDCC1, dataDCC2, chan, chanmask, channel_id;
-       int i;
-
-       mutex_lock(&codec->spdif_mutex);
-
-       chs = substream->runtime->channels;
-       chan = chs ? (chs - 1) : 1;
-
-       switch (chs) {
-       default:
-       case 0:
-       case 2:
-               chanmask = 0x00;
-               break;
-       case 4:
-               chanmask = 0x08;
-               break;
-       case 6:
-               chanmask = 0x0b;
-               break;
-       case 8:
-               chanmask = 0x13;
-               break;
-       }
-       dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT;
-       dataDCC2 = 0x2;
-
-       /* set the Audio InforFrame Channel Allocation */
-       snd_hda_codec_write(codec, 0x1, 0,
-                       Nv_VERB_SET_Channel_Allocation, chanmask);
-
-       /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
-       if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
-               snd_hda_codec_write(codec,
-                               nvhdmi_master_con_nid_7x,
-                               0,
-                               AC_VERB_SET_DIGI_CONVERT_1,
-                               codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
-
-       /* set the stream id */
-       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
-                       AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
-
-       /* set the stream format */
-       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
-                       AC_VERB_SET_STREAM_FORMAT, format);
-
-       /* turn on again (if needed) */
-       /* enable and set the channel status audio/data flag */
-       if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) {
-               snd_hda_codec_write(codec,
-                               nvhdmi_master_con_nid_7x,
-                               0,
-                               AC_VERB_SET_DIGI_CONVERT_1,
-                               codec->spdif_ctls & 0xff);
-               snd_hda_codec_write(codec,
-                               nvhdmi_master_con_nid_7x,
-                               0,
-                               AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
-       }
-
-       for (i = 0; i < 4; i++) {
-               if (chs == 2)
-                       channel_id = 0;
-               else
-                       channel_id = i * 2;
-
-               /* turn off SPDIF once;
-                *otherwise the IEC958 bits won't be updated
-                */
-               if (codec->spdif_status_reset &&
-               (codec->spdif_ctls & AC_DIG1_ENABLE))
-                       snd_hda_codec_write(codec,
-                               nvhdmi_con_nids_7x[i],
-                               0,
-                               AC_VERB_SET_DIGI_CONVERT_1,
-                               codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
-               /* set the stream id */
-               snd_hda_codec_write(codec,
-                               nvhdmi_con_nids_7x[i],
-                               0,
-                               AC_VERB_SET_CHANNEL_STREAMID,
-                               (stream_tag << 4) | channel_id);
-               /* set the stream format */
-               snd_hda_codec_write(codec,
-                               nvhdmi_con_nids_7x[i],
-                               0,
-                               AC_VERB_SET_STREAM_FORMAT,
-                               format);
-               /* turn on again (if needed) */
-               /* enable and set the channel status audio/data flag */
-               if (codec->spdif_status_reset &&
-               (codec->spdif_ctls & AC_DIG1_ENABLE)) {
-                       snd_hda_codec_write(codec,
-                                       nvhdmi_con_nids_7x[i],
-                                       0,
-                                       AC_VERB_SET_DIGI_CONVERT_1,
-                                       codec->spdif_ctls & 0xff);
-                       snd_hda_codec_write(codec,
-                                       nvhdmi_con_nids_7x[i],
-                                       0,
-                                       AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
-               }
-       }
-
-       /* set the Audio Info Frame Checksum */
-       snd_hda_codec_write(codec, 0x1, 0,
-                       Nv_VERB_SET_Info_Frame_Checksum,
-                       (0x71 - chan - chanmask));
-
-       mutex_unlock(&codec->spdif_mutex);
-       return 0;
-}
-
-static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo,
-                                       struct hda_codec *codec,
-                                       unsigned int stream_tag,
-                                       unsigned int format,
-                                       struct snd_pcm_substream *substream)
-{
-       struct hdmi_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
-                                       format, substream);
-}
-
-static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_89 = {
-       .substreams = 1,
-       .channels_min = 2,
-       .ops = {
-               .open = hdmi_pcm_open,
-               .prepare = nvhdmi_dig_playback_pcm_prepare_8ch_89,
-       },
-};
-
-static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_7x = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 8,
-       .nid = nvhdmi_master_con_nid_7x,
-       .rates = SUPPORTED_RATES,
-       .maxbps = SUPPORTED_MAXBPS,
-       .formats = SUPPORTED_FORMATS,
-       .ops = {
-               .open = nvhdmi_dig_playback_pcm_open,
-               .close = nvhdmi_dig_playback_pcm_close_8ch_7x,
-               .prepare = nvhdmi_dig_playback_pcm_prepare_8ch
-       },
-};
-
-static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = nvhdmi_master_con_nid_7x,
-       .rates = SUPPORTED_RATES,
-       .maxbps = SUPPORTED_MAXBPS,
-       .formats = SUPPORTED_FORMATS,
-       .ops = {
-               .open = nvhdmi_dig_playback_pcm_open,
-               .close = nvhdmi_dig_playback_pcm_close_2ch,
-               .prepare = nvhdmi_dig_playback_pcm_prepare_2ch
-       },
-};
-
-static int nvhdmi_build_pcms_8ch_89(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct hda_pcm *info = spec->pcm_rec;
-       int i;
-
-       codec->num_pcms = spec->num_cvts;
-       codec->pcm_info = info;
-
-       for (i = 0; i < codec->num_pcms; i++, info++) {
-               unsigned int chans;
-
-               chans = get_wcaps(codec, spec->cvt[i]);
-               chans = get_wcaps_channels(chans);
-
-               info->name = nvhdmi_pcm_names[i];
-               info->pcm_type = HDA_PCM_TYPE_HDMI;
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK]
-                                       = nvhdmi_pcm_digital_playback_8ch_89;
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i];
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans;
-       }
-
-       return 0;
-}
-
-static int nvhdmi_build_pcms_8ch_7x(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct hda_pcm *info = spec->pcm_rec;
-
-       codec->num_pcms = 1;
-       codec->pcm_info = info;
-
-       info->name = "NVIDIA HDMI";
-       info->pcm_type = HDA_PCM_TYPE_HDMI;
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK]
-                                       = nvhdmi_pcm_digital_playback_8ch_7x;
-
-       return 0;
-}
-
-static int nvhdmi_build_pcms_2ch(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct hda_pcm *info = spec->pcm_rec;
-
-       codec->num_pcms = 1;
-       codec->pcm_info = info;
-
-       info->name = "NVIDIA HDMI";
-       info->pcm_type = HDA_PCM_TYPE_HDMI;
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK]
-                                       = nvhdmi_pcm_digital_playback_2ch;
-
-       return 0;
-}
-
-static struct hda_codec_ops nvhdmi_patch_ops_8ch_89 = {
-       .build_controls = nvhdmi_build_controls,
-       .build_pcms = nvhdmi_build_pcms_8ch_89,
-       .init = nvhdmi_init,
-       .free = nvhdmi_free,
-       .unsol_event = hdmi_unsol_event,
-};
-
-static struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = {
-       .build_controls = nvhdmi_build_controls,
-       .build_pcms = nvhdmi_build_pcms_8ch_7x,
-       .init = nvhdmi_init,
-       .free = nvhdmi_free,
-};
-
-static struct hda_codec_ops nvhdmi_patch_ops_2ch = {
-       .build_controls = nvhdmi_build_controls,
-       .build_pcms = nvhdmi_build_pcms_2ch,
-       .init = nvhdmi_init,
-       .free = nvhdmi_free,
-};
-
-static int patch_nvhdmi_8ch_89(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec;
-       int i;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
-       spec->codec_type = HDA_CODEC_NVIDIA_MCP89;
-       spec->old_pin_detect = 1;
-
-       if (hdmi_parse_codec(codec) < 0) {
-               codec->spec = NULL;
-               kfree(spec);
-               return -EINVAL;
-       }
-       codec->patch_ops = nvhdmi_patch_ops_8ch_89;
-
-       for (i = 0; i < spec->num_pins; i++)
-               snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i);
-
-       init_channel_allocations();
-
-       return 0;
-}
-
-static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
-
-       spec->multiout.num_dacs = 0;  /* no analog */
-       spec->multiout.max_channels = 8;
-       spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
-       spec->codec_type = HDA_CODEC_NVIDIA_MCP7X;
-       spec->old_pin_detect = 1;
-
-       codec->patch_ops = nvhdmi_patch_ops_8ch_7x;
-
-       return 0;
-}
-
-static int patch_nvhdmi_2ch(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
-
-       spec->multiout.num_dacs = 0;  /* no analog */
-       spec->multiout.max_channels = 2;
-       spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x;
-       spec->codec_type = HDA_CODEC_NVIDIA_MCP7X;
-       spec->old_pin_detect = 1;
-
-       codec->patch_ops = nvhdmi_patch_ops_2ch;
-
-       return 0;
-}
-
-/*
- * patch entries
- */
-static struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
-       { .id = 0x10de0002, .name = "MCP77/78 HDMI",  .patch = patch_nvhdmi_8ch_7x },
-       { .id = 0x10de0003, .name = "MCP77/78 HDMI",  .patch = patch_nvhdmi_8ch_7x },
-       { .id = 0x10de0005, .name = "MCP77/78 HDMI",  .patch = patch_nvhdmi_8ch_7x },
-       { .id = 0x10de0006, .name = "MCP77/78 HDMI",  .patch = patch_nvhdmi_8ch_7x },
-       { .id = 0x10de0007, .name = "MCP79/7A HDMI",  .patch = patch_nvhdmi_8ch_7x },
-       { .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de000c, .name = "MCP89 HDMI",     .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
-       { .id = 0x10de0067, .name = "MCP67 HDMI",     .patch = patch_nvhdmi_2ch },
-       { .id = 0x10de8001, .name = "MCP73 HDMI",     .patch = patch_nvhdmi_2ch },
-       {} /* terminator */
-};
-
-MODULE_ALIAS("snd-hda-codec-id:10de0002");
-MODULE_ALIAS("snd-hda-codec-id:10de0003");
-MODULE_ALIAS("snd-hda-codec-id:10de0005");
-MODULE_ALIAS("snd-hda-codec-id:10de0006");
-MODULE_ALIAS("snd-hda-codec-id:10de0007");
-MODULE_ALIAS("snd-hda-codec-id:10de000a");
-MODULE_ALIAS("snd-hda-codec-id:10de000b");
-MODULE_ALIAS("snd-hda-codec-id:10de000c");
-MODULE_ALIAS("snd-hda-codec-id:10de000d");
-MODULE_ALIAS("snd-hda-codec-id:10de0010");
-MODULE_ALIAS("snd-hda-codec-id:10de0011");
-MODULE_ALIAS("snd-hda-codec-id:10de0012");
-MODULE_ALIAS("snd-hda-codec-id:10de0013");
-MODULE_ALIAS("snd-hda-codec-id:10de0014");
-MODULE_ALIAS("snd-hda-codec-id:10de0018");
-MODULE_ALIAS("snd-hda-codec-id:10de0019");
-MODULE_ALIAS("snd-hda-codec-id:10de001a");
-MODULE_ALIAS("snd-hda-codec-id:10de001b");
-MODULE_ALIAS("snd-hda-codec-id:10de001c");
-MODULE_ALIAS("snd-hda-codec-id:10de0040");
-MODULE_ALIAS("snd-hda-codec-id:10de0041");
-MODULE_ALIAS("snd-hda-codec-id:10de0042");
-MODULE_ALIAS("snd-hda-codec-id:10de0043");
-MODULE_ALIAS("snd-hda-codec-id:10de0044");
-MODULE_ALIAS("snd-hda-codec-id:10de0067");
-MODULE_ALIAS("snd-hda-codec-id:10de8001");
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("NVIDIA HDMI HD-audio codec");
-
-static struct hda_codec_preset_list nvhdmi_list = {
-       .preset = snd_hda_preset_nvhdmi,
-       .owner = THIS_MODULE,
-};
-
-static int __init patch_nvhdmi_init(void)
-{
-       return snd_hda_add_codec_preset(&nvhdmi_list);
-}
-
-static void __exit patch_nvhdmi_exit(void)
-{
-       snd_hda_delete_codec_preset(&nvhdmi_list);
-}
-
-module_init(patch_nvhdmi_init)
-module_exit(patch_nvhdmi_exit)
index a432e6efd19bbe7bbce3ad9b6607c44661f912cf..5f00589cb791aebed2d7aa1f0bd908819b9123b8 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <sound/core.h>
+#include <sound/jack.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_beep.h"
@@ -282,6 +283,12 @@ struct alc_mic_route {
        unsigned char amix_idx;
 };
 
+struct alc_jack {
+       hda_nid_t nid;
+       int type;
+       struct snd_jack *jack;
+};
+
 #define MUX_IDX_UNDEF  ((unsigned char)-1)
 
 struct alc_customize_define {
@@ -294,6 +301,7 @@ struct alc_customize_define {
        unsigned int  platform_type:1;
        unsigned int  swap:1;
        unsigned int  override:1;
+       unsigned int  fixup:1; /* Means that this sku is set by driver, not read from hw */
 };
 
 struct alc_spec {
@@ -357,6 +365,9 @@ struct alc_spec {
        /* PCM information */
        struct hda_pcm pcm_rec[3];      /* used in alc_build_pcms() */
 
+       /* jack detection */
+       struct snd_array jacks;
+
        /* dynamic controls, init_verbs and input_mux */
        struct auto_pin_cfg autocfg;
        struct alc_customize_define cdefine;
@@ -383,6 +394,7 @@ struct alc_spec {
        unsigned int no_analog :1; /* digital I/O only */
        unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
        int init_amp;
+       int codec_variant;      /* flag for other variants */
 
        /* for virtual master */
        hda_nid_t vmaster_nid;
@@ -846,7 +858,7 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
 {
        unsigned int val = PIN_IN;
 
-       if (auto_pin_type <= AUTO_PIN_FRONT_MIC) {
+       if (auto_pin_type == AUTO_PIN_MIC) {
                unsigned int pincap;
                unsigned int oldval;
                oldval = snd_hda_codec_read(codec, nid, 0,
@@ -866,6 +878,28 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
        snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
 }
 
+static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+
+       if (!cfg->line_outs) {
+               while (cfg->line_outs < AUTO_CFG_MAX_OUTS &&
+                      cfg->line_out_pins[cfg->line_outs])
+                       cfg->line_outs++;
+       }
+       if (!cfg->speaker_outs) {
+               while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS &&
+                      cfg->speaker_pins[cfg->speaker_outs])
+                       cfg->speaker_outs++;
+       }
+       if (!cfg->hp_outs) {
+               while (cfg->hp_outs < AUTO_CFG_MAX_OUTS &&
+                      cfg->hp_pins[cfg->hp_outs])
+                       cfg->hp_outs++;
+       }
+}
+
 /*
  */
 static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
@@ -934,6 +968,8 @@ static void setup_preset(struct hda_codec *codec,
 
        if (preset->setup)
                preset->setup(codec);
+
+       alc_fixup_autocfg_pin_nums(codec);
 }
 
 /* Enable GPIO mask and set output */
@@ -990,25 +1026,136 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
        alc_fix_pll(codec);
 }
 
-static void alc_automute_pin(struct hda_codec *codec)
+#ifdef CONFIG_SND_HDA_INPUT_JACK
+static void alc_free_jack_priv(struct snd_jack *jack)
+{
+       struct alc_jack *jacks = jack->private_data;
+       jacks->nid = 0;
+       jacks->jack = NULL;
+}
+
+static int alc_add_jack(struct hda_codec *codec,
+               hda_nid_t nid, int type)
+{
+       struct alc_spec *spec;
+       struct alc_jack *jack;
+       const char *name;
+       int err;
+
+       spec = codec->spec;
+       snd_array_init(&spec->jacks, sizeof(*jack), 32);
+       jack = snd_array_new(&spec->jacks);
+       if (!jack)
+               return -ENOMEM;
+
+       jack->nid = nid;
+       jack->type = type;
+       name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;
+
+       err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
+       if (err < 0)
+               return err;
+       jack->jack->private_data = jack;
+       jack->jack->private_free = alc_free_jack_priv;
+       return 0;
+}
+
+static void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
 {
        struct alc_spec *spec = codec->spec;
-       unsigned int nid = spec->autocfg.hp_pins[0];
+       struct alc_jack *jacks = spec->jacks.list;
+
+       if (jacks) {
+               int i;
+               for (i = 0; i < spec->jacks.used; i++) {
+                       if (jacks->nid == nid) {
+                               unsigned int present;
+                               present = snd_hda_jack_detect(codec, nid);
+
+                               present = (present) ? jacks->type : 0;
+
+                               snd_jack_report(jacks->jack, present);
+                       }
+                       jacks++;
+               }
+       }
+}
+
+static int alc_init_jacks(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       int err;
+       unsigned int hp_nid = spec->autocfg.hp_pins[0];
+       unsigned int mic_nid = spec->ext_mic.pin;
+
+       if (hp_nid) {
+               err = alc_add_jack(codec, hp_nid, SND_JACK_HEADPHONE);
+               if (err < 0)
+                       return err;
+               alc_report_jack(codec, hp_nid);
+       }
+
+       if (mic_nid) {
+               err = alc_add_jack(codec, mic_nid, SND_JACK_MICROPHONE);
+               if (err < 0)
+                       return err;
+               alc_report_jack(codec, mic_nid);
+       }
+
+       return 0;
+}
+#else
+static inline void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
+{
+}
+
+static inline int alc_init_jacks(struct hda_codec *codec)
+{
+       return 0;
+}
+#endif
+
+static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
+{
+       struct alc_spec *spec = codec->spec;
+       unsigned int mute;
+       hda_nid_t nid;
        int i;
 
-       if (!nid)
-               return;
-       spec->jack_present = snd_hda_jack_detect(codec, nid);
+       spec->jack_present = 0;
+       for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
+               nid = spec->autocfg.hp_pins[i];
+               if (!nid)
+                       break;
+               if (snd_hda_jack_detect(codec, nid)) {
+                       spec->jack_present = 1;
+                       break;
+               }
+               alc_report_jack(codec, spec->autocfg.hp_pins[i]);
+       }
+
+       mute = spec->jack_present ? HDA_AMP_MUTE : 0;
+       /* Toggle internal speakers muting */
        for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
                nid = spec->autocfg.speaker_pins[i];
                if (!nid)
                        break;
-               snd_hda_codec_write(codec, nid, 0,
+               if (pinctl) {
+                       snd_hda_codec_write(codec, nid, 0,
                                    AC_VERB_SET_PIN_WIDGET_CONTROL,
                                    spec->jack_present ? 0 : PIN_OUT);
+               } else {
+                       snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
+                                        HDA_AMP_MUTE, mute);
+               }
        }
 }
 
+static void alc_automute_pin(struct hda_codec *codec)
+{
+       alc_automute_speaker(codec, 1);
+}
+
 static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
                                hda_nid_t nid)
 {
@@ -1090,6 +1237,7 @@ static void alc_mic_automute(struct hda_codec *codec)
                                          AC_VERB_SET_CONNECT_SEL,
                                          alive->mux_idx);
        }
+       alc_report_jack(codec, spec->ext_mic.pin);
 
        /* FIXME: analog mixer */
 }
@@ -1236,24 +1384,35 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
 static void alc_init_auto_hp(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
 
-       if (!spec->autocfg.hp_pins[0])
-               return;
+       if (!cfg->hp_pins[0]) {
+               if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+                       return;
+       }
 
-       if (!spec->autocfg.speaker_pins[0]) {
-               if (spec->autocfg.line_out_pins[0] &&
-                   spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
-                       spec->autocfg.speaker_pins[0] =
-                               spec->autocfg.line_out_pins[0];
-               else
+       if (!cfg->speaker_pins[0]) {
+               if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
                        return;
+               memcpy(cfg->speaker_pins, cfg->line_out_pins,
+                      sizeof(cfg->speaker_pins));
+               cfg->speaker_outs = cfg->line_outs;
        }
 
-       snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
-                   spec->autocfg.hp_pins[0]);
-       snd_hda_codec_write_cache(codec, spec->autocfg.hp_pins[0], 0,
+       if (!cfg->hp_pins[0]) {
+               memcpy(cfg->hp_pins, cfg->line_out_pins,
+                      sizeof(cfg->hp_pins));
+               cfg->hp_outs = cfg->line_outs;
+       }
+
+       for (i = 0; i < cfg->hp_outs; i++) {
+               snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
+                           cfg->hp_pins[i]);
+               snd_hda_codec_write_cache(codec, cfg->hp_pins[i], 0,
                                  AC_VERB_SET_UNSOLICITED_ENABLE,
                                  AC_USRSP_EN | ALC880_HP_EVENT);
+       }
        spec->unsol_event = alc_sku_unsol_event;
 }
 
@@ -1265,30 +1424,28 @@ static void alc_init_auto_mic(struct hda_codec *codec)
        int i;
 
        /* there must be only two mic inputs exclusively */
-       for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++)
-               if (cfg->input_pins[i])
+       for (i = 0; i < cfg->num_inputs; i++)
+               if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN)
                        return;
 
        fixed = ext = 0;
-       for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++) {
-               hda_nid_t nid = cfg->input_pins[i];
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
                unsigned int defcfg;
-               if (!nid)
-                       return;
                defcfg = snd_hda_codec_get_pincfg(codec, nid);
-               switch (get_defcfg_connect(defcfg)) {
-               case AC_JACK_PORT_FIXED:
+               switch (snd_hda_get_input_pin_attr(defcfg)) {
+               case INPUT_PIN_ATTR_INT:
                        if (fixed)
                                return; /* already occupied */
                        fixed = nid;
                        break;
-               case AC_JACK_PORT_COMPLEX:
+               case INPUT_PIN_ATTR_UNUSED:
+                       return; /* invalid entry */
+               default:
                        if (ext)
                                return; /* already occupied */
                        ext = nid;
                        break;
-               default:
-                       return; /* invalid entry */
                }
        }
        if (!ext || !fixed)
@@ -1308,6 +1465,11 @@ static void alc_init_auto_mic(struct hda_codec *codec)
        spec->unsol_event = alc_sku_unsol_event;
 }
 
+/* Could be any non-zero and even value. When used as fixup, tells
+ * the driver to ignore any present sku defines.
+ */
+#define ALC_FIXUP_SKU_IGNORE (2)
+
 static int alc_auto_parse_customize_define(struct hda_codec *codec)
 {
        unsigned int ass, tmp, i;
@@ -1316,6 +1478,13 @@ static int alc_auto_parse_customize_define(struct hda_codec *codec)
 
        spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
 
+       if (spec->cdefine.fixup) {
+               ass = spec->cdefine.sku_cfg;
+               if (ass == ALC_FIXUP_SKU_IGNORE)
+                       return -1;
+               goto do_sku;
+       }
+
        ass = codec->subsystem_id & 0xffff;
        if (ass != codec->bus->pci->subsystem_device && (ass & 1))
                goto do_sku;
@@ -1383,6 +1552,13 @@ static int alc_subsystem_id(struct hda_codec *codec,
        unsigned nid;
        struct alc_spec *spec = codec->spec;
 
+       if (spec->cdefine.fixup) {
+               ass = spec->cdefine.sku_cfg;
+               if (ass == ALC_FIXUP_SKU_IGNORE)
+                       return 0;
+               goto do_sku;
+       }
+
        ass = codec->subsystem_id & 0xffff;
        if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
                goto do_sku;
@@ -1502,6 +1678,7 @@ struct alc_pincfg {
 };
 
 struct alc_fixup {
+       unsigned int sku;
        const struct alc_pincfg *pins;
        const struct hda_verb *verbs;
 };
@@ -1512,12 +1689,22 @@ static void alc_pick_fixup(struct hda_codec *codec,
                           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);
+#endif
+               spec = codec->spec;
+               spec->cdefine.sku_cfg = fix->sku;
+               spec->cdefine.fixup = 1;
+       }
        if (pre_init && cfg) {
 #ifdef CONFIG_SND_DEBUG_VERBOSE
                snd_printdd(KERN_INFO "hda_codec: %s: Apply pincfg for %s\n",
@@ -1546,6 +1733,15 @@ static int alc_read_coef_idx(struct hda_codec *codec,
        return val;
 }
 
+static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx,
+                                                       unsigned int coef_val)
+{
+       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
+                           coef_idx);
+       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF,
+                           coef_val);
+}
+
 /* set right pin controls for digital I/O */
 static void alc_auto_init_digital(struct hda_codec *codec)
 {
@@ -1723,31 +1919,7 @@ static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
 
 static void alc_automute_amp(struct hda_codec *codec)
 {
-       struct alc_spec *spec = codec->spec;
-       unsigned int mute;
-       hda_nid_t nid;
-       int i;
-
-       spec->jack_present = 0;
-       for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
-               nid = spec->autocfg.hp_pins[i];
-               if (!nid)
-                       break;
-               if (snd_hda_jack_detect(codec, nid)) {
-                       spec->jack_present = 1;
-                       break;
-               }
-       }
-
-       mute = spec->jack_present ? HDA_AMP_MUTE : 0;
-       /* Toggle internal speakers muting */
-       for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
-               nid = spec->autocfg.speaker_pins[i];
-               if (!nid)
-                       break;
-               snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
-                                        HDA_AMP_MUTE, mute);
-       }
+       alc_automute_speaker(codec, 0);
 }
 
 static void alc_automute_amp_unsol_event(struct hda_codec *codec,
@@ -3602,10 +3774,7 @@ static int alc_init(struct hda_codec *codec)
        if (spec->init_hook)
                spec->init_hook(codec);
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (codec->patch_ops.check_power_status)
-               codec->patch_ops.check_power_status(codec, 0x01);
-#endif
+       hda_call_check_power_status(codec, 0x01);
        return 0;
 }
 
@@ -4001,10 +4170,7 @@ static int alc_resume(struct hda_codec *codec)
        codec->patch_ops.init(codec);
        snd_hda_codec_resume_amp(codec);
        snd_hda_codec_resume_cache(codec);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       if (codec->patch_ops.check_power_status)
-               codec->patch_ops.check_power_status(codec, 0x01);
-#endif
+       hda_call_check_power_status(codec, 0x01);
        return 0;
 }
 #endif
@@ -4729,7 +4895,7 @@ static struct snd_kcontrol_new alc880_control_templates[] = {
 
 /* add dynamic controls */
 static int add_control(struct alc_spec *spec, int type, const char *name,
-                      unsigned long val)
+                      int cidx, unsigned long val)
 {
        struct snd_kcontrol_new *knew;
 
@@ -4741,6 +4907,7 @@ static int add_control(struct alc_spec *spec, int type, const char *name,
        knew->name = kstrdup(name, GFP_KERNEL);
        if (!knew->name)
                return -ENOMEM;
+       knew->index = cidx;
        if (get_amp_nid_(val))
                knew->subdevice = HDA_SUBDEV_AMP_FLAG;
        knew->private_value = val;
@@ -4749,17 +4916,21 @@ static int add_control(struct alc_spec *spec, int type, const char *name,
 
 static int add_control_with_pfx(struct alc_spec *spec, int type,
                                const char *pfx, const char *dir,
-                               const char *sfx, unsigned long val)
+                               const char *sfx, int cidx, unsigned long val)
 {
        char name[32];
        snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
-       return add_control(spec, type, name, val);
+       return add_control(spec, type, name, cidx, val);
 }
 
-#define add_pb_vol_ctrl(spec, type, pfx, val) \
-       add_control_with_pfx(spec, type, pfx, "Playback", "Volume", val)
-#define add_pb_sw_ctrl(spec, type, pfx, val) \
-       add_control_with_pfx(spec, type, pfx, "Playback", "Switch", val)
+#define add_pb_vol_ctrl(spec, type, pfx, val)                  \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
+#define add_pb_sw_ctrl(spec, type, pfx, val)                   \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
+#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val)                  \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
+#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val)                   \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
 
 #define alc880_is_fixed_pin(nid)       ((nid) >= 0x14 && (nid) <= 0x17)
 #define alc880_fixed_pin_idx(nid)      ((nid) - 0x14)
@@ -4912,16 +5083,16 @@ static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
 
 /* create input playback/capture controls for the given pin */
 static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
-                           const char *ctlname,
+                           const char *ctlname, int ctlidx,
                            int idx, hda_nid_t mix_nid)
 {
        int err;
 
-       err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
+       err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx,
                          HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
        if (err < 0)
                return err;
-       err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
+       err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx,
                          HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
        if (err < 0)
                return err;
@@ -4942,20 +5113,27 @@ 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;
+       int i, err, idx, type, type_idx = 0;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
+       for (i = 0; i < cfg->num_inputs; i++) {
                hda_nid_t pin;
+               const char *label;
 
-               pin = cfg->input_pins[i];
+               pin = cfg->inputs[i].pin;
                if (!alc_is_input_pin(codec, pin))
                        continue;
 
+               type = cfg->inputs[i].type;
+               if (i > 0 && type == cfg->inputs[i - 1].type)
+                       type_idx++;
+               else
+                       type_idx = 0;
+               label = hda_get_autocfg_input_label(codec, cfg, i);
                if (mixer) {
                        idx = get_connection_index(codec, mixer, pin);
                        if (idx >= 0) {
                                err = new_analog_input(spec, pin,
-                                                      auto_pin_cfg_labels[i],
+                                                      label, type_idx,
                                                       idx, mixer);
                                if (err < 0)
                                        return err;
@@ -4967,12 +5145,8 @@ static int alc_auto_create_input_ctls(struct hda_codec *codec,
                idx = get_connection_index(codec, cap1, pin);
                if (idx < 0 && cap2)
                        idx = get_connection_index(codec, cap2, pin);
-               if (idx >= 0) {
-                       imux->items[imux->num_items].label =
-                               auto_pin_cfg_labels[i];
-                       imux->items[imux->num_items].index = idx;
-                       imux->num_items++;
-               }
+               if (idx >= 0)
+                       snd_hda_add_imux_item(imux, label, idx, NULL);
        }
        return 0;
 }
@@ -5044,12 +5218,13 @@ static void alc880_auto_init_extra_out(struct hda_codec *codec)
 static void alc880_auto_init_analog_input(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = spec->autocfg.input_pins[i];
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
                if (alc_is_input_pin(codec, nid)) {
-                       alc_set_input_pin(codec, nid, i);
+                       alc_set_input_pin(codec, nid, cfg->inputs[i].type);
                        if (nid != ALC880_PIN_CD_NID &&
                            (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
@@ -5214,19 +5389,13 @@ static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
 static void fixup_single_adc(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       hda_nid_t pin = 0;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
 
        /* search for the input pin; there must be only one */
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (spec->autocfg.input_pins[i]) {
-                       pin = spec->autocfg.input_pins[i];
-                       break;
-               }
-       }
-       if (!pin)
+       if (cfg->num_inputs != 1)
                return;
-       i = init_capsrc_for_pin(codec, pin);
+       i = init_capsrc_for_pin(codec, cfg->inputs[0].pin);
        if (i >= 0) {
                /* use only this ADC */
                if (spec->capsrc_nids)
@@ -5279,6 +5448,7 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
                                 int num_nids)
 {
        struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
        int n;
        hda_nid_t fallback_adc = 0, fallback_cap = 0;
 
@@ -5304,10 +5474,8 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
                        fallback_adc = adc;
                        fallback_cap = cap;
                }
-               for (i = 0; i < AUTO_PIN_LAST; i++) {
-                       hda_nid_t nid = spec->autocfg.input_pins[i];
-                       if (!nid)
-                               continue;
+               for (i = 0; i < cfg->num_inputs; i++) {
+                       hda_nid_t nid = cfg->inputs[i].pin;
                        for (j = 0; j < nconns; j++) {
                                if (conn[j] == nid)
                                        break;
@@ -5315,7 +5483,7 @@ static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
                        if (j >= nconns)
                                break;
                }
-               if (i >= AUTO_PIN_LAST) {
+               if (i >= cfg->num_inputs) {
                        int num_adcs = spec->num_adc_nids;
                        spec->private_adc_nids[num_adcs] = adc;
                        spec->private_capsrc_nids[num_adcs] = cap;
@@ -6683,12 +6851,13 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec)
 static void alc260_auto_init_analog_input(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = spec->autocfg.input_pins[i];
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
                if (nid >= 0x12) {
-                       alc_set_input_pin(codec, nid, i);
+                       alc_set_input_pin(codec, nid, cfg->inputs[i].type);
                        if (nid != ALC260_PIN_CD_NID &&
                            (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
@@ -6810,14 +6979,12 @@ enum {
        PINFIX_HP_DC5750,
 };
 
-static struct alc_pincfg alc260_hp_dc5750_pinfix[] = {
-       { 0x11, 0x90130110 }, /* speaker */
-       { }
-};
-
 static const struct alc_fixup alc260_fixups[] = {
        [PINFIX_HP_DC5750] = {
-               .pins = alc260_hp_dc5750_pinfix
+               .pins = (const struct alc_pincfg[]) {
+                       { 0x11, 0x90130110 }, /* speaker */
+                       { }
+               }
        },
 };
 
@@ -10461,32 +10628,33 @@ static struct alc_config_preset alc882_presets[] = {
 enum {
        PINFIX_ABIT_AW9D_MAX,
        PINFIX_PB_M5210,
-};
-
-static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
-       { 0x15, 0x01080104 }, /* side */
-       { 0x16, 0x01011012 }, /* rear */
-       { 0x17, 0x01016011 }, /* clfe */
-       { }
-};
-
-static const struct hda_verb pb_m5210_verbs[] = {
-       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
-       {}
+       PINFIX_ACER_ASPIRE_7736,
 };
 
 static const struct alc_fixup alc882_fixups[] = {
        [PINFIX_ABIT_AW9D_MAX] = {
-               .pins = alc882_abit_aw9d_pinfix
+               .pins = (const struct alc_pincfg[]) {
+                       { 0x15, 0x01080104 }, /* side */
+                       { 0x16, 0x01011012 }, /* rear */
+                       { 0x17, 0x01016011 }, /* clfe */
+                       { }
+               }
        },
        [PINFIX_PB_M5210] = {
-               .verbs = pb_m5210_verbs
+               .verbs = (const struct hda_verb[]) {
+                       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
+                       {}
+               }
+       },
+       [PINFIX_ACER_ASPIRE_7736] = {
+               .sku = ALC_FIXUP_SKU_IGNORE,
        },
 };
 
 static struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
        SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
+       SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
        {}
 };
 
@@ -10535,16 +10703,21 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
        hda_nid_t pin, dac;
+       int i;
 
-       pin = spec->autocfg.hp_pins[0];
-       if (pin) {
+       for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
+               pin = spec->autocfg.hp_pins[i];
+               if (!pin)
+                       break;
                dac = spec->multiout.hp_nid;
                if (!dac)
                        dac = spec->multiout.dac_nids[0]; /* to front */
                alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
        }
-       pin = spec->autocfg.speaker_pins[0];
-       if (pin) {
+       for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
+               pin = spec->autocfg.speaker_pins[i];
+               if (!pin)
+                       break;
                dac = spec->multiout.extra_out_nid[0];
                if (!dac)
                        dac = spec->multiout.dac_nids[0]; /* to front */
@@ -10555,13 +10728,12 @@ static void alc882_auto_init_hp_out(struct hda_codec *codec)
 static void alc882_auto_init_analog_input(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = spec->autocfg.input_pins[i];
-               if (!nid)
-                       continue;
-               alc_set_input_pin(codec, nid, i);
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               alc_set_input_pin(codec, nid, cfg->inputs[i].type);
                if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
                        snd_hda_codec_write(codec, nid, 0,
                                            AC_VERB_SET_AMP_GAIN_MUTE,
@@ -10623,24 +10795,23 @@ static void alc882_auto_init_input_src(struct hda_codec *codec)
 static int alc_auto_add_mic_boost(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       int err;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i, err;
        hda_nid_t nid;
 
-       nid = spec->autocfg.input_pins[AUTO_PIN_MIC];
-       if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
-               err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                 "Mic Boost",
-                                 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
-               if (err < 0)
-                       return err;
-       }
-       nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC];
-       if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) {
-               err = add_control(spec, ALC_CTL_WIDGET_VOL,
-                                 "Front Mic Boost",
+       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];
+                       snprintf(label, sizeof(label), "%s Boost",
+                                hda_get_autocfg_input_label(codec, cfg, i));
+                       err = add_control(spec, ALC_CTL_WIDGET_VOL, label, 0,
                                  HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
-               if (err < 0)
-                       return err;
+                       if (err < 0)
+                               return err;
+               }
        }
        return 0;
 }
@@ -10726,8 +10897,6 @@ static int patch_alc882(struct hda_codec *codec)
 
        codec->spec = spec;
 
-       alc_auto_parse_customize_define(codec);
-
        switch (codec->vendor_id) {
        case 0x10ec0882:
        case 0x10ec0885:
@@ -10755,6 +10924,8 @@ static int patch_alc882(struct hda_codec *codec)
        if (board_config == ALC882_AUTO)
                alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 1);
 
+       alc_auto_parse_customize_define(codec);
+
        if (board_config == ALC882_AUTO) {
                /* automatic parse from the BIOS config */
                err = alc882_parse_auto_config(codec);
@@ -10835,6 +11006,8 @@ static int patch_alc882(struct hda_codec *codec)
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC882_AUTO)
                spec->init_hook = alc882_auto_init;
+
+       alc_init_jacks(codec);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc882_loopbacks;
@@ -11831,7 +12004,7 @@ static int alc262_check_volbit(hda_nid_t nid)
 }
 
 static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
-                                 const char *pfx, int *vbits)
+                                 const char *pfx, int *vbits, int idx)
 {
        unsigned long val;
        int vbit;
@@ -11846,11 +12019,11 @@ static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
                val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
        else
                val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
-       return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, val);
+       return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, val);
 }
 
 static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
-                                const char *pfx)
+                                const char *pfx, int idx)
 {
        unsigned long val;
 
@@ -11860,7 +12033,7 @@ static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
                val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
        else
                val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
-       return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val);
+       return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, val);
 }
 
 /* add playback controls from the parsed DAC table */
@@ -11869,7 +12042,7 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
 {
        const char *pfx;
        int vbits;
-       int err;
+       int i, err;
 
        spec->multiout.num_dacs = 1;    /* only use one dac */
        spec->multiout.dac_nids = spec->private_dac_nids;
@@ -11879,39 +12052,52 @@ static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
                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 = "Front";
-       err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[0], pfx);
-       if (err < 0)
-               return err;
-       err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[0], "Speaker");
-       if (err < 0)
-               return err;
-       err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[0], "Headphone");
-       if (err < 0)
-               return err;
+       for (i = 0; i < 2; i++) {
+               err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx, i);
+               if (err < 0)
+                       return err;
+               if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+                       err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[i],
+                                                   "Speaker", i);
+                       if (err < 0)
+                               return err;
+               }
+               if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
+                       err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[i],
+                                                   "Headphone", i);
+                       if (err < 0)
+                               return err;
+               }
+       }
 
        vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
                alc262_check_volbit(cfg->speaker_pins[0]) |
                alc262_check_volbit(cfg->hp_pins[0]);
        if (vbits == 1 || vbits == 2)
                pfx = "Master"; /* only one mixer is used */
-       else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-               pfx = "Speaker";
-       else
-               pfx = "Front";
        vbits = 0;
-       err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[0], pfx, &vbits);
-       if (err < 0)
-               return err;
-       err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[0], "Speaker",
-                                    &vbits);
-       if (err < 0)
-               return err;
-       err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[0], "Headphone",
-                                    &vbits);
-       if (err < 0)
-               return err;
+       for (i = 0; i < 2; i++) {
+               err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[i], pfx,
+                                            &vbits, i);
+               if (err < 0)
+                       return err;
+               if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+                       err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[i],
+                                                    "Speaker", &vbits, i);
+                       if (err < 0)
+                               return err;
+               }
+               if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
+                       err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[i],
+                                                    "Headphone", &vbits, i);
+                       if (err < 0)
+                               return err;
+               }
+       }
        return 0;
 }
 
@@ -12199,6 +12385,35 @@ static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
        {}
 };
 
+/*
+ * Pin config fixes
+ */
+enum {
+       PINFIX_FSC_H270,
+};
+
+static const struct alc_fixup alc262_fixups[] = {
+       [PINFIX_FSC_H270] = {
+               .pins = (const struct alc_pincfg[]) {
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x15, 0x0221142f }, /* front HP */
+                       { 0x1b, 0x0121141f }, /* rear HP */
+                       { }
+               }
+       },
+       [PINFIX_PB_M5210] = {
+               .verbs = (const struct hda_verb[]) {
+                       { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
+                       {}
+               }
+       },
+};
+
+static struct snd_pci_quirk alc262_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
+       {}
+};
+
 
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 #define alc262_loopbacks       alc880_loopbacks
@@ -12622,6 +12837,9 @@ static int patch_alc262(struct hda_codec *codec)
                board_config = ALC262_AUTO;
        }
 
+       if (board_config == ALC262_AUTO)
+               alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 1);
+
        if (board_config == ALC262_AUTO) {
                /* automatic parse from the BIOS config */
                err = alc262_parse_auto_config(codec);
@@ -12690,11 +12908,16 @@ static int patch_alc262(struct hda_codec *codec)
        if (!spec->no_analog && has_cdefine_beep(codec))
                set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
 
+       if (board_config == ALC262_AUTO)
+               alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 0);
+
        spec->vmaster_nid = 0x0c;
 
        codec->patch_ops = alc_patch_ops;
        if (board_config == ALC262_AUTO)
                spec->init_hook = alc262_auto_init;
+
+       alc_init_jacks(codec);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc262_loopbacks;
@@ -13310,8 +13533,10 @@ static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
 static void alc268_auto_init_multi_out(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
-       hda_nid_t nid = spec->autocfg.line_out_pins[0];
-       if (nid) {
+       int i;
+
+       for (i = 0; i < spec->autocfg.line_outs; i++) {
+               hda_nid_t nid = spec->autocfg.line_out_pins[i];
                int pin_type = get_pin_type(spec->autocfg.line_out_type);
                alc268_auto_set_output_and_unmute(codec, nid, pin_type);
        }
@@ -13321,13 +13546,19 @@ static void alc268_auto_init_hp_out(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
        hda_nid_t pin;
+       int i;
 
-       pin = spec->autocfg.hp_pins[0];
-       if (pin)
+       for (i = 0; i < spec->autocfg.hp_outs; i++) {
+               pin = spec->autocfg.hp_pins[i];
                alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
-       pin = spec->autocfg.speaker_pins[0];
-       if (pin)
+       }
+       for (i = 0; i < spec->autocfg.speaker_outs; i++) {
+               pin = spec->autocfg.speaker_pins[i];
                alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
+       }
+       if (spec->autocfg.mono_out_pin)
+               snd_hda_codec_write(codec, spec->autocfg.mono_out_pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
 }
 
 static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
@@ -13766,6 +13997,8 @@ static int patch_alc268(struct hda_codec *codec)
        if (board_config == ALC268_AUTO)
                spec->init_hook = alc268_auto_init;
 
+       alc_init_jacks(codec);
+
        return 0;
 }
 
@@ -14132,6 +14365,7 @@ static void alc269_speaker_automute(struct hda_codec *codec)
                                 HDA_AMP_MUTE, bits);
        snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
                                 HDA_AMP_MUTE, bits);
+       alc_report_jack(codec, nid);
 }
 
 /* unsolicited event for HP jack sensing */
@@ -14386,6 +14620,13 @@ static int alc275_setup_dual_adc(struct hda_codec *codec)
        return 0;
 }
 
+/* different alc269-variants */
+enum {
+       ALC269_TYPE_NORMAL,
+       ALC269_TYPE_ALC259,
+       ALC269_TYPE_ALC271X,
+};
+
 /*
  * BIOS auto configuration
  */
@@ -14403,7 +14644,11 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
        if (err < 0)
                return err;
-       err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
+       if (spec->codec_variant == ALC269_TYPE_NORMAL)
+               err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
+       else
+               err = alc_auto_create_input_ctls(codec, &spec->autocfg, 0,
+                                                0x22, 0);
        if (err < 0)
                return err;
 
@@ -14414,7 +14659,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        if (spec->kctls.list)
                add_mixer(spec, spec->kctls.list);
 
-       if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010) {
+       if (spec->codec_variant != ALC269_TYPE_NORMAL) {
                add_verb(spec, alc269vb_init_verbs);
                alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
        } else {
@@ -14461,19 +14706,71 @@ static void alc269_auto_init(struct hda_codec *codec)
                alc_inithook(codec);
 }
 
+#ifdef SND_HDA_NEEDS_RESUME
+static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
+{
+       int val = alc_read_coef_idx(codec, 0x04);
+       if (power_up)
+               val |= 1 << 11;
+       else
+               val &= ~(1 << 11);
+       alc_write_coef_idx(codec, 0x04, val);
+}
+
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static int alc269_suspend(struct hda_codec *codec, pm_message_t state)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
+               alc269_toggle_power_output(codec, 0);
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+               alc269_toggle_power_output(codec, 0);
+               msleep(150);
+       }
+
+       alc_shutup(codec);
+       if (spec && spec->power_hook)
+               spec->power_hook(codec);
+       return 0;
+}
+#endif /* CONFIG_SND_HDA_POWER_SAVE */
+
+static int alc269_resume(struct hda_codec *codec)
+{
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+               alc269_toggle_power_output(codec, 0);
+               msleep(150);
+       }
+
+       codec->patch_ops.init(codec);
+
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
+               alc269_toggle_power_output(codec, 1);
+               msleep(200);
+       }
+
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018)
+               alc269_toggle_power_output(codec, 1);
+
+       snd_hda_codec_resume_amp(codec);
+       snd_hda_codec_resume_cache(codec);
+       hda_call_check_power_status(codec, 0x01);
+       return 0;
+}
+#endif /* SND_HDA_NEEDS_RESUME */
+
 enum {
        ALC269_FIXUP_SONY_VAIO,
        ALC269_FIXUP_DELL_M101Z,
 };
 
-static const struct hda_verb alc269_sony_vaio_fixup_verbs[] = {
-       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
-       {}
-};
-
 static const struct alc_fixup alc269_fixups[] = {
        [ALC269_FIXUP_SONY_VAIO] = {
-               .verbs = alc269_sony_vaio_fixup_verbs
+               .verbs = (const struct hda_verb[]) {
+                       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
+                       {}
+               }
        },
        [ALC269_FIXUP_DELL_M101Z] = {
                .verbs = (const struct hda_verb[]) {
@@ -14486,8 +14783,7 @@ static const struct alc_fixup alc269_fixups[] = {
 };
 
 static struct snd_pci_quirk alc269_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
-       SND_PCI_QUIRK(0x104d, 0x9077, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
+       SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
        SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
        {}
 };
@@ -14689,12 +14985,46 @@ static struct alc_config_preset alc269_presets[] = {
        },
 };
 
+static int alc269_fill_coef(struct hda_codec *codec)
+{
+       int val;
+
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) {
+               alc_write_coef_idx(codec, 0xf, 0x960b);
+               alc_write_coef_idx(codec, 0xe, 0x8817);
+       }
+
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) {
+               alc_write_coef_idx(codec, 0xf, 0x960b);
+               alc_write_coef_idx(codec, 0xe, 0x8814);
+       }
+
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
+               val = alc_read_coef_idx(codec, 0x04);
+               /* Power up output pin */
+               alc_write_coef_idx(codec, 0x04, val | (1<<11));
+       }
+
+       if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
+               val = alc_read_coef_idx(codec, 0xd);
+               if ((val & 0x0c00) >> 10 != 0x1) {
+                       /* Capless ramp up clock control */
+                       alc_write_coef_idx(codec, 0xd, val | 1<<10);
+               }
+               val = alc_read_coef_idx(codec, 0x17);
+               if ((val & 0x01c0) >> 6 != 0x4) {
+                       /* Class D power on reset */
+                       alc_write_coef_idx(codec, 0x17, val | 1<<7);
+               }
+       }
+       return 0;
+}
+
 static int patch_alc269(struct hda_codec *codec)
 {
        struct alc_spec *spec;
        int board_config;
        int err;
-       int is_alc269vb = 0;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
@@ -14706,14 +15036,18 @@ static int patch_alc269(struct hda_codec *codec)
 
        if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
                if (codec->bus->pci->subsystem_vendor == 0x1025 &&
-                   spec->cdefine.platform_type == 1)
+                   spec->cdefine.platform_type == 1) {
                        alc_codec_rename(codec, "ALC271X");
-               else
+                       spec->codec_variant = ALC269_TYPE_ALC271X;
+               } else {
                        alc_codec_rename(codec, "ALC259");
-               is_alc269vb = 1;
+                       spec->codec_variant = ALC269_TYPE_ALC259;
+               }
        } else
                alc_fix_pll_init(codec, 0x20, 0x04, 15);
 
+       alc269_fill_coef(codec);
+
        board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
                                                  alc269_models,
                                                  alc269_cfg_tbl);
@@ -14770,7 +15104,7 @@ static int patch_alc269(struct hda_codec *codec)
        spec->stream_digital_capture = &alc269_pcm_digital_capture;
 
        if (!spec->adc_nids) { /* wasn't filled automatically? use default */
-               if (!is_alc269vb) {
+               if (spec->codec_variant != ALC269_TYPE_NORMAL) {
                        spec->adc_nids = alc269_adc_nids;
                        spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
                        spec->capsrc_nids = alc269_capsrc_nids;
@@ -14792,8 +15126,16 @@ static int patch_alc269(struct hda_codec *codec)
        spec->vmaster_nid = 0x02;
 
        codec->patch_ops = alc_patch_ops;
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+       codec->patch_ops.suspend = alc269_suspend;
+#endif
+#ifdef SND_HDA_NEEDS_RESUME
+       codec->patch_ops.resume = alc269_resume;
+#endif
        if (board_config == ALC269_AUTO)
                spec->init_hook = alc269_auto_init;
+
+       alc_init_jacks(codec);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc269_loopbacks;
@@ -15606,12 +15948,13 @@ static void alc861_auto_init_hp_out(struct hda_codec *codec)
 static void alc861_auto_init_analog_input(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = spec->autocfg.input_pins[i];
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
                if (nid >= 0x0c && nid <= 0x11)
-                       alc_set_input_pin(codec, nid, i);
+                       alc_set_input_pin(codec, nid, cfg->inputs[i].type);
        }
 }
 
@@ -15840,15 +16183,13 @@ enum {
        PINFIX_FSC_AMILO_PI1505,
 };
 
-static struct alc_pincfg alc861_fsc_amilo_pi1505_pinfix[] = {
-       { 0x0b, 0x0221101f }, /* HP */
-       { 0x0f, 0x90170310 }, /* speaker */
-       { }
-};
-
 static const struct alc_fixup alc861_fixups[] = {
        [PINFIX_FSC_AMILO_PI1505] = {
-               .pins = alc861_fsc_amilo_pi1505_pinfix
+               .pins = (const struct alc_pincfg[]) {
+                       { 0x0b, 0x0221101f }, /* HP */
+                       { 0x0f, 0x90170310 }, /* speaker */
+                       { }
+               }
        },
 };
 
@@ -16600,12 +16941,13 @@ static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
 static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = spec->autocfg.input_pins[i];
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
                if (alc_is_input_pin(codec, nid)) {
-                       alc_set_input_pin(codec, nid, i);
+                       alc_set_input_pin(codec, nid, cfg->inputs[i].type);
                        if (nid != ALC861VD_PIN_CD_NID &&
                            (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
@@ -16815,16 +17157,14 @@ enum {
 };
 
 /* reset GPIO1 */
-static const struct hda_verb alc660vd_fix_asus_gpio1_verbs[] = {
-       {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
-       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
-       {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
-       { }
-};
-
 static const struct alc_fixup alc861vd_fixups[] = {
        [ALC660VD_FIX_ASUS_GPIO1] = {
-               .verbs = alc660vd_fix_asus_gpio1_verbs,
+               .verbs = (const struct hda_verb[]) {
+                       {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
+                       {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
+                       {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
+                       { }
+               }
        },
 };
 
@@ -18838,12 +19178,13 @@ static void alc662_auto_init_hp_out(struct hda_codec *codec)
 static void alc662_auto_init_analog_input(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = spec->autocfg.input_pins[i];
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
                if (alc_is_input_pin(codec, nid)) {
-                       alc_set_input_pin(codec, nid, i);
+                       alc_set_input_pin(codec, nid, cfg->inputs[i].type);
                        if (nid != ALC662_PIN_CD_NID &&
                            (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
                                snd_hda_codec_write(codec, nid, 0,
@@ -18935,10 +19276,40 @@ static void alc662_auto_init(struct hda_codec *codec)
                alc_inithook(codec);
 }
 
+enum {
+       ALC662_FIXUP_ASPIRE,
+       ALC662_FIXUP_IDEAPAD,
+};
+
+static const struct alc_fixup alc662_fixups[] = {
+       [ALC662_FIXUP_ASPIRE] = {
+               .pins = (const struct alc_pincfg[]) {
+                       { 0x15, 0x99130112 }, /* subwoofer */
+                       { }
+               }
+       },
+       [ALC662_FIXUP_IDEAPAD] = {
+               .pins = (const struct alc_pincfg[]) {
+                       { 0x17, 0x99130112 }, /* subwoofer */
+                       { }
+               }
+       },
+};
+
+static struct snd_pci_quirk alc662_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
+       SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
+       SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
+       {}
+};
+
+
+
 static int patch_alc662(struct hda_codec *codec)
 {
        struct alc_spec *spec;
        int err, board_config;
+       int coef;
 
        spec = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (!spec)
@@ -18950,12 +19321,15 @@ static int patch_alc662(struct hda_codec *codec)
 
        alc_fix_pll_init(codec, 0x20, 0x04, 15);
 
-       if (alc_read_coef_idx(codec, 0) == 0x8020)
+       coef = alc_read_coef_idx(codec, 0);
+       if (coef == 0x8020 || coef == 0x8011)
                alc_codec_rename(codec, "ALC661");
-       else if ((alc_read_coef_idx(codec, 0) & (1 << 14)) &&
-                codec->bus->pci->subsystem_vendor == 0x1025 &&
-                spec->cdefine.platform_type == 1)
+       else if (coef & (1 << 14) &&
+               codec->bus->pci->subsystem_vendor == 0x1025 &&
+               spec->cdefine.platform_type == 1)
                alc_codec_rename(codec, "ALC272X");
+       else if (coef == 0x4011)
+               alc_codec_rename(codec, "ALC656");
 
        board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
                                                  alc662_models,
@@ -18967,6 +19341,7 @@ static int patch_alc662(struct hda_codec *codec)
        }
 
        if (board_config == ALC662_AUTO) {
+               alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 1);
                /* automatic parse from the BIOS config */
                err = alc662_parse_auto_config(codec);
                if (err < 0) {
@@ -19025,8 +19400,13 @@ static int patch_alc662(struct hda_codec *codec)
        spec->vmaster_nid = 0x02;
 
        codec->patch_ops = alc_patch_ops;
-       if (board_config == ALC662_AUTO)
+       if (board_config == ALC662_AUTO) {
                spec->init_hook = alc662_auto_init;
+               alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 0);
+       }
+
+       alc_init_jacks(codec);
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
        if (!spec->loopback.amplist)
                spec->loopback.amplist = alc662_loopbacks;
@@ -19070,6 +19450,39 @@ static hda_nid_t alc680_adc_nids[3] = {
 /*
  * Analog capture ADC cgange
  */
+static void alc680_rec_autoswitch(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int pin_found = 0;
+       int type_found = AUTO_PIN_LAST;
+       hda_nid_t nid;
+       int i;
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               nid = cfg->inputs[i].pin;
+               if (!(snd_hda_query_pin_caps(codec, nid) &
+                     AC_PINCAP_PRES_DETECT))
+                       continue;
+               if (snd_hda_jack_detect(codec, nid)) {
+                       if (cfg->inputs[i].type < type_found) {
+                               type_found = cfg->inputs[i].type;
+                               pin_found = nid;
+                       }
+               }
+       }
+
+       nid = 0x07;
+       if (pin_found)
+               snd_hda_get_connections(codec, pin_found, &nid, 1);
+
+       if (nid != spec->cur_adc)
+               __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
+       spec->cur_adc = nid;
+       snd_hda_codec_setup_stream(codec, nid, spec->cur_adc_stream_tag, 0,
+                                  spec->cur_adc_format);
+}
+
 static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
                                      struct hda_codec *codec,
                                      unsigned int stream_tag,
@@ -19077,24 +19490,12 @@ static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
                                      struct snd_pcm_substream *substream)
 {
        struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       unsigned int pre_mic, pre_line;
-
-       pre_mic  = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_MIC]);
-       pre_line = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_LINE]);
 
+       spec->cur_adc = 0x07;
        spec->cur_adc_stream_tag = stream_tag;
        spec->cur_adc_format = format;
 
-       if (pre_mic || pre_line) {
-               if (pre_mic)
-                       snd_hda_codec_setup_stream(codec, 0x08, stream_tag, 0,
-                                                                       format);
-               else
-                       snd_hda_codec_setup_stream(codec, 0x09, stream_tag, 0,
-                                                                       format);
-       } else
-               snd_hda_codec_setup_stream(codec, 0x07, stream_tag, 0, format);
+       alc680_rec_autoswitch(codec);
        return 0;
 }
 
@@ -19180,6 +19581,7 @@ static struct hda_verb alc680_init_verbs[] = {
 
        {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT   | AC_USRSP_EN},
        {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT  | AC_USRSP_EN},
+       {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT  | AC_USRSP_EN},
 
        { }
 };
@@ -19192,25 +19594,11 @@ static void alc680_base_setup(struct hda_codec *codec)
        spec->autocfg.hp_pins[0] = 0x16;
        spec->autocfg.speaker_pins[0] = 0x14;
        spec->autocfg.speaker_pins[1] = 0x15;
-       spec->autocfg.input_pins[AUTO_PIN_MIC] = 0x18;
-       spec->autocfg.input_pins[AUTO_PIN_LINE] = 0x19;
-}
-
-static void alc680_rec_autoswitch(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       unsigned int present;
-       hda_nid_t new_adc;
-
-       present = snd_hda_jack_detect(codec, cfg->input_pins[AUTO_PIN_MIC]);
-
-       new_adc = present ? 0x8 : 0x7;
-       __snd_hda_codec_cleanup_stream(codec, !present ? 0x8 : 0x7, 1);
-       snd_hda_codec_setup_stream(codec, new_adc,
-                                  spec->cur_adc_stream_tag, 0,
-                                  spec->cur_adc_format);
-
+       spec->autocfg.num_inputs = 2;
+       spec->autocfg.inputs[0].pin = 0x18;
+       spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
+       spec->autocfg.inputs[1].pin = 0x19;
+       spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
 }
 
 static void alc680_unsol_event(struct hda_codec *codec,
index c16c5ba0fda0fe61387d6924a6b84307b0dedcbb..82ebeb9544fe54296ab3043d9a25e34cee04f415 100644 (file)
@@ -32,6 +32,7 @@
 #include <sound/core.h>
 #include <sound/asoundef.h>
 #include <sound/jack.h>
+#include <sound/tlv.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_beep.h"
@@ -263,6 +264,7 @@ struct sigmatel_spec {
 
        struct sigmatel_mic_route ext_mic;
        struct sigmatel_mic_route int_mic;
+       struct sigmatel_mic_route dock_mic;
 
        const char **spdif_labels;
 
@@ -382,6 +384,11 @@ static unsigned int stac92hd83xxx_pwr_mapping[4] = {
        0x03, 0x0c, 0x20, 0x40,
 };
 
+#define STAC92HD83XXX_NUM_DMICS         2
+static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = {
+       0x11, 0x20, 0
+};
+
 #define STAC92HD83XXX_NUM_CAPS 2
 static unsigned long stac92hd83xxx_capvols[] = {
        HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
@@ -986,7 +993,7 @@ static struct hda_verb stac9205_core_init[] = {
        }
 
 static struct snd_kcontrol_new stac9200_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
@@ -1014,7 +1021,7 @@ static struct snd_kcontrol_new stac92hd71bxx_loopback[] = {
 };
 
 static struct snd_kcontrol_new stac925x_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x0e, 0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MIN_MUTE("Master Playback Volume", 0xe, 0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Master Playback Switch", 0x0e, 0, HDA_OUTPUT),
        { } /* end */
 };
@@ -1105,9 +1112,7 @@ static int stac92xx_build_controls(struct hda_codec *codec)
                struct hda_input_mux *smux = &spec->private_smux;
                /* check for mute support on SPDIF out */
                if (wcaps & AC_WCAP_OUT_AMP) {
-                       smux->items[smux->num_items].label = "Off";
-                       smux->items[smux->num_items].index = 0;
-                       smux->num_items++;
+                       snd_hda_add_imux_item(smux, "Off", 0, NULL);
                        spec->spdif_mute = 1;
                }
                stac_smux_mixer.count = spec->num_smuxes;
@@ -1140,6 +1145,8 @@ static int stac92xx_build_controls(struct hda_codec *codec)
                                        HDA_OUTPUT, vmaster_tlv);
                /* correct volume offset */
                vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset;
+               /* minimum value is actually mute */
+               vmaster_tlv[3] |= TLV_DB_SCALE_MUTE;
                err = snd_hda_add_vmaster(codec, "Master Playback Volume",
                                          vmaster_tlv, slave_vols);
                if (err < 0)
@@ -1180,14 +1187,11 @@ static int stac92xx_build_controls(struct hda_codec *codec)
                if (err < 0)
                        return err;
        }
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               nid = cfg->input_pins[i];
-               if (nid) {
-                       err = stac92xx_add_jack(codec, nid,
-                                               SND_JACK_MICROPHONE);
-                       if (err < 0)
-                               return err;
-               }
+       for (i = 0; i < cfg->num_inputs; i++) {
+               nid = cfg->inputs[i].pin;
+               err = stac92xx_add_jack(codec, nid, SND_JACK_MICROPHONE);
+               if (err < 0)
+                       return err;
        }
 
        return 0;       
@@ -2779,7 +2783,7 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
        struct sigmatel_spec *spec = codec->spec;
        char name[22];
 
-       if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) {
+       if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) {
                if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD
                        && nid == spec->line_switch)
                        control = STAC_CTL_WIDGET_IO_SWITCH;
@@ -2791,7 +2795,7 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
        }
 
        if (control) {
-               strcpy(name, auto_pin_cfg_labels[idx]);
+               strcpy(name, hda_get_input_pin_label(codec, nid, 1));
                return stac92xx_add_control(codec->spec, control,
                                        strcat(name, " Jack Mode"), nid);
        }
@@ -2823,41 +2827,49 @@ static hda_nid_t check_line_out_switch(struct hda_codec *codec)
        struct auto_pin_cfg *cfg = &spec->autocfg;
        hda_nid_t nid;
        unsigned int pincap;
+       int i;
 
        if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
                return 0;
-       nid = cfg->input_pins[AUTO_PIN_LINE];
-       pincap = snd_hda_query_pin_caps(codec, nid);
-       if (pincap & AC_PINCAP_OUT)
-               return nid;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               if (cfg->inputs[i].type == AUTO_PIN_LINE_IN) {
+                       nid = cfg->inputs[i].pin;
+                       pincap = snd_hda_query_pin_caps(codec, nid);
+                       if (pincap & AC_PINCAP_OUT)
+                               return nid;
+               }
+       }
        return 0;
 }
 
+static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid);
+
 /* check whether the mic-input can be used as line-out */
-static hda_nid_t check_mic_out_switch(struct hda_codec *codec)
+static hda_nid_t check_mic_out_switch(struct hda_codec *codec, hda_nid_t *dac)
 {
        struct sigmatel_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
        unsigned int def_conf, pincap;
-       unsigned int mic_pin;
+       int i;
 
+       *dac = 0;
        if (cfg->line_out_type != AUTO_PIN_LINE_OUT)
                return 0;
-       mic_pin = AUTO_PIN_MIC;
-       for (;;) {
-               hda_nid_t nid = cfg->input_pins[mic_pin];
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               if (cfg->inputs[i].type != AUTO_PIN_MIC)
+                       continue;
                def_conf = snd_hda_codec_get_pincfg(codec, nid);
                /* some laptops have an internal analog microphone
                 * which can't be used as a output */
-               if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) {
+               if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) {
                        pincap = snd_hda_query_pin_caps(codec, nid);
-                       if (pincap & AC_PINCAP_OUT)
-                               return nid;
+                       if (pincap & AC_PINCAP_OUT) {
+                               *dac = get_unassigned_dac(codec, nid);
+                               if (*dac)
+                                       return nid;
+                       }
                }
-               if (mic_pin == AUTO_PIN_MIC)
-                       mic_pin = AUTO_PIN_FRONT_MIC;
-               else
-                       break;
        }
        return 0;
 }
@@ -3004,17 +3016,14 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec)
                }
        }
        /* add mic as output */
-       nid = check_mic_out_switch(codec);
-       if (nid) {
-               dac = get_unassigned_dac(codec, nid);
-               if (dac) {
-                       snd_printdd("STAC: Add mic-in 0x%x as output %d\n",
-                                   nid, cfg->line_outs);
-                       cfg->line_out_pins[cfg->line_outs] = nid;
-                       cfg->line_outs++;
-                       spec->mic_switch = nid;
-                       add_spec_dacs(spec, dac);
-               }
+       nid = check_mic_out_switch(codec, &dac);
+       if (nid && dac) {
+               snd_printdd("STAC: Add mic-in 0x%x as output %d\n",
+                           nid, cfg->line_outs);
+               cfg->line_out_pins[cfg->line_outs] = nid;
+               cfg->line_outs++;
+               spec->mic_switch = nid;
+               add_spec_dacs(spec, dac);
        }
 
        snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
@@ -3204,13 +3213,13 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
                        return err;
        }
 
-       for (idx = AUTO_PIN_MIC; idx <= AUTO_PIN_FRONT_LINE; idx++) {
-               nid = cfg->input_pins[idx];
-               if (nid) {
-                       err = stac92xx_add_jack_mode_control(codec, nid, idx);
-                       if (err < 0)
-                               return err;
-               }
+       for (idx = 0; idx < cfg->num_inputs; idx++) {
+               if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN)
+                       break;
+               nid = cfg->inputs[idx].pin;
+               err = stac92xx_add_jack_mode_control(codec, nid, idx);
+               if (err < 0)
+                       return err;
        }
 
        return 0;
@@ -3256,12 +3265,9 @@ static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec)
        if (num_cons <= 0 || num_cons > ARRAY_SIZE(stac92xx_mono_labels))
                return -EINVAL;
 
-       for (i = 0; i < num_cons; i++) {
-               mono_mux->items[mono_mux->num_items].label =
-                                       stac92xx_mono_labels[i];
-               mono_mux->items[mono_mux->num_items].index = i;
-               mono_mux->num_items++;
-       }
+       for (i = 0; i < num_cons; i++)
+               snd_hda_add_imux_item(mono_mux, stac92xx_mono_labels[i], i,
+                                     NULL);
 
        return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX,
                                "Mono Mux", spec->mono_nid);
@@ -3386,11 +3392,8 @@ static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
        if (!labels)
                labels = stac92xx_spdif_labels;
 
-       for (i = 0; i < num_cons; i++) {
-               spdif_mux->items[spdif_mux->num_items].label = labels[i];
-               spdif_mux->items[spdif_mux->num_items].index = i;
-               spdif_mux->num_items++;
-       }
+       for (i = 0; i < num_cons; i++)
+               snd_hda_add_imux_item(spdif_mux, labels[i], i, NULL);
 
        return 0;
 }
@@ -3417,7 +3420,7 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
 /* create a volume assigned to the given pin (only if supported) */
 /* return 1 if the volume control is created */
 static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid,
-                                  const char *label, int direction)
+                                  const char *label, int idx, int direction)
 {
        unsigned int caps, nums;
        char name[32];
@@ -3434,8 +3437,8 @@ static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid,
        if (!nums)
                return 0;
        snprintf(name, sizeof(name), "%s Capture Volume", label);
-       err = stac92xx_add_control(codec->spec, STAC_CTL_WIDGET_VOL, name,
-                                   HDA_COMPOSE_AMP_VAL(nid, 3, 0, direction));
+       err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, name,
+                                      HDA_COMPOSE_AMP_VAL(nid, 3, 0, direction));
        if (err < 0)
                return err;
        return 1;
@@ -3448,27 +3451,14 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
        struct sigmatel_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux;
        struct hda_input_mux *dimux = &spec->private_dimux;
-       int err, i, active_mics;
+       int err, i;
        unsigned int def_conf;
 
-       dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0];
-       dimux->items[dimux->num_items].index = 0;
-       dimux->num_items++;
-
-       active_mics = 0;
-       for (i = 0; i < spec->num_dmics; i++) {
-               /* check the validity: sometimes it's a dead vendor-spec node */
-               if (get_wcaps_type(get_wcaps(codec, spec->dmic_nids[i]))
-                   != AC_WID_PIN)
-                       continue;
-               def_conf = snd_hda_codec_get_pincfg(codec, spec->dmic_nids[i]);
-               if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)
-                       active_mics++;
-       }
+       snd_hda_add_imux_item(dimux, stac92xx_dmic_labels[0], 0, NULL);
 
        for (i = 0; i < spec->num_dmics; i++) {
                hda_nid_t nid;
-               int index;
+               int index, type_idx;
                const char *label;
 
                nid = spec->dmic_nids[i];
@@ -3482,28 +3472,23 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
                if (index < 0)
                        continue;
 
-               if (active_mics == 1)
-                       label = "Digital Mic";
-               else
-                       label = stac92xx_dmic_labels[dimux->num_items];
+               label = hda_get_input_pin_label(codec, nid, 1);
+               snd_hda_add_imux_item(dimux, label, index, &type_idx);
 
-               err = create_elem_capture_vol(codec, nid, label, HDA_INPUT);
+               err = create_elem_capture_vol(codec, nid, label, type_idx,
+                                             HDA_INPUT);
                if (err < 0)
                        return err;
                if (!err) {
                        err = create_elem_capture_vol(codec, nid, label,
-                                                     HDA_OUTPUT);
+                                                     type_idx, HDA_OUTPUT);
                        if (err < 0)
                                return err;
                }
 
-               dimux->items[dimux->num_items].label = label;
-               dimux->items[dimux->num_items].index = index;
-               dimux->num_items++;
                if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) {
-                       imux->items[imux->num_items].label = label;
-                       imux->items[imux->num_items].index = index;
-                       imux->num_items++;
+                       snd_hda_add_imux_item(imux, label, index, NULL);
+                       spec->num_analog_muxes++;
                }
        }
 
@@ -3511,20 +3496,27 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec,
 }
 
 static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid,
-                        hda_nid_t *fixed, hda_nid_t *ext)
+                        hda_nid_t *fixed, hda_nid_t *ext, hda_nid_t *dock)
 {
        unsigned int cfg;
 
        if (!nid)
                return 0;
        cfg = snd_hda_codec_get_pincfg(codec, nid);
-       switch (get_defcfg_connect(cfg)) {
-       case AC_JACK_PORT_FIXED:
+       switch (snd_hda_get_input_pin_attr(cfg)) {
+       case INPUT_PIN_ATTR_INT:
                if (*fixed)
                        return 1; /* already occupied */
                *fixed = nid;
                break;
-       case AC_JACK_PORT_COMPLEX:
+       case INPUT_PIN_ATTR_UNUSED:
+               break;
+       case INPUT_PIN_ATTR_DOCK:
+               if (*dock)
+                       return 1; /* already occupied */
+               *dock = nid;
+               break;
+       default:
                if (*ext)
                        return 1; /* already occupied */
                *ext = nid;
@@ -3542,10 +3534,13 @@ static int set_mic_route(struct hda_codec *codec,
        int i;
 
        mic->pin = pin;
-       for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++)
-               if (pin == cfg->input_pins[i])
+       if (pin == 0)
+               return 0;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               if (pin == cfg->inputs[i].pin)
                        break;
-       if (i <= AUTO_PIN_FRONT_MIC) {
+       }
+       if (i < cfg->num_inputs && cfg->inputs[i].type == AUTO_PIN_MIC) {
                /* analog pin */
                i = get_connection_index(codec, spec->mux_nids[0], pin);
                if (i < 0)
@@ -3576,26 +3571,29 @@ static int stac_check_auto_mic(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
-       hda_nid_t fixed, ext;
+       hda_nid_t fixed, ext, dock;
        int i;
 
-       for (i = AUTO_PIN_LINE; i < AUTO_PIN_LAST; i++) {
-               if (cfg->input_pins[i])
+       for (i = 0; i < cfg->num_inputs; i++) {
+               if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN)
                        return 0; /* must be exclusively mics */
        }
-       fixed = ext = 0;
-       for (i = AUTO_PIN_MIC; i <= AUTO_PIN_FRONT_MIC; i++)
-               if (check_mic_pin(codec, cfg->input_pins[i], &fixed, &ext))
+       fixed = ext = dock = 0;
+       for (i = 0; i < cfg->num_inputs; i++)
+               if (check_mic_pin(codec, cfg->inputs[i].pin,
+                   &fixed, &ext, &dock))
                        return 0;
        for (i = 0; i < spec->num_dmics; i++)
-               if (check_mic_pin(codec, spec->dmic_nids[i], &fixed, &ext))
+               if (check_mic_pin(codec, spec->dmic_nids[i],
+                   &fixed, &ext, &dock))
                        return 0;
-       if (!fixed || !ext)
-               return 0;
+       if (!fixed && !ext && !dock)
+               return 0; /* no input to switch */
        if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
                return 0; /* no unsol support */
        if (set_mic_route(codec, &spec->ext_mic, ext) ||
-           set_mic_route(codec, &spec->int_mic, fixed))
+           set_mic_route(codec, &spec->int_mic, fixed) ||
+           set_mic_route(codec, &spec->dock_mic, dock))
                return 0; /* something is wrong */
        return 1;
 }
@@ -3606,13 +3604,12 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const
        struct sigmatel_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux;
        int i, j;
+       const char *label;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = cfg->input_pins[i];
-               int index, err;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               int index, err, type_idx;
 
-               if (!nid)
-                       continue;
                index = -1;
                for (j = 0; j < spec->num_muxes; j++) {
                        index = get_connection_index(codec, spec->mux_nids[j],
@@ -3623,15 +3620,14 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const
                if (index < 0)
                        continue;
 
+               label = hda_get_autocfg_input_label(codec, cfg, i);
+               snd_hda_add_imux_item(imux, label, index, &type_idx);
+
                err = create_elem_capture_vol(codec, nid,
-                                             auto_pin_cfg_labels[i],
+                                             label, type_idx,
                                              HDA_INPUT);
                if (err < 0)
                        return err;
-
-               imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
-               imux->items[imux->num_items].index = index;
-               imux->num_items++;
        }
        spec->num_analog_muxes = imux->num_items;
 
@@ -4305,38 +4301,38 @@ static int stac92xx_init(struct hda_codec *codec)
                                          AC_VERB_SET_CONNECT_SEL, 0);
                if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT))
                        stac_issue_unsol_event(codec, spec->ext_mic.pin);
-       }
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = cfg->input_pins[i];
-               if (nid) {
-                       unsigned int pinctl, conf;
-                       if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) {
-                               /* for mic pins, force to initialize */
-                               pinctl = stac92xx_get_default_vref(codec, nid);
+               if (enable_pin_detect(codec, spec->dock_mic.pin,
+                   STAC_MIC_EVENT))
+                       stac_issue_unsol_event(codec, spec->dock_mic.pin);
+       }
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               int type = cfg->inputs[i].type;
+               unsigned int pinctl, conf;
+               if (type == AUTO_PIN_MIC) {
+                       /* for mic pins, force to initialize */
+                       pinctl = stac92xx_get_default_vref(codec, nid);
+                       pinctl |= AC_PINCTL_IN_EN;
+                       stac92xx_auto_set_pinctl(codec, nid, pinctl);
+               } else {
+                       pinctl = snd_hda_codec_read(codec, nid, 0,
+                                       AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+                       /* if PINCTL already set then skip */
+                       /* Also, if both INPUT and OUTPUT are set,
+                        * it must be a BIOS bug; need to override, too
+                        */
+                       if (!(pinctl & AC_PINCTL_IN_EN) ||
+                           (pinctl & AC_PINCTL_OUT_EN)) {
+                               pinctl &= ~AC_PINCTL_OUT_EN;
                                pinctl |= AC_PINCTL_IN_EN;
                                stac92xx_auto_set_pinctl(codec, nid, pinctl);
-                       } else {
-                               pinctl = snd_hda_codec_read(codec, nid, 0,
-                                       AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-                               /* if PINCTL already set then skip */
-                               /* Also, if both INPUT and OUTPUT are set,
-                                * it must be a BIOS bug; need to override, too
-                                */
-                               if (!(pinctl & AC_PINCTL_IN_EN) ||
-                                   (pinctl & AC_PINCTL_OUT_EN)) {
-                                       pinctl &= ~AC_PINCTL_OUT_EN;
-                                       pinctl |= AC_PINCTL_IN_EN;
-                                       stac92xx_auto_set_pinctl(codec, nid,
-                                                                pinctl);
-                               }
-                       }
-                       conf = snd_hda_codec_get_pincfg(codec, nid);
-                       if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
-                               if (enable_pin_detect(codec, nid,
-                                                     STAC_INSERT_EVENT))
-                                       stac_issue_unsol_event(codec, nid);
                        }
                }
+               conf = snd_hda_codec_get_pincfg(codec, nid);
+               if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) {
+                       if (enable_pin_detect(codec, nid, STAC_INSERT_EVENT))
+                               stac_issue_unsol_event(codec, nid);
+               }
        }
        for (i = 0; i < spec->num_dmics; i++)
                stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i],
@@ -4383,11 +4379,9 @@ static int stac92xx_init(struct hda_codec *codec)
                        stac_issue_unsol_event(codec, nid);
        }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
        /* sync mute LED */
-       if (spec->gpio_led && codec->patch_ops.check_power_status)
-               codec->patch_ops.check_power_status(codec, 0x01);
-#endif 
+       if (spec->gpio_led)
+               hda_call_check_power_status(codec, 0x01);
        if (spec->dac_list)
                stac92xx_power_down(codec);
        return 0;
@@ -4688,6 +4682,36 @@ static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
        }
 }
 
+/* get the pin connection (fixed, none, etc) */
+static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       unsigned int cfg;
+
+       cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]);
+       return get_defcfg_connect(cfg);
+}
+
+static int stac92xx_connected_ports(struct hda_codec *codec,
+                                        hda_nid_t *nids, int num_nids)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       int idx, num;
+       unsigned int def_conf;
+
+       for (num = 0; num < num_nids; num++) {
+               for (idx = 0; idx < spec->num_pins; idx++)
+                       if (spec->pin_nids[idx] == nids[num])
+                               break;
+               if (idx >= spec->num_pins)
+                       break;
+               def_conf = stac_get_defcfg_connect(codec, idx);
+               if (def_conf == AC_JACK_PORT_NONE)
+                       break;
+       }
+       return num;
+}
+
 static void stac92xx_mic_detect(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
@@ -4695,6 +4719,8 @@ static void stac92xx_mic_detect(struct hda_codec *codec)
 
        if (get_pin_presence(codec, spec->ext_mic.pin))
                mic = &spec->ext_mic;
+       else if (get_pin_presence(codec, spec->dock_mic.pin))
+               mic = &spec->dock_mic;
        else
                mic = &spec->int_mic;
        if (mic->dmux_idx >= 0)
@@ -4937,11 +4963,9 @@ static int stac92xx_resume(struct hda_codec *codec)
                        stac_issue_unsol_event(codec,
                                               spec->autocfg.line_out_pins[0]);
        }
-#ifdef CONFIG_SND_HDA_POWER_SAVE
        /* sync mute LED */
-       if (spec->gpio_led && codec->patch_ops.check_power_status)
-               codec->patch_ops.check_power_status(codec, 0x01);
-#endif 
+       if (spec->gpio_led)
+               hda_call_check_power_status(codec, 0x01);
        return 0;
 }
 
@@ -5313,11 +5337,16 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
        if (spec == NULL)
                return -ENOMEM;
 
+       /* reset pin power-down; Windows may leave these bits after reboot */
+       snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7EC, 0);
+       snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7ED, 0);
        codec->no_trigger_sense = 1;
        codec->spec = spec;
        spec->linear_tone_beep = 1;
        codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs;
        spec->digbeep_nid = 0x21;
+       spec->dmic_nids = stac92hd83xxx_dmic_nids;
+       spec->dmux_nids = stac92hd83xxx_mux_nids;
        spec->mux_nids = stac92hd83xxx_mux_nids;
        spec->num_muxes = ARRAY_SIZE(stac92hd83xxx_mux_nids);
        spec->adc_nids = stac92hd83xxx_adc_nids;
@@ -5363,9 +5392,13 @@ again:
        case 0x111d76d4:
        case 0x111d7605:
        case 0x111d76d5:
+       case 0x111d76e7:
                if (spec->board_config == STAC_92HD83XXX_PWR_REF)
                        break;
                spec->num_pwrs = 0;
+               spec->num_dmics = stac92xx_connected_ports(codec,
+                               stac92hd83xxx_dmic_nids,
+                               STAC92HD83XXX_NUM_DMICS);
                break;
        }
 
@@ -5424,36 +5457,6 @@ again:
        return 0;
 }
 
-/* get the pin connection (fixed, none, etc) */
-static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       unsigned int cfg;
-
-       cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]);
-       return get_defcfg_connect(cfg);
-}
-
-static int stac92hd71bxx_connected_ports(struct hda_codec *codec,
-                                        hda_nid_t *nids, int num_nids)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       int idx, num;
-       unsigned int def_conf;
-
-       for (num = 0; num < num_nids; num++) {
-               for (idx = 0; idx < spec->num_pins; idx++)
-                       if (spec->pin_nids[idx] == nids[num])
-                               break;
-               if (idx >= spec->num_pins)
-                       break;
-               def_conf = stac_get_defcfg_connect(codec, idx);
-               if (def_conf == AC_JACK_PORT_NONE)
-                       break;
-       }
-       return num;
-}
-
 static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec,
                                          hda_nid_t dig0pin)
 {
@@ -5592,7 +5595,7 @@ again:
        case 0x111d76b5:
                spec->init = stac92hd71bxx_core_init;
                codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
-               spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+               spec->num_dmics = stac92xx_connected_ports(codec,
                                        stac92hd71bxx_dmic_nids,
                                        STAC92HD71BXX_NUM_DMICS);
                break;
@@ -5624,7 +5627,7 @@ again:
                snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
                snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
                stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS - 1] = 0;
-               spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+               spec->num_dmics = stac92xx_connected_ports(codec,
                                        stac92hd71bxx_dmic_nids,
                                        STAC92HD71BXX_NUM_DMICS - 1);
                break;
@@ -5638,7 +5641,7 @@ again:
        default:
                spec->init = stac92hd71bxx_core_init;
                codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
-               spec->num_dmics = stac92hd71bxx_connected_ports(codec,
+               spec->num_dmics = stac92xx_connected_ports(codec,
                                        stac92hd71bxx_dmic_nids,
                                        STAC92HD71BXX_NUM_DMICS);
                break;
@@ -6320,6 +6323,8 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = {
        { .id = 0x111d76cc, .name = "92HD89F3", .patch = patch_stac92hd73xx },
        { .id = 0x111d76cd, .name = "92HD89F2", .patch = patch_stac92hd73xx },
        { .id = 0x111d76ce, .name = "92HD89F1", .patch = patch_stac92hd73xx },
+       { .id = 0x111d76e0, .name = "92HD91BXX", .patch = patch_stac92hd83xxx},
+       { .id = 0x111d76e7, .name = "92HD90BXX", .patch = patch_stac92hd83xxx},
        {} /* terminator */
 };
 
index ae3acb2b42d11366a2d24bd768d823dbc61853b4..d1c3f8defc48d059f42124542d4e09b1fda000cf 100644 (file)
@@ -444,8 +444,8 @@ static hda_nid_t vt1812_adc_nids[2] = {
 
 
 /* add dynamic controls */
-static int via_add_control(struct via_spec *spec, int type, const char *name,
-                          unsigned long val)
+static int __via_add_control(struct via_spec *spec, int type, const char *name,
+                            int idx, unsigned long val)
 {
        struct snd_kcontrol_new *knew;
 
@@ -463,6 +463,9 @@ static int via_add_control(struct via_spec *spec, int type, const char *name,
        return 0;
 }
 
+#define via_add_control(spec, type, name, val) \
+       __via_add_control(spec, type, name, 0, val)
+
 static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec,
                                                struct snd_kcontrol_new *tmpl)
 {
@@ -494,18 +497,18 @@ static void via_free_kctls(struct hda_codec *codec)
 
 /* create input playback/capture controls for the given pin */
 static int via_new_analog_input(struct via_spec *spec, const char *ctlname,
-                               int idx, int mix_nid)
+                               int type_idx, int idx, int mix_nid)
 {
        char name[32];
        int err;
 
        sprintf(name, "%s Playback Volume", ctlname);
-       err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
+       err = __via_add_control(spec, VIA_CTL_WIDGET_VOL, name, type_idx,
                              HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
        if (err < 0)
                return err;
        sprintf(name, "%s Playback Switch", ctlname);
-       err = via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name,
+       err = __via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name, type_idx,
                              HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
        if (err < 0)
                return err;
@@ -557,17 +560,15 @@ static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin);
 static void via_auto_init_analog_input(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
        unsigned int ctl;
        int i;
 
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               hda_nid_t nid = spec->autocfg.input_pins[i];
-               if (!nid)
-                       continue;
-
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
                if (spec->smart51_enabled && is_smart51_pins(spec, nid))
                        ctl = PIN_OUT;
-               else if (i <= AUTO_PIN_FRONT_MIC)
+               else if (i == AUTO_PIN_MIC)
                        ctl = PIN_VREF50;
                else
                        ctl = PIN_IN;
@@ -1322,15 +1323,14 @@ static void mute_aa_path(struct hda_codec *codec, int mute)
 }
 static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin)
 {
-       int res = 0;
-       int index;
-       for (index = AUTO_PIN_MIC; index < AUTO_PIN_FRONT_LINE; index++) {
-               if (pin == spec->autocfg.input_pins[index]) {
-                       res = 1;
-                       break;
-               }
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               if (pin == cfg->inputs[i].pin)
+                       return cfg->inputs[i].type <= AUTO_PIN_LINE_IN;
        }
-       return res;
+       return 0;
 }
 
 static int via_smart51_info(struct snd_kcontrol *kcontrol,
@@ -1348,25 +1348,21 @@ static int via_smart51_get(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_spec *spec = codec->spec;
-       int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
        int on = 1;
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(index); i++) {
-               hda_nid_t nid = spec->autocfg.input_pins[index[i]];
-               if (nid) {
-                       int ctl =
-                           snd_hda_codec_read(codec, nid, 0,
-                                              AC_VERB_GET_PIN_WIDGET_CONTROL,
-                                              0);
-                       if (i == AUTO_PIN_FRONT_MIC
-                           && spec->hp_independent_mode
-                           && spec->codec_type != VT1718S)
-                               continue; /* ignore FMic for independent HP */
-                       if (ctl & AC_PINCTL_IN_EN
-                           && !(ctl & AC_PINCTL_OUT_EN))
-                               on = 0;
-               }
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               int ctl = snd_hda_codec_read(codec, nid, 0,
+                                            AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+               if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
+                       continue;
+               if (cfg->inputs[i].type == AUTO_PIN_MIC &&
+                   spec->hp_independent_mode && spec->codec_type != VT1718S)
+                       continue; /* ignore FMic for independent HP */
+               if ((ctl & AC_PINCTL_IN_EN) && !(ctl & AC_PINCTL_OUT_EN))
+                       on = 0;
        }
        *ucontrol->value.integer.value = on;
        return 0;
@@ -1377,36 +1373,38 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct via_spec *spec = codec->spec;
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
        int out_in = *ucontrol->value.integer.value
                ? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN;
-       int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(index); i++) {
-               hda_nid_t nid = spec->autocfg.input_pins[index[i]];
-               if (i == AUTO_PIN_FRONT_MIC
-                   && spec->hp_independent_mode
-                   && spec->codec_type != VT1718S)
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               unsigned int parm;
+
+               if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
+                       continue;
+               if (cfg->inputs[i].type == AUTO_PIN_MIC &&
+                   spec->hp_independent_mode && spec->codec_type != VT1718S)
                        continue; /* don't retask FMic for independent HP */
-               if (nid) {
-                       unsigned int parm = snd_hda_codec_read(
-                               codec, nid, 0,
-                               AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-                       parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
-                       parm |= out_in;
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           parm);
-                       if (out_in == AC_PINCTL_OUT_EN) {
-                               mute_aa_path(codec, 1);
-                               notify_aa_path_ctls(codec);
-                       }
-                       if (spec->codec_type == VT1718S)
-                               snd_hda_codec_amp_stereo(
+
+               parm = snd_hda_codec_read(codec, nid, 0,
+                                         AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+               parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
+               parm |= out_in;
+               snd_hda_codec_write(codec, nid, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                   parm);
+               if (out_in == AC_PINCTL_OUT_EN) {
+                       mute_aa_path(codec, 1);
+                       notify_aa_path_ctls(codec);
+               }
+               if (spec->codec_type == VT1718S) {
+                       snd_hda_codec_amp_stereo(
                                        codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE,
                                        HDA_AMP_UNMUTE);
                }
-               if (i == AUTO_PIN_FRONT_MIC) {
+               if (cfg->inputs[i].type == AUTO_PIN_MIC) {
                        if (spec->codec_type == VT1708S
                            || spec->codec_type == VT1716S) {
                                /* input = index 1 (AOW3) */
@@ -1442,7 +1440,7 @@ static struct snd_kcontrol_new via_smart51_mixer[2] = {
 static int via_smart51_build(struct via_spec *spec)
 {
        struct snd_kcontrol_new *knew;
-       int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE };
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
        hda_nid_t nid;
        int i;
 
@@ -1450,13 +1448,14 @@ static int via_smart51_build(struct via_spec *spec)
        if (knew == NULL)
                return -ENOMEM;
 
-       for (i = 0; i < ARRAY_SIZE(index); i++) {
-               nid = spec->autocfg.input_pins[index[i]];
-               if (nid) {
+       for (i = 0; i < cfg->num_inputs; i++) {
+               nid = cfg->inputs[i].pin;
+               if (cfg->inputs[i].type <= AUTO_PIN_LINE_IN) {
                        knew = via_clone_control(spec, &via_smart51_mixer[1]);
                        if (knew == NULL)
                                return -ENOMEM;
                        knew->subdevice = nid;
+                       break;
                }
        }
 
@@ -2375,13 +2374,8 @@ static void create_hp_imux(struct via_spec *spec)
        static const char *texts[] = { "OFF", "ON", NULL};
 
        /* for hp mode select */
-       i = 0;
-       while (texts[i] != NULL) {
-               imux->items[imux->num_items].label =  texts[i];
-               imux->items[imux->num_items].index = i;
-               imux->num_items++;
-               i++;
-       }
+       for (i = 0; texts[i]; i++)
+               snd_hda_add_imux_item(imux, texts[i], i, NULL);
 
        spec->hp_mux = &spec->private_imux[1];
 }
@@ -2413,51 +2407,53 @@ static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 }
 
 /* create playback/capture controls for input pins */
-static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec,
-                                               const struct auto_pin_cfg *cfg)
+static int vt_auto_create_analog_input_ctls(struct hda_codec *codec,
+                                           const struct auto_pin_cfg *cfg,
+                                           hda_nid_t cap_nid,
+                                           hda_nid_t pin_idxs[], int num_idxs)
 {
-       static char *labels[] = {
-               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-       };
+       struct via_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx = 0;
+       int i, err, idx, type, type_idx = 0;
 
        /* for internal loopback recording select */
-       imux->items[imux->num_items].label = "Stereo Mixer";
-       imux->items[imux->num_items].index = idx;
-       imux->num_items++;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (!cfg->input_pins[i])
-                       continue;
-
-               switch (cfg->input_pins[i]) {
-               case 0x1d: /* Mic */
-                       idx = 2;
-                       break;
-
-               case 0x1e: /* Line In */
-                       idx = 3;
-                       break;
-
-               case 0x21: /* Front Mic */
-                       idx = 4;
-                       break;
-
-               case 0x24: /* CD */
-                       idx = 1;
+       for (idx = 0; idx < num_idxs; idx++) {
+               if (pin_idxs[idx] == 0xff) {
+                       snd_hda_add_imux_item(imux, "Stereo Mixer", idx, NULL);
                        break;
                }
-               err = via_new_analog_input(spec, labels[i], idx, 0x17);
+       }
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               const char *label;
+               type = cfg->inputs[i].type;
+               for (idx = 0; idx < num_idxs; idx++)
+                       if (pin_idxs[idx] == cfg->inputs[i].pin)
+                               break;
+               if (idx >= num_idxs)
+                       continue;
+               if (i > 0 && type == cfg->inputs[i - 1].type)
+                       type_idx++;
+               else
+                       type_idx = 0;
+               label = hda_get_autocfg_input_label(codec, cfg, i);
+               err = via_new_analog_input(spec, label, type_idx, idx, cap_nid);
                if (err < 0)
                        return err;
-               imux->items[imux->num_items].label = labels[i];
-               imux->items[imux->num_items].index = idx;
-               imux->num_items++;
+               snd_hda_add_imux_item(imux, label, idx, NULL);
        }
        return 0;
 }
 
+/* create playback/capture controls for input pins */
+static int vt1708_auto_create_analog_input_ctls(struct hda_codec *codec,
+                                               const struct auto_pin_cfg *cfg)
+{
+       static hda_nid_t pin_idxs[] = { 0xff, 0x24, 0x1d, 0x1e, 0x21 };
+       return vt_auto_create_analog_input_ctls(codec, cfg, 0x17, pin_idxs,
+                                               ARRAY_SIZE(pin_idxs));
+}
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 static struct hda_amp_list vt1708_loopbacks[] = {
        { 0x17, HDA_INPUT, 1 },
@@ -2554,7 +2550,7 @@ static int vt1708_parse_auto_config(struct hda_codec *codec)
        err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = vt1708_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
        /* add jack detect on/off control */
@@ -3021,49 +3017,12 @@ static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 }
 
 /* create playback/capture controls for input pins */
-static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1709_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       static char *labels[] = {
-               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-       };
-       struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx = 0;
-
-       /* for internal loopback recording select */
-       imux->items[imux->num_items].label = "Stereo Mixer";
-       imux->items[imux->num_items].index = idx;
-       imux->num_items++;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (!cfg->input_pins[i])
-                       continue;
-
-               switch (cfg->input_pins[i]) {
-               case 0x1d: /* Mic */
-                       idx = 2;
-                       break;
-
-               case 0x1e: /* Line In */
-                       idx = 3;
-                       break;
-
-               case 0x21: /* Front Mic */
-                       idx = 4;
-                       break;
-
-               case 0x23: /* CD */
-                       idx = 1;
-                       break;
-               }
-               err = via_new_analog_input(spec, labels[i], idx, 0x18);
-               if (err < 0)
-                       return err;
-               imux->items[imux->num_items].label = labels[i];
-               imux->items[imux->num_items].index = idx;
-               imux->num_items++;
-       }
-       return 0;
+       static hda_nid_t pin_idxs[] = { 0xff, 0x23, 0x1d, 0x1e, 0x21 };
+       return vt_auto_create_analog_input_ctls(codec, cfg, 0x18, pin_idxs,
+                                               ARRAY_SIZE(pin_idxs));
 }
 
 static int vt1709_parse_auto_config(struct hda_codec *codec)
@@ -3086,7 +3045,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec)
        err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = vt1709_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -3588,49 +3547,12 @@ static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 }
 
 /* create playback/capture controls for input pins */
-static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1708B_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       static char *labels[] = {
-               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-       };
-       struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx = 0;
-
-       /* for internal loopback recording select */
-       imux->items[imux->num_items].label = "Stereo Mixer";
-       imux->items[imux->num_items].index = idx;
-       imux->num_items++;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (!cfg->input_pins[i])
-                       continue;
-
-               switch (cfg->input_pins[i]) {
-               case 0x1a: /* Mic */
-                       idx = 2;
-                       break;
-
-               case 0x1b: /* Line In */
-                       idx = 3;
-                       break;
-
-               case 0x1e: /* Front Mic */
-                       idx = 4;
-                       break;
-
-               case 0x1f: /* CD */
-                       idx = 1;
-                       break;
-               }
-               err = via_new_analog_input(spec, labels[i], idx, 0x16);
-               if (err < 0)
-                       return err;
-               imux->items[imux->num_items].label = labels[i];
-               imux->items[imux->num_items].index = idx;
-               imux->num_items++;
-       }
-       return 0;
+       static hda_nid_t pin_idxs[] = { 0xff, 0x1f, 0x1a, 0x1b, 0x1e };
+       return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
+                                               ARRAY_SIZE(pin_idxs));
 }
 
 static int vt1708B_parse_auto_config(struct hda_codec *codec)
@@ -3653,7 +3575,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec)
        err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = vt1708B_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -4061,49 +3983,12 @@ static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 }
 
 /* create playback/capture controls for input pins */
-static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1708S_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       static char *labels[] = {
-               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-       };
-       struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx = 0;
-
-       /* for internal loopback recording select */
-       imux->items[imux->num_items].label = "Stereo Mixer";
-       imux->items[imux->num_items].index = 5;
-       imux->num_items++;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (!cfg->input_pins[i])
-                       continue;
-
-               switch (cfg->input_pins[i]) {
-               case 0x1a: /* Mic */
-                       idx = 2;
-                       break;
-
-               case 0x1b: /* Line In */
-                       idx = 3;
-                       break;
-
-               case 0x1e: /* Front Mic */
-                       idx = 4;
-                       break;
-
-               case 0x1f: /* CD */
-                       idx = 1;
-                       break;
-               }
-               err = via_new_analog_input(spec, labels[i], idx, 0x16);
-               if (err < 0)
-                       return err;
-               imux->items[imux->num_items].label = labels[i];
-               imux->items[imux->num_items].index = idx-1;
-               imux->num_items++;
-       }
-       return 0;
+       static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
+       return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
+                                               ARRAY_SIZE(pin_idxs));
 }
 
 /* fill out digital output widgets; one for master and one for slave outputs */
@@ -4151,7 +4036,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
        err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = vt1708S_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -4441,58 +4326,20 @@ static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
        imux = &spec->private_imux[1];
 
        /* for hp mode select */
-       i = 0;
-       while (texts[i] != NULL)        {
-               imux->items[imux->num_items].label =  texts[i];
-               imux->items[imux->num_items].index = i;
-               imux->num_items++;
-               i++;
-       }
+       for (i = 0; texts[i]; i++)
+               snd_hda_add_imux_item(imux, texts[i], i, NULL);
 
        spec->hp_mux = &spec->private_imux[1];
        return 0;
 }
 
 /* create playback/capture controls for input pins */
-static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1702_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       static char *labels[] = {
-               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-       };
-       struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx = 0;
-
-       /* for internal loopback recording select */
-       imux->items[imux->num_items].label = "Stereo Mixer";
-       imux->items[imux->num_items].index = 3;
-       imux->num_items++;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (!cfg->input_pins[i])
-                       continue;
-
-               switch (cfg->input_pins[i]) {
-               case 0x14: /* Mic */
-                       idx = 1;
-                       break;
-
-               case 0x15: /* Line In */
-                       idx = 2;
-                       break;
-
-               case 0x18: /* Front Mic */
-                       idx = 3;
-                       break;
-               }
-               err = via_new_analog_input(spec, labels[i], idx, 0x1A);
-               if (err < 0)
-                       return err;
-               imux->items[imux->num_items].label = labels[i];
-               imux->items[imux->num_items].index = idx-1;
-               imux->num_items++;
-       }
-       return 0;
+       static hda_nid_t pin_idxs[] = { 0x14, 0x15, 0x18, 0xff };
+       return vt_auto_create_analog_input_ctls(codec, cfg, 0x1a, pin_idxs,
+                                               ARRAY_SIZE(pin_idxs));
 }
 
 static int vt1702_parse_auto_config(struct hda_codec *codec)
@@ -4521,7 +4368,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec)
                                  (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
                                  (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
                                  (1 << AC_AMPCAP_MUTE_SHIFT));
-       err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = vt1702_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -4872,49 +4719,12 @@ static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 }
 
 /* create playback/capture controls for input pins */
-static int vt1718S_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1718S_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       static char *labels[] = {
-               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-       };
-       struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx = 0;
-
-       /* for internal loopback recording select */
-       imux->items[imux->num_items].label = "Stereo Mixer";
-       imux->items[imux->num_items].index = 5;
-       imux->num_items++;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (!cfg->input_pins[i])
-                       continue;
-
-               switch (cfg->input_pins[i]) {
-               case 0x2b: /* Mic */
-                       idx = 1;
-                       break;
-
-               case 0x2a: /* Line In */
-                       idx = 2;
-                       break;
-
-               case 0x29: /* Front Mic */
-                       idx = 3;
-                       break;
-
-               case 0x2c: /* CD */
-                       idx = 0;
-                       break;
-               }
-               err = via_new_analog_input(spec, labels[i], idx, 0x21);
-               if (err < 0)
-                       return err;
-               imux->items[imux->num_items].label = labels[i];
-               imux->items[imux->num_items].index = idx;
-               imux->num_items++;
-       }
-       return 0;
+       static hda_nid_t pin_idxs[] = { 0x2c, 0x2b, 0x2a, 0x29, 0, 0xff };
+       return vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
+                                               ARRAY_SIZE(pin_idxs));
 }
 
 static int vt1718S_parse_auto_config(struct hda_codec *codec)
@@ -4938,7 +4748,7 @@ static int vt1718S_parse_auto_config(struct hda_codec *codec)
        err = vt1718S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       err = vt1718S_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = vt1718S_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -5371,49 +5181,12 @@ static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 }
 
 /* create playback/capture controls for input pins */
-static int vt1716S_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1716S_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       static char *labels[] = {
-               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-       };
-       struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx = 0;
-
-       /* for internal loopback recording select */
-       imux->items[imux->num_items].label = "Stereo Mixer";
-       imux->items[imux->num_items].index = 5;
-       imux->num_items++;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (!cfg->input_pins[i])
-                       continue;
-
-               switch (cfg->input_pins[i]) {
-               case 0x1a: /* Mic */
-                       idx = 2;
-                       break;
-
-               case 0x1b: /* Line In */
-                       idx = 3;
-                       break;
-
-               case 0x1e: /* Front Mic */
-                       idx = 4;
-                       break;
-
-               case 0x1f: /* CD */
-                       idx = 1;
-                       break;
-               }
-               err = via_new_analog_input(spec, labels[i], idx, 0x16);
-               if (err < 0)
-                       return err;
-               imux->items[imux->num_items].label = labels[i];
-               imux->items[imux->num_items].index = idx-1;
-               imux->num_items++;
-       }
-       return 0;
+       static hda_nid_t pin_idxs[] = { 0x1f, 0x1a, 0x1b, 0x1e, 0, 0xff };
+       return vt_auto_create_analog_input_ctls(codec, cfg, 0x16, pin_idxs,
+                                               ARRAY_SIZE(pin_idxs));
 }
 
 static int vt1716S_parse_auto_config(struct hda_codec *codec)
@@ -5436,7 +5209,7 @@ static int vt1716S_parse_auto_config(struct hda_codec *codec)
        err = vt1716S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       err = vt1716S_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = vt1716S_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -5717,54 +5490,25 @@ static int vt2002P_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 }
 
 /* create playback/capture controls for input pins */
-static int vt2002P_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt2002P_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       static char *labels[] = {
-               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-       };
+       struct via_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx = 0;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (!cfg->input_pins[i])
-                       continue;
-
-               switch (cfg->input_pins[i]) {
-               case 0x2b: /* Mic */
-                       idx = 0;
-                       break;
-
-               case 0x2a: /* Line In */
-                       idx = 1;
-                       break;
-
-               case 0x29: /* Front Mic */
-                       idx = 2;
-                       break;
-               }
-               err = via_new_analog_input(spec, labels[i], idx, 0x21);
-               if (err < 0)
-                       return err;
-               imux->items[imux->num_items].label = labels[i];
-               imux->items[imux->num_items].index = idx;
-               imux->num_items++;
-       }
+       static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0xff };
+       int err;
 
+       err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
+                                              ARRAY_SIZE(pin_idxs));
+       if (err < 0)
+               return err;
        /* build volume/mute control of loopback */
-       err = via_new_analog_input(spec, "Stereo Mixer", 3, 0x21);
+       err = via_new_analog_input(spec, "Stereo Mixer", 0, 3, 0x21);
        if (err < 0)
                return err;
 
-       /* for internal loopback recording select */
-       imux->items[imux->num_items].label = "Stereo Mixer";
-       imux->items[imux->num_items].index = 3;
-       imux->num_items++;
-
        /* for digital mic select */
-       imux->items[imux->num_items].label = "Digital Mic";
-       imux->items[imux->num_items].index = 4;
-       imux->num_items++;
+       snd_hda_add_imux_item(imux, "Digital Mic", 4, NULL);
 
        return 0;
 }
@@ -5792,7 +5536,7 @@ static int vt2002P_parse_auto_config(struct hda_codec *codec)
        err = vt2002P_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       err = vt2002P_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = vt2002P_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
@@ -6067,53 +5811,26 @@ static int vt1812_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
 }
 
 /* create playback/capture controls for input pins */
-static int vt1812_auto_create_analog_input_ctls(struct via_spec *spec,
+static int vt1812_auto_create_analog_input_ctls(struct hda_codec *codec,
                                                const struct auto_pin_cfg *cfg)
 {
-       static char *labels[] = {
-               "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
-       };
+       struct via_spec *spec = codec->spec;
        struct hda_input_mux *imux = &spec->private_imux[0];
-       int i, err, idx = 0;
-
-       for (i = 0; i < AUTO_PIN_LAST; i++) {
-               if (!cfg->input_pins[i])
-                       continue;
-
-               switch (cfg->input_pins[i]) {
-               case 0x2b: /* Mic */
-                       idx = 0;
-                       break;
+       static hda_nid_t pin_idxs[] = { 0x2b, 0x2a, 0x29, 0, 0, 0xff };
+       int err;
 
-               case 0x2a: /* Line In */
-                       idx = 1;
-                       break;
+       err = vt_auto_create_analog_input_ctls(codec, cfg, 0x21, pin_idxs,
+                                              ARRAY_SIZE(pin_idxs));
+       if (err < 0)
+               return err;
 
-               case 0x29: /* Front Mic */
-                       idx = 2;
-                       break;
-               }
-               err = via_new_analog_input(spec, labels[i], idx, 0x21);
-               if (err < 0)
-                       return err;
-               imux->items[imux->num_items].label = labels[i];
-               imux->items[imux->num_items].index = idx;
-               imux->num_items++;
-       }
        /* build volume/mute control of loopback */
-       err = via_new_analog_input(spec, "Stereo Mixer", 5, 0x21);
+       err = via_new_analog_input(spec, "Stereo Mixer", 0, 5, 0x21);
        if (err < 0)
                return err;
 
-       /* for internal loopback recording select */
-       imux->items[imux->num_items].label = "Stereo Mixer";
-       imux->items[imux->num_items].index = 5;
-       imux->num_items++;
-
        /* for digital mic select */
-       imux->items[imux->num_items].label = "Digital Mic";
-       imux->items[imux->num_items].index = 6;
-       imux->num_items++;
+       snd_hda_add_imux_item(imux, "Digital Mic", 6, NULL);
 
        return 0;
 }
@@ -6141,7 +5858,7 @@ static int vt1812_parse_auto_config(struct hda_codec *codec)
        err = vt1812_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
        if (err < 0)
                return err;
-       err = vt1812_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       err = vt1812_auto_create_analog_input_ctls(codec, &spec->autocfg);
        if (err < 0)
                return err;
 
index d216362626d019826adb262da1341c898666c65d..712c1710f9a2083398122552e66d4478cadae98d 100644 (file)
@@ -563,6 +563,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
        case ICE1712_SUBDEVICE_DELTA1010E:
        case ICE1712_SUBDEVICE_DELTA1010LT:
        case ICE1712_SUBDEVICE_MEDIASTATION:
+       case ICE1712_SUBDEVICE_EDIROLDA2496:
                ice->num_total_dacs = 8;
                ice->num_total_adcs = 8;
                break;
@@ -635,6 +636,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
                err = snd_ice1712_akm4xxx_init(ak, &akm_delta410, &akm_delta410_priv, ice);
                break;
        case ICE1712_SUBDEVICE_DELTA1010LT:
+       case ICE1712_SUBDEVICE_EDIROLDA2496:
                err = snd_ice1712_akm4xxx_init(ak, &akm_delta1010lt, &akm_delta1010lt_priv, ice);
                break;
        case ICE1712_SUBDEVICE_DELTA66:
@@ -734,6 +736,7 @@ static int __devinit snd_ice1712_delta_add_controls(struct snd_ice1712 *ice)
        case ICE1712_SUBDEVICE_DELTA66:
        case ICE1712_SUBDEVICE_VX442:
        case ICE1712_SUBDEVICE_DELTA66E:
+       case ICE1712_SUBDEVICE_EDIROLDA2496:
                err = snd_ice1712_akm4xxx_build_controls(ice);
                if (err < 0)
                        return err;
@@ -813,5 +816,12 @@ struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = {
                .chip_init = snd_ice1712_delta_init,
                .build_controls = snd_ice1712_delta_add_controls,
        },
+       {
+               .subvendor = ICE1712_SUBDEVICE_EDIROLDA2496,
+               .name = "Edirol DA2496",
+               .model = "da2496",
+               .chip_init = snd_ice1712_delta_init,
+               .build_controls = snd_ice1712_delta_add_controls,
+       },
        { } /* terminator */
 };
index f7f14df81f26e301089b77bcf26825872d8045c5..1a0ac6cd65014995245d4804315ad8d9ef1331f0 100644 (file)
@@ -34,7 +34,8 @@
                "{MidiMan M Audio,Delta 410},"\
                "{MidiMan M Audio,Audiophile 24/96},"\
                "{Digigram,VX442},"\
-               "{Lionstracs,Mediastation},"
+               "{Lionstracs,Mediastation},"\
+               "{Edirol,DA2496},"
 
 #define ICE1712_SUBDEVICE_DELTA1010    0x121430d6
 #define ICE1712_SUBDEVICE_DELTA1010E   0xff1430d6
@@ -47,6 +48,7 @@
 #define ICE1712_SUBDEVICE_DELTA1010LT  0x12143bd6
 #define ICE1712_SUBDEVICE_VX442                0x12143cd6
 #define ICE1712_SUBDEVICE_MEDIASTATION 0x694c0100
+#define ICE1712_SUBDEVICE_EDIROLDA2496 0xce164010
 
 /* entry point */
 extern struct snd_ice1712_card_info snd_ice1712_delta_cards[];
index 6bc3f91b728149ef7ab180856bcfd46b6ef8397e..cdb873f5da50923fb2ca1a1ff43d57ecf0ff4d01 100644 (file)
@@ -638,7 +638,7 @@ static struct snd_kcontrol_new pontis_controls[] __devinitdata = {
  */
 static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
-       struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+       struct snd_ice1712 *ice = entry->private_data;
        char line[64];
        unsigned int reg, val;
        mutex_lock(&ice->gpio_mutex);
@@ -653,7 +653,7 @@ static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buf
 
 static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
-       struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+       struct snd_ice1712 *ice = entry->private_data;
        int reg, val;
 
        mutex_lock(&ice->gpio_mutex);
@@ -676,7 +676,7 @@ static void wm_proc_init(struct snd_ice1712 *ice)
 
 static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
-       struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+       struct snd_ice1712 *ice = entry->private_data;
        int reg, val;
 
        mutex_lock(&ice->gpio_mutex);
index 2a8e5cd8f2d8093f18b3f2c12591ed503c483530..e36ddb94c382932a4e5c9b35095678d3b9c90ea5 100644 (file)
@@ -654,7 +654,7 @@ static int prodigy192_ak4114_init(struct snd_ice1712 *ice)
 static void stac9460_proc_regs_read(struct snd_info_entry *entry,
                struct snd_info_buffer *buffer)
 {
-       struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
+       struct snd_ice1712 *ice = entry->private_data;
        int reg, val;
        /* registers 0x0 - 0x14 */
        for (reg = 0; reg <= 0x15; reg++) {
index 6c0a11adb2a84511b83b23b69d5efce9fb2085c6..98a8eb3c92f76a614bba10332d519f5fd0e2b26d 100644 (file)
@@ -79,6 +79,7 @@ static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = {
        { 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 },
        { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN },
@@ -505,7 +506,8 @@ static const struct oxygen_model model_generic = {
                         PLAYBACK_2_TO_AC97_1 |
                         CAPTURE_0_FROM_I2S_1 |
                         CAPTURE_1_FROM_SPDIF |
-                        CAPTURE_2_FROM_AC97_1,
+                        CAPTURE_2_FROM_AC97_1 |
+                        AC97_CD_INPUT,
        .dac_channels = 8,
        .dac_volume_min = 0,
        .dac_volume_max = 255,
index a3409edcfb5094791c33563f8ad3911826ce3e26..7d5222caa0a92e5ca844269e02253fed98cfba98 100644 (file)
@@ -34,6 +34,7 @@
      /* CAPTURE_3_FROM_I2S_3           not implemented */
 #define MIDI_OUTPUT            0x0800
 #define MIDI_INPUT             0x1000
+#define AC97_CD_INPUT          0x2000
 
 enum {
        CONTROL_SPDIF_PCM,
index 7e93cf884437d0b5844c9515250c49994390e54c..e5ebe56fb0c5c5129206f5fa4be6fcfc99e8888c 100644 (file)
@@ -308,25 +308,46 @@ static void oxygen_restore_eeprom(struct oxygen *chip,
        }
 }
 
-static void pci_bridge_magic(void)
+static void configure_pcie_bridge(struct pci_dev *pci)
 {
-       struct pci_dev *pci = NULL;
+       enum { PEX811X, PI7C9X110 };
+       static const struct pci_device_id bridge_ids[] = {
+               { PCI_VDEVICE(PLX, 0x8111), .driver_data = PEX811X },
+               { PCI_VDEVICE(PLX, 0x8112), .driver_data = PEX811X },
+               { PCI_DEVICE(0x12d8, 0xe110), .driver_data = PI7C9X110 },
+               { }
+       };
+       struct pci_dev *bridge;
+       const struct pci_device_id *id;
        u32 tmp;
 
-       for (;;) {
-               /* If there is any Pericom PI7C9X110 PCI-E/PCI bridge ... */
-               pci = pci_get_device(0x12d8, 0xe110, pci);
-               if (!pci)
-                       break;
-               /*
-                * ... configure its secondary internal arbiter to park to
-                * the secondary port, instead of to the last master.
-                */
-               if (!pci_read_config_dword(pci, 0x40, &tmp)) {
-                       tmp |= 1;
-                       pci_write_config_dword(pci, 0x40, tmp);
-               }
-               /* Why?  Try asking C-Media. */
+       if (!pci->bus || !pci->bus->self)
+               return;
+       bridge = pci->bus->self;
+
+       id = pci_match_id(bridge_ids, bridge);
+       if (!id)
+               return;
+
+       switch (id->driver_data) {
+       case PEX811X:   /* PLX PEX8111/PEX8112 PCIe/PCI bridge */
+               pci_read_config_dword(bridge, 0x48, &tmp);
+               tmp |= 1;       /* enable blind prefetching */
+               tmp |= 1 << 11; /* enable beacon generation */
+               pci_write_config_dword(bridge, 0x48, tmp);
+
+               pci_write_config_dword(bridge, 0x84, 0x0c);
+               pci_read_config_dword(bridge, 0x88, &tmp);
+               tmp &= ~(7 << 27);
+               tmp |= 2 << 27; /* set prefetch size to 128 bytes */
+               pci_write_config_dword(bridge, 0x88, tmp);
+               break;
+
+       case PI7C9X110: /* Pericom PI7C9X110 PCIe/PCI bridge */
+               pci_read_config_dword(bridge, 0x40, &tmp);
+               tmp |= 1;       /* park the PCI arbiter to the sound chip */
+               pci_write_config_dword(bridge, 0x40, tmp);
+               break;
        }
 }
 
@@ -613,7 +634,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
        snd_card_set_dev(card, &pci->dev);
        card->private_free = oxygen_card_free;
 
-       pci_bridge_magic();
+       configure_pcie_bridge(pci);
        oxygen_init(chip);
        chip->model.init(chip);
 
index f375b8a27862452bb6ec24b4f46028136910263a..2849b36f5f7e72100c1691414cb6279e17f5d1ce 100644 (file)
@@ -708,7 +708,7 @@ static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl,
                .private_value = ((codec) << 24) | ((stereo) << 16) | (index), \
        }
 
-static DECLARE_TLV_DB_SCALE(monitor_db_scale, -1000, 1000, 0);
+static DECLARE_TLV_DB_SCALE(monitor_db_scale, -600, 600, 0);
 static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0);
 static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0);
 
@@ -972,6 +972,9 @@ static int add_controls(struct oxygen *chip,
                if (!strcmp(template.name, "Stereo Upmixing") &&
                    chip->model.dac_channels == 2)
                        continue;
+               if (!strncmp(template.name, "CD Capture ", 11) &&
+                   !(chip->model.device_config & AC97_CD_INPUT))
+                       continue;
                if (!strcmp(template.name, "Master Playback Volume") &&
                    chip->model.dac_tlv) {
                        template.tlv.p = chip->model.dac_tlv;
index 9dff6954c397a902980b6dedb2bb6ebe45337e38..814667442eb04f086e19e157ba43840f1a4d12b2 100644 (file)
@@ -56,8 +56,8 @@ static const struct snd_pcm_hardware oxygen_stereo_hardware = {
        .channels_max = 2,
        .buffer_bytes_max = BUFFER_BYTES_MAX,
        .period_bytes_min = PERIOD_BYTES_MIN,
-       .period_bytes_max = BUFFER_BYTES_MAX / 2,
-       .periods_min = 2,
+       .period_bytes_max = BUFFER_BYTES_MAX,
+       .periods_min = 1,
        .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
 };
 static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
@@ -82,8 +82,8 @@ static const struct snd_pcm_hardware oxygen_multichannel_hardware = {
        .channels_max = 8,
        .buffer_bytes_max = BUFFER_BYTES_MAX_MULTICH,
        .period_bytes_min = PERIOD_BYTES_MIN,
-       .period_bytes_max = BUFFER_BYTES_MAX_MULTICH / 2,
-       .periods_min = 2,
+       .period_bytes_max = BUFFER_BYTES_MAX_MULTICH,
+       .periods_min = 1,
        .periods_max = BUFFER_BYTES_MAX_MULTICH / PERIOD_BYTES_MIN,
 };
 static const struct snd_pcm_hardware oxygen_ac97_hardware = {
@@ -100,8 +100,8 @@ static const struct snd_pcm_hardware oxygen_ac97_hardware = {
        .channels_max = 2,
        .buffer_bytes_max = BUFFER_BYTES_MAX,
        .period_bytes_min = PERIOD_BYTES_MIN,
-       .period_bytes_max = BUFFER_BYTES_MAX / 2,
-       .periods_min = 2,
+       .period_bytes_max = BUFFER_BYTES_MAX,
+       .periods_min = 1,
        .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN,
 };
 
index 72de159d45673b123df400486962078e3f401650..4dcd41b782586b7d7d9251a4c75aef37c36a4169 100644 (file)
 /* OXYGEN_CHANNEL_* */
 
 #define OXYGEN_CODEC_VERSION           0xe4
-#define  OXYGEN_XCID_MASK              0x07
+#define  OXYGEN_CODEC_ID_MASK          0x07
 
 #define OXYGEN_REVISION                        0xe6
-#define  OXYGEN_REVISION_XPKGID_MASK   0x0007
+#define  OXYGEN_PACKAGE_ID_MASK                0x0007
+#define  OXYGEN_PACKAGE_ID_8786                0x0004
+#define  OXYGEN_PACKAGE_ID_8787                0x0006
+#define  OXYGEN_PACKAGE_ID_8788                0x0007
 #define  OXYGEN_REVISION_MASK          0xfff8
-#define  OXYGEN_REVISION_2             0x0008  /* bit flag */
-#define  OXYGEN_REVISION_8787          0x0014  /* 8 bits */
+#define  OXYGEN_REVISION_2             0x0008
 
 #define OXYGEN_OFFSIN_48K              0xe8
 #define OXYGEN_OFFSBASE_48K            0xe9
index 06c863e86e3d3d24a5dfd0f7b43f56a47b120719..469010a8b8497abcf615e88994683d6f69e6d46e 100644 (file)
@@ -25,9 +25,9 @@
 #include "xonar.h"
 
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
-MODULE_DESCRIPTION("Asus AVx00 driver");
+MODULE_DESCRIPTION("Asus Virtuoso driver");
 MODULE_LICENSE("GPL v2");
-MODULE_SUPPORTED_DEVICE("{{Asus,AV100},{Asus,AV200}}");
+MODULE_SUPPORTED_DEVICE("{{Asus,AV66},{Asus,AV100},{Asus,AV200}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
@@ -49,6 +49,7 @@ static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = {
        { OXYGEN_PCI_SUBID(0x1043, 0x834f) },
        { OXYGEN_PCI_SUBID(0x1043, 0x835c) },
        { OXYGEN_PCI_SUBID(0x1043, 0x835d) },
+       { OXYGEN_PCI_SUBID(0x1043, 0x835e) },
        { OXYGEN_PCI_SUBID(0x1043, 0x838e) },
        { OXYGEN_PCI_SUBID_BROKEN_EEPROM },
        { }
index 7c4986b27f2b07bd8faa7d824a0056d1db821308..aa27c31049afba1d8d759cc4c5fb7ce7d04e1947 100644 (file)
@@ -367,13 +367,6 @@ static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip,
 
 static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0);
 
-static int xonar_d1_control_filter(struct snd_kcontrol_new *template)
-{
-       if (!strncmp(template->name, "CD Capture ", 11))
-               return 1; /* no CD input */
-       return 0;
-}
-
 static int xonar_d1_mixer_init(struct oxygen *chip)
 {
        int err;
@@ -391,7 +384,6 @@ static const struct oxygen_model model_xonar_d1 = {
        .longname = "Asus Virtuoso 100",
        .chip = "AV200",
        .init = xonar_d1_init,
-       .control_filter = xonar_d1_control_filter,
        .mixer_init = xonar_d1_mixer_init,
        .cleanup = xonar_d1_cleanup,
        .suspend = xonar_d1_suspend,
index ba18fb546b4f9d7c8ace8b82d5100e3c82d0e3b1..d491fd6c0be239906380ae6af8864f1bfe0e4f6f 100644 (file)
  * GPIO 5 <- 0
  */
 
+/*
+ * Xonar HDAV1.3 Slim
+ * ------------------
+ *
+ * CMI8788:
+ *
+ * GPIO 1 -> enable output
+ *
+ * TXD -> HDMI controller
+ * RXD <- HDMI controller
+ */
+
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/mutex.h>
@@ -362,7 +374,6 @@ static void xonar_st_init_common(struct oxygen *chip)
 {
        struct xonar_pcm179x *data = chip->model_data;
 
-       data->generic.anti_pop_delay = 100;
        data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE;
        data->dacs = chip->model.private_data ? 4 : 1;
        data->hp_gain_offset = 2*-18;
@@ -408,6 +419,7 @@ static void xonar_st_init(struct oxygen *chip)
 {
        struct xonar_pcm179x *data = chip->model_data;
 
+       data->generic.anti_pop_delay = 100;
        data->has_cs2000 = 1;
        data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1;
 
@@ -428,6 +440,7 @@ static void xonar_stx_init(struct oxygen *chip)
        struct xonar_pcm179x *data = chip->model_data;
 
        xonar_st_init_i2c(chip);
+       data->generic.anti_pop_delay = 800;
        data->generic.ext_power_reg = OXYGEN_GPI_DATA;
        data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK;
        data->generic.ext_power_bit = GPI_EXT_POWER;
@@ -915,13 +928,6 @@ static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
        return 0;
 }
 
-static int xonar_st_control_filter(struct snd_kcontrol_new *template)
-{
-       if (!strncmp(template->name, "CD Capture ", 11))
-               return 1; /* no CD input */
-       return 0;
-}
-
 static int add_pcm1796_controls(struct oxygen *chip)
 {
        int err;
@@ -991,7 +997,8 @@ static const struct oxygen_model model_xonar_d2 = {
                         CAPTURE_0_FROM_I2S_2 |
                         CAPTURE_1_FROM_SPDIF |
                         MIDI_OUTPUT |
-                        MIDI_INPUT,
+                        MIDI_INPUT |
+                        AC97_CD_INPUT,
        .dac_channels = 8,
        .dac_volume_min = 255 - 2*60,
        .dac_volume_max = 255,
@@ -1037,7 +1044,6 @@ static const struct oxygen_model model_xonar_st = {
        .longname = "Asus Virtuoso 100",
        .chip = "AV200",
        .init = xonar_st_init,
-       .control_filter = xonar_st_control_filter,
        .mixer_init = xonar_st_mixer_init,
        .cleanup = xonar_st_cleanup,
        .suspend = xonar_st_suspend,
@@ -1108,6 +1114,9 @@ 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 b82c1cfa96f5334554435a6eeebc6e82fa63857d..200f7601276f8e5b5fa841a34ea5ad4a07c0fc44 100644 (file)
  * SPI 0 -> WM8766 (surround, center/LFE, back)
  * SPI 1 -> WM8776 (front, input)
  *
- * GPIO 4 <- headphone detect
- * GPIO 6 -> route input jack to input 1/2 (1/0)
- * GPIO 7 -> enable output to speakers
- * GPIO 8 -> enable output to speakers
+ * 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:
+ *
+ * input 1 <- line
+ * input 2 <- mic
+ * input 3 <- front mic
+ * input 4 <- aux
  */
 
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <sound/control.h>
 #include <sound/core.h>
+#include <sound/jack.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/tlv.h>
@@ -44,7 +52,8 @@
 
 #define GPIO_DS_HP_DETECT      0x0010
 #define GPIO_DS_INPUT_ROUTE    0x0040
-#define GPIO_DS_OUTPUT_ENABLE  0x0180
+#define GPIO_DS_OUTPUT_FRONTLR 0x0080
+#define GPIO_DS_OUTPUT_ENABLE  0x0100
 
 #define LC_CONTROL_LIMITER     0x40000000
 #define LC_CONTROL_ALC         0x20000000
@@ -56,6 +65,7 @@ struct xonar_wm87x6 {
        struct snd_kcontrol *line_adcmux_control;
        struct snd_kcontrol *mic_adcmux_control;
        struct snd_kcontrol *lc_controls[13];
+       struct snd_jack *hp_jack;
 };
 
 static void wm8776_write(struct oxygen *chip,
@@ -97,8 +107,12 @@ static void wm8766_write(struct oxygen *chip,
                         (0 << OXYGEN_SPI_CODEC_SHIFT) |
                         OXYGEN_SPI_CEN_LATCH_CLOCK_LO,
                         (reg << 9) | value);
-       if (reg < ARRAY_SIZE(data->wm8766_regs))
+       if (reg < ARRAY_SIZE(data->wm8766_regs)) {
+               if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) ||
+                   (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA))
+                       value &= ~WM8766_UPDATE;
                data->wm8766_regs[reg] = value;
+       }
 }
 
 static void wm8766_write_cached(struct oxygen *chip,
@@ -107,12 +121,8 @@ static void wm8766_write_cached(struct oxygen *chip,
        struct xonar_wm87x6 *data = chip->model_data;
 
        if (reg >= ARRAY_SIZE(data->wm8766_regs) ||
-           value != data->wm8766_regs[reg]) {
-               if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) ||
-                   (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA))
-                       value &= ~WM8766_UPDATE;
+           value != data->wm8766_regs[reg])
                wm8766_write(chip, reg, value);
-       }
 }
 
 static void wm8776_registers_init(struct oxygen *chip)
@@ -141,7 +151,10 @@ static void wm8776_registers_init(struct oxygen *chip)
 
 static void wm8766_registers_init(struct oxygen *chip)
 {
+       struct xonar_wm87x6 *data = chip->model_data;
+
        wm8766_write(chip, WM8766_RESET, 0);
+       wm8766_write(chip, WM8766_DAC_CTRL, data->wm8766_regs[WM8766_DAC_CTRL]);
        wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24);
        wm8766_write(chip, WM8766_DAC_CTRL2,
                     WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0));
@@ -170,6 +183,40 @@ static void wm8776_init(struct oxygen *chip)
        wm8776_registers_init(chip);
 }
 
+static void wm8766_init(struct oxygen *chip)
+{
+       struct xonar_wm87x6 *data = chip->model_data;
+
+       data->wm8766_regs[WM8766_DAC_CTRL] =
+               WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
+       wm8766_registers_init(chip);
+}
+
+static void xonar_ds_handle_hp_jack(struct oxygen *chip)
+{
+       struct xonar_wm87x6 *data = chip->model_data;
+       bool hp_plugged;
+       unsigned int reg;
+
+       mutex_lock(&chip->mutex);
+
+       hp_plugged = !(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
+                      GPIO_DS_HP_DETECT);
+
+       oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
+                             hp_plugged ? 0 : GPIO_DS_OUTPUT_FRONTLR,
+                             GPIO_DS_OUTPUT_FRONTLR);
+
+       reg = data->wm8766_regs[WM8766_DAC_CTRL] & ~WM8766_MUTEALL;
+       if (hp_plugged)
+               reg |= WM8766_MUTEALL;
+       wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
+
+       snd_jack_report(data->hp_jack, hp_plugged ? SND_JACK_HEADPHONE : 0);
+
+       mutex_unlock(&chip->mutex);
+}
+
 static void xonar_ds_init(struct oxygen *chip)
 {
        struct xonar_wm87x6 *data = chip->model_data;
@@ -178,16 +225,22 @@ static void xonar_ds_init(struct oxygen *chip)
        data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE;
 
        wm8776_init(chip);
-       wm8766_registers_init(chip);
+       wm8766_init(chip);
 
-       oxygen_write16_masked(chip, OXYGEN_GPIO_CONTROL, GPIO_DS_INPUT_ROUTE,
-                             GPIO_DS_HP_DETECT | GPIO_DS_INPUT_ROUTE);
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
+                         GPIO_DS_INPUT_ROUTE | GPIO_DS_OUTPUT_FRONTLR);
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
+                           GPIO_DS_HP_DETECT);
        oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE);
        oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT);
        chip->interrupt_mask |= OXYGEN_INT_GPIO;
 
        xonar_enable_output(chip);
 
+       snd_jack_new(chip->card, "Headphone",
+                    SND_JACK_HEADPHONE, &data->hp_jack);
+       xonar_ds_handle_hp_jack(chip);
+
        snd_component_add(chip->card, "WM8776");
        snd_component_add(chip->card, "WM8766");
 }
@@ -208,6 +261,7 @@ static void xonar_ds_resume(struct oxygen *chip)
        wm8776_registers_init(chip);
        wm8766_registers_init(chip);
        xonar_enable_output(chip);
+       xonar_ds_handle_hp_jack(chip);
 }
 
 static void wm8776_adc_hardware_filter(unsigned int channel,
@@ -323,12 +377,27 @@ static void update_wm87x6_mute(struct oxygen *chip)
                            (chip->dac_mute ? WM8766_DMUTE_MASK : 0));
 }
 
-static void xonar_ds_gpio_changed(struct oxygen *chip)
+static void update_wm8766_center_lfe_mix(struct oxygen *chip, bool mixed)
 {
-       u16 bits;
+       struct xonar_wm87x6 *data = chip->model_data;
+       unsigned int reg;
 
-       bits = oxygen_read16(chip, OXYGEN_GPIO_DATA);
-       snd_printk(KERN_INFO "HP detect: %d\n", !!(bits & GPIO_DS_HP_DETECT));
+       /*
+        * The WM8766 can mix left and right channels, but this setting
+        * applies to all three stereo pairs.
+        */
+       reg = data->wm8766_regs[WM8766_DAC_CTRL] &
+               ~(WM8766_PL_LEFT_MASK | WM8766_PL_RIGHT_MASK);
+       if (mixed)
+               reg |= WM8766_PL_LEFT_LRMIX | WM8766_PL_RIGHT_LRMIX;
+       else
+               reg |= WM8766_PL_LEFT_LEFT | WM8766_PL_RIGHT_RIGHT;
+       wm8766_write_cached(chip, WM8766_DAC_CTRL, reg);
+}
+
+static void xonar_ds_gpio_changed(struct oxygen *chip)
+{
+       xonar_ds_handle_hp_jack(chip);
 }
 
 static int wm8776_bit_switch_get(struct snd_kcontrol *ctl,
@@ -896,7 +965,10 @@ static const struct snd_kcontrol_new ds_controls[] = {
                .put = wm8776_input_mux_put,
                .private_value = 1 << 1,
        },
-       WM8776_BIT_SWITCH("Aux", WM8776_ADCMUX, 1 << 2, 0, 0),
+       WM8776_BIT_SWITCH("Front Mic Capture Switch",
+                         WM8776_ADCMUX, 1 << 2, 0, 0),
+       WM8776_BIT_SWITCH("Aux Capture Switch",
+                         WM8776_ADCMUX, 1 << 3, 0, 0),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "ADC Filter Capture Enum",
@@ -956,13 +1028,6 @@ static const struct snd_kcontrol_new lc_controls[] = {
                                LC_CONTROL_ALC, wm8776_ngth_db_scale),
 };
 
-static int xonar_ds_control_filter(struct snd_kcontrol_new *template)
-{
-       if (!strncmp(template->name, "CD Capture ", 11))
-               return 1; /* no CD input */
-       return 0;
-}
-
 static int xonar_ds_mixer_init(struct oxygen *chip)
 {
        struct xonar_wm87x6 *data = chip->model_data;
@@ -999,10 +1064,9 @@ static int xonar_ds_mixer_init(struct oxygen *chip)
 
 static const struct oxygen_model model_xonar_ds = {
        .shortname = "Xonar DS",
-       .longname = "Asus Virtuoso 200",
+       .longname = "Asus Virtuoso 66",
        .chip = "AV200",
        .init = xonar_ds_init,
-       .control_filter = xonar_ds_control_filter,
        .mixer_init = xonar_ds_mixer_init,
        .cleanup = xonar_ds_cleanup,
        .suspend = xonar_ds_suspend,
@@ -1013,6 +1077,7 @@ static const struct oxygen_model model_xonar_ds = {
        .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,
        .dac_tlv = wm87x6_dac_db_scale,
        .model_data_size = sizeof(struct xonar_wm87x6),
index d19dc052c3912f0aa235f8fae0344b5f241833fa..d5f5b440fc40f3ea7024adefe33d88d45e0377a5 100644 (file)
@@ -1527,14 +1527,14 @@ snd_rme96_free(void *private_data)
 static void
 snd_rme96_free_spdif_pcm(struct snd_pcm *pcm)
 {
-       struct rme96 *rme96 = (struct rme96 *) pcm->private_data;
+       struct rme96 *rme96 = pcm->private_data;
        rme96->spdif_pcm = NULL;
 }
 
 static void
 snd_rme96_free_adat_pcm(struct snd_pcm *pcm)
 {
-       struct rme96 *rme96 = (struct rme96 *) pcm->private_data;
+       struct rme96 *rme96 = pcm->private_data;
        rme96->adat_pcm = NULL;
 }
 
@@ -1661,7 +1661,7 @@ static void
 snd_rme96_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
        int n;
-       struct rme96 *rme96 = (struct rme96 *)entry->private_data;
+       struct rme96 *rme96 = entry->private_data;
        
        rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER);
 
@@ -2348,7 +2348,7 @@ snd_rme96_probe(struct pci_dev *pci,
        if (err < 0)
                return err;
        card->private_free = snd_rme96_card_free;
-       rme96 = (struct rme96 *)card->private_data;     
+       rme96 = card->private_data;
        rme96->card = card;
        rme96->pci = pci;
        snd_card_set_dev(card, &pci->dev);
index d6fa7bfd9aa123d7f8bb8142a8def39888129434..0b720cf7783e8d1347d0ddd766a3505014f3c7b4 100644 (file)
@@ -3284,7 +3284,7 @@ static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp)
 static void
 snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
-       struct hdsp *hdsp = (struct hdsp *) entry->private_data;
+       struct hdsp *hdsp = entry->private_data;
        unsigned int status;
        unsigned int status2;
        char *pref_sync_ref;
@@ -4566,7 +4566,7 @@ static int hdsp_get_peak(struct hdsp *hdsp, struct hdsp_peak_rms __user *peak_rm
 
 static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct hdsp *hdsp = (struct hdsp *)hw->private_data;
+       struct hdsp *hdsp = hw->private_data;
        void __user *argp = (void __user *)arg;
        int err;
 
@@ -5156,7 +5156,7 @@ static int snd_hdsp_free(struct hdsp *hdsp)
 
 static void snd_hdsp_card_free(struct snd_card *card)
 {
-       struct hdsp *hdsp = (struct hdsp *) card->private_data;
+       struct hdsp *hdsp = card->private_data;
 
        if (hdsp)
                snd_hdsp_free(hdsp);
@@ -5182,7 +5182,7 @@ static int __devinit snd_hdsp_probe(struct pci_dev *pci,
        if (err < 0)
                return err;
 
-       hdsp = (struct hdsp *) card->private_data;
+       hdsp = card->private_data;
        card->private_free = snd_hdsp_card_free;
        hdsp->dev = dev;
        hdsp->pci = pci;
index 20afdf9772eefd1e23768e724ab06e0a919da260..961d982976958aaaf0c4dae4906210ad3df0bfb4 100644 (file)
@@ -785,7 +785,7 @@ static int snapper_set_capture_source(struct pmac_tumbler *mix)
        if (! mix->i2c.client)
                return -ENODEV;
        if (mix->capture_source)
-               mix->acs = mix->acs |= 2;
+               mix->acs |= 2;
        else
                mix->acs &= ~2;
        return i2c_smbus_write_byte_data(mix->i2c.client, TAS_REG_ACS, mix->acs);
index dc5249fba85c71884c613c5b028a9fd173143bf5..d0e75323ec190a317d2c6c8252ad8cf1e1e8035a 100644 (file)
@@ -179,7 +179,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
        snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
        runtime->dma_bytes = params_buffer_bytes(params);
 
-       prtd->params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+       prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
        prtd->params->dma_intr_handler = atmel_pcm_dma_irq;
 
        prtd->dma_buffer = runtime->dma_addr;
@@ -374,14 +374,14 @@ static int atmel_pcm_new(struct snd_card *card,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = 0xffffffff;
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = atmel_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                pr_debug("at32-pcm:"
                                "Allocating PCM capture DMA buffer\n");
                ret = atmel_pcm_preallocate_dma_buffer(pcm,
@@ -414,12 +414,9 @@ static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm)
 }
 
 #ifdef CONFIG_PM
-static int atmel_pcm_suspend(struct snd_soc_dai_link *dai_link)
+static int atmel_pcm_suspend(struct snd_soc_dai *dai)
 {
-       struct snd_pcm *pcm = dai_link->pcm;
-       struct snd_pcm_str *stream = &pcm->streams[0];
-       struct snd_pcm_substream *substream = stream->substream;
-       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_pcm_runtime *runtime = dai->runtime;
        struct atmel_runtime_data *prtd;
        struct atmel_pcm_dma_params *params;
 
@@ -441,12 +438,9 @@ static int atmel_pcm_suspend(struct snd_soc_dai_link *dai_link)
        return 0;
 }
 
-static int atmel_pcm_resume(struct snd_soc_dai_link *dai_link)
+static int atmel_pcm_resume(struct snd_soc_dai *dai)
 {
-       struct snd_pcm *pcm = dai_link->pcm;
-       struct snd_pcm_str *stream = &pcm->streams[0];
-       struct snd_pcm_substream *substream = stream->substream;
-       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_pcm_runtime *runtime = dai->runtime;
        struct atmel_runtime_data *prtd;
        struct atmel_pcm_dma_params *params;
 
@@ -470,27 +464,46 @@ static int atmel_pcm_resume(struct snd_soc_dai_link *dai_link)
 #define atmel_pcm_resume       NULL
 #endif
 
-struct snd_soc_platform atmel_soc_platform = {
-       .name           = "atmel-audio",
-       .pcm_ops        = &atmel_pcm_ops,
+static struct snd_soc_platform_driver atmel_soc_platform = {
+       .ops            = &atmel_pcm_ops,
        .pcm_new        = atmel_pcm_new,
        .pcm_free       = atmel_pcm_free_dma_buffers,
        .suspend        = atmel_pcm_suspend,
        .resume         = atmel_pcm_resume,
 };
-EXPORT_SYMBOL_GPL(atmel_soc_platform);
 
-static int __init atmel_pcm_modinit(void)
+static int __devinit atmel_soc_platform_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_platform(&pdev->dev, &atmel_soc_platform);
+}
+
+static int __devexit atmel_soc_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver atmel_pcm_driver = {
+       .driver = {
+                       .name = "atmel-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = atmel_soc_platform_probe,
+       .remove = __devexit_p(atmel_soc_platform_remove),
+};
+
+static int __init snd_atmel_pcm_init(void)
 {
-       return snd_soc_register_platform(&atmel_soc_platform);
+       return platform_driver_register(&atmel_pcm_driver);
 }
-module_init(atmel_pcm_modinit);
+module_init(snd_atmel_pcm_init);
 
-static void __exit atmel_pcm_modexit(void)
+static void __exit snd_atmel_pcm_exit(void)
 {
-       snd_soc_unregister_platform(&atmel_soc_platform);
+       platform_driver_unregister(&atmel_pcm_driver);
 }
-module_exit(atmel_pcm_modexit);
+module_exit(snd_atmel_pcm_exit);
 
 MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>");
 MODULE_DESCRIPTION("Atmel PCM module");
index ec9b2824b66381d3e3e1479ef7039e875c0cbacd..2597329302e76c0c6d50a9f536eea39891f45c64 100644 (file)
@@ -74,9 +74,6 @@ struct atmel_pcm_dma_params {
        void (*dma_intr_handler)(u32, struct snd_pcm_substream *);
 };
 
-extern struct snd_soc_platform atmel_soc_platform;
-
-
 /*
  * SSC register access (since ssc_writel() / ssc_readl() require literal name)
  */
index c85844d4845bdc15f24c94c8d4a82dbedcfcc1ec..5d230cee3fa7a7ad9c0fb2dcb9d39d13bb5759fb 100644 (file)
@@ -205,8 +205,7 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id)
 static int atmel_ssc_startup(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
-       struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+       struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
        int dir_mask;
 
        pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
@@ -235,8 +234,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
 static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
                               struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
-       struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+       struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
        struct atmel_pcm_dma_params *dma_params;
        int dir, dir_mask;
 
@@ -338,7 +336,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
-       int id = rtd->dai->cpu_dai->id;
+       int id = dai->id;
        struct atmel_ssc_info *ssc_p = &ssc_info[id];
        struct atmel_pcm_dma_params *dma_params;
        int dir, channels, bits;
@@ -368,7 +366,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
         * function.  It should not be used for other purposes
         * as it is common to all substreams.
         */
-       snd_soc_dai_set_dma_data(rtd->dai->cpu_dai, substream, dma_params);
+       snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_params);
 
        channels = params_channels(params);
 
@@ -605,8 +603,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
 static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
-       struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+       struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
        struct atmel_pcm_dma_params *dma_params;
        int dir;
 
@@ -690,6 +687,32 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
 #  define atmel_ssc_resume     NULL
 #endif /* CONFIG_PM */
 
+static int atmel_ssc_probe(struct snd_soc_dai *dai)
+{
+       struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
+       int ret = 0;
+
+       snd_soc_dai_set_drvdata(dai, ssc_p);
+
+       /*
+        * Request SSC device
+        */
+       ssc_p->ssc = ssc_request(dai->id);
+       if (IS_ERR(ssc_p->ssc)) {
+               printk(KERN_ERR "ASoC: Failed to request SSC %d\n", dai->id);
+               ret = PTR_ERR(ssc_p->ssc);
+       }
+
+       return ret;
+}
+
+static int atmel_ssc_remove(struct snd_soc_dai *dai)
+{
+       struct atmel_ssc_info *ssc_p = snd_soc_dai_get_drvdata(dai);
+
+       ssc_free(ssc_p->ssc);
+       return 0;
+}
 
 #define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000)
 
@@ -705,9 +728,11 @@ static struct snd_soc_dai_ops atmel_ssc_dai_ops = {
        .set_clkdiv     = atmel_ssc_set_dai_clkdiv,
 };
 
-struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
-       {       .name = "atmel-ssc0",
-               .id = 0,
+static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = {
+       {
+               .name = "atmel-ssc-dai.0",
+               .probe = atmel_ssc_probe,
+               .remove = atmel_ssc_remove,
                .suspend = atmel_ssc_suspend,
                .resume = atmel_ssc_resume,
                .playback = {
@@ -721,11 +746,12 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
                        .rates = ATMEL_SSC_RATES,
                        .formats = ATMEL_SSC_FORMATS,},
                .ops = &atmel_ssc_dai_ops,
-               .private_data = &ssc_info[0],
        },
 #if NUM_SSC_DEVICES == 3
-       {       .name = "atmel-ssc1",
-               .id = 1,
+       {
+               .name = "atmel-ssc-dai.1",
+               .probe = atmel_ssc_probe,
+               .remove = atmel_ssc_remove,
                .suspend = atmel_ssc_suspend,
                .resume = atmel_ssc_resume,
                .playback = {
@@ -739,10 +765,11 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
                        .rates = ATMEL_SSC_RATES,
                        .formats = ATMEL_SSC_FORMATS,},
                .ops = &atmel_ssc_dai_ops,
-               .private_data = &ssc_info[1],
        },
-       {       .name = "atmel-ssc2",
-               .id = 2,
+       {
+               .name = "atmel-ssc-dai.2",
+               .probe = atmel_ssc_probe,
+               .remove = atmel_ssc_remove,
                .suspend = atmel_ssc_suspend,
                .resume = atmel_ssc_resume,
                .playback = {
@@ -756,23 +783,94 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
                        .rates = ATMEL_SSC_RATES,
                        .formats = ATMEL_SSC_FORMATS,},
                .ops = &atmel_ssc_dai_ops,
-               .private_data = &ssc_info[2],
        },
 #endif
 };
-EXPORT_SYMBOL_GPL(atmel_ssc_dai);
 
-static int __init atmel_ssc_modinit(void)
+static __devinit int asoc_ssc_probe(struct platform_device *pdev)
+{
+       BUG_ON(pdev->id < 0);
+       BUG_ON(pdev->id >= ARRAY_SIZE(atmel_ssc_dai));
+       return snd_soc_register_dai(&pdev->dev, &atmel_ssc_dai[pdev->id]);
+}
+
+static int __devexit asoc_ssc_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver asoc_ssc_driver = {
+       .driver = {
+                       .name = "atmel-ssc-dai",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = asoc_ssc_probe,
+       .remove = __devexit_p(asoc_ssc_remove),
+};
+
+/**
+ * atmel_ssc_set_audio - Allocate the specified SSC for audio use.
+ */
+int atmel_ssc_set_audio(int ssc_id)
+{
+       struct ssc_device *ssc;
+       static struct platform_device *dma_pdev;
+       struct platform_device *ssc_pdev;
+       int ret;
+
+       if (ssc_id < 0 || ssc_id >= ARRAY_SIZE(atmel_ssc_dai))
+               return -EINVAL;
+
+       /* Allocate a dummy device for DMA if we don't have one already */
+       if (!dma_pdev) {
+               dma_pdev = platform_device_alloc("atmel-pcm-audio", -1);
+               if (!dma_pdev)
+                       return -ENOMEM;
+
+               ret = platform_device_add(dma_pdev);
+               if (ret < 0) {
+                       platform_device_put(dma_pdev);
+                       dma_pdev = NULL;
+                       return ret;
+               }
+       }
+
+       ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id);
+       if (!ssc_pdev) {
+               ssc_free(ssc);
+               return -ENOMEM;
+       }
+
+       /* If we can grab the SSC briefly to parent the DAI device off it */
+       ssc = ssc_request(ssc_id);
+       if (IS_ERR(ssc))
+               pr_warn("Unable to parent ASoC SSC DAI on SSC: %ld\n",
+                       PTR_ERR(ssc));
+       else
+               ssc_pdev->dev.parent = &(ssc->pdev->dev);
+       ssc_free(ssc);
+
+       ret = platform_device_add(ssc_pdev);
+       if (ret < 0)
+               platform_device_put(ssc_pdev);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(atmel_ssc_set_audio);
+
+static int __init snd_atmel_ssc_init(void)
 {
-       return snd_soc_register_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai));
+       return platform_driver_register(&asoc_ssc_driver);
 }
-module_init(atmel_ssc_modinit);
+module_init(snd_atmel_ssc_init);
 
-static void __exit atmel_ssc_modexit(void)
+static void __exit snd_atmel_ssc_exit(void)
 {
-       snd_soc_unregister_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai));
+       platform_driver_unregister(&asoc_ssc_driver);
 }
-module_exit(atmel_ssc_modexit);
+module_exit(snd_atmel_ssc_exit);
 
 /* Module information */
 MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com");
index 391135f9c6c10b0057b7a1b742da180ca44927f2..5d4f0f9b4d9a875eb935ec79488b76ff17073ab0 100644 (file)
@@ -116,6 +116,7 @@ struct atmel_ssc_info {
        struct atmel_pcm_dma_params *dma_params[2];
        struct atmel_ssc_state ssc_state;
 };
-extern struct snd_soc_dai atmel_ssc_dai[];
+
+int atmel_ssc_set_audio(int ssc);
 
 #endif /* _AT91_SSC_DAI_H */
index 9df4c68ef000440cfeccd0cd0123de35c03e2a76..5f4e59f4461c3599a1cf3443e48d96e1e2aeee73 100644 (file)
@@ -83,7 +83,7 @@ static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock(
        struct snd_pcm_hw_params *params,
        struct snd_soc_dai *cpu_dai)
 {
-       struct at32_ssc_info *ssc_p = cpu_dai->private_data;
+       struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssc_device *ssc = ssc_p->ssc;
        struct ssc_clock_data cd;
        unsigned int rate, width_bits, channels;
@@ -131,9 +131,9 @@ static int playpaq_wm8510_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 at32_ssc_info *ssc_p = cpu_dai->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssc_device *ssc = ssc_p->ssc;
        unsigned int pll_out = 0, bclk = 0, mclk_div = 0;
        int ret;
@@ -315,8 +315,9 @@ static const struct snd_soc_dapm_route intercon[] = {
 
 
 
-static int playpaq_wm8510_init(struct snd_soc_codec *codec)
+static int playpaq_wm8510_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int i;
 
        /*
@@ -342,7 +343,7 @@ static int playpaq_wm8510_init(struct snd_soc_codec *codec)
 
 
        /* Make CSB show PLL rate */
-       snd_soc_dai_set_clkdiv(codec->dai, WM8510_OPCLKDIV,
+       snd_soc_dai_set_clkdiv(rtd->codec_dai, WM8510_OPCLKDIV,
                                       WM8510_OPCLKDIV_1 | 4);
 
        return 0;
@@ -353,8 +354,10 @@ static int playpaq_wm8510_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link playpaq_wm8510_dai = {
        .name = "WM8510",
        .stream_name = "WM8510 PCM",
-       .cpu_dai = &at32_ssc_dai[0],
-       .codec_dai = &wm8510_dai,
+       .cpu_dai_name= "atmel-ssc-dai.0",
+       .platform_name = "atmel-pcm-audio",
+       .codec_name = "wm8510-codec.0-0x1a",
+       .codec_dai_name = "wm8510-hifi",
        .init = playpaq_wm8510_init,
        .ops = &playpaq_wm8510_ops,
 };
@@ -363,46 +366,16 @@ static struct snd_soc_dai_link playpaq_wm8510_dai = {
 
 static struct snd_soc_card snd_soc_playpaq = {
        .name = "LRS_PlayPaq_WM8510",
-       .platform = &at32_soc_platform,
        .dai_link = &playpaq_wm8510_dai,
        .num_links = 1,
 };
 
-
-
-static struct wm8510_setup_data playpaq_wm8510_setup = {
-       .i2c_bus = 0,
-       .i2c_address = 0x1a,
-};
-
-
-
-static struct snd_soc_device playpaq_wm8510_snd_devdata = {
-       .card = &snd_soc_playpaq,
-       .codec_dev = &soc_codec_dev_wm8510,
-       .codec_data = &playpaq_wm8510_setup,
-};
-
 static struct platform_device *playpaq_snd_device;
 
 
 static int __init playpaq_asoc_init(void)
 {
        int ret = 0;
-       struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data;
-       struct ssc_device *ssc = NULL;
-
-
-       /*
-        * Request SSC device
-        */
-       ssc = ssc_request(0);
-       if (IS_ERR(ssc)) {
-               ret = PTR_ERR(ssc);
-               goto err_ssc;
-       }
-       ssc_p->ssc = ssc;
-
 
        /*
         * Configure MCLK for WM8510
@@ -439,8 +412,7 @@ static int __init playpaq_asoc_init(void)
                goto err_device_alloc;
        }
 
-       platform_set_drvdata(playpaq_snd_device, &playpaq_wm8510_snd_devdata);
-       playpaq_wm8510_snd_devdata.dev = &playpaq_snd_device->dev;
+       platform_set_drvdata(playpaq_snd_device, &snd_soc_playpaq);
 
        ret = platform_device_add(playpaq_snd_device);
        if (ret) {
@@ -468,25 +440,12 @@ err_pll0:
                clk_put(_gclk0);
                _gclk0 = NULL;
        }
-err_gclk0:
-       ssc_free(ssc);
-err_ssc:
        return ret;
 }
 
 
 static void __exit playpaq_asoc_exit(void)
 {
-       struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data;
-       struct ssc_device *ssc;
-
-       if (ssc_p != NULL) {
-               ssc = ssc_p->ssc;
-               if (ssc != NULL)
-                       ssc_free(ssc);
-               ssc_p->ssc = NULL;
-       }
-
        if (_gclk0 != NULL) {
                clk_put(_gclk0);
                _gclk0 = NULL;
index e028744c32ce9928c9160cc4f79f10642fa1d693..293569dfd0edec6d70551d90e610a93bba74ad7f 100644 (file)
@@ -69,8 +69,8 @@ static int at91sam9g20ek_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* set codec DAI configuration */
@@ -136,16 +136,17 @@ static const struct snd_soc_dapm_route intercon[] = {
 /*
  * Logic for a wm8731 as connected on a at91sam9g20ek board.
  */
-static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec)
+static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_dai *codec_dai = &codec->dai[0];
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int ret;
 
        printk(KERN_DEBUG
                        "at91sam9g20ek_wm8731 "
                        ": at91sam9g20ek_wm8731_init() called\n");
 
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
                MCLK_RATE, SND_SOC_CLOCK_IN);
        if (ret < 0) {
                printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret);
@@ -179,37 +180,37 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link at91sam9g20ek_dai = {
        .name = "WM8731",
        .stream_name = "WM8731 PCM",
-       .cpu_dai = &atmel_ssc_dai[0],
-       .codec_dai = &wm8731_dai,
+       .cpu_dai_name = "atmel-ssc-dai.0",
+       .codec_dai_name = "wm8731-hifi",
        .init = at91sam9g20ek_wm8731_init,
+       .platform_name = "atmel-pcm-audio",
+       .codec_name = "wm8731-codec.0-001b",
        .ops = &at91sam9g20ek_ops,
 };
 
 static struct snd_soc_card snd_soc_at91sam9g20ek = {
        .name = "AT91SAMG20-EK",
-       .platform = &atmel_soc_platform,
        .dai_link = &at91sam9g20ek_dai,
        .num_links = 1,
        .set_bias_level = at91sam9g20ek_set_bias_level,
 };
 
-static struct snd_soc_device at91sam9g20ek_snd_devdata = {
-       .card = &snd_soc_at91sam9g20ek,
-       .codec_dev = &soc_codec_dev_wm8731,
-};
-
 static struct platform_device *at91sam9g20ek_snd_device;
 
 static int __init at91sam9g20ek_init(void)
 {
-       struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data;
-       struct ssc_device *ssc = NULL;
        struct clk *pllb;
        int ret;
 
        if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc()))
                return -ENODEV;
 
+       ret = atmel_ssc_set_audio(0);
+       if (ret != 0) {
+               pr_err("Failed to set SSC 0 for audio: %d\n", ret);
+               return ret;
+       }
+
        /*
         * Codec MCLK is supplied by PCK0 - set it up.
         */
@@ -235,18 +236,6 @@ static int __init at91sam9g20ek_init(void)
 
        clk_set_rate(mclk, MCLK_RATE);
 
-       /*
-        * Request SSC device
-        */
-       ssc = ssc_request(0);
-       if (IS_ERR(ssc)) {
-               printk(KERN_ERR "ASoC: Failed to request SSC 0\n");
-               ret = PTR_ERR(ssc);
-               ssc = NULL;
-               goto err_ssc;
-       }
-       ssc_p->ssc = ssc;
-
        at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1);
        if (!at91sam9g20ek_snd_device) {
                printk(KERN_ERR "ASoC: Platform device allocation failed\n");
@@ -254,8 +243,7 @@ static int __init at91sam9g20ek_init(void)
        }
 
        platform_set_drvdata(at91sam9g20ek_snd_device,
-                       &at91sam9g20ek_snd_devdata);
-       at91sam9g20ek_snd_devdata.dev = &at91sam9g20ek_snd_device->dev;
+                       &snd_soc_at91sam9g20ek);
 
        ret = platform_device_add(at91sam9g20ek_snd_device);
        if (ret) {
@@ -265,9 +253,6 @@ static int __init at91sam9g20ek_init(void)
 
        return ret;
 
-err_ssc:
-       ssc_free(ssc);
-       ssc_p->ssc = NULL;
 err_mclk:
        clk_put(mclk);
        mclk = NULL;
@@ -277,16 +262,6 @@ err:
 
 static void __exit at91sam9g20ek_exit(void)
 {
-       struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data;
-       struct ssc_device *ssc;
-
-       if (ssc_p != NULL) {
-               ssc = ssc_p->ssc;
-               if (ssc != NULL)
-                       ssc_free(ssc);
-               ssc_p->ssc = NULL;
-       }
-
        platform_device_unregister(at91sam9g20ek_snd_device);
        at91sam9g20ek_snd_device = NULL;
        clk_put(mclk);
index 23349de273134871e153ce42a1129815c4fae745..e3d283561c196a8198e97d6bf2cc3b1b11987624 100644 (file)
@@ -46,8 +46,8 @@ static int afeb9260_hw_params(struct snd_pcm_substream *substream,
                         struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int err;
 
        /* Set codec DAI configuration */
@@ -102,8 +102,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"MICIN", NULL, "Mic Jack"},
 };
 
-static int afeb9260_tlv320aic23_init(struct snd_soc_codec *codec)
+static int afeb9260_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* Add afeb9260 specific widgets */
        snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
@@ -125,8 +126,10 @@ static int afeb9260_tlv320aic23_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link afeb9260_dai = {
        .name = "TLV320AIC23",
        .stream_name = "AIC23",
-       .cpu_dai = &atmel_ssc_dai[0],
-       .codec_dai = &tlv320aic23_dai,
+       .cpu_dai_name = "atmel-ssc-dai.0",
+       .codec_dai_name = "tlv320aic23-hifi",
+       .platform_name = "atmel_pcm-audio",
+       .codec_name = "tlv320aic23-codec.0-0x1a",
        .init = afeb9260_tlv320aic23_init,
        .ops = &afeb9260_ops,
 };
@@ -134,37 +137,20 @@ static struct snd_soc_dai_link afeb9260_dai = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_machine_afeb9260 = {
        .name = "AFEB9260",
-       .platform = &atmel_soc_platform,
        .dai_link = &afeb9260_dai,
        .num_links = 1,
 };
 
-/* Audio subsystem */
-static struct snd_soc_device afeb9260_snd_devdata = {
-       .card = &snd_soc_machine_afeb9260,
-       .codec_dev = &soc_codec_dev_tlv320aic23,
-};
-
 static struct platform_device *afeb9260_snd_device;
 
 static int __init afeb9260_soc_init(void)
 {
        int err;
        struct device *dev;
-       struct atmel_ssc_info *ssc_p = afeb9260_dai.cpu_dai->private_data;
-       struct ssc_device *ssc = NULL;
 
        if (!(machine_is_afeb9260()))
                return -ENODEV;
 
-       ssc = ssc_request(0);
-       if (IS_ERR(ssc)) {
-               printk(KERN_ERR "ASoC: Failed to request SSC 0\n");
-               err = PTR_ERR(ssc);
-               ssc = NULL;
-               goto err_ssc;
-       }
-       ssc_p->ssc = ssc;
 
        afeb9260_snd_device = platform_device_alloc("soc-audio", -1);
        if (!afeb9260_snd_device) {
@@ -172,8 +158,7 @@ static int __init afeb9260_soc_init(void)
                return -ENOMEM;
        }
 
-       platform_set_drvdata(afeb9260_snd_device, &afeb9260_snd_devdata);
-       afeb9260_snd_devdata.dev = &afeb9260_snd_device->dev;
+       platform_set_drvdata(afeb9260_snd_device, &snd_soc_machine_afeb9260);
        err = platform_device_add(afeb9260_snd_device);
        if (err)
                goto err1;
@@ -184,9 +169,7 @@ static int __init afeb9260_soc_init(void)
 err1:
        platform_device_del(afeb9260_snd_device);
        platform_device_put(afeb9260_snd_device);
-err_ssc:
        return err;
-
 }
 
 static void __exit afeb9260_soc_exit(void)
index cdf7be1b9b91095ce0053e0c39595c4f5911ebb1..b62fcd33e586f812b9c556002bdec1b44ee774aa 100644 (file)
@@ -19,7 +19,6 @@
 #include <asm/mach-au1x00/au1xxx_dbdma.h>
 #include <asm/mach-db1x00/bcsr.h>
 
-#include "../codecs/ac97.h"
 #include "../codecs/wm8731.h"
 #include "psc.h"
 
 static struct snd_soc_dai_link db1200_ac97_dai = {
        .name           = "AC97",
        .stream_name    = "AC97 HiFi",
-       .cpu_dai        = &au1xpsc_ac97_dai,
-       .codec_dai      = &ac97_dai,
+       .codec_dai_name = "ac97-hifi",
+       .cpu_dai_name   = "au1xpsc_ac97.1",
+       .platform_name  = "au1xpsc-pcm.1",
+       .codec_name     = "ac97-codec.1",
 };
 
 static struct snd_soc_card db1200_ac97_machine = {
        .name           = "DB1200_AC97",
        .dai_link       = &db1200_ac97_dai,
        .num_links      = 1,
-       .platform       = &au1xpsc_soc_platform,
-};
-
-static struct snd_soc_device db1200_ac97_devdata = {
-       .card           = &db1200_ac97_machine,
-       .codec_dev      = &soc_codec_dev_ac97,
 };
 
 /*-------------------------  I2S PART  ---------------------------*/
@@ -49,12 +44,12 @@ static struct snd_soc_device db1200_ac97_devdata = {
 static int db1200_i2s_startup(struct snd_pcm_substream *substream)
 {
        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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* WM8731 has its own 12MHz crystal */
-       snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
+       snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
                                12000000, SND_SOC_CLOCK_IN);
 
        /* codec is bitclock and lrclk master */
@@ -80,8 +75,10 @@ static struct snd_soc_ops db1200_i2s_wm8731_ops = {
 static struct snd_soc_dai_link db1200_i2s_dai = {
        .name           = "WM8731",
        .stream_name    = "WM8731 PCM",
-       .cpu_dai        = &au1xpsc_i2s_dai,
-       .codec_dai      = &wm8731_dai,
+       .codec_dai_name = "wm8731-hifi",
+       .cpu_dai_name   = "au1xpsc_i2s.1",
+       .platform_name  = "au1xpsc-pcm.1",
+       .codec_name     = "wm8731-codec.0-001b",
        .ops            = &db1200_i2s_wm8731_ops,
 };
 
@@ -89,12 +86,6 @@ static struct snd_soc_card db1200_i2s_machine = {
        .name           = "DB1200_I2S",
        .dai_link       = &db1200_i2s_dai,
        .num_links      = 1,
-       .platform       = &au1xpsc_soc_platform,
-};
-
-static struct snd_soc_device db1200_i2s_devdata = {
-       .card           = &db1200_i2s_machine,
-       .codec_dev      = &soc_codec_dev_wm8731,
 };
 
 /*-------------------------  COMMON PART  ---------------------------*/
@@ -106,18 +97,16 @@ static int __init db1200_audio_load(void)
        int ret;
 
        ret = -ENOMEM;
-       db1200_asoc_dev = platform_device_alloc("soc-audio", -1);
+       db1200_asoc_dev = platform_device_alloc("soc-audio", 1); /* PSC1 */
        if (!db1200_asoc_dev)
                goto out;
 
        /* DB1200 board setup set PSC1MUX to preferred audio device */
        if (bcsr_read(BCSR_RESETS) & BCSR_RESETS_PSC1MUX)
-               platform_set_drvdata(db1200_asoc_dev, &db1200_i2s_devdata);
+               platform_set_drvdata(db1200_asoc_dev, &db1200_i2s_machine);
        else
-               platform_set_drvdata(db1200_asoc_dev, &db1200_ac97_devdata);
+               platform_set_drvdata(db1200_asoc_dev, &db1200_ac97_machine);
 
-       db1200_ac97_devdata.dev = &db1200_asoc_dev->dev;
-       db1200_i2s_devdata.dev = &db1200_asoc_dev->dev;
        ret = platform_device_add(db1200_asoc_dev);
 
        if (ret) {
index 6d9f4c624949ed65906433a2efc2caa33bde841d..10fdd2854e584aaf17593521458abc4ba6a0818b 100644 (file)
@@ -10,9 +10,6 @@
  *
  * DMA glue for Au1x-PSC audio.
  *
- * NOTE: all of these drivers can only work with a SINGLE instance
- *      of a PSC. Multiple independent audio devices are impossible
- *      with ASoC v1.
  */
 
 
@@ -61,9 +58,6 @@ struct au1xpsc_audio_dmadata {
        int msbits;
 };
 
-/* instance data. There can be only one, MacLeod!!!! */
-static struct au1xpsc_audio_dmadata *au1xpsc_audio_pcmdma[2];
-
 /*
  * These settings are somewhat okay, at least on my machine audio plays
  * almost skip-free. Especially the 64kB buffer seems to help a LOT.
@@ -199,6 +193,14 @@ out:
        return 0;
 }
 
+static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream *ss)
+{
+       struct snd_soc_pcm_runtime *rtd = ss->private_data;
+       struct au1xpsc_audio_dmadata *pcd =
+                               snd_soc_platform_get_drvdata(rtd->platform);
+       return &pcd[SUBSTREAM_TYPE(ss)];
+}
+
 static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params)
 {
@@ -211,7 +213,7 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
                goto out;
 
        stype = SUBSTREAM_TYPE(substream);
-       pcd = au1xpsc_audio_pcmdma[stype];
+       pcd = to_dmadata(substream);
 
        DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d "
            "runtime->min_align %d\n",
@@ -249,8 +251,7 @@ static int au1xpsc_pcm_hw_free(struct snd_pcm_substream *substream)
 
 static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
 {
-       struct au1xpsc_audio_dmadata *pcd =
-                       au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)];
+       struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream);
 
        au1xxx_dbdma_reset(pcd->ddma_chan);
 
@@ -267,7 +268,7 @@ static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
 
 static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
-       u32 c = au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->ddma_chan;
+       u32 c = to_dmadata(substream)->ddma_chan;
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -287,8 +288,7 @@ static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 static snd_pcm_uframes_t
 au1xpsc_pcm_pointer(struct snd_pcm_substream *substream)
 {
-       return bytes_to_frames(substream->runtime,
-               au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->pos);
+       return bytes_to_frames(substream->runtime, to_dmadata(substream)->pos);
 }
 
 static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
@@ -299,7 +299,7 @@ static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
 
 static int au1xpsc_pcm_close(struct snd_pcm_substream *substream)
 {
-       au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]);
+       au1x_pcm_dbdma_free(to_dmadata(substream));
        return 0;
 }
 
@@ -329,42 +329,21 @@ static int au1xpsc_pcm_new(struct snd_card *card,
        return 0;
 }
 
-static int au1xpsc_pcm_probe(struct platform_device *pdev)
-{
-       if (!au1xpsc_audio_pcmdma[PCM_TX] || !au1xpsc_audio_pcmdma[PCM_RX])
-               return -ENODEV;
-
-       return 0;
-}
-
-static int au1xpsc_pcm_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
 /* au1xpsc audio platform */
-struct snd_soc_platform au1xpsc_soc_platform = {
-       .name           = "au1xpsc-pcm-dbdma",
-       .probe          = au1xpsc_pcm_probe,
-       .remove         = au1xpsc_pcm_remove,
-       .pcm_ops        = &au1xpsc_pcm_ops,
+struct snd_soc_platform_driver au1xpsc_soc_platform = {
+       .ops            = &au1xpsc_pcm_ops,
        .pcm_new        = au1xpsc_pcm_new,
        .pcm_free       = au1xpsc_pcm_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(au1xpsc_soc_platform);
 
 static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
 {
+       struct au1xpsc_audio_dmadata *dmadata;
        struct resource *r;
        int ret;
 
-       if (au1xpsc_audio_pcmdma[PCM_TX] || au1xpsc_audio_pcmdma[PCM_RX])
-               return -EBUSY;
-
-       /* TX DMA */
-       au1xpsc_audio_pcmdma[PCM_TX]
-               = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
-       if (!au1xpsc_audio_pcmdma[PCM_TX])
+       dmadata = kzalloc(2 * sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
+       if (!dmadata)
                return -ENOMEM;
 
        r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
@@ -372,47 +351,33 @@ static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
                ret = -ENODEV;
                goto out1;
        }
-       (au1xpsc_audio_pcmdma[PCM_TX])->ddma_id = r->start;
+       dmadata[PCM_TX].ddma_id = r->start;
 
        /* RX DMA */
-       au1xpsc_audio_pcmdma[PCM_RX]
-               = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
-       if (!au1xpsc_audio_pcmdma[PCM_RX])
-               return -ENOMEM;
-
        r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
        if (!r) {
                ret = -ENODEV;
-               goto out2;
+               goto out1;
        }
-       (au1xpsc_audio_pcmdma[PCM_RX])->ddma_id = r->start;
+       dmadata[PCM_RX].ddma_id = r->start;
+
+       platform_set_drvdata(pdev, dmadata);
 
-       ret = snd_soc_register_platform(&au1xpsc_soc_platform);
+       ret = snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform);
        if (!ret)
                return ret;
 
-out2:
-       kfree(au1xpsc_audio_pcmdma[PCM_RX]);
-       au1xpsc_audio_pcmdma[PCM_RX] = NULL;
 out1:
-       kfree(au1xpsc_audio_pcmdma[PCM_TX]);
-       au1xpsc_audio_pcmdma[PCM_TX] = NULL;
+       kfree(dmadata);
        return ret;
 }
 
 static int __devexit au1xpsc_pcm_drvremove(struct platform_device *pdev)
 {
-       int i;
+       struct au1xpsc_audio_dmadata *dmadata = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_platform(&au1xpsc_soc_platform);
-
-       for (i = 0; i < 2; i++) {
-               if (au1xpsc_audio_pcmdma[i]) {
-                       au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[i]);
-                       kfree(au1xpsc_audio_pcmdma[i]);
-                       au1xpsc_audio_pcmdma[i] = NULL;
-               }
-       }
+       snd_soc_unregister_platform(&pdev->dev);
+       kfree(dmadata);
 
        return 0;
 }
@@ -428,8 +393,6 @@ static struct platform_driver au1xpsc_pcm_driver = {
 
 static int __init au1xpsc_audio_dbdma_load(void)
 {
-       au1xpsc_audio_pcmdma[PCM_TX] = NULL;
-       au1xpsc_audio_pcmdma[PCM_RX] = NULL;
        return platform_driver_register(&au1xpsc_pcm_driver);
 }
 
@@ -467,7 +430,7 @@ struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev)
        res[1].start = res[1].end = id[1];
        res[0].flags = res[1].flags = IORESOURCE_DMA;
 
-       pd = platform_device_alloc("au1xpsc-pcm", -1);
+       pd = platform_device_alloc("au1xpsc-pcm", pdev->id);
        if (!pd)
                goto out;
 
index d14a5a91a4654dc347af790ace1244479659fb36..d0db66f24a00cc0ce68f622161bef3b4155a7c82 100644 (file)
@@ -10,9 +10,6 @@
  *
  * Au1xxx-PSC AC97 glue.
  *
- * NOTE: all of these drivers can only work with a SINGLE instance
- *      of a PSC. Multiple independent audio devices are impossible
- *      with ASoC v1.
  */
 
 #include <linux/init.h>
 /* instance data. There can be only one, MacLeod!!!! */
 static struct au1xpsc_audio_data *au1xpsc_ac97_workdata;
 
+#if 0
+
+/* this could theoretically work, but ac97->bus->card->private_data can be NULL
+ * when snd_ac97_mixer() is called; I don't know if the rest further down the
+ * chain are always valid either.
+ */
+static inline struct au1xpsc_audio_data *ac97_to_pscdata(struct snd_ac97 *x)
+{
+       struct snd_soc_card *c = x->bus->card->private_data;
+       return snd_soc_dai_get_drvdata(c->rtd->cpu_dai);
+}
+
+#else
+
+#define ac97_to_pscdata(x)     au1xpsc_ac97_workdata
+
+#endif
+
 /* AC97 controller reads codec register */
 static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
                                        unsigned short reg)
 {
-       /* FIXME */
-       struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+       struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
        unsigned short retry, tmo;
        unsigned long data;
 
@@ -102,8 +116,7 @@ static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
 static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
                                unsigned short val)
 {
-       /* FIXME */
-       struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+       struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
        unsigned int tmo, retry;
 
        au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata));
@@ -134,8 +147,7 @@ static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 /* AC97 controller asserts a warm reset */
 static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97)
 {
-       /* FIXME */
-       struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+       struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
 
        au_writel(PSC_AC97RST_SNC, AC97_RST(pscdata));
        au_sync();
@@ -146,8 +158,7 @@ static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97)
 
 static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97)
 {
-       /* FIXME */
-       struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+       struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
        int i;
 
        /* disable PSC during cold reset */
@@ -202,8 +213,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
                                  struct snd_pcm_hw_params *params,
                                  struct snd_soc_dai *dai)
 {
-       /* FIXME */
-       struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+       struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
        unsigned long r, ro, stat;
        int chans, t, stype = SUBSTREAM_TYPE(substream);
 
@@ -283,8 +293,7 @@ out:
 static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
                                int cmd, struct snd_soc_dai *dai)
 {
-       /* FIXME */
-       struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+       struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
        int ret, stype = SUBSTREAM_TYPE(substream);
 
        ret = 0;
@@ -315,27 +324,19 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
        return ret;
 }
 
-static int au1xpsc_ac97_probe(struct platform_device *pdev,
-                             struct snd_soc_dai *dai)
+static int au1xpsc_ac97_probe(struct snd_soc_dai *dai)
 {
        return au1xpsc_ac97_workdata ? 0 : -ENODEV;
 }
 
-static void au1xpsc_ac97_remove(struct platform_device *pdev,
-                               struct snd_soc_dai *dai)
-{
-}
-
 static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
        .trigger        = au1xpsc_ac97_trigger,
        .hw_params      = au1xpsc_ac97_hw_params,
 };
 
-struct snd_soc_dai au1xpsc_ac97_dai = {
-       .name                   = "au1xpsc_ac97",
+static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
        .ac97_control           = 1,
        .probe                  = au1xpsc_ac97_probe,
-       .remove                 = au1xpsc_ac97_remove,
        .playback = {
                .rates          = AC97_RATES,
                .formats        = AC97_FMTS,
@@ -350,7 +351,6 @@ struct snd_soc_dai au1xpsc_ac97_dai = {
        },
        .ops = &au1xpsc_ac97_dai_ops,
 };
-EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai);
 
 static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
 {
@@ -359,9 +359,6 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
        unsigned long sel;
        struct au1xpsc_audio_data *wd;
 
-       if (au1xpsc_ac97_workdata)
-               return -EBUSY;
-
        wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
        if (!wd)
                return -ENOMEM;
@@ -395,18 +392,24 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
        au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(wd));
        au_sync();
 
-       ret = snd_soc_register_dai(&au1xpsc_ac97_dai);
+       /* name the DAI like this device instance ("au1xpsc-ac97.PSCINDEX") */
+       memcpy(&wd->dai_drv, &au1xpsc_ac97_dai_template,
+              sizeof(struct snd_soc_dai_driver));
+       wd->dai_drv.name = dev_name(&pdev->dev);
+
+       platform_set_drvdata(pdev, wd);
+
+       ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
        if (ret)
                goto out1;
 
        wd->dmapd = au1xpsc_pcm_add(pdev);
        if (wd->dmapd) {
-               platform_set_drvdata(pdev, wd);
-               au1xpsc_ac97_workdata = wd;     /* MDEV */
+               au1xpsc_ac97_workdata = wd;
                return 0;
        }
 
-       snd_soc_unregister_dai(&au1xpsc_ac97_dai);
+       snd_soc_unregister_dai(&pdev->dev);
 out1:
        release_mem_region(r->start, resource_size(r));
 out0:
@@ -422,7 +425,7 @@ static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
        if (wd->dmapd)
                au1xpsc_pcm_destroy(wd->dmapd);
 
-       snd_soc_unregister_dai(&au1xpsc_ac97_dai);
+       snd_soc_unregister_dai(&pdev->dev);
 
        /* disable PSC completely */
        au_writel(0, AC97_CFG(wd));
index 6083fe7799faba3b6b4737136b12d74cc428f59b..fca091276320930e7f8abd230556dabbc392e2d7 100644 (file)
@@ -10,9 +10,6 @@
  *
  * Au1xxx-PSC I2S glue.
  *
- * NOTE: all of these drivers can only work with a SINGLE instance
- *      of a PSC. Multiple independent audio devices are impossible
- *      with ASoC v1.
  * NOTE: so far only PSC slave mode (bit- and frameclock) is supported.
  */
 
        ((stype) == PCM_TX ? PSC_I2SPCR_TC : PSC_I2SPCR_RC)
 
 
-/* instance data. There can be only one, MacLeod!!!! */
-static struct au1xpsc_audio_data *au1xpsc_i2s_workdata;
-
 static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
                               unsigned int fmt)
 {
-       struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+       struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(cpu_dai);
        unsigned long ct;
        int ret;
 
@@ -120,7 +114,7 @@ static int au1xpsc_i2s_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *dai)
 {
-       struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+       struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
 
        int cfgbits;
        unsigned long stat;
@@ -245,7 +239,7 @@ static int au1xpsc_i2s_stop(struct au1xpsc_audio_data *pscdata, int stype)
 static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
                               struct snd_soc_dai *dai)
 {
-       struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+       struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
        int ret, stype = SUBSTREAM_TYPE(substream);
 
        switch (cmd) {
@@ -263,27 +257,13 @@ static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
        return ret;
 }
 
-static int au1xpsc_i2s_probe(struct platform_device *pdev,
-                            struct snd_soc_dai *dai)
-{
-       return  au1xpsc_i2s_workdata ? 0 : -ENODEV;
-}
-
-static void au1xpsc_i2s_remove(struct platform_device *pdev,
-                              struct snd_soc_dai *dai)
-{
-}
-
 static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
        .trigger        = au1xpsc_i2s_trigger,
        .hw_params      = au1xpsc_i2s_hw_params,
        .set_fmt        = au1xpsc_i2s_set_fmt,
 };
 
-struct snd_soc_dai au1xpsc_i2s_dai = {
-       .name                   = "au1xpsc_i2s",
-       .probe                  = au1xpsc_i2s_probe,
-       .remove                 = au1xpsc_i2s_remove,
+static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = {
        .playback = {
                .rates          = AU1XPSC_I2S_RATES,
                .formats        = AU1XPSC_I2S_FMTS,
@@ -298,7 +278,6 @@ struct snd_soc_dai au1xpsc_i2s_dai = {
        },
        .ops = &au1xpsc_i2s_dai_ops,
 };
-EXPORT_SYMBOL(au1xpsc_i2s_dai);
 
 static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
 {
@@ -307,9 +286,6 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
        int ret;
        struct au1xpsc_audio_data *wd;
 
-       if (au1xpsc_i2s_workdata)
-               return -EBUSY;
-
        wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
        if (!wd)
                return -ENOMEM;
@@ -346,19 +322,23 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
         * time out.
         */
 
-       ret = snd_soc_register_dai(&au1xpsc_i2s_dai);
+       /* name the DAI like this device instance ("au1xpsc-i2s.PSCINDEX") */
+       memcpy(&wd->dai_drv, &au1xpsc_i2s_dai_template,
+              sizeof(struct snd_soc_dai_driver));
+       wd->dai_drv.name = dev_name(&pdev->dev);
+
+       platform_set_drvdata(pdev, wd);
+
+       ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
        if (ret)
                goto out1;
 
        /* finally add the DMA device for this PSC */
        wd->dmapd = au1xpsc_pcm_add(pdev);
-       if (wd->dmapd) {
-               platform_set_drvdata(pdev, wd);
-               au1xpsc_i2s_workdata = wd;
+       if (wd->dmapd)
                return 0;
-       }
 
-       snd_soc_unregister_dai(&au1xpsc_i2s_dai);
+       snd_soc_unregister_dai(&pdev->dev);
 out1:
        release_mem_region(r->start, resource_size(r));
 out0:
@@ -374,7 +354,7 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
        if (wd->dmapd)
                au1xpsc_pcm_destroy(wd->dmapd);
 
-       snd_soc_unregister_dai(&au1xpsc_i2s_dai);
+       snd_soc_unregister_dai(&pdev->dev);
 
        au_writel(0, I2S_CFG(wd));
        au_sync();
@@ -385,8 +365,6 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
        release_mem_region(r->start, resource_size(r));
        kfree(wd);
 
-       au1xpsc_i2s_workdata = NULL;    /* MDEV */
-
        return 0;
 }
 
@@ -446,7 +424,6 @@ static struct platform_driver au1xpsc_i2s_driver = {
 
 static int __init au1xpsc_i2s_load(void)
 {
-       au1xpsc_i2s_workdata = NULL;
        return platform_driver_register(&au1xpsc_i2s_driver);
 }
 
index 093775d4dc3e47185759c737e1bb18338a615b7c..b30eadd422a7fb7aee4856e671d491d769d2c6ac 100644 (file)
@@ -8,19 +8,11 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- * NOTE: all of these drivers can only work with a SINGLE instance
- *      of a PSC. Multiple independent audio devices are impossible
- *      with ASoC v1.
  */
 
 #ifndef _AU1X_PCM_H
 #define _AU1X_PCM_H
 
-extern struct snd_soc_dai au1xpsc_ac97_dai;
-extern struct snd_soc_dai au1xpsc_i2s_dai;
-extern struct snd_soc_platform au1xpsc_soc_platform;
-extern struct snd_ac97_bus_ops soc_ac97_ops;
-
 /* DBDMA helpers */
 extern struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev);
 extern void au1xpsc_pcm_destroy(struct platform_device *dmapd);
@@ -31,6 +23,8 @@ struct au1xpsc_audio_data {
        unsigned long cfg;
        unsigned long rate;
 
+       struct snd_soc_dai_driver dai_drv;
+
        unsigned long pm[2];
        struct mutex lock;
        struct platform_device *dmapd;
index 5e7aacf3bb5a2027c2decfe98e3b49919c04a207..5a2fd8abaefaee65e5509e4c98adf252c06293df 100644 (file)
@@ -422,14 +422,14 @@ int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -439,25 +439,44 @@ int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai,
        return ret;
 }
 
-struct snd_soc_platform bf5xx_ac97_soc_platform = {
-       .name           = "bf5xx-audio",
-       .pcm_ops        = &bf5xx_pcm_ac97_ops,
+static struct snd_soc_platform_driver bf5xx_ac97_soc_platform = {
+       .ops                    = &bf5xx_pcm_ac97_ops,
        .pcm_new        = bf5xx_pcm_ac97_new,
        .pcm_free       = bf5xx_pcm_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(bf5xx_ac97_soc_platform);
 
-static int __init bfin_ac97_init(void)
+static int __devinit bf5xx_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&bf5xx_ac97_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &bf5xx_ac97_soc_platform);
 }
-module_init(bfin_ac97_init);
 
-static void __exit bfin_ac97_exit(void)
+static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&bf5xx_ac97_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver bf5xx_pcm_driver = {
+       .driver = {
+                       .name = "bf5xx-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = bf5xx_soc_platform_probe,
+       .remove = __devexit_p(bf5xx_soc_platform_remove),
+};
+
+static int __init snd_bf5xx_pcm_init(void)
+{
+       return platform_driver_register(&bf5xx_pcm_driver);
+}
+module_init(snd_bf5xx_pcm_init);
+
+static void __exit snd_bf5xx_pcm_exit(void)
+{
+       platform_driver_unregister(&bf5xx_pcm_driver);
 }
-module_exit(bfin_ac97_exit);
+module_exit(snd_bf5xx_pcm_exit);
 
 MODULE_AUTHOR("Cliff Cai");
 MODULE_DESCRIPTION("ADI Blackfin AC97 PCM DMA module");
index 350125a0ae21282a74acd35c007c98de97d741f1..d324d5826a9baaaba648129bd21e2634160666df 100644 (file)
@@ -23,7 +23,4 @@ struct bf5xx_gpio {
        u32 frm;
 };
 
-/* platform data */
-extern struct snd_soc_platform bf5xx_ac97_soc_platform;
-
 #endif
index c0eba51099804fcebc40ee13d5b495b3106448f2..c5f856ec27ca1bedc8d0256cf5fe97d11ebac730 100644 (file)
@@ -255,7 +255,7 @@ EXPORT_SYMBOL_GPL(soc_ac97_ops);
 #ifdef CONFIG_PM
 static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
 {
-       struct sport_device *sport = dai->private_data;
+       struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
        pr_debug("%s : sport %d\n", __func__, dai->id);
        if (!dai->active)
@@ -270,7 +270,7 @@ static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
 static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
 {
        int ret;
-       struct sport_device *sport = dai->private_data;
+       struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
        pr_debug("%s : sport %d\n", __func__, dai->id);
        if (!dai->active)
@@ -306,8 +306,7 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
 #define bf5xx_ac97_resume      NULL
 #endif
 
-static int bf5xx_ac97_probe(struct platform_device *pdev,
-                           struct snd_soc_dai *dai)
+static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
 {
        int ret = 0;
        cmd_count = (int *)get_zeroed_page(GFP_KERNEL);
@@ -379,8 +378,7 @@ peripheral_err:
        return ret;
 }
 
-static void bf5xx_ac97_remove(struct platform_device *pdev,
-                             struct snd_soc_dai *dai)
+static int bf5xx_ac97_remove(struct snd_soc_dai *dai)
 {
        free_page((unsigned long)cmd_count);
        cmd_count = NULL;
@@ -388,11 +386,10 @@ static void bf5xx_ac97_remove(struct platform_device *pdev,
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
        gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
 #endif
+       return 0;
 }
 
-struct snd_soc_dai bfin_ac97_dai = {
-       .name = "bf5xx-ac97",
-       .id = 0,
+struct snd_soc_dai_driver bfin_ac97_dai = {
        .ac97_control = 1,
        .probe = bf5xx_ac97_probe,
        .remove = bf5xx_ac97_remove,
@@ -417,18 +414,40 @@ struct snd_soc_dai bfin_ac97_dai = {
 };
 EXPORT_SYMBOL_GPL(bfin_ac97_dai);
 
+static __devinit int asoc_bfin_ac97_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
+}
+
+static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver asoc_bfin_ac97_driver = {
+       .driver = {
+                       .name = "bfin-ac97",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = asoc_bfin_ac97_probe,
+       .remove = __devexit_p(asoc_bfin_ac97_remove),
+};
+
 static int __init bfin_ac97_init(void)
 {
-       return snd_soc_register_dai(&bfin_ac97_dai);
+       return platform_driver_register(&asoc_bfin_ac97_driver);
 }
 module_init(bfin_ac97_init);
 
 static void __exit bfin_ac97_exit(void)
 {
-       snd_soc_unregister_dai(&bfin_ac97_dai);
+       platform_driver_unregister(&asoc_bfin_ac97_driver);
 }
 module_exit(bfin_ac97_exit);
 
+
 MODULE_AUTHOR("Roy Huang");
 MODULE_DESCRIPTION("AC97 driver for ADI Blackfin");
 MODULE_LICENSE("GPL");
index a1f97dd809d63fda550f4d62cd18a5a2c1eb7bde..15c635e33f4d99a42b6386cbc7e7c54e2bf807ef 100644 (file)
@@ -50,8 +50,6 @@ struct ac97_frame {
 #define TAG_PCM_SR             0x0080
 #define TAG_PCM_LFE            0x0040
 
-extern struct snd_soc_dai bfin_ac97_dai;
-
 void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, \
                size_t count, unsigned int chan_mask);
 
index 0f45a3f56be8f3ff4ae335941d30c0fda62d24b8..2394bff2b655bce897b5ea209f134744dc8ffc94 100644 (file)
@@ -40,9 +40,9 @@ static struct snd_soc_card bf5xx_ad1836;
 static int bf5xx_ad1836_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
-       cpu_dai->private_data = sport_handle;
+       snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
        return 0;
 }
 
@@ -50,8 +50,8 @@ static int bf5xx_ad1836_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->dai->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        unsigned int channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7};
        int ret = 0;
        /* set cpu DAI configuration */
@@ -83,23 +83,19 @@ static struct snd_soc_ops bf5xx_ad1836_ops = {
 static struct snd_soc_dai_link bf5xx_ad1836_dai = {
        .name = "ad1836",
        .stream_name = "AD1836",
-       .cpu_dai = &bf5xx_tdm_dai,
-       .codec_dai = &ad1836_dai,
+       .cpu_dai_name = "bf5xx-tdm",
+       .codec_dai_name = "ad1836-hifi",
+       .platform_name = "bf5xx-tdm-pcm-audio",
+       .codec_name = "ad1836-codec.0",
        .ops = &bf5xx_ad1836_ops,
 };
 
 static struct snd_soc_card bf5xx_ad1836 = {
        .name = "bf5xx_ad1836",
-       .platform = &bf5xx_tdm_soc_platform,
        .dai_link = &bf5xx_ad1836_dai,
        .num_links = 1,
 };
 
-static struct snd_soc_device bf5xx_ad1836_snd_devdata = {
-       .card = &bf5xx_ad1836,
-       .codec_dev = &soc_codec_dev_ad1836,
-};
-
 static struct platform_device *bfxx_ad1836_snd_device;
 
 static int __init bf5xx_ad1836_init(void)
@@ -110,8 +106,7 @@ static int __init bf5xx_ad1836_init(void)
        if (!bfxx_ad1836_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(bfxx_ad1836_snd_device, &bf5xx_ad1836_snd_devdata);
-       bf5xx_ad1836_snd_devdata.dev = &bfxx_ad1836_snd_device->dev;
+       platform_set_drvdata(bfxx_ad1836_snd_device, &bf5xx_ad1836);
        ret = platform_device_add(bfxx_ad1836_snd_device);
 
        if (ret)
index b8c9060cfd8e801d15620d2c710f62a96c96c02d..e4a625317a1acde4e62ea0cc9a03eeaf0ad2e00f 100644 (file)
@@ -49,9 +49,9 @@ static struct snd_soc_card bf5xx_ad193x;
 static int bf5xx_ad193x_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
-       cpu_dai->private_data = sport_handle;
+       snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
        return 0;
 }
 
@@ -59,8 +59,8 @@ static int bf5xx_ad193x_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->dai->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7};
        int ret = 0;
        /* set cpu DAI configuration */
@@ -97,23 +97,19 @@ static struct snd_soc_ops bf5xx_ad193x_ops = {
 static struct snd_soc_dai_link bf5xx_ad193x_dai = {
        .name = "ad193x",
        .stream_name = "AD193X",
-       .cpu_dai = &bf5xx_tdm_dai,
-       .codec_dai = &ad193x_dai,
+       .cpu_dai_name = "bf5xx-tdm",
+       .codec_dai_name ="ad193x-hifi",
+       .platform_name = "bf5xx-tdm-pcm-audio",
+       .codec_name = "ad193x-codec.5",
        .ops = &bf5xx_ad193x_ops,
 };
 
 static struct snd_soc_card bf5xx_ad193x = {
        .name = "bf5xx_ad193x",
-       .platform = &bf5xx_tdm_soc_platform,
        .dai_link = &bf5xx_ad193x_dai,
        .num_links = 1,
 };
 
-static struct snd_soc_device bf5xx_ad193x_snd_devdata = {
-       .card = &bf5xx_ad193x,
-       .codec_dev = &soc_codec_dev_ad193x,
-};
-
 static struct platform_device *bfxx_ad193x_snd_device;
 
 static int __init bf5xx_ad193x_init(void)
@@ -124,8 +120,7 @@ static int __init bf5xx_ad193x_init(void)
        if (!bfxx_ad193x_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(bfxx_ad193x_snd_device, &bf5xx_ad193x_snd_devdata);
-       bf5xx_ad193x_snd_devdata.dev = &bfxx_ad193x_snd_device->dev;
+       platform_set_drvdata(bfxx_ad193x_snd_device, &bf5xx_ad193x);
        ret = platform_device_add(bfxx_ad193x_snd_device);
 
        if (ret)
index 92f7c327bb7a371c93d4298e6541fb9bc31b925f..d57c9c9c9883207039174b71cdfa490b64109dfa 100644 (file)
@@ -56,10 +56,10 @@ static struct snd_soc_card bf5xx_board;
 static int bf5xx_board_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
        pr_debug("%s enter\n", __func__);
-       cpu_dai->private_data = sport_handle;
+       snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
        return 0;
 }
 
@@ -70,23 +70,19 @@ static struct snd_soc_ops bf5xx_board_ops = {
 static struct snd_soc_dai_link bf5xx_board_dai = {
        .name = "AC97",
        .stream_name = "AC97 HiFi",
-       .cpu_dai = &bfin_ac97_dai,
-       .codec_dai = &ad1980_dai,
+       .cpu_dai_name = "bfin-ac97",
+       .codec_dai_name = "ad1980-hifi",
+       .platform_name = "bfin-pcm-audio",
+       .codec_name = "ad1980-codec",
        .ops = &bf5xx_board_ops,
 };
 
 static struct snd_soc_card bf5xx_board = {
        .name = "bf5xx-board",
-       .platform = &bf5xx_ac97_soc_platform,
        .dai_link = &bf5xx_board_dai,
        .num_links = 1,
 };
 
-static struct snd_soc_device bf5xx_board_snd_devdata = {
-       .card = &bf5xx_board,
-       .codec_dev = &soc_codec_dev_ad1980,
-};
-
 static struct platform_device *bf5xx_board_snd_device;
 
 static int __init bf5xx_board_init(void)
@@ -97,8 +93,7 @@ static int __init bf5xx_board_init(void)
        if (!bf5xx_board_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board_snd_devdata);
-       bf5xx_board_snd_devdata.dev = &bf5xx_board_snd_device->dev;
+       platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board);
        ret = platform_device_add(bf5xx_board_snd_device);
 
        if (ret)
index 9825b71d0e28a3a7002ab690afcc867efaaf7123..900ced54ac79bee6290e917f99faba5c71f1cb7d 100644 (file)
@@ -47,7 +47,6 @@
 #include "../codecs/ad73311.h"
 #include "bf5xx-sport.h"
 #include "bf5xx-i2s-pcm.h"
-#include "bf5xx-i2s.h"
 
 #if CONFIG_SND_BF5XX_SPORT_NUM == 0
 #define bfin_write_SPORT_TCR1  bfin_write_SPORT0_TCR1
@@ -150,10 +149,10 @@ static int bf5xx_probe(struct platform_device *pdev)
 static int bf5xx_ad73311_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
        pr_debug("%s enter\n", __func__);
-       cpu_dai->private_data = sport_handle;
+       snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
        return 0;
 }
 
@@ -161,7 +160,7 @@ static int bf5xx_ad73311_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->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret = 0;
 
        pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
@@ -185,24 +184,20 @@ static struct snd_soc_ops bf5xx_ad73311_ops = {
 static struct snd_soc_dai_link bf5xx_ad73311_dai = {
        .name = "ad73311",
        .stream_name = "AD73311",
-       .cpu_dai = &bf5xx_i2s_dai,
-       .codec_dai = &ad73311_dai,
+       .cpu_dai_name = "bf5xx-i2s",
+       .codec_dai_name = "ad73311-hifi",
+       .platform_name = "bfin-pcm-audio",
+       .codec_name = "ad73311-codec",
        .ops = &bf5xx_ad73311_ops,
 };
 
 static struct snd_soc_card bf5xx_ad73311 = {
        .name = "bf5xx_ad73311",
-       .platform = &bf5xx_i2s_soc_platform,
        .probe = bf5xx_probe,
        .dai_link = &bf5xx_ad73311_dai,
        .num_links = 1,
 };
 
-static struct snd_soc_device bf5xx_ad73311_snd_devdata = {
-       .card = &bf5xx_ad73311,
-       .codec_dev = &soc_codec_dev_ad73311,
-};
-
 static struct platform_device *bf5xx_ad73311_snd_device;
 
 static int __init bf5xx_ad73311_init(void)
@@ -214,8 +209,7 @@ static int __init bf5xx_ad73311_init(void)
        if (!bf5xx_ad73311_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311_snd_devdata);
-       bf5xx_ad73311_snd_devdata.dev = &bf5xx_ad73311_snd_device->dev;
+       platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311);
        ret = platform_device_add(bf5xx_ad73311_snd_device);
 
        if (ret)
index 1d2a1adf25759070cfa96a3cab81c89c31630b30..890a0dccf902a4fc14922cd11565406df86ec0b7 100644 (file)
@@ -40,7 +40,6 @@
 #include <asm/dma.h>
 
 #include "bf5xx-i2s-pcm.h"
-#include "bf5xx-i2s.h"
 #include "bf5xx-sport.h"
 
 static void bf5xx_dma_irq(void *data)
@@ -257,14 +256,14 @@ int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -274,25 +273,44 @@ int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai,
        return ret;
 }
 
-struct snd_soc_platform bf5xx_i2s_soc_platform = {
-       .name           = "bf5xx-audio",
-       .pcm_ops        = &bf5xx_pcm_i2s_ops,
+static struct snd_soc_platform_driver bf5xx_i2s_soc_platform = {
+       .ops            = &bf5xx_pcm_i2s_ops,
        .pcm_new        = bf5xx_pcm_i2s_new,
        .pcm_free       = bf5xx_pcm_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(bf5xx_i2s_soc_platform);
 
-static int __init bfin_i2s_init(void)
+static int __devinit bfin_i2s_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&bf5xx_i2s_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &bf5xx_i2s_soc_platform);
 }
-module_init(bfin_i2s_init);
 
-static void __exit bfin_i2s_exit(void)
+static int __devexit bfin_i2s_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&bf5xx_i2s_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver bfin_i2s_pcm_driver = {
+       .driver = {
+                       .name = "bfin-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = bfin_i2s_soc_platform_probe,
+       .remove = __devexit_p(bfin_i2s_soc_platform_remove),
+};
+
+static int __init snd_bfin_i2s_pcm_init(void)
+{
+       return platform_driver_register(&bfin_i2s_pcm_driver);
+}
+module_init(snd_bfin_i2s_pcm_init);
+
+static void __exit snd_bfin_i2s_pcm_exit(void)
+{
+       platform_driver_unregister(&bfin_i2s_pcm_driver);
 }
-module_exit(bfin_i2s_exit);
+module_exit(snd_bfin_i2s_pcm_exit);
 
 MODULE_AUTHOR("Cliff Cai");
 MODULE_DESCRIPTION("ADI Blackfin I2S PCM DMA module");
index 4d4609a97c598df1a8ec0dddd2a7d76618b41f3a..0c2c5a68d4fff43bc2438749bceb7c5bc1b32148 100644 (file)
@@ -23,7 +23,4 @@ struct bf5xx_gpio {
        u32 frm;
 };
 
-/* platform data */
-extern struct snd_soc_platform bf5xx_i2s_soc_platform;
-
 #endif
index 3e6ada0dd1c42ef1b07ee144aca320fea9ebeaf5..d453b1e9d607d0d0e9d712bf981a3e6dda4ae17f 100644 (file)
@@ -42,7 +42,6 @@
 #include <linux/gpio.h>
 
 #include "bf5xx-sport.h"
-#include "bf5xx-i2s.h"
 
 struct bf5xx_i2s_port {
        u16 tcr1;
@@ -195,8 +194,7 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
                bf5xx_i2s.configured = 0;
 }
 
-static int bf5xx_i2s_probe(struct platform_device *pdev,
-                          struct snd_soc_dai *dai)
+static int bf5xx_i2s_probe(struct snd_soc_dai *dai)
 {
        pr_debug("%s enter\n", __func__);
        if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
@@ -215,11 +213,11 @@ static int bf5xx_i2s_probe(struct platform_device *pdev,
        return 0;
 }
 
-static void bf5xx_i2s_remove(struct platform_device *pdev,
-                       struct snd_soc_dai *dai)
+static int bf5xx_i2s_remove(struct snd_soc_dai *dai)
 {
        pr_debug("%s enter\n", __func__);
        peripheral_free_list(&sport_req[sport_num][0]);
+       return 0;
 }
 
 #ifdef CONFIG_PM
@@ -228,9 +226,9 @@ static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
 
        pr_debug("%s : sport %d\n", __func__, dai->id);
 
-       if (dai->capture.active)
+       if (dai->capture_active)
                sport_rx_stop(sport_handle);
-       if (dai->playback.active)
+       if (dai->playback_active)
                sport_tx_stop(sport_handle);
        return 0;
 }
@@ -277,9 +275,7 @@ static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
        .set_fmt        = bf5xx_i2s_set_dai_fmt,
 };
 
-struct snd_soc_dai bf5xx_i2s_dai = {
-       .name = "bf5xx-i2s",
-       .id = 0,
+static struct snd_soc_dai_driver bf5xx_i2s_dai = {
        .probe = bf5xx_i2s_probe,
        .remove = bf5xx_i2s_remove,
        .suspend = bf5xx_i2s_suspend,
@@ -296,18 +292,39 @@ struct snd_soc_dai bf5xx_i2s_dai = {
                .formats = BF5XX_I2S_FORMATS,},
        .ops = &bf5xx_i2s_dai_ops,
 };
-EXPORT_SYMBOL_GPL(bf5xx_i2s_dai);
+
+static int bfin_i2s_drv_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
+}
+
+static int __devexit bfin_i2s_drv_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver bfin_i2s_driver = {
+       .probe = bfin_i2s_drv_probe,
+       .remove = __devexit_p(bfin_i2s_drv_remove),
+
+       .driver = {
+               .name = "bf5xx-i2s",
+               .owner = THIS_MODULE,
+       },
+};
 
 static int __init bfin_i2s_init(void)
 {
-       return snd_soc_register_dai(&bf5xx_i2s_dai);
+       return platform_driver_register(&bfin_i2s_driver);
 }
-module_init(bfin_i2s_init);
 
 static void __exit bfin_i2s_exit(void)
 {
-       snd_soc_unregister_dai(&bf5xx_i2s_dai);
+       platform_driver_unregister(&bfin_i2s_driver);
 }
+
+module_init(bfin_i2s_init);
 module_exit(bfin_i2s_exit);
 
 /* Module information */
diff --git a/sound/soc/blackfin/bf5xx-i2s.h b/sound/soc/blackfin/bf5xx-i2s.h
deleted file mode 100644 (file)
index 264ecdc..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * sound/soc/blackfin/bf5xx-i2s.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _BF5XX_I2S_H
-#define _BF5XX_I2S_H
-
-extern struct snd_soc_dai bf5xx_i2s_dai;
-
-#endif
index 3a00fa4dbe6d4202d5e32647a684000335c71e29..36f2769eb912b67c04bb08cb60a28681f7977f29 100644 (file)
 #include "../codecs/ssm2602.h"
 #include "bf5xx-sport.h"
 #include "bf5xx-i2s-pcm.h"
-#include "bf5xx-i2s.h"
 
 static struct snd_soc_card bf5xx_ssm2602;
 
 static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
        pr_debug("%s enter\n", __func__);
-       cpu_dai->private_data = sport_handle;
+       snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
        return 0;
 }
 
@@ -60,8 +59,8 @@ static int bf5xx_ssm2602_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int clk = 0;
        int ret = 0;
 
@@ -118,36 +117,19 @@ static struct snd_soc_ops bf5xx_ssm2602_ops = {
 static struct snd_soc_dai_link bf5xx_ssm2602_dai = {
        .name = "ssm2602",
        .stream_name = "SSM2602",
-       .cpu_dai = &bf5xx_i2s_dai,
-       .codec_dai = &ssm2602_dai,
+       .cpu_dai_name = "bf5xx-i2s",
+       .codec_dai_name = "ssm2602-hifi",
+       .platform_name = "bf5xx-pcm-audio",
+       .codec_name = "ssm2602-codec.0-0x1b",
        .ops = &bf5xx_ssm2602_ops,
 };
 
-/*
- * SSM2602 2 wire address is determined by CSB
- * state during powerup.
- *    low  = 0x1a
- *    high = 0x1b
- */
-
-static struct ssm2602_setup_data bf5xx_ssm2602_setup = {
-       .i2c_bus = 0,
-       .i2c_address = 0x1b,
-};
-
 static struct snd_soc_card bf5xx_ssm2602 = {
        .name = "bf5xx_ssm2602",
-       .platform = &bf5xx_i2s_soc_platform,
        .dai_link = &bf5xx_ssm2602_dai,
        .num_links = 1,
 };
 
-static struct snd_soc_device bf5xx_ssm2602_snd_devdata = {
-       .card = &bf5xx_ssm2602,
-       .codec_dev = &soc_codec_dev_ssm2602,
-       .codec_data = &bf5xx_ssm2602_setup,
-};
-
 static struct platform_device *bf5xx_ssm2602_snd_device;
 
 static int __init bf5xx_ssm2602_init(void)
@@ -159,9 +141,7 @@ static int __init bf5xx_ssm2602_init(void)
        if (!bf5xx_ssm2602_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(bf5xx_ssm2602_snd_device,
-                               &bf5xx_ssm2602_snd_devdata);
-       bf5xx_ssm2602_snd_devdata.dev = &bf5xx_ssm2602_snd_device->dev;
+       platform_set_drvdata(bf5xx_ssm2602_snd_device, &bf5xx_ssm2602);
        ret = platform_device_add(bf5xx_ssm2602_snd_device);
 
        if (ret)
index 6bac1ac1a315b72ee8b9fe134f4b94665a2cb47b..74cf759b78a6ceac0fa2210e25f540e191ed1e08 100644 (file)
@@ -290,14 +290,14 @@ static int bf5xx_pcm_tdm_new(struct snd_card *card, struct snd_soc_dai *dai,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -307,25 +307,44 @@ out:
        return ret;
 }
 
-struct snd_soc_platform bf5xx_tdm_soc_platform = {
-       .name           = "bf5xx-audio",
-       .pcm_ops        = &bf5xx_pcm_tdm_ops,
+static struct snd_soc_platform_driver bf5xx_tdm_soc_platform = {
+       .ops        = &bf5xx_pcm_tdm_ops,
        .pcm_new        = bf5xx_pcm_tdm_new,
        .pcm_free       = bf5xx_pcm_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(bf5xx_tdm_soc_platform);
 
-static int __init bfin_pcm_tdm_init(void)
+static int __devinit bf5xx_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&bf5xx_tdm_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &bf5xx_tdm_soc_platform);
 }
-module_init(bfin_pcm_tdm_init);
 
-static void __exit bfin_pcm_tdm_exit(void)
+static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&bf5xx_tdm_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver bfin_tdm_driver = {
+       .driver = {
+                       .name = "bf5xx-tdm-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = bf5xx_soc_platform_probe,
+       .remove = __devexit_p(bf5xx_soc_platform_remove),
+};
+
+static int __init snd_bfin_tdm_init(void)
+{
+       return platform_driver_register(&bfin_tdm_driver);
+}
+module_init(snd_bfin_tdm_init);
+
+static void __exit snd_bfin_tdm_exit(void)
+{
+       platform_driver_unregister(&bfin_tdm_driver);
 }
-module_exit(bfin_pcm_tdm_exit);
+module_exit(snd_bfin_tdm_exit);
 
 MODULE_AUTHOR("Barry Song");
 MODULE_DESCRIPTION("ADI Blackfin TDM PCM DMA module");
index ddc5047df88c9b00477ec7034884609c3cc9dce6..7f8cc01c447714326e88c126fc850fc87405c382 100644 (file)
@@ -15,7 +15,4 @@ struct bf5xx_pcm_dma_params {
        char *name;                     /* stream identifier */
 };
 
-/* platform data */
-extern struct snd_soc_platform bf5xx_tdm_soc_platform;
-
 #endif
index 24c14269f4bc498601fb920e130b1ff44c5d4028..125123929f16c28d1e52ca01ebde662196f66253 100644 (file)
@@ -214,9 +214,9 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
 
        if (!dai->active)
                return 0;
-       if (dai->capture.active)
+       if (dai->capture_active)
                sport_rx_stop(sport);
-       if (dai->playback.active)
+       if (dai->playback_active)
                sport_tx_stop(sport);
        return 0;
 }
@@ -224,7 +224,7 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
 static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
 {
        int ret;
-       struct sport_device *sport = dai->private_data;
+       struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
        if (!dai->active)
                return 0;
@@ -262,9 +262,7 @@ static struct snd_soc_dai_ops bf5xx_tdm_dai_ops = {
        .set_channel_map   = bf5xx_tdm_set_channel_map,
 };
 
-struct snd_soc_dai bf5xx_tdm_dai = {
-       .name = "bf5xx-tdm",
-       .id = 0,
+static struct snd_soc_dai_driver bf5xx_tdm_dai = {
        .suspend = bf5xx_tdm_suspend,
        .resume = bf5xx_tdm_resume,
        .playback = {
@@ -279,7 +277,6 @@ struct snd_soc_dai bf5xx_tdm_dai = {
                .formats = SNDRV_PCM_FMTBIT_S32_LE,},
        .ops = &bf5xx_tdm_dai_ops,
 };
-EXPORT_SYMBOL_GPL(bf5xx_tdm_dai);
 
 static int __devinit bfin_tdm_probe(struct platform_device *pdev)
 {
@@ -320,7 +317,7 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev)
                goto sport_config_err;
        }
 
-       ret = snd_soc_register_dai(&bf5xx_tdm_dai);
+       ret = snd_soc_register_dai(&pdev->dev, &bf5xx_tdm_dai);
        if (ret) {
                pr_err("Failed to register DAI: %d\n", ret);
                goto sport_config_err;
@@ -337,7 +334,7 @@ sport_config_err:
 static int __devexit bfin_tdm_remove(struct platform_device *pdev)
 {
        peripheral_free_list(&sport_req[sport_num][0]);
-       snd_soc_unregister_dai(&bf5xx_tdm_dai);
+       snd_soc_unregister_dai(&pdev->dev);
 
        return 0;
 }
index 04189a18c1bad941dc0a77d6d66134b7492109a7..e986a3ea3315781afadda87eff824944ae07d78a 100644 (file)
@@ -20,6 +20,4 @@ struct bf5xx_tdm_port {
        int configured;
 };
 
-extern struct snd_soc_dai bf5xx_tdm_dai;
-
 #endif
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
new file mode 100644 (file)
index 0000000..01d19e9
--- /dev/null
@@ -0,0 +1,1486 @@
+/*
+ * 88pm860x-codec.c -- 88PM860x ALSA SoC Audio Driver
+ *
+ * Copyright 2010 Marvell International Ltd.
+ * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/88pm860x.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/tlv.h>
+#include <sound/initval.h>
+#include <sound/jack.h>
+
+#include "88pm860x-codec.h"
+
+#define MAX_NAME_LEN           20
+#define REG_CACHE_SIZE         0x40
+#define REG_CACHE_BASE         0xb0
+
+/* Status Register 1 (0x01) */
+#define REG_STATUS_1           0x01
+#define MIC_STATUS             (1 << 7)
+#define HOOK_STATUS            (1 << 6)
+#define HEADSET_STATUS         (1 << 5)
+
+/* Mic Detection Register (0x37) */
+#define REG_MIC_DET            0x37
+#define CONTINUOUS_POLLING     (3 << 1)
+#define EN_MIC_DET             (1 << 0)
+#define MICDET_MASK            0x07
+
+/* Headset Detection Register (0x38) */
+#define REG_HS_DET             0x38
+#define EN_HS_DET              (1 << 0)
+
+/* Misc2 Register (0x42) */
+#define REG_MISC2              0x42
+#define AUDIO_PLL              (1 << 5)
+#define AUDIO_SECTION_RESET    (1 << 4)
+#define AUDIO_SECTION_ON       (1 << 3)
+
+/* PCM Interface Register 2 (0xb1) */
+#define PCM_INF2_BCLK          (1 << 6)        /* Bit clock polarity */
+#define PCM_INF2_FS            (1 << 5)        /* Frame Sync polarity */
+#define PCM_INF2_MASTER                (1 << 4)        /* Master / Slave */
+#define PCM_INF2_18WL          (1 << 3)        /* 18 / 16 bits */
+#define PCM_GENERAL_I2S                0
+#define PCM_EXACT_I2S          1
+#define PCM_LEFT_I2S           2
+#define PCM_RIGHT_I2S          3
+#define PCM_SHORT_FS           4
+#define PCM_LONG_FS            5
+#define PCM_MODE_MASK          7
+
+/* I2S Interface Register 4 (0xbe) */
+#define I2S_EQU_BYP            (1 << 6)
+
+/* DAC Offset Register (0xcb) */
+#define DAC_MUTE               (1 << 7)
+#define MUTE_LEFT              (1 << 6)
+#define MUTE_RIGHT             (1 << 2)
+
+/* ADC Analog Register 1 (0xd0) */
+#define REG_ADC_ANA_1          0xd0
+#define MIC1BIAS_MASK          0x60
+
+/* Earpiece/Speaker Control Register 2 (0xda) */
+#define REG_EAR2               0xda
+#define RSYNC_CHANGE           (1 << 2)
+
+/* Audio Supplies Register 2 (0xdc) */
+#define REG_SUPPLIES2          0xdc
+#define LDO15_READY            (1 << 4)
+#define LDO15_EN               (1 << 3)
+#define CPUMP_READY            (1 << 2)
+#define CPUMP_EN               (1 << 1)
+#define AUDIO_EN               (1 << 0)
+#define SUPPLY_MASK            (LDO15_EN | CPUMP_EN | AUDIO_EN)
+
+/* Audio Enable Register 1 (0xdd) */
+#define ADC_MOD_RIGHT          (1 << 1)
+#define ADC_MOD_LEFT           (1 << 0)
+
+/* Audio Enable Register 2 (0xde) */
+#define ADC_LEFT               (1 << 5)
+#define ADC_RIGHT              (1 << 4)
+
+/* DAC Enable Register 2 (0xe1) */
+#define DAC_LEFT               (1 << 5)
+#define DAC_RIGHT              (1 << 4)
+#define MODULATOR              (1 << 3)
+
+/* Shorts Register (0xeb) */
+#define REG_SHORTS             0xeb
+#define CLR_SHORT_LO2          (1 << 7)
+#define SHORT_LO2              (1 << 6)
+#define CLR_SHORT_LO1          (1 << 5)
+#define SHORT_LO1              (1 << 4)
+#define CLR_SHORT_HS2          (1 << 3)
+#define SHORT_HS2              (1 << 2)
+#define CLR_SHORT_HS1          (1 << 1)
+#define SHORT_HS1              (1 << 0)
+
+/*
+ * This widget should be just after DAC & PGA in DAPM power-on sequence and
+ * before DAC & PGA in DAPM power-off sequence.
+ */
+#define PM860X_DAPM_OUTPUT(wname, wevent)      \
+{      .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
+       .shift = 0, .invert = 0, .kcontrols = NULL, \
+       .num_kcontrols = 0, .event = wevent, \
+       .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD, }
+
+struct pm860x_det {
+       struct snd_soc_jack     *hp_jack;
+       struct snd_soc_jack     *mic_jack;
+       int                     hp_det;
+       int                     mic_det;
+       int                     hook_det;
+       int                     hs_shrt;
+       int                     lo_shrt;
+};
+
+struct pm860x_priv {
+       unsigned int            sysclk;
+       unsigned int            pcmclk;
+       unsigned int            dir;
+       unsigned int            filter;
+       struct snd_soc_codec    *codec;
+       struct i2c_client       *i2c;
+       struct pm860x_chip      *chip;
+       struct pm860x_det       det;
+
+       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) */
+static const DECLARE_TLV_DB_SCALE(dpga_tlv, -9450, 150, 1);
+
+/* -9dB to 0db in 3dB steps */
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -900, 300, 0);
+
+/* {-23, -17, -13.5, -11, -9, -6, -3, 0}dB */
+static const unsigned int mic_tlv[] = {
+       TLV_DB_RANGE_HEAD(5),
+       0, 0, TLV_DB_SCALE_ITEM(-2300, 0, 0),
+       1, 1, TLV_DB_SCALE_ITEM(-1700, 0, 0),
+       2, 2, TLV_DB_SCALE_ITEM(-1350, 0, 0),
+       3, 3, TLV_DB_SCALE_ITEM(-1100, 0, 0),
+       4, 7, TLV_DB_SCALE_ITEM(-900, 300, 0),
+};
+
+/* {0, 0, 0, -6, 0, 6, 12, 18}dB */
+static const unsigned int aux_tlv[] = {
+       TLV_DB_RANGE_HEAD(2),
+       0, 2, TLV_DB_SCALE_ITEM(0, 0, 0),
+       3, 7, TLV_DB_SCALE_ITEM(-600, 600, 0),
+};
+
+/* {-16, -13, -10, -7, -5.2, -3,3, -2.2, 0}dB, mute instead of -16dB */
+static const unsigned int out_tlv[] = {
+       TLV_DB_RANGE_HEAD(4),
+       0, 3, TLV_DB_SCALE_ITEM(-1600, 300, 1),
+       4, 4, TLV_DB_SCALE_ITEM(-520, 0, 0),
+       5, 5, TLV_DB_SCALE_ITEM(-330, 0, 0),
+       6, 7, TLV_DB_SCALE_ITEM(-220, 220, 0),
+};
+
+static const unsigned int st_tlv[] = {
+       TLV_DB_RANGE_HEAD(8),
+       0, 1, TLV_DB_SCALE_ITEM(-12041, 602, 0),
+       2, 3, TLV_DB_SCALE_ITEM(-11087, 250, 0),
+       4, 5, TLV_DB_SCALE_ITEM(-10643, 158, 0),
+       6, 7, TLV_DB_SCALE_ITEM(-10351, 116, 0),
+       8, 9, TLV_DB_SCALE_ITEM(-10133, 92, 0),
+       10, 13, TLV_DB_SCALE_ITEM(-9958, 70, 0),
+       14, 17, TLV_DB_SCALE_ITEM(-9689, 53, 0),
+       18, 271, TLV_DB_SCALE_ITEM(-9484, 37, 0),
+};
+
+/* Sidetone Gain = M * 2^(-5-N) */
+struct st_gain {
+       unsigned int    db;
+       unsigned int    m;
+       unsigned int    n;
+};
+
+static struct st_gain st_table[] = {
+       {-12041,  1, 15}, {-11439,  1, 14}, {-11087,  3, 15}, {-10837,  1, 13},
+       {-10643,  5, 15}, {-10485,  3, 14}, {-10351,  7, 15}, {-10235,  1, 12},
+       {-10133,  9, 15}, {-10041,  5, 14}, { -9958, 11, 15}, { -9883,  3, 13},
+       { -9813, 13, 15}, { -9749,  7, 14}, { -9689, 15, 15}, { -9633,  1, 11},
+       { -9580, 17, 15}, { -9531,  9, 14}, { -9484, 19, 15}, { -9439,  5, 13},
+       { -9397, 21, 15}, { -9356, 11, 14}, { -9318, 23, 15}, { -9281,  3, 12},
+       { -9245, 25, 15}, { -9211, 13, 14}, { -9178, 27, 15}, { -9147,  7, 13},
+       { -9116, 29, 15}, { -9087, 15, 14}, { -9058, 31, 15}, { -9031,  1, 10},
+       { -8978, 17, 14}, { -8929,  9, 13}, { -8882, 19, 14}, { -8837,  5, 12},
+       { -8795, 21, 14}, { -8754, 11, 13}, { -8716, 23, 14}, { -8679,  3, 11},
+       { -8643, 25, 14}, { -8609, 13, 13}, { -8576, 27, 14}, { -8545,  7, 12},
+       { -8514, 29, 14}, { -8485, 15, 13}, { -8456, 31, 14}, { -8429,  1,  9},
+       { -8376, 17, 13}, { -8327,  9, 12}, { -8280, 19, 13}, { -8235,  5, 11},
+       { -8193, 21, 13}, { -8152, 11, 12}, { -8114, 23, 13}, { -8077,  3, 10},
+       { -8041, 25, 13}, { -8007, 13, 12}, { -7974, 27, 13}, { -7943,  7, 11},
+       { -7912, 29, 13}, { -7883, 15, 12}, { -7854, 31, 13}, { -7827,  1,  8},
+       { -7774, 17, 12}, { -7724,  9, 11}, { -7678, 19, 12}, { -7633,  5, 10},
+       { -7591, 21, 12}, { -7550, 11, 11}, { -7512, 23, 12}, { -7475,  3,  9},
+       { -7439, 25, 12}, { -7405, 13, 11}, { -7372, 27, 12}, { -7341,  7, 10},
+       { -7310, 29, 12}, { -7281, 15, 11}, { -7252, 31, 12}, { -7225,  1,  7},
+       { -7172, 17, 11}, { -7122,  9, 10}, { -7075, 19, 11}, { -7031,  5,  9},
+       { -6989, 21, 11}, { -6948, 11, 10}, { -6910, 23, 11}, { -6873,  3,  8},
+       { -6837, 25, 11}, { -6803, 13, 10}, { -6770, 27, 11}, { -6739,  7,  9},
+       { -6708, 29, 11}, { -6679, 15, 10}, { -6650, 31, 11}, { -6623,  1,  6},
+       { -6570, 17, 10}, { -6520,  9,  9}, { -6473, 19, 10}, { -6429,  5,  8},
+       { -6386, 21, 10}, { -6346, 11,  9}, { -6307, 23, 10}, { -6270,  3,  7},
+       { -6235, 25, 10}, { -6201, 13,  9}, { -6168, 27, 10}, { -6137,  7,  8},
+       { -6106, 29, 10}, { -6077, 15,  9}, { -6048, 31, 10}, { -6021,  1,  5},
+       { -5968, 17,  9}, { -5918,  9,  8}, { -5871, 19,  9}, { -5827,  5,  7},
+       { -5784, 21,  9}, { -5744, 11,  8}, { -5705, 23,  9}, { -5668,  3,  6},
+       { -5633, 25,  9}, { -5599, 13,  8}, { -5566, 27,  9}, { -5535,  7,  7},
+       { -5504, 29,  9}, { -5475, 15,  8}, { -5446, 31,  9}, { -5419,  1,  4},
+       { -5366, 17,  8}, { -5316,  9,  7}, { -5269, 19,  8}, { -5225,  5,  6},
+       { -5182, 21,  8}, { -5142, 11,  7}, { -5103, 23,  8}, { -5066,  3,  5},
+       { -5031, 25,  8}, { -4997, 13,  7}, { -4964, 27,  8}, { -4932,  7,  6},
+       { -4902, 29,  8}, { -4873, 15,  7}, { -4844, 31,  8}, { -4816,  1,  3},
+       { -4764, 17,  7}, { -4714,  9,  6}, { -4667, 19,  7}, { -4623,  5,  5},
+       { -4580, 21,  7}, { -4540, 11,  6}, { -4501, 23,  7}, { -4464,  3,  4},
+       { -4429, 25,  7}, { -4395, 13,  6}, { -4362, 27,  7}, { -4330,  7,  5},
+       { -4300, 29,  7}, { -4270, 15,  6}, { -4242, 31,  7}, { -4214,  1,  2},
+       { -4162, 17,  6}, { -4112,  9,  5}, { -4065, 19,  6}, { -4021,  5,  4},
+       { -3978, 21,  6}, { -3938, 11,  5}, { -3899, 23,  6}, { -3862,  3,  3},
+       { -3827, 25,  6}, { -3793, 13,  5}, { -3760, 27,  6}, { -3728,  7,  4},
+       { -3698, 29,  6}, { -3668, 15,  5}, { -3640, 31,  6}, { -3612,  1,  1},
+       { -3560, 17,  5}, { -3510,  9,  4}, { -3463, 19,  5}, { -3419,  5,  3},
+       { -3376, 21,  5}, { -3336, 11,  4}, { -3297, 23,  5}, { -3260,  3,  2},
+       { -3225, 25,  5}, { -3191, 13,  4}, { -3158, 27,  5}, { -3126,  7,  3},
+       { -3096, 29,  5}, { -3066, 15,  4}, { -3038, 31,  5}, { -3010,  1,  0},
+       { -2958, 17,  4}, { -2908,  9,  3}, { -2861, 19,  4}, { -2816,  5,  2},
+       { -2774, 21,  4}, { -2734, 11,  3}, { -2695, 23,  4}, { -2658,  3,  1},
+       { -2623, 25,  4}, { -2589, 13,  3}, { -2556, 27,  4}, { -2524,  7,  2},
+       { -2494, 29,  4}, { -2464, 15,  3}, { -2436, 31,  4}, { -2408,  2,  0},
+       { -2356, 17,  3}, { -2306,  9,  2}, { -2259, 19,  3}, { -2214,  5,  1},
+       { -2172, 21,  3}, { -2132, 11,  2}, { -2093, 23,  3}, { -2056,  3,  0},
+       { -2021, 25,  3}, { -1987, 13,  2}, { -1954, 27,  3}, { -1922,  7,  1},
+       { -1892, 29,  3}, { -1862, 15,  2}, { -1834, 31,  3}, { -1806,  4,  0},
+       { -1754, 17,  2}, { -1704,  9,  1}, { -1657, 19,  2}, { -1612,  5,  0},
+       { -1570, 21,  2}, { -1530, 11,  1}, { -1491, 23,  2}, { -1454,  6,  0},
+       { -1419, 25,  2}, { -1384, 13,  1}, { -1352, 27,  2}, { -1320,  7,  0},
+       { -1290, 29,  2}, { -1260, 15,  1}, { -1232, 31,  2}, { -1204,  8,  0},
+       { -1151, 17,  1}, { -1102,  9,  0}, { -1055, 19,  1}, { -1010, 10,  0},
+       {  -968, 21,  1}, {  -928, 11,  0}, {  -889, 23,  1}, {  -852, 12,  0},
+       {  -816, 25,  1}, {  -782, 13,  0}, {  -750, 27,  1}, {  -718, 14,  0},
+       {  -688, 29,  1}, {  -658, 15,  0}, {  -630, 31,  1}, {  -602, 16,  0},
+       {  -549, 17,  0}, {  -500, 18,  0}, {  -453, 19,  0}, {  -408, 20,  0},
+       {  -366, 21,  0}, {  -325, 22,  0}, {  -287, 23,  0}, {  -250, 24,  0},
+       {  -214, 25,  0}, {  -180, 26,  0}, {  -148, 27,  0}, {  -116, 28,  0},
+       {   -86, 29,  0}, {   -56, 30,  0}, {   -28, 31,  0}, {     0,  0,  0},
+};
+
+static int pm860x_volatile(unsigned int reg)
+{
+       BUG_ON(reg >= REG_CACHE_SIZE);
+
+       switch (reg) {
+       case PM860X_AUDIO_SUPPLIES_2:
+               return 1;
+       }
+
+       return 0;
+}
+
+static unsigned int pm860x_read_reg_cache(struct snd_soc_codec *codec,
+                                         unsigned int reg)
+{
+       unsigned char *cache = codec->reg_cache;
+
+       BUG_ON(reg >= REG_CACHE_SIZE);
+
+       if (pm860x_volatile(reg))
+               return cache[reg];
+
+       reg += REG_CACHE_BASE;
+
+       return pm860x_reg_read(codec->control_data, reg);
+}
+
+static int pm860x_write_reg_cache(struct snd_soc_codec *codec,
+                                 unsigned int reg, unsigned int value)
+{
+       unsigned char *cache = codec->reg_cache;
+
+       BUG_ON(reg >= REG_CACHE_SIZE);
+
+       if (!pm860x_volatile(reg))
+               cache[reg] = (unsigned char)value;
+
+       reg += REG_CACHE_BASE;
+
+       return pm860x_reg_write(codec->control_data, reg, value);
+}
+
+static int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg = mc->reg;
+       unsigned int reg2 = mc->rreg;
+       int val[2], val2[2], i;
+
+       val[0] = snd_soc_read(codec, reg) & 0x3f;
+       val[1] = (snd_soc_read(codec, PM860X_SIDETONE_SHIFT) >> 4) & 0xf;
+       val2[0] = snd_soc_read(codec, reg2) & 0x3f;
+       val2[1] = (snd_soc_read(codec, PM860X_SIDETONE_SHIFT)) & 0xf;
+
+       for (i = 0; i < ARRAY_SIZE(st_table); i++) {
+               if ((st_table[i].m == val[0]) && (st_table[i].n == val[1]))
+                       ucontrol->value.integer.value[0] = i;
+               if ((st_table[i].m == val2[0]) && (st_table[i].n == val2[1]))
+                       ucontrol->value.integer.value[1] = i;
+       }
+       return 0;
+}
+
+static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg = mc->reg;
+       unsigned int reg2 = mc->rreg;
+       int err;
+       unsigned int val, val2;
+
+       val = ucontrol->value.integer.value[0];
+       val2 = ucontrol->value.integer.value[1];
+
+       err = snd_soc_update_bits(codec, reg, 0x3f, st_table[val].m);
+       if (err < 0)
+               return err;
+       err = snd_soc_update_bits(codec, PM860X_SIDETONE_SHIFT, 0xf0,
+                                 st_table[val].n << 4);
+       if (err < 0)
+               return err;
+
+       err = snd_soc_update_bits(codec, reg2, 0x3f, st_table[val2].m);
+       if (err < 0)
+               return err;
+       err = snd_soc_update_bits(codec, PM860X_SIDETONE_SHIFT, 0x0f,
+                                 st_table[val2].n);
+       return err;
+}
+
+static int snd_soc_get_volsw_2r_out(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg = mc->reg;
+       unsigned int reg2 = mc->rreg;
+       unsigned int shift = mc->shift;
+       int max = mc->max, val, val2;
+       unsigned int mask = (1 << fls(max)) - 1;
+
+       val = snd_soc_read(codec, reg) >> shift;
+       val2 = snd_soc_read(codec, reg2) >> shift;
+       ucontrol->value.integer.value[0] = (max - val) & mask;
+       ucontrol->value.integer.value[1] = (max - val2) & mask;
+
+       return 0;
+}
+
+static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg = mc->reg;
+       unsigned int reg2 = mc->rreg;
+       unsigned int shift = mc->shift;
+       int max = mc->max;
+       unsigned int mask = (1 << fls(max)) - 1;
+       int err;
+       unsigned int val, val2, val_mask;
+
+       val_mask = mask << shift;
+       val = ((max - ucontrol->value.integer.value[0]) & mask);
+       val2 = ((max - ucontrol->value.integer.value[1]) & mask);
+
+       val = val << shift;
+       val2 = val2 << shift;
+
+       err = snd_soc_update_bits(codec, reg, val_mask, val);
+       if (err < 0)
+               return err;
+
+       err = snd_soc_update_bits(codec, reg2, val_mask, val2);
+       return err;
+}
+
+/* DAPM Widget Events */
+/*
+ * A lot registers are belong to RSYNC domain. It requires enabling RSYNC bit
+ * after updating these registers. Otherwise, these updated registers won't
+ * be effective.
+ */
+static int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
+                             struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+
+       /*
+        * In order to avoid current on the load, mute power-on and power-off
+        * should be transients.
+        * Unmute by DAC_MUTE. It should be unmuted when DAPM sequence is
+        * finished.
+        */
+       snd_soc_update_bits(codec, PM860X_DAC_OFFSET, DAC_MUTE, 0);
+       snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+                           RSYNC_CHANGE, RSYNC_CHANGE);
+       return 0;
+}
+
+static int pm860x_dac_event(struct snd_soc_dapm_widget *w,
+                           struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       unsigned int dac = 0;
+       int data;
+
+       if (!strcmp(w->name, "Left DAC"))
+               dac = DAC_LEFT;
+       if (!strcmp(w->name, "Right DAC"))
+               dac = DAC_RIGHT;
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (dac) {
+                       /* Auto mute in power-on sequence. */
+                       dac |= MODULATOR;
+                       snd_soc_update_bits(codec, PM860X_DAC_OFFSET,
+                                           DAC_MUTE, DAC_MUTE);
+                       snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+                                           RSYNC_CHANGE, RSYNC_CHANGE);
+                       /* update dac */
+                       snd_soc_update_bits(codec, PM860X_DAC_EN_2,
+                                           dac, dac);
+               }
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               if (dac) {
+                       /* Auto mute in power-off sequence. */
+                       snd_soc_update_bits(codec, PM860X_DAC_OFFSET,
+                                           DAC_MUTE, DAC_MUTE);
+                       snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+                                           RSYNC_CHANGE, RSYNC_CHANGE);
+                       /* update dac */
+                       data = snd_soc_read(codec, PM860X_DAC_EN_2);
+                       data &= ~dac;
+                       if (!(data & (DAC_LEFT | DAC_RIGHT)))
+                               data &= ~MODULATOR;
+                       snd_soc_write(codec, PM860X_DAC_EN_2, data);
+               }
+               break;
+       }
+       return 0;
+}
+
+static const char *pm860x_opamp_texts[] = {"-50%", "-25%", "0%", "75%"};
+
+static const char *pm860x_pa_texts[] = {"-33%", "0%", "33%", "66%"};
+
+static const struct soc_enum pm860x_hs1_opamp_enum =
+       SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 5, 4, pm860x_opamp_texts);
+
+static const struct soc_enum pm860x_hs2_opamp_enum =
+       SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 5, 4, pm860x_opamp_texts);
+
+static const struct soc_enum pm860x_hs1_pa_enum =
+       SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 3, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_hs2_pa_enum =
+       SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 3, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_lo1_opamp_enum =
+       SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 5, 4, pm860x_opamp_texts);
+
+static const struct soc_enum pm860x_lo2_opamp_enum =
+       SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 5, 4, pm860x_opamp_texts);
+
+static const struct soc_enum pm860x_lo1_pa_enum =
+       SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 3, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_lo2_pa_enum =
+       SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 3, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_spk_pa_enum =
+       SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 5, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_ear_pa_enum =
+       SOC_ENUM_SINGLE(PM860X_EAR_CTRL_2, 0, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_spk_ear_opamp_enum =
+       SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 3, 4, pm860x_opamp_texts);
+
+static const struct snd_kcontrol_new pm860x_snd_controls[] = {
+       SOC_DOUBLE_R_TLV("ADC Capture Volume", PM860X_ADC_ANA_2,
+                       PM860X_ADC_ANA_3, 6, 3, 0, adc_tlv),
+       SOC_DOUBLE_TLV("AUX Capture Volume", PM860X_ADC_ANA_3, 0, 3, 7, 0,
+                       aux_tlv),
+       SOC_SINGLE_TLV("MIC1 Capture Volume", PM860X_ADC_ANA_2, 0, 7, 0,
+                       mic_tlv),
+       SOC_SINGLE_TLV("MIC3 Capture Volume", PM860X_ADC_ANA_2, 3, 7, 0,
+                       mic_tlv),
+       SOC_DOUBLE_R_EXT_TLV("Sidetone Volume", PM860X_SIDETONE_L_GAIN,
+                            PM860X_SIDETONE_R_GAIN, 0, ARRAY_SIZE(st_table)-1,
+                            0, snd_soc_get_volsw_2r_st,
+                            snd_soc_put_volsw_2r_st, st_tlv),
+       SOC_SINGLE_TLV("Speaker Playback Volume", PM860X_EAR_CTRL_1,
+                       0, 7, 0, out_tlv),
+       SOC_DOUBLE_R_TLV("Line Playback Volume", PM860X_LO1_CTRL,
+                        PM860X_LO2_CTRL, 0, 7, 0, out_tlv),
+       SOC_DOUBLE_R_TLV("Headset Playback Volume", PM860X_HS1_CTRL,
+                        PM860X_HS2_CTRL, 0, 7, 0, out_tlv),
+       SOC_DOUBLE_R_EXT_TLV("Hifi Left Playback Volume",
+                            PM860X_HIFIL_GAIN_LEFT,
+                            PM860X_HIFIL_GAIN_RIGHT, 0, 63, 0,
+                            snd_soc_get_volsw_2r_out,
+                            snd_soc_put_volsw_2r_out, dpga_tlv),
+       SOC_DOUBLE_R_EXT_TLV("Hifi Right Playback Volume",
+                            PM860X_HIFIR_GAIN_LEFT,
+                            PM860X_HIFIR_GAIN_RIGHT, 0, 63, 0,
+                            snd_soc_get_volsw_2r_out,
+                            snd_soc_put_volsw_2r_out, dpga_tlv),
+       SOC_DOUBLE_R_EXT_TLV("Lofi Playback Volume", PM860X_LOFI_GAIN_LEFT,
+                            PM860X_LOFI_GAIN_RIGHT, 0, 63, 0,
+                            snd_soc_get_volsw_2r_out,
+                            snd_soc_put_volsw_2r_out, dpga_tlv),
+       SOC_ENUM("Headset1 Operational Amplifier Current",
+                pm860x_hs1_opamp_enum),
+       SOC_ENUM("Headset2 Operational Amplifier Current",
+                pm860x_hs2_opamp_enum),
+       SOC_ENUM("Headset1 Amplifier Current", pm860x_hs1_pa_enum),
+       SOC_ENUM("Headset2 Amplifier Current", pm860x_hs2_pa_enum),
+       SOC_ENUM("Lineout1 Operational Amplifier Current",
+                pm860x_lo1_opamp_enum),
+       SOC_ENUM("Lineout2 Operational Amplifier Current",
+                pm860x_lo2_opamp_enum),
+       SOC_ENUM("Lineout1 Amplifier Current", pm860x_lo1_pa_enum),
+       SOC_ENUM("Lineout2 Amplifier Current", pm860x_lo2_pa_enum),
+       SOC_ENUM("Speaker Operational Amplifier Current",
+                pm860x_spk_ear_opamp_enum),
+       SOC_ENUM("Speaker Amplifier Current", pm860x_spk_pa_enum),
+       SOC_ENUM("Earpiece Amplifier Current", pm860x_ear_pa_enum),
+};
+
+/*
+ * DAPM Controls
+ */
+
+/* PCM Switch / PCM Interface */
+static const struct snd_kcontrol_new pcm_switch_controls =
+       SOC_DAPM_SINGLE("Switch", PM860X_ADC_EN_2, 0, 1, 0);
+
+/* AUX1 Switch */
+static const struct snd_kcontrol_new aux1_switch_controls =
+       SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 4, 1, 0);
+
+/* AUX2 Switch */
+static const struct snd_kcontrol_new aux2_switch_controls =
+       SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 5, 1, 0);
+
+/* Left Ex. PA Switch */
+static const struct snd_kcontrol_new lepa_switch_controls =
+       SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 2, 1, 0);
+
+/* Right Ex. PA Switch */
+static const struct snd_kcontrol_new repa_switch_controls =
+       SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 1, 1, 0);
+
+/* PCM Mux / Mux7 */
+static const char *aif1_text[] = {
+       "PCM L", "PCM R",
+};
+
+static const struct soc_enum aif1_enum =
+       SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 6, 2, aif1_text);
+
+static const struct snd_kcontrol_new aif1_mux =
+       SOC_DAPM_ENUM("PCM Mux", aif1_enum);
+
+/* I2S Mux / Mux9 */
+static const char *i2s_din_text[] = {
+       "DIN", "DIN1",
+};
+
+static const struct soc_enum i2s_din_enum =
+       SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 1, 2, i2s_din_text);
+
+static const struct snd_kcontrol_new i2s_din_mux =
+       SOC_DAPM_ENUM("I2S DIN Mux", i2s_din_enum);
+
+/* I2S Mic Mux / Mux8 */
+static const char *i2s_mic_text[] = {
+       "Ex PA", "ADC",
+};
+
+static const struct soc_enum i2s_mic_enum =
+       SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 4, 2, i2s_mic_text);
+
+static const struct snd_kcontrol_new i2s_mic_mux =
+       SOC_DAPM_ENUM("I2S Mic Mux", i2s_mic_enum);
+
+/* ADCL Mux / Mux2 */
+static const char *adcl_text[] = {
+       "ADCR", "ADCL",
+};
+
+static const struct soc_enum adcl_enum =
+       SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 4, 2, adcl_text);
+
+static const struct snd_kcontrol_new adcl_mux =
+       SOC_DAPM_ENUM("ADC Left Mux", adcl_enum);
+
+/* ADCR Mux / Mux3 */
+static const char *adcr_text[] = {
+       "ADCL", "ADCR",
+};
+
+static const struct soc_enum adcr_enum =
+       SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 2, 2, adcr_text);
+
+static const struct snd_kcontrol_new adcr_mux =
+       SOC_DAPM_ENUM("ADC Right Mux", adcr_enum);
+
+/* ADCR EC Mux / Mux6 */
+static const char *adcr_ec_text[] = {
+       "ADCR", "EC",
+};
+
+static const struct soc_enum adcr_ec_enum =
+       SOC_ENUM_SINGLE(PM860X_ADC_EN_2, 3, 2, adcr_ec_text);
+
+static const struct snd_kcontrol_new adcr_ec_mux =
+       SOC_DAPM_ENUM("ADCR EC Mux", adcr_ec_enum);
+
+/* EC Mux / Mux4 */
+static const char *ec_text[] = {
+       "Left", "Right", "Left + Right",
+};
+
+static const struct soc_enum ec_enum =
+       SOC_ENUM_SINGLE(PM860X_EC_PATH, 1, 3, ec_text);
+
+static const struct snd_kcontrol_new ec_mux =
+       SOC_DAPM_ENUM("EC Mux", ec_enum);
+
+static const char *dac_text[] = {
+       "No input", "Right", "Left", "No input",
+};
+
+/* DAC Headset 1 Mux / Mux10 */
+static const struct soc_enum dac_hs1_enum =
+       SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 0, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_hs1_mux =
+       SOC_DAPM_ENUM("DAC HS1 Mux", dac_hs1_enum);
+
+/* DAC Headset 2 Mux / Mux11 */
+static const struct soc_enum dac_hs2_enum =
+       SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 2, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_hs2_mux =
+       SOC_DAPM_ENUM("DAC HS2 Mux", dac_hs2_enum);
+
+/* DAC Lineout 1 Mux / Mux12 */
+static const struct soc_enum dac_lo1_enum =
+       SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 4, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_lo1_mux =
+       SOC_DAPM_ENUM("DAC LO1 Mux", dac_lo1_enum);
+
+/* DAC Lineout 2 Mux / Mux13 */
+static const struct soc_enum dac_lo2_enum =
+       SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 6, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_lo2_mux =
+       SOC_DAPM_ENUM("DAC LO2 Mux", dac_lo2_enum);
+
+/* DAC Spearker Earphone Mux / Mux14 */
+static const struct soc_enum dac_spk_ear_enum =
+       SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_2, 0, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_spk_ear_mux =
+       SOC_DAPM_ENUM("DAC SP Mux", dac_spk_ear_enum);
+
+/* Headset 1 Mux / Mux15 */
+static const char *in_text[] = {
+       "Digital", "Analog",
+};
+
+static const struct soc_enum hs1_enum =
+       SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 0, 2, in_text);
+
+static const struct snd_kcontrol_new hs1_mux =
+       SOC_DAPM_ENUM("Headset1 Mux", hs1_enum);
+
+/* Headset 2 Mux / Mux16 */
+static const struct soc_enum hs2_enum =
+       SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 1, 2, in_text);
+
+static const struct snd_kcontrol_new hs2_mux =
+       SOC_DAPM_ENUM("Headset2 Mux", hs2_enum);
+
+/* Lineout 1 Mux / Mux17 */
+static const struct soc_enum lo1_enum =
+       SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 2, 2, in_text);
+
+static const struct snd_kcontrol_new lo1_mux =
+       SOC_DAPM_ENUM("Lineout1 Mux", lo1_enum);
+
+/* Lineout 2 Mux / Mux18 */
+static const struct soc_enum lo2_enum =
+       SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 3, 2, in_text);
+
+static const struct snd_kcontrol_new lo2_mux =
+       SOC_DAPM_ENUM("Lineout2 Mux", lo2_enum);
+
+/* Speaker Earpiece Demux */
+static const char *spk_text[] = {
+       "Earpiece", "Speaker",
+};
+
+static const struct soc_enum spk_enum =
+       SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 6, 2, spk_text);
+
+static const struct snd_kcontrol_new spk_demux =
+       SOC_DAPM_ENUM("Speaker Earpiece Demux", spk_enum);
+
+/* MIC Mux / Mux1 */
+static const char *mic_text[] = {
+       "Mic 1", "Mic 2",
+};
+
+static const struct soc_enum mic_enum =
+       SOC_ENUM_SINGLE(PM860X_ADC_ANA_4, 4, 2, mic_text);
+
+static const struct snd_kcontrol_new mic_mux =
+       SOC_DAPM_ENUM("MIC Mux", mic_enum);
+
+static const struct snd_soc_dapm_widget pm860x_dapm_widgets[] = {
+       SND_SOC_DAPM_AIF_IN("PCM SDI", "PCM Playback", 0,
+                           PM860X_ADC_EN_2, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("PCM SDO", "PCM Capture", 0,
+                            PM860X_PCM_IFACE_3, 1, 1),
+
+
+       SND_SOC_DAPM_AIF_IN("I2S DIN", "I2S Playback", 0,
+                           PM860X_DAC_EN_2, 0, 0),
+       SND_SOC_DAPM_AIF_IN("I2S DIN1", "I2S Playback", 0,
+                           PM860X_DAC_EN_2, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("I2S DOUT", "I2S Capture", 0,
+                            PM860X_I2S_IFACE_3, 5, 1),
+       SND_SOC_DAPM_MUX("I2S Mic Mux", SND_SOC_NOPM, 0, 0, &i2s_mic_mux),
+       SND_SOC_DAPM_MUX("ADC Left Mux", SND_SOC_NOPM, 0, 0, &adcl_mux),
+       SND_SOC_DAPM_MUX("ADC Right Mux", SND_SOC_NOPM, 0, 0, &adcr_mux),
+       SND_SOC_DAPM_MUX("EC Mux", SND_SOC_NOPM, 0, 0, &ec_mux),
+       SND_SOC_DAPM_MUX("ADCR EC Mux", SND_SOC_NOPM, 0, 0, &adcr_ec_mux),
+       SND_SOC_DAPM_SWITCH("Left EPA", SND_SOC_NOPM, 0, 0,
+                           &lepa_switch_controls),
+       SND_SOC_DAPM_SWITCH("Right EPA", SND_SOC_NOPM, 0, 0,
+                           &repa_switch_controls),
+
+       SND_SOC_DAPM_REG(snd_soc_dapm_supply, "Left ADC MOD", PM860X_ADC_EN_1,
+                        0, 1, 1, 0),
+       SND_SOC_DAPM_REG(snd_soc_dapm_supply, "Right ADC MOD", PM860X_ADC_EN_1,
+                        1, 1, 1, 0),
+       SND_SOC_DAPM_ADC("Left ADC", NULL, PM860X_ADC_EN_2, 5, 0),
+       SND_SOC_DAPM_ADC("Right ADC", NULL, PM860X_ADC_EN_2, 4, 0),
+
+       SND_SOC_DAPM_SWITCH("AUX1 Switch", SND_SOC_NOPM, 0, 0,
+                           &aux1_switch_controls),
+       SND_SOC_DAPM_SWITCH("AUX2 Switch", SND_SOC_NOPM, 0, 0,
+                           &aux2_switch_controls),
+
+       SND_SOC_DAPM_MUX("MIC Mux", SND_SOC_NOPM, 0, 0, &mic_mux),
+       SND_SOC_DAPM_MICBIAS("Mic1 Bias", PM860X_ADC_ANA_1, 2, 0),
+       SND_SOC_DAPM_MICBIAS("Mic3 Bias", PM860X_ADC_ANA_1, 7, 0),
+       SND_SOC_DAPM_PGA("MIC1 Volume", PM860X_ADC_EN_1, 2, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("MIC3 Volume", PM860X_ADC_EN_1, 3, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("AUX1 Volume", PM860X_ADC_EN_1, 4, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("AUX2 Volume", PM860X_ADC_EN_1, 5, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Sidetone PGA", PM860X_ADC_EN_2, 1, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Lofi PGA", PM860X_ADC_EN_2, 2, 0, NULL, 0),
+
+       SND_SOC_DAPM_INPUT("AUX1"),
+       SND_SOC_DAPM_INPUT("AUX2"),
+       SND_SOC_DAPM_INPUT("MIC1P"),
+       SND_SOC_DAPM_INPUT("MIC1N"),
+       SND_SOC_DAPM_INPUT("MIC2P"),
+       SND_SOC_DAPM_INPUT("MIC2N"),
+       SND_SOC_DAPM_INPUT("MIC3P"),
+       SND_SOC_DAPM_INPUT("MIC3N"),
+
+       SND_SOC_DAPM_DAC_E("Left DAC", NULL, SND_SOC_NOPM, 0, 0,
+                          pm860x_dac_event,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+       SND_SOC_DAPM_DAC_E("Right DAC", NULL, SND_SOC_NOPM, 0, 0,
+                          pm860x_dac_event,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+       SND_SOC_DAPM_MUX("I2S DIN Mux", SND_SOC_NOPM, 0, 0, &i2s_din_mux),
+       SND_SOC_DAPM_MUX("DAC HS1 Mux", SND_SOC_NOPM, 0, 0, &dac_hs1_mux),
+       SND_SOC_DAPM_MUX("DAC HS2 Mux", SND_SOC_NOPM, 0, 0, &dac_hs2_mux),
+       SND_SOC_DAPM_MUX("DAC LO1 Mux", SND_SOC_NOPM, 0, 0, &dac_lo1_mux),
+       SND_SOC_DAPM_MUX("DAC LO2 Mux", SND_SOC_NOPM, 0, 0, &dac_lo2_mux),
+       SND_SOC_DAPM_MUX("DAC SP Mux", SND_SOC_NOPM, 0, 0, &dac_spk_ear_mux),
+       SND_SOC_DAPM_MUX("Headset1 Mux", SND_SOC_NOPM, 0, 0, &hs1_mux),
+       SND_SOC_DAPM_MUX("Headset2 Mux", SND_SOC_NOPM, 0, 0, &hs2_mux),
+       SND_SOC_DAPM_MUX("Lineout1 Mux", SND_SOC_NOPM, 0, 0, &lo1_mux),
+       SND_SOC_DAPM_MUX("Lineout2 Mux", SND_SOC_NOPM, 0, 0, &lo2_mux),
+       SND_SOC_DAPM_MUX("Speaker Earpiece Demux", SND_SOC_NOPM, 0, 0,
+                        &spk_demux),
+
+
+       SND_SOC_DAPM_PGA("Headset1 PGA", PM860X_DAC_EN_1, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Headset2 PGA", PM860X_DAC_EN_1, 1, 0, NULL, 0),
+       SND_SOC_DAPM_OUTPUT("HS1"),
+       SND_SOC_DAPM_OUTPUT("HS2"),
+       SND_SOC_DAPM_PGA("Lineout1 PGA", PM860X_DAC_EN_1, 2, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Lineout2 PGA", PM860X_DAC_EN_1, 3, 0, NULL, 0),
+       SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+       SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+       SND_SOC_DAPM_PGA("Earpiece PGA", PM860X_DAC_EN_1, 4, 0, NULL, 0),
+       SND_SOC_DAPM_OUTPUT("EARP"),
+       SND_SOC_DAPM_OUTPUT("EARN"),
+       SND_SOC_DAPM_PGA("Speaker PGA", PM860X_DAC_EN_1, 5, 0, NULL, 0),
+       SND_SOC_DAPM_OUTPUT("LSP"),
+       SND_SOC_DAPM_OUTPUT("LSN"),
+       SND_SOC_DAPM_REG(snd_soc_dapm_supply, "VCODEC", PM860X_AUDIO_SUPPLIES_2,
+                        0, SUPPLY_MASK, SUPPLY_MASK, 0),
+
+       PM860X_DAPM_OUTPUT("RSYNC", pm860x_rsync_event),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* supply */
+       {"Left DAC", NULL, "VCODEC"},
+       {"Right DAC", NULL, "VCODEC"},
+       {"Left ADC", NULL, "VCODEC"},
+       {"Right ADC", NULL, "VCODEC"},
+       {"Left ADC", NULL, "Left ADC MOD"},
+       {"Right ADC", NULL, "Right ADC MOD"},
+
+       /* PCM/AIF1 Inputs */
+       {"PCM SDO", NULL, "ADC Left Mux"},
+       {"PCM SDO", NULL, "ADCR EC Mux"},
+
+       /* PCM/AFI2 Outputs */
+       {"Lofi PGA", NULL, "PCM SDI"},
+       {"Lofi PGA", NULL, "Sidetone PGA"},
+       {"Left DAC", NULL, "Lofi PGA"},
+       {"Right DAC", NULL, "Lofi PGA"},
+
+       /* I2S/AIF2 Inputs */
+       {"MIC Mux", "Mic 1", "MIC1P"},
+       {"MIC Mux", "Mic 1", "MIC1N"},
+       {"MIC Mux", "Mic 2", "MIC2P"},
+       {"MIC Mux", "Mic 2", "MIC2N"},
+       {"MIC1 Volume", NULL, "MIC Mux"},
+       {"MIC3 Volume", NULL, "MIC3P"},
+       {"MIC3 Volume", NULL, "MIC3N"},
+       {"Left ADC", NULL, "MIC1 Volume"},
+       {"Right ADC", NULL, "MIC3 Volume"},
+       {"ADC Left Mux", "ADCR", "Right ADC"},
+       {"ADC Left Mux", "ADCL", "Left ADC"},
+       {"ADC Right Mux", "ADCL", "Left ADC"},
+       {"ADC Right Mux", "ADCR", "Right ADC"},
+       {"Left EPA", "Switch", "Left DAC"},
+       {"Right EPA", "Switch", "Right DAC"},
+       {"EC Mux", "Left", "Left DAC"},
+       {"EC Mux", "Right", "Right DAC"},
+       {"EC Mux", "Left + Right", "Left DAC"},
+       {"EC Mux", "Left + Right", "Right DAC"},
+       {"ADCR EC Mux", "ADCR", "ADC Right Mux"},
+       {"ADCR EC Mux", "EC", "EC Mux"},
+       {"I2S Mic Mux", "Ex PA", "Left EPA"},
+       {"I2S Mic Mux", "Ex PA", "Right EPA"},
+       {"I2S Mic Mux", "ADC", "ADC Left Mux"},
+       {"I2S Mic Mux", "ADC", "ADCR EC Mux"},
+       {"I2S DOUT", NULL, "I2S Mic Mux"},
+
+       /* I2S/AIF2 Outputs */
+       {"I2S DIN Mux", "DIN", "I2S DIN"},
+       {"I2S DIN Mux", "DIN1", "I2S DIN1"},
+       {"Left DAC", NULL, "I2S DIN Mux"},
+       {"Right DAC", NULL, "I2S DIN Mux"},
+       {"DAC HS1 Mux", "Left", "Left DAC"},
+       {"DAC HS1 Mux", "Right", "Right DAC"},
+       {"DAC HS2 Mux", "Left", "Left DAC"},
+       {"DAC HS2 Mux", "Right", "Right DAC"},
+       {"DAC LO1 Mux", "Left", "Left DAC"},
+       {"DAC LO1 Mux", "Right", "Right DAC"},
+       {"DAC LO2 Mux", "Left", "Left DAC"},
+       {"DAC LO2 Mux", "Right", "Right DAC"},
+       {"Headset1 Mux", "Digital", "DAC HS1 Mux"},
+       {"Headset2 Mux", "Digital", "DAC HS2 Mux"},
+       {"Lineout1 Mux", "Digital", "DAC LO1 Mux"},
+       {"Lineout2 Mux", "Digital", "DAC LO2 Mux"},
+       {"Headset1 PGA", NULL, "Headset1 Mux"},
+       {"Headset2 PGA", NULL, "Headset2 Mux"},
+       {"Lineout1 PGA", NULL, "Lineout1 Mux"},
+       {"Lineout2 PGA", NULL, "Lineout2 Mux"},
+       {"DAC SP Mux", "Left", "Left DAC"},
+       {"DAC SP Mux", "Right", "Right DAC"},
+       {"Speaker Earpiece Demux", "Speaker", "DAC SP Mux"},
+       {"Speaker PGA", NULL, "Speaker Earpiece Demux"},
+       {"Earpiece PGA", NULL, "Speaker Earpiece Demux"},
+
+       {"RSYNC", NULL, "Headset1 PGA"},
+       {"RSYNC", NULL, "Headset2 PGA"},
+       {"RSYNC", NULL, "Lineout1 PGA"},
+       {"RSYNC", NULL, "Lineout2 PGA"},
+       {"RSYNC", NULL, "Speaker PGA"},
+       {"RSYNC", NULL, "Speaker PGA"},
+       {"RSYNC", NULL, "Earpiece PGA"},
+       {"RSYNC", NULL, "Earpiece PGA"},
+
+       {"HS1", NULL, "RSYNC"},
+       {"HS2", NULL, "RSYNC"},
+       {"LINEOUT1", NULL, "RSYNC"},
+       {"LINEOUT2", NULL, "RSYNC"},
+       {"LSP", NULL, "RSYNC"},
+       {"LSN", NULL, "RSYNC"},
+       {"EARP", NULL, "RSYNC"},
+       {"EARN", NULL, "RSYNC"},
+};
+
+/*
+ * Use MUTE_LEFT & MUTE_RIGHT to implement digital mute.
+ * These bits can also be used to mute.
+ */
+static int pm860x_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int data = 0, mask = MUTE_LEFT | MUTE_RIGHT;
+
+       if (mute)
+               data = mask;
+       snd_soc_update_bits(codec, PM860X_DAC_OFFSET, mask, data);
+       snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+                           RSYNC_CHANGE, RSYNC_CHANGE);
+       return 0;
+}
+
+static int pm860x_pcm_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;
+       unsigned char inf = 0, mask = 0;
+
+       /* bit size */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               inf &= ~PCM_INF2_18WL;
+               break;
+       case SNDRV_PCM_FORMAT_S18_3LE:
+               inf |= PCM_INF2_18WL;
+               break;
+       default:
+               return -EINVAL;
+       }
+       mask |= PCM_INF2_18WL;
+       snd_soc_update_bits(codec, PM860X_PCM_IFACE_2, mask, inf);
+
+       /* sample rate */
+       switch (params_rate(params)) {
+       case 8000:
+               inf = 0;
+               break;
+       case 16000:
+               inf = 3;
+               break;
+       case 32000:
+               inf = 6;
+               break;
+       case 48000:
+               inf = 8;
+               break;
+       default:
+               return -EINVAL;
+       }
+       snd_soc_update_bits(codec, PM860X_PCM_RATE, 0x0f, inf);
+
+       return 0;
+}
+
+static int pm860x_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                                 unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+       unsigned char inf = 0, mask = 0;
+       int ret = -EINVAL;
+
+       mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER;
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_CBM_CFS:
+               if (pm860x->dir == PM860X_CLK_DIR_OUT) {
+                       inf |= PCM_INF2_MASTER;
+                       ret = 0;
+               }
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               if (pm860x->dir == PM860X_CLK_DIR_IN) {
+                       inf &= ~PCM_INF2_MASTER;
+                       ret = 0;
+               }
+               break;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               inf |= PCM_EXACT_I2S;
+               ret = 0;
+               break;
+       }
+       mask |= PCM_MODE_MASK;
+       if (ret)
+               return ret;
+       snd_soc_update_bits(codec, PM860X_PCM_IFACE_2, mask, inf);
+       return 0;
+}
+
+static int pm860x_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 pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+
+       if (dir == PM860X_CLK_DIR_OUT)
+               pm860x->dir = PM860X_CLK_DIR_OUT;
+       else {
+               pm860x->dir = PM860X_CLK_DIR_IN;
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int pm860x_i2s_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;
+       unsigned char inf;
+
+       /* bit size */
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               inf = 0;
+               break;
+       case SNDRV_PCM_FORMAT_S18_3LE:
+               inf = PCM_INF2_18WL;
+               break;
+       default:
+               return -EINVAL;
+       }
+       snd_soc_update_bits(codec, PM860X_I2S_IFACE_2, PCM_INF2_18WL, inf);
+
+       /* sample rate */
+       switch (params_rate(params)) {
+       case 8000:
+               inf = 0;
+               break;
+       case 11025:
+               inf = 1;
+               break;
+       case 16000:
+               inf = 3;
+               break;
+       case 22050:
+               inf = 4;
+               break;
+       case 32000:
+               inf = 6;
+               break;
+       case 44100:
+               inf = 7;
+               break;
+       case 48000:
+               inf = 8;
+               break;
+       default:
+               return -EINVAL;
+       }
+       snd_soc_update_bits(codec, PM860X_I2S_IFACE_4, 0xf, inf);
+
+       return 0;
+}
+
+static int pm860x_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                                 unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+       unsigned char inf = 0, mask = 0;
+
+       mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER;
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               if (pm860x->dir == PM860X_CLK_DIR_OUT)
+                       inf |= PCM_INF2_MASTER;
+               else
+                       return -EINVAL;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               if (pm860x->dir == PM860X_CLK_DIR_IN)
+                       inf &= ~PCM_INF2_MASTER;
+               else
+                       return -EINVAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               inf |= PCM_EXACT_I2S;
+               break;
+       default:
+               return -EINVAL;
+       }
+       mask |= PCM_MODE_MASK;
+       snd_soc_update_bits(codec, PM860X_I2S_IFACE_2, mask, inf);
+       return 0;
+}
+
+static int pm860x_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       int data;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       /* Enable Audio PLL & Audio section */
+                       data = AUDIO_PLL | AUDIO_SECTION_RESET
+                               | AUDIO_SECTION_ON;
+                       pm860x_reg_write(codec->control_data, REG_MISC2, data);
+               }
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               data = AUDIO_PLL | AUDIO_SECTION_RESET | AUDIO_SECTION_ON;
+               pm860x_set_bits(codec->control_data, REG_MISC2, data, 0);
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+static struct snd_soc_dai_ops pm860x_pcm_dai_ops = {
+       .digital_mute   = pm860x_digital_mute,
+       .hw_params      = pm860x_pcm_hw_params,
+       .set_fmt        = pm860x_pcm_set_dai_fmt,
+       .set_sysclk     = pm860x_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_ops pm860x_i2s_dai_ops = {
+       .digital_mute   = pm860x_digital_mute,
+       .hw_params      = pm860x_i2s_hw_params,
+       .set_fmt        = pm860x_i2s_set_dai_fmt,
+       .set_sysclk     = pm860x_set_dai_sysclk,
+};
+
+#define PM860X_RATES   (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |   \
+                        SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+
+static struct snd_soc_dai_driver pm860x_dai[] = {
+       {
+               /* DAI PCM */
+               .name   = "88pm860x-pcm",
+               .id     = 1,
+               .playback = {
+                       .stream_name    = "PCM Playback",
+                       .channels_min   = 2,
+                       .channels_max   = 2,
+                       .rates          = PM860X_RATES,
+                       .formats        = SNDRV_PCM_FORMAT_S16_LE | \
+                                         SNDRV_PCM_FORMAT_S18_3LE,
+               },
+               .capture = {
+                       .stream_name    = "PCM Capture",
+                       .channels_min   = 2,
+                       .channels_max   = 2,
+                       .rates          = PM860X_RATES,
+                       .formats        = SNDRV_PCM_FORMAT_S16_LE | \
+                                         SNDRV_PCM_FORMAT_S18_3LE,
+               },
+               .ops    = &pm860x_pcm_dai_ops,
+       }, {
+               /* DAI I2S */
+               .name   = "88pm860x-i2s",
+               .id     = 2,
+               .playback = {
+                       .stream_name    = "I2S Playback",
+                       .channels_min   = 2,
+                       .channels_max   = 2,
+                       .rates          = SNDRV_PCM_RATE_8000_48000,
+                       .formats        = SNDRV_PCM_FORMAT_S16_LE | \
+                                         SNDRV_PCM_FORMAT_S18_3LE,
+               },
+               .capture = {
+                       .stream_name    = "I2S Capture",
+                       .channels_min   = 2,
+                       .channels_max   = 2,
+                       .rates          = SNDRV_PCM_RATE_8000_48000,
+                       .formats        = SNDRV_PCM_FORMAT_S16_LE | \
+                                         SNDRV_PCM_FORMAT_S18_3LE,
+               },
+               .ops    = &pm860x_i2s_dai_ops,
+       },
+};
+
+static irqreturn_t pm860x_codec_handler(int irq, void *data)
+{
+       struct pm860x_priv *pm860x = data;
+       int status, shrt, report = 0, mic_report = 0;
+       int mask;
+
+       status = pm860x_reg_read(pm860x->i2c, REG_STATUS_1);
+       shrt = pm860x_reg_read(pm860x->i2c, REG_SHORTS);
+       mask = pm860x->det.hs_shrt | pm860x->det.hook_det | pm860x->det.lo_shrt
+               | pm860x->det.hp_det;
+
+       if ((pm860x->det.hp_det & SND_JACK_HEADPHONE)
+               && (status & HEADSET_STATUS))
+               report |= SND_JACK_HEADPHONE;
+
+       if ((pm860x->det.mic_det & SND_JACK_MICROPHONE)
+               && (status & MIC_STATUS))
+               mic_report |= SND_JACK_MICROPHONE;
+
+       if (pm860x->det.hs_shrt && (shrt & (SHORT_HS1 | SHORT_HS2)))
+               report |= pm860x->det.hs_shrt;
+
+       if (pm860x->det.hook_det && (status & HOOK_STATUS))
+               report |= pm860x->det.hook_det;
+
+       if (pm860x->det.lo_shrt && (shrt & (SHORT_LO1 | SHORT_LO2)))
+               report |= pm860x->det.lo_shrt;
+
+       if (report)
+               snd_soc_jack_report(pm860x->det.hp_jack, report, mask);
+       if (mic_report)
+               snd_soc_jack_report(pm860x->det.mic_jack, SND_JACK_MICROPHONE,
+                                   SND_JACK_MICROPHONE);
+
+       dev_dbg(pm860x->codec->dev, "headphone report:0x%x, mask:%x\n",
+               report, mask);
+       dev_dbg(pm860x->codec->dev, "microphone report:0x%x\n", mic_report);
+       return IRQ_HANDLED;
+}
+
+int pm860x_hs_jack_detect(struct snd_soc_codec *codec,
+                         struct snd_soc_jack *jack,
+                         int det, int hook, int hs_shrt, int lo_shrt)
+{
+       struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+       int data;
+
+       pm860x->det.hp_jack = jack;
+       pm860x->det.hp_det = det;
+       pm860x->det.hook_det = hook;
+       pm860x->det.hs_shrt = hs_shrt;
+       pm860x->det.lo_shrt = lo_shrt;
+
+       if (det & SND_JACK_HEADPHONE)
+               pm860x_set_bits(codec->control_data, REG_HS_DET,
+                               EN_HS_DET, EN_HS_DET);
+       /* headset short detect */
+       if (hs_shrt) {
+               data = CLR_SHORT_HS2 | CLR_SHORT_HS1;
+               pm860x_set_bits(codec->control_data, REG_SHORTS, data, data);
+       }
+       /* Lineout short detect */
+       if (lo_shrt) {
+               data = CLR_SHORT_LO2 | CLR_SHORT_LO1;
+               pm860x_set_bits(codec->control_data, REG_SHORTS, data, data);
+       }
+
+       /* sync status */
+       pm860x_codec_handler(0, pm860x);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pm860x_hs_jack_detect);
+
+int pm860x_mic_jack_detect(struct snd_soc_codec *codec,
+                          struct snd_soc_jack *jack, int det)
+{
+       struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+
+       pm860x->det.mic_jack = jack;
+       pm860x->det.mic_det = det;
+
+       if (det & SND_JACK_MICROPHONE)
+               pm860x_set_bits(codec->control_data, REG_MIC_DET,
+                               MICDET_MASK, MICDET_MASK);
+
+       /* sync status */
+       pm860x_codec_handler(0, pm860x);
+       return 0;
+}
+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);
+       int i, ret;
+
+       pm860x->codec = codec;
+
+       codec->control_data = pm860x->i2c;
+
+       for (i = 0; i < 4; i++) {
+               ret = request_threaded_irq(pm860x->irq[i], NULL,
+                                          pm860x_codec_handler, IRQF_ONESHOT,
+                                          pm860x->name[i], pm860x);
+               if (ret < 0) {
+                       dev_err(codec->dev, "Failed to request IRQ!\n");
+                       goto out_irq;
+               }
+       }
+
+       pm860x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       ret = pm860x_bulk_read(codec->control_data, REG_CACHE_BASE,
+                              REG_CACHE_SIZE, codec->reg_cache);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to fill register cache: %d\n",
+                       ret);
+               goto out_codec;
+       }
+
+       snd_soc_add_controls(codec, pm860x_snd_controls,
+                            ARRAY_SIZE(pm860x_snd_controls));
+       snd_soc_dapm_new_controls(codec, pm860x_dapm_widgets,
+                                 ARRAY_SIZE(pm860x_dapm_widgets));
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       return 0;
+
+out_codec:
+       i = 3;
+out_irq:
+       for (; i >= 0; i--)
+               free_irq(pm860x->irq[i], pm860x);
+       return -EINVAL;
+}
+
+static int pm860x_remove(struct snd_soc_codec *codec)
+{
+       struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+       int i;
+
+       for (i = 3; i >= 0; i--)
+               free_irq(pm860x->irq[i], pm860x);
+       pm860x_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_pm860x = {
+       .probe          = pm860x_probe,
+       .remove         = pm860x_remove,
+       .read           = pm860x_read_reg_cache,
+       .write          = pm860x_write_reg_cache,
+       .reg_cache_size = REG_CACHE_SIZE,
+       .reg_word_size  = sizeof(u8),
+       .set_bias_level = pm860x_set_bias_level,
+};
+
+static int __devinit pm860x_codec_probe(struct platform_device *pdev)
+{
+       struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct pm860x_priv *pm860x;
+       struct resource *res;
+       int i, ret;
+
+       pm860x = kzalloc(sizeof(struct pm860x_priv), GFP_KERNEL);
+       if (pm860x == NULL)
+               return -ENOMEM;
+
+       pm860x->chip = chip;
+       pm860x->i2c = (chip->id == CHIP_PM8607) ? chip->client
+                       : chip->companion;
+       platform_set_drvdata(pdev, pm860x);
+
+       for (i = 0; i < 4; i++) {
+               res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
+               if (!res) {
+                       dev_err(&pdev->dev, "Failed to get IRQ resources\n");
+                       goto out;
+               }
+               pm860x->irq[i] = res->start + chip->irq_base;
+               strncpy(pm860x->name[i], res->name, MAX_NAME_LEN);
+       }
+
+       ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pm860x,
+                                    pm860x_dai, ARRAY_SIZE(pm860x_dai));
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register codec\n");
+               goto out;
+       }
+       return ret;
+
+out:
+       platform_set_drvdata(pdev, NULL);
+       kfree(pm860x);
+       return -EINVAL;
+}
+
+static int __devexit pm860x_codec_remove(struct platform_device *pdev)
+{
+       struct pm860x_priv *pm860x = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_codec(&pdev->dev);
+       platform_set_drvdata(pdev, NULL);
+       kfree(pm860x);
+       return 0;
+}
+
+static struct platform_driver pm860x_codec_driver = {
+       .driver = {
+               .name   = "88pm860x-codec",
+               .owner  = THIS_MODULE,
+       },
+       .probe  = pm860x_codec_probe,
+       .remove = __devexit_p(pm860x_codec_remove),
+};
+
+static __init int pm860x_init(void)
+{
+       return platform_driver_register(&pm860x_codec_driver);
+}
+module_init(pm860x_init);
+
+static __exit void pm860x_exit(void)
+{
+       platform_driver_unregister(&pm860x_codec_driver);
+}
+module_exit(pm860x_exit);
+
+MODULE_DESCRIPTION("ASoC 88PM860x driver");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:88pm860x-codec");
+
diff --git a/sound/soc/codecs/88pm860x-codec.h b/sound/soc/codecs/88pm860x-codec.h
new file mode 100644 (file)
index 0000000..3364ba4
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 88pm860x-codec.h -- 88PM860x ALSA SoC Audio Driver
+ *
+ * Copyright 2010 Marvell International Ltd.
+ *     Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __88PM860X_H
+#define __88PM860X_H
+
+/* The offset of these registers are 0xb0 */
+#define PM860X_PCM_IFACE_1             0x00
+#define PM860X_PCM_IFACE_2             0x01
+#define PM860X_PCM_IFACE_3             0x02
+#define PM860X_PCM_RATE                        0x03
+#define PM860X_EC_PATH                 0x04
+#define PM860X_SIDETONE_L_GAIN         0x05
+#define PM860X_SIDETONE_R_GAIN         0x06
+#define PM860X_SIDETONE_SHIFT          0x07
+#define PM860X_ADC_OFFSET_1            0x08
+#define PM860X_ADC_OFFSET_2            0x09
+#define PM860X_DMIC_DELAY              0x0a
+
+#define PM860X_I2S_IFACE_1             0x0b
+#define PM860X_I2S_IFACE_2             0x0c
+#define PM860X_I2S_IFACE_3             0x0d
+#define PM860X_I2S_IFACE_4             0x0e
+#define PM860X_EQUALIZER_N0_1          0x0f
+#define PM860X_EQUALIZER_N0_2          0x10
+#define PM860X_EQUALIZER_N1_1          0x11
+#define PM860X_EQUALIZER_N1_2          0x12
+#define PM860X_EQUALIZER_D1_1          0x13
+#define PM860X_EQUALIZER_D1_2          0x14
+#define PM860X_LOFI_GAIN_LEFT          0x15
+#define PM860X_LOFI_GAIN_RIGHT         0x16
+#define PM860X_HIFIL_GAIN_LEFT         0x17
+#define PM860X_HIFIL_GAIN_RIGHT                0x18
+#define PM860X_HIFIR_GAIN_LEFT         0x19
+#define PM860X_HIFIR_GAIN_RIGHT                0x1a
+#define PM860X_DAC_OFFSET              0x1b
+#define PM860X_OFFSET_LEFT_1           0x1c
+#define PM860X_OFFSET_LEFT_2           0x1d
+#define PM860X_OFFSET_RIGHT_1          0x1e
+#define PM860X_OFFSET_RIGHT_2          0x1f
+#define PM860X_ADC_ANA_1               0x20
+#define PM860X_ADC_ANA_2               0x21
+#define PM860X_ADC_ANA_3               0x22
+#define PM860X_ADC_ANA_4               0x23
+#define PM860X_ANA_TO_ANA              0x24
+#define PM860X_HS1_CTRL                        0x25
+#define PM860X_HS2_CTRL                        0x26
+#define PM860X_LO1_CTRL                        0x27
+#define PM860X_LO2_CTRL                        0x28
+#define PM860X_EAR_CTRL_1              0x29
+#define PM860X_EAR_CTRL_2              0x2a
+#define PM860X_AUDIO_SUPPLIES_1                0x2b
+#define PM860X_AUDIO_SUPPLIES_2                0x2c
+#define PM860X_ADC_EN_1                        0x2d
+#define PM860X_ADC_EN_2                        0x2e
+#define PM860X_DAC_EN_1                        0x2f
+#define PM860X_DAC_EN_2                        0x31
+#define PM860X_AUDIO_CAL_1             0x32
+#define PM860X_AUDIO_CAL_2             0x33
+#define PM860X_AUDIO_CAL_3             0x34
+#define PM860X_AUDIO_CAL_4             0x35
+#define PM860X_AUDIO_CAL_5             0x36
+#define PM860X_ANA_INPUT_SEL_1         0x37
+#define PM860X_ANA_INPUT_SEL_2         0x38
+
+#define PM860X_PCM_IFACE_4             0x39
+#define PM860X_I2S_IFACE_5             0x3a
+
+#define PM860X_SHORTS                  0x3b
+#define PM860X_PLL_ADJ_1               0x3c
+#define PM860X_PLL_ADJ_2               0x3d
+
+/* bits definition */
+#define PM860X_CLK_DIR_IN              0
+#define PM860X_CLK_DIR_OUT             1
+
+#define PM860X_DET_HEADSET             (1 << 0)
+#define PM860X_DET_MIC                 (1 << 1)
+#define PM860X_DET_HOOK                        (1 << 2)
+#define PM860X_SHORT_HEADSET           (1 << 3)
+#define PM860X_SHORT_LINEOUT           (1 << 4)
+#define PM860X_DET_MASK                        0x1F
+
+extern int pm860x_hs_jack_detect(struct snd_soc_codec *, struct snd_soc_jack *,
+                                int, int, int, int);
+extern int pm860x_mic_jack_detect(struct snd_soc_codec *, struct snd_soc_jack *,
+                                 int);
+
+#endif /* __88PM860X_H */
index 83f5c67d3c41630794ee8d2aa3fc54409e240a70..94a9d06b90277797215e299907444a85ca3f379a 100644 (file)
@@ -10,6 +10,7 @@ config SND_SOC_I2C_AND_SPI
 
 config SND_SOC_ALL_CODECS
        tristate "Build all ASoC CODEC drivers"
+       select SND_SOC_88PM860X if MFD_88PM860X
        select SND_SOC_L3
        select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
        select SND_SOC_AD1836 if SPI_MASTER
@@ -26,6 +27,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_CS4270 if I2C
        select SND_SOC_DA7210 if I2C
        select SND_SOC_JZ4740 if SOC_JZ4740
+       select SND_SOC_MAX98088 if I2C
        select SND_SOC_MAX9877 if I2C
        select SND_SOC_PCM3008
        select SND_SOC_SPDIF
@@ -40,6 +42,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_TWL6040 if TWL4030_CORE
        select SND_SOC_UDA134X
        select SND_SOC_UDA1380 if I2C
+       select SND_SOC_WL1273 if WL1273_CORE
        select SND_SOC_WM2000 if I2C
        select SND_SOC_WM8350 if MFD_WM8350
        select SND_SOC_WM8400 if MFD_WM8400
@@ -54,6 +57,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
        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
        select SND_SOC_WM8903 if I2C
        select SND_SOC_WM8904 if I2C
@@ -61,9 +65,11 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8955 if I2C
        select SND_SOC_WM8960 if I2C
        select SND_SOC_WM8961 if I2C
+       select SND_SOC_WM8962 if I2C
        select SND_SOC_WM8971 if I2C
        select SND_SOC_WM8974 if I2C
        select SND_SOC_WM8978 if I2C
+       select SND_SOC_WM8985 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8990 if I2C
        select SND_SOC_WM8993 if I2C
@@ -84,6 +90,9 @@ config SND_SOC_ALL_CODECS
 
           If unsure select "N".
 
+config SND_SOC_88PM860X
+       tristate
+
 config SND_SOC_WM_HUBS
        tristate
        default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y
@@ -150,6 +159,9 @@ config SND_SOC_L3
 config SND_SOC_DA7210
         tristate
 
+config SND_SOC_MAX98088
+       tristate
+
 config SND_SOC_PCM3008
        tristate
 
@@ -188,6 +200,9 @@ config SND_SOC_UDA134X
 config SND_SOC_UDA1380
         tristate
 
+config SND_SOC_WL1273
+       tristate
+
 config SND_SOC_WM8350
        tristate
 
@@ -227,6 +242,9 @@ config SND_SOC_WM8753
 config SND_SOC_WM8776
        tristate
 
+config SND_SOC_WM8804
+       tristate
+
 config SND_SOC_WM8900
        tristate
 
@@ -248,6 +266,9 @@ config SND_SOC_WM8960
 config SND_SOC_WM8961
        tristate
 
+config SND_SOC_WM8962
+       tristate
+
 config SND_SOC_WM8971
        tristate
 
@@ -257,6 +278,9 @@ config SND_SOC_WM8974
 config SND_SOC_WM8978
        tristate
 
+config SND_SOC_WM8985
+       tristate
+
 config SND_SOC_WM8988
        tristate
 
index 53524095759c62ed322a033d818c78543182749a..f67a2d6f7a46c0386f67f8a1b6dc43bb4318aeff 100644 (file)
@@ -1,3 +1,4 @@
+snd-soc-88pm860x-objs := 88pm860x-codec.o
 snd-soc-ac97-objs := ac97.o
 snd-soc-ad1836-objs := ad1836.o
 snd-soc-ad193x-objs := ad193x.o
@@ -14,6 +15,7 @@ snd-soc-cs4270-objs := cs4270.o
 snd-soc-cx20442-objs := cx20442.o
 snd-soc-da7210-objs := da7210.o
 snd-soc-l3-objs := l3.o
+snd-soc-max98088-objs := max98088.o
 snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-spdif-objs := spdif_transciever.o
 snd-soc-ssm2602-objs := ssm2602.o
@@ -26,6 +28,7 @@ snd-soc-twl4030-objs := twl4030.o
 snd-soc-twl6040-objs := twl6040.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
+snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm8350-objs := wm8350.o
 snd-soc-wm8400-objs := wm8400.o
 snd-soc-wm8510-objs := wm8510.o
@@ -39,6 +42,7 @@ snd-soc-wm8741-objs := wm8741.o
 snd-soc-wm8750-objs := wm8750.o
 snd-soc-wm8753-objs := wm8753.o
 snd-soc-wm8776-objs := wm8776.o
+snd-soc-wm8804-objs := wm8804.o
 snd-soc-wm8900-objs := wm8900.o
 snd-soc-wm8903-objs := wm8903.o
 snd-soc-wm8904-objs := wm8904.o
@@ -46,9 +50,11 @@ snd-soc-wm8940-objs := wm8940.o
 snd-soc-wm8955-objs := wm8955.o
 snd-soc-wm8960-objs := wm8960.o
 snd-soc-wm8961-objs := wm8961.o
+snd-soc-wm8962-objs := wm8962.o
 snd-soc-wm8971-objs := wm8971.o
 snd-soc-wm8974-objs := wm8974.o
 snd-soc-wm8978-objs := wm8978.o
+snd-soc-wm8985-objs := wm8985.o
 snd-soc-wm8988-objs := wm8988.o
 snd-soc-wm8990-objs := wm8990.o
 snd-soc-wm8993-objs := wm8993.o
@@ -66,6 +72,7 @@ snd-soc-tpa6130a2-objs := tpa6130a2.o
 snd-soc-wm2000-objs := wm2000.o
 snd-soc-wm9090-objs := wm9090.o
 
+obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o
 obj-$(CONFIG_SND_SOC_AC97_CODEC)       += snd-soc-ac97.o
 obj-$(CONFIG_SND_SOC_AD1836)   += snd-soc-ad1836.o
 obj-$(CONFIG_SND_SOC_AD193X)   += snd-soc-ad193x.o
@@ -83,6 +90,7 @@ obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
 obj-$(CONFIG_SND_SOC_DA7210)   += snd-soc-da7210.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_SPDIF)    += snd-soc-spdif.o
 obj-$(CONFIG_SND_SOC_SSM2602)  += snd-soc-ssm2602.o
@@ -95,6 +103,7 @@ obj-$(CONFIG_SND_SOC_TWL4030)        += snd-soc-twl4030.o
 obj-$(CONFIG_SND_SOC_TWL6040)  += snd-soc-twl6040.o
 obj-$(CONFIG_SND_SOC_UDA134X)  += snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)  += snd-soc-uda1380.o
+obj-$(CONFIG_SND_SOC_WL1273)   += snd-soc-wl1273.o
 obj-$(CONFIG_SND_SOC_WM8350)   += snd-soc-wm8350.o
 obj-$(CONFIG_SND_SOC_WM8400)   += snd-soc-wm8400.o
 obj-$(CONFIG_SND_SOC_WM8510)   += snd-soc-wm8510.o
@@ -108,6 +117,7 @@ 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_WM8776)   += snd-soc-wm8776.o
+obj-$(CONFIG_SND_SOC_WM8804)   += snd-soc-wm8804.o
 obj-$(CONFIG_SND_SOC_WM8900)   += snd-soc-wm8900.o
 obj-$(CONFIG_SND_SOC_WM8903)   += snd-soc-wm8903.o
 obj-$(CONFIG_SND_SOC_WM8904)   += snd-soc-wm8904.o
@@ -115,9 +125,11 @@ obj-$(CONFIG_SND_SOC_WM8940)       += snd-soc-wm8940.o
 obj-$(CONFIG_SND_SOC_WM8955)   += snd-soc-wm8955.o
 obj-$(CONFIG_SND_SOC_WM8960)   += snd-soc-wm8960.o
 obj-$(CONFIG_SND_SOC_WM8961)   += snd-soc-wm8961.o
+obj-$(CONFIG_SND_SOC_WM8962)   += snd-soc-wm8962.o
 obj-$(CONFIG_SND_SOC_WM8971)   += snd-soc-wm8971.o
 obj-$(CONFIG_SND_SOC_WM8974)   += snd-soc-wm8974.o
 obj-$(CONFIG_SND_SOC_WM8978)   += snd-soc-wm8978.o
+obj-$(CONFIG_SND_SOC_WM8985)   += snd-soc-wm8985.o
 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
index 1f5e57a4bb7accdfdad3eefdd209b9b056b7351c..3c087936aa57028b11b0567d5165088a4aa5aed9 100644 (file)
 #include <sound/ac97_codec.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
-#include "ac97.h"
-
-#define AC97_VERSION "0.6"
 
 static int ac97_prepare(struct snd_pcm_substream *substream,
                        struct snd_soc_dai *dai)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
                  AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
@@ -46,8 +42,8 @@ static struct snd_soc_dai_ops ac97_dai_ops = {
        .prepare        = ac97_prepare,
 };
 
-struct snd_soc_dai ac97_dai = {
-       .name = "AC97 HiFi",
+static struct snd_soc_dai_driver ac97_dai = {
+       .name = "ac97-hifi",
        .ac97_control = 1,
        .playback = {
                .stream_name = "AC97 Playback",
@@ -63,7 +59,6 @@ struct snd_soc_dai ac97_dai = {
                .formats = SND_SOC_STD_AC97_FMTS,},
        .ops = &ac97_dai_ops,
 };
-EXPORT_SYMBOL_GPL(ac97_dai);
 
 static unsigned int ac97_read(struct snd_soc_codec *codec,
        unsigned int reg)
@@ -78,95 +73,41 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
        return 0;
 }
 
-static int ac97_soc_probe(struct platform_device *pdev)
+static int ac97_soc_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_codec *codec;
        struct snd_ac97_bus *ac97_bus;
        struct snd_ac97_template ac97_template;
-       int i;
-       int ret = 0;
-
-       printk(KERN_INFO "AC97 SoC Audio Codec %s\n", AC97_VERSION);
-
-       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (!socdev->card->codec)
-               return -ENOMEM;
-       codec = socdev->card->codec;
-       mutex_init(&codec->mutex);
-
-       codec->name = "AC97";
-       codec->owner = THIS_MODULE;
-       codec->dai = &ac97_dai;
-       codec->num_dai = 1;
-       codec->write = ac97_write;
-       codec->read = ac97_read;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0)
-               goto err;
+       int ret;
 
        /* add codec as bus device for standard ac97 */
-       ret = snd_ac97_bus(codec->card, 0, &soc_ac97_ops, NULL, &ac97_bus);
+       ret = snd_ac97_bus(codec->card->snd_card, 0, &soc_ac97_ops, NULL, &ac97_bus);
        if (ret < 0)
-               goto bus_err;
+               return ret;
 
        memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
        ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97);
        if (ret < 0)
-               goto bus_err;
-
-       for (i = 0; i < card->num_links; i++) {
-               if (card->dai_link[i].codec_dai->ac97_control) {
-                       snd_ac97_dev_add_pdata(codec->ac97,
-                               card->dai_link[i].cpu_dai->ac97_pdata);
-               }
-       }
+               return ret;
 
        return 0;
-
-bus_err:
-       snd_soc_free_pcms(socdev);
-
-err:
-       kfree(socdev->card->codec);
-       socdev->card->codec = NULL;
-       return ret;
 }
 
-static int ac97_soc_remove(struct platform_device *pdev)
+static int ac97_soc_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (!codec)
-               return 0;
-
-       snd_soc_free_pcms(socdev);
-       kfree(socdev->card->codec);
-
        return 0;
 }
 
 #ifdef CONFIG_PM
-static int ac97_soc_suspend(struct platform_device *pdev, pm_message_t msg)
+static int ac97_soc_suspend(struct snd_soc_codec *codec, pm_message_t msg)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_ac97_suspend(socdev->card->codec->ac97);
+       snd_ac97_suspend(codec->ac97);
 
        return 0;
 }
 
-static int ac97_soc_resume(struct platform_device *pdev)
+static int ac97_soc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_ac97_resume(socdev->card->codec->ac97);
+       snd_ac97_resume(codec->ac97);
 
        return 0;
 }
@@ -175,14 +116,50 @@ static int ac97_soc_resume(struct platform_device *pdev)
 #define ac97_soc_resume NULL
 #endif
 
-struct snd_soc_codec_device soc_codec_dev_ac97 = {
+static struct snd_soc_codec_driver soc_codec_dev_ac97 = {
+       .write =        ac97_write,
+       .read =         ac97_read,
        .probe =        ac97_soc_probe,
        .remove =       ac97_soc_remove,
        .suspend =      ac97_soc_suspend,
        .resume =       ac97_soc_resume,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_ac97);
+
+static __devinit int ac97_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_ac97, &ac97_dai, 1);
+}
+
+static int __devexit ac97_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver ac97_codec_driver = {
+       .driver = {
+               .name = "ac97-codec",
+               .owner = THIS_MODULE,
+       },
+
+       .probe = ac97_probe,
+       .remove = __devexit_p(ac97_remove),
+};
+
+static int __init ac97_init(void)
+{
+       return platform_driver_register(&ac97_codec_driver);
+}
+module_init(ac97_init);
+
+static void __exit ac97_exit(void)
+{
+       platform_driver_unregister(&ac97_codec_driver);
+}
+module_exit(ac97_exit);
 
 MODULE_DESCRIPTION("Soc Generic AC97 driver");
 MODULE_AUTHOR("Liam Girdwood");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ac97-codec");
diff --git a/sound/soc/codecs/ac97.h b/sound/soc/codecs/ac97.h
deleted file mode 100644 (file)
index 281aa42..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * linux/sound/codecs/ac97.h -- ALSA SoC Layer
- *
- * Author:             Liam Girdwood
- * Created:            Dec 1st 2005
- * Copyright:  Wolfson Microelectronics. PLC.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __LINUX_SND_SOC_AC97_H
-#define __LINUX_SND_SOC_AC97_H
-
-extern struct snd_soc_codec_device soc_codec_dev_ac97;
-extern struct snd_soc_dai ac97_dai;
-
-#endif
index a01006c8c606ffd613b250bf7f95fbc95ebaa05c..d272534c8f8413dba5221dc60d01fdbfb74b72e8 100644 (file)
 
 /* codec private data */
 struct ad1836_priv {
-       struct snd_soc_codec codec;
-       u16 reg_cache[AD1836_NUM_REGS];
+       enum snd_soc_control_type control_type;
+       void *control_data;
 };
 
-static struct snd_soc_codec *ad1836_codec;
-struct snd_soc_codec_device soc_codec_dev_ad1836;
-static int ad1836_register(struct ad1836_priv *ad1836);
-static void ad1836_unregister(struct ad1836_priv *ad1836);
-
 /*
  * AD1836 volume/mute/de-emphasis etc. controls
  */
@@ -146,8 +141,7 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
        int word_len = 0;
 
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* bit size */
        switch (params_format(params)) {
@@ -173,12 +167,9 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
 }
 
 #ifdef CONFIG_PM
-static int ad1836_soc_suspend(struct platform_device *pdev,
+static int ad1836_soc_suspend(struct snd_soc_codec *codec,
                pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        /* reset clock control mode */
        u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
        adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK;
@@ -186,11 +177,8 @@ static int ad1836_soc_suspend(struct platform_device *pdev,
        return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
 }
 
-static int ad1836_soc_resume(struct platform_device *pdev)
+static int ad1836_soc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        /* restore clock control mode */
        u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
        adc_ctrl2 |= AD1836_ADC_AUX;
@@ -202,49 +190,14 @@ static int ad1836_soc_resume(struct platform_device *pdev)
 #define ad1836_soc_resume  NULL
 #endif
 
-static int __devinit ad1836_spi_probe(struct spi_device *spi)
-{
-       struct snd_soc_codec *codec;
-       struct ad1836_priv *ad1836;
-
-       ad1836 = kzalloc(sizeof(struct ad1836_priv), GFP_KERNEL);
-       if (ad1836 == NULL)
-               return -ENOMEM;
-
-       codec = &ad1836->codec;
-       codec->control_data = spi;
-       codec->dev = &spi->dev;
-
-       dev_set_drvdata(&spi->dev, ad1836);
-
-       return ad1836_register(ad1836);
-}
-
-static int __devexit ad1836_spi_remove(struct spi_device *spi)
-{
-       struct ad1836_priv *ad1836 = dev_get_drvdata(&spi->dev);
-
-       ad1836_unregister(ad1836);
-       return 0;
-}
-
-static struct spi_driver ad1836_spi_driver = {
-       .driver = {
-               .name   = "ad1836",
-               .owner  = THIS_MODULE,
-       },
-       .probe          = ad1836_spi_probe,
-       .remove         = __devexit_p(ad1836_spi_remove),
-};
-
 static struct snd_soc_dai_ops ad1836_dai_ops = {
        .hw_params = ad1836_hw_params,
        .set_fmt = ad1836_set_dai_fmt,
 };
 
 /* codec DAI instance */
-struct snd_soc_dai ad1836_dai = {
-       .name = "AD1836",
+static struct snd_soc_dai_driver ad1836_dai = {
+       .name = "ad1836-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -263,35 +216,13 @@ struct snd_soc_dai ad1836_dai = {
        },
        .ops = &ad1836_dai_ops,
 };
-EXPORT_SYMBOL_GPL(ad1836_dai);
 
-static int ad1836_register(struct ad1836_priv *ad1836)
+static int ad1836_probe(struct snd_soc_codec *codec)
 {
-       int ret;
-       struct snd_soc_codec *codec = &ad1836->codec;
-
-       if (ad1836_codec) {
-               dev_err(codec->dev, "Another ad1836 is registered\n");
-               kfree(ad1836);
-               return -EINVAL;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-       snd_soc_codec_set_drvdata(codec, ad1836);
-       codec->reg_cache = ad1836->reg_cache;
-       codec->reg_cache_size = AD1836_NUM_REGS;
-       codec->name = "AD1836";
-       codec->owner = THIS_MODULE;
-       codec->dai = &ad1836_dai;
-       codec->num_dai = 1;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       ad1836_dai.dev = codec->dev;
-       ad1836_codec = codec;
+       struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0;
 
+       codec->control_data = ad1836->control_data;
        ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI);
        if (ret < 0) {
                dev_err(codec->dev, "failed to set cache I/O: %d\n",
@@ -319,81 +250,69 @@ static int ad1836_register(struct ad1836_priv *ad1836)
        snd_soc_write(codec, AD1836_DAC_L3_VOL, 0x3FF);
        snd_soc_write(codec, AD1836_DAC_R3_VOL, 0x3FF);
 
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               kfree(ad1836);
-               return ret;
-       }
-
-       ret = snd_soc_register_dai(&ad1836_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               snd_soc_unregister_codec(codec);
-               kfree(ad1836);
-               return ret;
-       }
-
-       return 0;
-}
-
-static void ad1836_unregister(struct ad1836_priv *ad1836)
-{
-       snd_soc_unregister_dai(&ad1836_dai);
-       snd_soc_unregister_codec(&ad1836->codec);
-       kfree(ad1836);
-       ad1836_codec = NULL;
-}
-
-static int ad1836_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (ad1836_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = ad1836_codec;
-       codec = ad1836_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
        snd_soc_add_controls(codec, ad1836_snd_controls,
                             ARRAY_SIZE(ad1836_snd_controls));
        snd_soc_dapm_new_controls(codec, ad1836_dapm_widgets,
                                  ARRAY_SIZE(ad1836_dapm_widgets));
        snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
 
-pcm_err:
        return ret;
 }
 
 /* power down chip */
-static int ad1836_remove(struct platform_device *pdev)
+static int ad1836_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
+       /* reset clock control mode */
+       u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
+       adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK;
 
-       return 0;
+       return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
 }
 
-struct snd_soc_codec_device soc_codec_dev_ad1836 = {
+static struct snd_soc_codec_driver soc_codec_dev_ad1836 = {
        .probe =        ad1836_probe,
        .remove =       ad1836_remove,
        .suspend =      ad1836_soc_suspend,
        .resume =       ad1836_soc_resume,
+       .reg_cache_size = AD1836_NUM_REGS,
+       .reg_word_size = sizeof(u16),
+};
+
+static int __devinit ad1836_spi_probe(struct spi_device *spi)
+{
+       struct ad1836_priv *ad1836;
+       int ret;
+
+       ad1836 = kzalloc(sizeof(struct ad1836_priv), GFP_KERNEL);
+       if (ad1836 == NULL)
+               return -ENOMEM;
+
+       spi_set_drvdata(spi, ad1836);
+       ad1836->control_data = spi;
+       ad1836->control_type = SND_SOC_SPI;
+
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_ad1836, &ad1836_dai, 1);
+       if (ret < 0)
+               kfree(ad1836);
+       return ret;
+}
+
+static int __devexit ad1836_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
+       return 0;
+}
+
+static struct spi_driver ad1836_spi_driver = {
+       .driver = {
+               .name   = "ad1836-codec",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ad1836_spi_probe,
+       .remove         = __devexit_p(ad1836_spi_remove),
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_ad1836);
 
 static int __init ad1836_init(void)
 {
index e9d90d3951c520f4c18fdb56d9eae6d72dd0b160..845596717fdf522d2de2d83d37e123825a36cade 100644 (file)
@@ -60,6 +60,4 @@
 
 #define AD1836_NUM_REGS                16
 
-extern struct snd_soc_dai ad1836_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ad1836;
 #endif
index 1def75e4862f60fe2a143470cdb2ae458453e08a..fa2834c91b9f5e8507841eba8155d54a59386e35 100644 (file)
 
 /* codec private data */
 struct ad193x_priv {
-       unsigned int sysclk;
-       struct snd_soc_codec codec;
        u8 reg_cache[AD193X_NUM_REGS];
+       enum snd_soc_control_type bus_type;
+       void *control_data;
+       int sysclk;
 };
 
 /* ad193x register cache & default register settings */
@@ -34,9 +35,6 @@ static const u8 ad193x_reg[AD193X_NUM_REGS] = {
        0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0,
 };
 
-static struct snd_soc_codec *ad193x_codec;
-struct snd_soc_codec_device soc_codec_dev_ad193x;
-
 /*
  * AD193X volume/mute/de-emphasis etc. controls
  */
@@ -275,8 +273,7 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
        int word_len = 0, reg = 0, master_rate = 0;
 
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
 
        /* bit size */
@@ -323,100 +320,6 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int ad193x_bus_probe(struct device *dev, void *ctrl_data, int bus_type)
-{
-       struct snd_soc_codec *codec;
-       struct ad193x_priv *ad193x;
-       int ret;
-
-       if (ad193x_codec) {
-               dev_err(dev, "Another ad193x is registered\n");
-               return -EINVAL;
-       }
-
-       ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
-       if (ad193x == NULL)
-               return -ENOMEM;
-
-       dev_set_drvdata(dev, ad193x);
-
-       codec = &ad193x->codec;
-       mutex_init(&codec->mutex);
-       codec->control_data = ctrl_data;
-       codec->dev = dev;
-       snd_soc_codec_set_drvdata(codec, ad193x);
-       codec->reg_cache = ad193x->reg_cache;
-       codec->reg_cache_size = AD193X_NUM_REGS;
-       codec->name = "AD193X";
-       codec->owner = THIS_MODULE;
-       codec->dai = &ad193x_dai;
-       codec->num_dai = 1;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       ad193x_dai.dev = codec->dev;
-       ad193x_codec = codec;
-
-       memcpy(codec->reg_cache, ad193x_reg, AD193X_NUM_REGS);
-
-       if (bus_type == SND_SOC_I2C)
-               ret = snd_soc_codec_set_cache_io(codec, 8, 8, bus_type);
-       else
-               ret = snd_soc_codec_set_cache_io(codec, 16, 8, bus_type);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to set cache I/O: %d\n",
-                               ret);
-               kfree(ad193x);
-               return ret;
-       }
-
-       /* default setting for ad193x */
-
-       /* unmute dac channels */
-       snd_soc_write(codec, AD193X_DAC_CHNL_MUTE, 0x0);
-       /* de-emphasis: 48kHz, powedown dac */
-       snd_soc_write(codec, AD193X_DAC_CTRL2, 0x1A);
-       /* powerdown dac, dac in tdm mode */
-       snd_soc_write(codec, AD193X_DAC_CTRL0, 0x41);
-       /* high-pass filter enable */
-       snd_soc_write(codec, AD193X_ADC_CTRL0, 0x3);
-       /* sata delay=1, adc aux mode */
-       snd_soc_write(codec, AD193X_ADC_CTRL1, 0x43);
-       /* pll input: mclki/xi */
-       snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
-       snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04);
-       ad193x->sysclk = 12288000;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               kfree(ad193x);
-               return ret;
-       }
-
-       ret = snd_soc_register_dai(&ad193x_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               snd_soc_unregister_codec(codec);
-               kfree(ad193x);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int ad193x_bus_remove(struct device *dev)
-{
-       struct ad193x_priv *ad193x = dev_get_drvdata(dev);
-
-       snd_soc_unregister_dai(&ad193x_dai);
-       snd_soc_unregister_codec(&ad193x->codec);
-       kfree(ad193x);
-       ad193x_codec = NULL;
-
-       return 0;
-}
-
 static struct snd_soc_dai_ops ad193x_dai_ops = {
        .hw_params = ad193x_hw_params,
        .digital_mute = ad193x_mute,
@@ -426,8 +329,8 @@ static struct snd_soc_dai_ops ad193x_dai_ops = {
 };
 
 /* codec DAI instance */
-struct snd_soc_dai ad193x_dai = {
-       .name = "AD193X",
+static struct snd_soc_dai_driver ad193x_dai = {
+       .name = "ad193x-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -446,28 +349,39 @@ struct snd_soc_dai ad193x_dai = {
        },
        .ops = &ad193x_dai_ops,
 };
-EXPORT_SYMBOL_GPL(ad193x_dai);
 
-static int ad193x_probe(struct platform_device *pdev)
+static int ad193x_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
+       struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
+       int ret;
 
-       if (ad193x_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
+       codec->control_data = ad193x->control_data;
+       if (ad193x->bus_type == SND_SOC_I2C)
+               ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->bus_type);
+       else
+               ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->bus_type);
+       if (ret < 0) {
+               dev_err(codec->dev, "failed to set cache I/O: %d\n",
+                               ret);
+               kfree(ad193x);
+               return ret;
        }
 
-       socdev->card->codec = ad193x_codec;
-       codec = ad193x_codec;
+       /* default setting for ad193x */
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
+       /* unmute dac channels */
+       snd_soc_write(codec, AD193X_DAC_CHNL_MUTE, 0x0);
+       /* de-emphasis: 48kHz, powedown dac */
+       snd_soc_write(codec, AD193X_DAC_CTRL2, 0x1A);
+       /* powerdown dac, dac in tdm mode */
+       snd_soc_write(codec, AD193X_DAC_CTRL0, 0x41);
+       /* high-pass filter enable */
+       snd_soc_write(codec, AD193X_ADC_CTRL0, 0x3);
+       /* sata delay=1, adc aux mode */
+       snd_soc_write(codec, AD193X_ADC_CTRL1, 0x43);
+       /* pll input: mclki/xi */
+       snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
+       snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04);
 
        snd_soc_add_controls(codec, ad193x_snd_controls,
                             ARRAY_SIZE(ad193x_snd_controls));
@@ -475,41 +389,47 @@ static int ad193x_probe(struct platform_device *pdev)
                                  ARRAY_SIZE(ad193x_dapm_widgets));
        snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
 
-pcm_err:
        return ret;
 }
 
-/* power down chip */
-static int ad193x_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ad193x = {
+static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
        .probe =        ad193x_probe,
-       .remove =       ad193x_remove,
+       .reg_cache_default = ad193x_reg,
+       .reg_cache_size = AD193X_NUM_REGS,
+       .reg_word_size = sizeof(u16),
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_ad193x);
 
 #if defined(CONFIG_SPI_MASTER)
 static int __devinit ad193x_spi_probe(struct spi_device *spi)
 {
-       return ad193x_bus_probe(&spi->dev, spi, SND_SOC_SPI);
+       struct ad193x_priv *ad193x;
+       int ret;
+
+       ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
+       if (ad193x == NULL)
+               return -ENOMEM;
+
+       spi_set_drvdata(spi, ad193x);
+       ad193x->control_data = spi;
+       ad193x->bus_type = SND_SOC_SPI;
+
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_ad193x, &ad193x_dai, 1);
+       if (ret < 0)
+               kfree(ad193x);
+       return ret;
 }
 
 static int __devexit ad193x_spi_remove(struct spi_device *spi)
 {
-       return ad193x_bus_remove(&spi->dev);
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
+       return 0;
 }
 
 static struct spi_driver ad193x_spi_driver = {
        .driver = {
-               .name   = "ad193x",
+               .name   = "ad193x-codec",
                .owner  = THIS_MODULE,
        },
        .probe          = ad193x_spi_probe,
@@ -528,17 +448,34 @@ MODULE_DEVICE_TABLE(i2c, ad193x_id);
 static int __devinit ad193x_i2c_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
-       return ad193x_bus_probe(&client->dev, client, SND_SOC_I2C);
+       struct ad193x_priv *ad193x;
+       int ret;
+
+       ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
+       if (ad193x == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, ad193x);
+       ad193x->control_data = client;
+       ad193x->bus_type = SND_SOC_I2C;
+
+       ret =  snd_soc_register_codec(&client->dev,
+                       &soc_codec_dev_ad193x, &ad193x_dai, 1);
+       if (ret < 0)
+               kfree(ad193x);
+       return ret;
 }
 
 static int __devexit ad193x_i2c_remove(struct i2c_client *client)
 {
-       return ad193x_bus_remove(&client->dev);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
+       return 0;
 }
 
 static struct i2c_driver ad193x_i2c_driver = {
        .driver = {
-               .name = "ad193x",
+               .name = "ad193x-codec",
        },
        .probe    = ad193x_i2c_probe,
        .remove   = __devexit_p(ad193x_i2c_remove),
index 654ba64ae04c6d4b0e8ebc89a0138916c37eed1c..9747b54978775cd43fe5d5af4f0234670ba2ff2f 100644 (file)
@@ -80,7 +80,4 @@
 
 #define AD193X_NUM_REGS          17
 
-extern struct snd_soc_dai ad193x_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ad193x;
-
 #endif
index 70cfaec3be2c0efbcf57c0c753622e747683b67c..410ccd5d41cdeb5ab2ca706bd67bccb075245ec2 100644 (file)
 
 #include "ad1980.h"
 
-static unsigned int ac97_read(struct snd_soc_codec *codec,
-       unsigned int reg);
-static int ac97_write(struct snd_soc_codec *codec,
-       unsigned int reg, unsigned int val);
-
 /*
  * AD1980 register cache
  */
@@ -138,8 +133,8 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
        return 0;
 }
 
-struct snd_soc_dai ad1980_dai = {
-       .name = "AC97",
+static struct snd_soc_dai_driver ad1980_dai = {
+       .name = "ad1980-hifi",
        .ac97_control = 1,
        .playback = {
                .stream_name = "Playback",
@@ -185,53 +180,20 @@ err:
        return -EIO;
 }
 
-static int ad1980_soc_probe(struct platform_device *pdev)
+static int ad1980_soc_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
+       int ret;
        u16 vendor_id2;
        u16 ext_status;
 
        printk(KERN_INFO "AD1980 SoC Audio Codec\n");
 
-       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (socdev->card->codec == NULL)
-               return -ENOMEM;
-       codec = socdev->card->codec;
-       mutex_init(&codec->mutex);
-
-       codec->reg_cache =
-               kzalloc(sizeof(u16) * ARRAY_SIZE(ad1980_reg), GFP_KERNEL);
-       if (codec->reg_cache == NULL) {
-               ret = -ENOMEM;
-               goto cache_err;
-       }
-       memcpy(codec->reg_cache, ad1980_reg, sizeof(u16) * \
-                       ARRAY_SIZE(ad1980_reg));
-       codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(ad1980_reg);
-       codec->reg_cache_step = 2;
-       codec->name = "AD1980";
-       codec->owner = THIS_MODULE;
-       codec->dai = &ad1980_dai;
-       codec->num_dai = 1;
-       codec->write = ac97_write;
-       codec->read = ac97_read;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0) {
                printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
-               goto codec_err;
+               return ret;
        }
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0)
-               goto pcm_err;
-
-
        ret = ad1980_reset(codec, 0);
        if (ret < 0) {
                printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n");
@@ -270,41 +232,60 @@ static int ad1980_soc_probe(struct platform_device *pdev)
        return 0;
 
 reset_err:
-       snd_soc_free_pcms(socdev);
-
-pcm_err:
        snd_soc_free_ac97_codec(codec);
-
-codec_err:
-       kfree(codec->reg_cache);
-
-cache_err:
-       kfree(socdev->card->codec);
-       socdev->card->codec = NULL;
        return ret;
 }
 
-static int ad1980_soc_remove(struct platform_device *pdev)
+static int ad1980_soc_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec == NULL)
-               return 0;
-
-       snd_soc_dapm_free(socdev);
-       snd_soc_free_pcms(socdev);
        snd_soc_free_ac97_codec(codec);
-       kfree(codec->reg_cache);
-       kfree(codec);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_ad1980 = {
+static struct snd_soc_codec_driver soc_codec_dev_ad1980 = {
        .probe =        ad1980_soc_probe,
        .remove =       ad1980_soc_remove,
+       .reg_cache_size = ARRAY_SIZE(ad1980_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = ad1980_reg,
+       .reg_cache_step = 2,
+       .write = ac97_write,
+       .read = ac97_read,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_ad1980);
+
+static __devinit int ad1980_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_ad1980, &ad1980_dai, 1);
+}
+
+static int __devexit ad1980_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver ad1980_codec_driver = {
+       .driver = {
+                       .name = "ad1980-codec",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = ad1980_probe,
+       .remove = __devexit_p(ad1980_remove),
+};
+
+static int __init ad1980_init(void)
+{
+       return platform_driver_register(&ad1980_codec_driver);
+}
+module_init(ad1980_init);
+
+static void __exit ad1980_exit(void)
+{
+       platform_driver_unregister(&ad1980_codec_driver);
+}
+module_exit(ad1980_exit);
 
 MODULE_DESCRIPTION("ASoC ad1980 driver (Obsolete)");
 MODULE_AUTHOR("Roy Huang, Cliff Cai");
index 538f37c908068628eddf039194762a8e1bfb0898..eb0af44ad3dfb6f7050e8943814172d7ca4bc26e 100644 (file)
@@ -23,7 +23,4 @@
 #define PR5            0x2000
 #define PR6            0x4000
 
-extern struct snd_soc_dai ad1980_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ad1980;
-
 #endif
index 475807bea2c229d04e4e3ed91dd8647ffa26d259..c53955fe17b65875e8354063e897c6501edc7b50 100644 (file)
@@ -23,8 +23,8 @@
 
 #include "ad73311.h"
 
-struct snd_soc_dai ad73311_dai = {
-       .name = "AD73311",
+static struct snd_soc_dai_driver ad73311_dai = {
+       .name = "ad73311-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -38,68 +38,40 @@ struct snd_soc_dai ad73311_dai = {
                .rates = SNDRV_PCM_RATE_8000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE, },
 };
-EXPORT_SYMBOL_GPL(ad73311_dai);
 
-static int ad73311_soc_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
-       mutex_init(&codec->mutex);
-       codec->name = "AD73311";
-       codec->owner = THIS_MODULE;
-       codec->dai = &ad73311_dai;
-       codec->num_dai = 1;
-       socdev->card->codec = codec;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "ad73311: failed to create pcms\n");
-               goto pcm_err;
-       }
-
-       return ret;
+static struct snd_soc_codec_driver soc_codec_dev_ad73311;
 
-pcm_err:
-       kfree(socdev->card->codec);
-       socdev->card->codec = NULL;
-       return ret;
+static int ad73311_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_ad73311, &ad73311_dai, 1);
 }
 
-static int ad73311_soc_remove(struct platform_device *pdev)
+static int ad73311_remove(struct platform_device *pdev)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec == NULL)
-               return 0;
-       snd_soc_free_pcms(socdev);
-       kfree(codec);
+       snd_soc_unregister_codec(&pdev->dev);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_ad73311 = {
-       .probe =        ad73311_soc_probe,
-       .remove =       ad73311_soc_remove,
+static struct platform_driver ad73311_codec_driver = {
+       .driver = {
+                       .name = "ad73311-codec",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = ad73311_probe,
+       .remove = __devexit_p(ad73311_remove),
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311);
 
 static int __init ad73311_init(void)
 {
-       return snd_soc_register_dai(&ad73311_dai);
+       return platform_driver_register(&ad73311_codec_driver);
 }
 module_init(ad73311_init);
 
 static void __exit ad73311_exit(void)
 {
-       snd_soc_unregister_dai(&ad73311_dai);
+       platform_driver_unregister(&ad73311_codec_driver);
 }
 module_exit(ad73311_exit);
 
index 569573d2d4d7a628b18c9c1a108512e11a4e9008..4b353eefc0bf04508ffce2c24ecc36405773381d 100644 (file)
@@ -85,6 +85,4 @@
 #define REGF_INV               (1 << 6)
 #define REGF_ALB               (1 << 7)
 
-extern struct snd_soc_dai ad73311_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ad73311;
 #endif
index f8e75edb27b7ec793f21f32e10200db2d734148c..8402854ec15e30b320d31e1416896ced2f964850 100644 (file)
 #include <sound/initval.h>
 #include <sound/soc.h>
 
-#include "ads117x.h"
-
 #define ADS117X_RATES (SNDRV_PCM_RATE_8000_48000)
-
 #define ADS117X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
 
-struct snd_soc_dai ads117x_dai = {
+static struct snd_soc_dai_driver ads117x_dai = {
 /* ADC */
-       .name = "ADS117X ADC",
-       .id = 1,
+       .name = "ads117x-hifi",
        .capture = {
                .stream_name = "Capture",
                .channels_min = 1,
@@ -36,75 +32,29 @@ struct snd_soc_dai ads117x_dai = {
                .rates = ADS117X_RATES,
                .formats = ADS117X_FORMATS,},
 };
-EXPORT_SYMBOL_GPL(ads117x_dai);
-
-static int ads117x_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret;
-
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
 
-       socdev->card->codec = codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-       codec->name = "ADS117X";
-       codec->owner = THIS_MODULE;
-       codec->dai = &ads117x_dai;
-       codec->num_dai = 1;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "ads117x: failed to create pcms\n");
-               kfree(codec);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int ads117x_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       snd_soc_free_pcms(socdev);
-       kfree(codec);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ads117x = {
-       .probe =        ads117x_probe,
-       .remove =       ads117x_remove,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ads117x);
+static struct snd_soc_codec_driver soc_codec_dev_ads117x;
 
-static __devinit int ads117x_platform_probe(struct platform_device *pdev)
+static __devinit int ads117x_probe(struct platform_device *pdev)
 {
-       ads117x_dai.dev = &pdev->dev;
-       return snd_soc_register_dai(&ads117x_dai);
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_ads117x, &ads117x_dai, 1);
 }
 
-static int __devexit ads117x_platform_remove(struct platform_device *pdev)
+static int __devexit ads117x_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&ads117x_dai);
+       snd_soc_unregister_codec(&pdev->dev);
        return 0;
 }
 
 static struct platform_driver ads117x_codec_driver = {
        .driver = {
-                       .name = "ads117x",
+                       .name = "ads117x-codec",
                        .owner = THIS_MODULE,
        },
 
-       .probe = ads117x_platform_probe,
-       .remove = __devexit_p(ads117x_platform_remove),
+       .probe = ads117x_probe,
+       .remove = __devexit_p(ads117x_remove),
 };
 
 static int __init ads117x_init(void)
index dbcf50ec9bd175e32efed8f14b0d295730b87849..3ce028614002c1bbc14d094ccdf7d056fb8b436a 100644 (file)
@@ -9,5 +9,5 @@
  *  Free Software Foundation;  either version 2 of the  License, or (at your
  *  option) any later version.
  */
-extern struct snd_soc_dai ads117x_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ads117x;
+extern struct snd_soc_dai_driver ads117x_dai;
+extern struct snd_soc_codec_driver soc_codec_dev_ads117x;
index 192aebda3029628efa7f11e8a4b019d825f857ca..c27f8f59dc66d38cc4fb98fe7a428168333ac3db 100644 (file)
@@ -17,8 +17,6 @@
 #include <linux/spi/spi.h>
 #include <sound/asoundef.h>
 
-#include "ak4104.h"
-
 /* AK4104 registers addresses */
 #define AK4104_REG_CONTROL1            0x00
 #define AK4104_REG_RESERVED            0x01
 #define AK4104_TX_TXE                  (1 << 0)
 #define AK4104_TX_V                    (1 << 1)
 
-#define DRV_NAME "ak4104"
+#define DRV_NAME "ak4104-codec"
 
 struct ak4104_private {
-       struct snd_soc_codec codec;
-       u8 reg_cache[AK4104_NUM_REGS];
+       enum snd_soc_control_type control_type;
+       void *control_data;
 };
 
 static int ak4104_fill_cache(struct snd_soc_codec *codec)
@@ -58,7 +56,7 @@ static int ak4104_fill_cache(struct snd_soc_codec *codec)
        u8 *reg_cache = codec->reg_cache;
        struct spi_device *spi = codec->control_data;
 
-       for (i = 0; i < codec->reg_cache_size; i++) {
+       for (i = 0; i < codec->driver->reg_cache_size; i++) {
                int ret = spi_w8r8(spi, i | AK4104_READ);
                if (ret < 0) {
                        dev_err(&spi->dev, "SPI write failure\n");
@@ -76,7 +74,7 @@ static unsigned int ak4104_read_reg_cache(struct snd_soc_codec *codec,
 {
        u8 *reg_cache = codec->reg_cache;
 
-       if (reg >= codec->reg_cache_size)
+       if (reg >= codec->driver->reg_cache_size)
                return -EINVAL;
 
        return reg_cache[reg];
@@ -88,7 +86,7 @@ static int ak4104_spi_write(struct snd_soc_codec *codec, unsigned int reg,
        u8 *cache = codec->reg_cache;
        struct spi_device *spi = codec->control_data;
 
-       if (reg >= codec->reg_cache_size)
+       if (reg >= codec->driver->reg_cache_size)
                return -EINVAL;
 
        /* only write to the hardware if value has changed */
@@ -145,8 +143,7 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        int val = 0;
 
        /* set the IEC958 bits: consumer mode, no copyright bit */
@@ -178,8 +175,8 @@ static struct snd_soc_dai_ops ak4101_dai_ops = {
        .set_fmt = ak4104_set_dai_fmt,
 };
 
-struct snd_soc_dai ak4104_dai = {
-       .name = DRV_NAME,
+static struct snd_soc_dai_driver ak4104_dai = {
+       .name = "ak4104-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -192,45 +189,17 @@ struct snd_soc_dai ak4104_dai = {
        .ops = &ak4101_dai_ops,
 };
 
-static struct snd_soc_codec *ak4104_codec;
-
-static int ak4104_spi_probe(struct spi_device *spi)
+static int ak4104_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec;
-       struct ak4104_private *ak4104;
+       struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
        int ret, val;
 
-       spi->bits_per_word = 8;
-       spi->mode = SPI_MODE_0;
-       ret = spi_setup(spi);
-       if (ret < 0)
-               return ret;
-
-       ak4104 = kzalloc(sizeof(struct ak4104_private), GFP_KERNEL);
-       if (!ak4104) {
-               dev_err(&spi->dev, "could not allocate codec\n");
-               return -ENOMEM;
-       }
-
-       codec = &ak4104->codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->dev = &spi->dev;
-       codec->name = DRV_NAME;
-       codec->owner = THIS_MODULE;
-       codec->dai = &ak4104_dai;
-       codec->num_dai = 1;
-       snd_soc_codec_set_drvdata(codec, ak4104);
-       codec->control_data = spi;
-       codec->reg_cache = ak4104->reg_cache;
-       codec->reg_cache_size = AK4104_NUM_REGS;
+       codec->control_data = ak4104->control_data;
 
        /* read all regs and fill the cache */
        ret = ak4104_fill_cache(codec);
        if (ret < 0) {
-               dev_err(&spi->dev, "failed to fill register cache\n");
+               dev_err(codec->dev, "failed to fill register cache\n");
                return ret;
        }
 
@@ -238,93 +207,81 @@ static int ak4104_spi_probe(struct spi_device *spi)
         * should contain 0x5b. Not a good way to verify the presence of
         * the device, but there is no hardware ID register. */
        if (ak4104_read_reg_cache(codec, AK4104_REG_RESERVED) !=
-                                        AK4104_RESERVED_VAL) {
-               ret = -ENODEV;
-               goto error_free_codec;
-       }
+                                        AK4104_RESERVED_VAL)
+               return -ENODEV;
 
        /* set power-up and non-reset bits */
        val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
        val |= AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN;
        ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
        if (ret < 0)
-               goto error_free_codec;
+               return ret;
 
        /* enable transmitter */
        val = ak4104_read_reg_cache(codec, AK4104_REG_TX);
        val |= AK4104_TX_TXE;
        ret = ak4104_spi_write(codec, AK4104_REG_TX, val);
        if (ret < 0)
-               goto error_free_codec;
-
-       ak4104_codec = codec;
-       ret = snd_soc_register_dai(&ak4104_dai);
-       if (ret < 0) {
-               dev_err(&spi->dev, "failed to register DAI\n");
-               goto error_free_codec;
-       }
+               return ret;
 
-       spi_set_drvdata(spi, ak4104);
-       dev_info(&spi->dev, "SPI device initialized\n");
+       dev_info(codec->dev, "SPI device initialized\n");
        return 0;
-
-error_free_codec:
-       kfree(ak4104);
-       ak4104_dai.dev = NULL;
-       return ret;
 }
 
-static int __devexit ak4104_spi_remove(struct spi_device *spi)
+static int ak4104_remove(struct snd_soc_codec *codec)
 {
-       int ret, val;
-       struct ak4104_private *ak4104 = spi_get_drvdata(spi);
+       int val, ret;
 
-       val = ak4104_read_reg_cache(&ak4104->codec, AK4104_REG_CONTROL1);
+       val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
        if (val < 0)
                return val;
 
        /* clear power-up and non-reset bits */
        val &= ~(AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
-       ret = ak4104_spi_write(&ak4104->codec, AK4104_REG_CONTROL1, val);
-       if (ret < 0)
-               return ret;
+       ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
 
-       ak4104_codec = NULL;
-       kfree(ak4104);
-       return 0;
+       return ret;
 }
 
-static int ak4104_probe(struct platform_device *pdev)
+static struct snd_soc_codec_driver soc_codec_device_ak4104 = {
+       .probe =        ak4104_probe,
+       .remove =       ak4104_remove,
+       .reg_cache_size = AK4104_NUM_REGS,
+       .reg_word_size = sizeof(u16),
+};
+
+static int ak4104_spi_probe(struct spi_device *spi)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = ak4104_codec;
+       struct ak4104_private *ak4104;
        int ret;
 
-       /* Connect the codec to the socdev.  snd_soc_new_pcms() needs this. */
-       socdev->card->codec = codec;
-
-       /* Register PCMs */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms\n");
+       spi->bits_per_word = 8;
+       spi->mode = SPI_MODE_0;
+       ret = spi_setup(spi);
+       if (ret < 0)
                return ret;
-       }
 
-       return 0;
+       ak4104 = kzalloc(sizeof(struct ak4104_private), GFP_KERNEL);
+       if (ak4104 == NULL)
+               return -ENOMEM;
+
+       ak4104->control_data = spi;
+       ak4104->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, ak4104);
+
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_device_ak4104, &ak4104_dai, 1);
+       if (ret < 0)
+               kfree(ak4104);
+       return ret;
 }
 
-static int ak4104_remove(struct platform_device *pdev)
+static int __devexit ak4104_spi_remove(struct spi_device *spi)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       snd_soc_free_pcms(socdev);
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
        return 0;
-};
-
-struct snd_soc_codec_device soc_codec_device_ak4104 = {
-       .probe =        ak4104_probe,
-       .remove =       ak4104_remove
-};
-EXPORT_SYMBOL_GPL(soc_codec_device_ak4104);
+}
 
 static struct spi_driver ak4104_spi_driver = {
        .driver  = {
diff --git a/sound/soc/codecs/ak4104.h b/sound/soc/codecs/ak4104.h
deleted file mode 100644 (file)
index eb88fe7..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef _AK4104_H
-#define _AK4104_H
-
-extern struct snd_soc_dai ak4104_dai;
-extern struct snd_soc_codec_device soc_codec_device_ak4104;
-
-#endif
index d4253675b2d386f6aaa4d5a7fa53a20ebc07d22d..cd88c8f32a3871da48e1f2b5d4874e5b23cc0b78 100644 (file)
 
 #define AK4535_VERSION "0.3"
 
-struct snd_soc_codec_device soc_codec_dev_ak4535;
-
 /* codec private data */
 struct ak4535_priv {
        unsigned int sysclk;
+       enum snd_soc_control_type control_type;
+       void *control_data;
 };
 
 /*
@@ -313,8 +313,7 @@ static int ak4535_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
        u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5);
        int rate = params_rate(params), fs = 256;
@@ -378,14 +377,16 @@ static int ak4535_mute(struct snd_soc_dai *dai, int mute)
 static int ak4535_set_bias_level(struct snd_soc_codec *codec,
        enum snd_soc_bias_level level)
 {
-       u16 i;
+       u16 i, mute_reg;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               ak4535_mute(codec->dai, 0);
+               mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
+               ak4535_write(codec, AK4535_DAC, mute_reg);
                break;
        case SND_SOC_BIAS_PREPARE:
-               ak4535_mute(codec->dai, 1);
+               mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
+               ak4535_write(codec, AK4535_DAC, mute_reg | 0x20);
                break;
        case SND_SOC_BIAS_STANDBY:
                i = ak4535_read_reg_cache(codec, AK4535_PM1);
@@ -413,8 +414,8 @@ static struct snd_soc_dai_ops ak4535_dai_ops = {
        .set_sysclk     = ak4535_set_dai_sysclk,
 };
 
-struct snd_soc_dai ak4535_dai = {
-       .name = "AK4535",
+static struct snd_soc_dai_driver ak4535_dai = {
+       .name = "ak4535-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -429,54 +430,27 @@ struct snd_soc_dai ak4535_dai = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
        .ops = &ak4535_dai_ops,
 };
-EXPORT_SYMBOL_GPL(ak4535_dai);
 
-static int ak4535_suspend(struct platform_device *pdev, pm_message_t state)
+static int ak4535_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int ak4535_resume(struct platform_device *pdev)
+static int ak4535_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        ak4535_sync(codec);
        ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        return 0;
 }
 
-/*
- * initialise the AK4535 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int ak4535_init(struct snd_soc_device *socdev)
+static int ak4535_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int ret = 0;
+       struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
 
-       codec->name = "AK4535";
-       codec->owner = THIS_MODULE;
-       codec->read = ak4535_read_reg_cache;
-       codec->write = ak4535_write;
-       codec->set_bias_level = ak4535_set_bias_level;
-       codec->dai = &ak4535_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(ak4535_reg);
-       codec->reg_cache = kmemdup(ak4535_reg, sizeof(ak4535_reg), GFP_KERNEL);
-
-       if (codec->reg_cache == NULL)
-               return -ENOMEM;
+       printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "ak4535: failed to create pcms\n");
-               goto pcm_err;
-       }
+       codec->control_data = ak4535->control_data;
 
        /* power on device */
        ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -485,39 +459,55 @@ static int ak4535_init(struct snd_soc_device *socdev)
                                ARRAY_SIZE(ak4535_snd_controls));
        ak4535_add_widgets(codec);
 
-       return ret;
-
-pcm_err:
-       kfree(codec->reg_cache);
+       return 0;
+}
 
-       return ret;
+/* power down chip */
+static int ak4535_remove(struct snd_soc_codec *codec)
+{
+       ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
 
-static struct snd_soc_device *ak4535_socdev;
+static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
+       .probe =        ak4535_probe,
+       .remove =       ak4535_remove,
+       .suspend =      ak4535_suspend,
+       .resume =       ak4535_resume,
+       .read = ak4535_read_reg_cache,
+       .write = ak4535_write,
+       .set_bias_level = ak4535_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(ak4535_reg),
+       .reg_word_size = sizeof(u8),
+       .reg_cache_default = ak4535_reg,
+};
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-static int ak4535_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+static __devinit int ak4535_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
-       struct snd_soc_device *socdev = ak4535_socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct ak4535_priv *ak4535;
        int ret;
 
-       i2c_set_clientdata(i2c, codec);
-       codec->control_data = i2c;
+       ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL);
+       if (ak4535 == NULL)
+               return -ENOMEM;
 
-       ret = ak4535_init(socdev);
-       if (ret < 0)
-               printk(KERN_ERR "failed to initialise AK4535\n");
+       i2c_set_clientdata(i2c, ak4535);
+       ak4535->control_data = i2c;
+       ak4535->control_type = SND_SOC_I2C;
 
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_ak4535, &ak4535_dai, 1);
+       if (ret < 0)
+               kfree(ak4535);
        return ret;
 }
 
-static int ak4535_i2c_remove(struct i2c_client *client)
+static __devexit int ak4535_i2c_remove(struct i2c_client *client)
 {
-       struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       kfree(codec->reg_cache);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -529,138 +519,34 @@ MODULE_DEVICE_TABLE(i2c, ak4535_i2c_id);
 
 static struct i2c_driver ak4535_i2c_driver = {
        .driver = {
-               .name = "AK4535 I2C Codec",
+               .name = "ak4535-codec",
                .owner = THIS_MODULE,
        },
        .probe =    ak4535_i2c_probe,
-       .remove =   ak4535_i2c_remove,
+       .remove =   __devexit_p(ak4535_i2c_remove),
        .id_table = ak4535_i2c_id,
 };
-
-static int ak4535_add_i2c_device(struct platform_device *pdev,
-                                const struct ak4535_setup_data *setup)
-{
-       struct i2c_board_info info;
-       struct i2c_adapter *adapter;
-       struct i2c_client *client;
-       int ret;
-
-       ret = i2c_add_driver(&ak4535_i2c_driver);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "can't add i2c driver\n");
-               return ret;
-       }
-
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       info.addr = setup->i2c_address;
-       strlcpy(info.type, "ak4535", I2C_NAME_SIZE);
-
-       adapter = i2c_get_adapter(setup->i2c_bus);
-       if (!adapter) {
-               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
-                       setup->i2c_bus);
-               goto err_driver;
-       }
-
-       client = i2c_new_device(adapter, &info);
-       i2c_put_adapter(adapter);
-       if (!client) {
-               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
-                       (unsigned int)info.addr);
-               goto err_driver;
-       }
-
-       return 0;
-
-err_driver:
-       i2c_del_driver(&ak4535_i2c_driver);
-       return -ENODEV;
-}
 #endif
 
-static int ak4535_probe(struct platform_device *pdev)
+static int __init ak4535_modinit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct ak4535_setup_data *setup;
-       struct snd_soc_codec *codec;
-       struct ak4535_priv *ak4535;
-       int ret;
-
-       printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
-
-       setup = socdev->codec_data;
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
-
-       ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL);
-       if (ak4535 == NULL) {
-               kfree(codec);
-               return -ENOMEM;
-       }
-
-       snd_soc_codec_set_drvdata(codec, ak4535);
-       socdev->card->codec = codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       ak4535_socdev = socdev;
-       ret = -ENODEV;
-
+       int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       if (setup->i2c_address) {
-               codec->hw_write = (hw_write_t)i2c_master_send;
-               ret = ak4535_add_i2c_device(pdev, setup);
-       }
-#endif
-
+       ret = i2c_add_driver(&ak4535_i2c_driver);
        if (ret != 0) {
-               kfree(snd_soc_codec_get_drvdata(codec));
-               kfree(codec);
+               printk(KERN_ERR "Failed to register AK4535 I2C driver: %d\n",
+                      ret);
        }
+#endif
        return ret;
 }
+module_init(ak4535_modinit);
 
-/* power down chip */
-static int ak4535_remove(struct platform_device *pdev)
+static void __exit ak4535_exit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec->control_data)
-               ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       if (codec->control_data)
-               i2c_unregister_device(codec->control_data);
        i2c_del_driver(&ak4535_i2c_driver);
 #endif
-       kfree(snd_soc_codec_get_drvdata(codec));
-       kfree(codec);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ak4535 = {
-       .probe =        ak4535_probe,
-       .remove =       ak4535_remove,
-       .suspend =      ak4535_suspend,
-       .resume =       ak4535_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535);
-
-static int __init ak4535_modinit(void)
-{
-       return snd_soc_register_dai(&ak4535_dai);
-}
-module_init(ak4535_modinit);
-
-static void __exit ak4535_exit(void)
-{
-       snd_soc_unregister_dai(&ak4535_dai);
 }
 module_exit(ak4535_exit);
 
index c7a58703ea394ccd30c79a359d4be1401b438710..0431e5f634a2440c8ef9f0206fe1c0959a6cd553 100644 (file)
 
 #define AK4535_CACHEREGNUM     0x10
 
-struct ak4535_setup_data {
-       int            i2c_bus;
-       unsigned short i2c_address;
-};
-
-extern struct snd_soc_dai ak4535_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ak4535;
-
 #endif
index 3d7dc55305ec3531838627e7a33f8b22009cfb2f..90c90b7f4a2ee553fcc8af76537da0c5ae7067ed 100644 (file)
@@ -30,8 +30,6 @@
 #include <sound/initval.h>
 #include <sound/tlv.h>
 
-#include "ak4642.h"
-
 #define AK4642_VERSION "0.0.1"
 
 #define PW_MGMT1       0x00
 
 #define AK4642_CACHEREGNUM     0x25
 
+/* PW_MGMT1*/
+#define PMVCM          (1 << 6) /* VCOM Power Management */
+#define PMMIN          (1 << 5) /* MIN Input Power Management */
+#define PMDAC          (1 << 2) /* DAC Power Management */
+#define PMADL          (1 << 0) /* MIC Amp Lch and ADC Lch Power Management */
+
 /* PW_MGMT2 */
 #define HPMTN          (1 << 6)
 #define PMHPL          (1 << 5)
 #define PMHP_MASK      (PMHPL | PMHPR)
 #define PMHP           PMHP_MASK
 
+/* PW_MGMT3 */
+#define PMADR          (1 << 0) /* MIC L / ADC R Power Management */
+
+/* SG_SL1 */
+#define MINS           (1 << 6) /* Switch from MIN to Speaker */
+#define DACL           (1 << 4) /* Switch from DAC to Stereo or Receiver */
+#define PMMP           (1 << 2) /* MPWR pin Power Management */
+#define MGAIN0         (1 << 0) /* MIC amp gain*/
+
+/* TIMER */
+#define ZTM(param)     ((param & 0x3) << 4) /* ALC Zoro Crossing TimeOut */
+#define WTM(param)     (((param & 0x4) << 4) | ((param & 0x3) << 2))
+
+/* ALC_CTL1 */
+#define ALC            (1 << 5) /* ALC Enable */
+#define LMTH0          (1 << 0) /* ALC Limiter / Recovery Level */
+
 /* MD_CTL1 */
 #define PLL3           (1 << 7)
 #define PLL2           (1 << 6)
 #define FS3            (1 << 5)
 #define FS_MASK                (FS0 | FS1 | FS2 | FS3)
 
-struct snd_soc_codec_device soc_codec_dev_ak4642;
+/* MD_CTL3 */
+#define BST1           (1 << 3)
+
+/* MD_CTL4 */
+#define DACH           (1 << 0)
 
 /*
  * Playback Volume (table 39)
@@ -123,11 +148,11 @@ static const struct snd_kcontrol_new ak4642_snd_controls[] = {
 
 /* codec private data */
 struct ak4642_priv {
-       struct snd_soc_codec codec;
+       unsigned int sysclk;
+       enum snd_soc_control_type control_type;
+       void *control_data;
 };
 
-static struct snd_soc_codec *ak4642_codec;
-
 /*
  * ak4642 register cache
  */
@@ -219,11 +244,12 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
                 * This operation came from example code of
                 * "ASAHI KASEI AK4642" (japanese) manual p97.
                 */
-               ak4642_write(codec, 0x0f, 0x09);
-               ak4642_write(codec, 0x0e, 0x19);
-               ak4642_write(codec, 0x09, 0x91);
-               ak4642_write(codec, 0x0c, 0x91);
-               ak4642_write(codec, 0x00, 0x64);
+               snd_soc_update_bits(codec, MD_CTL4, DACH, DACH);
+               snd_soc_update_bits(codec, MD_CTL3, BST1, BST1);
+               ak4642_write(codec, L_IVC, 0x91); /* volume */
+               ak4642_write(codec, R_IVC, 0x91); /* volume */
+               snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMMIN | PMDAC,
+                                                    PMVCM | PMMIN | PMDAC);
                snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP);
                snd_soc_update_bits(codec, PW_MGMT2, HPMTN,     HPMTN);
        } else {
@@ -240,13 +266,12 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
                 * This operation came from example code of
                 * "ASAHI KASEI AK4642" (japanese) manual p94.
                 */
-               ak4642_write(codec, 0x02, 0x05);
-               ak4642_write(codec, 0x06, 0x3c);
-               ak4642_write(codec, 0x08, 0xe1);
-               ak4642_write(codec, 0x0b, 0x00);
-               ak4642_write(codec, 0x07, 0x21);
-               ak4642_write(codec, 0x00, 0x41);
-               ak4642_write(codec, 0x10, 0x01);
+               ak4642_write(codec, SG_SL1, PMMP | MGAIN0);
+               ak4642_write(codec, TIMER, ZTM(0x3) | WTM(0x3));
+               ak4642_write(codec, ALC_CTL1, ALC | LMTH0);
+               snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMADL,
+                                                    PMVCM | PMADL);
+               snd_soc_update_bits(codec, PW_MGMT3, PMADR, PMADR);
        }
 
        return 0;
@@ -262,14 +287,14 @@ static void ak4642_dai_shutdown(struct snd_pcm_substream *substream,
                /* stop headphone output */
                snd_soc_update_bits(codec, PW_MGMT2, HPMTN,     0);
                snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, 0);
-               ak4642_write(codec, 0x00, 0x40);
-               ak4642_write(codec, 0x0e, 0x11);
-               ak4642_write(codec, 0x0f, 0x08);
+               snd_soc_update_bits(codec, PW_MGMT1, PMMIN | PMDAC, 0);
+               snd_soc_update_bits(codec, MD_CTL3, BST1, 0);
+               snd_soc_update_bits(codec, MD_CTL4, DACH, 0);
        } else {
                /* stop stereo input */
-               ak4642_write(codec, 0x00, 0x40);
-               ak4642_write(codec, 0x10, 0x00);
-               ak4642_write(codec, 0x07, 0x01);
+               snd_soc_update_bits(codec, PW_MGMT1, PMADL, 0);
+               snd_soc_update_bits(codec, PW_MGMT3, PMADR, 0);
+               snd_soc_update_bits(codec, ALC_CTL1, ALC, 0);
        }
 }
 
@@ -393,8 +418,8 @@ static struct snd_soc_dai_ops ak4642_dai_ops = {
        .hw_params      = ak4642_dai_hw_params,
 };
 
-struct snd_soc_dai ak4642_dai = {
-       .name = "AK4642",
+static struct snd_soc_dai_driver ak4642_dai = {
+       .name = "ak4642-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -410,112 +435,65 @@ struct snd_soc_dai ak4642_dai = {
        .ops = &ak4642_dai_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(ak4642_dai);
 
-static int ak4642_resume(struct platform_device *pdev)
+static int ak4642_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        ak4642_sync(codec);
        return 0;
 }
 
-/*
- * initialise the AK4642 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int ak4642_init(struct ak4642_priv *ak4642)
+
+static int ak4642_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = &ak4642->codec;
-       int ret = 0;
+       struct ak4642_priv *ak4642 = snd_soc_codec_get_drvdata(codec);
 
-       if (ak4642_codec) {
-               dev_err(codec->dev, "Another ak4642 is registered\n");
-               return -EINVAL;
-       }
+       dev_info(codec->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
 
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, ak4642);
-       codec->name             = "AK4642";
-       codec->owner            = THIS_MODULE;
-       codec->read             = ak4642_read_reg_cache;
-       codec->write            = ak4642_write;
-       codec->dai              = &ak4642_dai;
-       codec->num_dai          = 1;
        codec->hw_write         = (hw_write_t)i2c_master_send;
-       codec->reg_cache_size   = ARRAY_SIZE(ak4642_reg);
-       codec->reg_cache        = kmemdup(ak4642_reg,
-                                         sizeof(ak4642_reg), GFP_KERNEL);
+       codec->control_data     = ak4642->control_data;
 
-       if (!codec->reg_cache)
-               return -ENOMEM;
-
-       ak4642_dai.dev = codec->dev;
-       ak4642_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto reg_cache_err;
-       }
-
-       ret = snd_soc_register_dai(&ak4642_dai);
-       if (ret) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               snd_soc_unregister_codec(codec);
-               goto reg_cache_err;
-       }
-
-       return ret;
-
-reg_cache_err:
-       kfree(codec->reg_cache);
-       codec->reg_cache = NULL;
+       snd_soc_add_controls(codec, ak4642_snd_controls,
+                            ARRAY_SIZE(ak4642_snd_controls));
 
-       return ret;
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
+       .probe                  = ak4642_probe,
+       .resume                 = ak4642_resume,
+       .read                   = ak4642_read_reg_cache,
+       .write                  = ak4642_write,
+       .reg_cache_size         = ARRAY_SIZE(ak4642_reg),
+       .reg_word_size          = sizeof(u8),
+       .reg_cache_default      = ak4642_reg,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static int ak4642_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+static __devinit int ak4642_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
        struct ak4642_priv *ak4642;
-       struct snd_soc_codec *codec;
        int ret;
 
        ak4642 = kzalloc(sizeof(struct ak4642_priv), GFP_KERNEL);
        if (!ak4642)
                return -ENOMEM;
 
-       codec = &ak4642->codec;
-       codec->dev = &i2c->dev;
-
        i2c_set_clientdata(i2c, ak4642);
-       codec->control_data = i2c;
+       ak4642->control_data = i2c;
+       ak4642->control_type = SND_SOC_I2C;
 
-       ret = ak4642_init(ak4642);
-       if (ret < 0) {
-               printk(KERN_ERR "failed to initialise AK4642\n");
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_ak4642, &ak4642_dai, 1);
+       if (ret < 0)
                kfree(ak4642);
-       }
-
        return ret;
 }
 
-static int ak4642_i2c_remove(struct i2c_client *client)
+static __devexit int ak4642_i2c_remove(struct i2c_client *client)
 {
-       struct ak4642_priv *ak4642 = i2c_get_clientdata(client);
-
-       snd_soc_unregister_dai(&ak4642_dai);
-       snd_soc_unregister_codec(&ak4642->codec);
-       kfree(ak4642->codec.reg_cache);
-       kfree(ak4642);
-       ak4642_codec = NULL;
-
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -528,64 +506,15 @@ MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);
 
 static struct i2c_driver ak4642_i2c_driver = {
        .driver = {
-               .name = "AK4642 I2C Codec",
+               .name = "ak4642-codec",
                .owner = THIS_MODULE,
        },
        .probe          = ak4642_i2c_probe,
-       .remove         = ak4642_i2c_remove,
+       .remove         = __devexit_p(ak4642_i2c_remove),
        .id_table       = ak4642_i2c_id,
 };
-
 #endif
 
-static int ak4642_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       int ret;
-
-       if (!ak4642_codec) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = ak4642_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "ak4642: failed to create pcms\n");
-               goto pcm_err;
-       }
-
-       snd_soc_add_controls(ak4642_codec, ak4642_snd_controls,
-                            ARRAY_SIZE(ak4642_snd_controls));
-
-       dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
-       return ret;
-
-pcm_err:
-       return ret;
-
-}
-
-/* power down chip */
-static int ak4642_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ak4642 = {
-       .probe =        ak4642_probe,
-       .remove =       ak4642_remove,
-       .resume =       ak4642_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ak4642);
-
 static int __init ak4642_modinit(void)
 {
        int ret = 0;
diff --git a/sound/soc/codecs/ak4642.h b/sound/soc/codecs/ak4642.h
deleted file mode 100644 (file)
index e476833..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * ak4642.h  --  AK4642 Soc Audio driver
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on ak4535.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.
- */
-
-#ifndef _AK4642_H
-#define _AK4642_H
-
-extern struct snd_soc_dai ak4642_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ak4642;
-
-#endif
index 87566932a3b174c8afa318c679421882ff906356..24f5f49bb9d2cf9f5a84b205643b74ddfca47126 100644 (file)
 
 #include "ak4671.h"
 
-static struct snd_soc_codec *ak4671_codec;
 
 /* codec private data */
 struct ak4671_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+       void *control_data;
        u8 reg_cache[AK4671_CACHEREGNUM];
 };
 
@@ -619,8 +619,8 @@ static struct snd_soc_dai_ops ak4671_dai_ops = {
        .set_fmt        = ak4671_set_dai_fmt,
 };
 
-struct snd_soc_dai ak4671_dai = {
-       .name = "AK4671",
+static struct snd_soc_dai_driver ak4671_dai = {
+       .name = "ak4671-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -635,27 +635,18 @@ struct snd_soc_dai ak4671_dai = {
                .formats = AK4671_FORMATS,},
        .ops = &ak4671_dai_ops,
 };
-EXPORT_SYMBOL_GPL(ak4671_dai);
 
-static int ak4671_probe(struct platform_device *pdev)
+static int ak4671_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (ak4671_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
+       struct ak4671_priv *ak4671 = snd_soc_codec_get_drvdata(codec);
+       int ret;
 
-       socdev->card->codec = ak4671_codec;
-       codec = ak4671_codec;
+       codec->hw_write = (hw_write_t)i2c_master_send;
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4671->control_type);
        if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
        snd_soc_add_controls(codec, ak4671_snd_controls,
@@ -665,121 +656,48 @@ static int ak4671_probe(struct platform_device *pdev)
        ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return ret;
-
-pcm_err:
-       return ret;
 }
 
-static int ak4671_remove(struct platform_device *pdev)
+static int ak4671_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
+       ak4671_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_ak4671 = {
+static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
        .probe = ak4671_probe,
        .remove = ak4671_remove,
+       .set_bias_level = ak4671_set_bias_level,
+       .reg_cache_size = AK4671_CACHEREGNUM,
+       .reg_word_size = sizeof(u8),
+       .reg_cache_default = ak4671_reg,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_ak4671);
-
-static int ak4671_register(struct ak4671_priv *ak4671,
-               enum snd_soc_control_type control)
-{
-       int ret;
-       struct snd_soc_codec *codec = &ak4671->codec;
-
-       if (ak4671_codec) {
-               dev_err(codec->dev, "Another AK4671 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec,  ak4671);
-       codec->name = "AK4671";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = ak4671_set_bias_level;
-       codec->dai = &ak4671_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = AK4671_CACHEREGNUM;
-       codec->reg_cache = &ak4671->reg_cache;
-
-       memcpy(codec->reg_cache, ak4671_reg, sizeof(ak4671_reg));
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, control);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
-       }
-
-       ak4671_dai.dev = codec->dev;
-       ak4671_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dai(&ak4671_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
-
-       return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(ak4671);
-       return ret;
-}
-
-static void ak4671_unregister(struct ak4671_priv *ak4671)
-{
-       ak4671_set_bias_level(&ak4671->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dai(&ak4671_dai);
-       snd_soc_unregister_codec(&ak4671->codec);
-       kfree(ak4671);
-       ak4671_codec = NULL;
-}
 
 static int __devinit ak4671_i2c_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
        struct ak4671_priv *ak4671;
-       struct snd_soc_codec *codec;
+       int ret;
 
        ak4671 = kzalloc(sizeof(struct ak4671_priv), GFP_KERNEL);
        if (ak4671 == NULL)
                return -ENOMEM;
 
-       codec = &ak4671->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
        i2c_set_clientdata(client, ak4671);
-       codec->control_data = client;
-
-       codec->dev = &client->dev;
+       ak4671->control_data = client;
+       ak4671->control_type = SND_SOC_I2C;
 
-       return ak4671_register(ak4671, SND_SOC_I2C);
+       ret = snd_soc_register_codec(&client->dev,
+                       &soc_codec_dev_ak4671, &ak4671_dai, 1);
+       if (ret < 0)
+               kfree(ak4671);
+       return ret;
 }
 
 static __devexit int ak4671_i2c_remove(struct i2c_client *client)
 {
-       struct ak4671_priv *ak4671 = i2c_get_clientdata(client);
-
-       ak4671_unregister(ak4671);
-
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -791,7 +709,7 @@ MODULE_DEVICE_TABLE(i2c, ak4671_i2c_id);
 
 static struct i2c_driver ak4671_i2c_driver = {
        .driver = {
-               .name = "ak4671",
+               .name = "ak4671-codec",
                .owner = THIS_MODULE,
        },
        .probe = ak4671_i2c_probe,
index e2fad964e88b125e54a58967743d2e2837a676ad..61cb7ab7552ce5a390fd1306905214a60bdd442e 100644 (file)
 /* AK4671_LOUT2_POWER_MANAGEMENT (0x10) Fields */
 #define AK4671_MUTEN                           0x04
 
-extern struct snd_soc_dai ak4671_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ak4671;
-
 #endif
index a320fb5a0e26afefba683311539584a71c6ade7c..823643932dde2eb6208fd290f90254a2416e29bc 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/mfd/davinci_voicecodec.h>
+#include <linux/spi/spi.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -41,8 +42,6 @@
 
 #include <mach/dm365.h>
 
-#include "cq93vc.h"
-
 static inline unsigned int cq93vc_read(struct snd_soc_codec *codec,
                                                unsigned int reg)
 {
@@ -130,8 +129,8 @@ static struct snd_soc_dai_ops cq93vc_dai_ops = {
        .set_sysclk     = cq93vc_set_dai_sysclk,
 };
 
-struct snd_soc_dai cq93vc_dai = {
-       .name = "CQ93VC",
+static struct snd_soc_dai_driver cq93vc_dai = {
+       .name = "cq93vc-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -146,36 +145,20 @@ struct snd_soc_dai cq93vc_dai = {
                .formats = CQ93VC_FORMATS,},
        .ops = &cq93vc_dai_ops,
 };
-EXPORT_SYMBOL_GPL(cq93vc_dai);
 
-static int cq93vc_resume(struct platform_device *pdev)
+static int cq93vc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
 }
 
-static struct snd_soc_codec *cq93vc_codec;
-
-static int cq93vc_probe(struct platform_device *pdev)
+static int cq93vc_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct device *dev = &pdev->dev;
-       struct snd_soc_codec *codec;
-       int ret;
-
-       socdev->card->codec = cq93vc_codec;
-       codec = socdev->card->codec;
-
-       /* Register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(dev, "%s: failed to create pcms\n", pdev->name);
-               return ret;
-       }
+       struct davinci_vc *davinci_vc = codec->dev->platform_data;
+
+       davinci_vc->cq93vc.codec = codec;
+       codec->control_data = davinci_vc;
 
        /* Set controls */
        snd_soc_add_controls(codec, cq93vc_snd_controls,
@@ -187,108 +170,51 @@ static int cq93vc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int cq93vc_remove(struct platform_device *pdev)
+static int cq93vc_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
+       cq93vc_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_cq93vc = {
+static struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
+       .read = cq93vc_read,
+       .write = cq93vc_write,
+       .set_bias_level = cq93vc_set_bias_level,
        .probe = cq93vc_probe,
        .remove = cq93vc_remove,
        .resume = cq93vc_resume,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_cq93vc);
 
-static __init int cq93vc_codec_probe(struct platform_device *pdev)
+static int cq93vc_platform_probe(struct platform_device *pdev)
 {
-       struct davinci_vc *davinci_vc = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret;
-
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL) {
-               dev_dbg(davinci_vc->dev,
-                       "could not allocate memory for codec data\n");
-               return -ENOMEM;
-       }
-
-       davinci_vc->cq93vc.codec = codec;
-
-       cq93vc_dai.dev = &pdev->dev;
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-       codec->dev = &pdev->dev;
-       codec->name = "CQ93VC";
-       codec->owner = THIS_MODULE;
-       codec->read = cq93vc_read;
-       codec->write = cq93vc_write;
-       codec->set_bias_level = cq93vc_set_bias_level;
-       codec->dai = &cq93vc_dai;
-       codec->num_dai = 1;
-       codec->control_data = davinci_vc;
-
-       cq93vc_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret) {
-               dev_err(davinci_vc->dev, "failed to register codec\n");
-               goto fail1;
-       }
-
-       ret = snd_soc_register_dai(&cq93vc_dai);
-       if (ret) {
-               dev_err(davinci_vc->dev, "could register dai\n");
-               goto fail2;
-       }
-       return 0;
-
-fail2:
-       snd_soc_unregister_codec(codec);
-
-fail1:
-       kfree(codec);
-       cq93vc_codec = NULL;
-
-       return ret;
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_cq93vc, &cq93vc_dai, 1);
 }
 
-static int __devexit cq93vc_codec_remove(struct platform_device *pdev)
+static int cq93vc_platform_remove(struct platform_device *pdev)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       snd_soc_unregister_dai(&cq93vc_dai);
-       snd_soc_unregister_codec(&codec);
-
-       kfree(codec);
-       cq93vc_codec = NULL;
-
+       snd_soc_unregister_codec(&pdev->dev);
        return 0;
 }
 
 static struct platform_driver cq93vc_codec_driver = {
        .driver = {
-                  .name = "cq93vc",
-                  .owner = THIS_MODULE,
-                  },
-       .probe = cq93vc_codec_probe,
-       .remove = __devexit_p(cq93vc_codec_remove),
+                       .name = "cq93vc-codec",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = cq93vc_platform_probe,
+       .remove = __devexit_p(cq93vc_platform_remove),
 };
 
-static __init int cq93vc_init(void)
+static int __init cq93vc_init(void)
 {
-       return platform_driver_probe(&cq93vc_codec_driver, cq93vc_codec_probe);
+       return platform_driver_register(&cq93vc_codec_driver);
 }
 module_init(cq93vc_init);
 
-static __exit void cq93vc_exit(void)
+static void __exit cq93vc_exit(void)
 {
        platform_driver_unregister(&cq93vc_codec_driver);
 }
diff --git a/sound/soc/codecs/cq93vc.h b/sound/soc/codecs/cq93vc.h
deleted file mode 100644 (file)
index 845b196..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * ALSA SoC CQ0093 Voice Codec Driver for DaVinci platforms
- *
- * Copyright (C) 2010 Texas Instruments, Inc
- *
- * Author: Miguel Aguilar <miguel.aguilar@ridgerun.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _CQ93VC_H
-#define _CQ93VC_H
-
-extern struct snd_soc_dai cq93vc_dai;
-extern struct snd_soc_codec_device soc_codec_dev_cq93vc;
-
-#endif
index 30d949239def0727127497f6a8f5c92f6885d386..6d4bdc609ac87db254e6a145f35b952509c92a2f 100644 (file)
@@ -31,8 +31,6 @@
 #include <linux/delay.h>
 #include <linux/regulator/consumer.h>
 
-#include "cs4270.h"
-
 /*
  * The codec isn't really big-endian or little-endian, since the I2S
  * interface requires data to be sent serially with the MSbit first.
@@ -114,7 +112,8 @@ static const char *supply_names[] = {
 
 /* Private data for the CS4270 */
 struct cs4270_private {
-       struct snd_soc_codec codec;
+       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) */
@@ -212,44 +211,8 @@ static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
-       unsigned int rates = 0;
-       unsigned int rate_min = -1;
-       unsigned int rate_max = 0;
-       unsigned int i;
 
        cs4270->mclk = freq;
-
-       if (cs4270->mclk) {
-               for (i = 0; i < NUM_MCLK_RATIOS; i++) {
-                       unsigned int rate = freq / cs4270_mode_ratios[i].ratio;
-                       rates |= snd_pcm_rate_to_rate_bit(rate);
-                       if (rate < rate_min)
-                               rate_min = rate;
-                       if (rate > rate_max)
-                               rate_max = rate;
-               }
-               /* FIXME: soc should support a rate list */
-               rates &= ~SNDRV_PCM_RATE_KNOT;
-
-               if (!rates) {
-                       dev_err(codec->dev, "could not find a valid sample rate\n");
-                       return -EINVAL;
-               }
-       } else {
-               /* enable all possible rates */
-               rates = SNDRV_PCM_RATE_8000_192000;
-               rate_min = 8000;
-               rate_max = 192000;
-       }
-
-       codec_dai->playback.rates = rates;
-       codec_dai->playback.rate_min = rate_min;
-       codec_dai->playback.rate_max = rate_max;
-
-       codec_dai->capture.rates = rates;
-       codec_dai->capture.rate_min = rate_min;
-       codec_dai->capture.rate_max = rate_max;
-
        return 0;
 }
 
@@ -410,8 +373,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
        int ret;
        unsigned int i;
@@ -549,19 +511,6 @@ static const struct snd_kcontrol_new cs4270_snd_controls[] = {
                snd_soc_get_volsw, cs4270_soc_put_mute),
 };
 
-/*
- * cs4270_codec - global variable to store codec for the ASoC probe function
- *
- * If struct i2c_driver had a private_data field, we wouldn't need to use
- * cs4270_codec.  This is the only way to pass the codec structure from
- * cs4270_i2c_probe() to cs4270_probe().  Unfortunately, there is no good
- * way to synchronize these two functions.  cs4270_i2c_probe() can be called
- * multiple times before cs4270_probe() is called even once.  So for now, we
- * also only allow cs4270_i2c_probe() to be run once.  That means that we do
- * not support more than one cs4270 device in the system, at least for now.
- */
-static struct snd_soc_codec *cs4270_codec;
-
 static struct snd_soc_dai_ops cs4270_dai_ops = {
        .hw_params      = cs4270_hw_params,
        .set_sysclk     = cs4270_set_dai_sysclk,
@@ -569,25 +518,28 @@ static struct snd_soc_dai_ops cs4270_dai_ops = {
        .digital_mute   = cs4270_dai_mute,
 };
 
-struct snd_soc_dai cs4270_dai = {
-       .name = "cs4270",
+static struct snd_soc_dai_driver cs4270_dai = {
+       .name = "cs4270-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
                .channels_max = 2,
-               .rates = 0,
+               .rates = SNDRV_PCM_RATE_CONTINUOUS,
+               .rate_min = 4000,
+               .rate_max = 216000,
                .formats = CS4270_FORMATS,
        },
        .capture = {
                .stream_name = "Capture",
                .channels_min = 1,
                .channels_max = 2,
-               .rates = 0,
+               .rates = SNDRV_PCM_RATE_CONTINUOUS,
+               .rate_min = 4000,
+               .rate_max = 216000,
                .formats = CS4270_FORMATS,
        },
        .ops = &cs4270_dai_ops,
 };
-EXPORT_SYMBOL_GPL(cs4270_dai);
 
 /**
  * cs4270_probe - ASoC probe function
@@ -596,153 +548,19 @@ EXPORT_SYMBOL_GPL(cs4270_dai);
  * This function is called when ASoC has all the pieces it needs to
  * instantiate a sound driver.
  */
-static int cs4270_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = cs4270_codec;
-       struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
-       int i, ret;
-
-       /* Connect the codec to the socdev.  snd_soc_new_pcms() needs this. */
-       socdev->card->codec = codec;
-
-       /* Register PCMs */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms\n");
-               return ret;
-       }
-
-       /* Add the non-DAPM controls */
-       ret = snd_soc_add_controls(codec, cs4270_snd_controls,
-                               ARRAY_SIZE(cs4270_snd_controls));
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to add controls\n");
-               goto error_free_pcms;
-       }
-
-       /* get the power supply regulators */
-       for (i = 0; i < ARRAY_SIZE(supply_names); i++)
-               cs4270->supplies[i].supply = supply_names[i];
-
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(cs4270->supplies),
-                                cs4270->supplies);
-       if (ret < 0)
-               goto error_free_pcms;
-
-       ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
-                                   cs4270->supplies);
-       if (ret < 0)
-               goto error_free_regulators;
-
-       return 0;
-
-error_free_regulators:
-       regulator_bulk_free(ARRAY_SIZE(cs4270->supplies),
-                           cs4270->supplies);
-
-error_free_pcms:
-       snd_soc_free_pcms(socdev);
-
-       return ret;
-}
-
-/**
- * cs4270_remove - ASoC remove function
- * @pdev: platform device
- *
- * This function is the counterpart to cs4270_probe().
- */
-static int cs4270_remove(struct platform_device *pdev)
+static int cs4270_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = cs4270_codec;
        struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
+       int i, ret, reg;
 
-       snd_soc_free_pcms(socdev);
-       regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
-       regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
-
-       return 0;
-};
-
-/**
- * cs4270_i2c_probe - initialize the I2C interface of the CS4270
- * @i2c_client: the I2C client object
- * @id: the I2C device ID (ignored)
- *
- * This function is called whenever the I2C subsystem finds a device that
- * matches the device ID given via a prior call to i2c_add_driver().
- */
-static int cs4270_i2c_probe(struct i2c_client *i2c_client,
-       const struct i2c_device_id *id)
-{
-       struct snd_soc_codec *codec;
-       struct cs4270_private *cs4270;
-       unsigned int reg;
-       int ret;
-
-       /* For now, we only support one cs4270 device in the system.  See the
-        * comment for cs4270_codec.
-        */
-       if (cs4270_codec) {
-               dev_err(&i2c_client->dev, "ignoring CS4270 at addr %X\n",
-                      i2c_client->addr);
-               dev_err(&i2c_client->dev, "only one per board allowed\n");
-               /* Should we return something other than ENODEV here? */
-               return -ENODEV;
-       }
-
-       /* Verify that we have a CS4270 */
-
-       ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);
-       if (ret < 0) {
-               dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n",
-                      i2c_client->addr);
-               return ret;
-       }
-       /* The top four bits of the chip ID should be 1100. */
-       if ((ret & 0xF0) != 0xC0) {
-               dev_err(&i2c_client->dev, "device at addr %X is not a CS4270\n",
-                      i2c_client->addr);
-               return -ENODEV;
-       }
-
-       dev_info(&i2c_client->dev, "found device at i2c address %X\n",
-               i2c_client->addr);
-       dev_info(&i2c_client->dev, "hardware revision %X\n", ret & 0xF);
-
-       /* Allocate enough space for the snd_soc_codec structure
-          and our private data together. */
-       cs4270 = kzalloc(sizeof(struct cs4270_private), GFP_KERNEL);
-       if (!cs4270) {
-               dev_err(&i2c_client->dev, "could not allocate codec\n");
-               return -ENOMEM;
-       }
-       codec = &cs4270->codec;
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->dev = &i2c_client->dev;
-       codec->name = "CS4270";
-       codec->owner = THIS_MODULE;
-       codec->dai = &cs4270_dai;
-       codec->num_dai = 1;
-       snd_soc_codec_set_drvdata(codec, cs4270);
-       codec->control_data = i2c_client;
-       codec->read = cs4270_read_reg_cache;
-       codec->write = cs4270_i2c_write;
-       codec->reg_cache = cs4270->reg_cache;
-       codec->reg_cache_size = CS4270_NUMREGS;
+       codec->control_data = cs4270->control_data;
 
        /* The I2C interface is set up, so pre-fill our register cache */
 
        ret = cs4270_fill_cache(codec);
        if (ret < 0) {
-               dev_err(&i2c_client->dev, "failed to fill register cache\n");
-               goto error_free_codec;
+               dev_err(codec->dev, "failed to fill register cache\n");
+               return ret;
        }
 
        /* Disable auto-mute.  This feature appears to be buggy.  In some
@@ -755,7 +573,7 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
        reg &= ~CS4270_MUTE_AUTO;
        ret = cs4270_i2c_write(codec, CS4270_MUTE, reg);
        if (ret < 0) {
-               dev_err(&i2c_client->dev, "i2c write failed\n");
+               dev_err(codec->dev, "i2c write failed\n");
                return ret;
        }
 
@@ -769,65 +587,56 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
        reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO);
        ret = cs4270_i2c_write(codec, CS4270_TRANS, reg);
        if (ret < 0) {
-               dev_err(&i2c_client->dev, "i2c write failed\n");
+               dev_err(codec->dev, "i2c write failed\n");
                return ret;
        }
 
-       /* Initialize the DAI. Normally, we'd prefer to have a kmalloc'd DAI
-        * structure for each CS4270 device, but the machine driver needs to
-        * have a pointer to the DAI structure, so for now it must be a global
-        * variable.
-        */
-       cs4270_dai.dev = &i2c_client->dev;
-
-       /* Register the DAI.  If all the other ASoC driver have already
-        * registered, then this will call our probe function, so
-        * cs4270_codec needs to be ready.
-        */
-       cs4270_codec = codec;
-       ret = snd_soc_register_dai(&cs4270_dai);
+       /* Add the non-DAPM controls */
+       ret = snd_soc_add_controls(codec, cs4270_snd_controls,
+                               ARRAY_SIZE(cs4270_snd_controls));
        if (ret < 0) {
-               dev_err(&i2c_client->dev, "failed to register DAIe\n");
-               goto error_free_codec;
+               dev_err(codec->dev, "failed to add controls\n");
+               return ret;
        }
 
-       i2c_set_clientdata(i2c_client, cs4270);
+       /* get the power supply regulators */
+       for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+               cs4270->supplies[i].supply = supply_names[i];
+
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(cs4270->supplies),
+                                cs4270->supplies);
+       if (ret < 0)
+               return ret;
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
+                                   cs4270->supplies);
+       if (ret < 0)
+               goto error_free_regulators;
 
        return 0;
 
-error_free_codec:
-       kfree(cs4270);
-       cs4270_codec = NULL;
-       cs4270_dai.dev = NULL;
+error_free_regulators:
+       regulator_bulk_free(ARRAY_SIZE(cs4270->supplies),
+                           cs4270->supplies);
 
        return ret;
 }
 
 /**
- * cs4270_i2c_remove - remove an I2C device
- * @i2c_client: the I2C client object
+ * cs4270_remove - ASoC remove function
+ * @pdev: platform device
  *
- * This function is the counterpart to cs4270_i2c_probe().
+ * This function is the counterpart to cs4270_probe().
  */
-static int cs4270_i2c_remove(struct i2c_client *i2c_client)
+static int cs4270_remove(struct snd_soc_codec *codec)
 {
-       struct cs4270_private *cs4270 = i2c_get_clientdata(i2c_client);
+       struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
 
-       kfree(cs4270);
-       cs4270_codec = NULL;
-       cs4270_dai.dev = NULL;
+       regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
+       regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
 
        return 0;
-}
-
-/*
- * cs4270_id - I2C device IDs supported by this driver
- */
-static struct i2c_device_id cs4270_id[] = {
-       {"cs4270", 0},
-       {}
 };
-MODULE_DEVICE_TABLE(i2c, cs4270_id);
 
 #ifdef CONFIG_PM
 
@@ -840,9 +649,8 @@ MODULE_DEVICE_TABLE(i2c, cs4270_id);
  * and all registers are written back to the hardware when resuming.
  */
 
-static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg)
+static int cs4270_soc_suspend(struct snd_soc_codec *codec, pm_message_t mesg)
 {
-       struct snd_soc_codec *codec = cs4270_codec;
        struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
        int reg, ret;
 
@@ -860,9 +668,8 @@ static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg)
        return 0;
 }
 
-static int cs4270_soc_resume(struct platform_device *pdev)
+static int cs4270_soc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = cs4270_codec;
        struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
        struct i2c_client *i2c_client = codec->control_data;
        int reg;
@@ -895,6 +702,95 @@ static int cs4270_soc_resume(struct platform_device *pdev)
 #define cs4270_soc_resume      NULL
 #endif /* CONFIG_PM */
 
+/*
+ * ASoC codec device structure
+ *
+ * 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),
+};
+
+/**
+ * cs4270_i2c_probe - initialize the I2C interface of the CS4270
+ * @i2c_client: the I2C client object
+ * @id: the I2C device ID (ignored)
+ *
+ * This function is called whenever the I2C subsystem finds a device that
+ * matches the device ID given via a prior call to i2c_add_driver().
+ */
+static int cs4270_i2c_probe(struct i2c_client *i2c_client,
+       const struct i2c_device_id *id)
+{
+       struct cs4270_private *cs4270;
+       int ret;
+
+       /* Verify that we have a CS4270 */
+
+       ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);
+       if (ret < 0) {
+               dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n",
+                      i2c_client->addr);
+               return ret;
+       }
+       /* The top four bits of the chip ID should be 1100. */
+       if ((ret & 0xF0) != 0xC0) {
+               dev_err(&i2c_client->dev, "device at addr %X is not a CS4270\n",
+                      i2c_client->addr);
+               return -ENODEV;
+       }
+
+       dev_info(&i2c_client->dev, "found device at i2c address %X\n",
+               i2c_client->addr);
+       dev_info(&i2c_client->dev, "hardware revision %X\n", ret & 0xF);
+
+       cs4270 = kzalloc(sizeof(struct cs4270_private), GFP_KERNEL);
+       if (!cs4270) {
+               dev_err(&i2c_client->dev, "could not allocate codec\n");
+               return -ENOMEM;
+       }
+
+       i2c_set_clientdata(i2c_client, cs4270);
+       cs4270->control_data = i2c_client;
+       cs4270->control_type = SND_SOC_I2C;
+
+       ret = snd_soc_register_codec(&i2c_client->dev,
+                       &soc_codec_device_cs4270, &cs4270_dai, 1);
+       if (ret < 0)
+               kfree(cs4270);
+       return ret;
+}
+
+/**
+ * cs4270_i2c_remove - remove an I2C device
+ * @i2c_client: the I2C client object
+ *
+ * This function is the counterpart to cs4270_i2c_probe().
+ */
+static int cs4270_i2c_remove(struct i2c_client *i2c_client)
+{
+       snd_soc_unregister_codec(&i2c_client->dev);
+       kfree(i2c_get_clientdata(i2c_client));
+       return 0;
+}
+
+/*
+ * cs4270_id - I2C device IDs supported by this driver
+ */
+static struct i2c_device_id cs4270_id[] = {
+       {"cs4270", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, cs4270_id);
+
 /*
  * cs4270_i2c_driver - I2C device identification
  *
@@ -903,7 +799,7 @@ static int cs4270_soc_resume(struct platform_device *pdev)
  */
 static struct i2c_driver cs4270_i2c_driver = {
        .driver = {
-               .name = "cs4270",
+               .name = "cs4270-codec",
                .owner = THIS_MODULE,
        },
        .id_table = cs4270_id,
@@ -911,20 +807,6 @@ static struct i2c_driver cs4270_i2c_driver = {
        .remove = cs4270_i2c_remove,
 };
 
-/*
- * ASoC codec device structure
- *
- * Assign this variable to the codec_dev field of the machine driver's
- * snd_soc_device structure.
- */
-struct snd_soc_codec_device soc_codec_device_cs4270 = {
-       .probe =        cs4270_probe,
-       .remove =       cs4270_remove,
-       .suspend =      cs4270_soc_suspend,
-       .resume =       cs4270_soc_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_device_cs4270);
-
 static int __init cs4270_init(void)
 {
        pr_info("Cirrus Logic CS4270 ALSA SoC Codec Driver\n");
diff --git a/sound/soc/codecs/cs4270.h b/sound/soc/codecs/cs4270.h
deleted file mode 100644 (file)
index adc6cd9..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Cirrus Logic CS4270 ALSA SoC Codec Driver
- *
- * Author: Timur Tabi <timur@freescale.com>
- *
- * Copyright 2007 Freescale Semiconductor, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef _CS4270_H
-#define _CS4270_H
-
-/*
- * The ASoC codec DAI structure for the CS4270.  Assign this structure to
- * the .codec_dai field of your machine driver's snd_soc_dai_link structure.
- */
-extern struct snd_soc_dai cs4270_dai;
-
-/*
- * The ASoC codec device structure for the CS4270.  Assign this structure
- * to the .codec_dev field of your machine driver's snd_soc_device
- * structure.
- */
-extern struct snd_soc_codec_device soc_codec_device_cs4270;
-
-#endif
index dd9b8550c402bcb65f2757ecc4123ba6c6c3c219..cb086eaf4e07dd3382331acd9009f81f2e3647fd 100644 (file)
@@ -42,15 +42,14 @@ enum master_slave_mode {
 };
 
 struct cs42l51_private {
+       enum snd_soc_control_type control_type;
+       void *control_data;
        unsigned int mclk;
        unsigned int audio_mode;        /* The mode (I2S or left-justified) */
        enum master_slave_mode func;
-       struct snd_soc_codec codec;
        u8 reg_cache[CS42L51_NUMREGS];
 };
 
-static struct snd_soc_codec *cs42l51_codec;
-
 #define CS42L51_FORMATS ( \
                SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S16_BE  | \
                SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
@@ -75,134 +74,6 @@ static int cs42l51_fill_cache(struct snd_soc_codec *codec)
        return 0;
 }
 
-static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
-       const struct i2c_device_id *id)
-{
-       struct snd_soc_codec *codec;
-       struct cs42l51_private *cs42l51;
-       int ret = 0;
-       int reg;
-
-       if (cs42l51_codec)
-               return -EBUSY;
-
-       /* Verify that we have a CS42L51 */
-       ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID);
-       if (ret < 0) {
-               dev_err(&i2c_client->dev, "failed to read I2C\n");
-               goto error;
-       }
-
-       if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
-           (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
-               dev_err(&i2c_client->dev, "Invalid chip id\n");
-               ret = -ENODEV;
-               goto error;
-       }
-
-       dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
-                               ret & 7);
-
-       cs42l51 = kzalloc(sizeof(struct cs42l51_private), GFP_KERNEL);
-       if (!cs42l51) {
-               dev_err(&i2c_client->dev, "could not allocate codec\n");
-               return -ENOMEM;
-       }
-       codec = &cs42l51->codec;
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->dev = &i2c_client->dev;
-       codec->name = "CS42L51";
-       codec->owner = THIS_MODULE;
-       codec->dai = &cs42l51_dai;
-       codec->num_dai = 1;
-       snd_soc_codec_set_drvdata(codec, cs42l51);
-
-       codec->control_data = i2c_client;
-       codec->reg_cache = cs42l51->reg_cache;
-       codec->reg_cache_size = CS42L51_NUMREGS;
-       i2c_set_clientdata(i2c_client, codec);
-
-       ret = cs42l51_fill_cache(codec);
-       if (ret < 0) {
-               dev_err(&i2c_client->dev, "failed to fill register cache\n");
-               goto error_alloc;
-       }
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
-       if (ret < 0) {
-               dev_err(&i2c_client->dev, "Failed to set cache I/O: %d\n", ret);
-               goto error_alloc;
-       }
-
-       /*
-        * DAC configuration
-        * - Use signal processor
-        * - auto mute
-        * - vol changes immediate
-        * - no de-emphasize
-        */
-       reg = CS42L51_DAC_CTL_DATA_SEL(1)
-               | CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
-       ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg);
-       if (ret < 0)
-               goto error_alloc;
-
-       cs42l51_dai.dev = codec->dev;
-       cs42l51_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto error_alloc;
-       }
-
-       ret = snd_soc_register_dai(&cs42l51_dai);
-       if (ret < 0) {
-               dev_err(&i2c_client->dev, "failed to register DAIe\n");
-               goto error_reg;
-       }
-
-       return 0;
-
-error_reg:
-       snd_soc_unregister_codec(codec);
-error_alloc:
-       kfree(cs42l51);
-error:
-       return ret;
-}
-
-static int cs42l51_i2c_remove(struct i2c_client *client)
-{
-       struct cs42l51_private *cs42l51 = i2c_get_clientdata(client);
-       snd_soc_unregister_dai(&cs42l51_dai);
-       snd_soc_unregister_codec(cs42l51_codec);
-       cs42l51_codec = NULL;
-       kfree(cs42l51);
-       return 0;
-}
-
-
-static const struct i2c_device_id cs42l51_id[] = {
-       {"cs42l51", 0},
-       {}
-};
-MODULE_DEVICE_TABLE(i2c, cs42l51_id);
-
-static struct i2c_driver cs42l51_i2c_driver = {
-       .driver = {
-               .name = "CS42L51 I2C",
-               .owner = THIS_MODULE,
-       },
-       .id_table = cs42l51_id,
-       .probe = cs42l51_i2c_probe,
-       .remove = cs42l51_i2c_remove,
-};
-
 static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
                        struct snd_ctl_elem_value *ucontrol)
 {
@@ -484,51 +355,8 @@ static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
-       struct cs42l51_ratios *ratios = NULL;
-       int nr_ratios = 0;
-       unsigned int rates = 0;
-       unsigned int rate_min = -1;
-       unsigned int rate_max = 0;
-       int i;
 
        cs42l51->mclk = freq;
-
-       switch (cs42l51->func) {
-       case MODE_MASTER:
-               return -EINVAL;
-       case MODE_SLAVE:
-               ratios = slave_ratios;
-               nr_ratios = ARRAY_SIZE(slave_ratios);
-               break;
-       case MODE_SLAVE_AUTO:
-               ratios = slave_auto_ratios;
-               nr_ratios = ARRAY_SIZE(slave_auto_ratios);
-               break;
-       }
-
-       for (i = 0; i < nr_ratios; i++) {
-               unsigned int rate = freq / ratios[i].ratio;
-               rates |= snd_pcm_rate_to_rate_bit(rate);
-               if (rate < rate_min)
-                       rate_min = rate;
-               if (rate > rate_max)
-                       rate_max = rate;
-       }
-       rates &= ~SNDRV_PCM_RATE_KNOT;
-
-       if (!rates) {
-               dev_err(codec->dev, "could not find a valid sample rate\n");
-               return -EINVAL;
-       }
-
-       codec_dai->playback.rates = rates;
-       codec_dai->playback.rate_min = rate_min;
-       codec_dai->playback.rate_max = rate_max;
-
-       codec_dai->capture.rates = rates;
-       codec_dai->capture.rate_min = rate_min;
-       codec_dai->capture.rate_max = rate_max;
-
        return 0;
 }
 
@@ -537,8 +365,7 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
        int ret;
        unsigned int i;
@@ -670,8 +497,8 @@ static struct snd_soc_dai_ops cs42l51_dai_ops = {
        .digital_mute   = cs42l51_dai_mute,
 };
 
-struct snd_soc_dai cs42l51_dai = {
-       .name = "CS42L51 HiFi",
+static struct snd_soc_dai_driver cs42l51_dai = {
+       .name = "cs42l51-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -688,30 +515,39 @@ struct snd_soc_dai cs42l51_dai = {
        },
        .ops = &cs42l51_dai_ops,
 };
-EXPORT_SYMBOL_GPL(cs42l51_dai);
-
 
-static int cs42l51_probe(struct platform_device *pdev)
+static int cs42l51_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
+       struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
+       int ret, reg;
 
-       if (!cs42l51_codec) {
-               dev_err(&pdev->dev, "CS42L51 codec not yet registered\n");
-               return -EINVAL;
-       }
+       codec->control_data = cs42l51->control_data;
 
-       socdev->card->codec = cs42l51_codec;
-       codec = socdev->card->codec;
+       ret = cs42l51_fill_cache(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "failed to fill register cache\n");
+               return ret;
+       }
 
-       /* Register PCMs */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, cs42l51->control_type);
        if (ret < 0) {
-               dev_err(&pdev->dev, "failed to create PCMs\n");
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
        }
 
+       /*
+        * DAC configuration
+        * - Use signal processor
+        * - auto mute
+        * - vol changes immediate
+        * - no de-emphasize
+        */
+       reg = CS42L51_DAC_CTL_DATA_SEL(1)
+               | CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
+       ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg);
+       if (ret < 0)
+               return ret;
+
        snd_soc_add_controls(codec, cs42l51_snd_controls,
                ARRAY_SIZE(cs42l51_snd_controls));
        snd_soc_dapm_new_controls(codec, cs42l51_dapm_widgets,
@@ -722,22 +558,77 @@ static int cs42l51_probe(struct platform_device *pdev)
        return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_device_cs42l51 = {
+       .probe =        cs42l51_probe,
+       .reg_cache_size = CS42L51_NUMREGS,
+       .reg_word_size = sizeof(u8),
+};
 
-static int cs42l51_remove(struct platform_device *pdev)
+static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
+       const struct i2c_device_id *id)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct cs42l51_private *cs42l51;
+       int ret;
 
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
+       /* Verify that we have a CS42L51 */
+       ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID);
+       if (ret < 0) {
+               dev_err(&i2c_client->dev, "failed to read I2C\n");
+               goto error;
+       }
+
+       if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
+           (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
+               dev_err(&i2c_client->dev, "Invalid chip id\n");
+               ret = -ENODEV;
+               goto error;
+       }
+
+       dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
+                               ret & 7);
+
+       cs42l51 = kzalloc(sizeof(struct cs42l51_private), GFP_KERNEL);
+       if (!cs42l51) {
+               dev_err(&i2c_client->dev, "could not allocate codec\n");
+               return -ENOMEM;
+       }
+
+       i2c_set_clientdata(i2c_client, cs42l51);
+       cs42l51->control_data = i2c_client;
+       cs42l51->control_type = SND_SOC_I2C;
 
+       ret =  snd_soc_register_codec(&i2c_client->dev,
+                       &soc_codec_device_cs42l51, &cs42l51_dai, 1);
+       if (ret < 0)
+               kfree(cs42l51);
+error:
+       return ret;
+}
+
+static int cs42l51_i2c_remove(struct i2c_client *client)
+{
+       struct cs42l51_private *cs42l51 = i2c_get_clientdata(client);
+
+       snd_soc_unregister_codec(&client->dev);
+       kfree(cs42l51);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_device_cs42l51 = {
-       .probe =        cs42l51_probe,
-       .remove =       cs42l51_remove
+static const struct i2c_device_id cs42l51_id[] = {
+       {"cs42l51", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, cs42l51_id);
+
+static struct i2c_driver cs42l51_i2c_driver = {
+       .driver = {
+               .name = "cs42l51-codec",
+               .owner = THIS_MODULE,
+       },
+       .id_table = cs42l51_id,
+       .probe = cs42l51_i2c_probe,
+       .remove = cs42l51_i2c_remove,
 };
-EXPORT_SYMBOL_GPL(soc_codec_device_cs42l51);
 
 static int __init cs42l51_init(void)
 {
@@ -758,6 +649,6 @@ static void __exit cs42l51_exit(void)
 }
 module_exit(cs42l51_exit);
 
-MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
 MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
 MODULE_LICENSE("GPL");
index 8f0bd9786ad2a4966421bab434441944bebd84c5..2beeb171db4b99f8635b01304d97f7b0439e7fe0 100644 (file)
 #define CS42L51_LASTREG                0x20
 #define CS42L51_NUMREGS                (CS42L51_LASTREG - CS42L51_FIRSTREG + 1)
 
-extern struct snd_soc_dai cs42l51_dai;
-extern struct snd_soc_codec_device soc_codec_device_cs42l51;
 #endif
index f07a415c753fd12a31d1b24d7cc4e82deafa5819..e8d27c8f9ba392e16a8f05ae38da6cd7a274fab2 100644 (file)
@@ -24,7 +24,8 @@
 
 
 struct cx20442_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+       void *control_data;
        u8 reg_cache[1];
 };
 
@@ -102,7 +103,7 @@ static unsigned int cx20442_read_reg_cache(struct snd_soc_codec *codec,
 {
        u8 *reg_cache = codec->reg_cache;
 
-       if (reg >= codec->reg_cache_size)
+       if (reg >= codec->driver->reg_cache_size)
                return -EINVAL;
 
        return reg_cache[reg];
@@ -164,16 +165,17 @@ static int cx20442_pm_to_v253_vsp(u8 value)
 static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
                                                        unsigned int value)
 {
+       struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
        u8 *reg_cache = codec->reg_cache;
        int vls, vsp, old, len;
        char buf[18];
 
-       if (reg >= codec->reg_cache_size)
+       if (reg >= codec->driver->reg_cache_size)
                return -EINVAL;
 
        /* hw_write and control_data pointers required for talking to the modem
         * are expected to be set by the line discipline initialization code */
-       if (!codec->hw_write || !codec->control_data)
+       if (!codec->hw_write || !cx20442->control_data)
                return -EIO;
 
        old = reg_cache[reg];
@@ -202,17 +204,13 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg,
                return -ENOMEM;
 
        dev_dbg(codec->dev, "%s: %s\n", __func__, buf);
-       if (codec->hw_write(codec->control_data, buf, len) != len)
+       if (codec->hw_write(cx20442->control_data, buf, len) != len)
                return -EIO;
 
        return 0;
 }
 
 
-/* Moved up here as line discipline referres it during initialization */
-static struct snd_soc_codec *cx20442_codec;
-
-
 /*
  * Line discpline related code
  *
@@ -228,15 +226,15 @@ static const char *v253_init = "ate0m0q0+fclass=8\r";
 /* Line discipline .open() */
 static int v253_open(struct tty_struct *tty)
 {
-       struct snd_soc_codec *codec = cx20442_codec;
        int ret, len = strlen(v253_init);
 
        /* Doesn't make sense without write callback */
        if (!tty->ops->write)
                return -EINVAL;
 
-       /* Pass the codec structure address for use by other ldisc callbacks */
-       tty->disc_data = codec;
+       /* Won't work if no codec pointer has been passed by a card driver */
+       if (!tty->disc_data)
+               return -ENODEV;
 
        if (tty->ops->write(tty, v253_init, len) != len) {
                ret = -EIO;
@@ -253,15 +251,18 @@ err:
 static void v253_close(struct tty_struct *tty)
 {
        struct snd_soc_codec *codec = tty->disc_data;
+       struct cx20442_priv *cx20442;
 
        tty->disc_data = NULL;
 
        if (!codec)
                return;
 
+       cx20442 = snd_soc_codec_get_drvdata(codec);
+
        /* Prevent the codec driver from further accessing the modem */
        codec->hw_write = NULL;
-       codec->control_data = NULL;
+       cx20442->control_data = NULL;
        codec->pop_time = 0;
 }
 
@@ -277,15 +278,18 @@ static void v253_receive(struct tty_struct *tty,
                                const unsigned char *cp, char *fp, int count)
 {
        struct snd_soc_codec *codec = tty->disc_data;
+       struct cx20442_priv *cx20442;
 
        if (!codec)
                return;
 
-       if (!codec->control_data) {
+       cx20442 = snd_soc_codec_get_drvdata(codec);
+
+       if (!cx20442->control_data) {
                /* First modem response, complete setup procedure */
 
                /* Set up codec driver access to modem controls */
-               codec->control_data = tty;
+               cx20442->control_data = tty;
                codec->hw_write = (hw_write_t)tty->ops->write;
                codec->pop_time = 1;
        }
@@ -313,8 +317,8 @@ EXPORT_SYMBOL_GPL(v253_ops);
  * Codec DAI
  */
 
-struct snd_soc_dai cx20442_dai = {
-       .name = "CX20442",
+static struct snd_soc_dai_driver cx20442_dai = {
+       .name = "cx20442-voice",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -330,142 +334,63 @@ struct snd_soc_dai cx20442_dai = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
 };
-EXPORT_SYMBOL_GPL(cx20442_dai);
 
-static int cx20442_codec_probe(struct platform_device *pdev)
+static int cx20442_codec_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret;
-
-       if (!cx20442_codec) {
-               dev_err(&pdev->dev, "cx20442 not yet discovered\n");
-               return -ENODEV;
-       }
-       codec = cx20442_codec;
-
-       socdev->card->codec = codec;
+       struct cx20442_priv *cx20442;
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to create pcms\n");
-               goto pcm_err;
-       }
+       cx20442 = kzalloc(sizeof(struct cx20442_priv), GFP_KERNEL);
+       if (cx20442 == NULL)
+               return -ENOMEM;
+       snd_soc_codec_set_drvdata(codec, cx20442);
 
        cx20442_add_widgets(codec);
 
-pcm_err:
-       return ret;
+       cx20442->control_data = NULL;
+       codec->hw_write = NULL;
+       codec->pop_time = 0;
+
+       return 0;
 }
 
 /* power down chip */
-static int cx20442_codec_remove(struct platform_device *pdev)
+static int cx20442_codec_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct cx20442_priv *cx20442 = snd_soc_codec_get_drvdata(codec);
 
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
+       if (cx20442->control_data) {
+                       struct tty_struct *tty = cx20442->control_data;
+                       tty_hangup(tty);
+       }
 
+       kfree(cx20442);
        return 0;
 }
 
-struct snd_soc_codec_device cx20442_codec_dev = {
+static struct snd_soc_codec_driver cx20442_codec_dev = {
        .probe =        cx20442_codec_probe,
        .remove =       cx20442_codec_remove,
+       .reg_cache_size = 1,
+       .reg_word_size = sizeof(u8),
+       .read = cx20442_read_reg_cache,
+       .write = cx20442_write,
 };
-EXPORT_SYMBOL_GPL(cx20442_codec_dev);
-
-static int cx20442_register(struct cx20442_priv *cx20442)
-{
-       struct snd_soc_codec *codec = &cx20442->codec;
-       int ret;
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->name = "CX20442";
-       codec->owner = THIS_MODULE;
-       snd_soc_codec_set_drvdata(codec, cx20442);
-
-       codec->dai = &cx20442_dai;
-       codec->num_dai = 1;
-
-       codec->reg_cache = &cx20442->reg_cache;
-       codec->reg_cache_size = ARRAY_SIZE(cx20442->reg_cache);
-       codec->read = cx20442_read_reg_cache;
-       codec->write = cx20442_write;
-
-       codec->bias_level = SND_SOC_BIAS_OFF;
-
-       cx20442_dai.dev = codec->dev;
-
-       cx20442_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dai(&cx20442_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
-
-       return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       cx20442_codec = NULL;
-       kfree(cx20442);
-       return ret;
-}
-
-static void cx20442_unregister(struct cx20442_priv *cx20442)
-{
-       snd_soc_unregister_dai(&cx20442_dai);
-       snd_soc_unregister_codec(&cx20442->codec);
-
-       cx20442_codec = NULL;
-       kfree(cx20442);
-}
 
 static int cx20442_platform_probe(struct platform_device *pdev)
 {
-       struct cx20442_priv *cx20442;
-       struct snd_soc_codec *codec;
-
-       cx20442 = kzalloc(sizeof(struct cx20442_priv), GFP_KERNEL);
-       if (cx20442 == NULL)
-               return -ENOMEM;
-
-       codec = &cx20442->codec;
-
-       codec->control_data = NULL;
-       codec->hw_write = NULL;
-       codec->pop_time = 0;
-
-       codec->dev = &pdev->dev;
-       platform_set_drvdata(pdev, cx20442);
-
-       return cx20442_register(cx20442);
+       return snd_soc_register_codec(&pdev->dev,
+                       &cx20442_codec_dev, &cx20442_dai, 1);
 }
 
 static int __exit cx20442_platform_remove(struct platform_device *pdev)
 {
-       struct cx20442_priv *cx20442 = platform_get_drvdata(pdev);
-
-       cx20442_unregister(cx20442);
+       snd_soc_unregister_codec(&pdev->dev);
        return 0;
 }
 
 static struct platform_driver cx20442_platform_driver = {
        .driver = {
-               .name = "cx20442",
+               .name = "cx20442-codec",
                .owner = THIS_MODULE,
                },
        .probe = cx20442_platform_probe,
@@ -487,4 +412,4 @@ module_exit(cx20442_exit);
 MODULE_DESCRIPTION("ASoC CX20442-11 voice modem codec driver");
 MODULE_AUTHOR("Janusz Krzysztofik");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:cx20442");
+MODULE_ALIAS("platform:cx20442-codec");
index 688a5eb62e17d7ab4dbafa3c28e36f705b9465f5..c7a7c79ef0cd4d242783ccf7050a0ebc65cafacc 100644 (file)
@@ -13,8 +13,6 @@
 #ifndef _CX20442_CODEC_H
 #define _CX20442_CODEC_H
 
-extern struct snd_soc_dai cx20442_dai;
-extern struct snd_soc_codec_device cx20442_codec_dev;
 extern struct tty_ldisc_ops v253_ops;
 
 #endif
index 3c51d6a575237270de5d540bb13a1b93a77829d2..58bb9b994811ac9ea946db98ffa4836266afb510 100644 (file)
@@ -25,8 +25,6 @@
 #include <sound/initval.h>
 #include <sound/tlv.h>
 
-#include "da7210.h"
-
 /* DA7210 register space */
 #define DA7210_STATUS                  0x02
 #define DA7210_STARTUP1                        0x03
@@ -162,11 +160,10 @@ static const struct snd_kcontrol_new da7210_snd_controls[] = {
 
 /* Codec private data */
 struct da7210_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+       void *control_data;
 };
 
-static struct snd_soc_codec *da7210_codec;
-
 /*
  * Register cache
  */
@@ -209,12 +206,12 @@ static int da7210_write(struct snd_soc_codec *codec, u32 reg, u32 value)
        u8 *cache = codec->reg_cache;
        u8 data[2];
 
-       BUG_ON(codec->volatile_register);
+       BUG_ON(codec->driver->volatile_register);
 
        data[0] = reg & 0xff;
        data[1] = value & 0xff;
 
-       if (reg >= codec->reg_cache_size)
+       if (reg >= codec->driver->reg_cache_size)
                return -EIO;
 
        if (2 != codec->hw_write(codec->control_data, data, 2))
@@ -267,8 +264,7 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u32 dai_cfg1;
        u32 hpf_reg, hpf_mask, hpf_value;
        u32 fs, bypass;
@@ -430,9 +426,8 @@ static struct snd_soc_dai_ops da7210_dai_ops = {
        .set_fmt        = da7210_set_dai_fmt,
 };
 
-struct snd_soc_dai da7210_dai = {
-       .name = "DA7210 IIS",
-       .id = 0,
+static struct snd_soc_dai_driver da7210_dai = {
+       .name = "da7210-hifi",
        /* playback capabilities */
        .playback = {
                .stream_name = "Playback",
@@ -452,55 +447,15 @@ struct snd_soc_dai da7210_dai = {
        .ops = &da7210_dai_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(da7210_dai);
 
-/*
- * Initialize the DA7210 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int da7210_init(struct da7210_priv *da7210)
+static int da7210_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = &da7210->codec;
-       int ret = 0;
+       struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
 
-       if (da7210_codec) {
-               dev_err(codec->dev, "Another da7210 is registered\n");
-               return -EINVAL;
-       }
+       dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
 
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, da7210);
-       codec->name             = "DA7210";
-       codec->owner            = THIS_MODULE;
-       codec->read             = da7210_read;
-       codec->write            = da7210_write;
-       codec->dai              = &da7210_dai;
-       codec->num_dai          = 1;
+       codec->control_data     = da7210->control_data;
        codec->hw_write         = (hw_write_t)i2c_master_send;
-       codec->reg_cache_size   = ARRAY_SIZE(da7210_reg);
-       codec->reg_cache        = kmemdup(da7210_reg,
-                                         sizeof(da7210_reg), GFP_KERNEL);
-
-       if (!codec->reg_cache)
-               return -ENOMEM;
-
-       da7210_dai.dev = codec->dev;
-       da7210_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret) {
-               dev_err(codec->dev, "Failed to register CODEC: %d\n", ret);
-               goto init_err;
-       }
-
-       ret = snd_soc_register_dai(&da7210_dai);
-       if (ret) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto codec_err;
-       }
 
        /* FIXME
         *
@@ -583,54 +538,50 @@ static int da7210_init(struct da7210_priv *da7210)
        /* Activate all enabled subsystem */
        da7210_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);
 
-       return ret;
-
-codec_err:
-       snd_soc_unregister_codec(codec);
-init_err:
-       kfree(codec->reg_cache);
-       codec->reg_cache = NULL;
+       snd_soc_add_controls(codec, da7210_snd_controls,
+                            ARRAY_SIZE(da7210_snd_controls));
 
-       return ret;
+       dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
 
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_da7210 = {
+       .probe                  = da7210_probe,
+       .read                   = da7210_read,
+       .write                  = da7210_write,
+       .reg_cache_size         = ARRAY_SIZE(da7210_reg),
+       .reg_word_size          = sizeof(u8),
+       .reg_cache_default      = da7210_reg,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct da7210_priv *da7210;
-       struct snd_soc_codec *codec;
        int ret;
 
        da7210 = kzalloc(sizeof(struct da7210_priv), GFP_KERNEL);
        if (!da7210)
                return -ENOMEM;
 
-       codec = &da7210->codec;
-       codec->dev = &i2c->dev;
-
        i2c_set_clientdata(i2c, da7210);
-       codec->control_data = i2c;
+       da7210->control_data = i2c;
+       da7210->control_type = SND_SOC_I2C;
 
-       ret = da7210_init(da7210);
-       if (ret < 0) {
-               pr_err("Failed to initialise da7210 audio codec\n");
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_da7210, &da7210_dai, 1);
+       if (ret < 0)
                kfree(da7210);
-       }
 
        return ret;
 }
 
 static int __devexit da7210_i2c_remove(struct i2c_client *client)
 {
-       struct da7210_priv *da7210 = i2c_get_clientdata(client);
-
-       snd_soc_unregister_dai(&da7210_dai);
-       kfree(da7210->codec.reg_cache);
-       kfree(da7210);
-       da7210_codec = NULL;
-
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -643,59 +594,15 @@ MODULE_DEVICE_TABLE(i2c, da7210_i2c_id);
 /* I2C codec control layer */
 static struct i2c_driver da7210_i2c_driver = {
        .driver = {
-               .name = "DA7210 I2C Codec",
+               .name = "da7210-codec",
                .owner = THIS_MODULE,
        },
-       .probe = da7210_i2c_probe,
-       .remove  __devexit_p(da7210_i2c_remove),
-       .id_table = da7210_i2c_id,
+       .probe          = da7210_i2c_probe,
+       .remove         = __devexit_p(da7210_i2c_remove),
+       .id_table       = da7210_i2c_id,
 };
 #endif
 
-static int da7210_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret;
-
-       if (!da7210_codec) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = da7210_codec;
-       codec = da7210_codec;
-
-       /* Register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0)
-               goto pcm_err;
-
-       snd_soc_add_controls(da7210_codec, da7210_snd_controls,
-                            ARRAY_SIZE(da7210_snd_controls));
-
-       dev_info(&pdev->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
-
-pcm_err:
-       return ret;
-}
-
-static int da7210_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_da7210 = {
-       .probe =        da7210_probe,
-       .remove =       da7210_remove,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_da7210);
-
 static int __init da7210_modinit(void)
 {
        int ret = 0;
diff --git a/sound/soc/codecs/da7210.h b/sound/soc/codecs/da7210.h
deleted file mode 100644 (file)
index 390d621..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * da7210.h  --  audio driver for da7210
- *
- * Copyright (c) 2009 Dialog Semiconductor
- * Written by David Chen <Dajun.chen@diasemi.com>
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Cleanups by Kuninori Morimoto <morimoto.kuninori@renesas.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.
- *
- */
-
-#ifndef _DA7210_H
-#define _DA7210_H
-
-extern struct snd_soc_dai da7210_dai;
-extern struct snd_soc_codec_device soc_codec_dev_da7210;
-
-#endif
-
index 66557de1e4fec533f0e0e1f4ddb8a9294b58c13f..16253ec9b0228e0bf8bd5fce98ba2a7c62436444 100644 (file)
@@ -74,29 +74,22 @@ static const uint32_t jz4740_codec_regs[] = {
 struct jz4740_codec {
        void __iomem *base;
        struct resource *mem;
-
-       uint32_t reg_cache[2];
-       struct snd_soc_codec codec;
 };
 
-static inline struct jz4740_codec *codec_to_jz4740(struct snd_soc_codec *codec)
-{
-       return container_of(codec, struct jz4740_codec, codec);
-}
-
 static unsigned int jz4740_codec_read(struct snd_soc_codec *codec,
        unsigned int reg)
 {
-       struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec);
+       struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec);
        return readl(jz4740_codec->base + (reg << 2));
 }
 
 static int jz4740_codec_write(struct snd_soc_codec *codec, unsigned int reg,
        unsigned int val)
 {
-       struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec);
+       struct jz4740_codec *jz4740_codec = snd_soc_codec_get_drvdata(codec);
+       u32 *cache = codec->reg_cache;
 
-       jz4740_codec->reg_cache[reg] = val;
+       cache[reg] = val;
        writel(val, jz4740_codec->base + (reg << 2));
 
        return 0;
@@ -172,8 +165,7 @@ static int jz4740_codec_hw_params(struct snd_pcm_substream *substream,
 {
        uint32_t val;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec =rtd->codec;
 
        switch (params_rate(params)) {
        case 8000:
@@ -219,8 +211,8 @@ static struct snd_soc_dai_ops jz4740_codec_dai_ops = {
        .hw_params = jz4740_codec_hw_params,
 };
 
-struct snd_soc_dai jz4740_codec_dai = {
-       .name = "jz4740",
+static struct snd_soc_dai_driver jz4740_codec_dai = {
+       .name = "jz4740-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -238,7 +230,6 @@ struct snd_soc_dai jz4740_codec_dai = {
        .ops = &jz4740_codec_dai_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(jz4740_codec_dai);
 
 static void jz4740_codec_wakeup(struct snd_soc_codec *codec)
 {
@@ -302,23 +293,10 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-static struct snd_soc_codec *jz4740_codec_codec;
-
-static int jz4740_codec_dev_probe(struct platform_device *pdev)
+static int jz4740_codec_dev_probe(struct snd_soc_codec *codec)
 {
-       int ret;
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = jz4740_codec_codec;
-
-       BUG_ON(!codec);
-
-       socdev->card->codec = codec;
-
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to create pcms: %d\n", ret);
-               return ret;
-       }
+       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));
@@ -331,34 +309,27 @@ static int jz4740_codec_dev_probe(struct platform_device *pdev)
 
        snd_soc_dapm_new_widgets(codec);
 
+       jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
        return 0;
 }
 
-static int jz4740_codec_dev_remove(struct platform_device *pdev)
+static int jz4740_codec_dev_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
+       jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
 #ifdef CONFIG_PM_SLEEP
 
-static int jz4740_codec_suspend(struct platform_device *pdev, pm_message_t state)
+static int jz4740_codec_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);
 }
 
-static int jz4740_codec_resume(struct platform_device *pdev)
+static int jz4740_codec_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 }
 
@@ -367,19 +338,23 @@ static int jz4740_codec_resume(struct platform_device *pdev)
 #define jz4740_codec_resume NULL
 #endif
 
-struct snd_soc_codec_device soc_codec_dev_jz4740_codec = {
+static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {
        .probe = jz4740_codec_dev_probe,
        .remove = jz4740_codec_dev_remove,
        .suspend = jz4740_codec_suspend,
        .resume = jz4740_codec_resume,
+       .read = jz4740_codec_read,
+       .write = jz4740_codec_write,
+       .set_bias_level = jz4740_codec_set_bias_level,
+       .reg_cache_default      = jz4740_codec_regs,
+       .reg_word_size = sizeof(u32),
+       .reg_cache_size = 2,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_jz4740_codec);
 
 static int __devinit jz4740_codec_probe(struct platform_device *pdev)
 {
        int ret;
        struct jz4740_codec *jz4740_codec;
-       struct snd_soc_codec *codec;
        struct resource *mem;
 
        jz4740_codec = kzalloc(sizeof(*jz4740_codec), GFP_KERNEL);
@@ -408,55 +383,17 @@ static int __devinit jz4740_codec_probe(struct platform_device *pdev)
        }
        jz4740_codec->mem = mem;
 
-       jz4740_codec_dai.dev = &pdev->dev;
-
-       codec = &jz4740_codec->codec;
-
-       codec->dev              = &pdev->dev;
-       codec->name             = "jz4740";
-       codec->owner            = THIS_MODULE;
-
-       codec->read             = jz4740_codec_read;
-       codec->write            = jz4740_codec_write;
-       codec->set_bias_level   = jz4740_codec_set_bias_level;
-       codec->bias_level       = SND_SOC_BIAS_OFF;
-
-       codec->dai              = &jz4740_codec_dai;
-       codec->num_dai          = 1;
-
-       codec->reg_cache        = jz4740_codec->reg_cache;
-       codec->reg_cache_size   = 2;
-       memcpy(codec->reg_cache, jz4740_codec_regs, sizeof(jz4740_codec_regs));
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       jz4740_codec_codec = codec;
-
-       snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
-                       JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
-
        platform_set_drvdata(pdev, jz4740_codec);
 
-       ret = snd_soc_register_codec(codec);
+       ret = snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_jz4740_codec, &jz4740_codec_dai, 1);
        if (ret) {
                dev_err(&pdev->dev, "Failed to register codec\n");
                goto err_iounmap;
        }
 
-       ret = snd_soc_register_dai(&jz4740_codec_dai);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to register codec dai\n");
-               goto err_unregister_codec;
-       }
-
-       jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
        return 0;
 
-err_unregister_codec:
-       snd_soc_unregister_codec(codec);
 err_iounmap:
        iounmap(jz4740_codec->base);
 err_release_mem_region:
@@ -472,8 +409,7 @@ static int __devexit jz4740_codec_remove(struct platform_device *pdev)
        struct jz4740_codec *jz4740_codec = platform_get_drvdata(pdev);
        struct resource *mem = jz4740_codec->mem;
 
-       snd_soc_unregister_dai(&jz4740_codec_dai);
-       snd_soc_unregister_codec(&jz4740_codec->codec);
+       snd_soc_unregister_codec(&pdev->dev);
 
        iounmap(jz4740_codec->base);
        release_mem_region(mem->start, resource_size(mem));
diff --git a/sound/soc/codecs/jz4740.h b/sound/soc/codecs/jz4740.h
deleted file mode 100644 (file)
index b5a0691..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  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 __SND_SOC_CODECS_JZ4740_CODEC_H__
-#define __SND_SOC_CODECS_JZ4740_CODEC_H__
-
-extern struct snd_soc_dai jz4740_codec_dai;
-extern struct snd_soc_codec_device soc_codec_dev_jz4740_codec;
-
-#endif
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
new file mode 100644 (file)
index 0000000..e7a40d1
--- /dev/null
@@ -0,0 +1,2097 @@
+/*
+ * max98088.c -- MAX98088 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.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 <linux/slab.h>
+#include <asm/div64.h>
+#include <sound/max98088.h>
+#include "max98088.h"
+
+struct max98088_cdata {
+       unsigned int rate;
+       unsigned int fmt;
+       int eq_sel;
+};
+
+struct max98088_priv {
+       u8 reg_cache[M98088_REG_CNT];
+       void *control_data;
+       struct max98088_pdata *pdata;
+       unsigned int sysclk;
+       struct max98088_cdata dai[2];
+       int eq_textcnt;
+       const char **eq_texts;
+       struct soc_enum eq_enum;
+       u8 ina_state;
+       u8 inb_state;
+       unsigned int ex_mode;
+       unsigned int digmic;
+       unsigned int mic1pre;
+       unsigned int mic2pre;
+       unsigned int extmic_mode;
+};
+
+static const u8 max98088_reg[M98088_REG_CNT] = {
+       0x00, /* 00 IRQ status */
+       0x00, /* 01 MIC status */
+       0x00, /* 02 jack status */
+       0x00, /* 03 battery voltage */
+       0x00, /* 04 */
+       0x00, /* 05 */
+       0x00, /* 06 */
+       0x00, /* 07 */
+       0x00, /* 08 */
+       0x00, /* 09 */
+       0x00, /* 0A */
+       0x00, /* 0B */
+       0x00, /* 0C */
+       0x00, /* 0D */
+       0x00, /* 0E */
+       0x00, /* 0F interrupt enable */
+
+       0x00, /* 10 master clock */
+       0x00, /* 11 DAI1 clock mode */
+       0x00, /* 12 DAI1 clock control */
+       0x00, /* 13 DAI1 clock control */
+       0x00, /* 14 DAI1 format */
+       0x00, /* 15 DAI1 clock */
+       0x00, /* 16 DAI1 config */
+       0x00, /* 17 DAI1 TDM */
+       0x00, /* 18 DAI1 filters */
+       0x00, /* 19 DAI2 clock mode */
+       0x00, /* 1A DAI2 clock control */
+       0x00, /* 1B DAI2 clock control */
+       0x00, /* 1C DAI2 format */
+       0x00, /* 1D DAI2 clock */
+       0x00, /* 1E DAI2 config */
+       0x00, /* 1F DAI2 TDM */
+
+       0x00, /* 20 DAI2 filters */
+       0x00, /* 21 data config */
+       0x00, /* 22 DAC mixer */
+       0x00, /* 23 left ADC mixer */
+       0x00, /* 24 right ADC mixer */
+       0x00, /* 25 left HP mixer */
+       0x00, /* 26 right HP mixer */
+       0x00, /* 27 HP control */
+       0x00, /* 28 left REC mixer */
+       0x00, /* 29 right REC mixer */
+       0x00, /* 2A REC control */
+       0x00, /* 2B left SPK mixer */
+       0x00, /* 2C right SPK mixer */
+       0x00, /* 2D SPK control */
+       0x00, /* 2E sidetone */
+       0x00, /* 2F DAI1 playback level */
+
+       0x00, /* 30 DAI1 playback level */
+       0x00, /* 31 DAI2 playback level */
+       0x00, /* 32 DAI2 playbakc level */
+       0x00, /* 33 left ADC level */
+       0x00, /* 34 right ADC level */
+       0x00, /* 35 MIC1 level */
+       0x00, /* 36 MIC2 level */
+       0x00, /* 37 INA level */
+       0x00, /* 38 INB level */
+       0x00, /* 39 left HP volume */
+       0x00, /* 3A right HP volume */
+       0x00, /* 3B left REC volume */
+       0x00, /* 3C right REC volume */
+       0x00, /* 3D left SPK volume */
+       0x00, /* 3E right SPK volume */
+       0x00, /* 3F MIC config */
+
+       0x00, /* 40 MIC threshold */
+       0x00, /* 41 excursion limiter filter */
+       0x00, /* 42 excursion limiter threshold */
+       0x00, /* 43 ALC */
+       0x00, /* 44 power limiter threshold */
+       0x00, /* 45 power limiter config */
+       0x00, /* 46 distortion limiter config */
+       0x00, /* 47 audio input */
+       0x00, /* 48 microphone */
+       0x00, /* 49 level control */
+       0x00, /* 4A bypass switches */
+       0x00, /* 4B jack detect */
+       0x00, /* 4C input enable */
+       0x00, /* 4D output enable */
+       0xF0, /* 4E bias control */
+       0x00, /* 4F DAC power */
+
+       0x0F, /* 50 DAC power */
+       0x00, /* 51 system */
+       0x00, /* 52 DAI1 EQ1 */
+       0x00, /* 53 DAI1 EQ1 */
+       0x00, /* 54 DAI1 EQ1 */
+       0x00, /* 55 DAI1 EQ1 */
+       0x00, /* 56 DAI1 EQ1 */
+       0x00, /* 57 DAI1 EQ1 */
+       0x00, /* 58 DAI1 EQ1 */
+       0x00, /* 59 DAI1 EQ1 */
+       0x00, /* 5A DAI1 EQ1 */
+       0x00, /* 5B DAI1 EQ1 */
+       0x00, /* 5C DAI1 EQ2 */
+       0x00, /* 5D DAI1 EQ2 */
+       0x00, /* 5E DAI1 EQ2 */
+       0x00, /* 5F DAI1 EQ2 */
+
+       0x00, /* 60 DAI1 EQ2 */
+       0x00, /* 61 DAI1 EQ2 */
+       0x00, /* 62 DAI1 EQ2 */
+       0x00, /* 63 DAI1 EQ2 */
+       0x00, /* 64 DAI1 EQ2 */
+       0x00, /* 65 DAI1 EQ2 */
+       0x00, /* 66 DAI1 EQ3 */
+       0x00, /* 67 DAI1 EQ3 */
+       0x00, /* 68 DAI1 EQ3 */
+       0x00, /* 69 DAI1 EQ3 */
+       0x00, /* 6A DAI1 EQ3 */
+       0x00, /* 6B DAI1 EQ3 */
+       0x00, /* 6C DAI1 EQ3 */
+       0x00, /* 6D DAI1 EQ3 */
+       0x00, /* 6E DAI1 EQ3 */
+       0x00, /* 6F DAI1 EQ3 */
+
+       0x00, /* 70 DAI1 EQ4 */
+       0x00, /* 71 DAI1 EQ4 */
+       0x00, /* 72 DAI1 EQ4 */
+       0x00, /* 73 DAI1 EQ4 */
+       0x00, /* 74 DAI1 EQ4 */
+       0x00, /* 75 DAI1 EQ4 */
+       0x00, /* 76 DAI1 EQ4 */
+       0x00, /* 77 DAI1 EQ4 */
+       0x00, /* 78 DAI1 EQ4 */
+       0x00, /* 79 DAI1 EQ4 */
+       0x00, /* 7A DAI1 EQ5 */
+       0x00, /* 7B DAI1 EQ5 */
+       0x00, /* 7C DAI1 EQ5 */
+       0x00, /* 7D DAI1 EQ5 */
+       0x00, /* 7E DAI1 EQ5 */
+       0x00, /* 7F DAI1 EQ5 */
+
+       0x00, /* 80 DAI1 EQ5 */
+       0x00, /* 81 DAI1 EQ5 */
+       0x00, /* 82 DAI1 EQ5 */
+       0x00, /* 83 DAI1 EQ5 */
+       0x00, /* 84 DAI2 EQ1 */
+       0x00, /* 85 DAI2 EQ1 */
+       0x00, /* 86 DAI2 EQ1 */
+       0x00, /* 87 DAI2 EQ1 */
+       0x00, /* 88 DAI2 EQ1 */
+       0x00, /* 89 DAI2 EQ1 */
+       0x00, /* 8A DAI2 EQ1 */
+       0x00, /* 8B DAI2 EQ1 */
+       0x00, /* 8C DAI2 EQ1 */
+       0x00, /* 8D DAI2 EQ1 */
+       0x00, /* 8E DAI2 EQ2 */
+       0x00, /* 8F DAI2 EQ2 */
+
+       0x00, /* 90 DAI2 EQ2 */
+       0x00, /* 91 DAI2 EQ2 */
+       0x00, /* 92 DAI2 EQ2 */
+       0x00, /* 93 DAI2 EQ2 */
+       0x00, /* 94 DAI2 EQ2 */
+       0x00, /* 95 DAI2 EQ2 */
+       0x00, /* 96 DAI2 EQ2 */
+       0x00, /* 97 DAI2 EQ2 */
+       0x00, /* 98 DAI2 EQ3 */
+       0x00, /* 99 DAI2 EQ3 */
+       0x00, /* 9A DAI2 EQ3 */
+       0x00, /* 9B DAI2 EQ3 */
+       0x00, /* 9C DAI2 EQ3 */
+       0x00, /* 9D DAI2 EQ3 */
+       0x00, /* 9E DAI2 EQ3 */
+       0x00, /* 9F DAI2 EQ3 */
+
+       0x00, /* A0 DAI2 EQ3 */
+       0x00, /* A1 DAI2 EQ3 */
+       0x00, /* A2 DAI2 EQ4 */
+       0x00, /* A3 DAI2 EQ4 */
+       0x00, /* A4 DAI2 EQ4 */
+       0x00, /* A5 DAI2 EQ4 */
+       0x00, /* A6 DAI2 EQ4 */
+       0x00, /* A7 DAI2 EQ4 */
+       0x00, /* A8 DAI2 EQ4 */
+       0x00, /* A9 DAI2 EQ4 */
+       0x00, /* AA DAI2 EQ4 */
+       0x00, /* AB DAI2 EQ4 */
+       0x00, /* AC DAI2 EQ5 */
+       0x00, /* AD DAI2 EQ5 */
+       0x00, /* AE DAI2 EQ5 */
+       0x00, /* AF DAI2 EQ5 */
+
+       0x00, /* B0 DAI2 EQ5 */
+       0x00, /* B1 DAI2 EQ5 */
+       0x00, /* B2 DAI2 EQ5 */
+       0x00, /* B3 DAI2 EQ5 */
+       0x00, /* B4 DAI2 EQ5 */
+       0x00, /* B5 DAI2 EQ5 */
+       0x00, /* B6 DAI1 biquad */
+       0x00, /* B7 DAI1 biquad */
+       0x00, /* B8 DAI1 biquad */
+       0x00, /* B9 DAI1 biquad */
+       0x00, /* BA DAI1 biquad */
+       0x00, /* BB DAI1 biquad */
+       0x00, /* BC DAI1 biquad */
+       0x00, /* BD DAI1 biquad */
+       0x00, /* BE DAI1 biquad */
+       0x00, /* BF DAI1 biquad */
+
+       0x00, /* C0 DAI2 biquad */
+       0x00, /* C1 DAI2 biquad */
+       0x00, /* C2 DAI2 biquad */
+       0x00, /* C3 DAI2 biquad */
+       0x00, /* C4 DAI2 biquad */
+       0x00, /* C5 DAI2 biquad */
+       0x00, /* C6 DAI2 biquad */
+       0x00, /* C7 DAI2 biquad */
+       0x00, /* C8 DAI2 biquad */
+       0x00, /* C9 DAI2 biquad */
+       0x00, /* CA */
+       0x00, /* CB */
+       0x00, /* CC */
+       0x00, /* CD */
+       0x00, /* CE */
+       0x00, /* CF */
+
+       0x00, /* D0 */
+       0x00, /* D1 */
+       0x00, /* D2 */
+       0x00, /* D3 */
+       0x00, /* D4 */
+       0x00, /* D5 */
+       0x00, /* D6 */
+       0x00, /* D7 */
+       0x00, /* D8 */
+       0x00, /* D9 */
+       0x00, /* DA */
+       0x70, /* DB */
+       0x00, /* DC */
+       0x00, /* DD */
+       0x00, /* DE */
+       0x00, /* DF */
+
+       0x00, /* E0 */
+       0x00, /* E1 */
+       0x00, /* E2 */
+       0x00, /* E3 */
+       0x00, /* E4 */
+       0x00, /* E5 */
+       0x00, /* E6 */
+       0x00, /* E7 */
+       0x00, /* E8 */
+       0x00, /* E9 */
+       0x00, /* EA */
+       0x00, /* EB */
+       0x00, /* EC */
+       0x00, /* ED */
+       0x00, /* EE */
+       0x00, /* EF */
+
+       0x00, /* F0 */
+       0x00, /* F1 */
+       0x00, /* F2 */
+       0x00, /* F3 */
+       0x00, /* F4 */
+       0x00, /* F5 */
+       0x00, /* F6 */
+       0x00, /* F7 */
+       0x00, /* F8 */
+       0x00, /* F9 */
+       0x00, /* FA */
+       0x00, /* FB */
+       0x00, /* FC */
+       0x00, /* FD */
+       0x00, /* FE */
+       0x00, /* FF */
+};
+
+static struct {
+       int readable;
+       int writable;
+       int vol;
+} max98088_access[M98088_REG_CNT] = {
+       { 0xFF, 0xFF, 1 }, /* 00 IRQ status */
+       { 0xFF, 0x00, 1 }, /* 01 MIC status */
+       { 0xFF, 0x00, 1 }, /* 02 jack status */
+       { 0x1F, 0x1F, 1 }, /* 03 battery voltage */
+       { 0xFF, 0xFF, 0 }, /* 04 */
+       { 0xFF, 0xFF, 0 }, /* 05 */
+       { 0xFF, 0xFF, 0 }, /* 06 */
+       { 0xFF, 0xFF, 0 }, /* 07 */
+       { 0xFF, 0xFF, 0 }, /* 08 */
+       { 0xFF, 0xFF, 0 }, /* 09 */
+       { 0xFF, 0xFF, 0 }, /* 0A */
+       { 0xFF, 0xFF, 0 }, /* 0B */
+       { 0xFF, 0xFF, 0 }, /* 0C */
+       { 0xFF, 0xFF, 0 }, /* 0D */
+       { 0xFF, 0xFF, 0 }, /* 0E */
+       { 0xFF, 0xFF, 0 }, /* 0F interrupt enable */
+
+       { 0xFF, 0xFF, 0 }, /* 10 master clock */
+       { 0xFF, 0xFF, 0 }, /* 11 DAI1 clock mode */
+       { 0xFF, 0xFF, 0 }, /* 12 DAI1 clock control */
+       { 0xFF, 0xFF, 0 }, /* 13 DAI1 clock control */
+       { 0xFF, 0xFF, 0 }, /* 14 DAI1 format */
+       { 0xFF, 0xFF, 0 }, /* 15 DAI1 clock */
+       { 0xFF, 0xFF, 0 }, /* 16 DAI1 config */
+       { 0xFF, 0xFF, 0 }, /* 17 DAI1 TDM */
+       { 0xFF, 0xFF, 0 }, /* 18 DAI1 filters */
+       { 0xFF, 0xFF, 0 }, /* 19 DAI2 clock mode */
+       { 0xFF, 0xFF, 0 }, /* 1A DAI2 clock control */
+       { 0xFF, 0xFF, 0 }, /* 1B DAI2 clock control */
+       { 0xFF, 0xFF, 0 }, /* 1C DAI2 format */
+       { 0xFF, 0xFF, 0 }, /* 1D DAI2 clock */
+       { 0xFF, 0xFF, 0 }, /* 1E DAI2 config */
+       { 0xFF, 0xFF, 0 }, /* 1F DAI2 TDM */
+
+       { 0xFF, 0xFF, 0 }, /* 20 DAI2 filters */
+       { 0xFF, 0xFF, 0 }, /* 21 data config */
+       { 0xFF, 0xFF, 0 }, /* 22 DAC mixer */
+       { 0xFF, 0xFF, 0 }, /* 23 left ADC mixer */
+       { 0xFF, 0xFF, 0 }, /* 24 right ADC mixer */
+       { 0xFF, 0xFF, 0 }, /* 25 left HP mixer */
+       { 0xFF, 0xFF, 0 }, /* 26 right HP mixer */
+       { 0xFF, 0xFF, 0 }, /* 27 HP control */
+       { 0xFF, 0xFF, 0 }, /* 28 left REC mixer */
+       { 0xFF, 0xFF, 0 }, /* 29 right REC mixer */
+       { 0xFF, 0xFF, 0 }, /* 2A REC control */
+       { 0xFF, 0xFF, 0 }, /* 2B left SPK mixer */
+       { 0xFF, 0xFF, 0 }, /* 2C right SPK mixer */
+       { 0xFF, 0xFF, 0 }, /* 2D SPK control */
+       { 0xFF, 0xFF, 0 }, /* 2E sidetone */
+       { 0xFF, 0xFF, 0 }, /* 2F DAI1 playback level */
+
+       { 0xFF, 0xFF, 0 }, /* 30 DAI1 playback level */
+       { 0xFF, 0xFF, 0 }, /* 31 DAI2 playback level */
+       { 0xFF, 0xFF, 0 }, /* 32 DAI2 playbakc level */
+       { 0xFF, 0xFF, 0 }, /* 33 left ADC level */
+       { 0xFF, 0xFF, 0 }, /* 34 right ADC level */
+       { 0xFF, 0xFF, 0 }, /* 35 MIC1 level */
+       { 0xFF, 0xFF, 0 }, /* 36 MIC2 level */
+       { 0xFF, 0xFF, 0 }, /* 37 INA level */
+       { 0xFF, 0xFF, 0 }, /* 38 INB level */
+       { 0xFF, 0xFF, 0 }, /* 39 left HP volume */
+       { 0xFF, 0xFF, 0 }, /* 3A right HP volume */
+       { 0xFF, 0xFF, 0 }, /* 3B left REC volume */
+       { 0xFF, 0xFF, 0 }, /* 3C right REC volume */
+       { 0xFF, 0xFF, 0 }, /* 3D left SPK volume */
+       { 0xFF, 0xFF, 0 }, /* 3E right SPK volume */
+       { 0xFF, 0xFF, 0 }, /* 3F MIC config */
+
+       { 0xFF, 0xFF, 0 }, /* 40 MIC threshold */
+       { 0xFF, 0xFF, 0 }, /* 41 excursion limiter filter */
+       { 0xFF, 0xFF, 0 }, /* 42 excursion limiter threshold */
+       { 0xFF, 0xFF, 0 }, /* 43 ALC */
+       { 0xFF, 0xFF, 0 }, /* 44 power limiter threshold */
+       { 0xFF, 0xFF, 0 }, /* 45 power limiter config */
+       { 0xFF, 0xFF, 0 }, /* 46 distortion limiter config */
+       { 0xFF, 0xFF, 0 }, /* 47 audio input */
+       { 0xFF, 0xFF, 0 }, /* 48 microphone */
+       { 0xFF, 0xFF, 0 }, /* 49 level control */
+       { 0xFF, 0xFF, 0 }, /* 4A bypass switches */
+       { 0xFF, 0xFF, 0 }, /* 4B jack detect */
+       { 0xFF, 0xFF, 0 }, /* 4C input enable */
+       { 0xFF, 0xFF, 0 }, /* 4D output enable */
+       { 0xFF, 0xFF, 0 }, /* 4E bias control */
+       { 0xFF, 0xFF, 0 }, /* 4F DAC power */
+
+       { 0xFF, 0xFF, 0 }, /* 50 DAC power */
+       { 0xFF, 0xFF, 0 }, /* 51 system */
+       { 0xFF, 0xFF, 0 }, /* 52 DAI1 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 53 DAI1 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 54 DAI1 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 55 DAI1 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 56 DAI1 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 57 DAI1 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 58 DAI1 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 59 DAI1 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 5A DAI1 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 5B DAI1 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 5C DAI1 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 5D DAI1 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 5E DAI1 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 5F DAI1 EQ2 */
+
+       { 0xFF, 0xFF, 0 }, /* 60 DAI1 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 61 DAI1 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 62 DAI1 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 63 DAI1 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 64 DAI1 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 65 DAI1 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 66 DAI1 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 67 DAI1 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 68 DAI1 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 69 DAI1 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 6A DAI1 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 6B DAI1 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 6C DAI1 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 6D DAI1 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 6E DAI1 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 6F DAI1 EQ3 */
+
+       { 0xFF, 0xFF, 0 }, /* 70 DAI1 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* 71 DAI1 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* 72 DAI1 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* 73 DAI1 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* 74 DAI1 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* 75 DAI1 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* 76 DAI1 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* 77 DAI1 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* 78 DAI1 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* 79 DAI1 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* 7A DAI1 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* 7B DAI1 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* 7C DAI1 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* 7D DAI1 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* 7E DAI1 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* 7F DAI1 EQ5 */
+
+       { 0xFF, 0xFF, 0 }, /* 80 DAI1 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* 81 DAI1 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* 82 DAI1 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* 83 DAI1 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* 84 DAI2 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 85 DAI2 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 86 DAI2 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 87 DAI2 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 88 DAI2 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 89 DAI2 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 8A DAI2 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 8B DAI2 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 8C DAI2 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 8D DAI2 EQ1 */
+       { 0xFF, 0xFF, 0 }, /* 8E DAI2 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 8F DAI2 EQ2 */
+
+       { 0xFF, 0xFF, 0 }, /* 90 DAI2 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 91 DAI2 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 92 DAI2 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 93 DAI2 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 94 DAI2 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 95 DAI2 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 96 DAI2 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 97 DAI2 EQ2 */
+       { 0xFF, 0xFF, 0 }, /* 98 DAI2 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 99 DAI2 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 9A DAI2 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 9B DAI2 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 9C DAI2 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 9D DAI2 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 9E DAI2 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* 9F DAI2 EQ3 */
+
+       { 0xFF, 0xFF, 0 }, /* A0 DAI2 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* A1 DAI2 EQ3 */
+       { 0xFF, 0xFF, 0 }, /* A2 DAI2 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* A3 DAI2 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* A4 DAI2 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* A5 DAI2 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* A6 DAI2 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* A7 DAI2 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* A8 DAI2 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* A9 DAI2 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* AA DAI2 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* AB DAI2 EQ4 */
+       { 0xFF, 0xFF, 0 }, /* AC DAI2 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* AD DAI2 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* AE DAI2 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* AF DAI2 EQ5 */
+
+       { 0xFF, 0xFF, 0 }, /* B0 DAI2 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* B1 DAI2 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* B2 DAI2 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* B3 DAI2 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* B4 DAI2 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* B5 DAI2 EQ5 */
+       { 0xFF, 0xFF, 0 }, /* B6 DAI1 biquad */
+       { 0xFF, 0xFF, 0 }, /* B7 DAI1 biquad */
+       { 0xFF, 0xFF, 0 }, /* B8 DAI1 biquad */
+       { 0xFF, 0xFF, 0 }, /* B9 DAI1 biquad */
+       { 0xFF, 0xFF, 0 }, /* BA DAI1 biquad */
+       { 0xFF, 0xFF, 0 }, /* BB DAI1 biquad */
+       { 0xFF, 0xFF, 0 }, /* BC DAI1 biquad */
+       { 0xFF, 0xFF, 0 }, /* BD DAI1 biquad */
+       { 0xFF, 0xFF, 0 }, /* BE DAI1 biquad */
+       { 0xFF, 0xFF, 0 }, /* BF DAI1 biquad */
+
+       { 0xFF, 0xFF, 0 }, /* C0 DAI2 biquad */
+       { 0xFF, 0xFF, 0 }, /* C1 DAI2 biquad */
+       { 0xFF, 0xFF, 0 }, /* C2 DAI2 biquad */
+       { 0xFF, 0xFF, 0 }, /* C3 DAI2 biquad */
+       { 0xFF, 0xFF, 0 }, /* C4 DAI2 biquad */
+       { 0xFF, 0xFF, 0 }, /* C5 DAI2 biquad */
+       { 0xFF, 0xFF, 0 }, /* C6 DAI2 biquad */
+       { 0xFF, 0xFF, 0 }, /* C7 DAI2 biquad */
+       { 0xFF, 0xFF, 0 }, /* C8 DAI2 biquad */
+       { 0xFF, 0xFF, 0 }, /* C9 DAI2 biquad */
+       { 0x00, 0x00, 0 }, /* CA */
+       { 0x00, 0x00, 0 }, /* CB */
+       { 0x00, 0x00, 0 }, /* CC */
+       { 0x00, 0x00, 0 }, /* CD */
+       { 0x00, 0x00, 0 }, /* CE */
+       { 0x00, 0x00, 0 }, /* CF */
+
+       { 0x00, 0x00, 0 }, /* D0 */
+       { 0x00, 0x00, 0 }, /* D1 */
+       { 0x00, 0x00, 0 }, /* D2 */
+       { 0x00, 0x00, 0 }, /* D3 */
+       { 0x00, 0x00, 0 }, /* D4 */
+       { 0x00, 0x00, 0 }, /* D5 */
+       { 0x00, 0x00, 0 }, /* D6 */
+       { 0x00, 0x00, 0 }, /* D7 */
+       { 0x00, 0x00, 0 }, /* D8 */
+       { 0x00, 0x00, 0 }, /* D9 */
+       { 0x00, 0x00, 0 }, /* DA */
+       { 0x00, 0x00, 0 }, /* DB */
+       { 0x00, 0x00, 0 }, /* DC */
+       { 0x00, 0x00, 0 }, /* DD */
+       { 0x00, 0x00, 0 }, /* DE */
+       { 0x00, 0x00, 0 }, /* DF */
+
+       { 0x00, 0x00, 0 }, /* E0 */
+       { 0x00, 0x00, 0 }, /* E1 */
+       { 0x00, 0x00, 0 }, /* E2 */
+       { 0x00, 0x00, 0 }, /* E3 */
+       { 0x00, 0x00, 0 }, /* E4 */
+       { 0x00, 0x00, 0 }, /* E5 */
+       { 0x00, 0x00, 0 }, /* E6 */
+       { 0x00, 0x00, 0 }, /* E7 */
+       { 0x00, 0x00, 0 }, /* E8 */
+       { 0x00, 0x00, 0 }, /* E9 */
+       { 0x00, 0x00, 0 }, /* EA */
+       { 0x00, 0x00, 0 }, /* EB */
+       { 0x00, 0x00, 0 }, /* EC */
+       { 0x00, 0x00, 0 }, /* ED */
+       { 0x00, 0x00, 0 }, /* EE */
+       { 0x00, 0x00, 0 }, /* EF */
+
+       { 0x00, 0x00, 0 }, /* F0 */
+       { 0x00, 0x00, 0 }, /* F1 */
+       { 0x00, 0x00, 0 }, /* F2 */
+       { 0x00, 0x00, 0 }, /* F3 */
+       { 0x00, 0x00, 0 }, /* F4 */
+       { 0x00, 0x00, 0 }, /* F5 */
+       { 0x00, 0x00, 0 }, /* F6 */
+       { 0x00, 0x00, 0 }, /* F7 */
+       { 0x00, 0x00, 0 }, /* F8 */
+       { 0x00, 0x00, 0 }, /* F9 */
+       { 0x00, 0x00, 0 }, /* FA */
+       { 0x00, 0x00, 0 }, /* FB */
+       { 0x00, 0x00, 0 }, /* FC */
+       { 0x00, 0x00, 0 }, /* FD */
+       { 0x00, 0x00, 0 }, /* FE */
+       { 0xFF, 0x00, 1 }, /* FF */
+};
+
+static int max98088_volatile_register(unsigned int reg)
+{
+       return max98088_access[reg].vol;
+}
+
+
+/*
+ * Load equalizer DSP coefficient configurations registers
+ */
+static void m98088_eq_band(struct snd_soc_codec *codec, unsigned int dai,
+                   unsigned int band, u16 *coefs)
+{
+       unsigned int eq_reg;
+       unsigned int i;
+
+       BUG_ON(band > 4);
+       BUG_ON(dai > 1);
+
+       /* Load the base register address */
+       eq_reg = dai ? M98088_REG_84_DAI2_EQ_BASE : M98088_REG_52_DAI1_EQ_BASE;
+
+       /* Add the band address offset, note adjustment for word address */
+       eq_reg += band * (M98088_COEFS_PER_BAND << 1);
+
+       /* Step through the registers and coefs */
+       for (i = 0; i < M98088_COEFS_PER_BAND; i++) {
+               snd_soc_write(codec, eq_reg++, M98088_BYTE1(coefs[i]));
+               snd_soc_write(codec, eq_reg++, M98088_BYTE0(coefs[i]));
+       }
+}
+
+/*
+ * Excursion limiter modes
+ */
+static const char *max98088_exmode_texts[] = {
+       "Off", "100Hz", "400Hz", "600Hz", "800Hz", "1000Hz", "200-400Hz",
+       "400-600Hz", "400-800Hz",
+};
+
+static const unsigned int max98088_exmode_values[] = {
+       0x00, 0x43, 0x10, 0x20, 0x30, 0x40, 0x11, 0x22, 0x32
+};
+
+static const struct soc_enum max98088_exmode_enum =
+       SOC_VALUE_ENUM_SINGLE(M98088_REG_41_SPKDHP, 0, 127,
+                             ARRAY_SIZE(max98088_exmode_texts),
+                             max98088_exmode_texts,
+                             max98088_exmode_values);
+static const struct snd_kcontrol_new max98088_exmode_controls =
+       SOC_DAPM_VALUE_ENUM("Route", max98088_exmode_enum);
+
+static const char *max98088_ex_thresh[] = { /* volts PP */
+       "0.6", "1.2", "1.8", "2.4", "3.0", "3.6", "4.2", "4.8"};
+static const struct soc_enum max98088_ex_thresh_enum[] = {
+       SOC_ENUM_SINGLE(M98088_REG_42_SPKDHP_THRESH, 0, 8,
+               max98088_ex_thresh),
+};
+
+static const char *max98088_fltr_mode[] = {"Voice", "Music" };
+static const struct soc_enum max98088_filter_mode_enum[] = {
+       SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 7, 2, max98088_fltr_mode),
+};
+
+static const char *max98088_extmic_text[] = { "None", "MIC1", "MIC2" };
+
+static const struct soc_enum max98088_extmic_enum =
+       SOC_ENUM_SINGLE(M98088_REG_48_CFG_MIC, 0, 3, max98088_extmic_text);
+
+static const struct snd_kcontrol_new max98088_extmic_mux =
+       SOC_DAPM_ENUM("External MIC Mux", max98088_extmic_enum);
+
+static const char *max98088_dai1_fltr[] = {
+       "Off", "fc=258/fs=16k", "fc=500/fs=16k",
+       "fc=258/fs=8k", "fc=500/fs=8k", "fc=200"};
+static const struct soc_enum max98088_dai1_dac_filter_enum[] = {
+       SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 0, 6, max98088_dai1_fltr),
+};
+static const struct soc_enum max98088_dai1_adc_filter_enum[] = {
+       SOC_ENUM_SINGLE(M98088_REG_18_DAI1_FILTERS, 4, 6, max98088_dai1_fltr),
+};
+
+static int max98088_mic1pre_set(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       unsigned int sel = ucontrol->value.integer.value[0];
+
+       max98088->mic1pre = sel;
+       snd_soc_update_bits(codec, M98088_REG_35_LVL_MIC1, M98088_MICPRE_MASK,
+               (1+sel)<<M98088_MICPRE_SHIFT);
+
+       return 0;
+}
+
+static int max98088_mic1pre_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = max98088->mic1pre;
+       return 0;
+}
+
+static int max98088_mic2pre_set(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       unsigned int sel = ucontrol->value.integer.value[0];
+
+       max98088->mic2pre = sel;
+       snd_soc_update_bits(codec, M98088_REG_36_LVL_MIC2, M98088_MICPRE_MASK,
+               (1+sel)<<M98088_MICPRE_SHIFT);
+
+       return 0;
+}
+
+static int max98088_mic2pre_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = max98088->mic2pre;
+       return 0;
+}
+
+static const unsigned int max98088_micboost_tlv[] = {
+       TLV_DB_RANGE_HEAD(2),
+       0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
+       2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
+};
+
+static const struct snd_kcontrol_new max98088_snd_controls[] = {
+
+       SOC_DOUBLE_R("Headphone Volume", M98088_REG_39_LVL_HP_L,
+               M98088_REG_3A_LVL_HP_R, 0, 31, 0),
+       SOC_DOUBLE_R("Speaker Volume", M98088_REG_3D_LVL_SPK_L,
+               M98088_REG_3E_LVL_SPK_R, 0, 31, 0),
+       SOC_DOUBLE_R("Receiver Volume", M98088_REG_3B_LVL_REC_L,
+               M98088_REG_3C_LVL_REC_R, 0, 31, 0),
+
+       SOC_DOUBLE_R("Headphone Switch", M98088_REG_39_LVL_HP_L,
+               M98088_REG_3A_LVL_HP_R, 7, 1, 1),
+       SOC_DOUBLE_R("Speaker Switch", M98088_REG_3D_LVL_SPK_L,
+               M98088_REG_3E_LVL_SPK_R, 7, 1, 1),
+       SOC_DOUBLE_R("Receiver Switch", M98088_REG_3B_LVL_REC_L,
+               M98088_REG_3C_LVL_REC_R, 7, 1, 1),
+
+       SOC_SINGLE("MIC1 Volume", M98088_REG_35_LVL_MIC1, 0, 31, 1),
+       SOC_SINGLE("MIC2 Volume", M98088_REG_36_LVL_MIC2, 0, 31, 1),
+
+       SOC_SINGLE_EXT_TLV("MIC1 Boost Volume",
+                       M98088_REG_35_LVL_MIC1, 5, 2, 0,
+                       max98088_mic1pre_get, max98088_mic1pre_set,
+                       max98088_micboost_tlv),
+       SOC_SINGLE_EXT_TLV("MIC2 Boost Volume",
+                       M98088_REG_36_LVL_MIC2, 5, 2, 0,
+                       max98088_mic2pre_get, max98088_mic2pre_set,
+                       max98088_micboost_tlv),
+
+       SOC_SINGLE("INA Volume", M98088_REG_37_LVL_INA, 0, 7, 1),
+       SOC_SINGLE("INB Volume", M98088_REG_38_LVL_INB, 0, 7, 1),
+
+       SOC_SINGLE("ADCL Volume", M98088_REG_33_LVL_ADC_L, 0, 15, 0),
+       SOC_SINGLE("ADCR Volume", M98088_REG_34_LVL_ADC_R, 0, 15, 0),
+
+       SOC_SINGLE("ADCL Boost Volume", M98088_REG_33_LVL_ADC_L, 4, 3, 0),
+       SOC_SINGLE("ADCR Boost Volume", M98088_REG_34_LVL_ADC_R, 4, 3, 0),
+
+       SOC_SINGLE("EQ1 Switch", M98088_REG_49_CFG_LEVEL, 0, 1, 0),
+       SOC_SINGLE("EQ2 Switch", M98088_REG_49_CFG_LEVEL, 1, 1, 0),
+
+       SOC_ENUM("EX Limiter Threshold", max98088_ex_thresh_enum),
+
+       SOC_ENUM("DAI1 Filter Mode", max98088_filter_mode_enum),
+       SOC_ENUM("DAI1 DAC Filter", max98088_dai1_dac_filter_enum),
+       SOC_ENUM("DAI1 ADC Filter", max98088_dai1_adc_filter_enum),
+       SOC_SINGLE("DAI2 DC Block Switch", M98088_REG_20_DAI2_FILTERS,
+               0, 1, 0),
+
+       SOC_SINGLE("ALC Switch", M98088_REG_43_SPKALC_COMP, 7, 1, 0),
+       SOC_SINGLE("ALC Threshold", M98088_REG_43_SPKALC_COMP, 0, 7, 0),
+       SOC_SINGLE("ALC Multiband", M98088_REG_43_SPKALC_COMP, 3, 1, 0),
+       SOC_SINGLE("ALC Release Time", M98088_REG_43_SPKALC_COMP, 4, 7, 0),
+
+       SOC_SINGLE("PWR Limiter Threshold", M98088_REG_44_PWRLMT_CFG,
+               4, 15, 0),
+       SOC_SINGLE("PWR Limiter Weight", M98088_REG_44_PWRLMT_CFG, 0, 7, 0),
+       SOC_SINGLE("PWR Limiter Time1", M98088_REG_45_PWRLMT_TIME, 0, 15, 0),
+       SOC_SINGLE("PWR Limiter Time2", M98088_REG_45_PWRLMT_TIME, 4, 15, 0),
+
+       SOC_SINGLE("THD Limiter Threshold", M98088_REG_46_THDLMT_CFG, 4, 15, 0),
+       SOC_SINGLE("THD Limiter Time", M98088_REG_46_THDLMT_CFG, 0, 7, 0),
+};
+
+/* Left speaker mixer switch */
+static const struct snd_kcontrol_new max98088_left_speaker_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 4, 1, 0),
+};
+
+/* Right speaker mixer switch */
+static const struct snd_kcontrol_new max98088_right_speaker_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 4, 1, 0),
+};
+
+/* Left headphone mixer switch */
+static const struct snd_kcontrol_new max98088_left_hp_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_25_MIX_HP_LEFT, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_25_MIX_HP_LEFT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_25_MIX_HP_LEFT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_25_MIX_HP_LEFT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_25_MIX_HP_LEFT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_25_MIX_HP_LEFT, 4, 1, 0),
+};
+
+/* Right headphone mixer switch */
+static const struct snd_kcontrol_new max98088_right_hp_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_26_MIX_HP_RIGHT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_26_MIX_HP_RIGHT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_26_MIX_HP_RIGHT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_26_MIX_HP_RIGHT, 4, 1, 0),
+};
+
+/* Left earpiece/receiver mixer switch */
+static const struct snd_kcontrol_new max98088_left_rec_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_28_MIX_REC_LEFT, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_28_MIX_REC_LEFT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_28_MIX_REC_LEFT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_28_MIX_REC_LEFT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_28_MIX_REC_LEFT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_28_MIX_REC_LEFT, 4, 1, 0),
+};
+
+/* Right earpiece/receiver mixer switch */
+static const struct snd_kcontrol_new max98088_right_rec_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0),
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 5, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_29_MIX_REC_RIGHT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_29_MIX_REC_RIGHT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_29_MIX_REC_RIGHT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_29_MIX_REC_RIGHT, 4, 1, 0),
+};
+
+/* Left ADC mixer switch */
+static const struct snd_kcontrol_new max98088_left_ADC_mixer_controls[] = {
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_23_MIX_ADC_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_23_MIX_ADC_LEFT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_23_MIX_ADC_LEFT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_23_MIX_ADC_LEFT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_23_MIX_ADC_LEFT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_23_MIX_ADC_LEFT, 0, 1, 0),
+};
+
+/* Right ADC mixer switch */
+static const struct snd_kcontrol_new max98088_right_ADC_mixer_controls[] = {
+       SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 7, 1, 0),
+       SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 6, 1, 0),
+       SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 3, 1, 0),
+       SOC_DAPM_SINGLE("INA2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 2, 1, 0),
+       SOC_DAPM_SINGLE("INB1 Switch", M98088_REG_24_MIX_ADC_RIGHT, 1, 1, 0),
+       SOC_DAPM_SINGLE("INB2 Switch", M98088_REG_24_MIX_ADC_RIGHT, 0, 1, 0),
+};
+
+static int max98088_mic_event(struct snd_soc_dapm_widget *w,
+                            struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               if (w->reg == M98088_REG_35_LVL_MIC1) {
+                       snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK,
+                               (1+max98088->mic1pre)<<M98088_MICPRE_SHIFT);
+               } else {
+                       snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK,
+                               (1+max98088->mic2pre)<<M98088_MICPRE_SHIFT);
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, w->reg, M98088_MICPRE_MASK, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * The line inputs are 2-channel stereo inputs with the left
+ * and right channels sharing a common PGA power control signal.
+ */
+static int max98088_line_pga(struct snd_soc_dapm_widget *w,
+                            int event, int line, u8 channel)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       u8 *state;
+
+       BUG_ON(!((channel == 1) || (channel == 2)));
+
+       switch (line) {
+       case LINE_INA:
+               state = &max98088->ina_state;
+               break;
+       case LINE_INB:
+               state = &max98088->inb_state;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               *state |= channel;
+               snd_soc_update_bits(codec, w->reg,
+                       (1 << w->shift), (1 << w->shift));
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               *state &= ~channel;
+               if (*state == 0) {
+                       snd_soc_update_bits(codec, w->reg,
+                               (1 << w->shift), 0);
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int max98088_pga_ina1_event(struct snd_soc_dapm_widget *w,
+                                  struct snd_kcontrol *k, int event)
+{
+       return max98088_line_pga(w, event, LINE_INA, 1);
+}
+
+static int max98088_pga_ina2_event(struct snd_soc_dapm_widget *w,
+                                  struct snd_kcontrol *k, int event)
+{
+       return max98088_line_pga(w, event, LINE_INA, 2);
+}
+
+static int max98088_pga_inb1_event(struct snd_soc_dapm_widget *w,
+                                  struct snd_kcontrol *k, int event)
+{
+       return max98088_line_pga(w, event, LINE_INB, 1);
+}
+
+static int max98088_pga_inb2_event(struct snd_soc_dapm_widget *w,
+                                  struct snd_kcontrol *k, int event)
+{
+       return max98088_line_pga(w, event, LINE_INB, 2);
+}
+
+static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = {
+
+       SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 1, 0),
+       SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 0, 0),
+
+       SND_SOC_DAPM_DAC("DACL1", "HiFi Playback",
+               M98088_REG_4D_PWR_EN_OUT, 1, 0),
+       SND_SOC_DAPM_DAC("DACR1", "HiFi Playback",
+               M98088_REG_4D_PWR_EN_OUT, 0, 0),
+       SND_SOC_DAPM_DAC("DACL2", "Aux Playback",
+               M98088_REG_4D_PWR_EN_OUT, 1, 0),
+       SND_SOC_DAPM_DAC("DACR2", "Aux Playback",
+               M98088_REG_4D_PWR_EN_OUT, 0, 0),
+
+       SND_SOC_DAPM_PGA("HP Left Out", M98088_REG_4D_PWR_EN_OUT,
+               7, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("HP Right Out", M98088_REG_4D_PWR_EN_OUT,
+               6, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("SPK Left Out", M98088_REG_4D_PWR_EN_OUT,
+               5, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("SPK Right Out", M98088_REG_4D_PWR_EN_OUT,
+               4, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("REC Left Out", M98088_REG_4D_PWR_EN_OUT,
+               3, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("REC Right Out", M98088_REG_4D_PWR_EN_OUT,
+               2, 0, NULL, 0),
+
+       SND_SOC_DAPM_MUX("External MIC", SND_SOC_NOPM, 0, 0,
+               &max98088_extmic_mux),
+
+       SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
+               &max98088_left_hp_mixer_controls[0],
+               ARRAY_SIZE(max98088_left_hp_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0,
+               &max98088_right_hp_mixer_controls[0],
+               ARRAY_SIZE(max98088_right_hp_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Left SPK Mixer", SND_SOC_NOPM, 0, 0,
+               &max98088_left_speaker_mixer_controls[0],
+               ARRAY_SIZE(max98088_left_speaker_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Right SPK Mixer", SND_SOC_NOPM, 0, 0,
+               &max98088_right_speaker_mixer_controls[0],
+               ARRAY_SIZE(max98088_right_speaker_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Left REC Mixer", SND_SOC_NOPM, 0, 0,
+         &max98088_left_rec_mixer_controls[0],
+               ARRAY_SIZE(max98088_left_rec_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Right REC Mixer", SND_SOC_NOPM, 0, 0,
+         &max98088_right_rec_mixer_controls[0],
+               ARRAY_SIZE(max98088_right_rec_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
+               &max98088_left_ADC_mixer_controls[0],
+               ARRAY_SIZE(max98088_left_ADC_mixer_controls)),
+
+       SND_SOC_DAPM_MIXER("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
+               &max98088_right_ADC_mixer_controls[0],
+               ARRAY_SIZE(max98088_right_ADC_mixer_controls)),
+
+       SND_SOC_DAPM_PGA_E("MIC1 Input", M98088_REG_35_LVL_MIC1,
+               5, 0, NULL, 0, max98088_mic_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_PGA_E("MIC2 Input", M98088_REG_36_LVL_MIC2,
+               5, 0, NULL, 0, max98088_mic_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_PGA_E("INA1 Input", M98088_REG_4C_PWR_EN_IN,
+               7, 0, NULL, 0, max98088_pga_ina1_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_PGA_E("INA2 Input", M98088_REG_4C_PWR_EN_IN,
+               7, 0, NULL, 0, max98088_pga_ina2_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_PGA_E("INB1 Input", M98088_REG_4C_PWR_EN_IN,
+               6, 0, NULL, 0, max98088_pga_inb1_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_PGA_E("INB2 Input", M98088_REG_4C_PWR_EN_IN,
+               6, 0, NULL, 0, max98088_pga_inb2_event,
+               SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MICBIAS("MICBIAS", M98088_REG_4C_PWR_EN_IN, 3, 0),
+
+       SND_SOC_DAPM_MUX("EX Limiter Mode", SND_SOC_NOPM, 0, 0,
+               &max98088_exmode_controls),
+
+       SND_SOC_DAPM_OUTPUT("HPL"),
+       SND_SOC_DAPM_OUTPUT("HPR"),
+       SND_SOC_DAPM_OUTPUT("SPKL"),
+       SND_SOC_DAPM_OUTPUT("SPKR"),
+       SND_SOC_DAPM_OUTPUT("RECL"),
+       SND_SOC_DAPM_OUTPUT("RECR"),
+
+       SND_SOC_DAPM_INPUT("MIC1"),
+       SND_SOC_DAPM_INPUT("MIC2"),
+       SND_SOC_DAPM_INPUT("INA1"),
+       SND_SOC_DAPM_INPUT("INA2"),
+       SND_SOC_DAPM_INPUT("INB1"),
+       SND_SOC_DAPM_INPUT("INB2"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       /* Left headphone output mixer */
+       {"Left HP Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Left HP Mixer", "Left DAC2 Switch", "DACL2"},
+       {"Left HP Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Left HP Mixer", "Right DAC2 Switch", "DACR2"},
+       {"Left HP Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Left HP Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Left HP Mixer", "INA1 Switch", "INA1 Input"},
+       {"Left HP Mixer", "INA2 Switch", "INA2 Input"},
+       {"Left HP Mixer", "INB1 Switch", "INB1 Input"},
+       {"Left HP Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Right headphone output mixer */
+       {"Right HP Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Right HP Mixer", "Left DAC2 Switch", "DACL2"  },
+       {"Right HP Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Right HP Mixer", "Right DAC2 Switch", "DACR2"},
+       {"Right HP Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Right HP Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Right HP Mixer", "INA1 Switch", "INA1 Input"},
+       {"Right HP Mixer", "INA2 Switch", "INA2 Input"},
+       {"Right HP Mixer", "INB1 Switch", "INB1 Input"},
+       {"Right HP Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Left speaker output mixer */
+       {"Left SPK Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Left SPK Mixer", "Left DAC2 Switch", "DACL2"},
+       {"Left SPK Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Left SPK Mixer", "Right DAC2 Switch", "DACR2"},
+       {"Left SPK Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Left SPK Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Left SPK Mixer", "INA1 Switch", "INA1 Input"},
+       {"Left SPK Mixer", "INA2 Switch", "INA2 Input"},
+       {"Left SPK Mixer", "INB1 Switch", "INB1 Input"},
+       {"Left SPK Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Right speaker output mixer */
+       {"Right SPK Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Right SPK Mixer", "Left DAC2 Switch", "DACL2"},
+       {"Right SPK Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Right SPK Mixer", "Right DAC2 Switch", "DACR2"},
+       {"Right SPK Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Right SPK Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Right SPK Mixer", "INA1 Switch", "INA1 Input"},
+       {"Right SPK Mixer", "INA2 Switch", "INA2 Input"},
+       {"Right SPK Mixer", "INB1 Switch", "INB1 Input"},
+       {"Right SPK Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Earpiece/Receiver output mixer */
+       {"Left REC Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Left REC Mixer", "Left DAC2 Switch", "DACL2"},
+       {"Left REC Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Left REC Mixer", "Right DAC2 Switch", "DACR2"},
+       {"Left REC Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Left REC Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Left REC Mixer", "INA1 Switch", "INA1 Input"},
+       {"Left REC Mixer", "INA2 Switch", "INA2 Input"},
+       {"Left REC Mixer", "INB1 Switch", "INB1 Input"},
+       {"Left REC Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Earpiece/Receiver output mixer */
+       {"Right REC Mixer", "Left DAC1 Switch", "DACL1"},
+       {"Right REC Mixer", "Left DAC2 Switch", "DACL2"},
+       {"Right REC Mixer", "Right DAC1 Switch", "DACR1"},
+       {"Right REC Mixer", "Right DAC2 Switch", "DACR2"},
+       {"Right REC Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Right REC Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Right REC Mixer", "INA1 Switch", "INA1 Input"},
+       {"Right REC Mixer", "INA2 Switch", "INA2 Input"},
+       {"Right REC Mixer", "INB1 Switch", "INB1 Input"},
+       {"Right REC Mixer", "INB2 Switch", "INB2 Input"},
+
+       {"HP Left Out", NULL, "Left HP Mixer"},
+       {"HP Right Out", NULL, "Right HP Mixer"},
+       {"SPK Left Out", NULL, "Left SPK Mixer"},
+       {"SPK Right Out", NULL, "Right SPK Mixer"},
+       {"REC Left Out", NULL, "Left REC Mixer"},
+       {"REC Right Out", NULL, "Right REC Mixer"},
+
+       {"HPL", NULL, "HP Left Out"},
+       {"HPR", NULL, "HP Right Out"},
+       {"SPKL", NULL, "SPK Left Out"},
+       {"SPKR", NULL, "SPK Right Out"},
+       {"RECL", NULL, "REC Left Out"},
+       {"RECR", NULL, "REC Right Out"},
+
+       /* Left ADC input mixer */
+       {"Left ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Left ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Left ADC Mixer", "INA1 Switch", "INA1 Input"},
+       {"Left ADC Mixer", "INA2 Switch", "INA2 Input"},
+       {"Left ADC Mixer", "INB1 Switch", "INB1 Input"},
+       {"Left ADC Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Right ADC input mixer */
+       {"Right ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+       {"Right ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+       {"Right ADC Mixer", "INA1 Switch", "INA1 Input"},
+       {"Right ADC Mixer", "INA2 Switch", "INA2 Input"},
+       {"Right ADC Mixer", "INB1 Switch", "INB1 Input"},
+       {"Right ADC Mixer", "INB2 Switch", "INB2 Input"},
+
+       /* Inputs */
+       {"ADCL", NULL, "Left ADC Mixer"},
+       {"ADCR", NULL, "Right ADC Mixer"},
+       {"INA1 Input", NULL, "INA1"},
+       {"INA2 Input", NULL, "INA2"},
+       {"INB1 Input", NULL, "INB1"},
+       {"INB2 Input", NULL, "INB2"},
+       {"MIC1 Input", NULL, "MIC1"},
+       {"MIC2 Input", NULL, "MIC2"},
+};
+
+static int max98088_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, max98088_dapm_widgets,
+                                 ARRAY_SIZE(max98088_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, 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);
+       return 0;
+}
+
+/* codec mclk clock divider coefficients */
+static const struct {
+       u32 rate;
+       u8  sr;
+} rate_table[] = {
+       {8000,  0x10},
+       {11025, 0x20},
+       {16000, 0x30},
+       {22050, 0x40},
+       {24000, 0x50},
+       {32000, 0x60},
+       {44100, 0x70},
+       {48000, 0x80},
+       {88200, 0x90},
+       {96000, 0xA0},
+};
+
+static inline int rate_value(int rate, u8 *value)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
+               if (rate_table[i].rate >= rate) {
+                       *value = rate_table[i].sr;
+                       return 0;
+               }
+       }
+       *value = rate_table[0].sr;
+       return -EINVAL;
+}
+
+static int max98088_dai1_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 max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_cdata *cdata;
+       unsigned long long ni;
+       unsigned int rate;
+       u8 regval;
+
+       cdata = &max98088->dai[0];
+
+       rate = params_rate(params);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+                       M98088_DAI_WS, 0);
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+                       M98088_DAI_WS, M98088_DAI_WS);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN, 0);
+
+       if (rate_value(rate, &regval))
+               return -EINVAL;
+
+       snd_soc_update_bits(codec, M98088_REG_11_DAI1_CLKMODE,
+               M98088_CLKMODE_MASK, regval);
+       cdata->rate = rate;
+
+       /* Configure NI when operating as master */
+       if (snd_soc_read(codec, M98088_REG_14_DAI1_FORMAT)
+               & M98088_DAI_MAS) {
+               if (max98088->sysclk == 0) {
+                       dev_err(codec->dev, "Invalid system clock frequency\n");
+                       return -EINVAL;
+               }
+               ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+                               * (unsigned long long int)rate;
+               do_div(ni, (unsigned long long int)max98088->sysclk);
+               snd_soc_write(codec, M98088_REG_12_DAI1_CLKCFG_HI,
+                       (ni >> 8) & 0x7F);
+               snd_soc_write(codec, M98088_REG_13_DAI1_CLKCFG_LO,
+                       ni & 0xFF);
+       }
+
+       /* Update sample rate mode */
+       if (rate < 50000)
+               snd_soc_update_bits(codec, M98088_REG_18_DAI1_FILTERS,
+                       M98088_DAI_DHF, 0);
+       else
+               snd_soc_update_bits(codec, M98088_REG_18_DAI1_FILTERS,
+                       M98088_DAI_DHF, M98088_DAI_DHF);
+
+       snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN,
+               M98088_SHDNRUN);
+
+       return 0;
+}
+
+static int max98088_dai2_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 max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_cdata *cdata;
+       unsigned long long ni;
+       unsigned int rate;
+       u8 regval;
+
+       cdata = &max98088->dai[1];
+
+       rate = params_rate(params);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+                       M98088_DAI_WS, 0);
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+                       M98088_DAI_WS, M98088_DAI_WS);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN, 0);
+
+       if (rate_value(rate, &regval))
+               return -EINVAL;
+
+       snd_soc_update_bits(codec, M98088_REG_19_DAI2_CLKMODE,
+               M98088_CLKMODE_MASK, regval);
+       cdata->rate = rate;
+
+       /* Configure NI when operating as master */
+       if (snd_soc_read(codec, M98088_REG_1C_DAI2_FORMAT)
+               & M98088_DAI_MAS) {
+               if (max98088->sysclk == 0) {
+                       dev_err(codec->dev, "Invalid system clock frequency\n");
+                       return -EINVAL;
+               }
+               ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+                               * (unsigned long long int)rate;
+               do_div(ni, (unsigned long long int)max98088->sysclk);
+               snd_soc_write(codec, M98088_REG_1A_DAI2_CLKCFG_HI,
+                       (ni >> 8) & 0x7F);
+               snd_soc_write(codec, M98088_REG_1B_DAI2_CLKCFG_LO,
+                       ni & 0xFF);
+       }
+
+       /* Update sample rate mode */
+       if (rate < 50000)
+               snd_soc_update_bits(codec, M98088_REG_20_DAI2_FILTERS,
+                       M98088_DAI_DHF, 0);
+       else
+               snd_soc_update_bits(codec, M98088_REG_20_DAI2_FILTERS,
+                       M98088_DAI_DHF, M98088_DAI_DHF);
+
+       snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS, M98088_SHDNRUN,
+               M98088_SHDNRUN);
+
+       return 0;
+}
+
+static int max98088_dai_set_sysclk(struct snd_soc_dai *dai,
+                                  int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+       /* Requested clock frequency is already setup */
+       if (freq == max98088->sysclk)
+               return 0;
+
+       max98088->sysclk = freq; /* remember current sysclk */
+
+       /* Setup clocks for slave mode, and using the PLL
+        * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
+        *         0x02 (when master clk is 20MHz to 30MHz)..
+        */
+       if ((freq >= 10000000) && (freq < 20000000)) {
+               snd_soc_write(codec, M98088_REG_10_SYS_CLK, 0x10);
+       } else if ((freq >= 20000000) && (freq < 30000000)) {
+               snd_soc_write(codec, M98088_REG_10_SYS_CLK, 0x20);
+       } else {
+               dev_err(codec->dev, "Invalid master clock frequency\n");
+               return -EINVAL;
+       }
+
+       if (snd_soc_read(codec, M98088_REG_51_PWR_SYS)  & M98088_SHDNRUN) {
+               snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS,
+                       M98088_SHDNRUN, 0);
+               snd_soc_update_bits(codec, M98088_REG_51_PWR_SYS,
+                       M98088_SHDNRUN, M98088_SHDNRUN);
+       }
+
+       dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq);
+
+       max98088->sysclk = freq;
+       return 0;
+}
+
+static int max98088_dai1_set_fmt(struct snd_soc_dai *codec_dai,
+                                unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_cdata *cdata;
+       u8 reg15val;
+       u8 reg14val = 0;
+
+       cdata = &max98088->dai[0];
+
+       if (fmt != cdata->fmt) {
+               cdata->fmt = fmt;
+
+               switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+               case SND_SOC_DAIFMT_CBS_CFS:
+                       /* Slave mode PLL */
+                       snd_soc_write(codec, M98088_REG_12_DAI1_CLKCFG_HI,
+                               0x80);
+                       snd_soc_write(codec, M98088_REG_13_DAI1_CLKCFG_LO,
+                               0x00);
+                       break;
+               case SND_SOC_DAIFMT_CBM_CFM:
+                       /* Set to master mode */
+                       reg14val |= M98088_DAI_MAS;
+                       break;
+               case SND_SOC_DAIFMT_CBS_CFM:
+               case SND_SOC_DAIFMT_CBM_CFS:
+               default:
+                       dev_err(codec->dev, "Clock mode unsupported");
+                       return -EINVAL;
+               }
+
+               switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+               case SND_SOC_DAIFMT_I2S:
+                       reg14val |= M98088_DAI_DLY;
+                       break;
+               case SND_SOC_DAIFMT_LEFT_J:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       reg14val |= M98088_DAI_WCI;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       reg14val |= M98088_DAI_BCI;
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       reg14val |= M98088_DAI_BCI|M98088_DAI_WCI;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
+                       M98088_DAI_MAS | M98088_DAI_DLY | M98088_DAI_BCI |
+                       M98088_DAI_WCI, reg14val);
+
+               reg15val = M98088_DAI_BSEL64;
+               if (max98088->digmic)
+                       reg15val |= M98088_DAI_OSR64;
+               snd_soc_write(codec, M98088_REG_15_DAI1_CLOCK, reg15val);
+       }
+
+       return 0;
+}
+
+static int max98088_dai2_set_fmt(struct snd_soc_dai *codec_dai,
+                                unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_cdata *cdata;
+       u8 reg1Cval = 0;
+
+       cdata = &max98088->dai[1];
+
+       if (fmt != cdata->fmt) {
+               cdata->fmt = fmt;
+
+               switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+               case SND_SOC_DAIFMT_CBS_CFS:
+                       /* Slave mode PLL */
+                       snd_soc_write(codec, M98088_REG_1A_DAI2_CLKCFG_HI,
+                               0x80);
+                       snd_soc_write(codec, M98088_REG_1B_DAI2_CLKCFG_LO,
+                               0x00);
+                       break;
+               case SND_SOC_DAIFMT_CBM_CFM:
+                       /* Set to master mode */
+                       reg1Cval |= M98088_DAI_MAS;
+                       break;
+               case SND_SOC_DAIFMT_CBS_CFM:
+               case SND_SOC_DAIFMT_CBM_CFS:
+               default:
+                       dev_err(codec->dev, "Clock mode unsupported");
+                       return -EINVAL;
+               }
+
+               switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+               case SND_SOC_DAIFMT_I2S:
+                       reg1Cval |= M98088_DAI_DLY;
+                       break;
+               case SND_SOC_DAIFMT_LEFT_J:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+                       break;
+               case SND_SOC_DAIFMT_NB_IF:
+                       reg1Cval |= M98088_DAI_WCI;
+                       break;
+               case SND_SOC_DAIFMT_IB_NF:
+                       reg1Cval |= M98088_DAI_BCI;
+                       break;
+               case SND_SOC_DAIFMT_IB_IF:
+                       reg1Cval |= M98088_DAI_BCI|M98088_DAI_WCI;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               snd_soc_update_bits(codec, M98088_REG_1C_DAI2_FORMAT,
+                       M98088_DAI_MAS | M98088_DAI_DLY | M98088_DAI_BCI |
+                       M98088_DAI_WCI, reg1Cval);
+
+               snd_soc_write(codec, M98088_REG_1D_DAI2_CLOCK,
+                       M98088_DAI_BSEL64);
+       }
+
+       return 0;
+}
+
+static void max98088_sync_cache(struct snd_soc_codec *codec)
+{
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       int i;
+
+       if (!codec->cache_sync)
+               return;
+
+       codec->cache_only = 0;
+
+       /* write back cached values if they're writeable and
+        * different from the hardware default.
+        */
+       for (i = 1; i < ARRAY_SIZE(max98088->reg_cache); i++) {
+               if (!max98088_access[i].writable)
+                       continue;
+
+               if (max98088->reg_cache[i] == max98088_reg[i])
+                       continue;
+
+               snd_soc_write(codec, i, max98088->reg_cache[i]);
+       }
+
+       codec->cache_sync = 0;
+}
+
+static int max98088_set_bias_level(struct snd_soc_codec *codec,
+                                  enum snd_soc_bias_level level)
+{
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF)
+                       max98088_sync_cache(codec);
+
+               snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
+                               M98088_MBEN, M98088_MBEN);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
+                               M98088_MBEN, 0);
+               codec->cache_sync = 1;
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+#define MAX98088_RATES SNDRV_PCM_RATE_8000_96000
+#define MAX98088_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops max98088_dai1_ops = {
+       .set_sysclk = max98088_dai_set_sysclk,
+       .set_fmt = max98088_dai1_set_fmt,
+       .hw_params = max98088_dai1_hw_params,
+};
+
+static struct snd_soc_dai_ops max98088_dai2_ops = {
+       .set_sysclk = max98088_dai_set_sysclk,
+       .set_fmt = max98088_dai2_set_fmt,
+       .hw_params = max98088_dai2_hw_params,
+};
+
+static struct snd_soc_dai_driver max98088_dai[] = {
+{
+       .name = "HiFi",
+       .playback = {
+               .stream_name = "HiFi Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = MAX98088_RATES,
+               .formats = MAX98088_FORMATS,
+       },
+       .capture = {
+               .stream_name = "HiFi Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = MAX98088_RATES,
+               .formats = MAX98088_FORMATS,
+       },
+        .ops = &max98088_dai1_ops,
+},
+{
+       .name = "Aux",
+       .playback = {
+               .stream_name = "Aux Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = MAX98088_RATES,
+               .formats = MAX98088_FORMATS,
+       },
+       .ops = &max98088_dai2_ops,
+}
+};
+
+static int max98088_get_channel(const char *name)
+{
+       if (strcmp(name, "EQ1 Mode") == 0)
+               return 0;
+       if (strcmp(name, "EQ2 Mode") == 0)
+               return 1;
+       return -EINVAL;
+}
+
+static void max98088_setup_eq1(struct snd_soc_codec *codec)
+{
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_pdata *pdata = max98088->pdata;
+       struct max98088_eq_cfg *coef_set;
+       int best, best_val, save, i, sel, fs;
+       struct max98088_cdata *cdata;
+
+       cdata = &max98088->dai[0];
+
+       if (!pdata || !max98088->eq_textcnt)
+               return;
+
+       /* Find the selected configuration with nearest sample rate */
+       fs = cdata->rate;
+       sel = cdata->eq_sel;
+
+       best = 0;
+       best_val = INT_MAX;
+       for (i = 0; i < pdata->eq_cfgcnt; i++) {
+               if (strcmp(pdata->eq_cfg[i].name, max98088->eq_texts[sel]) == 0 &&
+                   abs(pdata->eq_cfg[i].rate - fs) < best_val) {
+                       best = i;
+                       best_val = abs(pdata->eq_cfg[i].rate - fs);
+               }
+       }
+
+       dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+               pdata->eq_cfg[best].name,
+               pdata->eq_cfg[best].rate, fs);
+
+       /* Disable EQ while configuring, and save current on/off state */
+       save = snd_soc_read(codec, M98088_REG_49_CFG_LEVEL);
+       snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ1EN, 0);
+
+       coef_set = &pdata->eq_cfg[sel];
+
+       m98088_eq_band(codec, 0, 0, coef_set->band1);
+       m98088_eq_band(codec, 0, 1, coef_set->band2);
+       m98088_eq_band(codec, 0, 2, coef_set->band3);
+       m98088_eq_band(codec, 0, 3, coef_set->band4);
+       m98088_eq_band(codec, 0, 4, coef_set->band5);
+
+       /* Restore the original on/off state */
+       snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ1EN, save);
+}
+
+static void max98088_setup_eq2(struct snd_soc_codec *codec)
+{
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_pdata *pdata = max98088->pdata;
+       struct max98088_eq_cfg *coef_set;
+       int best, best_val, save, i, sel, fs;
+       struct max98088_cdata *cdata;
+
+       cdata = &max98088->dai[1];
+
+       if (!pdata || !max98088->eq_textcnt)
+               return;
+
+       /* Find the selected configuration with nearest sample rate */
+       fs = cdata->rate;
+
+       sel = cdata->eq_sel;
+       best = 0;
+       best_val = INT_MAX;
+       for (i = 0; i < pdata->eq_cfgcnt; i++) {
+               if (strcmp(pdata->eq_cfg[i].name, max98088->eq_texts[sel]) == 0 &&
+                   abs(pdata->eq_cfg[i].rate - fs) < best_val) {
+                       best = i;
+                       best_val = abs(pdata->eq_cfg[i].rate - fs);
+               }
+       }
+
+       dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+               pdata->eq_cfg[best].name,
+               pdata->eq_cfg[best].rate, fs);
+
+       /* Disable EQ while configuring, and save current on/off state */
+       save = snd_soc_read(codec, M98088_REG_49_CFG_LEVEL);
+       snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ2EN, 0);
+
+       coef_set = &pdata->eq_cfg[sel];
+
+       m98088_eq_band(codec, 1, 0, coef_set->band1);
+       m98088_eq_band(codec, 1, 1, coef_set->band2);
+       m98088_eq_band(codec, 1, 2, coef_set->band3);
+       m98088_eq_band(codec, 1, 3, coef_set->band4);
+       m98088_eq_band(codec, 1, 4, coef_set->band5);
+
+       /* Restore the original on/off state */
+       snd_soc_update_bits(codec, M98088_REG_49_CFG_LEVEL, M98088_EQ2EN,
+               save);
+}
+
+static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_pdata *pdata = max98088->pdata;
+       int channel = max98088_get_channel(kcontrol->id.name);
+       struct max98088_cdata *cdata;
+       int sel = ucontrol->value.integer.value[0];
+
+       cdata = &max98088->dai[channel];
+
+       if (sel >= pdata->eq_cfgcnt)
+               return -EINVAL;
+
+       cdata->eq_sel = sel;
+
+       switch (channel) {
+       case 0:
+               max98088_setup_eq1(codec);
+               break;
+       case 1:
+               max98088_setup_eq2(codec);
+               break;
+       }
+
+       return 0;
+}
+
+static int max98088_get_eq_enum(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       int channel = max98088_get_channel(kcontrol->id.name);
+       struct max98088_cdata *cdata;
+
+       cdata = &max98088->dai[channel];
+       ucontrol->value.enumerated.item[0] = cdata->eq_sel;
+       return 0;
+}
+
+static void max98088_handle_eq_pdata(struct snd_soc_codec *codec)
+{
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_pdata *pdata = max98088->pdata;
+       struct max98088_eq_cfg *cfg;
+       unsigned int cfgcnt;
+       int i, j;
+       const char **t;
+       int ret;
+
+       struct snd_kcontrol_new controls[] = {
+               SOC_ENUM_EXT("EQ1 Mode",
+                       max98088->eq_enum,
+                       max98088_get_eq_enum,
+                       max98088_put_eq_enum),
+               SOC_ENUM_EXT("EQ2 Mode",
+                       max98088->eq_enum,
+                       max98088_get_eq_enum,
+                       max98088_put_eq_enum),
+       };
+
+       cfg = pdata->eq_cfg;
+       cfgcnt = pdata->eq_cfgcnt;
+
+       /* Setup an array of texts for the equalizer enum.
+        * This is based on Mark Brown's equalizer driver code.
+        */
+       max98088->eq_textcnt = 0;
+       max98088->eq_texts = NULL;
+       for (i = 0; i < cfgcnt; i++) {
+               for (j = 0; j < max98088->eq_textcnt; j++) {
+                       if (strcmp(cfg[i].name, max98088->eq_texts[j]) == 0)
+                               break;
+               }
+
+               if (j != max98088->eq_textcnt)
+                       continue;
+
+               /* Expand the array */
+               t = krealloc(max98088->eq_texts,
+                            sizeof(char *) * (max98088->eq_textcnt + 1),
+                            GFP_KERNEL);
+               if (t == NULL)
+                       continue;
+
+               /* Store the new entry */
+               t[max98088->eq_textcnt] = cfg[i].name;
+               max98088->eq_textcnt++;
+               max98088->eq_texts = t;
+       }
+
+       /* Now point the soc_enum to .texts array items */
+       max98088->eq_enum.texts = max98088->eq_texts;
+       max98088->eq_enum.max = max98088->eq_textcnt;
+
+       ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
+       if (ret != 0)
+               dev_err(codec->dev, "Failed to add EQ control: %d\n", ret);
+}
+
+static void max98088_handle_pdata(struct snd_soc_codec *codec)
+{
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_pdata *pdata = max98088->pdata;
+       u8 regval = 0;
+
+       if (!pdata) {
+               dev_dbg(codec->dev, "No platform data\n");
+               return;
+       }
+
+       /* Configure mic for analog/digital mic mode */
+       if (pdata->digmic_left_mode)
+               regval |= M98088_DIGMIC_L;
+
+       if (pdata->digmic_right_mode)
+               regval |= M98088_DIGMIC_R;
+
+       max98088->digmic = (regval ? 1 : 0);
+
+       snd_soc_write(codec, M98088_REG_48_CFG_MIC, regval);
+
+       /* Configure receiver output */
+       regval = ((pdata->receiver_mode) ? M98088_REC_LINEMODE : 0);
+       snd_soc_update_bits(codec, M98088_REG_2A_MIC_REC_CNTL,
+               M98088_REC_LINEMODE_MASK, regval);
+
+       /* Configure equalizers */
+       if (pdata->eq_cfgcnt)
+               max98088_handle_eq_pdata(codec);
+}
+
+#ifdef CONFIG_PM
+static int max98088_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+       max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static int max98088_resume(struct snd_soc_codec *codec)
+{
+       max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+}
+#else
+#define max98088_suspend NULL
+#define max98088_resume NULL
+#endif
+
+static int max98088_probe(struct snd_soc_codec *codec)
+{
+       struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+       struct max98088_cdata *cdata;
+       int ret = 0;
+
+       codec->cache_sync = 1;
+       memcpy(codec->reg_cache, max98088_reg, sizeof(max98088_reg));
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       /* initalize private data */
+
+       max98088->sysclk = (unsigned)-1;
+       max98088->eq_textcnt = 0;
+
+       cdata = &max98088->dai[0];
+       cdata->rate = (unsigned)-1;
+       cdata->fmt  = (unsigned)-1;
+       cdata->eq_sel = 0;
+
+       cdata = &max98088->dai[1];
+       cdata->rate = (unsigned)-1;
+       cdata->fmt  = (unsigned)-1;
+       cdata->eq_sel = 0;
+
+       max98088->ina_state = 0;
+       max98088->inb_state = 0;
+       max98088->ex_mode = 0;
+       max98088->digmic = 0;
+       max98088->mic1pre = 0;
+       max98088->mic2pre = 0;
+
+       ret = snd_soc_read(codec, M98088_REG_FF_REV_ID);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read device revision: %d\n",
+                       ret);
+               goto err_access;
+       }
+       dev_info(codec->dev, "revision %c\n", ret + 'A');
+
+       snd_soc_write(codec, M98088_REG_51_PWR_SYS, M98088_PWRSV);
+
+       /* initialize registers cache to hardware default */
+       max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       snd_soc_write(codec, M98088_REG_0F_IRQ_ENABLE, 0x00);
+
+       snd_soc_write(codec, M98088_REG_22_MIX_DAC,
+               M98088_DAI1L_TO_DACL|M98088_DAI2L_TO_DACL|
+               M98088_DAI1R_TO_DACR|M98088_DAI2R_TO_DACR);
+
+       snd_soc_write(codec, M98088_REG_4E_BIAS_CNTL, 0xF0);
+       snd_soc_write(codec, M98088_REG_50_DAC_BIAS2, 0x0F);
+
+       snd_soc_write(codec, M98088_REG_16_DAI1_IOCFG,
+               M98088_S1NORMAL|M98088_SDATA);
+
+       snd_soc_write(codec, M98088_REG_1E_DAI2_IOCFG,
+               M98088_S2NORMAL|M98088_SDATA);
+
+       max98088_handle_pdata(codec);
+
+       max98088_add_widgets(codec);
+
+err_access:
+       return ret;
+}
+
+static int max98088_remove(struct snd_soc_codec *codec)
+{
+       max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_max98088 = {
+       .probe   = max98088_probe,
+       .remove  = max98088_remove,
+       .suspend = max98088_suspend,
+       .resume  = max98088_resume,
+       .set_bias_level = max98088_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(max98088_reg),
+       .reg_word_size = sizeof(u8),
+       .reg_cache_default = max98088_reg,
+       .volatile_register = max98088_volatile_register,
+};
+
+static int max98088_i2c_probe(struct i2c_client *i2c,
+                            const struct i2c_device_id *id)
+{
+       struct max98088_priv *max98088;
+       int ret;
+
+       max98088 = kzalloc(sizeof(struct max98088_priv), GFP_KERNEL);
+       if (max98088 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, max98088);
+       max98088->control_data = i2c;
+       max98088->pdata = i2c->dev.platform_data;
+
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_max98088, &max98088_dai[0], 2);
+       if (ret < 0)
+               kfree(max98088);
+       return ret;
+}
+
+static int max98088_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 max98088_i2c_id[] = {
+       { "max98088", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max98088_i2c_id);
+
+static struct i2c_driver max98088_i2c_driver = {
+       .driver = {
+               .name = "max98088",
+               .owner = THIS_MODULE,
+       },
+       .probe  = max98088_i2c_probe,
+       .remove = __devexit_p(max98088_i2c_remove),
+       .id_table = max98088_i2c_id,
+};
+
+static int __init max98088_init(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&max98088_i2c_driver);
+       if (ret)
+               pr_err("Failed to register max98088 I2C driver: %d\n", ret);
+
+       return ret;
+}
+module_init(max98088_init);
+
+static void __exit max98088_exit(void)
+{
+       i2c_del_driver(&max98088_i2c_driver);
+}
+module_exit(max98088_exit);
+
+MODULE_DESCRIPTION("ALSA SoC MAX98088 driver");
+MODULE_AUTHOR("Peter Hsiang, Jesse Marroquin");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98088.h b/sound/soc/codecs/max98088.h
new file mode 100644 (file)
index 0000000..56554c7
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * max98088.h -- MAX98088 ALSA SoC Audio driver
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ * 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 _MAX98088_H
+#define _MAX98088_H
+
+/*
+ * MAX98088 Registers Definition
+ */
+#define M98088_REG_00_IRQ_STATUS            0x00
+#define M98088_REG_01_MIC_STATUS            0x01
+#define M98088_REG_02_JACK_STAUS            0x02
+#define M98088_REG_03_BATTERY_VOLTAGE       0x03
+#define M98088_REG_0F_IRQ_ENABLE            0x0F
+#define M98088_REG_10_SYS_CLK               0x10
+#define M98088_REG_11_DAI1_CLKMODE          0x11
+#define M98088_REG_12_DAI1_CLKCFG_HI        0x12
+#define M98088_REG_13_DAI1_CLKCFG_LO        0x13
+#define M98088_REG_14_DAI1_FORMAT           0x14
+#define M98088_REG_15_DAI1_CLOCK            0x15
+#define M98088_REG_16_DAI1_IOCFG            0x16
+#define M98088_REG_17_DAI1_TDM              0x17
+#define M98088_REG_18_DAI1_FILTERS          0x18
+#define M98088_REG_19_DAI2_CLKMODE          0x19
+#define M98088_REG_1A_DAI2_CLKCFG_HI        0x1A
+#define M98088_REG_1B_DAI2_CLKCFG_LO        0x1B
+#define M98088_REG_1C_DAI2_FORMAT           0x1C
+#define M98088_REG_1D_DAI2_CLOCK            0x1D
+#define M98088_REG_1E_DAI2_IOCFG            0x1E
+#define M98088_REG_1F_DAI2_TDM              0x1F
+#define M98088_REG_20_DAI2_FILTERS          0x20
+#define M98088_REG_21_SRC                   0x21
+#define M98088_REG_22_MIX_DAC               0x22
+#define M98088_REG_23_MIX_ADC_LEFT          0x23
+#define M98088_REG_24_MIX_ADC_RIGHT         0x24
+#define M98088_REG_25_MIX_HP_LEFT           0x25
+#define M98088_REG_26_MIX_HP_RIGHT          0x26
+#define M98088_REG_27_MIX_HP_CNTL           0x27
+#define M98088_REG_28_MIX_REC_LEFT          0x28
+#define M98088_REG_29_MIX_REC_RIGHT         0x29
+#define M98088_REG_2A_MIC_REC_CNTL          0x2A
+#define M98088_REG_2B_MIX_SPK_LEFT          0x2B
+#define M98088_REG_2C_MIX_SPK_RIGHT         0x2C
+#define M98088_REG_2D_MIX_SPK_CNTL          0x2D
+#define M98088_REG_2E_LVL_SIDETONE          0x2E
+#define M98088_REG_2F_LVL_DAI1_PLAY         0x2F
+#define M98088_REG_30_LVL_DAI1_PLAY_EQ      0x30
+#define M98088_REG_31_LVL_DAI2_PLAY         0x31
+#define M98088_REG_32_LVL_DAI2_PLAY_EQ      0x32
+#define M98088_REG_33_LVL_ADC_L             0x33
+#define M98088_REG_34_LVL_ADC_R             0x34
+#define M98088_REG_35_LVL_MIC1              0x35
+#define M98088_REG_36_LVL_MIC2              0x36
+#define M98088_REG_37_LVL_INA               0x37
+#define M98088_REG_38_LVL_INB               0x38
+#define M98088_REG_39_LVL_HP_L              0x39
+#define M98088_REG_3A_LVL_HP_R              0x3A
+#define M98088_REG_3B_LVL_REC_L             0x3B
+#define M98088_REG_3C_LVL_REC_R             0x3C
+#define M98088_REG_3D_LVL_SPK_L             0x3D
+#define M98088_REG_3E_LVL_SPK_R             0x3E
+#define M98088_REG_3F_MICAGC_CFG            0x3F
+#define M98088_REG_40_MICAGC_THRESH         0x40
+#define M98088_REG_41_SPKDHP                0x41
+#define M98088_REG_42_SPKDHP_THRESH         0x42
+#define M98088_REG_43_SPKALC_COMP           0x43
+#define M98088_REG_44_PWRLMT_CFG            0x44
+#define M98088_REG_45_PWRLMT_TIME           0x45
+#define M98088_REG_46_THDLMT_CFG            0x46
+#define M98088_REG_47_CFG_AUDIO_IN          0x47
+#define M98088_REG_48_CFG_MIC               0x48
+#define M98088_REG_49_CFG_LEVEL             0x49
+#define M98088_REG_4A_CFG_BYPASS            0x4A
+#define M98088_REG_4B_CFG_JACKDET           0x4B
+#define M98088_REG_4C_PWR_EN_IN             0x4C
+#define M98088_REG_4D_PWR_EN_OUT            0x4D
+#define M98088_REG_4E_BIAS_CNTL             0x4E
+#define M98088_REG_4F_DAC_BIAS1             0x4F
+#define M98088_REG_50_DAC_BIAS2             0x50
+#define M98088_REG_51_PWR_SYS               0x51
+#define M98088_REG_52_DAI1_EQ_BASE          0x52
+#define M98088_REG_84_DAI2_EQ_BASE          0x84
+#define M98088_REG_B6_DAI1_BIQUAD_BASE      0xB6
+#define M98088_REG_C0_DAI2_BIQUAD_BASE      0xC0
+#define M98088_REG_FF_REV_ID                0xFF
+
+#define M98088_REG_CNT                      (0xFF+1)
+
+/* MAX98088 Registers Bit Fields */
+
+/* M98088_REG_11_DAI1_CLKMODE, M98088_REG_19_DAI2_CLKMODE */
+       #define M98088_CLKMODE_MASK             0xFF
+
+/* M98088_REG_14_DAI1_FORMAT, M98088_REG_1C_DAI2_FORMAT */
+       #define M98088_DAI_MAS                  (1<<7)
+       #define M98088_DAI_WCI                  (1<<6)
+       #define M98088_DAI_BCI                  (1<<5)
+       #define M98088_DAI_DLY                  (1<<4)
+       #define M98088_DAI_TDM                  (1<<2)
+       #define M98088_DAI_FSW                  (1<<1)
+       #define M98088_DAI_WS                   (1<<0)
+
+/* M98088_REG_15_DAI1_CLOCK, M98088_REG_1D_DAI2_CLOCK */
+       #define M98088_DAI_BSEL64               (1<<0)
+       #define M98088_DAI_OSR64                (1<<6)
+
+/* M98088_REG_16_DAI1_IOCFG, M98088_REG_1E_DAI2_IOCFG */
+       #define M98088_S1NORMAL                 (1<<6)
+       #define M98088_S2NORMAL                 (2<<6)
+       #define M98088_SDATA                    (3<<0)
+
+/* M98088_REG_18_DAI1_FILTERS, M98088_REG_20_DAI2_FILTERS */
+       #define M98088_DAI_DHF                  (1<<3)
+
+/* M98088_REG_22_MIX_DAC */
+       #define M98088_DAI1L_TO_DACL            (1<<7)
+       #define M98088_DAI1R_TO_DACL            (1<<6)
+       #define M98088_DAI2L_TO_DACL            (1<<5)
+       #define M98088_DAI2R_TO_DACL            (1<<4)
+       #define M98088_DAI1L_TO_DACR            (1<<3)
+       #define M98088_DAI1R_TO_DACR            (1<<2)
+       #define M98088_DAI2L_TO_DACR            (1<<1)
+       #define M98088_DAI2R_TO_DACR            (1<<0)
+
+/* M98088_REG_2A_MIC_REC_CNTL */
+       #define M98088_REC_LINEMODE             (1<<7)
+       #define M98088_REC_LINEMODE_MASK        (1<<7)
+
+/* M98088_REG_35_LVL_MIC1, M98088_REG_36_LVL_MIC2 */
+       #define M98088_MICPRE_MASK              (3<<5)
+       #define M98088_MICPRE_SHIFT             5
+
+/* M98088_REG_3A_LVL_HP_R */
+       #define M98088_HP_MUTE                  (1<<7)
+
+/* M98088_REG_3C_LVL_REC_R */
+       #define M98088_REC_MUTE                 (1<<7)
+
+/* M98088_REG_3E_LVL_SPK_R */
+       #define M98088_SP_MUTE                  (1<<7)
+
+/* M98088_REG_48_CFG_MIC */
+       #define M98088_EXTMIC_MASK              (3<<0)
+       #define M98088_DIGMIC_L                 (1<<5)
+       #define M98088_DIGMIC_R                 (1<<4)
+
+/* M98088_REG_49_CFG_LEVEL */
+       #define M98088_VSEN                     (1<<6)
+       #define M98088_ZDEN                     (1<<5)
+       #define M98088_EQ2EN                    (1<<1)
+       #define M98088_EQ1EN                    (1<<0)
+
+/* M98088_REG_4C_PWR_EN_IN */
+       #define M98088_INAEN                    (1<<7)
+       #define M98088_INBEN                    (1<<6)
+       #define M98088_MBEN                     (1<<3)
+       #define M98088_ADLEN                    (1<<1)
+       #define M98088_ADREN                    (1<<0)
+
+/* M98088_REG_4D_PWR_EN_OUT */
+       #define M98088_HPLEN                    (1<<7)
+       #define M98088_HPREN                    (1<<6)
+       #define M98088_HPEN                     ((1<<7)|(1<<6))
+       #define M98088_SPLEN                    (1<<5)
+       #define M98088_SPREN                    (1<<4)
+       #define M98088_RECEN                    (1<<3)
+       #define M98088_DALEN                    (1<<1)
+       #define M98088_DAREN                    (1<<0)
+
+/* M98088_REG_51_PWR_SYS */
+       #define M98088_SHDNRUN                  (1<<7)
+       #define M98088_PERFMODE                 (1<<3)
+       #define M98088_HPPLYBACK                (1<<2)
+       #define M98088_PWRSV8K                  (1<<1)
+       #define M98088_PWRSV                    (1<<0)
+
+/* Line inputs */
+#define LINE_INA  0
+#define LINE_INB  1
+
+#define M98088_COEFS_PER_BAND               5
+
+#define M98088_BYTE1(w) ((w >> 8) & 0xff)
+#define M98088_BYTE0(w) (w & 0xff)
+
+#endif
index 5a5f187a265738283cb4f05049f78d12430d9789..bd8f26e41602cf2fe8bcb36dd423bc62a1c1c521 100644 (file)
@@ -32,8 +32,8 @@
 #define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |   \
                       SNDRV_PCM_RATE_48000)
 
-struct snd_soc_dai pcm3008_dai = {
-       .name = "PCM3008 HiFi",
+static struct snd_soc_dai_driver pcm3008_dai = {
+       .name = "pcm3008-hifi",
        .playback = {
                .stream_name = "PCM3008 Playback",
                .channels_min = 1,
@@ -49,7 +49,6 @@ struct snd_soc_dai pcm3008_dai = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
 };
-EXPORT_SYMBOL_GPL(pcm3008_dai);
 
 static void pcm3008_gpio_free(struct pcm3008_setup_data *setup)
 {
@@ -59,38 +58,13 @@ static void pcm3008_gpio_free(struct pcm3008_setup_data *setup)
        gpio_free(setup->pdda_pin);
 }
 
-static int pcm3008_soc_probe(struct platform_device *pdev)
+static int pcm3008_soc_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       struct pcm3008_setup_data *setup = socdev->codec_data;
+       struct pcm3008_setup_data *setup = codec->dev->platform_data;
        int ret = 0;
 
        printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION);
 
-       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (!socdev->card->codec)
-               return -ENOMEM;
-
-       codec = socdev->card->codec;
-       mutex_init(&codec->mutex);
-
-       codec->name = "PCM3008";
-       codec->owner = THIS_MODULE;
-       codec->dai = &pcm3008_dai;
-       codec->num_dai = 1;
-       codec->write = NULL;
-       codec->read = NULL;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       /* Register PCMs. */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "pcm3008: failed to create pcms\n");
-               goto pcm_err;
-       }
-
        /* DEM1  DEM0  DE-EMPHASIS_MODE
         * Low   Low   De-emphasis 44.1 kHz ON
         * Low   High  De-emphasis OFF
@@ -130,33 +104,22 @@ static int pcm3008_soc_probe(struct platform_device *pdev)
 
 gpio_err:
        pcm3008_gpio_free(setup);
-pcm_err:
-       kfree(socdev->card->codec);
 
        return ret;
 }
 
-static int pcm3008_soc_remove(struct platform_device *pdev)
+static int pcm3008_soc_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-       struct pcm3008_setup_data *setup = socdev->codec_data;
-
-       if (!codec)
-               return 0;
+       struct pcm3008_setup_data *setup = codec->dev->platform_data;
 
        pcm3008_gpio_free(setup);
-       snd_soc_free_pcms(socdev);
-       kfree(socdev->card->codec);
-
        return 0;
 }
 
 #ifdef CONFIG_PM
-static int pcm3008_soc_suspend(struct platform_device *pdev, pm_message_t msg)
+static int pcm3008_soc_suspend(struct snd_soc_codec *codec, pm_message_t msg)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct pcm3008_setup_data *setup = socdev->codec_data;
+       struct pcm3008_setup_data *setup = codec->dev->platform_data;
 
        gpio_set_value(setup->pdad_pin, 0);
        gpio_set_value(setup->pdda_pin, 0);
@@ -164,10 +127,9 @@ static int pcm3008_soc_suspend(struct platform_device *pdev, pm_message_t msg)
        return 0;
 }
 
-static int pcm3008_soc_resume(struct platform_device *pdev)
+static int pcm3008_soc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct pcm3008_setup_data *setup = socdev->codec_data;
+       struct pcm3008_setup_data *setup = codec->dev->platform_data;
 
        gpio_set_value(setup->pdad_pin, 1);
        gpio_set_value(setup->pdda_pin, 1);
@@ -179,23 +141,45 @@ static int pcm3008_soc_resume(struct platform_device *pdev)
 #define pcm3008_soc_resume NULL
 #endif
 
-struct snd_soc_codec_device soc_codec_dev_pcm3008 = {
+static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = {
        .probe =        pcm3008_soc_probe,
        .remove =       pcm3008_soc_remove,
        .suspend =      pcm3008_soc_suspend,
        .resume =       pcm3008_soc_resume,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_pcm3008);
 
-static int __init pcm3008_init(void)
+static int __devinit pcm3008_codec_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_pcm3008, &pcm3008_dai, 1);
+}
+
+static int __devexit pcm3008_codec_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+MODULE_ALIAS("platform:pcm3008-codec");
+
+static struct platform_driver pcm3008_codec_driver = {
+       .probe          = pcm3008_codec_probe,
+       .remove         = __devexit_p(pcm3008_codec_remove),
+       .driver         = {
+               .name   = "pcm3008-codec",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init pcm3008_modinit(void)
 {
-       return snd_soc_register_dai(&pcm3008_dai);
+       return platform_driver_register(&pcm3008_codec_driver);
 }
-module_init(pcm3008_init);
+module_init(pcm3008_modinit);
 
 static void __exit pcm3008_exit(void)
 {
-       snd_soc_unregister_dai(&pcm3008_dai);
+       platform_driver_unregister(&pcm3008_codec_driver);
 }
 module_exit(pcm3008_exit);
 
index d04e87d3c060c964614fcfcb803e0d07b016309f..7e5489ab48123ec46b19a239a15bf2b39944693e 100644 (file)
@@ -19,7 +19,4 @@ struct pcm3008_setup_data {
        unsigned pdda_pin;
 };
 
-extern struct snd_soc_codec_device soc_codec_dev_pcm3008;
-extern struct snd_soc_dai pcm3008_dai;
-
 #endif
index 9119836051a4721abef78468869c07b7bdc409a8..4c32b54913ad0f6316de3bea2f4e03a558fe8ec6 100644 (file)
 #include <sound/pcm.h>
 #include <sound/initval.h>
 
-#include "spdif_transciever.h"
-
 MODULE_LICENSE("GPL");
 
 #define STUB_RATES     SNDRV_PCM_RATE_8000_96000
 #define STUB_FORMATS   SNDRV_PCM_FMTBIT_S16_LE
 
-static struct snd_soc_codec *spdif_dit_codec;
-
-static int spdif_dit_codec_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret;
-
-       if (spdif_dit_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = spdif_dit_codec;
-       codec = spdif_dit_codec;
-
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto err_create_pcms;
-       }
-
-       return 0;
-
-err_create_pcms:
-       return ret;
-}
-
-static int spdif_dit_codec_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-
-       return 0;
-}
 
-struct snd_soc_codec_device soc_codec_dev_spdif_dit = {
-       .probe          = spdif_dit_codec_probe,
-       .remove         = spdif_dit_codec_remove,
-}; EXPORT_SYMBOL_GPL(soc_codec_dev_spdif_dit);
+static struct snd_soc_codec_driver soc_codec_spdif_dit;
 
-struct snd_soc_dai dit_stub_dai = {
-       .name           = "DIT",
+static struct snd_soc_dai_driver dit_stub_dai = {
+       .name           = "dit-hifi",
        .playback       = {
                .stream_name    = "Playback",
                .channels_min   = 1,
@@ -80,65 +39,16 @@ struct snd_soc_dai dit_stub_dai = {
                .formats        = STUB_FORMATS,
        },
 };
-EXPORT_SYMBOL_GPL(dit_stub_dai);
 
 static int spdif_dit_probe(struct platform_device *pdev)
 {
-       struct snd_soc_codec *codec;
-       int ret;
-
-       if (spdif_dit_codec) {
-               dev_err(&pdev->dev, "Another Codec is registered\n");
-               ret = -EINVAL;
-               goto err_reg_codec;
-       }
-
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
-
-       codec->dev = &pdev->dev;
-
-       mutex_init(&codec->mutex);
-
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->name = "spdif-dit";
-       codec->owner = THIS_MODULE;
-       codec->dai = &dit_stub_dai;
-       codec->num_dai = 1;
-
-       spdif_dit_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err_reg_codec;
-       }
-
-       dit_stub_dai.dev = &pdev->dev;
-       ret = snd_soc_register_dai(&dit_stub_dai);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to register dai: %d\n", ret);
-               goto err_reg_dai;
-       }
-
-       return 0;
-
-err_reg_dai:
-       snd_soc_unregister_codec(codec);
-err_reg_codec:
-       kfree(spdif_dit_codec);
-       return ret;
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_spdif_dit,
+                       &dit_stub_dai, 1);
 }
 
 static int spdif_dit_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&dit_stub_dai);
-       snd_soc_unregister_codec(spdif_dit_codec);
-       kfree(spdif_dit_codec);
-       spdif_dit_codec = NULL;
+       snd_soc_unregister_codec(&pdev->dev);
        return 0;
 }
 
diff --git a/sound/soc/codecs/spdif_transciever.h b/sound/soc/codecs/spdif_transciever.h
deleted file mode 100644 (file)
index 1e10212..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * ALSA SoC DIT/DIR driver header
- *
- * Author:      Steve Chen,  <schen@mvista.com>
- * Copyright:   (C) 2008 MontaVista Software, Inc., <source@mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef CODEC_STUBS_H
-#define CODEC_STUBS_H
-
-extern struct snd_soc_codec_device soc_codec_dev_spdif_dit;
-extern struct snd_soc_dai dit_stub_dai;
-
-#endif /* CODEC_STUBS_H */
index b47ed4f6ab2072b86157b97da602d168e3756bd6..6f38d619bf8ab207ab35252f16c4a7f4db3d41fe 100644 (file)
 
 #define SSM2602_VERSION "0.1"
 
-struct snd_soc_codec_device soc_codec_dev_ssm2602;
-
 /* codec private data */
 struct ssm2602_priv {
        unsigned int sysclk;
+       enum snd_soc_control_type control_type;
+       void *control_data;
        struct snd_pcm_substream *master_substream;
        struct snd_pcm_substream *slave_substream;
 };
@@ -276,8 +276,7 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
 {
        u16 srate;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
        struct i2c_client *i2c = codec->control_data;
        u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3;
@@ -321,8 +320,7 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
        struct i2c_client *i2c = codec->control_data;
        struct snd_pcm_runtime *master_runtime;
@@ -360,8 +358,7 @@ static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream,
                               struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        /* set active */
        ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
 
@@ -372,8 +369,7 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 
        /* deactivate */
@@ -518,8 +514,8 @@ static struct snd_soc_dai_ops ssm2602_dai_ops = {
        .set_fmt        = ssm2602_set_dai_fmt,
 };
 
-struct snd_soc_dai ssm2602_dai = {
-       .name = "SSM2602",
+static struct snd_soc_dai_driver ssm2602_dai = {
+       .name = "ssm2602-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -534,21 +530,15 @@ struct snd_soc_dai ssm2602_dai = {
                .formats = SSM2602_FORMATS,},
        .ops = &ssm2602_dai_ops,
 };
-EXPORT_SYMBOL_GPL(ssm2602_dai);
 
-static int ssm2602_suspend(struct platform_device *pdev, pm_message_t state)
+static int ssm2602_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int ssm2602_resume(struct platform_device *pdev)
+static int ssm2602_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -563,36 +553,17 @@ static int ssm2602_resume(struct platform_device *pdev)
        return 0;
 }
 
-/*
- * initialise the ssm2602 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int ssm2602_init(struct snd_soc_device *socdev)
+static int ssm2602_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int reg, ret = 0;
-
-       codec->name = "SSM2602";
-       codec->owner = THIS_MODULE;
-       codec->read = ssm2602_read_reg_cache;
-       codec->write = ssm2602_write;
-       codec->set_bias_level = ssm2602_set_bias_level;
-       codec->dai = &ssm2602_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = sizeof(ssm2602_reg);
-       codec->reg_cache = kmemdup(ssm2602_reg, sizeof(ssm2602_reg),
-                                       GFP_KERNEL);
-       if (codec->reg_cache == NULL)
-               return -ENOMEM;
+       struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0, reg;
+
+       pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
+
+       codec->control_data = ssm2602->control_data;
 
        ssm2602_reset(codec);
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               pr_err("ssm2602: failed to create pcms\n");
-               goto pcm_err;
-       }
        /*power on device*/
        ssm2602_write(codec, SSM2602_ACTIVE, 0);
        /* set the update bits */
@@ -614,13 +585,27 @@ static int ssm2602_init(struct snd_soc_device *socdev)
        ssm2602_add_widgets(codec);
 
        return ret;
+}
 
-pcm_err:
-       kfree(codec->reg_cache);
-       return ret;
+/* remove everything here */
+static int ssm2602_remove(struct snd_soc_codec *codec)
+{
+       ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
 
-static struct snd_soc_device *ssm2602_socdev;
+static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
+       .probe =        ssm2602_probe,
+       .remove =       ssm2602_remove,
+       .suspend =      ssm2602_suspend,
+       .resume =       ssm2602_resume,
+       .read = ssm2602_read_reg_cache,
+       .write = ssm2602_write,
+       .set_bias_level = ssm2602_set_bias_level,
+       .reg_cache_size = sizeof(ssm2602_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = ssm2602_reg,
+};
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 /*
@@ -632,24 +617,28 @@ static struct snd_soc_device *ssm2602_socdev;
 static int ssm2602_i2c_probe(struct i2c_client *i2c,
                             const struct i2c_device_id *id)
 {
-       struct snd_soc_device *socdev = ssm2602_socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct ssm2602_priv *ssm2602;
        int ret;
 
-       i2c_set_clientdata(i2c, codec);
-       codec->control_data = i2c;
+       ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL);
+       if (ssm2602 == NULL)
+               return -ENOMEM;
 
-       ret = ssm2602_init(socdev);
-       if (ret < 0)
-               pr_err("failed to initialise SSM2602\n");
+       i2c_set_clientdata(i2c, ssm2602);
+       ssm2602->control_data = i2c;
+       ssm2602->control_type = SND_SOC_I2C;
 
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_ssm2602, &ssm2602_dai, 1);
+       if (ret < 0)
+               kfree(ssm2602);
        return ret;
 }
 
 static int ssm2602_i2c_remove(struct i2c_client *client)
 {
-       struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       kfree(codec->reg_cache);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -658,130 +647,39 @@ static const struct i2c_device_id ssm2602_i2c_id[] = {
        { }
 };
 MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
+
 /* corgi i2c codec control layer */
 static struct i2c_driver ssm2602_i2c_driver = {
        .driver = {
-               .name = "SSM2602 I2C Codec",
+               .name = "ssm2602-codec",
                .owner = THIS_MODULE,
        },
        .probe = ssm2602_i2c_probe,
        .remove = ssm2602_i2c_remove,
        .id_table = ssm2602_i2c_id,
 };
-
-static int ssm2602_add_i2c_device(struct platform_device *pdev,
-                                 const struct ssm2602_setup_data *setup)
-{
-       struct i2c_board_info info;
-       struct i2c_adapter *adapter;
-       struct i2c_client *client;
-       int ret;
-
-       ret = i2c_add_driver(&ssm2602_i2c_driver);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "can't add i2c driver\n");
-               return ret;
-       }
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       info.addr = setup->i2c_address;
-       strlcpy(info.type, "ssm2602", I2C_NAME_SIZE);
-       adapter = i2c_get_adapter(setup->i2c_bus);
-       if (!adapter) {
-               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
-               setup->i2c_bus);
-               goto err_driver;
-       }
-       client = i2c_new_device(adapter, &info);
-       i2c_put_adapter(adapter);
-       if (!client) {
-               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
-               (unsigned int)info.addr);
-               goto err_driver;
-       }
-       return 0;
-err_driver:
-       i2c_del_driver(&ssm2602_i2c_driver);
-       return -ENODEV;
-}
 #endif
 
-static int ssm2602_probe(struct platform_device *pdev)
+
+static int __init ssm2602_modinit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct ssm2602_setup_data *setup;
-       struct snd_soc_codec *codec;
-       struct ssm2602_priv *ssm2602;
        int ret = 0;
-
-       pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
-
-       setup = socdev->codec_data;
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
-
-       ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL);
-       if (ssm2602 == NULL) {
-               kfree(codec);
-               return -ENOMEM;
-       }
-
-       snd_soc_codec_set_drvdata(codec, ssm2602);
-       socdev->card->codec = codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       ssm2602_socdev = socdev;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       if (setup->i2c_address) {
-               codec->hw_write = (hw_write_t)i2c_master_send;
-               ret = ssm2602_add_i2c_device(pdev, setup);
+       ret = i2c_add_driver(&ssm2602_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register SSM2602 I2C driver: %d\n",
+                      ret);
        }
-#else
-       /* other interfaces */
 #endif
        return ret;
 }
+module_init(ssm2602_modinit);
 
-/* remove everything here */
-static int ssm2602_remove(struct platform_device *pdev)
+static void __exit ssm2602_exit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec->control_data)
-               ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       i2c_unregister_device(codec->control_data);
        i2c_del_driver(&ssm2602_i2c_driver);
 #endif
-       kfree(snd_soc_codec_get_drvdata(codec));
-       kfree(codec);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ssm2602 = {
-       .probe =        ssm2602_probe,
-       .remove =       ssm2602_remove,
-       .suspend =      ssm2602_suspend,
-       .resume =       ssm2602_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602);
-
-static int __init ssm2602_modinit(void)
-{
-       return snd_soc_register_dai(&ssm2602_dai);
-}
-module_init(ssm2602_modinit);
-
-static void __exit ssm2602_exit(void)
-{
-       snd_soc_unregister_dai(&ssm2602_dai);
 }
 module_exit(ssm2602_exit);
 
index f344e6d76e31735d43d15c6b34d4ab3a01a1c6ad..42a47d0f8e2551879c7d9397e1d035ecfe918f46 100644 (file)
@@ -124,7 +124,4 @@ struct ssm2602_setup_data {
        unsigned short i2c_address;
 };
 
-extern struct snd_soc_dai ssm2602_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ssm2602;
-
 #endif
index ee86568545c255f2746c32eb6d469a3633f2a470..00d67cc8e2062a9071dcb78ee0fb2d64b5a77166 100644 (file)
@@ -25,7 +25,6 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/tlv.h>
-#include <sound/soc-of-simple.h>
 
 #include "stac9766.h"
 
@@ -257,20 +256,15 @@ static int stac9766_reset(struct snd_soc_codec *codec, int try_warm)
        return 0;
 }
 
-static int stac9766_codec_suspend(struct platform_device *pdev,
+static int stac9766_codec_suspend(struct snd_soc_codec *codec,
                                  pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        stac9766_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int stac9766_codec_resume(struct platform_device *pdev)
+static int stac9766_codec_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        u16 id, reset;
 
        reset = 0;
@@ -300,10 +294,9 @@ static struct snd_soc_dai_ops stac9766_dai_ops_digital = {
        .prepare = ac97_digital_prepare,
 };
 
-struct snd_soc_dai stac9766_dai[] = {
+static struct snd_soc_dai_driver stac9766_dai[] = {
 {
-       .name = "stac9766 analog",
-       .id = 0,
+       .name = "stac9766-hifi-analog",
        .ac97_control = 1,
 
        /* stream cababilities */
@@ -325,8 +318,7 @@ struct snd_soc_dai stac9766_dai[] = {
        .ops = &stac9766_dai_ops_analog,
 },
 {
-       .name = "stac9766 IEC958",
-       .id = 1,
+       .name = "stac9766-hifi-IEC958",
        .ac97_control = 1,
 
        /* stream cababilities */
@@ -342,57 +334,24 @@ struct snd_soc_dai stac9766_dai[] = {
        .ops = &stac9766_dai_ops_digital,
 }
 };
-EXPORT_SYMBOL_GPL(stac9766_dai);
 
-static int stac9766_codec_probe(struct platform_device *pdev)
+static int stac9766_codec_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
        int ret = 0;
 
        printk(KERN_INFO "STAC9766 SoC Audio Codec %s\n", STAC9766_VERSION);
 
-       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (socdev->card->codec == NULL)
-               return -ENOMEM;
-       codec = socdev->card->codec;
-       mutex_init(&codec->mutex);
-
-       codec->reg_cache = kmemdup(stac9766_reg, sizeof(stac9766_reg),
-                                  GFP_KERNEL);
-       if (codec->reg_cache == NULL) {
-               ret = -ENOMEM;
-               goto cache_err;
-       }
-       codec->reg_cache_size = sizeof(stac9766_reg);
-       codec->reg_cache_step = 2;
-
-       codec->name = "STAC9766";
-       codec->owner = THIS_MODULE;
-       codec->dai = stac9766_dai;
-       codec->num_dai = ARRAY_SIZE(stac9766_dai);
-       codec->write = stac9766_ac97_write;
-       codec->read = stac9766_ac97_read;
-       codec->set_bias_level = stac9766_set_bias_level;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0)
                goto codec_err;
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0)
-               goto pcm_err;
-
        /* do a cold reset for the controller and then try
         * a warm reset followed by an optional cold reset for codec */
        stac9766_reset(codec, 0);
        ret = stac9766_reset(codec, 1);
        if (ret < 0) {
                printk(KERN_ERR "Failed to reset STAC9766: AC97 link error\n");
-               goto reset_err;
+               goto codec_err;
        }
 
        stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -402,40 +361,63 @@ static int stac9766_codec_probe(struct platform_device *pdev)
 
        return 0;
 
-reset_err:
-       snd_soc_free_pcms(socdev);
-pcm_err:
-       snd_soc_free_ac97_codec(codec);
 codec_err:
-       kfree(snd_soc_codec_get_drvdata(codec));
-cache_err:
-       kfree(socdev->card->codec);
-       socdev->card->codec = NULL;
+       snd_soc_free_ac97_codec(codec);
        return ret;
 }
 
-static int stac9766_codec_remove(struct platform_device *pdev)
+static int stac9766_codec_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec == NULL)
-               return 0;
-
-       snd_soc_free_pcms(socdev);
        snd_soc_free_ac97_codec(codec);
-       kfree(codec->reg_cache);
-       kfree(codec);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_stac9766 = {
+static struct snd_soc_codec_driver soc_codec_dev_stac9766 = {
+       .write = stac9766_ac97_write,
+       .read = stac9766_ac97_read,
+       .set_bias_level = stac9766_set_bias_level,
        .probe = stac9766_codec_probe,
        .remove = stac9766_codec_remove,
        .suspend = stac9766_codec_suspend,
        .resume = stac9766_codec_resume,
+       .reg_cache_size = sizeof(stac9766_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_step = 2,
+};
+
+static __devinit int stac9766_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_stac9766, stac9766_dai, ARRAY_SIZE(stac9766_dai));
+}
+
+static int __devexit stac9766_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver stac9766_codec_driver = {
+       .driver = {
+                       .name = "stac9766-codec",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = stac9766_probe,
+       .remove = __devexit_p(stac9766_remove),
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_stac9766);
+
+static int __init stac9766_init(void)
+{
+       return platform_driver_register(&stac9766_codec_driver);
+}
+module_init(stac9766_init);
+
+static void __exit stac9766_exit(void)
+{
+       platform_driver_unregister(&stac9766_codec_driver);
+}
+module_exit(stac9766_exit);
 
 MODULE_DESCRIPTION("ASoC stac9766 driver");
 MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
index 65642eb8393e2d71ad26d7413496976520cbdcff..c726f907e2c03311c54ff31318193fff5cee4e7e 100644 (file)
@@ -14,8 +14,4 @@
 #define STAC9766_DAI_AC97_ANALOG               0
 #define STAC9766_DAI_AC97_DIGITAL              1
 
-extern struct snd_soc_dai stac9766_dai[];
-extern struct snd_soc_codec_device soc_codec_dev_stac9766;
-
-
 #endif
index 0a4b0fef33550f217adf1a597636963e76cb4d48..e8652b1ae32606b5c57bd0ff7d0a8b4a304fa9d5 100644 (file)
@@ -240,7 +240,8 @@ static const struct snd_soc_dapm_route intercon[] = {
 
 /* AIC23 driver data */
 struct aic23 {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+       void *control_data;
        int mclk;
        int requested_adc;
        int requested_dac;
@@ -404,11 +405,10 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u16 iface_reg;
        int ret;
-       struct aic23 *aic23 = container_of(codec, struct aic23, codec);
+       struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
        u32 sample_rate_adc = aic23->requested_adc;
        u32 sample_rate_dac = aic23->requested_dac;
        u32 sample_rate = params_rate(params);
@@ -452,8 +452,7 @@ static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream,
                                   struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* set active */
        tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001);
@@ -465,9 +464,8 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
-       struct aic23 *aic23 = container_of(codec, struct aic23, codec);
+       struct snd_soc_codec *codec = rtd->codec;
+       struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
 
        /* deactivate */
        if (!codec->active) {
@@ -546,8 +544,7 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
 static int tlv320aic23_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 aic23 *aic23 = container_of(codec, struct aic23, codec);
+       struct aic23 *aic23 = snd_soc_dai_get_drvdata(codec_dai);
        aic23->mclk = freq;
        return 0;
 }
@@ -594,8 +591,8 @@ static struct snd_soc_dai_ops tlv320aic23_dai_ops = {
        .set_sysclk     = tlv320aic23_set_dai_sysclk,
 };
 
-struct snd_soc_dai tlv320aic23_dai = {
-       .name = "tlv320aic23",
+static struct snd_soc_dai_driver tlv320aic23_dai = {
+       .name = "tlv320aic23-hifi",
        .playback = {
                     .stream_name = "Playback",
                     .channels_min = 2,
@@ -610,23 +607,17 @@ struct snd_soc_dai tlv320aic23_dai = {
                    .formats = AIC23_FORMATS,},
        .ops = &tlv320aic23_dai_ops,
 };
-EXPORT_SYMBOL_GPL(tlv320aic23_dai);
 
-static int tlv320aic23_suspend(struct platform_device *pdev,
+static int tlv320aic23_suspend(struct snd_soc_codec *codec,
                               pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int tlv320aic23_resume(struct platform_device *pdev)
+static int tlv320aic23_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        u16 reg;
 
        /* Sync reg_cache with the hardware */
@@ -639,39 +630,19 @@ static int tlv320aic23_resume(struct platform_device *pdev)
        return 0;
 }
 
-/*
- * initialise the AIC23 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int tlv320aic23_init(struct snd_soc_device *socdev)
+static int tlv320aic23_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int ret = 0;
-       u16 reg;
+       struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
+       int reg;
 
-       codec->name = "tlv320aic23";
-       codec->owner = THIS_MODULE;
-       codec->read = tlv320aic23_read_reg_cache;
-       codec->write = tlv320aic23_write;
-       codec->set_bias_level = tlv320aic23_set_bias_level;
-       codec->dai = &tlv320aic23_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(tlv320aic23_reg);
-       codec->reg_cache =
-           kmemdup(tlv320aic23_reg, sizeof(tlv320aic23_reg), GFP_KERNEL);
-       if (codec->reg_cache == NULL)
-               return -ENOMEM;
+       printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
+       codec->control_data = aic23->control_data;
+       codec->hw_write = (hw_write_t)i2c_master_send;
+       codec->hw_read = NULL;
 
        /* Reset codec */
        tlv320aic23_write(codec, TLV320AIC23_RESET, 0);
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "tlv320aic23: failed to create pcms\n");
-               goto pcm_err;
-       }
-
        /* power on device */
        tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
@@ -707,13 +678,27 @@ static int tlv320aic23_init(struct snd_soc_device *socdev)
                                ARRAY_SIZE(tlv320aic23_snd_controls));
        tlv320aic23_add_widgets(codec);
 
-       return ret;
+       return 0;
+}
 
-pcm_err:
-       kfree(codec->reg_cache);
-       return ret;
+static int tlv320aic23_remove(struct snd_soc_codec *codec)
+{
+       tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
-static struct snd_soc_device *tlv320aic23_socdev;
+
+static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
+       .reg_cache_size = ARRAY_SIZE(tlv320aic23_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = tlv320aic23_reg,
+       .probe = tlv320aic23_probe,
+       .remove = tlv320aic23_remove,
+       .suspend = tlv320aic23_suspend,
+       .resume = tlv320aic23_resume,
+       .read = tlv320aic23_read_reg_cache,
+       .write = tlv320aic23_write,
+       .set_bias_level = tlv320aic23_set_bias_level,
+};
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 /*
@@ -723,31 +708,30 @@ static struct snd_soc_device *tlv320aic23_socdev;
 static int tlv320aic23_codec_probe(struct i2c_client *i2c,
                                   const struct i2c_device_id *i2c_id)
 {
-       struct snd_soc_device *socdev = tlv320aic23_socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct aic23 *aic23;
        int ret;
 
        if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -EINVAL;
 
-       i2c_set_clientdata(i2c, codec);
-       codec->control_data = i2c;
+       aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL);
+       if (aic23 == NULL)
+               return -ENOMEM;
 
-       ret = tlv320aic23_init(socdev);
-       if (ret < 0) {
-               printk(KERN_ERR "tlv320aic23: failed to initialise AIC23\n");
-               goto err;
-       }
-       return ret;
+       i2c_set_clientdata(i2c, aic23);
+       aic23->control_data = i2c;
+       aic23->control_type = SND_SOC_I2C;
 
-err:
-       kfree(codec);
-       kfree(i2c);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1);
+       if (ret < 0)
+               kfree(aic23);
        return ret;
 }
 static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c)
 {
-       put_device(&i2c->dev);
+       snd_soc_unregister_codec(&i2c->dev);
+       kfree(i2c_get_clientdata(i2c));
        return 0;
 }
 
@@ -760,7 +744,7 @@ MODULE_DEVICE_TABLE(i2c, tlv320aic23_id);
 
 static struct i2c_driver tlv320aic23_i2c_driver = {
        .driver = {
-                  .name = "tlv320aic23",
+                  .name = "tlv320aic23-codec",
                   },
        .probe = tlv320aic23_codec_probe,
        .remove = __exit_p(tlv320aic23_i2c_remove),
@@ -769,71 +753,25 @@ static struct i2c_driver tlv320aic23_i2c_driver = {
 
 #endif
 
-static int tlv320aic23_probe(struct platform_device *pdev)
+static int __init tlv320aic23_modinit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       struct aic23 *aic23;
-       int ret = 0;
-
-       printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
-
-       aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL);
-       if (aic23 == NULL)
-               return -ENOMEM;
-       codec = &aic23->codec;
-       socdev->card->codec = codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       tlv320aic23_socdev = socdev;
+       int ret;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       codec->hw_write = (hw_write_t) i2c_master_send;
-       codec->hw_read = NULL;
        ret = i2c_add_driver(&tlv320aic23_i2c_driver);
-       if (ret != 0)
-               printk(KERN_ERR "can't add i2c driver");
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register TLV320AIC23 I2C driver: %d\n",
+                      ret);
+       }
 #endif
        return ret;
 }
+module_init(tlv320aic23_modinit);
 
-static int tlv320aic23_remove(struct platform_device *pdev)
+static void __exit tlv320aic23_exit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-       struct aic23 *aic23 = container_of(codec, struct aic23, codec);
-
-       if (codec->control_data)
-               tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&tlv320aic23_i2c_driver);
 #endif
-       kfree(codec->reg_cache);
-       kfree(aic23);
-
-       return 0;
-}
-struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = {
-       .probe = tlv320aic23_probe,
-       .remove = tlv320aic23_remove,
-       .suspend = tlv320aic23_suspend,
-       .resume = tlv320aic23_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23);
-
-static int __init tlv320aic23_modinit(void)
-{
-       return snd_soc_register_dai(&tlv320aic23_dai);
-}
-module_init(tlv320aic23_modinit);
-
-static void __exit tlv320aic23_exit(void)
-{
-       snd_soc_unregister_dai(&tlv320aic23_dai);
 }
 module_exit(tlv320aic23_exit);
 
index 79d1faf8e570bafa76147716e3b2fa3b247bd8ab..e804120bd3da3bae2354fe5bfd46809d93f561cb 100644 (file)
 #define TLV320AIC23_SIDETONE_12                0x080
 #define TLV320AIC23_SIDETONE_18                0x0c0
 
-extern struct snd_soc_dai tlv320aic23_dai;
-extern struct snd_soc_codec_device soc_codec_dev_tlv320aic23;
-
 #endif /* _TLV320AIC23_H */
index f0e00fd4b43578ef78f1f20a8d82c5561379a556..6b7d71ec0004ddb660e9e962a64002dc430ecd2d 100644 (file)
@@ -19,7 +19,6 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
-#include <sound/soc-of-simple.h>
 #include <sound/initval.h>
 
 #include "tlv320aic26.h"
@@ -130,8 +129,7 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
        int fsref, divisor, wlen, pval, jval, dval, qval;
        u16 reg;
@@ -278,8 +276,8 @@ static struct snd_soc_dai_ops aic26_dai_ops = {
        .set_fmt        = aic26_set_fmt,
 };
 
-struct snd_soc_dai aic26_dai = {
-       .name = "tlv320aic26",
+static struct snd_soc_dai_driver aic26_dai = {
+       .name = "tlv320aic26-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -296,7 +294,6 @@ struct snd_soc_dai aic26_dai = {
        },
        .ops = &aic26_dai_ops,
 };
-EXPORT_SYMBOL_GPL(aic26_dai);
 
 /* ---------------------------------------------------------------------
  * ALSA controls
@@ -318,61 +315,6 @@ static const struct snd_kcontrol_new aic26_snd_controls[] = {
        SOC_ENUM("Capture Source", aic26_capture_src_enum),
 };
 
-/* ---------------------------------------------------------------------
- * SoC CODEC portion of driver: probe and release routines
- */
-static int aic26_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       struct aic26 *aic26;
-       int ret, err;
-
-       dev_info(&pdev->dev, "Probing AIC26 SoC CODEC driver\n");
-       dev_dbg(&pdev->dev, "socdev=%p\n", socdev);
-       dev_dbg(&pdev->dev, "codec_data=%p\n", socdev->codec_data);
-
-       /* Fetch the relevant aic26 private data here (it's already been
-        * stored in the .codec pointer) */
-       aic26 = socdev->codec_data;
-       if (aic26 == NULL) {
-               dev_err(&pdev->dev, "aic26: missing codec pointer\n");
-               return -ENODEV;
-       }
-       codec = &aic26->codec;
-       socdev->card->codec = codec;
-
-       dev_dbg(&pdev->dev, "Registering PCMs, dev=%p, socdev->dev=%p\n",
-               &pdev->dev, socdev->dev);
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "aic26: failed to create pcms\n");
-               return -ENODEV;
-       }
-
-       /* register controls */
-       dev_dbg(&pdev->dev, "Registering controls\n");
-       err = snd_soc_add_controls(codec, aic26_snd_controls,
-                       ARRAY_SIZE(aic26_snd_controls));
-       WARN_ON(err < 0);
-
-       return 0;
-}
-
-static int aic26_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       snd_soc_free_pcms(socdev);
-       return 0;
-}
-
-struct snd_soc_codec_device aic26_soc_codec_dev = {
-       .probe = aic26_probe,
-       .remove = aic26_remove,
-};
-EXPORT_SYMBOL_GPL(aic26_soc_codec_dev);
-
 /* ---------------------------------------------------------------------
  * SPI device portion of driver: sysfs files for debugging
  */
@@ -409,95 +351,95 @@ static ssize_t aic26_keyclick_set(struct device *dev,
 static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set);
 
 /* ---------------------------------------------------------------------
- * SPI device portion of driver: probe and release routines and SPI
- *                              driver registration.
+ * SoC CODEC portion of driver: probe and release routines
  */
-static int aic26_spi_probe(struct spi_device *spi)
+static int aic26_probe(struct snd_soc_codec *codec)
 {
-       struct aic26 *aic26;
-       int ret, i, reg;
-
-       dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n");
-
-       /* Allocate driver data */
-       aic26 = kzalloc(sizeof *aic26, GFP_KERNEL);
-       if (!aic26)
-               return -ENOMEM;
-
-       /* Initialize the driver data */
-       aic26->spi = spi;
-       dev_set_drvdata(&spi->dev, aic26);
+       struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
+       int ret, err, i, reg;
 
-       /* Setup what we can in the codec structure so that the register
-        * access functions will work as expected.  More will be filled
-        * out when it is probed by the SoC CODEC part of this driver */
-       snd_soc_codec_set_drvdata(&aic26->codec, aic26);
-       aic26->codec.name = "aic26";
-       aic26->codec.owner = THIS_MODULE;
-       aic26->codec.dai = &aic26_dai;
-       aic26->codec.num_dai = 1;
-       aic26->codec.read = aic26_reg_read;
-       aic26->codec.write = aic26_reg_write;
-       aic26->master = 1;
-       mutex_init(&aic26->codec.mutex);
-       INIT_LIST_HEAD(&aic26->codec.dapm_widgets);
-       INIT_LIST_HEAD(&aic26->codec.dapm_paths);
-       aic26->codec.reg_cache_size = AIC26_NUM_REGS;
-       aic26->codec.reg_cache = aic26->reg_cache;
-
-       aic26_dai.dev = &spi->dev;
-       ret = snd_soc_register_dai(&aic26_dai);
-       if (ret != 0) {
-               dev_err(&spi->dev, "Failed to register DAI: %d\n", ret);
-               kfree(aic26);
-               return ret;
-       }
+       dev_info(codec->dev, "Probing AIC26 SoC CODEC driver\n");
 
        /* Reset the codec to power on defaults */
-       aic26_reg_write(&aic26->codec, AIC26_REG_RESET, 0xBB00);
+       aic26_reg_write(codec, AIC26_REG_RESET, 0xBB00);
 
        /* Power up CODEC */
-       aic26_reg_write(&aic26->codec, AIC26_REG_POWER_CTRL, 0);
+       aic26_reg_write(codec, AIC26_REG_POWER_CTRL, 0);
 
        /* Audio Control 3 (master mode, fsref rate) */
-       reg = aic26_reg_read(&aic26->codec, AIC26_REG_AUDIO_CTRL3);
+       reg = aic26_reg_read(codec, AIC26_REG_AUDIO_CTRL3);
        reg &= ~0xf800;
        reg |= 0x0800; /* set master mode */
-       aic26_reg_write(&aic26->codec, AIC26_REG_AUDIO_CTRL3, reg);
+       aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
 
        /* Fill register cache */
        for (i = 0; i < ARRAY_SIZE(aic26->reg_cache); i++)
-               aic26_reg_read(&aic26->codec, i);
+               aic26_reg_read(codec, i);
 
        /* Register the sysfs files for debugging */
        /* Create SysFS files */
-       ret = device_create_file(&spi->dev, &dev_attr_keyclick);
+       ret = device_create_file(codec->dev, &dev_attr_keyclick);
        if (ret)
-               dev_info(&spi->dev, "error creating sysfs files\n");
+               dev_info(codec->dev, "error creating sysfs files\n");
 
-#if defined(CONFIG_SND_SOC_OF_SIMPLE)
-       /* Tell the of_soc helper about this codec */
-       of_snd_soc_register_codec(&aic26_soc_codec_dev, aic26, &aic26_dai,
-                                 spi->dev.archdata.of_node);
-#endif
+       /* register controls */
+       dev_dbg(codec->dev, "Registering controls\n");
+       err = snd_soc_add_controls(codec, aic26_snd_controls,
+                       ARRAY_SIZE(aic26_snd_controls));
+       WARN_ON(err < 0);
 
-       dev_dbg(&spi->dev, "SPI device initialized\n");
        return 0;
 }
 
-static int aic26_spi_remove(struct spi_device *spi)
+static struct snd_soc_codec_driver aic26_soc_codec_dev = {
+       .probe = aic26_probe,
+       .read = aic26_reg_read,
+       .write = aic26_reg_write,
+       .reg_cache_size = AIC26_NUM_REGS,
+       .reg_word_size = sizeof(u16),
+};
+
+/* ---------------------------------------------------------------------
+ * SPI device portion of driver: probe and release routines and SPI
+ *                              driver registration.
+ */
+static int aic26_spi_probe(struct spi_device *spi)
 {
-       struct aic26 *aic26 = dev_get_drvdata(&spi->dev);
+       struct aic26 *aic26;
+       int ret;
 
-       snd_soc_unregister_dai(&aic26_dai);
-       kfree(aic26);
+       dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n");
+
+       /* Allocate driver data */
+       aic26 = kzalloc(sizeof *aic26, GFP_KERNEL);
+       if (!aic26)
+               return -ENOMEM;
 
+       /* Initialize the driver data */
+       aic26->spi = spi;
+       dev_set_drvdata(&spi->dev, aic26);
+       aic26->master = 1;
+
+       ret = snd_soc_register_codec(&spi->dev,
+                       &aic26_soc_codec_dev, &aic26_dai, 1);
+       if (ret < 0)
+               kfree(aic26);
+       return ret;
+
+       dev_dbg(&spi->dev, "SPI device initialized\n");
+       return 0;
+}
+
+static int aic26_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
 static struct spi_driver aic26_spi = {
        .driver = {
-               .name = "tlv320aic26",
+               .name = "tlv320aic26-codec",
                .owner = THIS_MODULE,
        },
        .probe = aic26_spi_probe,
index 786ba16c945fa13728e2169baab21f5a3ffadfcc..62b1f2261429cf8c25747b5ecb4c4554c5b6d71f 100644 (file)
@@ -90,7 +90,4 @@ enum aic26_wlen {
        AIC26_WLEN_32   = 3 << 10,
 };
 
-extern struct snd_soc_dai aic26_dai;
-extern struct snd_soc_codec_device aic26_soc_codec_dev;
-
 #endif /* _TLV320AIC16_H_ */
index 71a69908ccf69485e0bbdb3e2804fcf06ee3fe8f..fc687790188b2f1ee2b33f48f2dab0b831f3ffa9 100644 (file)
  *
  * Notes:
  *  The AIC3X is a driver for a low power stereo audio
- *  codecs aic31, aic32, aic33.
+ *  codecs aic31, aic32, aic33, aic3007.
  *
  *  It supports full aic33 codec functionality.
- *  The compatibility with aic32, aic31 is as follows:
- *        aic32        |        aic31
+ *  The compatibility with aic32, aic31 and aic3007 is as follows:
+ *    aic32/aic3007    |        aic31
  *  ---------------------------------------
  *   MONO_LOUT -> N/A  |  MONO_LOUT -> N/A
  *                     |  IN1L -> LINE1L
@@ -61,13 +61,29 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = {
        "DRVDD",        /* ADC Analog and Output Driver Voltage */
 };
 
+struct aic3x_priv;
+
+struct aic3x_disable_nb {
+       struct notifier_block nb;
+       struct aic3x_priv *aic3x;
+};
+
 /* codec private data */
 struct aic3x_priv {
-       struct snd_soc_codec codec;
+       struct snd_soc_codec *codec;
        struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES];
+       struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES];
+       enum snd_soc_control_type control_type;
+       struct aic3x_setup_data *setup;
+       void *control_data;
        unsigned int sysclk;
        int master;
        int gpio_reset;
+       int power;
+#define AIC3X_MODEL_3X 0
+#define AIC3X_MODEL_33 1
+#define AIC3X_MODEL_3007 2
+       u16 model;
 };
 
 /*
@@ -106,62 +122,23 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = {
 };
 
 /*
- * read aic3x register cache
+ * read from the aic3x register space. Only use for this function is if
+ * wanting to read volatile bits from those registers that has both read-only
+ * and read/write bits. All other cases should use snd_soc_read.
  */
-static inline unsigned int aic3x_read_reg_cache(struct snd_soc_codec *codec,
-                                               unsigned int reg)
+static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg,
+                     u8 *value)
 {
        u8 *cache = codec->reg_cache;
-       if (reg >= AIC3X_CACHEREGNUM)
-               return -1;
-       return cache[reg];
-}
 
-/*
- * write aic3x register cache
- */
-static inline void aic3x_write_reg_cache(struct snd_soc_codec *codec,
-                                        u8 reg, u8 value)
-{
-       u8 *cache = codec->reg_cache;
+       if (codec->cache_only)
+               return -EINVAL;
        if (reg >= AIC3X_CACHEREGNUM)
-               return;
-       cache[reg] = value;
-}
-
-/*
- * write to the aic3x register space
- */
-static int aic3x_write(struct snd_soc_codec *codec, unsigned int reg,
-                      unsigned int value)
-{
-       u8 data[2];
-
-       /* data is
-        *   D15..D8 aic3x register offset
-        *   D7...D0 register data
-        */
-       data[0] = reg & 0xff;
-       data[1] = value & 0xff;
-
-       aic3x_write_reg_cache(codec, data[0], data[1]);
-       if (codec->hw_write(codec->control_data, data, 2) == 2)
-               return 0;
-       else
-               return -EIO;
-}
-
-/*
- * read from the aic3x register space
- */
-static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg,
-                     u8 *value)
-{
-       *value = reg & 0xff;
+               return -1;
 
-       value[0] = i2c_smbus_read_byte_data(codec->control_data, value[0]);
+       *value = codec->hw_read(codec, reg);
+       cache[reg] = *value;
 
-       aic3x_write_reg_cache(codec, reg, *value);
        return 0;
 }
 
@@ -286,64 +263,102 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
        SOC_DOUBLE_R_TLV("PCM Playback Volume",
                         LDAC_VOL, RDAC_VOL, 0, 0x7f, 1, dac_tlv),
 
+       /*
+        * Output controls that map to output mixer switches. Note these are
+        * only for swapped L-to-R and R-to-L routes. See below stereo controls
+        * for direct L-to-L and R-to-R routes.
+        */
+       SOC_SINGLE_TLV("Left Line Mixer Line2R Bypass Volume",
+                      LINE2R_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Left Line Mixer PGAR Bypass Volume",
+                      PGAR_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Left Line Mixer DACR1 Playback Volume",
+                      DACR1_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
+
+       SOC_SINGLE_TLV("Right Line Mixer Line2L Bypass Volume",
+                      LINE2L_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Right Line Mixer PGAL Bypass Volume",
+                      PGAL_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Right Line Mixer DACL1 Playback Volume",
+                      DACL1_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
+
+       SOC_SINGLE_TLV("Left HP Mixer Line2R Bypass Volume",
+                      LINE2R_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Left HP Mixer PGAR Bypass Volume",
+                      PGAR_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Left HP Mixer DACR1 Playback Volume",
+                      DACR1_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
+
+       SOC_SINGLE_TLV("Right HP Mixer Line2L Bypass Volume",
+                      LINE2L_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Right HP Mixer PGAL Bypass Volume",
+                      PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Right HP Mixer DACL1 Playback Volume",
+                      DACL1_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
+
+       SOC_SINGLE_TLV("Left HPCOM Mixer Line2R Bypass Volume",
+                      LINE2R_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Left HPCOM Mixer PGAR Bypass Volume",
+                      PGAR_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Left HPCOM Mixer DACR1 Playback Volume",
+                      DACR1_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
+
+       SOC_SINGLE_TLV("Right HPCOM Mixer Line2L Bypass Volume",
+                      LINE2L_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Right HPCOM Mixer PGAL Bypass Volume",
+                      PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
+       SOC_SINGLE_TLV("Right HPCOM Mixer DACL1 Playback Volume",
+                      DACL1_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
+
+       /* Stereo output controls for direct L-to-L and R-to-R routes */
+       SOC_DOUBLE_R_TLV("Line Line2 Bypass Volume",
+                        LINE2L_2_LLOPM_VOL, LINE2R_2_RLOPM_VOL,
+                        0, 118, 1, output_stage_tlv),
+       SOC_DOUBLE_R_TLV("Line PGA Bypass Volume",
+                        PGAL_2_LLOPM_VOL, PGAR_2_RLOPM_VOL,
+                        0, 118, 1, output_stage_tlv),
        SOC_DOUBLE_R_TLV("Line DAC Playback Volume",
                         DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL,
                         0, 118, 1, output_stage_tlv),
-       SOC_SINGLE("LineL Playback Switch", LLOPM_CTRL, 3, 0x01, 0),
-       SOC_SINGLE("LineR Playback Switch", RLOPM_CTRL, 3, 0x01, 0),
-       SOC_DOUBLE_R_TLV("LineL DAC Playback Volume",
-                        DACL1_2_LLOPM_VOL, DACR1_2_LLOPM_VOL,
-                        0, 118, 1, output_stage_tlv),
-       SOC_SINGLE_TLV("LineL Left PGA Bypass Playback Volume",
-                      PGAL_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
-       SOC_SINGLE_TLV("LineR Right PGA Bypass Playback Volume",
-                      PGAR_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
-       SOC_DOUBLE_R_TLV("LineL Line2 Bypass Playback Volume",
-                        LINE2L_2_LLOPM_VOL, LINE2R_2_LLOPM_VOL,
+
+       SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume",
+                        LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
                         0, 118, 1, output_stage_tlv),
-       SOC_DOUBLE_R_TLV("LineR Line2 Bypass Playback Volume",
-                        LINE2L_2_RLOPM_VOL, LINE2R_2_RLOPM_VOL,
+       SOC_DOUBLE_R_TLV("Mono PGA Bypass Volume",
+                        PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL,
                         0, 118, 1, output_stage_tlv),
-
        SOC_DOUBLE_R_TLV("Mono DAC Playback Volume",
                         DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL,
                         0, 118, 1, output_stage_tlv),
-       SOC_SINGLE("Mono DAC Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
-       SOC_DOUBLE_R_TLV("Mono PGA Bypass Playback Volume",
-                        PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL,
+
+       SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume",
+                        LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
                         0, 118, 1, output_stage_tlv),
-       SOC_DOUBLE_R_TLV("Mono Line2 Bypass Playback Volume",
-                        LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
+       SOC_DOUBLE_R_TLV("HP PGA Bypass Volume",
+                        PGAL_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL,
                         0, 118, 1, output_stage_tlv),
-
        SOC_DOUBLE_R_TLV("HP DAC Playback Volume",
                         DACL1_2_HPLOUT_VOL, DACR1_2_HPROUT_VOL,
                         0, 118, 1, output_stage_tlv),
-       SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
-                    0x01, 0),
-       SOC_DOUBLE_R_TLV("HP Right PGA Bypass Playback Volume",
-                        PGAR_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL,
+
+       SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Volume",
+                        LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL,
                         0, 118, 1, output_stage_tlv),
-       SOC_SINGLE_TLV("HPL PGA Bypass Playback Volume",
-                      PGAL_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
-       SOC_SINGLE_TLV("HPR PGA Bypass Playback Volume",
-                      PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
-       SOC_DOUBLE_R_TLV("HP Line2 Bypass Playback Volume",
-                        LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
+       SOC_DOUBLE_R_TLV("HPCOM PGA Bypass Volume",
+                        PGAL_2_HPLCOM_VOL, PGAR_2_HPRCOM_VOL,
                         0, 118, 1, output_stage_tlv),
-
        SOC_DOUBLE_R_TLV("HPCOM DAC Playback Volume",
                         DACL1_2_HPLCOM_VOL, DACR1_2_HPRCOM_VOL,
                         0, 118, 1, output_stage_tlv),
-       SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
+
+       /* Output pin mute controls */
+       SOC_DOUBLE_R("Line Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3,
+                    0x01, 0),
+       SOC_SINGLE("Mono Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
+       SOC_DOUBLE_R("HP Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
+                    0x01, 0),
+       SOC_DOUBLE_R("HPCOM Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
                     0x01, 0),
-       SOC_SINGLE_TLV("HPLCOM PGA Bypass Playback Volume",
-                      PGAL_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
-       SOC_SINGLE_TLV("HPRCOM PGA Bypass Playback Volume",
-                      PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
-       SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Playback Volume",
-                        LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL,
-                        0, 118, 1, output_stage_tlv),
 
        /*
         * Note: enable Automatic input Gain Controller with care. It can
@@ -359,6 +374,14 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
        SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]),
 };
 
+/*
+ * Class-D amplifier gain. From 0 to 18 dB in 6 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(classd_amp_tlv, 0, 600, 0);
+
+static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl =
+       SOC_DOUBLE_TLV("Class-D Amplifier Gain", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv);
+
 /* Left DAC Mux */
 static const struct snd_kcontrol_new aic3x_left_dac_mux_controls =
 SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]);
@@ -375,22 +398,74 @@ SOC_DAPM_ENUM("Route", aic3x_enum[LHPCOM_ENUM]);
 static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls =
 SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]);
 
-/* Left DAC_L1 Mixer */
-static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = {
-       SOC_DAPM_SINGLE("LineL Switch", DACL1_2_LLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("LineR Switch", DACL1_2_RLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Mono Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HP Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPCOM Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0),
+/* Left Line Mixer */
+static const struct snd_kcontrol_new aic3x_left_line_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_LLOPM_VOL, 7, 1, 0),
+};
+
+/* Right Line Mixer */
+static const struct snd_kcontrol_new aic3x_right_line_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_RLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_RLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_RLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_RLOPM_VOL, 7, 1, 0),
+};
+
+/* Mono Mixer */
+static const struct snd_kcontrol_new aic3x_mono_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0),
+};
+
+/* Left HP Mixer */
+static const struct snd_kcontrol_new aic3x_left_hp_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLOUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLOUT_VOL, 7, 1, 0),
+};
+
+/* Right HP Mixer */
+static const struct snd_kcontrol_new aic3x_right_hp_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPROUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPROUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPROUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPROUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPROUT_VOL, 7, 1, 0),
+};
+
+/* Left HPCOM Mixer */
+static const struct snd_kcontrol_new aic3x_left_hpcom_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLCOM_VOL, 7, 1, 0),
 };
 
-/* Right DAC_R1 Mixer */
-static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = {
-       SOC_DAPM_SINGLE("LineL Switch", DACR1_2_LLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("LineR Switch", DACR1_2_RLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Mono Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HP Switch", DACR1_2_HPROUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPCOM Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0),
+/* Right HPCOM Mixer */
+static const struct snd_kcontrol_new aic3x_right_hpcom_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPRCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPRCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0),
 };
 
 /* Left PGA Mixer */
@@ -427,54 +502,11 @@ SOC_DAPM_ENUM("Route", aic3x_enum[LINE2L_ENUM]);
 static const struct snd_kcontrol_new aic3x_right_line2_mux_controls =
 SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]);
 
-/* Left PGA Bypass Mixer */
-static const struct snd_kcontrol_new aic3x_left_pga_bp_mixer_controls[] = {
-       SOC_DAPM_SINGLE("LineL Switch", PGAL_2_LLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("LineR Switch", PGAL_2_RLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Mono Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPL Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPR Switch", PGAL_2_HPROUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPLCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPRCOM Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0),
-};
-
-/* Right PGA Bypass Mixer */
-static const struct snd_kcontrol_new aic3x_right_pga_bp_mixer_controls[] = {
-       SOC_DAPM_SINGLE("LineL Switch", PGAR_2_LLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("LineR Switch", PGAR_2_RLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Mono Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPL Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPR Switch", PGAR_2_HPROUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPLCOM Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPRCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0),
-};
-
-/* Left Line2 Bypass Mixer */
-static const struct snd_kcontrol_new aic3x_left_line2_bp_mixer_controls[] = {
-       SOC_DAPM_SINGLE("LineL Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("LineR Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Mono Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HP Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPLCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
-};
-
-/* Right Line2 Bypass Mixer */
-static const struct snd_kcontrol_new aic3x_right_line2_bp_mixer_controls[] = {
-       SOC_DAPM_SINGLE("LineL Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("LineR Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Mono Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HP Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("HPRCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
-};
-
 static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
        /* Left DAC to Left Outputs */
        SND_SOC_DAPM_DAC("Left DAC", "Left Playback", DAC_PWR, 7, 0),
        SND_SOC_DAPM_MUX("Left DAC Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_left_dac_mux_controls),
-       SND_SOC_DAPM_MIXER("Left DAC_L1 Mixer", SND_SOC_NOPM, 0, 0,
-                          &aic3x_left_dac_mixer_controls[0],
-                          ARRAY_SIZE(aic3x_left_dac_mixer_controls)),
        SND_SOC_DAPM_MUX("Left HPCOM Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_left_hpcom_mux_controls),
        SND_SOC_DAPM_PGA("Left Line Out", LLOPM_CTRL, 0, 0, NULL, 0),
@@ -485,9 +517,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
        SND_SOC_DAPM_DAC("Right DAC", "Right Playback", DAC_PWR, 6, 0),
        SND_SOC_DAPM_MUX("Right DAC Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_right_dac_mux_controls),
-       SND_SOC_DAPM_MIXER("Right DAC_R1 Mixer", SND_SOC_NOPM, 0, 0,
-                          &aic3x_right_dac_mixer_controls[0],
-                          ARRAY_SIZE(aic3x_right_dac_mixer_controls)),
        SND_SOC_DAPM_MUX("Right HPCOM Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_right_hpcom_mux_controls),
        SND_SOC_DAPM_PGA("Right Line Out", RLOPM_CTRL, 0, 0, NULL, 0),
@@ -551,25 +580,28 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
        SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "Mic Bias AVDD",
                         MICBIAS_CTRL, 6, 3, 3, 0),
 
-       /* Left PGA to Left Output bypass */
-       SND_SOC_DAPM_MIXER("Left PGA Bypass Mixer", SND_SOC_NOPM, 0, 0,
-                          &aic3x_left_pga_bp_mixer_controls[0],
-                          ARRAY_SIZE(aic3x_left_pga_bp_mixer_controls)),
-
-       /* Right PGA to Right Output bypass */
-       SND_SOC_DAPM_MIXER("Right PGA Bypass Mixer", SND_SOC_NOPM, 0, 0,
-                          &aic3x_right_pga_bp_mixer_controls[0],
-                          ARRAY_SIZE(aic3x_right_pga_bp_mixer_controls)),
-
-       /* Left Line2 to Left Output bypass */
-       SND_SOC_DAPM_MIXER("Left Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0,
-                          &aic3x_left_line2_bp_mixer_controls[0],
-                          ARRAY_SIZE(aic3x_left_line2_bp_mixer_controls)),
-
-       /* Right Line2 to Right Output bypass */
-       SND_SOC_DAPM_MIXER("Right Line2 Bypass Mixer", SND_SOC_NOPM, 0, 0,
-                          &aic3x_right_line2_bp_mixer_controls[0],
-                          ARRAY_SIZE(aic3x_right_line2_bp_mixer_controls)),
+       /* Output mixers */
+       SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_left_line_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_left_line_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Right Line Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_right_line_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_right_line_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_mono_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_mono_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_left_hp_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_left_hp_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_right_hp_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_right_hp_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Left HPCOM Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_left_hpcom_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_left_hpcom_mixer_controls)),
+       SND_SOC_DAPM_MIXER("Right HPCOM Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_right_hpcom_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_right_hpcom_mixer_controls)),
 
        SND_SOC_DAPM_OUTPUT("LLOUT"),
        SND_SOC_DAPM_OUTPUT("RLOUT"),
@@ -585,69 +617,26 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("LINE1R"),
        SND_SOC_DAPM_INPUT("LINE2L"),
        SND_SOC_DAPM_INPUT("LINE2R"),
-};
-
-static const struct snd_soc_dapm_route intercon[] = {
-       /* Left Output */
-       {"Left DAC Mux", "DAC_L1", "Left DAC"},
-       {"Left DAC Mux", "DAC_L2", "Left DAC"},
-       {"Left DAC Mux", "DAC_L3", "Left DAC"},
-
-       {"Left DAC_L1 Mixer", "LineL Switch", "Left DAC Mux"},
-       {"Left DAC_L1 Mixer", "LineR Switch", "Left DAC Mux"},
-       {"Left DAC_L1 Mixer", "Mono Switch", "Left DAC Mux"},
-       {"Left DAC_L1 Mixer", "HP Switch", "Left DAC Mux"},
-       {"Left DAC_L1 Mixer", "HPCOM Switch", "Left DAC Mux"},
-       {"Left Line Out", NULL, "Left DAC Mux"},
-       {"Left HP Out", NULL, "Left DAC Mux"},
-
-       {"Left HPCOM Mux", "differential of HPLOUT", "Left DAC_L1 Mixer"},
-       {"Left HPCOM Mux", "constant VCM", "Left DAC_L1 Mixer"},
-       {"Left HPCOM Mux", "single-ended", "Left DAC_L1 Mixer"},
-
-       {"Left Line Out", NULL, "Left DAC_L1 Mixer"},
-       {"Mono Out", NULL, "Left DAC_L1 Mixer"},
-       {"Left HP Out", NULL, "Left DAC_L1 Mixer"},
-       {"Left HP Com", NULL, "Left HPCOM Mux"},
-
-       {"LLOUT", NULL, "Left Line Out"},
-       {"LLOUT", NULL, "Left Line Out"},
-       {"HPLOUT", NULL, "Left HP Out"},
-       {"HPLCOM", NULL, "Left HP Com"},
-
-       /* Right Output */
-       {"Right DAC Mux", "DAC_R1", "Right DAC"},
-       {"Right DAC Mux", "DAC_R2", "Right DAC"},
-       {"Right DAC Mux", "DAC_R3", "Right DAC"},
 
-       {"Right DAC_R1 Mixer", "LineL Switch", "Right DAC Mux"},
-       {"Right DAC_R1 Mixer", "LineR Switch", "Right DAC Mux"},
-       {"Right DAC_R1 Mixer", "Mono Switch", "Right DAC Mux"},
-       {"Right DAC_R1 Mixer", "HP Switch", "Right DAC Mux"},
-       {"Right DAC_R1 Mixer", "HPCOM Switch", "Right DAC Mux"},
-       {"Right Line Out", NULL, "Right DAC Mux"},
-       {"Right HP Out", NULL, "Right DAC Mux"},
+       /*
+        * Virtual output pin to detection block inside codec. This can be
+        * used to keep codec bias on if gpio or detection features are needed.
+        * Force pin on or construct a path with an input jack and mic bias
+        * widgets.
+        */
+       SND_SOC_DAPM_OUTPUT("Detection"),
+};
 
-       {"Right HPCOM Mux", "differential of HPROUT", "Right DAC_R1 Mixer"},
-       {"Right HPCOM Mux", "constant VCM", "Right DAC_R1 Mixer"},
-       {"Right HPCOM Mux", "single-ended", "Right DAC_R1 Mixer"},
-       {"Right HPCOM Mux", "differential of HPLCOM", "Right DAC_R1 Mixer"},
-       {"Right HPCOM Mux", "external feedback", "Right DAC_R1 Mixer"},
+static const struct snd_soc_dapm_widget aic3007_dapm_widgets[] = {
+       /* Class-D outputs */
+       SND_SOC_DAPM_PGA("Left Class-D Out", CLASSD_CTRL, 3, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Class-D Out", CLASSD_CTRL, 2, 0, NULL, 0),
 
-       {"Right Line Out", NULL, "Right DAC_R1 Mixer"},
-       {"Mono Out", NULL, "Right DAC_R1 Mixer"},
-       {"Right HP Out", NULL, "Right DAC_R1 Mixer"},
-       {"Right HP Com", NULL, "Right HPCOM Mux"},
-
-       {"RLOUT", NULL, "Right Line Out"},
-       {"RLOUT", NULL, "Right Line Out"},
-       {"HPROUT", NULL, "Right HP Out"},
-       {"HPRCOM", NULL, "Right HP Com"},
-
-       /* Mono Output */
-       {"MONO_LOUT", NULL, "Mono Out"},
-       {"MONO_LOUT", NULL, "Mono Out"},
+       SND_SOC_DAPM_OUTPUT("SPOP"),
+       SND_SOC_DAPM_OUTPUT("SPOM"),
+};
 
+static const struct snd_soc_dapm_route intercon[] = {
        /* Left Input */
        {"Left Line1L Mux", "single-ended", "LINE1L"},
        {"Left Line1L Mux", "differential", "LINE1L"},
@@ -680,74 +669,6 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Right ADC", NULL, "Right PGA Mixer"},
        {"Right ADC", NULL, "GPIO1 dmic modclk"},
 
-       /* Left PGA Bypass */
-       {"Left PGA Bypass Mixer", "LineL Switch", "Left PGA Mixer"},
-       {"Left PGA Bypass Mixer", "LineR Switch", "Left PGA Mixer"},
-       {"Left PGA Bypass Mixer", "Mono Switch", "Left PGA Mixer"},
-       {"Left PGA Bypass Mixer", "HPL Switch", "Left PGA Mixer"},
-       {"Left PGA Bypass Mixer", "HPR Switch", "Left PGA Mixer"},
-       {"Left PGA Bypass Mixer", "HPLCOM Switch", "Left PGA Mixer"},
-       {"Left PGA Bypass Mixer", "HPRCOM Switch", "Left PGA Mixer"},
-
-       {"Left HPCOM Mux", "differential of HPLOUT", "Left PGA Bypass Mixer"},
-       {"Left HPCOM Mux", "constant VCM", "Left PGA Bypass Mixer"},
-       {"Left HPCOM Mux", "single-ended", "Left PGA Bypass Mixer"},
-
-       {"Left Line Out", NULL, "Left PGA Bypass Mixer"},
-       {"Mono Out", NULL, "Left PGA Bypass Mixer"},
-       {"Left HP Out", NULL, "Left PGA Bypass Mixer"},
-
-       /* Right PGA Bypass */
-       {"Right PGA Bypass Mixer", "LineL Switch", "Right PGA Mixer"},
-       {"Right PGA Bypass Mixer", "LineR Switch", "Right PGA Mixer"},
-       {"Right PGA Bypass Mixer", "Mono Switch", "Right PGA Mixer"},
-       {"Right PGA Bypass Mixer", "HPL Switch", "Right PGA Mixer"},
-       {"Right PGA Bypass Mixer", "HPR Switch", "Right PGA Mixer"},
-       {"Right PGA Bypass Mixer", "HPLCOM Switch", "Right PGA Mixer"},
-       {"Right PGA Bypass Mixer", "HPRCOM Switch", "Right PGA Mixer"},
-
-       {"Right HPCOM Mux", "differential of HPROUT", "Right PGA Bypass Mixer"},
-       {"Right HPCOM Mux", "constant VCM", "Right PGA Bypass Mixer"},
-       {"Right HPCOM Mux", "single-ended", "Right PGA Bypass Mixer"},
-       {"Right HPCOM Mux", "differential of HPLCOM", "Right PGA Bypass Mixer"},
-       {"Right HPCOM Mux", "external feedback", "Right PGA Bypass Mixer"},
-
-       {"Right Line Out", NULL, "Right PGA Bypass Mixer"},
-       {"Mono Out", NULL, "Right PGA Bypass Mixer"},
-       {"Right HP Out", NULL, "Right PGA Bypass Mixer"},
-
-       /* Left Line2 Bypass */
-       {"Left Line2 Bypass Mixer", "LineL Switch", "Left Line2L Mux"},
-       {"Left Line2 Bypass Mixer", "LineR Switch", "Left Line2L Mux"},
-       {"Left Line2 Bypass Mixer", "Mono Switch", "Left Line2L Mux"},
-       {"Left Line2 Bypass Mixer", "HP Switch", "Left Line2L Mux"},
-       {"Left Line2 Bypass Mixer", "HPLCOM Switch", "Left Line2L Mux"},
-
-       {"Left HPCOM Mux", "differential of HPLOUT", "Left Line2 Bypass Mixer"},
-       {"Left HPCOM Mux", "constant VCM", "Left Line2 Bypass Mixer"},
-       {"Left HPCOM Mux", "single-ended", "Left Line2 Bypass Mixer"},
-
-       {"Left Line Out", NULL, "Left Line2 Bypass Mixer"},
-       {"Mono Out", NULL, "Left Line2 Bypass Mixer"},
-       {"Left HP Out", NULL, "Left Line2 Bypass Mixer"},
-
-       /* Right Line2 Bypass */
-       {"Right Line2 Bypass Mixer", "LineL Switch", "Right Line2R Mux"},
-       {"Right Line2 Bypass Mixer", "LineR Switch", "Right Line2R Mux"},
-       {"Right Line2 Bypass Mixer", "Mono Switch", "Right Line2R Mux"},
-       {"Right Line2 Bypass Mixer", "HP Switch", "Right Line2R Mux"},
-       {"Right Line2 Bypass Mixer", "HPRCOM Switch", "Right Line2R Mux"},
-
-       {"Right HPCOM Mux", "differential of HPROUT", "Right Line2 Bypass Mixer"},
-       {"Right HPCOM Mux", "constant VCM", "Right Line2 Bypass Mixer"},
-       {"Right HPCOM Mux", "single-ended", "Right Line2 Bypass Mixer"},
-       {"Right HPCOM Mux", "differential of HPLCOM", "Right Line2 Bypass Mixer"},
-       {"Right HPCOM Mux", "external feedback", "Right Line2 Bypass Mixer"},
-
-       {"Right Line Out", NULL, "Right Line2 Bypass Mixer"},
-       {"Mono Out", NULL, "Right Line2 Bypass Mixer"},
-       {"Right HP Out", NULL, "Right Line2 Bypass Mixer"},
-
        /*
         * Logical path between digital mic enable and GPIO1 modulator clock
         * output function
@@ -755,16 +676,131 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"GPIO1 dmic modclk", NULL, "DMic Rate 128"},
        {"GPIO1 dmic modclk", NULL, "DMic Rate 64"},
        {"GPIO1 dmic modclk", NULL, "DMic Rate 32"},
+
+       /* Left DAC Output */
+       {"Left DAC Mux", "DAC_L1", "Left DAC"},
+       {"Left DAC Mux", "DAC_L2", "Left DAC"},
+       {"Left DAC Mux", "DAC_L3", "Left DAC"},
+
+       /* Right DAC Output */
+       {"Right DAC Mux", "DAC_R1", "Right DAC"},
+       {"Right DAC Mux", "DAC_R2", "Right DAC"},
+       {"Right DAC Mux", "DAC_R3", "Right DAC"},
+
+       /* Left Line Output */
+       {"Left Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Left Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+       {"Left Line Mixer", "DACL1 Switch", "Left DAC Mux"},
+       {"Left Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+       {"Left Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+       {"Left Line Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+       {"Left Line Out", NULL, "Left Line Mixer"},
+       {"Left Line Out", NULL, "Left DAC Mux"},
+       {"LLOUT", NULL, "Left Line Out"},
+
+       /* Right Line Output */
+       {"Right Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Right Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+       {"Right Line Mixer", "DACL1 Switch", "Left DAC Mux"},
+       {"Right Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+       {"Right Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+       {"Right Line Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+       {"Right Line Out", NULL, "Right Line Mixer"},
+       {"Right Line Out", NULL, "Right DAC Mux"},
+       {"RLOUT", NULL, "Right Line Out"},
+
+       /* Mono Output */
+       {"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Mono Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+       {"Mono Mixer", "DACL1 Switch", "Left DAC Mux"},
+       {"Mono Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+       {"Mono Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+       {"Mono Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+       {"Mono Out", NULL, "Mono Mixer"},
+       {"MONO_LOUT", NULL, "Mono Out"},
+
+       /* Left HP Output */
+       {"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Left HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+       {"Left HP Mixer", "DACL1 Switch", "Left DAC Mux"},
+       {"Left HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+       {"Left HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+       {"Left HP Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+       {"Left HP Out", NULL, "Left HP Mixer"},
+       {"Left HP Out", NULL, "Left DAC Mux"},
+       {"HPLOUT", NULL, "Left HP Out"},
+
+       /* Right HP Output */
+       {"Right HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Right HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+       {"Right HP Mixer", "DACL1 Switch", "Left DAC Mux"},
+       {"Right HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+       {"Right HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+       {"Right HP Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+       {"Right HP Out", NULL, "Right HP Mixer"},
+       {"Right HP Out", NULL, "Right DAC Mux"},
+       {"HPROUT", NULL, "Right HP Out"},
+
+       /* Left HPCOM Output */
+       {"Left HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Left HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+       {"Left HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"},
+       {"Left HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+       {"Left HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+       {"Left HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+       {"Left HPCOM Mux", "differential of HPLOUT", "Left HP Mixer"},
+       {"Left HPCOM Mux", "constant VCM", "Left HPCOM Mixer"},
+       {"Left HPCOM Mux", "single-ended", "Left HPCOM Mixer"},
+       {"Left HP Com", NULL, "Left HPCOM Mux"},
+       {"HPLCOM", NULL, "Left HP Com"},
+
+       /* Right HPCOM Output */
+       {"Right HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Right HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+       {"Right HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"},
+       {"Right HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+       {"Right HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+       {"Right HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"},
+
+       {"Right HPCOM Mux", "differential of HPROUT", "Right HP Mixer"},
+       {"Right HPCOM Mux", "constant VCM", "Right HPCOM Mixer"},
+       {"Right HPCOM Mux", "single-ended", "Right HPCOM Mixer"},
+       {"Right HPCOM Mux", "differential of HPLCOM", "Left HPCOM Mixer"},
+       {"Right HPCOM Mux", "external feedback", "Right HPCOM Mixer"},
+       {"Right HP Com", NULL, "Right HPCOM Mux"},
+       {"HPRCOM", NULL, "Right HP Com"},
+};
+
+static const struct snd_soc_dapm_route intercon_3007[] = {
+       /* Class-D outputs */
+       {"Left Class-D Out", NULL, "Left Line Out"},
+       {"Right Class-D Out", NULL, "Left Line Out"},
+       {"SPOP", NULL, "Left Class-D Out"},
+       {"SPOM", NULL, "Right Class-D Out"},
 };
 
 static int aic3x_add_widgets(struct snd_soc_codec *codec)
 {
+       struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+
        snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
                                  ARRAY_SIZE(aic3x_dapm_widgets));
 
        /* set up audio path interconnects */
        snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
 
+       if (aic3x->model == AIC3X_MODEL_3007) {
+               snd_soc_dapm_new_controls(codec, aic3007_dapm_widgets,
+                       ARRAY_SIZE(aic3007_dapm_widgets));
+               snd_soc_dapm_add_routes(codec, intercon_3007, ARRAY_SIZE(intercon_3007));
+       }
+
        return 0;
 }
 
@@ -773,8 +809,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec =rtd->codec;
        struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
        int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
        u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
@@ -783,8 +818,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
        int clk;
 
        /* select data word length */
-       data =
-           aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4));
+       data = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4));
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
                break;
@@ -798,7 +832,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
                data |= (0x03 << 4);
                break;
        }
-       aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data);
+       snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, data);
 
        /* Fsref can be 44100 or 48000 */
        fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000;
@@ -813,17 +847,17 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
 
        if (bypass_pll) {
                pll_q &= 0xf;
-               aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT);
-               aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV);
+               snd_soc_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT);
+               snd_soc_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV);
                /* disable PLL if it is bypassed */
-               reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
-               aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE);
+               reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
+               snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg & ~PLL_ENABLE);
 
        } else {
-               aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV);
+               snd_soc_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV);
                /* enable PLL when it is used */
-               reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
-               aic3x_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE);
+               reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
+               snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE);
        }
 
        /* Route Left DAC to left channel input and
@@ -832,7 +866,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
        data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000;
        if (params_rate(params) >= 64000)
                data |= DUAL_RATE_MODE;
-       aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data);
+       snd_soc_write(codec, AIC3X_CODEC_DATAPATH_REG, data);
 
        /* codec sample rate select */
        data = (fsref * 20) / params_rate(params);
@@ -841,7 +875,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
        data /= 5;
        data -= 2;
        data |= (data << 4);
-       aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data);
+       snd_soc_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data);
 
        if (bypass_pll)
                return 0;
@@ -910,13 +944,16 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
        }
 
 found:
-       data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
-       aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT));
-       aic3x_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT);
-       aic3x_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT);
-       aic3x_write(codec, AIC3X_PLL_PROGC_REG, (pll_d >> 6) << PLLD_MSB_SHIFT);
-       aic3x_write(codec, AIC3X_PLL_PROGD_REG,
-                   (pll_d & 0x3F) << PLLD_LSB_SHIFT);
+       data = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
+       snd_soc_write(codec, AIC3X_PLL_PROGA_REG,
+                     data | (pll_p << PLLP_SHIFT));
+       snd_soc_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG,
+                     pll_r << PLLR_SHIFT);
+       snd_soc_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT);
+       snd_soc_write(codec, AIC3X_PLL_PROGC_REG,
+                     (pll_d >> 6) << PLLD_MSB_SHIFT);
+       snd_soc_write(codec, AIC3X_PLL_PROGD_REG,
+                     (pll_d & 0x3F) << PLLD_LSB_SHIFT);
 
        return 0;
 }
@@ -924,15 +961,15 @@ found:
 static int aic3x_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
-       u8 ldac_reg = aic3x_read_reg_cache(codec, LDAC_VOL) & ~MUTE_ON;
-       u8 rdac_reg = aic3x_read_reg_cache(codec, RDAC_VOL) & ~MUTE_ON;
+       u8 ldac_reg = snd_soc_read(codec, LDAC_VOL) & ~MUTE_ON;
+       u8 rdac_reg = snd_soc_read(codec, RDAC_VOL) & ~MUTE_ON;
 
        if (mute) {
-               aic3x_write(codec, LDAC_VOL, ldac_reg | MUTE_ON);
-               aic3x_write(codec, RDAC_VOL, rdac_reg | MUTE_ON);
+               snd_soc_write(codec, LDAC_VOL, ldac_reg | MUTE_ON);
+               snd_soc_write(codec, RDAC_VOL, rdac_reg | MUTE_ON);
        } else {
-               aic3x_write(codec, LDAC_VOL, ldac_reg);
-               aic3x_write(codec, RDAC_VOL, rdac_reg);
+               snd_soc_write(codec, LDAC_VOL, ldac_reg);
+               snd_soc_write(codec, RDAC_VOL, rdac_reg);
        }
 
        return 0;
@@ -956,8 +993,8 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
        u8 iface_areg, iface_breg;
        int delay = 0;
 
-       iface_areg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f;
-       iface_breg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f;
+       iface_areg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f;
+       iface_breg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f;
 
        /* set master/slave audio interface */
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -996,13 +1033,98 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
        }
 
        /* set iface */
-       aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg);
-       aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg);
-       aic3x_write(codec, AIC3X_ASD_INTF_CTRLC, delay);
+       snd_soc_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg);
+       snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg);
+       snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, delay);
+
+       return 0;
+}
+
+static int aic3x_init_3007(struct snd_soc_codec *codec)
+{
+       u8 tmp1, tmp2, *cache = codec->reg_cache;
+
+       /*
+        * There is no need to cache writes to undocumented page 0xD but
+        * respective page 0 register cache entries must be preserved
+        */
+       tmp1 = cache[0xD];
+       tmp2 = cache[0x8];
+       /* Class-D speaker driver init; datasheet p. 46 */
+       snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x0D);
+       snd_soc_write(codec, 0xD, 0x0D);
+       snd_soc_write(codec, 0x8, 0x5C);
+       snd_soc_write(codec, 0x8, 0x5D);
+       snd_soc_write(codec, 0x8, 0x5C);
+       snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x00);
+       cache[0xD] = tmp1;
+       cache[0x8] = tmp2;
 
        return 0;
 }
 
+static int aic3x_regulator_event(struct notifier_block *nb,
+                                unsigned long event, void *data)
+{
+       struct aic3x_disable_nb *disable_nb =
+               container_of(nb, struct aic3x_disable_nb, nb);
+       struct aic3x_priv *aic3x = disable_nb->aic3x;
+
+       if (event & REGULATOR_EVENT_DISABLE) {
+               /*
+                * Put codec to reset and require cache sync as at least one
+                * of the supplies was disabled
+                */
+               if (aic3x->gpio_reset >= 0)
+                       gpio_set_value(aic3x->gpio_reset, 0);
+               aic3x->codec->cache_sync = 1;
+       }
+
+       return 0;
+}
+
+static int aic3x_set_power(struct snd_soc_codec *codec, int power)
+{
+       struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+       int i, ret;
+       u8 *cache = codec->reg_cache;
+
+       if (power) {
+               ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies),
+                                           aic3x->supplies);
+               if (ret)
+                       goto out;
+               aic3x->power = 1;
+               /*
+                * Reset release and cache sync is necessary only if some
+                * supply was off or if there were cached writes
+                */
+               if (!codec->cache_sync)
+                       goto out;
+
+               if (aic3x->gpio_reset >= 0) {
+                       udelay(1);
+                       gpio_set_value(aic3x->gpio_reset, 1);
+               }
+
+               /* Sync reg_cache with the hardware */
+               codec->cache_only = 0;
+               for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++)
+                       snd_soc_write(codec, i, cache[i]);
+               if (aic3x->model == AIC3X_MODEL_3007)
+                       aic3x_init_3007(codec);
+               codec->cache_sync = 0;
+       } else {
+               aic3x->power = 0;
+               /* HW writes are needless when bias is off */
+               codec->cache_only = 1;
+               ret = regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies),
+                                            aic3x->supplies);
+       }
+out:
+       return ret;
+}
+
 static int aic3x_set_bias_level(struct snd_soc_codec *codec,
                                enum snd_soc_bias_level level)
 {
@@ -1013,23 +1135,29 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_ON:
                break;
        case SND_SOC_BIAS_PREPARE:
-               if (aic3x->master) {
+               if (codec->bias_level == SND_SOC_BIAS_STANDBY &&
+                   aic3x->master) {
                        /* enable pll */
-                       reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
-                       aic3x_write(codec, AIC3X_PLL_PROGA_REG,
-                                   reg | PLL_ENABLE);
+                       reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
+                       snd_soc_write(codec, AIC3X_PLL_PROGA_REG,
+                                     reg | PLL_ENABLE);
                }
                break;
        case SND_SOC_BIAS_STANDBY:
-               /* fall through and disable pll */
-       case SND_SOC_BIAS_OFF:
-               if (aic3x->master) {
+               if (!aic3x->power)
+                       aic3x_set_power(codec, 1);
+               if (codec->bias_level == SND_SOC_BIAS_PREPARE &&
+                   aic3x->master) {
                        /* disable pll */
-                       reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
-                       aic3x_write(codec, AIC3X_PLL_PROGA_REG,
-                                   reg & ~PLL_ENABLE);
+                       reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
+                       snd_soc_write(codec, AIC3X_PLL_PROGA_REG,
+                                     reg & ~PLL_ENABLE);
                }
                break;
+       case SND_SOC_BIAS_OFF:
+               if (aic3x->power)
+                       aic3x_set_power(codec, 0);
+               break;
        }
        codec->bias_level = level;
 
@@ -1040,8 +1168,8 @@ void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state)
 {
        u8 reg = gpio ? AIC3X_GPIO2_REG : AIC3X_GPIO1_REG;
        u8 bit = gpio ? 3: 0;
-       u8 val = aic3x_read_reg_cache(codec, reg) & ~(1 << bit);
-       aic3x_write(codec, reg, val | (!!state << bit));
+       u8 val = snd_soc_read(codec, reg) & ~(1 << bit);
+       snd_soc_write(codec, reg, val | (!!state << bit));
 }
 EXPORT_SYMBOL_GPL(aic3x_set_gpio);
 
@@ -1070,7 +1198,7 @@ void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect,
        if (detect & AIC3X_HEADSET_DETECT_MASK)
                val |= AIC3X_HEADSET_DETECT_ENABLED;
 
-       aic3x_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val);
+       snd_soc_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val);
 }
 EXPORT_SYMBOL_GPL(aic3x_set_headset_detection);
 
@@ -1101,8 +1229,8 @@ static struct snd_soc_dai_ops aic3x_dai_ops = {
        .set_fmt        = aic3x_set_dai_fmt,
 };
 
-struct snd_soc_dai aic3x_dai = {
-       .name = "tlv320aic3x",
+static struct snd_soc_dai_driver aic3x_dai = {
+       .name = "tlv320aic3x-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -1116,34 +1244,18 @@ struct snd_soc_dai aic3x_dai = {
                .rates = AIC3X_RATES,
                .formats = AIC3X_FORMATS,},
        .ops = &aic3x_dai_ops,
+       .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(aic3x_dai);
 
-static int aic3x_suspend(struct platform_device *pdev, pm_message_t state)
+static int aic3x_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int aic3x_resume(struct platform_device *pdev)
+static int aic3x_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int i;
-       u8 data[2];
-       u8 *cache = codec->reg_cache;
-
-       /* Sync reg_cache with the hardware */
-       for (i = 0; i < ARRAY_SIZE(aic3x_reg); i++) {
-               data[0] = i;
-               data[1] = cache[i];
-               codec->hw_write(codec->control_data, data, 2);
-       }
-
        aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
@@ -1155,152 +1267,203 @@ static int aic3x_resume(struct platform_device *pdev)
  */
 static int aic3x_init(struct snd_soc_codec *codec)
 {
+       struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
        int reg;
 
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->name = "tlv320aic3x";
-       codec->owner = THIS_MODULE;
-       codec->read = aic3x_read_reg_cache;
-       codec->write = aic3x_write;
-       codec->set_bias_level = aic3x_set_bias_level;
-       codec->dai = &aic3x_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(aic3x_reg);
-       codec->reg_cache = kmemdup(aic3x_reg, sizeof(aic3x_reg), GFP_KERNEL);
-       if (codec->reg_cache == NULL)
-               return -ENOMEM;
-
-       aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT);
-       aic3x_write(codec, AIC3X_RESET, SOFT_RESET);
+       snd_soc_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT);
+       snd_soc_write(codec, AIC3X_RESET, SOFT_RESET);
 
        /* DAC default volume and mute */
-       aic3x_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON);
-       aic3x_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON);
+       snd_soc_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON);
+       snd_soc_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON);
 
        /* DAC to HP default volume and route to Output mixer */
-       aic3x_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON);
-       aic3x_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON);
-       aic3x_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON);
-       aic3x_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON);
+       snd_soc_write(codec, DACL1_2_HPLOUT_VOL, DEFAULT_VOL | ROUTE_ON);
+       snd_soc_write(codec, DACR1_2_HPROUT_VOL, DEFAULT_VOL | ROUTE_ON);
+       snd_soc_write(codec, DACL1_2_HPLCOM_VOL, DEFAULT_VOL | ROUTE_ON);
+       snd_soc_write(codec, DACR1_2_HPRCOM_VOL, DEFAULT_VOL | ROUTE_ON);
        /* DAC to Line Out default volume and route to Output mixer */
-       aic3x_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
-       aic3x_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+       snd_soc_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+       snd_soc_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
        /* DAC to Mono Line Out default volume and route to Output mixer */
-       aic3x_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
-       aic3x_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+       snd_soc_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+       snd_soc_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
 
        /* unmute all outputs */
-       reg = aic3x_read_reg_cache(codec, LLOPM_CTRL);
-       aic3x_write(codec, LLOPM_CTRL, reg | UNMUTE);
-       reg = aic3x_read_reg_cache(codec, RLOPM_CTRL);
-       aic3x_write(codec, RLOPM_CTRL, reg | UNMUTE);
-       reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL);
-       aic3x_write(codec, MONOLOPM_CTRL, reg | UNMUTE);
-       reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL);
-       aic3x_write(codec, HPLOUT_CTRL, reg | UNMUTE);
-       reg = aic3x_read_reg_cache(codec, HPROUT_CTRL);
-       aic3x_write(codec, HPROUT_CTRL, reg | UNMUTE);
-       reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL);
-       aic3x_write(codec, HPLCOM_CTRL, reg | UNMUTE);
-       reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL);
-       aic3x_write(codec, HPRCOM_CTRL, reg | UNMUTE);
+       reg = snd_soc_read(codec, LLOPM_CTRL);
+       snd_soc_write(codec, LLOPM_CTRL, reg | UNMUTE);
+       reg = snd_soc_read(codec, RLOPM_CTRL);
+       snd_soc_write(codec, RLOPM_CTRL, reg | UNMUTE);
+       reg = snd_soc_read(codec, MONOLOPM_CTRL);
+       snd_soc_write(codec, MONOLOPM_CTRL, reg | UNMUTE);
+       reg = snd_soc_read(codec, HPLOUT_CTRL);
+       snd_soc_write(codec, HPLOUT_CTRL, reg | UNMUTE);
+       reg = snd_soc_read(codec, HPROUT_CTRL);
+       snd_soc_write(codec, HPROUT_CTRL, reg | UNMUTE);
+       reg = snd_soc_read(codec, HPLCOM_CTRL);
+       snd_soc_write(codec, HPLCOM_CTRL, reg | UNMUTE);
+       reg = snd_soc_read(codec, HPRCOM_CTRL);
+       snd_soc_write(codec, HPRCOM_CTRL, reg | UNMUTE);
 
        /* ADC default volume and unmute */
-       aic3x_write(codec, LADC_VOL, DEFAULT_GAIN);
-       aic3x_write(codec, RADC_VOL, DEFAULT_GAIN);
+       snd_soc_write(codec, LADC_VOL, DEFAULT_GAIN);
+       snd_soc_write(codec, RADC_VOL, DEFAULT_GAIN);
        /* By default route Line1 to ADC PGA mixer */
-       aic3x_write(codec, LINE1L_2_LADC_CTRL, 0x0);
-       aic3x_write(codec, LINE1R_2_RADC_CTRL, 0x0);
+       snd_soc_write(codec, LINE1L_2_LADC_CTRL, 0x0);
+       snd_soc_write(codec, LINE1R_2_RADC_CTRL, 0x0);
 
        /* PGA to HP Bypass default volume, disconnect from Output Mixer */
-       aic3x_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL);
-       aic3x_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL);
-       aic3x_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL);
-       aic3x_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, PGAL_2_HPLOUT_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, PGAR_2_HPROUT_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, PGAL_2_HPLCOM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, PGAR_2_HPRCOM_VOL, DEFAULT_VOL);
        /* PGA to Line Out default volume, disconnect from Output Mixer */
-       aic3x_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL);
-       aic3x_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL);
        /* PGA to Mono Line Out default volume, disconnect from Output Mixer */
-       aic3x_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
-       aic3x_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
 
        /* Line2 to HP Bypass default volume, disconnect from Output Mixer */
-       aic3x_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL);
-       aic3x_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL);
-       aic3x_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL);
-       aic3x_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, LINE2R_2_HPROUT_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, LINE2L_2_HPLCOM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, LINE2R_2_HPRCOM_VOL, DEFAULT_VOL);
        /* Line2 Line Out default volume, disconnect from Output Mixer */
-       aic3x_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL);
-       aic3x_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL);
        /* Line2 to Mono Out default volume, disconnect from Output Mixer */
-       aic3x_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
-       aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
+       snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
 
-       /* off, with power on */
-       aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       if (aic3x->model == AIC3X_MODEL_3007) {
+               aic3x_init_3007(codec);
+               snd_soc_write(codec, CLASSD_CTRL, 0);
+       }
 
        return 0;
 }
 
-static struct snd_soc_codec *aic3x_codec;
-
-static int aic3x_register(struct snd_soc_codec *codec)
+static int aic3x_probe(struct snd_soc_codec *codec)
 {
-       int ret;
+       struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+       int ret, i;
 
-       ret = aic3x_init(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to initialise device\n");
+       codec->control_data = aic3x->control_data;
+       aic3x->codec = codec;
+       codec->idle_bias_off = 1;
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
        }
 
-       aic3x_codec = codec;
+       if (aic3x->gpio_reset >= 0) {
+               ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset");
+               if (ret != 0)
+                       goto err_gpio;
+               gpio_direction_output(aic3x->gpio_reset, 0);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
+               aic3x->supplies[i].supply = aic3x_supply_names[i];
 
-       ret = snd_soc_register_codec(codec);
-       if (ret) {
-               dev_err(codec->dev, "Failed to register codec\n");
-               return ret;
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies),
+                                aic3x->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               goto err_get;
+       }
+       for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) {
+               aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event;
+               aic3x->disable_nb[i].aic3x = aic3x;
+               ret = regulator_register_notifier(aic3x->supplies[i].consumer,
+                                                 &aic3x->disable_nb[i].nb);
+               if (ret) {
+                       dev_err(codec->dev,
+                               "Failed to request regulator notifier: %d\n",
+                                ret);
+                       goto err_notif;
+               }
        }
 
-       ret = snd_soc_register_dai(&aic3x_dai);
-       if (ret) {
-               dev_err(codec->dev, "Failed to register dai\n");
-               snd_soc_unregister_codec(codec);
-               return ret;
+       codec->cache_only = 1;
+       aic3x_init(codec);
+
+       if (aic3x->setup) {
+               /* setup GPIO functions */
+               snd_soc_write(codec, AIC3X_GPIO1_REG,
+                             (aic3x->setup->gpio_func[0] & 0xf) << 4);
+               snd_soc_write(codec, AIC3X_GPIO2_REG,
+                             (aic3x->setup->gpio_func[1] & 0xf) << 4);
        }
 
+       snd_soc_add_controls(codec, aic3x_snd_controls,
+                            ARRAY_SIZE(aic3x_snd_controls));
+       if (aic3x->model == AIC3X_MODEL_3007)
+               snd_soc_add_controls(codec, &aic3x_classd_amp_gain_ctrl, 1);
+
+       aic3x_add_widgets(codec);
+
        return 0;
+
+err_notif:
+       while (i--)
+               regulator_unregister_notifier(aic3x->supplies[i].consumer,
+                                             &aic3x->disable_nb[i].nb);
+       regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
+err_get:
+       if (aic3x->gpio_reset >= 0)
+               gpio_free(aic3x->gpio_reset);
+err_gpio:
+       kfree(aic3x);
+       return ret;
 }
 
-static int aic3x_unregister(struct aic3x_priv *aic3x)
+static int aic3x_remove(struct snd_soc_codec *codec)
 {
-       aic3x_set_bias_level(&aic3x->codec, SND_SOC_BIAS_OFF);
-
-       snd_soc_unregister_dai(&aic3x_dai);
-       snd_soc_unregister_codec(&aic3x->codec);
+       struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+       int i;
 
+       aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
        if (aic3x->gpio_reset >= 0) {
                gpio_set_value(aic3x->gpio_reset, 0);
                gpio_free(aic3x->gpio_reset);
        }
-       regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
+       for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
+               regulator_unregister_notifier(aic3x->supplies[i].consumer,
+                                             &aic3x->disable_nb[i].nb);
        regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
 
-       kfree(aic3x);
-       aic3x_codec = NULL;
-
        return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
+       .set_bias_level = aic3x_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(aic3x_reg),
+       .reg_word_size = sizeof(u8),
+       .reg_cache_default = aic3x_reg,
+       .probe = aic3x_probe,
+       .remove = aic3x_remove,
+       .suspend = aic3x_suspend,
+       .resume = aic3x_resume,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 /*
  * AIC3X 2 wire address can be up to 4 devices with device addresses
  * 0x18, 0x19, 0x1A, 0x1B
  */
 
+static const struct i2c_device_id aic3x_i2c_id[] = {
+       [AIC3X_MODEL_3X] = { "tlv320aic3x", 0 },
+       [AIC3X_MODEL_33] = { "tlv320aic33", 0 },
+       [AIC3X_MODEL_3007] = { "tlv320aic3007", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
+
 /*
  * If the i2c layer weren't so broken, we could pass this kind of data
  * around
@@ -1308,10 +1471,10 @@ static int aic3x_unregister(struct aic3x_priv *aic3x)
 static int aic3x_i2c_probe(struct i2c_client *i2c,
                           const struct i2c_device_id *id)
 {
-       struct snd_soc_codec *codec;
-       struct aic3x_priv *aic3x;
        struct aic3x_pdata *pdata = i2c->dev.platform_data;
-       int ret, i;
+       struct aic3x_priv *aic3x;
+       int ret;
+       const struct i2c_device_id *tbl;
 
        aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
        if (aic3x == NULL) {
@@ -1319,75 +1482,41 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
                return -ENOMEM;
        }
 
-       codec = &aic3x->codec;
-       codec->dev = &i2c->dev;
-       snd_soc_codec_set_drvdata(codec, aic3x);
-       codec->control_data = i2c;
-       codec->hw_write = (hw_write_t) i2c_master_send;
+       aic3x->control_data = i2c;
+       aic3x->control_type = SND_SOC_I2C;
 
        i2c_set_clientdata(i2c, aic3x);
-
-       aic3x->gpio_reset = -1;
-       if (pdata && pdata->gpio_reset >= 0) {
-               ret = gpio_request(pdata->gpio_reset, "tlv320aic3x reset");
-               if (ret != 0)
-                       goto err_gpio;
+       if (pdata) {
                aic3x->gpio_reset = pdata->gpio_reset;
-               gpio_direction_output(aic3x->gpio_reset, 0);
-       }
-
-       for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
-               aic3x->supplies[i].supply = aic3x_supply_names[i];
-
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies),
-                                aic3x->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               goto err_get;
-       }
-
-       ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies),
-                                   aic3x->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
-               goto err_enable;
+               aic3x->setup = pdata->setup;
+       } else {
+               aic3x->gpio_reset = -1;
        }
 
-       if (aic3x->gpio_reset >= 0) {
-               udelay(1);
-               gpio_set_value(aic3x->gpio_reset, 1);
+       for (tbl = aic3x_i2c_id; tbl->name[0]; tbl++) {
+               if (!strcmp(tbl->name, id->name))
+                       break;
        }
+       aic3x->model = tbl - aic3x_i2c_id;
 
-       return aic3x_register(codec);
-
-err_enable:
-       regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
-err_get:
-       if (aic3x->gpio_reset >= 0)
-               gpio_free(aic3x->gpio_reset);
-err_gpio:
-       kfree(aic3x);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_aic3x, &aic3x_dai, 1);
+       if (ret < 0)
+               kfree(aic3x);
        return ret;
 }
 
 static int aic3x_i2c_remove(struct i2c_client *client)
 {
-       struct aic3x_priv *aic3x = i2c_get_clientdata(client);
-
-       return aic3x_unregister(aic3x);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
+       return 0;
 }
 
-static const struct i2c_device_id aic3x_i2c_id[] = {
-       { "tlv320aic3x", 0 },
-       { "tlv320aic33", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
-
 /* machine i2c codec control layer */
 static struct i2c_driver aic3x_i2c_driver = {
        .driver = {
-               .name = "aic3x I2C Codec",
+               .name = "tlv320aic3x-codec",
                .owner = THIS_MODULE,
        },
        .probe  = aic3x_i2c_probe,
@@ -1409,90 +1538,27 @@ static inline void aic3x_i2c_exit(void)
 {
        i2c_del_driver(&aic3x_i2c_driver);
 }
-#else
-static inline void aic3x_i2c_init(void) { }
-static inline void aic3x_i2c_exit(void) { }
 #endif
 
-static int aic3x_probe(struct platform_device *pdev)
+static int __init aic3x_modinit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct aic3x_setup_data *setup;
-       struct snd_soc_codec *codec;
        int ret = 0;
-
-       codec = aic3x_codec;
-       if (!codec) {
-               dev_err(&pdev->dev, "Codec not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = codec;
-       setup = socdev->codec_data;
-
-       if (setup) {
-               /* setup GPIO functions */
-               aic3x_write(codec, AIC3X_GPIO1_REG,
-                           (setup->gpio_func[0] & 0xf) << 4);
-               aic3x_write(codec, AIC3X_GPIO2_REG,
-                           (setup->gpio_func[1] & 0xf) << 4);
-       }
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "aic3x: failed to create pcms\n");
-               goto pcm_err;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&aic3x_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register TLV320AIC3x I2C driver: %d\n",
+                      ret);
        }
-
-       snd_soc_add_controls(codec, aic3x_snd_controls,
-                            ARRAY_SIZE(aic3x_snd_controls));
-
-       aic3x_add_widgets(codec);
-
-       return ret;
-
-pcm_err:
-       kfree(codec->reg_cache);
+#endif
        return ret;
 }
-
-static int aic3x_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       /* power down chip */
-       if (codec->control_data)
-               aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       kfree(codec->reg_cache);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_aic3x = {
-       .probe = aic3x_probe,
-       .remove = aic3x_remove,
-       .suspend = aic3x_suspend,
-       .resume = aic3x_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x);
-
-static int __init aic3x_modinit(void)
-{
-       aic3x_i2c_init();
-
-       return 0;
-}
 module_init(aic3x_modinit);
 
 static void __exit aic3x_exit(void)
 {
-       aic3x_i2c_exit();
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&aic3x_i2c_driver);
+#endif
 }
 module_exit(aic3x_exit);
 
index 9af1c886213c0f1d432014ea65a259dfea4ecfd8..06a19784b162dddfd2f719d850deaf45d52dfef6 100644 (file)
 /* DAC Digital control registers */
 #define LDAC_VOL                       43
 #define RDAC_VOL                       44
-/* High Power Output control registers */
+/* Left High Power Output control registers */
 #define LINE2L_2_HPLOUT_VOL            45
-#define LINE2R_2_HPROUT_VOL            62
 #define PGAL_2_HPLOUT_VOL              46
-#define PGAL_2_HPROUT_VOL              60
-#define PGAR_2_HPLOUT_VOL              49
-#define PGAR_2_HPROUT_VOL              63
 #define DACL1_2_HPLOUT_VOL             47
-#define DACR1_2_HPROUT_VOL             64
+#define LINE2R_2_HPLOUT_VOL            48
+#define PGAR_2_HPLOUT_VOL              49
+#define DACR1_2_HPLOUT_VOL             50
 #define HPLOUT_CTRL                    51
-#define HPROUT_CTRL                    65
-/* High Power COM control registers */
+/* Left High Power COM control registers */
 #define LINE2L_2_HPLCOM_VOL            52
-#define LINE2R_2_HPRCOM_VOL            69
 #define PGAL_2_HPLCOM_VOL              53
+#define DACL1_2_HPLCOM_VOL             54
+#define LINE2R_2_HPLCOM_VOL            55
 #define PGAR_2_HPLCOM_VOL              56
+#define DACR1_2_HPLCOM_VOL             57
+#define HPLCOM_CTRL                    58
+/* Right High Power Output control registers */
+#define LINE2L_2_HPROUT_VOL            59
+#define PGAL_2_HPROUT_VOL              60
+#define DACL1_2_HPROUT_VOL             61
+#define LINE2R_2_HPROUT_VOL            62
+#define PGAR_2_HPROUT_VOL              63
+#define DACR1_2_HPROUT_VOL             64
+#define HPROUT_CTRL                    65
+/* Right High Power COM control registers */
+#define LINE2L_2_HPRCOM_VOL            66
 #define PGAL_2_HPRCOM_VOL              67
+#define DACL1_2_HPRCOM_VOL             68
+#define LINE2R_2_HPRCOM_VOL            69
 #define PGAR_2_HPRCOM_VOL              70
-#define DACL1_2_HPLCOM_VOL             54
 #define DACR1_2_HPRCOM_VOL             71
-#define HPLCOM_CTRL                    58
 #define HPRCOM_CTRL                    72
 /* Mono Line Output Plus/Minus control registers */
 #define LINE2L_2_MONOLOPM_VOL          73
-#define LINE2R_2_MONOLOPM_VOL          76
 #define PGAL_2_MONOLOPM_VOL            74
-#define PGAR_2_MONOLOPM_VOL            77
 #define DACL1_2_MONOLOPM_VOL           75
+#define LINE2R_2_MONOLOPM_VOL          76
+#define PGAR_2_MONOLOPM_VOL            77
 #define DACR1_2_MONOLOPM_VOL           78
 #define MONOLOPM_CTRL                  79
-/* Line Output Plus/Minus control registers */
+/* Class-D speaker driver on tlv320aic3007 */
+#define CLASSD_CTRL                    73
+/* Left Line Output Plus/Minus control registers */
 #define LINE2L_2_LLOPM_VOL             80
-#define LINE2L_2_RLOPM_VOL             87
-#define LINE2R_2_LLOPM_VOL             83
-#define LINE2R_2_RLOPM_VOL             90
 #define PGAL_2_LLOPM_VOL               81
-#define PGAL_2_RLOPM_VOL               88
-#define PGAR_2_LLOPM_VOL               84
-#define PGAR_2_RLOPM_VOL               91
 #define DACL1_2_LLOPM_VOL              82
-#define DACL1_2_RLOPM_VOL              89
-#define DACR1_2_RLOPM_VOL              92
+#define LINE2R_2_LLOPM_VOL             83
+#define PGAR_2_LLOPM_VOL               84
 #define DACR1_2_LLOPM_VOL              85
 #define LLOPM_CTRL                     86
+/* Right Line Output Plus/Minus control registers */
+#define LINE2L_2_RLOPM_VOL             87
+#define PGAL_2_RLOPM_VOL               88
+#define DACL1_2_RLOPM_VOL              89
+#define LINE2R_2_RLOPM_VOL             90
+#define PGAR_2_RLOPM_VOL               91
+#define DACR1_2_RLOPM_VOL              92
 #define RLOPM_CTRL                     93
 /* GPIO/IRQ registers */
 #define AIC3X_STICKY_IRQ_FLAGS_REG     96
 /* Default input volume */
 #define DEFAULT_GAIN    0x20
 
-/* GPIO API */
-enum {
-       AIC3X_GPIO1_FUNC_DISABLED               = 0,
-       AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC      = 1,
-       AIC3X_GPIO1_FUNC_CLOCK_MUX              = 2,
-       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2         = 3,
-       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4         = 4,
-       AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8         = 5,
-       AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ      = 6,
-       AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ          = 7,
-       AIC3X_GPIO1_FUNC_INPUT                  = 8,
-       AIC3X_GPIO1_FUNC_OUTPUT                 = 9,
-       AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK     = 10,
-       AIC3X_GPIO1_FUNC_AUDIO_WORDCLK          = 11,
-       AIC3X_GPIO1_FUNC_BUTTON_IRQ             = 12,
-       AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ     = 13,
-       AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ   = 14,
-       AIC3X_GPIO1_FUNC_ALL_IRQ                = 16
-};
-
-enum {
-       AIC3X_GPIO2_FUNC_DISABLED               = 0,
-       AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ     = 2,
-       AIC3X_GPIO2_FUNC_INPUT                  = 3,
-       AIC3X_GPIO2_FUNC_OUTPUT                 = 4,
-       AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT      = 5,
-       AIC3X_GPIO2_FUNC_AUDIO_BITCLK           = 8,
-       AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9,
-       AIC3X_GPIO2_FUNC_ALL_IRQ                = 10,
-       AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11,
-       AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12,
-       AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ      = 13,
-       AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ          = 14,
-       AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ       = 15
-};
-
 void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state);
 int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio);
 
@@ -281,11 +258,4 @@ void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect,
 int aic3x_headset_detected(struct snd_soc_codec *codec);
 int aic3x_button_pressed(struct snd_soc_codec *codec);
 
-struct aic3x_setup_data {
-       unsigned int gpio_func[2];
-};
-
-extern struct snd_soc_dai aic3x_dai;
-extern struct snd_soc_codec_device soc_codec_dev_aic3x;
-
 #endif /* _AIC3X_H */
index 8651b01ed22358a636abdd7ba2c63e051ae95461..d251ff54a2d36f8b691b4aca2073d74adb010673 100644 (file)
@@ -66,8 +66,6 @@
 static void dac33_calculate_times(struct snd_pcm_substream *substream);
 static int dac33_prepare_chip(struct snd_pcm_substream *substream);
 
-static struct snd_soc_codec *tlv320dac33_codec;
-
 enum dac33_state {
        DAC33_IDLE = 0,
        DAC33_PREFILL,
@@ -93,7 +91,7 @@ struct tlv320dac33_priv {
        struct mutex mutex;
        struct workqueue_struct *dac33_wq;
        struct work_struct work;
-       struct snd_soc_codec codec;
+       struct snd_soc_codec *codec;
        struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES];
        struct snd_pcm_substream *substream;
        int power_gpio;
@@ -128,6 +126,8 @@ struct tlv320dac33_priv {
        unsigned int uthr;
 
        enum dac33_state state;
+       enum snd_soc_control_type control_type;
+       void *control_data;
 };
 
 static const u8 dac33_reg[DAC33_CACHEREGNUM] = {
@@ -524,6 +524,22 @@ static const struct soc_enum dac33_fifo_mode_enum =
        SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dac33_fifo_mode_texts),
                            dac33_fifo_mode_texts);
 
+/* L/R Line Output Gain */
+static const char *lr_lineout_gain_texts[] = {
+       "Line -12dB DAC 0dB", "Line -6dB DAC 6dB",
+       "Line 0dB DAC 12dB", "Line 6dB DAC 18dB",
+};
+
+static const struct soc_enum l_lineout_gain_enum =
+       SOC_ENUM_SINGLE(DAC33_LDAC_PWR_CTRL, 0,
+                       ARRAY_SIZE(lr_lineout_gain_texts),
+                       lr_lineout_gain_texts);
+
+static const struct soc_enum r_lineout_gain_enum =
+       SOC_ENUM_SINGLE(DAC33_RDAC_PWR_CTRL, 0,
+                       ARRAY_SIZE(lr_lineout_gain_texts),
+                       lr_lineout_gain_texts);
+
 /*
  * DACL/R digital volume control:
  * from 0 dB to -63.5 in 0.5 dB steps
@@ -541,6 +557,8 @@ static const struct snd_kcontrol_new dac33_snd_controls[] = {
                 DAC33_LDAC_DIG_VOL_CTRL, DAC33_RDAC_DIG_VOL_CTRL, 7, 1, 1),
        SOC_DOUBLE_R("Line to Line Out Volume",
                 DAC33_LINEL_TO_LLO_VOL, DAC33_LINER_TO_RLO_VOL, 0, 127, 1),
+       SOC_ENUM("Left Line Output Gain", l_lineout_gain_enum),
+       SOC_ENUM("Right Line Output Gain", r_lineout_gain_enum),
 };
 
 static const struct snd_kcontrol_new dac33_mode_snd_controls[] = {
@@ -650,9 +668,8 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
 
 static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
 {
-       struct snd_soc_codec *codec;
-
-       codec = &dac33->codec;
+       struct snd_soc_codec *codec = dac33->codec;
+       unsigned int delay;
 
        switch (dac33->fifo_mode) {
        case DAC33_FIFO_MODE1:
@@ -668,8 +685,9 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
                dac33_write16(codec, DAC33_PREFILL_MSB,
                                DAC33_THRREG(dac33->alarm_threshold));
                /* Enable Alarm Threshold IRQ with a delay */
-               udelay(SAMPLES_TO_US(dac33->burst_rate,
-                                    dac33->alarm_threshold));
+               delay = SAMPLES_TO_US(dac33->burst_rate,
+                                    dac33->alarm_threshold) + 1000;
+               usleep_range(delay, delay + 500);
                dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT);
                break;
        case DAC33_FIFO_MODE7:
@@ -695,9 +713,7 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
 
 static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33)
 {
-       struct snd_soc_codec *codec;
-
-       codec = &dac33->codec;
+       struct snd_soc_codec *codec = dac33->codec;
 
        switch (dac33->fifo_mode) {
        case DAC33_FIFO_MODE1:
@@ -726,7 +742,7 @@ static void dac33_work(struct work_struct *work)
        u8 reg;
 
        dac33 = container_of(work, struct tlv320dac33_priv, work);
-       codec = &dac33->codec;
+       codec = dac33->codec;
 
        mutex_lock(&dac33->mutex);
        switch (dac33->state) {
@@ -771,11 +787,11 @@ static irqreturn_t dac33_interrupt_handler(int irq, void *dev)
 
 static void dac33_oscwait(struct snd_soc_codec *codec)
 {
-       int timeout = 20;
+       int timeout = 60;
        u8 reg;
 
        do {
-               msleep(1);
+               usleep_range(1000, 2000);
                dac33_read(codec, DAC33_INT_OSC_STATUS, &reg);
        } while (((reg & 0x03) != DAC33_OSCSTATUS_NORMAL) && timeout--);
        if ((reg & 0x03) != DAC33_OSCSTATUS_NORMAL)
@@ -787,8 +803,7 @@ static int dac33_startup(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
        /* Stream started, save the substream pointer */
@@ -801,8 +816,7 @@ static void dac33_shutdown(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
        dac33->substream = NULL;
@@ -817,8 +831,7 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* Check parameters for validity */
        switch (params_rate(params)) {
@@ -856,8 +869,7 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
 static int dac33_prepare_chip(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
        unsigned int oscset, ratioset, pwr_ctrl, reg_tmp;
        u8 aictrl_a, aictrl_b, fifoctrl_a;
@@ -1049,8 +1061,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
 static void dac33_calculate_times(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
        unsigned int period_size = substream->runtime->period_size;
        unsigned int rate = substream->runtime->rate;
@@ -1129,8 +1140,7 @@ static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
                             struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
 
@@ -1163,8 +1173,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
                        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
        unsigned long long t0, t1, t_now;
        unsigned int time_delta, uthr;
@@ -1389,24 +1398,46 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
        return 0;
 }
 
-static int dac33_soc_probe(struct platform_device *pdev)
+static int dac33_soc_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       struct tlv320dac33_priv *dac33;
+       struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
 
-       BUG_ON(!tlv320dac33_codec);
+       codec->control_data = dac33->control_data;
+       codec->hw_write = (hw_write_t) i2c_master_send;
+       codec->idle_bias_off = 1;
+       dac33->codec = codec;
 
-       codec = tlv320dac33_codec;
-       socdev->card->codec = codec;
-       dac33 = snd_soc_codec_get_drvdata(codec);
+       /* Read the tlv320dac33 ID registers */
+       ret = dac33_hard_power(codec, 1);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to power up codec: %d\n", ret);
+               goto err_power;
+       }
+       dac33_read_id(codec);
+       dac33_hard_power(codec, 0);
+
+       /* Check if the IRQ number is valid and request it */
+       if (dac33->irq >= 0) {
+               ret = request_irq(dac33->irq, dac33_interrupt_handler,
+                                 IRQF_TRIGGER_RISING | IRQF_DISABLED,
+                                 codec->name, codec);
+               if (ret < 0) {
+                       dev_err(codec->dev, "Could not request IRQ%d (%d)\n",
+                                               dac33->irq, ret);
+                       dac33->irq = -1;
+               }
+               if (dac33->irq != -1) {
+                       /* Setup work queue */
+                       dac33->dac33_wq =
+                               create_singlethread_workqueue("tlv320dac33");
+                       if (dac33->dac33_wq == NULL) {
+                               free_irq(dac33->irq, codec);
+                               return -ENOMEM;
+                       }
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms\n");
-               goto pcm_err;
+                       INIT_WORK(&dac33->work, dac33_work);
+               }
        }
 
        snd_soc_add_controls(codec, dac33_snd_controls,
@@ -1420,56 +1451,51 @@ static int dac33_soc_probe(struct platform_device *pdev)
                        snd_soc_add_controls(codec, dac33_fifo_snd_controls,
                                        ARRAY_SIZE(dac33_fifo_snd_controls));
        }
-
        dac33_add_widgets(codec);
 
-       return 0;
-
-pcm_err:
-       dac33_hard_power(codec, 0);
+err_power:
        return ret;
 }
 
-static int dac33_soc_remove(struct platform_device *pdev)
+static int dac33_soc_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
        dac33_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
+       if (dac33->irq >= 0) {
+               free_irq(dac33->irq, dac33->codec);
+               destroy_workqueue(dac33->dac33_wq);
+       }
        return 0;
 }
 
-static int dac33_soc_suspend(struct platform_device *pdev, pm_message_t state)
+static int dac33_soc_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        dac33_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int dac33_soc_resume(struct platform_device *pdev)
+static int dac33_soc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_tlv320dac33 = {
+static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
+       .read = dac33_read_reg_cache,
+       .write = dac33_write_locked,
+       .set_bias_level = dac33_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(dac33_reg),
+       .reg_word_size = sizeof(u8),
+       .reg_cache_default = dac33_reg,
        .probe = dac33_soc_probe,
        .remove = dac33_soc_remove,
        .suspend = dac33_soc_suspend,
        .resume = dac33_soc_resume,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320dac33);
 
 #define DAC33_RATES    (SNDRV_PCM_RATE_44100 | \
                         SNDRV_PCM_RATE_48000)
@@ -1485,8 +1511,8 @@ static struct snd_soc_dai_ops dac33_dai_ops = {
        .set_fmt        = dac33_set_dai_fmt,
 };
 
-struct snd_soc_dai dac33_dai = {
-       .name = "tlv320dac33",
+static struct snd_soc_dai_driver dac33_dai = {
+       .name = "tlv320dac33-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -1495,14 +1521,12 @@ struct snd_soc_dai dac33_dai = {
                .formats = DAC33_FORMATS,},
        .ops = &dac33_dai_ops,
 };
-EXPORT_SYMBOL_GPL(dac33_dai);
 
 static int __devinit dac33_i2c_probe(struct i2c_client *client,
                                     const struct i2c_device_id *id)
 {
        struct tlv320dac33_platform_data *pdata;
        struct tlv320dac33_priv *dac33;
-       struct snd_soc_codec *codec;
        int ret, i;
 
        if (client->dev.platform_data == NULL) {
@@ -1515,33 +1539,9 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
        if (dac33 == NULL)
                return -ENOMEM;
 
-       codec = &dac33->codec;
-       snd_soc_codec_set_drvdata(codec, dac33);
-       codec->control_data = client;
-
-       mutex_init(&codec->mutex);
+       dac33->control_data = client;
        mutex_init(&dac33->mutex);
        spin_lock_init(&dac33->lock);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->name = "tlv320dac33";
-       codec->owner = THIS_MODULE;
-       codec->read = dac33_read_reg_cache;
-       codec->write = dac33_write_locked;
-       codec->hw_write = (hw_write_t) i2c_master_send;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = dac33_set_bias_level;
-       codec->idle_bias_off = 1;
-       codec->dai = &dac33_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(dac33_reg);
-       codec->reg_cache = kmemdup(dac33_reg, ARRAY_SIZE(dac33_reg),
-                                  GFP_KERNEL);
-       if (codec->reg_cache == NULL) {
-               ret = -ENOMEM;
-               goto error_reg;
-       }
 
        i2c_set_clientdata(client, dac33);
 
@@ -1561,125 +1561,59 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
        /* Disable FIFO use by default */
        dac33->fifo_mode = DAC33_FIFO_BYPASS;
 
-       tlv320dac33_codec = codec;
-
-       codec->dev = &client->dev;
-       dac33_dai.dev = codec->dev;
-
        /* Check if the reset GPIO number is valid and request it */
        if (dac33->power_gpio >= 0) {
                ret = gpio_request(dac33->power_gpio, "tlv320dac33 reset");
                if (ret < 0) {
-                       dev_err(codec->dev,
+                       dev_err(&client->dev,
                                "Failed to request reset GPIO (%d)\n",
                                dac33->power_gpio);
-                       snd_soc_unregister_dai(&dac33_dai);
-                       snd_soc_unregister_codec(codec);
-                       goto error_gpio;
+                       goto err_gpio;
                }
                gpio_direction_output(dac33->power_gpio, 0);
        }
 
-       /* Check if the IRQ number is valid and request it */
-       if (dac33->irq >= 0) {
-               ret = request_irq(dac33->irq, dac33_interrupt_handler,
-                                 IRQF_TRIGGER_RISING | IRQF_DISABLED,
-                                 codec->name, codec);
-               if (ret < 0) {
-                       dev_err(codec->dev, "Could not request IRQ%d (%d)\n",
-                                               dac33->irq, ret);
-                       dac33->irq = -1;
-               }
-               if (dac33->irq != -1) {
-                       /* Setup work queue */
-                       dac33->dac33_wq =
-                               create_singlethread_workqueue("tlv320dac33");
-                       if (dac33->dac33_wq == NULL) {
-                               free_irq(dac33->irq, &dac33->codec);
-                               ret = -ENOMEM;
-                               goto error_wq;
-                       }
-
-                       INIT_WORK(&dac33->work, dac33_work);
-               }
-       }
-
        for (i = 0; i < ARRAY_SIZE(dac33->supplies); i++)
                dac33->supplies[i].supply = dac33_supply_names[i];
 
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(dac33->supplies),
+       ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(dac33->supplies),
                                 dac33->supplies);
 
        if (ret != 0) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               dev_err(&client->dev, "Failed to request supplies: %d\n", ret);
                goto err_get;
        }
 
-       /* Read the tlv320dac33 ID registers */
-       ret = dac33_hard_power(codec, 1);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to power up codec: %d\n", ret);
-               goto error_codec;
-       }
-       dac33_read_id(codec);
-       dac33_hard_power(codec, 0);
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto error_codec;
-       }
-
-       ret = snd_soc_register_dai(&dac33_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               snd_soc_unregister_codec(codec);
-               goto error_codec;
-       }
+       ret = snd_soc_register_codec(&client->dev,
+                       &soc_codec_dev_tlv320dac33, &dac33_dai, 1);
+       if (ret < 0)
+               goto err_register;
 
        return ret;
-
-error_codec:
+err_register:
        regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
 err_get:
-       if (dac33->irq >= 0) {
-               free_irq(dac33->irq, &dac33->codec);
-               destroy_workqueue(dac33->dac33_wq);
-       }
-error_wq:
        if (dac33->power_gpio >= 0)
                gpio_free(dac33->power_gpio);
-error_gpio:
-       kfree(codec->reg_cache);
-error_reg:
-       tlv320dac33_codec = NULL;
+err_gpio:
        kfree(dac33);
-
        return ret;
 }
 
 static int __devexit dac33_i2c_remove(struct i2c_client *client)
 {
-       struct tlv320dac33_priv *dac33;
-
-       dac33 = i2c_get_clientdata(client);
+       struct tlv320dac33_priv *dac33 = i2c_get_clientdata(client);
 
        if (unlikely(dac33->chip_power))
-               dac33_hard_power(&dac33->codec, 0);
+               dac33_hard_power(dac33->codec, 0);
 
        if (dac33->power_gpio >= 0)
                gpio_free(dac33->power_gpio);
-       if (dac33->irq >= 0)
-               free_irq(dac33->irq, &dac33->codec);
 
        regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
 
-       destroy_workqueue(dac33->dac33_wq);
-       snd_soc_unregister_dai(&dac33_dai);
-       snd_soc_unregister_codec(&dac33->codec);
-       kfree(dac33->codec.reg_cache);
+       snd_soc_unregister_codec(&client->dev);
        kfree(dac33);
-       tlv320dac33_codec = NULL;
 
        return 0;
 }
@@ -1694,7 +1628,7 @@ static const struct i2c_device_id tlv320dac33_i2c_id[] = {
 
 static struct i2c_driver tlv320dac33_i2c_driver = {
        .driver = {
-               .name = "tlv320dac33",
+               .name = "tlv320dac33-codec",
                .owner = THIS_MODULE,
        },
        .probe          = dac33_i2c_probe,
index eb8ae07f0bd2e166003aeda14789e47799e82b2b..7c318b5da4370bfb1c8cee6af5e436161068203e 100644 (file)
 #define TLV320DAC33_MCLK               0
 #define TLV320DAC33_SLEEPCLK           1
 
-extern struct snd_soc_dai dac33_dai;
-extern struct snd_soc_codec_device soc_codec_dev_tlv320dac33;
-
 #endif /* __TLV320DAC33_H */
index 99b70e5978a2ee122e6799df5f27e20711a93976..329acc1a207457942a560e86d7f990a2fc44ffd8 100644 (file)
@@ -98,16 +98,21 @@ static u8 tpa6130a2_read(int reg)
        return data->regs[reg];
 }
 
-static void tpa6130a2_initialize(void)
+static int tpa6130a2_initialize(void)
 {
        struct tpa6130a2_data *data;
-       int i;
+       int i, ret = 0;
 
        BUG_ON(tpa6130a2_client == NULL);
        data = i2c_get_clientdata(tpa6130a2_client);
 
-       for (i = 1; i < TPA6130A2_REG_VERSION; i++)
-               tpa6130a2_i2c_write(i, data->regs[i]);
+       for (i = 1; i < TPA6130A2_REG_VERSION; i++) {
+               ret = tpa6130a2_i2c_write(i, data->regs[i]);
+               if (ret < 0)
+                       break;
+       }
+
+       return ret;
 }
 
 static int tpa6130a2_power(int power)
@@ -133,7 +138,16 @@ static int tpa6130a2_power(int power)
                }
 
                data->power_state = 1;
-               tpa6130a2_initialize();
+               ret = tpa6130a2_initialize();
+               if (ret < 0) {
+                       dev_err(&tpa6130a2_client->dev,
+                               "Failed to initialize chip\n");
+                       if (data->power_gpio >= 0)
+                               gpio_set_value(data->power_gpio, 0);
+                       regulator_disable(data->supply);
+                       data->power_state = 0;
+                       goto exit;
+               }
 
                /* Clear SWS */
                val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
@@ -375,7 +389,9 @@ int tpa6130a2_add_controls(struct snd_soc_codec *codec)
 {
        struct  tpa6130a2_data *data;
 
-       BUG_ON(tpa6130a2_client == NULL);
+       if (tpa6130a2_client == NULL)
+               return -ENODEV;
+
        data = i2c_get_clientdata(tpa6130a2_client);
 
        snd_soc_dapm_new_controls(codec, tpa6130a2_dapm_widgets,
index 7b618bbff8844d65f55092780b199d4b213e433b..cbebec6ba1ba42fda499b018b9f6a1a6938eb1c6 100644 (file)
 #include <sound/initval.h>
 #include <sound/tlv.h>
 
-#include "twl4030.h"
+/* Register descriptions are here */
+#include <linux/mfd/twl4030-codec.h>
+
+/* Shadow register used by the audio driver */
+#define TWL4030_REG_SW_SHADOW          0x4A
+#define TWL4030_CACHEREGNUM    (TWL4030_REG_SW_SHADOW + 1)
+
+/* TWL4030_REG_SW_SHADOW (0x4A) Fields */
+#define TWL4030_HFL_EN                 0x01
+#define TWL4030_HFR_EN                 0x02
 
 /*
  * twl4030 register cache & default register settings
@@ -277,21 +286,19 @@ static inline void twl4030_reset_registers(struct snd_soc_codec *codec)
 
 }
 
-static void twl4030_init_chip(struct platform_device *pdev)
+static void twl4030_init_chip(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct twl4030_setup_data *setup = socdev->codec_data;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct twl4030_codec_audio_data *pdata = dev_get_platdata(codec->dev);
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        u8 reg, byte;
        int i = 0;
 
        /* Check defaults, if instructed before anything else */
-       if (setup && setup->check_defaults)
+       if (pdata && pdata->check_defaults)
                twl4030_check_defaults(codec);
 
        /* Reset registers, if no setup data or if instructed to do so */
-       if (!setup || (setup && setup->reset_registers))
+       if (!pdata || (pdata && pdata->reset_registers))
                twl4030_reset_registers(codec);
 
        /* Refresh APLL_CTL register from HW */
@@ -312,20 +319,14 @@ static void twl4030_init_chip(struct platform_device *pdev)
        twl4030_write(codec, TWL4030_REG_ARXR2_APGA_CTL, 0x32);
 
        /* Machine dependent setup */
-       if (!setup)
+       if (!pdata)
                return;
 
-       twl4030->digimic_delay = setup->digimic_delay;
-
-       /* Configuration for headset ramp delay from setup data */
-       if (setup->sysclk != twl4030->sysclk)
-               dev_warn(codec->dev,
-                               "Mismatch in APLL mclk: %u (configured: %u)\n",
-                               setup->sysclk, twl4030->sysclk);
+       twl4030->digimic_delay = pdata->digimic_delay;
 
        reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
        reg &= ~TWL4030_RAMP_DELAY;
-       reg |= (setup->ramp_delay_value << 2);
+       reg |= (pdata->ramp_delay_value << 2);
        twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, reg);
 
        /* initiate offset cancellation */
@@ -333,7 +334,7 @@ static void twl4030_init_chip(struct platform_device *pdev)
 
        reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
        reg &= ~TWL4030_OFFSET_CNCL_SEL;
-       reg |= setup->offset_cncl_path;
+       reg |= pdata->offset_cncl_path;
        twl4030_write(codec, TWL4030_REG_ANAMICL,
                reg | TWL4030_CNCL_OFFSET_START);
 
@@ -718,9 +719,7 @@ static int aif_event(struct snd_soc_dapm_widget *w,
 
 static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 {
-       struct snd_soc_device *socdev = codec->socdev;
-       struct twl4030_setup_data *setup = socdev->codec_data;
-
+       struct twl4030_codec_audio_data *pdata = codec->dev->platform_data;
        unsigned char hs_gain, hs_pop;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        /* Base values for ramp delay calculation: 2^19 - 2^26 */
@@ -732,9 +731,9 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 
        /* Enable external mute control, this dramatically reduces
         * the pop-noise */
-       if (setup && setup->hs_extmute) {
-               if (setup->set_hs_extmute) {
-                       setup->set_hs_extmute(1);
+       if (pdata && pdata->hs_extmute) {
+               if (pdata->set_hs_extmute) {
+                       pdata->set_hs_extmute(1);
                } else {
                        hs_pop |= TWL4030_EXTMUTE;
                        twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
@@ -772,9 +771,9 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
        }
 
        /* Disable external mute */
-       if (setup && setup->hs_extmute) {
-               if (setup->set_hs_extmute) {
-                       setup->set_hs_extmute(0);
+       if (pdata && pdata->hs_extmute) {
+               if (pdata->set_hs_extmute) {
+                       pdata->set_hs_extmute(0);
                } else {
                        hs_pop &= ~TWL4030_EXTMUTE;
                        twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
@@ -1707,8 +1706,7 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 
        if (twl4030->master_substream) {
@@ -1738,8 +1736,7 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 
        if (twl4030->master_substream == substream)
@@ -1764,8 +1761,7 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        u8 mode, old_mode, format, old_format;
 
@@ -1999,8 +1995,7 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        u8 mode;
 
@@ -2033,8 +2028,7 @@ static void twl4030_voice_shutdown(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* Enable voice digital filters */
        twl4030_voice_enable(codec, substream->stream, 0);
@@ -2044,8 +2038,7 @@ static int twl4030_voice_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_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        u8 old_mode, mode;
 
@@ -2175,7 +2168,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)
 
-static struct snd_soc_dai_ops twl4030_dai_ops = {
+static struct snd_soc_dai_ops twl4030_dai_hifi_ops = {
        .startup        = twl4030_startup,
        .shutdown       = twl4030_shutdown,
        .hw_params      = twl4030_hw_params,
@@ -2193,9 +2186,9 @@ static struct snd_soc_dai_ops twl4030_dai_voice_ops = {
        .set_tristate   = twl4030_voice_set_tristate,
 };
 
-struct snd_soc_dai twl4030_dai[] = {
+static struct snd_soc_dai_driver twl4030_dai[] = {
 {
-       .name = "twl4030",
+       .name = "twl4030-hifi",
        .playback = {
                .stream_name = "HiFi Playback",
                .channels_min = 2,
@@ -2208,10 +2201,10 @@ struct snd_soc_dai twl4030_dai[] = {
                .channels_max = 4,
                .rates = TWL4030_RATES,
                .formats = TWL4030_FORMATS,},
-       .ops = &twl4030_dai_ops,
+       .ops = &twl4030_dai_hifi_ops,
 },
 {
-       .name = "twl4030 Voice",
+       .name = "twl4030-voice",
        .playback = {
                .stream_name = "Voice Playback",
                .channels_min = 1,
@@ -2227,164 +2220,91 @@ struct snd_soc_dai twl4030_dai[] = {
        .ops = &twl4030_dai_voice_ops,
 },
 };
-EXPORT_SYMBOL_GPL(twl4030_dai);
 
-static int twl4030_soc_suspend(struct platform_device *pdev, pm_message_t state)
+static int twl4030_soc_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
        return 0;
 }
 
-static int twl4030_soc_resume(struct platform_device *pdev)
+static int twl4030_soc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        return 0;
 }
 
-static struct snd_soc_codec *twl4030_codec;
-
-static int twl4030_soc_probe(struct platform_device *pdev)
+static int twl4030_soc_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret;
-
-       BUG_ON(!twl4030_codec);
-
-       codec = twl4030_codec;
-       socdev->card->codec = codec;
-
-       twl4030_init_chip(pdev);
+       struct twl4030_priv *twl4030;
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to create pcms\n");
-               return ret;
+       twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL);
+       if (twl4030 == NULL) {
+               printk("Can not allocate memroy\n");
+               return -ENOMEM;
        }
+       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;
+
+       twl4030_init_chip(codec);
 
        snd_soc_add_controls(codec, twl4030_snd_controls,
                                ARRAY_SIZE(twl4030_snd_controls));
        twl4030_add_widgets(codec);
-
        return 0;
 }
 
-static int twl4030_soc_remove(struct platform_device *pdev)
+static int twl4030_soc_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        /* Reset registers to their chip default before leaving */
        twl4030_reset_registers(codec);
        twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
        return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
+       .probe = twl4030_soc_probe,
+       .remove = twl4030_soc_remove,
+       .suspend = twl4030_soc_suspend,
+       .resume = twl4030_soc_resume,
+       .read = twl4030_read_reg_cache,
+       .write = twl4030_write,
+       .set_bias_level = twl4030_set_bias_level,
+       .reg_cache_size = sizeof(twl4030_reg),
+       .reg_word_size = sizeof(u8),
+       .reg_cache_default = twl4030_reg,
+};
+
 static int __devinit twl4030_codec_probe(struct platform_device *pdev)
 {
        struct twl4030_codec_audio_data *pdata = pdev->dev.platform_data;
-       struct snd_soc_codec *codec;
-       struct twl4030_priv *twl4030;
-       int ret;
 
        if (!pdata) {
                dev_err(&pdev->dev, "platform_data is missing\n");
                return -EINVAL;
        }
 
-       twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL);
-       if (twl4030 == NULL) {
-               dev_err(&pdev->dev, "Can not allocate memroy\n");
-               return -ENOMEM;
-       }
-
-       codec = &twl4030->codec;
-       snd_soc_codec_set_drvdata(codec, twl4030);
-       codec->dev = &pdev->dev;
-       twl4030_dai[0].dev = &pdev->dev;
-       twl4030_dai[1].dev = &pdev->dev;
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->name = "twl4030";
-       codec->owner = THIS_MODULE;
-       codec->read = twl4030_read_reg_cache;
-       codec->write = twl4030_write;
-       codec->set_bias_level = twl4030_set_bias_level;
-       codec->idle_bias_off = 1;
-       codec->dai = twl4030_dai;
-       codec->num_dai = ARRAY_SIZE(twl4030_dai);
-       codec->reg_cache_size = sizeof(twl4030_reg);
-       codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg),
-                                       GFP_KERNEL);
-       if (codec->reg_cache == NULL) {
-               ret = -ENOMEM;
-               goto error_cache;
-       }
-
-       platform_set_drvdata(pdev, twl4030);
-       twl4030_codec = codec;
-
-       /* Set the defaults, and power up the codec */
-       twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto error_codec;
-       }
-
-       ret = snd_soc_register_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai));
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
-               snd_soc_unregister_codec(codec);
-               goto error_codec;
-       }
-
-       return 0;
-
-error_codec:
-       twl4030_codec_enable(codec, 0);
-       kfree(codec->reg_cache);
-error_cache:
-       kfree(twl4030);
-       return ret;
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl4030,
+                       twl4030_dai, ARRAY_SIZE(twl4030_dai));
 }
 
 static int __devexit twl4030_codec_remove(struct platform_device *pdev)
 {
-       struct twl4030_priv *twl4030 = platform_get_drvdata(pdev);
+       struct twl4030_priv *twl4030 = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dais(&twl4030_dai[0], ARRAY_SIZE(twl4030_dai));
-       snd_soc_unregister_codec(&twl4030->codec);
-       kfree(twl4030->codec.reg_cache);
+       snd_soc_unregister_codec(&pdev->dev);
        kfree(twl4030);
-
-       twl4030_codec = NULL;
        return 0;
 }
 
-MODULE_ALIAS("platform:twl4030_codec_audio");
+MODULE_ALIAS("platform:twl4030-codec");
 
 static struct platform_driver twl4030_codec_driver = {
        .probe          = twl4030_codec_probe,
        .remove         = __devexit_p(twl4030_codec_remove),
        .driver         = {
-               .name   = "twl4030_codec_audio",
+               .name   = "twl4030-codec",
                .owner  = THIS_MODULE,
        },
 };
@@ -2401,14 +2321,6 @@ static void __exit twl4030_exit(void)
 }
 module_exit(twl4030_exit);
 
-struct snd_soc_codec_device soc_codec_dev_twl4030 = {
-       .probe = twl4030_soc_probe,
-       .remove = twl4030_soc_remove,
-       .suspend = twl4030_soc_suspend,
-       .resume = twl4030_soc_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030);
-
 MODULE_DESCRIPTION("ASoC TWL4030 codec driver");
 MODULE_AUTHOR("Steve Sakoman");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h
deleted file mode 100644 (file)
index 6c57430..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * ALSA SoC TWL4030 codec driver
- *
- * Author: Steve Sakoman <steve@sakoman.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.
- *
- * 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
- *
- */
-
-#ifndef __TWL4030_AUDIO_H__
-#define __TWL4030_AUDIO_H__
-
-/* Register descriptions are here */
-#include <linux/mfd/twl4030-codec.h>
-
-/* Shadow register used by the audio driver */
-#define TWL4030_REG_SW_SHADOW          0x4A
-#define TWL4030_CACHEREGNUM    (TWL4030_REG_SW_SHADOW + 1)
-
-/* TWL4030_REG_SW_SHADOW (0x4A) Fields */
-#define TWL4030_HFL_EN                 0x01
-#define TWL4030_HFR_EN                 0x02
-
-#define TWL4030_DAI_HIFI               0
-#define TWL4030_DAI_VOICE              1
-
-extern struct snd_soc_dai twl4030_dai[2];
-extern struct snd_soc_codec_device soc_codec_dev_twl4030;
-
-struct twl4030_setup_data {
-       unsigned int ramp_delay_value;
-       unsigned int digimic_delay; /* in ms */
-       unsigned int sysclk;
-       unsigned int offset_cncl_path;
-       unsigned int check_defaults:1;
-       unsigned int reset_registers:1;
-       unsigned int hs_extmute:1;
-       void (*set_hs_extmute)(int mute);
-};
-
-#endif /* End of __TWL4030_AUDIO_H__ */
-
-
index 64a807f1a8a1812e4b01d891b8809f69ce1bf1f9..10f6e521451161dbdd169b59d69101a3010f41c3 100644 (file)
@@ -45,7 +45,6 @@
 
 /* codec private data */
 struct twl6040_data {
-       struct snd_soc_codec codec;
        int audpwron;
        int naudint;
        int codec_powered;
@@ -770,8 +769,7 @@ static int twl6040_startup(struct snd_pcm_substream *substream,
                        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 
        if (!priv->sysclk) {
@@ -803,8 +801,7 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
                        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
        u8 lppllctl;
        int rate;
@@ -839,8 +836,7 @@ static int twl6040_trigger(struct snd_pcm_substream *substream,
                        int cmd, struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 
        switch (cmd) {
@@ -978,8 +974,8 @@ static struct snd_soc_dai_ops twl6040_dai_ops = {
        .set_sysclk     = twl6040_set_dai_sysclk,
 };
 
-struct snd_soc_dai twl6040_dai = {
-       .name = "twl6040",
+static struct snd_soc_dai_driver twl6040_dai = {
+       .name = "twl6040-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -996,24 +992,17 @@ struct snd_soc_dai twl6040_dai = {
        },
        .ops = &twl6040_dai_ops,
 };
-EXPORT_SYMBOL_GPL(twl6040_dai);
 
 #ifdef CONFIG_PM
-static int twl6040_suspend(struct platform_device *pdev, pm_message_t state)
+static int twl6040_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int twl6040_resume(struct platform_device *pdev)
+static int twl6040_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
@@ -1023,68 +1012,9 @@ static int twl6040_resume(struct platform_device *pdev)
 #define twl6040_resume NULL
 #endif
 
-static struct snd_soc_codec *twl6040_codec;
-
-static int twl6040_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       BUG_ON(!twl6040_codec);
-
-       codec = twl6040_codec;
-       socdev->card->codec = codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to create pcms\n");
-               return ret;
-       }
-
-       snd_soc_add_controls(codec, twl6040_snd_controls,
-                               ARRAY_SIZE(twl6040_snd_controls));
-       twl6040_add_widgets(codec);
-
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to register card\n");
-               goto card_err;
-       }
-
-       return ret;
-
-card_err:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-       return ret;
-}
-
-static int twl6040_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-       kfree(codec);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_twl6040 = {
-       .probe = twl6040_probe,
-       .remove = twl6040_remove,
-       .suspend = twl6040_suspend,
-       .resume = twl6040_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_twl6040);
-
-static int __devinit twl6040_codec_probe(struct platform_device *pdev)
+static int twl6040_probe(struct snd_soc_codec *codec)
 {
-       struct twl4030_codec_data *twl_codec = pdev->dev.platform_data;
-       struct snd_soc_codec *codec;
+       struct twl4030_codec_data *twl_codec = codec->dev->platform_data;
        struct twl6040_data *priv;
        int audpwron, naudint;
        int ret = 0;
@@ -1092,6 +1022,7 @@ static int __devinit twl6040_codec_probe(struct platform_device *pdev)
        priv = kzalloc(sizeof(struct twl6040_data), GFP_KERNEL);
        if (priv == NULL)
                return -ENOMEM;
+       snd_soc_codec_set_drvdata(codec, priv);
 
        if (twl_codec) {
                audpwron = twl_codec->audpwron_gpio;
@@ -1104,29 +1035,6 @@ static int __devinit twl6040_codec_probe(struct platform_device *pdev)
        priv->audpwron = audpwron;
        priv->naudint = naudint;
 
-       codec = &priv->codec;
-       codec->dev = &pdev->dev;
-       twl6040_dai.dev = &pdev->dev;
-
-       codec->name = "twl6040";
-       codec->owner = THIS_MODULE;
-       codec->read = twl6040_read_reg_cache;
-       codec->write = twl6040_write;
-       codec->set_bias_level = twl6040_set_bias_level;
-       snd_soc_codec_set_drvdata(codec, priv);
-       codec->dai = &twl6040_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(twl6040_reg);
-       codec->reg_cache = kmemdup(twl6040_reg, sizeof(twl6040_reg),
-                                       GFP_KERNEL);
-       if (codec->reg_cache == NULL) {
-               ret = -ENOMEM;
-               goto cache_err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
        init_completion(&priv->ready);
 
        if (gpio_is_valid(audpwron)) {
@@ -1169,23 +1077,12 @@ static int __devinit twl6040_codec_probe(struct platform_device *pdev)
        if (ret)
                goto irq_err;
 
-       ret = snd_soc_register_codec(codec);
-       if (ret)
-               goto reg_err;
-
-       twl6040_codec = codec;
-
-       ret = snd_soc_register_dai(&twl6040_dai);
-       if (ret)
-               goto dai_err;
+       snd_soc_add_controls(codec, twl6040_snd_controls,
+                               ARRAY_SIZE(twl6040_snd_controls));
+       twl6040_add_widgets(codec);
 
        return 0;
 
-dai_err:
-       snd_soc_unregister_codec(codec);
-       twl6040_codec = NULL;
-reg_err:
-       twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
 irq_err:
        if (naudint)
                free_irq(naudint, codec);
@@ -1193,36 +1090,57 @@ gpio2_err:
        if (gpio_is_valid(audpwron))
                gpio_free(audpwron);
 gpio1_err:
-       kfree(codec->reg_cache);
-cache_err:
        kfree(priv);
        return ret;
 }
 
-static int __devexit twl6040_codec_remove(struct platform_device *pdev)
+static int twl6040_remove(struct snd_soc_codec *codec)
 {
-       struct twl6040_data *priv = snd_soc_codec_get_drvdata(twl6040_codec);
+       struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
        int audpwron = priv->audpwron;
        int naudint = priv->naudint;
 
+       twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
        if (gpio_is_valid(audpwron))
                gpio_free(audpwron);
 
        if (naudint)
-               free_irq(naudint, twl6040_codec);
+               free_irq(naudint, codec);
 
-       snd_soc_unregister_dai(&twl6040_dai);
-       snd_soc_unregister_codec(twl6040_codec);
+       kfree(priv);
 
-       kfree(twl6040_codec);
-       twl6040_codec = NULL;
+       return 0;
+}
 
+static struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
+       .probe = twl6040_probe,
+       .remove = twl6040_remove,
+       .suspend = twl6040_suspend,
+       .resume = twl6040_resume,
+       .read = twl6040_read_reg_cache,
+       .write = twl6040_write,
+       .set_bias_level = twl6040_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(twl6040_reg),
+       .reg_word_size = sizeof(u8),
+       .reg_cache_default = twl6040_reg,
+};
+
+static int __devinit twl6040_codec_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_twl6040, &twl6040_dai, 1);
+}
+
+static int __devexit twl6040_codec_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
        return 0;
 }
 
 static struct platform_driver twl6040_codec_driver = {
        .driver = {
-               .name = "twl6040_codec",
+               .name = "twl6040-codec",
                .owner = THIS_MODULE,
        },
        .probe = twl6040_codec_probe,
index c472070a1da2c93544cc67e9fe827eb5d146eccd..f7c77fa58a3c4b5de3e836dfd7cdc98b4c15b52f 100644 (file)
 #define TWL6040_HPPLL_ID               1
 #define TWL6040_LPPLL_ID               2
 
-extern struct snd_soc_dai twl6040_dai;
-extern struct snd_soc_codec_device soc_codec_dev_twl6040;
-
 #endif /* End of __TWL6040_H__ */
index f3b4c1d6a82d1927975d80c303a62d38448bb238..7540a509a6f58acec8c29aad5c76b65a86a5f83a 100644 (file)
@@ -161,8 +161,7 @@ static int uda134x_startup(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec =rtd->codec;
        struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
        struct snd_pcm_runtime *master_runtime;
 
@@ -194,8 +193,7 @@ static void uda134x_shutdown(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
 
        if (uda134x->master_substream == substream)
@@ -209,8 +207,7 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
        u8 hw_params;
 
@@ -364,7 +361,7 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec,
                        pd->power(1);
                        /* Sync reg_cache with the hardware */
                        for (i = 0; i < ARRAY_SIZE(uda134x_reg); i++)
-                               codec->write(codec, i, *cache++);
+                               codec->driver->write(codec, i, *cache++);
                }
                break;
        case SND_SOC_BIAS_STANDBY:
@@ -465,8 +462,8 @@ static struct snd_soc_dai_ops uda134x_dai_ops = {
        .set_fmt        = uda134x_set_dai_fmt,
 };
 
-struct snd_soc_dai uda134x_dai = {
-       .name = "UDA134X",
+static struct snd_soc_dai_driver uda134x_dai = {
+       .name = "uda134x-hifi",
        /* playback capabilities */
        .playback = {
                .stream_name = "Playback",
@@ -486,27 +483,21 @@ struct snd_soc_dai uda134x_dai = {
        /* pcm operations */
        .ops = &uda134x_dai_ops,
 };
-EXPORT_SYMBOL(uda134x_dai);
 
-
-static int uda134x_soc_probe(struct platform_device *pdev)
+static int uda134x_soc_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
        struct uda134x_priv *uda134x;
-       void *codec_setup_data = socdev->codec_data;
-       int ret = -ENOMEM;
-       struct uda134x_platform_data *pd;
+       struct uda134x_platform_data *pd = dev_get_drvdata(codec->card->dev);
+       int ret;
 
        printk(KERN_INFO "UDA134X SoC Audio Codec\n");
 
-       if (!codec_setup_data) {
+       if (!pd) {
                printk(KERN_ERR "UDA134X SoC codec: "
                       "missing L3 bitbang function\n");
                return -ENODEV;
        }
 
-       pd = codec_setup_data;
        switch (pd->model) {
        case UDA134X_UDA1340:
        case UDA134X_UDA1341:
@@ -520,58 +511,22 @@ static int uda134x_soc_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (socdev->card->codec == NULL)
-               return ret;
-
-       codec = socdev->card->codec;
-
        uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL);
        if (uda134x == NULL)
-               goto priv_err;
+               return -ENOMEM;
        snd_soc_codec_set_drvdata(codec, uda134x);
 
-       codec->reg_cache = kmemdup(uda134x_reg, sizeof(uda134x_reg),
-                                  GFP_KERNEL);
-       if (codec->reg_cache == NULL)
-               goto reg_err;
-
-       mutex_init(&codec->mutex);
-
-       codec->reg_cache_size = sizeof(uda134x_reg);
-       codec->reg_cache_step = 1;
-
-       codec->name = "UDA134X";
-       codec->owner = THIS_MODULE;
-       codec->dai = &uda134x_dai;
-       codec->num_dai = 1;
-       codec->read = uda134x_read_reg_cache;
-       codec->write = uda134x_write;
-
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->control_data = codec_setup_data;
+       codec->control_data = pd;
 
        if (pd->power)
                pd->power(1);
 
        uda134x_reset(codec);
 
-       if (pd->is_powered_on_standby) {
-               codec->set_bias_level = NULL;
+       if (pd->is_powered_on_standby)
                uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
-       } else {
-               codec->set_bias_level = uda134x_set_bias_level;
+       else
                uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-       }
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "UDA134X: failed to register pcms\n");
-               goto pcm_err;
-       }
 
        switch (pd->model) {
        case UDA134X_UDA1340:
@@ -590,61 +545,42 @@ static int uda134x_soc_probe(struct platform_device *pdev)
        default:
                printk(KERN_ERR "%s unknown codec type: %d",
                        __func__, pd->model);
-       return -EINVAL;
+               kfree(uda134x);
+               return -EINVAL;
        }
 
        if (ret < 0) {
                printk(KERN_ERR "UDA134X: failed to register controls\n");
-               goto pcm_err;
+               kfree(uda134x);
+               return ret;
        }
 
        return 0;
-
-pcm_err:
-       kfree(codec->reg_cache);
-reg_err:
-       kfree(snd_soc_codec_get_drvdata(codec));
-priv_err:
-       kfree(codec);
-       return ret;
 }
 
 /* power down chip */
-static int uda134x_soc_remove(struct platform_device *pdev)
+static int uda134x_soc_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
 
        uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       kfree(snd_soc_codec_get_drvdata(codec));
-       kfree(codec->reg_cache);
-       kfree(codec);
-
+       kfree(uda134x);
        return 0;
 }
 
 #if defined(CONFIG_PM)
-static int uda134x_soc_suspend(struct platform_device *pdev,
+static int uda134x_soc_suspend(struct snd_soc_codec *codec,
                                                pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int uda134x_soc_resume(struct platform_device *pdev)
+static int uda134x_soc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
        uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
        return 0;
@@ -654,25 +590,53 @@ static int uda134x_soc_resume(struct platform_device *pdev)
 #define uda134x_soc_resume NULL
 #endif /* CONFIG_PM */
 
-struct snd_soc_codec_device soc_codec_dev_uda134x = {
+static struct snd_soc_codec_driver soc_codec_dev_uda134x = {
        .probe =        uda134x_soc_probe,
        .remove =       uda134x_soc_remove,
        .suspend =      uda134x_soc_suspend,
        .resume =       uda134x_soc_resume,
+       .reg_cache_size = sizeof(uda134x_reg),
+       .reg_word_size = sizeof(u8),
+       .reg_cache_step = 1,
+       .read = uda134x_read_reg_cache,
+       .write = uda134x_write,
+#ifdef POWER_OFF_ON_STANDBY
+       .set_bias_level = uda134x_set_bias_level,
+#endif
+};
+
+static int __devinit uda134x_codec_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_uda134x, &uda134x_dai, 1);
+}
+
+static int __devexit uda134x_codec_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver uda134x_codec_driver = {
+       .driver = {
+               .name = "uda134x-codec",
+               .owner = THIS_MODULE,
+       },
+       .probe = uda134x_codec_probe,
+       .remove = __devexit_p(uda134x_codec_remove),
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x);
 
-static int __init uda134x_init(void)
+static int __init uda134x_codec_init(void)
 {
-       return snd_soc_register_dai(&uda134x_dai);
+       return platform_driver_register(&uda134x_codec_driver);
 }
-module_init(uda134x_init);
+module_init(uda134x_codec_init);
 
-static void __exit uda134x_exit(void)
+static void __exit uda134x_codec_exit(void)
 {
-       snd_soc_unregister_dai(&uda134x_dai);
+       platform_driver_unregister(&uda134x_codec_driver);
 }
-module_exit(uda134x_exit);
+module_exit(uda134x_codec_exit);
 
 MODULE_DESCRIPTION("UDA134X ALSA soc codec driver");
 MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
index 205f03b3eaf81674de74f4a60e8ac28cddbf4c83..9faae06972b32fc226cbb9450e84e86b7f6f271e 100644 (file)
@@ -31,7 +31,4 @@
 #define STATUS0_DAIFMT_MASK (~(7<<1))
 #define STATUS0_SYSCLK_MASK (~(3<<4))
 
-extern struct snd_soc_dai uda134x_dai;
-extern struct snd_soc_codec_device soc_codec_dev_uda134x;
-
 #endif
index 2f925a27dcde2353f35566aa8dd2f057ebe3a971..0c6c725736c628b0046dad43cc9d30260483de8d 100644 (file)
 
 #include "uda1380.h"
 
-static struct snd_soc_codec *uda1380_codec;
-
 /* codec private data */
 struct uda1380_priv {
-       struct snd_soc_codec codec;
+       struct snd_soc_codec *codec;
        u16 reg_cache[UDA1380_CACHEREGNUM];
        unsigned int dac_clk;
        struct work_struct work;
+       void *control_data;
 };
 
 /*
@@ -131,10 +130,51 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
                return -EIO;
 }
 
-#define uda1380_reset(c)       uda1380_write(c, UDA1380_RESET, 0)
+static void uda1380_sync_cache(struct snd_soc_codec *codec)
+{
+       int reg;
+       u8 data[3];
+       u16 *cache = codec->reg_cache;
+
+       /* Sync reg_cache with the hardware */
+       for (reg = 0; reg < UDA1380_MVOL; reg++) {
+               data[0] = reg;
+               data[1] = (cache[reg] & 0xff00) >> 8;
+               data[2] = cache[reg] & 0x00ff;
+               if (codec->hw_write(codec->control_data, data, 3) != 3)
+                       dev_err(codec->dev, "%s: write to reg 0x%x failed\n",
+                               __func__, reg);
+       }
+}
+
+static int uda1380_reset(struct snd_soc_codec *codec)
+{
+       struct uda1380_platform_data *pdata = codec->dev->platform_data;
+
+       if (gpio_is_valid(pdata->gpio_reset)) {
+               gpio_set_value(pdata->gpio_reset, 1);
+               mdelay(1);
+               gpio_set_value(pdata->gpio_reset, 0);
+       } else {
+               u8 data[3];
+
+               data[0] = UDA1380_RESET;
+               data[1] = 0;
+               data[2] = 0;
+
+               if (codec->hw_write(codec->control_data, data, 3) != 3) {
+                       dev_err(codec->dev, "%s: failed\n", __func__);
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
 
 static void uda1380_flush_work(struct work_struct *work)
 {
+       struct uda1380_priv *uda1380 = container_of(work, struct uda1380_priv, work);
+       struct snd_soc_codec *uda1380_codec = uda1380->codec;
        int bit, reg;
 
        for_each_set_bit(bit, &uda1380_cache_dirty, UDA1380_CACHEREGNUM - 0x10) {
@@ -145,6 +185,7 @@ static void uda1380_flush_work(struct work_struct *work)
                                uda1380_read_reg_cache(uda1380_codec, reg));
                clear_bit(bit, &uda1380_cache_dirty);
        }
+
 }
 
 /* declarations of ALSA reg_elem_REAL controls */
@@ -474,8 +515,7 @@ static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
        int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER);
 
@@ -501,8 +541,7 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
 
        /* set WSPLL power and divider if running from this clock */
@@ -540,8 +579,7 @@ static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
 
        /* shut down WSPLL power if running from this clock */
@@ -562,18 +600,41 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
        enum snd_soc_bias_level level)
 {
        int pm = uda1380_read_reg_cache(codec, UDA1380_PM);
+       int reg;
+       struct uda1380_platform_data *pdata = codec->dev->platform_data;
+
+       if (codec->bias_level == level)
+               return 0;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
        case SND_SOC_BIAS_PREPARE:
+               /* ADC, DAC on */
                uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm);
                break;
        case SND_SOC_BIAS_STANDBY:
-               uda1380_write(codec, UDA1380_PM, R02_PON_BIAS);
-               break;
-       case SND_SOC_BIAS_OFF:
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       if (gpio_is_valid(pdata->gpio_power)) {
+                               gpio_set_value(pdata->gpio_power, 1);
+                               mdelay(1);
+                               uda1380_reset(codec);
+                       }
+
+                       uda1380_sync_cache(codec);
+               }
                uda1380_write(codec, UDA1380_PM, 0x0);
                break;
+       case SND_SOC_BIAS_OFF:
+               if (!gpio_is_valid(pdata->gpio_power))
+                       break;
+
+               gpio_set_value(pdata->gpio_power, 0);
+
+               /* Mark mixer regs cache dirty to sync them with
+                * codec regs on power on.
+                */
+               for (reg = UDA1380_MVOL; reg < UDA1380_CACHEREGNUM; reg++)
+                       set_bit(reg - 0x10, &uda1380_cache_dirty);
        }
        codec->bias_level = level;
        return 0;
@@ -604,9 +665,9 @@ static struct snd_soc_dai_ops uda1380_dai_ops_capture = {
        .set_fmt        = uda1380_set_dai_fmt_capture,
 };
 
-struct snd_soc_dai uda1380_dai[] = {
+static struct snd_soc_dai_driver uda1380_dai[] = {
 {
-       .name = "UDA1380",
+       .name = "uda1380-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -622,7 +683,7 @@ struct snd_soc_dai uda1380_dai[] = {
        .ops = &uda1380_dai_ops,
 },
 { /* playback only - dual interface */
-       .name = "UDA1380",
+       .name = "uda1380-hifi-playback",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -633,7 +694,7 @@ struct snd_soc_dai uda1380_dai[] = {
        .ops = &uda1380_dai_ops_playback,
 },
 { /* capture only - dual interface*/
-       .name = "UDA1380",
+       .name = "uda1380-hifi-capture",
        .capture = {
                .stream_name = "Capture",
                .channels_min = 1,
@@ -644,67 +705,69 @@ struct snd_soc_dai uda1380_dai[] = {
        .ops = &uda1380_dai_ops_capture,
 },
 };
-EXPORT_SYMBOL_GPL(uda1380_dai);
 
-static int uda1380_suspend(struct platform_device *pdev, pm_message_t state)
+static int uda1380_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int uda1380_resume(struct platform_device *pdev)
+static int uda1380_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int i;
-       u8 data[2];
-       u16 *cache = codec->reg_cache;
-
-       /* Sync reg_cache with the hardware */
-       for (i = 0; i < ARRAY_SIZE(uda1380_reg); i++) {
-               data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
-               data[1] = cache[i] & 0x00ff;
-               codec->hw_write(codec->control_data, data, 2);
-       }
        uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        return 0;
 }
 
-static int uda1380_probe(struct platform_device *pdev)
+static int uda1380_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       struct uda1380_platform_data *pdata;
-       int ret = 0;
+       struct uda1380_platform_data *pdata =codec->dev->platform_data;
+       struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
+       int ret;
 
-       if (uda1380_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
+       uda1380->codec = codec;
+
+       codec->hw_write = (hw_write_t)i2c_master_send;
+       codec->control_data = uda1380->control_data;
+
+       if (!pdata)
+               return -EINVAL;
 
-       socdev->card->codec = uda1380_codec;
-       codec = uda1380_codec;
-       pdata = codec->dev->platform_data;
+       if (gpio_is_valid(pdata->gpio_reset)) {
+               ret = gpio_request(pdata->gpio_reset, "uda1380 reset");
+               if (ret)
+                       goto err_out;
+               ret = gpio_direction_output(pdata->gpio_reset, 0);
+               if (ret)
+                       goto err_gpio_reset_conf;
+       }
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
+       if (gpio_is_valid(pdata->gpio_power)) {
+               ret = gpio_request(pdata->gpio_power, "uda1380 power");
+               if (ret)
+                       goto err_gpio;
+               ret = gpio_direction_output(pdata->gpio_power, 0);
+               if (ret)
+                       goto err_gpio_power_conf;
+       } else {
+               ret = uda1380_reset(codec);
+               if (ret) {
+                       dev_err(codec->dev, "Failed to issue reset\n");
+                       goto err_reset;
+               }
        }
 
+       INIT_WORK(&uda1380->work, uda1380_flush_work);
+
        /* power on device */
        uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        /* set clock input */
        switch (pdata->dac_clk) {
        case UDA1380_DAC_CLK_SYSCLK:
-               uda1380_write(codec, UDA1380_CLK, 0);
+               uda1380_write_reg_cache(codec, UDA1380_CLK, 0);
                break;
        case UDA1380_DAC_CLK_WSPLL:
-               uda1380_write(codec, UDA1380_CLK, R00_DAC_CLK);
+               uda1380_write_reg_cache(codec, UDA1380_CLK,
+                       R00_DAC_CLK);
                break;
        }
 
@@ -712,167 +775,73 @@ static int uda1380_probe(struct platform_device *pdev)
                                ARRAY_SIZE(uda1380_snd_controls));
        uda1380_add_widgets(codec);
 
-       return ret;
-
-pcm_err:
-       return ret;
-}
-
-/* power down chip */
-static int uda1380_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec->control_data)
-               uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
        return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_uda1380 = {
-       .probe =        uda1380_probe,
-       .remove =       uda1380_remove,
-       .suspend =      uda1380_suspend,
-       .resume =       uda1380_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380);
-
-static int uda1380_register(struct uda1380_priv *uda1380)
-{
-       int ret, i;
-       struct snd_soc_codec *codec = &uda1380->codec;
-       struct uda1380_platform_data *pdata = codec->dev->platform_data;
-
-       if (uda1380_codec) {
-               dev_err(codec->dev, "Another UDA1380 is registered\n");
-               return -EINVAL;
-       }
-
-       if (!pdata || !pdata->gpio_power || !pdata->gpio_reset)
-               return -EINVAL;
-
-       ret = gpio_request(pdata->gpio_power, "uda1380 power");
-       if (ret)
-               goto err_out;
-       ret = gpio_request(pdata->gpio_reset, "uda1380 reset");
-       if (ret)
-               goto err_gpio;
-
-       gpio_direction_output(pdata->gpio_power, 1);
-
-       /* we may need to have the clock running here - pH5 */
-       gpio_direction_output(pdata->gpio_reset, 1);
-       udelay(5);
-       gpio_set_value(pdata->gpio_reset, 0);
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, uda1380);
-       codec->name = "UDA1380";
-       codec->owner = THIS_MODULE;
-       codec->read = uda1380_read_reg_cache;
-       codec->write = uda1380_write;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = uda1380_set_bias_level;
-       codec->dai = uda1380_dai;
-       codec->num_dai = ARRAY_SIZE(uda1380_dai);
-       codec->reg_cache_size = ARRAY_SIZE(uda1380_reg);
-       codec->reg_cache = &uda1380->reg_cache;
-       codec->reg_cache_step = 1;
-
-       memcpy(codec->reg_cache, uda1380_reg, sizeof(uda1380_reg));
-
-       ret = uda1380_reset(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset\n");
-               goto err_reset;
-       }
-
-       INIT_WORK(&uda1380->work, uda1380_flush_work);
 
-       for (i = 0; i < ARRAY_SIZE(uda1380_dai); i++)
-               uda1380_dai[i].dev = codec->dev;
-
-       uda1380_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err_reset;
-       }
-
-       ret = snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
-               goto err_dai;
-       }
-
-       return 0;
-
-err_dai:
-       snd_soc_unregister_codec(codec);
 err_reset:
-       gpio_set_value(pdata->gpio_power, 0);
-       gpio_free(pdata->gpio_reset);
+err_gpio_power_conf:
+       if (gpio_is_valid(pdata->gpio_power))
+               gpio_free(pdata->gpio_power);
+
+err_gpio_reset_conf:
 err_gpio:
-       gpio_free(pdata->gpio_power);
+       if (gpio_is_valid(pdata->gpio_reset))
+               gpio_free(pdata->gpio_reset);
 err_out:
        return ret;
 }
 
-static void uda1380_unregister(struct uda1380_priv *uda1380)
+/* power down chip */
+static int uda1380_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = &uda1380->codec;
-       struct uda1380_platform_data *pdata = codec->dev->platform_data;
+       struct uda1380_platform_data *pdata =codec->dev->platform_data;
 
-       snd_soc_unregister_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
-       snd_soc_unregister_codec(&uda1380->codec);
+       uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
-       gpio_set_value(pdata->gpio_power, 0);
        gpio_free(pdata->gpio_reset);
        gpio_free(pdata->gpio_power);
 
-       kfree(uda1380);
-       uda1380_codec = NULL;
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_uda1380 = {
+       .probe =        uda1380_probe,
+       .remove =       uda1380_remove,
+       .suspend =      uda1380_suspend,
+       .resume =       uda1380_resume,
+       .read =         uda1380_read_reg_cache,
+       .write =        uda1380_write,
+       .set_bias_level = uda1380_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(uda1380_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = uda1380_reg,
+       .reg_cache_step = 1,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int uda1380_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct uda1380_priv *uda1380;
-       struct snd_soc_codec *codec;
        int ret;
 
        uda1380 = kzalloc(sizeof(struct uda1380_priv), GFP_KERNEL);
        if (uda1380 == NULL)
                return -ENOMEM;
 
-       codec = &uda1380->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
        i2c_set_clientdata(i2c, uda1380);
-       codec->control_data = i2c;
+       uda1380->control_data = i2c;
 
-       codec->dev = &i2c->dev;
-
-       ret = uda1380_register(uda1380);
-       if (ret != 0)
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_uda1380, uda1380_dai, ARRAY_SIZE(uda1380_dai));
+       if (ret < 0)
                kfree(uda1380);
-
        return ret;
 }
 
 static int __devexit uda1380_i2c_remove(struct i2c_client *i2c)
 {
-       struct uda1380_priv *uda1380 = i2c_get_clientdata(i2c);
-       uda1380_unregister(uda1380);
+       snd_soc_unregister_codec(&i2c->dev);
+       kfree(i2c_get_clientdata(i2c));
        return 0;
 }
 
@@ -884,7 +853,7 @@ MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id);
 
 static struct i2c_driver uda1380_i2c_driver = {
        .driver = {
-               .name =  "UDA1380 I2C Codec",
+               .name =  "uda1380-codec",
                .owner = THIS_MODULE,
        },
        .probe =    uda1380_i2c_probe,
index 9cefa8a54770da1c003db0e0cfb029b1a65a8baa..942e3927c72b11e033a98cda16dbf9b80b9b2dd1 100644 (file)
@@ -76,7 +76,4 @@
 #define UDA1380_DAI_PLAYBACK   1 /* playback DAI */
 #define UDA1380_DAI_CAPTURE    2 /* capture DAI */
 
-extern struct snd_soc_dai uda1380_dai[3];
-extern struct snd_soc_codec_device soc_codec_dev_uda1380;
-
 #endif /* _UDA1380_H */
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
new file mode 100644 (file)
index 0000000..0c47c78
--- /dev/null
@@ -0,0 +1,528 @@
+/*
+ * ALSA SoC WL1273 codec driver
+ *
+ * Author:      Matti Aaltonen, <matti.j.aaltonen@nokia.com>
+ *
+ * Copyright:   (C) 2010 Nokia Corporation
+ *
+ * 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/mfd/wl1273-core.h>
+#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/initval.h>
+
+#include "wl1273.h"
+
+enum wl1273_mode { WL1273_MODE_BT, WL1273_MODE_FM_RX, WL1273_MODE_FM_TX };
+
+/* codec private data */
+struct wl1273_priv {
+       enum wl1273_mode mode;
+       struct wl1273_core *core;
+       unsigned int channels;
+};
+
+static int snd_wl1273_fm_set_i2s_mode(struct wl1273_core *core,
+                                     int rate, int width)
+{
+       struct device *dev = &core->i2c_dev->dev;
+       int r = 0;
+       u16 mode;
+
+       dev_dbg(dev, "rate: %d\n", rate);
+       dev_dbg(dev, "width: %d\n", width);
+
+       mutex_lock(&core->lock);
+
+       mode = core->i2s_mode & ~WL1273_IS2_WIDTH & ~WL1273_IS2_RATE;
+
+       switch (rate) {
+       case 48000:
+               mode |= WL1273_IS2_RATE_48K;
+               break;
+       case 44100:
+               mode |= WL1273_IS2_RATE_44_1K;
+               break;
+       case 32000:
+               mode |= WL1273_IS2_RATE_32K;
+               break;
+       case 22050:
+               mode |= WL1273_IS2_RATE_22_05K;
+               break;
+       case 16000:
+               mode |= WL1273_IS2_RATE_16K;
+               break;
+       case 12000:
+               mode |= WL1273_IS2_RATE_12K;
+               break;
+       case 11025:
+               mode |= WL1273_IS2_RATE_11_025;
+               break;
+       case 8000:
+               mode |= WL1273_IS2_RATE_8K;
+               break;
+       default:
+               dev_err(dev, "Sampling rate: %d not supported\n", rate);
+               r = -EINVAL;
+               goto out;
+       }
+
+       switch (width) {
+       case 16:
+               mode |= WL1273_IS2_WIDTH_32;
+               break;
+       case 20:
+               mode |= WL1273_IS2_WIDTH_40;
+               break;
+       case 24:
+               mode |= WL1273_IS2_WIDTH_48;
+               break;
+       case 25:
+               mode |= WL1273_IS2_WIDTH_50;
+               break;
+       case 30:
+               mode |= WL1273_IS2_WIDTH_60;
+               break;
+       case 32:
+               mode |= WL1273_IS2_WIDTH_64;
+               break;
+       case 40:
+               mode |= WL1273_IS2_WIDTH_80;
+               break;
+       case 48:
+               mode |= WL1273_IS2_WIDTH_96;
+               break;
+       case 64:
+               mode |= WL1273_IS2_WIDTH_128;
+               break;
+       default:
+               dev_err(dev, "Data width: %d not supported\n", width);
+               r = -EINVAL;
+               goto out;
+       }
+
+       dev_dbg(dev, "WL1273_I2S_DEF_MODE: 0x%04x\n",  WL1273_I2S_DEF_MODE);
+       dev_dbg(dev, "core->i2s_mode: 0x%04x\n", core->i2s_mode);
+       dev_dbg(dev, "mode: 0x%04x\n", mode);
+
+       if (core->i2s_mode != mode) {
+               r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET, mode);
+               if (r)
+                       goto out;
+
+               core->i2s_mode = mode;
+               r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE,
+                                       WL1273_AUDIO_ENABLE_I2S);
+               if (r)
+                       goto out;
+       }
+out:
+       mutex_unlock(&core->lock);
+
+       return r;
+}
+
+static int snd_wl1273_fm_set_channel_number(struct wl1273_core *core,
+                                           int channel_number)
+{
+       struct i2c_client *client = core->i2c_dev;
+       struct device *dev = &client->dev;
+       int r = 0;
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       mutex_lock(&core->lock);
+
+       if (core->channel_number == channel_number)
+               goto out;
+
+       if (channel_number == 1 && core->mode == WL1273_MODE_RX)
+               r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET,
+                                       WL1273_RX_MONO);
+       else if (channel_number == 1 && core->mode == WL1273_MODE_TX)
+               r = wl1273_fm_write_cmd(core, WL1273_MONO_SET,
+                                       WL1273_TX_MONO);
+       else if (channel_number == 2 && core->mode == WL1273_MODE_RX)
+               r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET,
+                                       WL1273_RX_STEREO);
+       else if (channel_number == 2 && core->mode == WL1273_MODE_TX)
+               r = wl1273_fm_write_cmd(core, WL1273_MONO_SET,
+                                       WL1273_TX_STEREO);
+       else
+               r = -EINVAL;
+out:
+       mutex_unlock(&core->lock);
+
+       return r;
+}
+
+static int snd_wl1273_get_audio_route(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = wl1273->mode;
+
+       return 0;
+}
+
+static const char *wl1273_audio_route[] = { "Bt", "FmRx", "FmTx" };
+
+static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+       if (wl1273->mode == ucontrol->value.integer.value[0])
+               return 0;
+
+       /* Do not allow changes while stream is running */
+       if (codec->active)
+               return -EPERM;
+
+       if (ucontrol->value.integer.value[0] < 0 ||
+           ucontrol->value.integer.value[0] >=  ARRAY_SIZE(wl1273_audio_route))
+               return -EINVAL;
+
+       wl1273->mode = ucontrol->value.integer.value[0];
+
+       return 1;
+}
+
+static const struct soc_enum wl1273_enum =
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wl1273_audio_route), wl1273_audio_route);
+
+static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+       dev_dbg(codec->dev, "%s: enter.\n", __func__);
+
+       ucontrol->value.integer.value[0] = wl1273->core->audio_mode;
+
+       return 0;
+}
+
+static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+       int val, r = 0;
+
+       dev_dbg(codec->dev, "%s: enter.\n", __func__);
+
+       val = ucontrol->value.integer.value[0];
+       if (wl1273->core->audio_mode == val)
+               return 0;
+
+       r = wl1273_fm_set_audio(wl1273->core, val);
+       if (r < 0)
+               return r;
+
+       return 1;
+}
+
+static const char *wl1273_audio_strings[] = { "Digital", "Analog" };
+
+static const struct soc_enum wl1273_audio_enum =
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wl1273_audio_strings),
+                           wl1273_audio_strings);
+
+static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+       dev_dbg(codec->dev, "%s: enter.\n", __func__);
+
+       ucontrol->value.integer.value[0] = wl1273->core->volume;
+
+       return 0;
+}
+
+static int snd_wl1273_fm_volume_put(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+       int r;
+
+       dev_dbg(codec->dev, "%s: enter.\n", __func__);
+
+       r = wl1273_fm_set_volume(wl1273->core,
+                                ucontrol->value.integer.value[0]);
+       if (r)
+               return r;
+
+       return 1;
+}
+
+static const struct snd_kcontrol_new wl1273_controls[] = {
+       SOC_ENUM_EXT("Codec Mode", wl1273_enum,
+                    snd_wl1273_get_audio_route, snd_wl1273_set_audio_route),
+       SOC_ENUM_EXT("Audio Switch", wl1273_audio_enum,
+                    snd_wl1273_fm_audio_get,  snd_wl1273_fm_audio_put),
+       SOC_SINGLE_EXT("Volume", 0, 0, WL1273_MAX_VOLUME, 0,
+                      snd_wl1273_fm_volume_get, snd_wl1273_fm_volume_put),
+};
+
+static int wl1273_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 wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+       switch (wl1273->mode) {
+       case WL1273_MODE_BT:
+               snd_pcm_hw_constraint_minmax(substream->runtime,
+                                            SNDRV_PCM_HW_PARAM_RATE,
+                                            8000, 8000);
+               snd_pcm_hw_constraint_minmax(substream->runtime,
+                                            SNDRV_PCM_HW_PARAM_CHANNELS, 1, 1);
+               break;
+       case WL1273_MODE_FM_RX:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       pr_err("Cannot play in RX mode.\n");
+                       return -EINVAL;
+               }
+               break;
+       case WL1273_MODE_FM_TX:
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+                       pr_err("Cannot capture in TX mode.\n");
+                       return -EINVAL;
+               }
+               break;
+       default:
+               return -EINVAL;
+               break;
+       }
+
+       return 0;
+}
+
+static int wl1273_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 wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(rtd->codec);
+       struct wl1273_core *core = wl1273->core;
+       unsigned int rate, width, r;
+
+       if (params_format(params) != SNDRV_PCM_FORMAT_S16_LE) {
+               pr_err("Only SNDRV_PCM_FORMAT_S16_LE supported.\n");
+               return -EINVAL;
+       }
+
+       rate = params_rate(params);
+       width =  hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min;
+
+       if (wl1273->mode == WL1273_MODE_BT) {
+               if (rate != 8000) {
+                       pr_err("Rate %d not supported.\n", params_rate(params));
+                       return -EINVAL;
+               }
+
+               if (params_channels(params) != 1) {
+                       pr_err("Only mono supported.\n");
+                       return -EINVAL;
+               }
+
+               return 0;
+       }
+
+       if (wl1273->mode == WL1273_MODE_FM_TX &&
+           substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               pr_err("Only playback supported with TX.\n");
+               return -EINVAL;
+       }
+
+       if (wl1273->mode == WL1273_MODE_FM_RX  &&
+           substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               pr_err("Only capture supported with RX.\n");
+               return -EINVAL;
+       }
+
+       if (wl1273->mode != WL1273_MODE_FM_RX  &&
+           wl1273->mode != WL1273_MODE_FM_TX) {
+               pr_err("Unexpected mode: %d.\n", wl1273->mode);
+               return -EINVAL;
+       }
+
+       r = snd_wl1273_fm_set_i2s_mode(core, rate, width);
+       if (r)
+               return r;
+
+       wl1273->channels = params_channels(params);
+       r = snd_wl1273_fm_set_channel_number(core, wl1273->channels);
+       if (r)
+               return r;
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops wl1273_dai_ops = {
+       .startup        = wl1273_startup,
+       .hw_params      = wl1273_hw_params,
+};
+
+static struct snd_soc_dai_driver wl1273_dai = {
+       .name = "wl1273-fm",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE},
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE},
+       .ops = &wl1273_dai_ops,
+};
+
+/* Audio interface format for the soc_card driver */
+int wl1273_get_format(struct snd_soc_codec *codec, unsigned int *fmt)
+{
+       struct wl1273_priv *wl1273;
+
+       if (codec == NULL || fmt == NULL)
+               return -EINVAL;
+
+       wl1273 = snd_soc_codec_get_drvdata(codec);
+
+       switch (wl1273->mode) {
+       case WL1273_MODE_FM_RX:
+       case WL1273_MODE_FM_TX:
+               *fmt =  SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBM_CFM;
+
+               break;
+       case WL1273_MODE_BT:
+               *fmt =  SND_SOC_DAIFMT_DSP_A |
+                       SND_SOC_DAIFMT_IB_NF |
+                       SND_SOC_DAIFMT_CBM_CFM;
+
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wl1273_get_format);
+
+static int wl1273_probe(struct snd_soc_codec *codec)
+{
+       struct wl1273_core **core = codec->dev->platform_data;
+       struct wl1273_priv *wl1273;
+       int r;
+
+       dev_dbg(codec->dev, "%s.\n", __func__);
+
+       if (!core) {
+               dev_err(codec->dev, "Platform data is missing.\n");
+               return -EINVAL;
+       }
+
+       wl1273 = kzalloc(sizeof(struct wl1273_priv), GFP_KERNEL);
+       if (wl1273 == NULL) {
+               dev_err(codec->dev, "Cannot allocate memory.\n");
+               return -ENOMEM;
+       }
+
+       wl1273->mode = WL1273_MODE_BT;
+       wl1273->core = *core;
+
+       snd_soc_codec_set_drvdata(codec, wl1273);
+       mutex_init(&codec->mutex);
+
+       r = snd_soc_add_controls(codec, wl1273_controls,
+                                ARRAY_SIZE(wl1273_controls));
+       if (r)
+               kfree(wl1273);
+
+       return r;
+}
+
+static int wl1273_remove(struct snd_soc_codec *codec)
+{
+       struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
+
+       dev_dbg(codec->dev, "%s\n", __func__);
+       kfree(wl1273);
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wl1273 = {
+       .probe = wl1273_probe,
+       .remove = wl1273_remove,
+};
+
+static int __devinit wl1273_platform_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wl1273,
+                                     &wl1273_dai, 1);
+}
+
+static int __devexit wl1273_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+MODULE_ALIAS("platform:wl1273-codec");
+
+static struct platform_driver wl1273_platform_driver = {
+       .driver         = {
+               .name   = "wl1273-codec",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = wl1273_platform_probe,
+       .remove         = __devexit_p(wl1273_platform_remove),
+};
+
+static int __init wl1273_init(void)
+{
+       return platform_driver_register(&wl1273_platform_driver);
+}
+module_init(wl1273_init);
+
+static void __exit wl1273_exit(void)
+{
+       platform_driver_unregister(&wl1273_platform_driver);
+}
+module_exit(wl1273_exit);
+
+MODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@nokia.com>");
+MODULE_DESCRIPTION("ASoC WL1273 codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wl1273.h b/sound/soc/codecs/wl1273.h
new file mode 100644 (file)
index 0000000..14ed027
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * sound/soc/codec/wl1273.h
+ *
+ * ALSA SoC WL1273 codec driver
+ *
+ * Copyright (C) Nokia Corporation
+ * Author: Matti Aaltonen <matti.j.aaltonen@nokia.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.
+ *
+ * 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
+ *
+ */
+
+#ifndef __WL1273_CODEC_H__
+#define __WL1273_CODEC_H__
+
+/* I2S protocol, left channel first, data width 16 bits */
+#define WL1273_PCM_DEF_MODE            0x00
+
+/* Rx */
+#define WL1273_AUDIO_ENABLE_I2S                (1 << 0)
+#define WL1273_AUDIO_ENABLE_ANALOG     (1 << 1)
+
+/* Tx */
+#define WL1273_AUDIO_IO_SET_ANALOG     0
+#define WL1273_AUDIO_IO_SET_I2S                1
+
+#define WL1273_POWER_SET_OFF           0
+#define WL1273_POWER_SET_FM            (1 << 0)
+#define WL1273_POWER_SET_RDS           (1 << 1)
+#define WL1273_POWER_SET_RETENTION     (1 << 4)
+
+#define WL1273_PUPD_SET_OFF            0x00
+#define WL1273_PUPD_SET_ON             0x01
+#define WL1273_PUPD_SET_RETENTION      0x10
+
+/* I2S mode */
+#define WL1273_IS2_WIDTH_32    0x0
+#define WL1273_IS2_WIDTH_40    0x1
+#define WL1273_IS2_WIDTH_22_23 0x2
+#define WL1273_IS2_WIDTH_23_22 0x3
+#define WL1273_IS2_WIDTH_48    0x4
+#define WL1273_IS2_WIDTH_50    0x5
+#define WL1273_IS2_WIDTH_60    0x6
+#define WL1273_IS2_WIDTH_64    0x7
+#define WL1273_IS2_WIDTH_80    0x8
+#define WL1273_IS2_WIDTH_96    0x9
+#define WL1273_IS2_WIDTH_128   0xa
+#define WL1273_IS2_WIDTH       0xf
+
+#define WL1273_IS2_FORMAT_STD  (0x0 << 4)
+#define WL1273_IS2_FORMAT_LEFT (0x1 << 4)
+#define WL1273_IS2_FORMAT_RIGHT        (0x2 << 4)
+#define WL1273_IS2_FORMAT_USER (0x3 << 4)
+
+#define WL1273_IS2_MASTER      (0x0 << 6)
+#define WL1273_IS2_SLAVEW      (0x1 << 6)
+
+#define WL1273_IS2_TRI_AFTER_SENDING   (0x0 << 7)
+#define WL1273_IS2_TRI_ALWAYS_ACTIVE   (0x1 << 7)
+
+#define WL1273_IS2_SDOWS_RR    (0x0 << 8)
+#define WL1273_IS2_SDOWS_RF    (0x1 << 8)
+#define WL1273_IS2_SDOWS_FR    (0x2 << 8)
+#define WL1273_IS2_SDOWS_FF    (0x3 << 8)
+
+#define WL1273_IS2_TRI_OPT     (0x0 << 10)
+#define WL1273_IS2_TRI_ALWAYS  (0x1 << 10)
+
+#define WL1273_IS2_RATE_48K    (0x0 << 12)
+#define WL1273_IS2_RATE_44_1K  (0x1 << 12)
+#define WL1273_IS2_RATE_32K    (0x2 << 12)
+#define WL1273_IS2_RATE_22_05K (0x4 << 12)
+#define WL1273_IS2_RATE_16K    (0x5 << 12)
+#define WL1273_IS2_RATE_12K    (0x8 << 12)
+#define WL1273_IS2_RATE_11_025 (0x9 << 12)
+#define WL1273_IS2_RATE_8K     (0xa << 12)
+#define WL1273_IS2_RATE                (0xf << 12)
+
+#define WL1273_I2S_DEF_MODE    (WL1273_IS2_WIDTH_32 | \
+                                WL1273_IS2_FORMAT_STD | \
+                                WL1273_IS2_MASTER | \
+                                WL1273_IS2_TRI_AFTER_SENDING | \
+                                WL1273_IS2_SDOWS_RR | \
+                                WL1273_IS2_TRI_OPT | \
+                                WL1273_IS2_RATE_48K)
+
+int wl1273_get_format(struct snd_soc_codec *codec, unsigned int *fmt);
+
+#endif /* End of __WL1273_CODEC_H__ */
index c18e261c3c7fb089cefc032dd4e67e74675570b5..0b6f056f73cc53a80ab0fedc5733641573bc4974 100644 (file)
@@ -16,9 +16,6 @@ struct wm2000_setup_data {
 
 extern int wm2000_add_controls(struct snd_soc_codec *codec);
 
-extern struct snd_soc_dai wm2000_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm2000;
-
 #define WM2000_REG_SYS_START       0x8000
 #define WM2000_REG_SPEECH_CLARITY   0x8fef
 #define WM2000_REG_SYS_WATCHDOG     0x8ff6
index 0221ca79b3ae59831a15499e263b7ca9cbf1118b..f4f1fba38eb9458176f5bda41cc93d12c87722eb 100644 (file)
@@ -1321,20 +1321,14 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-static int wm8350_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8350_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8350_resume(struct platform_device *pdev)
+static int wm8350_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
@@ -1489,24 +1483,74 @@ int wm8350_mic_jack_detect(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(wm8350_mic_jack_detect);
 
-static struct snd_soc_codec *wm8350_codec;
+#define WM8350_RATES (SNDRV_PCM_RATE_8000_96000)
+
+#define WM8350_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                       SNDRV_PCM_FMTBIT_S20_3LE |\
+                       SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops wm8350_dai_ops = {
+        .hw_params     = wm8350_pcm_hw_params,
+        .digital_mute  = wm8350_mute,
+        .trigger       = wm8350_pcm_trigger,
+        .set_fmt       = wm8350_set_dai_fmt,
+        .set_sysclk    = wm8350_set_dai_sysclk,
+        .set_pll       = wm8350_set_fll,
+        .set_clkdiv    = wm8350_set_clkdiv,
+};
+
+static struct snd_soc_dai_driver wm8350_dai = {
+       .name = "wm8350-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = WM8350_RATES,
+               .formats = WM8350_FORMATS,
+       },
+       .capture = {
+                .stream_name = "Capture",
+                .channels_min = 1,
+                .channels_max = 2,
+                .rates = WM8350_RATES,
+                .formats = WM8350_FORMATS,
+        },
+       .ops = &wm8350_dai_ops,
+};
 
-static int wm8350_probe(struct platform_device *pdev)
+static  int wm8350_codec_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       struct wm8350 *wm8350;
+       struct wm8350 *wm8350 = dev_get_platdata(codec->dev);
        struct wm8350_data *priv;
-       int ret;
        struct wm8350_output *out1;
        struct wm8350_output *out2;
+       int ret, i;
 
-       BUG_ON(!wm8350_codec);
+       if (wm8350->codec.platform_data == NULL) {
+               dev_err(codec->dev, "No audio platform data supplied\n");
+               return -EINVAL;
+       }
+
+       priv = kzalloc(sizeof(struct wm8350_data), GFP_KERNEL);
+       if (priv == NULL)
+               return -ENOMEM;
+       snd_soc_codec_set_drvdata(codec, priv);
+
+       for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+               priv->supplies[i].supply = supply_names[i];
+
+       ret = regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies),
+                                priv->supplies);
+       if (ret != 0)
+               goto err_priv;
+
+       wm8350->codec.codec = codec;
+       codec->control_data = wm8350;
 
-       socdev->card->codec = wm8350_codec;
-       codec = socdev->card->codec;
-       wm8350 = codec->control_data;
-       priv = snd_soc_codec_get_drvdata(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);
 
        /* Enable the codec */
        wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
@@ -1557,11 +1601,6 @@ static int wm8350_probe(struct platform_device *pdev)
        wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD,
                            wm8350_mic_handler, 0, "Microphone detect", priv);
 
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to create pcms\n");
-               return ret;
-       }
 
        snd_soc_add_controls(codec, wm8350_snd_controls,
                                ARRAY_SIZE(wm8350_snd_controls));
@@ -1570,14 +1609,16 @@ static int wm8350_probe(struct platform_device *pdev)
        wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
+
+err_priv:
+       kfree(priv);
+       return ret;
 }
 
-static int wm8350_remove(struct platform_device *pdev)
+static int  wm8350_codec_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-       struct wm8350 *wm8350 = codec->control_data;
        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,
@@ -1607,134 +1648,30 @@ static int wm8350_remove(struct platform_device *pdev)
 
        wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
 
+       regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
+       kfree(priv);
        return 0;
 }
 
-#define WM8350_RATES (SNDRV_PCM_RATE_8000_96000)
-
-#define WM8350_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
-                       SNDRV_PCM_FMTBIT_S20_3LE |\
-                       SNDRV_PCM_FMTBIT_S24_LE)
-
-static struct snd_soc_dai_ops wm8350_dai_ops = {
-        .hw_params     = wm8350_pcm_hw_params,
-        .digital_mute  = wm8350_mute,
-        .trigger       = wm8350_pcm_trigger,
-        .set_fmt       = wm8350_set_dai_fmt,
-        .set_sysclk    = wm8350_set_dai_sysclk,
-        .set_pll       = wm8350_set_fll,
-        .set_clkdiv    = wm8350_set_clkdiv,
-};
-
-struct snd_soc_dai wm8350_dai = {
-       .name = "WM8350",
-       .playback = {
-               .stream_name = "Playback",
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = WM8350_RATES,
-               .formats = WM8350_FORMATS,
-       },
-       .capture = {
-                .stream_name = "Capture",
-                .channels_min = 1,
-                .channels_max = 2,
-                .rates = WM8350_RATES,
-                .formats = WM8350_FORMATS,
-        },
-       .ops = &wm8350_dai_ops,
-};
-EXPORT_SYMBOL_GPL(wm8350_dai);
-
-struct snd_soc_codec_device soc_codec_dev_wm8350 = {
-       .probe =        wm8350_probe,
-       .remove =       wm8350_remove,
+static struct snd_soc_codec_driver soc_codec_dev_wm8350 = {
+       .probe =        wm8350_codec_probe,
+       .remove =       wm8350_codec_remove,
        .suspend =      wm8350_suspend,
        .resume =       wm8350_resume,
+       .read = wm8350_codec_read,
+       .write = wm8350_codec_write,
+       .set_bias_level = wm8350_set_bias_level,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8350);
 
-static __devinit int wm8350_codec_probe(struct platform_device *pdev)
+static int __devinit wm8350_probe(struct platform_device *pdev)
 {
-       struct wm8350 *wm8350 = platform_get_drvdata(pdev);
-       struct wm8350_data *priv;
-       struct snd_soc_codec *codec;
-       int ret, i;
-
-       if (wm8350->codec.platform_data == NULL) {
-               dev_err(&pdev->dev, "No audio platform data supplied\n");
-               return -EINVAL;
-       }
-
-       priv = kzalloc(sizeof(struct wm8350_data), GFP_KERNEL);
-       if (priv == NULL)
-               return -ENOMEM;
-
-       for (i = 0; i < ARRAY_SIZE(supply_names); i++)
-               priv->supplies[i].supply = supply_names[i];
-
-       ret = regulator_bulk_get(wm8350->dev, ARRAY_SIZE(priv->supplies),
-                                priv->supplies);
-       if (ret != 0)
-               goto err_priv;
-
-       codec = &priv->codec;
-       wm8350->codec.codec = codec;
-
-       wm8350_dai.dev = &pdev->dev;
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-       codec->dev = &pdev->dev;
-       codec->name = "WM8350";
-       codec->owner = THIS_MODULE;
-       codec->read = wm8350_codec_read;
-       codec->write = wm8350_codec_write;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8350_set_bias_level;
-       codec->dai = &wm8350_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8350_MAX_REGISTER;
-       snd_soc_codec_set_drvdata(codec, priv);
-       codec->control_data = wm8350;
-
-       /* 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);
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0)
-               goto err_supply;
-
-       wm8350_codec = codec;
-
-       ret = snd_soc_register_dai(&wm8350_dai);
-       if (ret != 0)
-               goto err_codec;
-       return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err_supply:
-       regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
-err_priv:
-       kfree(priv);
-       wm8350_codec = NULL;
-       return ret;
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8350,
+                       &wm8350_dai, 1);
 }
 
-static int __devexit wm8350_codec_remove(struct platform_device *pdev)
+static int __devexit wm8350_remove(struct platform_device *pdev)
 {
-       struct wm8350 *wm8350 = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = wm8350->codec.codec;
-       struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
-
-       snd_soc_unregister_dai(&wm8350_dai);
-       snd_soc_unregister_codec(codec);
-       regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies);
-       kfree(priv);
-       wm8350_codec = NULL;
+       snd_soc_unregister_codec(&pdev->dev);
        return 0;
 }
 
@@ -1743,8 +1680,8 @@ static struct platform_driver wm8350_codec_driver = {
                   .name = "wm8350-codec",
                   .owner = THIS_MODULE,
                   },
-       .probe = wm8350_codec_probe,
-       .remove = __devexit_p(wm8350_codec_remove),
+       .probe = wm8350_probe,
+       .remove = __devexit_p(wm8350_remove),
 };
 
 static __init int wm8350_init(void)
index 9ed0467c71db70b42db50e563b10abbf4485348e..74108eb82938ca29b3caec1156bc8dd22e4931a1 100644 (file)
@@ -15,9 +15,6 @@
 #include <sound/soc.h>
 #include <linux/mfd/wm8350/audio.h>
 
-extern struct snd_soc_dai wm8350_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8350;
-
 enum wm8350_jack {
        WM8350_JDL = 1,
        WM8350_JDR = 2,
index 8f294066b0ed3e4edfc382b992e943a6157e1af2..850299786e02d0d87f77e673bb093fffb68bcbdc 100644 (file)
@@ -65,7 +65,7 @@ static struct regulator_bulk_data power[] = {
 
 /* codec private data */
 struct wm8400_priv {
-       struct snd_soc_codec codec;
+       struct snd_soc_codec *codec;
        struct wm8400 *wm8400;
        u16 fake_register;
        unsigned int sysclk;
@@ -1163,8 +1163,7 @@ static int wm8400_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u16 audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1);
 
        audio1 &= ~WM8400_AIF_WL_MASK;
@@ -1332,10 +1331,9 @@ static struct snd_soc_dai_ops wm8400_dai_ops = {
  * 1. ADC/DAC on Primary Interface
  * 2. ADC on Primary Interface/DAC on secondary
  */
-struct snd_soc_dai wm8400_dai = {
+static struct snd_soc_dai_driver wm8400_dai = {
 /* ADC/DAC on primary */
-       .name = "WM8400 ADC/DAC Primary",
-       .id = 1,
+       .name = "wm8400-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -1352,147 +1350,53 @@ struct snd_soc_dai wm8400_dai = {
        },
        .ops = &wm8400_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8400_dai);
 
-static int wm8400_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8400_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int wm8400_resume(struct platform_device *pdev)
+static int wm8400_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
 }
 
-static struct snd_soc_codec *wm8400_codec;
-
-static int wm8400_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret;
-
-       if (!wm8400_codec) {
-               dev_err(&pdev->dev, "wm8400 not yet discovered\n");
-               return -ENODEV;
-       }
-       codec = wm8400_codec;
-
-       socdev->card->codec = codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to create pcms\n");
-               goto pcm_err;
-       }
-
-       wm8400_add_controls(codec);
-       wm8400_add_widgets(codec);
-
-pcm_err:
-       return ret;
-}
-
-/* power down chip */
-static int wm8400_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8400 = {
-       .probe =        wm8400_probe,
-       .remove =       wm8400_remove,
-       .suspend =      wm8400_suspend,
-       .resume =       wm8400_resume,
-};
-
 static void wm8400_probe_deferred(struct work_struct *work)
 {
        struct wm8400_priv *priv = container_of(work, struct wm8400_priv,
                                                work);
-       struct snd_soc_codec *codec = &priv->codec;
-       int ret;
+       struct snd_soc_codec *codec = priv->codec;
 
        /* charge output caps */
        wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       /* We're done, tell the subsystem. */
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(priv->wm8400->dev,
-                       "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dai(&wm8400_dai);
-       if (ret != 0) {
-               dev_err(priv->wm8400->dev,
-                       "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
-
-       return;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF);
 }
 
-static int wm8400_codec_probe(struct platform_device *dev)
+static int wm8400_codec_probe(struct snd_soc_codec *codec)
 {
+       struct wm8400 *wm8400 = dev_get_platdata(codec->dev);
        struct wm8400_priv *priv;
        int ret;
        u16 reg;
-       struct snd_soc_codec *codec;
 
        priv = kzalloc(sizeof(struct wm8400_priv), GFP_KERNEL);
        if (priv == NULL)
                return -ENOMEM;
 
-       codec = &priv->codec;
        snd_soc_codec_set_drvdata(codec, priv);
-       codec->control_data = dev_get_drvdata(&dev->dev);
-       priv->wm8400 = dev_get_drvdata(&dev->dev);
+       codec->control_data = priv->wm8400 = wm8400;
+       priv->codec = codec;
 
-       ret = regulator_bulk_get(priv->wm8400->dev,
+       ret = regulator_bulk_get(wm8400->dev,
                                 ARRAY_SIZE(power), &power[0]);
        if (ret != 0) {
-               dev_err(&dev->dev, "Failed to get regulators: %d\n", ret);
+               dev_err(codec->dev, "Failed to get regulators: %d\n", ret);
                goto err;
        }
 
-       codec->dev = &dev->dev;
-       wm8400_dai.dev = &dev->dev;
-
-       codec->name = "WM8400";
-       codec->owner = THIS_MODULE;
-       codec->read = wm8400_read;
-       codec->write = wm8400_write;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8400_set_bias_level;
-       codec->dai = &wm8400_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8400_REGISTER_COUNT;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
        INIT_WORK(&priv->work, wm8400_probe_deferred);
 
        wm8400_codec_reset(codec);
@@ -1511,65 +1415,78 @@ static int wm8400_codec_probe(struct platform_device *dev)
        wm8400_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
        wm8400_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
 
-       wm8400_codec = codec;
-
        if (!schedule_work(&priv->work)) {
                ret = -EINVAL;
                goto err_regulator;
        }
-
+       wm8400_add_controls(codec);
+       wm8400_add_widgets(codec);
        return 0;
 
 err_regulator:
-       wm8400_codec = NULL;
        regulator_bulk_free(ARRAY_SIZE(power), power);
 err:
        kfree(priv);
        return ret;
 }
 
-static int __exit wm8400_codec_remove(struct platform_device *dev)
+static int  wm8400_codec_remove(struct snd_soc_codec *codec)
 {
-       struct wm8400_priv *priv = snd_soc_codec_get_drvdata(wm8400_codec);
+       struct wm8400_priv *priv = snd_soc_codec_get_drvdata(codec);
        u16 reg;
 
-       snd_soc_unregister_dai(&wm8400_dai);
-       snd_soc_unregister_codec(wm8400_codec);
-
-       reg = wm8400_read(wm8400_codec, WM8400_POWER_MANAGEMENT_1);
-       wm8400_write(wm8400_codec, WM8400_POWER_MANAGEMENT_1,
+       reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
+       wm8400_write(codec, WM8400_POWER_MANAGEMENT_1,
                     reg & (~WM8400_CODEC_ENA));
 
        regulator_bulk_free(ARRAY_SIZE(power), power);
        kfree(priv);
 
-       wm8400_codec = NULL;
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8400 = {
+       .probe =        wm8400_codec_probe,
+       .remove =       wm8400_codec_remove,
+       .suspend =      wm8400_suspend,
+       .resume =       wm8400_resume,
+       .read = wm8400_read,
+       .write = wm8400_write,
+       .set_bias_level = wm8400_set_bias_level,
+};
+
+static int __devinit wm8400_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8400,
+                       &wm8400_dai, 1);
+}
 
+static int __devexit wm8400_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
        return 0;
 }
 
 static struct platform_driver wm8400_codec_driver = {
        .driver = {
-               .name = "wm8400-codec",
-               .owner = THIS_MODULE,
-       },
-       .probe = wm8400_codec_probe,
-       .remove = __exit_p(wm8400_codec_remove),
+                  .name = "wm8400-codec",
+                  .owner = THIS_MODULE,
+                  },
+       .probe = wm8400_probe,
+       .remove = __devexit_p(wm8400_remove),
 };
 
-static int __init wm8400_codec_init(void)
+static __init int wm8400_init(void)
 {
        return platform_driver_register(&wm8400_codec_driver);
 }
-module_init(wm8400_codec_init);
+module_init(wm8400_init);
 
-static void __exit wm8400_codec_exit(void)
+static __exit void wm8400_exit(void)
 {
        platform_driver_unregister(&wm8400_codec_driver);
 }
-module_exit(wm8400_codec_exit);
-
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8400);
+module_exit(wm8400_exit);
 
 MODULE_DESCRIPTION("ASoC WM8400 driver");
 MODULE_AUTHOR("Mark Brown");
index 79c5934d4776f2b3cda9907e7ca5c7d2d3a383fc..521adb19387087048e3d86e299d3f4b5682ba0d6 100644 (file)
@@ -56,7 +56,4 @@
 #define WM8400_BCLK_DIV_44                      (0xE << 1)
 #define WM8400_BCLK_DIV_48                      (0xF << 1)
 
-extern struct snd_soc_dai wm8400_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8400;
-
 #endif
index 0f7bcb61071ac6a12cd9fc4b82ea2350d5b469c8..8f107095760e2206f875e0be53b88001395787bb 100644 (file)
 
 #include "wm8510.h"
 
-#define WM8510_VERSION "0.6"
-
-struct snd_soc_codec_device soc_codec_dev_wm8510;
-
 /*
  * wm8510 register cache
  * We can't read the WM8510 register space when we are
@@ -61,6 +57,11 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = {
 
 #define wm8510_reset(c)        snd_soc_write(c, WM8510_RESET, 0)
 
+/* codec private data */
+struct wm8510_priv {
+       enum snd_soc_control_type control_type;
+};
+
 static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" };
 static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
 static const char *wm8510_alc[] = { "ALC", "Limiter" };
@@ -403,8 +404,7 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u16 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f;
        u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1;
 
@@ -514,8 +514,8 @@ static struct snd_soc_dai_ops wm8510_dai_ops = {
        .set_pll        = wm8510_set_dai_pll,
 };
 
-struct snd_soc_dai wm8510_dai = {
-       .name = "WM8510 HiFi",
+static struct snd_soc_dai_driver wm8510_dai = {
+       .name = "wm8510-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -531,21 +531,15 @@ struct snd_soc_dai wm8510_dai = {
        .ops = &wm8510_dai_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(wm8510_dai);
 
-static int wm8510_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8510_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8510_resume(struct platform_device *pdev)
+static int wm8510_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -561,256 +555,158 @@ static int wm8510_resume(struct platform_device *pdev)
        return 0;
 }
 
-/*
- * initialise the WM8510 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int wm8510_init(struct snd_soc_device *socdev,
-                      enum snd_soc_control_type control)
+static int wm8510_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int ret = 0;
-
-       codec->name = "WM8510";
-       codec->owner = THIS_MODULE;
-       codec->set_bias_level = wm8510_set_bias_level;
-       codec->dai = &wm8510_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(wm8510_reg);
-       codec->reg_cache = kmemdup(wm8510_reg, sizeof(wm8510_reg), GFP_KERNEL);
-
-       if (codec->reg_cache == NULL)
-               return -ENOMEM;
+       struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec);
+       int ret;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9,  wm8510->control_type);
        if (ret < 0) {
-               printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n",
-                      ret);
-               goto err;
+               printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
        wm8510_reset(codec);
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8510: failed to create pcms\n");
-               goto err;
-       }
-
        /* power on device */
-       codec->bias_level = SND_SOC_BIAS_OFF;
        wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        snd_soc_add_controls(codec, wm8510_snd_controls,
                                ARRAY_SIZE(wm8510_snd_controls));
        wm8510_add_widgets(codec);
 
        return ret;
-
-err:
-       kfree(codec->reg_cache);
-       return ret;
 }
 
-static struct snd_soc_device *wm8510_socdev;
+/* power down chip */
+static int wm8510_remove(struct snd_soc_codec *codec)
+{
+       struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec);
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       kfree(wm8510);
+       return 0;
+}
 
-/*
- * WM8510 2 wire address is 0x1a
- */
+static struct snd_soc_codec_driver soc_codec_dev_wm8510 = {
+       .probe =        wm8510_probe,
+       .remove =       wm8510_remove,
+       .suspend =      wm8510_suspend,
+       .resume =       wm8510_resume,
+       .set_bias_level = wm8510_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8510_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default =wm8510_reg,
+};
 
-static int wm8510_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8510_spi_probe(struct spi_device *spi)
 {
-       struct snd_soc_device *socdev = wm8510_socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct wm8510_priv *wm8510;
        int ret;
 
-       i2c_set_clientdata(i2c, codec);
-       codec->control_data = i2c;
+       wm8510 = kzalloc(sizeof(struct wm8510_priv), GFP_KERNEL);
+       if (wm8510 == NULL)
+               return -ENOMEM;
 
-       ret = wm8510_init(socdev, SND_SOC_I2C);
-       if (ret < 0)
-               pr_err("failed to initialise WM8510\n");
+       wm8510->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8510);
 
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_wm8510, &wm8510_dai, 1);
+       if (ret < 0)
+               kfree(wm8510);
        return ret;
 }
 
-static int wm8510_i2c_remove(struct i2c_client *client)
+static int __devexit wm8510_spi_remove(struct spi_device *spi)
 {
-       struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       kfree(codec->reg_cache);
+       snd_soc_unregister_codec(&spi->dev);
        return 0;
 }
 
-static const struct i2c_device_id wm8510_i2c_id[] = {
-       { "wm8510", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id);
-
-static struct i2c_driver wm8510_i2c_driver = {
+static struct spi_driver wm8510_spi_driver = {
        .driver = {
-               .name = "WM8510 I2C Codec",
-               .owner = THIS_MODULE,
+               .name   = "wm8510",
+               .owner  = THIS_MODULE,
        },
-       .probe =    wm8510_i2c_probe,
-       .remove =   wm8510_i2c_remove,
-       .id_table = wm8510_i2c_id,
+       .probe          = wm8510_spi_probe,
+       .remove         = __devexit_p(wm8510_spi_remove),
 };
+#endif /* CONFIG_SPI_MASTER */
 
-static int wm8510_add_i2c_device(struct platform_device *pdev,
-                                const struct wm8510_setup_data *setup)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8510_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
-       struct i2c_board_info info;
-       struct i2c_adapter *adapter;
-       struct i2c_client *client;
+       struct wm8510_priv *wm8510;
        int ret;
 
-       ret = i2c_add_driver(&wm8510_i2c_driver);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "can't add i2c driver\n");
-               return ret;
-       }
-
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       info.addr = setup->i2c_address;
-       strlcpy(info.type, "wm8510", I2C_NAME_SIZE);
-
-       adapter = i2c_get_adapter(setup->i2c_bus);
-       if (!adapter) {
-               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
-                       setup->i2c_bus);
-               goto err_driver;
-       }
-
-       client = i2c_new_device(adapter, &info);
-       i2c_put_adapter(adapter);
-       if (!client) {
-               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
-                       (unsigned int)info.addr);
-               goto err_driver;
-       }
-
-       return 0;
-
-err_driver:
-       i2c_del_driver(&wm8510_i2c_driver);
-       return -ENODEV;
-}
-#endif
-
-#if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8510_spi_probe(struct spi_device *spi)
-{
-       struct snd_soc_device *socdev = wm8510_socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int ret;
+       wm8510 = kzalloc(sizeof(struct wm8510_priv), GFP_KERNEL);
+       if (wm8510 == NULL)
+               return -ENOMEM;
 
-       codec->control_data = spi;
+       i2c_set_clientdata(i2c, wm8510);
+       wm8510->control_type = SND_SOC_I2C;
 
-       ret = wm8510_init(socdev, SND_SOC_SPI);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8510, &wm8510_dai, 1);
        if (ret < 0)
-               dev_err(&spi->dev, "failed to initialise WM8510\n");
-
+               kfree(wm8510);
        return ret;
 }
 
-static int __devexit wm8510_spi_remove(struct spi_device *spi)
+static __devexit int wm8510_i2c_remove(struct i2c_client *client)
 {
+       snd_soc_unregister_codec(&client->dev);
        return 0;
 }
 
-static struct spi_driver wm8510_spi_driver = {
+static const struct i2c_device_id wm8510_i2c_id[] = {
+       { "wm8510", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id);
+
+static struct i2c_driver wm8510_i2c_driver = {
        .driver = {
-               .name   = "wm8510",
-               .bus    = &spi_bus_type,
-               .owner  = THIS_MODULE,
+               .name = "wm8510-codec",
+               .owner = THIS_MODULE,
        },
-       .probe          = wm8510_spi_probe,
-       .remove         = __devexit_p(wm8510_spi_remove),
+       .probe =    wm8510_i2c_probe,
+       .remove =   __devexit_p(wm8510_i2c_remove),
+       .id_table = wm8510_i2c_id,
 };
-#endif /* CONFIG_SPI_MASTER */
+#endif
 
-static int wm8510_probe(struct platform_device *pdev)
+static int __init wm8510_modinit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct wm8510_setup_data *setup;
-       struct snd_soc_codec *codec;
        int ret = 0;
-
-       pr_info("WM8510 Audio Codec %s", WM8510_VERSION);
-
-       setup = socdev->codec_data;
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
-
-       socdev->card->codec = codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       wm8510_socdev = socdev;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       if (setup->i2c_address) {
-               ret = wm8510_add_i2c_device(pdev, setup);
+       ret = i2c_add_driver(&wm8510_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8510 I2C driver: %d\n",
+                      ret);
        }
 #endif
 #if defined(CONFIG_SPI_MASTER)
-       if (setup->spi) {
-               ret = spi_register_driver(&wm8510_spi_driver);
-               if (ret != 0)
-                       printk(KERN_ERR "can't add spi driver");
+       ret = spi_register_driver(&wm8510_spi_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8510 SPI driver: %d\n",
+                      ret);
        }
 #endif
-
-       if (ret != 0)
-               kfree(codec);
        return ret;
 }
+module_init(wm8510_modinit);
 
-/* power down chip */
-static int wm8510_remove(struct platform_device *pdev)
+static void __exit wm8510_exit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec->control_data)
-               wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       i2c_unregister_device(codec->control_data);
        i2c_del_driver(&wm8510_i2c_driver);
 #endif
 #if defined(CONFIG_SPI_MASTER)
        spi_unregister_driver(&wm8510_spi_driver);
 #endif
-       kfree(codec);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8510 = {
-       .probe =        wm8510_probe,
-       .remove =       wm8510_remove,
-       .suspend =      wm8510_suspend,
-       .resume =       wm8510_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510);
-
-static int __init wm8510_modinit(void)
-{
-       return snd_soc_register_dai(&wm8510_dai);
-}
-module_init(wm8510_modinit);
-
-static void __exit wm8510_exit(void)
-{
-       snd_soc_unregister_dai(&wm8510_dai);
 }
 module_exit(wm8510_exit);
 
index bdefcf5c69ff2a9ed57e160843710467d19d33d0..b3e26ed9f2d0f40b234977cf3a4d90f64eeafed5 100644 (file)
@@ -99,7 +99,4 @@ struct wm8510_setup_data {
        unsigned short i2c_address;
 };
 
-extern struct snd_soc_dai wm8510_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8510;
-
 #endif
index 0ad039b4adf5fd0b12e587a115f91196e921b331..712ef7c76f90bbde579229ea85716dd14f7acb10 100644 (file)
@@ -30,9 +30,6 @@
 
 #include "wm8523.h"
 
-static struct snd_soc_codec *wm8523_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8523;
-
 #define WM8523_NUM_SUPPLIES 2
 static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = {
        "AVDD",
@@ -43,7 +40,7 @@ static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = {
 
 /* codec private data */
 struct wm8523_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
        u16 reg_cache[WM8523_REGISTER_COUNT];
        struct regulator_bulk_data supplies[WM8523_NUM_SUPPLIES];
        unsigned int sysclk;
@@ -162,8 +159,7 @@ static int wm8523_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
        int i;
        u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1);
@@ -387,8 +383,8 @@ static struct snd_soc_dai_ops wm8523_dai_ops = {
        .set_fmt        = wm8523_set_dai_fmt,
 };
 
-struct snd_soc_dai wm8523_dai = {
-       .name = "WM8523",
+static struct snd_soc_dai_driver wm8523_dai = {
+       .name = "wm8523-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,  /* Mono modes not yet supported */
@@ -398,25 +394,17 @@ struct snd_soc_dai wm8523_dai = {
        },
        .ops = &wm8523_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8523_dai);
 
 #ifdef CONFIG_PM
-static int wm8523_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8523_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8523_resume(struct platform_device *pdev)
+static int wm8523_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
        return 0;
 }
 #else
@@ -424,93 +412,20 @@ static int wm8523_resume(struct platform_device *pdev)
 #define wm8523_resume NULL
 #endif
 
-static int wm8523_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (wm8523_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8523_codec;
-       codec = wm8523_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       snd_soc_add_controls(codec, wm8523_snd_controls,
-                            ARRAY_SIZE(wm8523_snd_controls));
-       wm8523_add_widgets(codec);
-
-       return ret;
-
-pcm_err:
-       return ret;
-}
-
-static int wm8523_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8523 = {
-       .probe =        wm8523_probe,
-       .remove =       wm8523_remove,
-       .suspend =      wm8523_suspend,
-       .resume =       wm8523_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8523);
-
-static int wm8523_register(struct wm8523_priv *wm8523,
-                          enum snd_soc_control_type control)
+static int wm8523_probe(struct snd_soc_codec *codec)
 {
-       int ret;
-       struct snd_soc_codec *codec = &wm8523->codec;
-       int i;
-
-       if (wm8523_codec) {
-               dev_err(codec->dev, "Another WM8523 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8523);
-       codec->name = "WM8523";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8523_set_bias_level;
-       codec->dai = &wm8523_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8523_REGISTER_COUNT;
-       codec->reg_cache = &wm8523->reg_cache;
-       codec->volatile_register = wm8523_volatile_register;
+       struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
+       int ret, i;
 
+       codec->hw_write = (hw_write_t)i2c_master_send;
        wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0];
        wm8523->rate_constraint.count =
                ARRAY_SIZE(wm8523->rate_constraint_list);
 
-       memcpy(codec->reg_cache, wm8523_reg, sizeof(wm8523_reg));
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8523->control_type);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++)
@@ -520,7 +435,7 @@ static int wm8523_register(struct wm8523_priv *wm8523,
                                 wm8523->supplies);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies),
@@ -555,8 +470,6 @@ static int wm8523_register(struct wm8523_priv *wm8523,
                goto err_enable;
        }
 
-       wm8523_dai.dev = codec->dev;
-
        /* Change some default settings - latch VU and enable ZC */
        wm8523->reg_cache[WM8523_DAC_GAINR] |= WM8523_DACR_VU;
        wm8523->reg_cache[WM8523_DAC_CTRL3] |= WM8523_ZC;
@@ -566,69 +479,67 @@ static int wm8523_register(struct wm8523_priv *wm8523,
        /* Bias level configuration will have done an extra enable */
        regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
 
-       wm8523_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err_enable;
-       }
-
-       ret = snd_soc_register_dai(&wm8523_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
+       snd_soc_add_controls(codec, wm8523_snd_controls,
+                            ARRAY_SIZE(wm8523_snd_controls));
+       wm8523_add_widgets(codec);
 
        return 0;
 
-err_codec:
-       snd_soc_unregister_codec(codec);
 err_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
 err_get:
        regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
-err:
-       kfree(wm8523);
+
        return ret;
 }
 
-static void wm8523_unregister(struct wm8523_priv *wm8523)
+static int wm8523_remove(struct snd_soc_codec *codec)
 {
-       wm8523_set_bias_level(&wm8523->codec, SND_SOC_BIAS_OFF);
+       struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
+
+       wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF);
        regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
-       snd_soc_unregister_dai(&wm8523_dai);
-       snd_soc_unregister_codec(&wm8523->codec);
-       kfree(wm8523);
-       wm8523_codec = NULL;
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_wm8523 = {
+       .probe =        wm8523_probe,
+       .remove =       wm8523_remove,
+       .suspend =      wm8523_suspend,
+       .resume =       wm8523_resume,
+       .set_bias_level = wm8523_set_bias_level,
+       .reg_cache_size = WM8523_REGISTER_COUNT,
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8523_reg,
+       .volatile_register = wm8523_volatile_register,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8523_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8523_priv *wm8523;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8523 = kzalloc(sizeof(struct wm8523_priv), GFP_KERNEL);
        if (wm8523 == NULL)
                return -ENOMEM;
 
-       codec = &wm8523->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
        i2c_set_clientdata(i2c, wm8523);
-       codec->control_data = i2c;
+       wm8523->control_type = SND_SOC_I2C;
 
-       codec->dev = &i2c->dev;
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8523, &wm8523_dai, 1);
+       if (ret < 0)
+               kfree(wm8523);
+       return ret;
 
-       return wm8523_register(wm8523, SND_SOC_I2C);
 }
 
 static __devexit int wm8523_i2c_remove(struct i2c_client *client)
 {
-       struct wm8523_priv *wm8523 = i2c_get_clientdata(client);
-       wm8523_unregister(wm8523);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -640,7 +551,7 @@ MODULE_DEVICE_TABLE(i2c, wm8523_i2c_id);
 
 static struct i2c_driver wm8523_i2c_driver = {
        .driver = {
-               .name = "WM8523",
+               .name = "wm8523-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8523_i2c_probe,
index 1aa9ce3e135775ce03cce3e4d57b75e54b98167d..4d5b1eb8f2fc806d20552698cce5df6bf43b1da0 100644 (file)
 #define WM8523_ZD_COUNT_SHIFT                        0  /* ZD_COUNT - [1:0] */
 #define WM8523_ZD_COUNT_WIDTH                        2  /* ZD_COUNT - [1:0] */
 
-extern struct snd_soc_dai wm8523_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8523;
-
 #endif
index 72deeabef4fe4cf7b4fbb822054cc5e99ce1708e..a2e0ed59b3769f0b7d73024a6e4740338b1ccb81 100644 (file)
@@ -94,6 +94,8 @@
 
 #define WM8580_MAX_REGISTER                  0x35
 
+#define WM8580_DACOSR 0x40
+
 /* PLLB4 (register 7h) */
 #define WM8580_PLLB4_MCLKOUTSRC_MASK   0x60
 #define WM8580_PLLB4_MCLKOUTSRC_PLLA   0x20
 
 /* AIF control 1 (registers 9h-bh) */
 #define WM8580_AIF_RATE_MASK       0x7
-#define WM8580_AIF_RATE_128        0x0
-#define WM8580_AIF_RATE_192        0x1
-#define WM8580_AIF_RATE_256        0x2
-#define WM8580_AIF_RATE_384        0x3
-#define WM8580_AIF_RATE_512        0x4
-#define WM8580_AIF_RATE_768        0x5
-#define WM8580_AIF_RATE_1152       0x6
-
 #define WM8580_AIF_BCLKSEL_MASK   0x18
-#define WM8580_AIF_BCLKSEL_64     0x00
-#define WM8580_AIF_BCLKSEL_128    0x08
-#define WM8580_AIF_BCLKSEL_256    0x10
-#define WM8580_AIF_BCLKSEL_SYSCLK 0x18
 
 #define WM8580_AIF_MS             0x20
 
@@ -199,11 +189,12 @@ static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = {
 
 /* codec private data */
 struct wm8580_priv {
-       struct snd_soc_codec codec;
+       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];
 };
 
 static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
@@ -273,8 +264,8 @@ SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 1),
 SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 1),
 SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 1),
 
-SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0),
-SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0),
+SOC_DOUBLE("Capture Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 1),
+SOC_SINGLE("Capture High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0),
 };
 
 static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = {
@@ -476,6 +467,10 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
        return 0;
 }
 
+static const int wm8580_sysclk_ratios[] = {
+       128, 192, 256, 384, 512, 768, 1152,
+};
+
 /*
  * Set PCM DAI bit size and sample rate.
  */
@@ -484,29 +479,68 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
-       u16 paifb = snd_soc_read(codec, WM8580_PAIF3 + dai->id);
+       struct snd_soc_codec *codec = rtd->codec;
+       struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+       u16 paifa = 0;
+       u16 paifb = 0;
+       int i, ratio, osr;
 
-       paifb &= ~WM8580_AIF_LENGTH_MASK;
        /* bit size */
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
+               paifa |= 0x8;
                break;
        case SNDRV_PCM_FORMAT_S20_3LE:
+               paifa |= 0x10;
                paifb |= WM8580_AIF_LENGTH_20;
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
+               paifa |= 0x10;
                paifb |= WM8580_AIF_LENGTH_24;
                break;
        case SNDRV_PCM_FORMAT_S32_LE:
+               paifa |= 0x10;
                paifb |= WM8580_AIF_LENGTH_24;
                break;
        default:
                return -EINVAL;
        }
 
-       snd_soc_write(codec, WM8580_PAIF3 + dai->id, paifb);
+       /* Look up the SYSCLK ratio; accept only exact matches */
+       ratio = wm8580->sysclk[dai->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));
+               return -EINVAL;
+       }
+       paifa |= i;
+       dev_dbg(codec->dev, "Running at %dfs with %dHz clock\n",
+               wm8580_sysclk_ratios[i], wm8580->sysclk[dai->driver->id]);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               switch (ratio) {
+               case 128:
+               case 192:
+                       osr = WM8580_DACOSR;
+                       dev_dbg(codec->dev, "Selecting 64x OSR\n");
+                       break;
+               default:
+                       osr = 0;
+                       dev_dbg(codec->dev, "Selecting 128x OSR\n");
+                       break;
+               }
+
+               snd_soc_update_bits(codec, WM8580_PAIF3, WM8580_DACOSR, osr);
+       }
+
+       snd_soc_update_bits(codec, WM8580_PAIF1 + dai->driver->id,
+                           WM8580_AIF_RATE_MASK | WM8580_AIF_BCLKSEL_MASK,
+                           paifa);
+       snd_soc_update_bits(codec, WM8580_PAIF3 + dai->driver->id,
+                           WM8580_AIF_LENGTH_MASK, paifb);
        return 0;
 }
 
@@ -518,8 +552,8 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai,
        unsigned int aifb;
        int can_invert_lrclk;
 
-       aifa = snd_soc_read(codec, WM8580_PAIF1 + codec_dai->id);
-       aifb = snd_soc_read(codec, WM8580_PAIF3 + codec_dai->id);
+       aifa = snd_soc_read(codec, WM8580_PAIF1 + codec_dai->driver->id);
+       aifb = snd_soc_read(codec, WM8580_PAIF3 + codec_dai->driver->id);
 
        aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP);
 
@@ -585,8 +619,8 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai,
                return -EINVAL;
        }
 
-       snd_soc_write(codec, WM8580_PAIF1 + codec_dai->id, aifa);
-       snd_soc_write(codec, WM8580_PAIF3 + codec_dai->id, aifb);
+       snd_soc_write(codec, WM8580_PAIF1 + codec_dai->driver->id, aifa);
+       snd_soc_write(codec, WM8580_PAIF3 + codec_dai->driver->id, aifb);
 
        return 0;
 }
@@ -624,28 +658,6 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
                snd_soc_write(codec, WM8580_PLLB4, reg);
                break;
 
-       case WM8580_DAC_CLKSEL:
-               reg = snd_soc_read(codec, WM8580_CLKSEL);
-               reg &= ~WM8580_CLKSEL_DAC_CLKSEL_MASK;
-
-               switch (div) {
-               case WM8580_CLKSRC_MCLK:
-                       break;
-
-               case WM8580_CLKSRC_PLLA:
-                       reg |= WM8580_CLKSEL_DAC_CLKSEL_PLLA;
-                       break;
-
-               case WM8580_CLKSRC_PLLB:
-                       reg |= WM8580_CLKSEL_DAC_CLKSEL_PLLB;
-                       break;
-
-               default:
-                       return -EINVAL;
-               }
-               snd_soc_write(codec, WM8580_CLKSEL, reg);
-               break;
-
        case WM8580_CLKOUTSRC:
                reg = snd_soc_read(codec, WM8580_PLLB4);
                reg &= ~WM8580_PLLB4_CLKOUTSRC_MASK;
@@ -679,6 +691,55 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
        return 0;
 }
 
+static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+                            unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+       int sel, sel_mask, sel_shift;
+
+       switch (dai->driver->id) {
+       case WM8580_DAI_PAIFRX:
+               sel_mask = 0x3;
+               sel_shift = 0;
+               break;
+
+       case WM8580_DAI_PAIFTX:
+               sel_mask = 0xc;
+               sel_shift = 2;
+               break;
+
+       default:
+               BUG_ON("Unknown DAI driver ID\n");
+               return -EINVAL;
+       }
+
+       switch (clk_id) {
+       case WM8580_CLKSRC_ADCMCLK:
+               if (dai->id != WM8580_DAI_PAIFTX)
+                       return -EINVAL;
+               sel = 0 << sel_shift;
+               break;
+       case WM8580_CLKSRC_PLLA:
+               sel = 1 << sel_shift;
+               break;
+       case WM8580_CLKSRC_PLLB:
+               sel = 2 << sel_shift;
+               break;
+       case WM8580_CLKSRC_MCLK:
+               sel = 3 << sel_shift;
+               break;
+       default:
+               dev_err(codec->dev, "Unknown clock %d\n", clk_id);
+               return -EINVAL;
+       }
+
+       /* We really should validate PLL settings but not yet */
+       wm8580->sysclk[dai->id] = freq;
+
+       return snd_soc_update_bits(codec, WM8580_CLKSEL, sel_mask, sel);
+}
+
 static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
@@ -732,6 +793,7 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
                        SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
 static struct snd_soc_dai_ops wm8580_dai_ops_playback = {
+       .set_sysclk     = wm8580_set_sysclk,
        .hw_params      = wm8580_paif_hw_params,
        .set_fmt        = wm8580_set_paif_dai_fmt,
        .set_clkdiv     = wm8580_set_dai_clkdiv,
@@ -740,16 +802,17 @@ static struct snd_soc_dai_ops wm8580_dai_ops_playback = {
 };
 
 static struct snd_soc_dai_ops wm8580_dai_ops_capture = {
+       .set_sysclk     = wm8580_set_sysclk,
        .hw_params      = wm8580_paif_hw_params,
        .set_fmt        = wm8580_set_paif_dai_fmt,
        .set_clkdiv     = wm8580_set_dai_clkdiv,
        .set_pll        = wm8580_set_dai_pll,
 };
 
-struct snd_soc_dai wm8580_dai[] = {
+static struct snd_soc_dai_driver wm8580_dai[] = {
        {
-               .name = "WM8580 PAIFRX",
-               .id = 0,
+               .name = "wm8580-hifi-playback",
+               .id     = WM8580_DAI_PAIFRX,
                .playback = {
                        .stream_name = "Playback",
                        .channels_min = 1,
@@ -760,8 +823,8 @@ struct snd_soc_dai wm8580_dai[] = {
                .ops = &wm8580_dai_ops_playback,
        },
        {
-               .name = "WM8580 PAIFTX",
-               .id = 1,
+               .name = "wm8580-hifi-capture",
+               .id     =       WM8580_DAI_PAIFTX,
                .capture = {
                        .stream_name = "Capture",
                        .channels_min = 2,
@@ -772,90 +835,16 @@ struct snd_soc_dai wm8580_dai[] = {
                .ops = &wm8580_dai_ops_capture,
        },
 };
-EXPORT_SYMBOL_GPL(wm8580_dai);
-
-static struct snd_soc_codec *wm8580_codec;
 
-static int wm8580_probe(struct platform_device *pdev)
+static int wm8580_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (wm8580_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8580_codec;
-       codec = wm8580_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       snd_soc_add_controls(codec, wm8580_snd_controls,
-                            ARRAY_SIZE(wm8580_snd_controls));
-       wm8580_add_widgets(codec);
-
-       return ret;
-
-pcm_err:
-       return ret;
-}
-
-/* power down chip */
-static int wm8580_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8580 = {
-       .probe =        wm8580_probe,
-       .remove =       wm8580_remove,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580);
-
-static int wm8580_register(struct wm8580_priv *wm8580,
-                          enum snd_soc_control_type control)
-{
-       int ret, i;
-       struct snd_soc_codec *codec = &wm8580->codec;
-
-       if (wm8580_codec) {
-               dev_err(codec->dev, "Another WM8580 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8580);
-       codec->name = "WM8580";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8580_set_bias_level;
-       codec->dai = wm8580_dai;
-       codec->num_dai = ARRAY_SIZE(wm8580_dai);
-       codec->reg_cache_size = ARRAY_SIZE(wm8580->reg_cache);
-       codec->reg_cache = &wm8580->reg_cache;
-
-       memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg));
+       struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0,i;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8580->control_type);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++)
@@ -865,7 +854,7 @@ static int wm8580_register(struct wm8580_priv *wm8580,
                                 wm8580->supplies);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies),
@@ -882,74 +871,68 @@ static int wm8580_register(struct wm8580_priv *wm8580,
                goto err_regulator_enable;
        }
 
-       for (i = 0; i < ARRAY_SIZE(wm8580_dai); i++)
-               wm8580_dai[i].dev = codec->dev;
-
        wm8580_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       wm8580_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err_regulator_enable;
-       }
-
-       ret = snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
+       snd_soc_add_controls(codec, wm8580_snd_controls,
+                            ARRAY_SIZE(wm8580_snd_controls));
+       wm8580_add_widgets(codec);
 
        return 0;
 
-err_codec:
-       snd_soc_unregister_codec(codec);
 err_regulator_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
 err_regulator_get:
        regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
-err:
-       kfree(wm8580);
        return ret;
 }
 
-static void wm8580_unregister(struct wm8580_priv *wm8580)
+/* power down chip */
+static int wm8580_remove(struct snd_soc_codec *codec)
 {
-       wm8580_set_bias_level(&wm8580->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
-       snd_soc_unregister_codec(&wm8580->codec);
+       struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
+
+       wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
        regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
        regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
-       kfree(wm8580);
-       wm8580_codec = NULL;
+
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_wm8580 = {
+       .probe =        wm8580_probe,
+       .remove =       wm8580_remove,
+       .set_bias_level = wm8580_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8580_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = &wm8580_reg,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static int wm8580_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct wm8580_priv *wm8580;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL);
        if (wm8580 == NULL)
                return -ENOMEM;
 
-       codec = &wm8580->codec;
-
        i2c_set_clientdata(i2c, wm8580);
-       codec->control_data = i2c;
+       wm8580->control_type = SND_SOC_I2C;
 
-       codec->dev = &i2c->dev;
-
-       return wm8580_register(wm8580, SND_SOC_I2C);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8580, wm8580_dai, ARRAY_SIZE(wm8580_dai));
+       if (ret < 0)
+               kfree(wm8580);
+       return ret;
 }
 
 static int wm8580_i2c_remove(struct i2c_client *client)
 {
-       struct wm8580_priv *wm8580 = i2c_get_clientdata(client);
-       wm8580_unregister(wm8580);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -961,7 +944,7 @@ MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id);
 
 static struct i2c_driver wm8580_i2c_driver = {
        .driver = {
-               .name = "wm8580",
+               .name = "wm8580-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8580_i2c_probe,
@@ -972,7 +955,7 @@ static struct i2c_driver wm8580_i2c_driver = {
 
 static int __init wm8580_modinit(void)
 {
-       int ret;
+       int ret = 0;
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8580_i2c_driver);
@@ -981,7 +964,7 @@ static int __init wm8580_modinit(void)
        }
 #endif
 
-       return 0;
+       return ret;
 }
 module_init(wm8580_modinit);
 
index 0dfb5ddde6a2a700fe4aacb878ae9def6af73777..1d34656d0dcb1b8711b2996d25857cb8c1f5d672 100644 (file)
 #define WM8580_PLLB  2
 
 #define WM8580_MCLK       1
-#define WM8580_DAC_CLKSEL 2
-#define WM8580_CLKOUTSRC  3
+#define WM8580_CLKOUTSRC  2
 
-#define WM8580_CLKSRC_MCLK 1
-#define WM8580_CLKSRC_PLLA 2
-#define WM8580_CLKSRC_PLLB 3
-#define WM8580_CLKSRC_OSC  4
-#define WM8580_CLKSRC_NONE 5
+#define WM8580_CLKSRC_MCLK    1
+#define WM8580_CLKSRC_PLLA    2
+#define WM8580_CLKSRC_PLLB    3
+#define WM8580_CLKSRC_OSC     4
+#define WM8580_CLKSRC_NONE    5
+#define WM8580_CLKSRC_ADCMCLK 6
 
 #define WM8580_DAI_PAIFRX 0
 #define WM8580_DAI_PAIFTX 1
 
-extern struct snd_soc_dai wm8580_dai[];
-extern struct snd_soc_codec_device soc_codec_dev_wm8580;
-
 #endif
 
index e2dba07f0260d77279e32b9a433220465d6071f9..54fbd76c8bca3aeeb8799b7dabd8694f60b221b9 100644 (file)
 
 #include "wm8711.h"
 
-static struct snd_soc_codec *wm8711_codec;
-
 /* codec private data */
 struct wm8711_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type bus_type;
        u16 reg_cache[WM8711_CACHEREGNUM];
        unsigned int sysclk;
 };
@@ -163,7 +161,7 @@ static int wm8711_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct snd_soc_codec *codec = dai->codec;
-       struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
+       struct wm8711_priv *wm8711 =  snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfffc;
        int i = get_coeff(wm8711->sysclk, params_rate(params));
        u16 srate = (coeff_div[i].sr << 2) |
@@ -227,7 +225,7 @@ static int wm8711_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 wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
+       struct wm8711_priv *wm8711 =  snd_soc_codec_get_drvdata(codec);
 
        switch (freq) {
        case 11289600:
@@ -338,8 +336,8 @@ static struct snd_soc_dai_ops wm8711_ops = {
        .set_fmt = wm8711_set_dai_fmt,
 };
 
-struct snd_soc_dai wm8711_dai = {
-       .name = "WM8711",
+static struct snd_soc_dai_driver wm8711_dai = {
+       .name = "wm8711-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -349,22 +347,16 @@ struct snd_soc_dai wm8711_dai = {
        },
        .ops = &wm8711_ops,
 };
-EXPORT_SYMBOL_GPL(wm8711_dai);
 
-static int wm8711_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8711_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        snd_soc_write(codec, WM8711_ACTIVE, 0x0);
        wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8711_resume(struct platform_device *pdev)
+static int wm8711_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -380,99 +372,23 @@ static int wm8711_resume(struct platform_device *pdev)
        return 0;
 }
 
-static int wm8711_probe(struct platform_device *pdev)
+static int wm8711_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (wm8711_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8711_codec;
-       codec = wm8711_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       snd_soc_add_controls(codec, wm8711_snd_controls,
-                            ARRAY_SIZE(wm8711_snd_controls));
-       wm8711_add_widgets(codec);
-
-       return ret;
-
-pcm_err:
-       return ret;
-}
-
-/* power down chip */
-static int wm8711_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8711 = {
-       .probe =        wm8711_probe,
-       .remove =       wm8711_remove,
-       .suspend =      wm8711_suspend,
-       .resume =       wm8711_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8711);
-
-static int wm8711_register(struct wm8711_priv *wm8711,
-                          enum snd_soc_control_type control)
-{
-       int ret;
-       struct snd_soc_codec *codec = &wm8711->codec;
-       u16 reg;
-
-       if (wm8711_codec) {
-               dev_err(codec->dev, "Another WM8711 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8711);
-       codec->name = "WM8711";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8711_set_bias_level;
-       codec->dai = &wm8711_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8711_CACHEREGNUM;
-       codec->reg_cache = &wm8711->reg_cache;
-
-       memcpy(codec->reg_cache, wm8711_reg, sizeof(wm8711_reg));
+       struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
+       int ret, reg;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8711->bus_type);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        ret = wm8711_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset\n");
-               goto err;
+               return ret;
        }
 
-       wm8711_dai.dev = codec->dev;
-
        wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* Latch the update bits */
@@ -481,70 +397,62 @@ static int wm8711_register(struct wm8711_priv *wm8711,
        reg = snd_soc_read(codec, WM8711_ROUT1V);
        snd_soc_write(codec, WM8711_ROUT1V, reg | 0x0100);
 
-       wm8711_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dai(&wm8711_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
-
-       return 0;
+       snd_soc_add_controls(codec, wm8711_snd_controls,
+                            ARRAY_SIZE(wm8711_snd_controls));
+       wm8711_add_widgets(codec);
 
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm8711);
        return ret;
+
 }
 
-static void wm8711_unregister(struct wm8711_priv *wm8711)
+/* power down chip */
+static int wm8711_remove(struct snd_soc_codec *codec)
 {
-       wm8711_set_bias_level(&wm8711->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dai(&wm8711_dai);
-       snd_soc_unregister_codec(&wm8711->codec);
-       kfree(wm8711);
-       wm8711_codec = NULL;
+       wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_wm8711 = {
+       .probe =        wm8711_probe,
+       .remove =       wm8711_remove,
+       .suspend =      wm8711_suspend,
+       .resume =       wm8711_resume,
+       .set_bias_level = wm8711_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8711_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8711_reg,
+};
+
 #if defined(CONFIG_SPI_MASTER)
 static int __devinit wm8711_spi_probe(struct spi_device *spi)
 {
-       struct snd_soc_codec *codec;
        struct wm8711_priv *wm8711;
+       int ret;
 
        wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL);
        if (wm8711 == NULL)
                return -ENOMEM;
 
-       codec = &wm8711->codec;
-       codec->control_data = spi;
-       codec->dev = &spi->dev;
+       spi_set_drvdata(spi, wm8711);
+       wm8711->bus_type = SND_SOC_SPI;
 
-       dev_set_drvdata(&spi->dev, wm8711);
-
-       return wm8711_register(wm8711, SND_SOC_SPI);
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_wm8711, &wm8711_dai, 1);
+       if (ret < 0)
+               kfree(wm8711);
+       return ret;
 }
 
 static int __devexit wm8711_spi_remove(struct spi_device *spi)
 {
-       struct wm8711_priv *wm8711 = dev_get_drvdata(&spi->dev);
-
-       wm8711_unregister(wm8711);
-
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
 static struct spi_driver wm8711_spi_driver = {
        .driver = {
-               .name   = "wm8711",
-               .bus    = &spi_bus_type,
+               .name   = "wm8711-codec",
                .owner  = THIS_MODULE,
        },
        .probe          = wm8711_spi_probe,
@@ -553,31 +461,30 @@ static struct spi_driver wm8711_spi_driver = {
 #endif /* CONFIG_SPI_MASTER */
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static __devinit int wm8711_i2c_probe(struct i2c_client *i2c,
+static __devinit int wm8711_i2c_probe(struct i2c_client *client,
                                      const struct i2c_device_id *id)
 {
        struct wm8711_priv *wm8711;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL);
        if (wm8711 == NULL)
                return -ENOMEM;
 
-       codec = &wm8711->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
-       i2c_set_clientdata(i2c, wm8711);
-       codec->control_data = i2c;
+       i2c_set_clientdata(client, wm8711);
+       wm8711->bus_type = SND_SOC_I2C;
 
-       codec->dev = &i2c->dev;
-
-       return wm8711_register(wm8711, SND_SOC_I2C);
+       ret =  snd_soc_register_codec(&client->dev,
+                       &soc_codec_dev_wm8711, &wm8711_dai, 1);
+       if (ret < 0)
+               kfree(wm8711);
+       return ret;
 }
 
 static __devexit int wm8711_i2c_remove(struct i2c_client *client)
 {
-       struct wm8711_priv *wm8711 = i2c_get_clientdata(client);
-       wm8711_unregister(wm8711);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -589,7 +496,7 @@ MODULE_DEVICE_TABLE(i2c, wm8711_i2c_id);
 
 static struct i2c_driver wm8711_i2c_driver = {
        .driver = {
-               .name = "WM8711 I2C Codec",
+               .name = "wm8711-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8711_i2c_probe,
index 381e84a4381696699a9b796d6c9c125ddf0fa3ea..a61db985499f933e88736664510e90bfa1505e03 100644 (file)
@@ -36,7 +36,4 @@ struct wm8711_setup_data {
        unsigned short i2c_address;
 };
 
-extern struct snd_soc_dai wm8711_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8711;
-
 #endif
index 9d1df26281361ef9ed569e0b87a39d9a934f9254..7488082851191ce120a8a66fd8704b53613b8189 100644 (file)
@@ -23,7 +23,6 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 
-#include "wm8727.h"
 /*
  * Note this is a simple chip with no configuration interface, sample rate is
  * determined automatically by examining the Master clock and Bit clock ratios
@@ -33,8 +32,8 @@
                        SNDRV_PCM_RATE_192000)
 
 
-struct snd_soc_dai wm8727_dai = {
-       .name = "WM8727",
+static struct snd_soc_dai_driver wm8727_dai = {
+       .name = "wm8727-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -43,103 +42,18 @@ struct snd_soc_dai wm8727_dai = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
                },
 };
-EXPORT_SYMBOL_GPL(wm8727_dai);
 
-static struct snd_soc_codec *wm8727_codec;
+static struct snd_soc_codec_driver soc_codec_dev_wm8727;
 
-static int wm8727_soc_probe(struct platform_device *pdev)
+static __devinit int wm8727_probe(struct platform_device *pdev)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       int ret = 0;
-
-       BUG_ON(!wm8727_codec);
-
-       socdev->card->codec = wm8727_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8727: failed to create pcms\n");
-               goto pcm_err;
-       }
-
-       return ret;
-
-pcm_err:
-       kfree(socdev->card->codec);
-       socdev->card->codec = NULL;
-       return ret;
-}
-
-static int wm8727_soc_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8727 = {
-       .probe =        wm8727_soc_probe,
-       .remove =       wm8727_soc_remove,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8727);
-
-
-static __devinit int wm8727_platform_probe(struct platform_device *pdev)
-{
-       struct snd_soc_codec *codec;
-       int ret;
-
-       if (wm8727_codec) {
-               dev_err(&pdev->dev, "Another WM8727 is registered\n");
-               return -EBUSY;
-       }
-
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
-       wm8727_codec = codec;
-
-       platform_set_drvdata(pdev, codec);
-
-       mutex_init(&codec->mutex);
-       codec->dev = &pdev->dev;
-       codec->name = "WM8727";
-       codec->owner = THIS_MODULE;
-       codec->dai = &wm8727_dai;
-       codec->num_dai = 1;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       wm8727_dai.dev = &pdev->dev;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "Failed to register CODEC: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dai(&wm8727_dai);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
-
-       return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(codec);
-       return ret;
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_wm8727, &wm8727_dai, 1);
 }
 
-static int __devexit wm8727_platform_remove(struct platform_device *pdev)
+static int __devexit wm8727_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&wm8727_dai);
-       snd_soc_unregister_codec(platform_get_drvdata(pdev));
+       snd_soc_unregister_codec(&pdev->dev);
        return 0;
 }
 
@@ -149,8 +63,8 @@ static struct platform_driver wm8727_codec_driver = {
                        .owner = THIS_MODULE,
        },
 
-       .probe = wm8727_platform_probe,
-       .remove = __devexit_p(wm8727_platform_remove),
+       .probe = wm8727_probe,
+       .remove = __devexit_p(wm8727_remove),
 };
 
 static int __init wm8727_init(void)
diff --git a/sound/soc/codecs/wm8727.h b/sound/soc/codecs/wm8727.h
deleted file mode 100644 (file)
index ee19aa7..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * wm8727.h
- *
- *  Created on: 15-Oct-2009
- *      Author: neil.jones@imgtec.com
- *
- * Copyright (C) 2009 Imagination Technologies 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.
- */
-
-#ifndef WM8727_H_
-#define WM8727_H_
-
-extern struct snd_soc_dai wm8727_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8727;
-
-#endif /* WM8727_H_ */
index 34be2d2b69eff81ab96f8b243d5541a7b71f2b73..075f35e4f4cbbd33bde2b9904e0bc3b894350d39 100644 (file)
@@ -29,8 +29,6 @@
 
 #include "wm8728.h"
 
-struct snd_soc_codec_device soc_codec_dev_wm8728;
-
 /*
  * We can't read the WM8728 register space so we cache them instead.
  * Note that the defaults here aren't the physical defaults, we latch
@@ -44,6 +42,11 @@ static const u16 wm8728_reg_defaults[] = {
        0x100,
 };
 
+/* codec private data */
+struct wm8728_priv {
+       enum snd_soc_control_type control_type;
+};
+
 static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1);
 
 static const struct snd_kcontrol_new wm8728_snd_controls[] = {
@@ -96,8 +99,7 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u16 dac = snd_soc_read(codec, WM8728_DACCTL);
 
        dac &= ~0x18;
@@ -210,8 +212,8 @@ static struct snd_soc_dai_ops wm8728_dai_ops = {
        .set_fmt        = wm8728_set_dai_fmt,
 };
 
-struct snd_soc_dai wm8728_dai = {
-       .name = "WM8728",
+static struct snd_soc_dai_driver wm8728_dai = {
+       .name = "wm8728-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -221,63 +223,31 @@ struct snd_soc_dai wm8728_dai = {
        },
        .ops = &wm8728_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8728_dai);
 
-static int wm8728_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8728_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int wm8728_resume(struct platform_device *pdev)
+static int wm8728_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
 }
 
-/*
- * initialise the WM8728 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int wm8728_init(struct snd_soc_device *socdev,
-                      enum snd_soc_control_type control)
+static int wm8728_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int ret = 0;
-
-       codec->name = "WM8728";
-       codec->owner = THIS_MODULE;
-       codec->set_bias_level = wm8728_set_bias_level;
-       codec->dai = &wm8728_dai;
-       codec->num_dai = 1;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults);
-       codec->reg_cache = kmemdup(wm8728_reg_defaults,
-                                  sizeof(wm8728_reg_defaults),
-                                  GFP_KERNEL);
-       if (codec->reg_cache == NULL)
-               return -ENOMEM;
+       struct wm8728_priv *wm8728 = snd_soc_codec_get_drvdata(codec);
+       int ret;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8728->control_type);
        if (ret < 0) {
                printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n",
                       ret);
-               goto err;
-       }
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8728: failed to create pcms\n");
-               goto err;
+               return ret;
        }
 
        /* power on device */
@@ -288,215 +258,136 @@ static int wm8728_init(struct snd_soc_device *socdev,
        wm8728_add_widgets(codec);
 
        return ret;
-
-err:
-       kfree(codec->reg_cache);
-       return ret;
 }
 
-static struct snd_soc_device *wm8728_socdev;
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static int wm8728_remove(struct snd_soc_codec *codec)
+{
+       wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
 
-/*
- * WM8728 2 wire address is determined by GPIO5
- * state during powerup.
- *    low  = 0x1a
- *    high = 0x1b
- */
+static struct snd_soc_codec_driver soc_codec_dev_wm8728 = {
+       .probe =        wm8728_probe,
+       .remove =       wm8728_remove,
+       .suspend =      wm8728_suspend,
+       .resume =       wm8728_resume,
+       .set_bias_level = wm8728_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8728_reg_defaults,
+};
 
-static int wm8728_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8728_spi_probe(struct spi_device *spi)
 {
-       struct snd_soc_device *socdev = wm8728_socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct wm8728_priv *wm8728;
        int ret;
 
-       i2c_set_clientdata(i2c, codec);
-       codec->control_data = i2c;
+       wm8728 = kzalloc(sizeof(struct wm8728_priv), GFP_KERNEL);
+       if (wm8728 == NULL)
+               return -ENOMEM;
+
+       wm8728->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8728);
 
-       ret = wm8728_init(socdev, SND_SOC_I2C);
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_wm8728, &wm8728_dai, 1);
        if (ret < 0)
-               pr_err("failed to initialise WM8728\n");
-
+               kfree(wm8728);
        return ret;
 }
 
-static int wm8728_i2c_remove(struct i2c_client *client)
+static int __devexit wm8728_spi_remove(struct spi_device *spi)
 {
-       struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       kfree(codec->reg_cache);
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
-static const struct i2c_device_id wm8728_i2c_id[] = {
-       { "wm8728", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id);
-
-static struct i2c_driver wm8728_i2c_driver = {
+static struct spi_driver wm8728_spi_driver = {
        .driver = {
-               .name = "WM8728 I2C Codec",
-               .owner = THIS_MODULE,
+               .name   = "wm8728-codec",
+               .owner  = THIS_MODULE,
        },
-       .probe =    wm8728_i2c_probe,
-       .remove =   wm8728_i2c_remove,
-       .id_table = wm8728_i2c_id,
+       .probe          = wm8728_spi_probe,
+       .remove         = __devexit_p(wm8728_spi_remove),
 };
+#endif /* CONFIG_SPI_MASTER */
 
-static int wm8728_add_i2c_device(struct platform_device *pdev,
-                                const struct wm8728_setup_data *setup)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8728_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
-       struct i2c_board_info info;
-       struct i2c_adapter *adapter;
-       struct i2c_client *client;
+       struct wm8728_priv *wm8728;
        int ret;
 
-       ret = i2c_add_driver(&wm8728_i2c_driver);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "can't add i2c driver\n");
-               return ret;
-       }
-
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       info.addr = setup->i2c_address;
-       strlcpy(info.type, "wm8728", I2C_NAME_SIZE);
-
-       adapter = i2c_get_adapter(setup->i2c_bus);
-       if (!adapter) {
-               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
-                       setup->i2c_bus);
-               goto err_driver;
-       }
-
-       client = i2c_new_device(adapter, &info);
-       i2c_put_adapter(adapter);
-       if (!client) {
-               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
-                       (unsigned int)info.addr);
-               goto err_driver;
-       }
-
-       return 0;
-
-err_driver:
-       i2c_del_driver(&wm8728_i2c_driver);
-       return -ENODEV;
-}
-#endif
-
-#if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8728_spi_probe(struct spi_device *spi)
-{
-       struct snd_soc_device *socdev = wm8728_socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int ret;
+       wm8728 = kzalloc(sizeof(struct wm8728_priv), GFP_KERNEL);
+       if (wm8728 == NULL)
+               return -ENOMEM;
 
-       codec->control_data = spi;
+       i2c_set_clientdata(i2c, wm8728);
+       wm8728->control_type = SND_SOC_I2C;
 
-       ret = wm8728_init(socdev, SND_SOC_SPI);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8728, &wm8728_dai, 1);
        if (ret < 0)
-               dev_err(&spi->dev, "failed to initialise WM8728\n");
-
+               kfree(wm8728);
        return ret;
 }
 
-static int __devexit wm8728_spi_remove(struct spi_device *spi)
+static __devexit int wm8728_i2c_remove(struct i2c_client *client)
 {
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
-static struct spi_driver wm8728_spi_driver = {
+static const struct i2c_device_id wm8728_i2c_id[] = {
+       { "wm8728", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id);
+
+static struct i2c_driver wm8728_i2c_driver = {
        .driver = {
-               .name   = "wm8728",
-               .bus    = &spi_bus_type,
-               .owner  = THIS_MODULE,
+               .name = "wm8728-codec",
+               .owner = THIS_MODULE,
        },
-       .probe          = wm8728_spi_probe,
-       .remove         = __devexit_p(wm8728_spi_remove),
+       .probe =    wm8728_i2c_probe,
+       .remove =   __devexit_p(wm8728_i2c_remove),
+       .id_table = wm8728_i2c_id,
 };
-#endif /* CONFIG_SPI_MASTER */
+#endif
 
-static int wm8728_probe(struct platform_device *pdev)
+static int __init wm8728_modinit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct wm8728_setup_data *setup;
-       struct snd_soc_codec *codec;
        int ret = 0;
-
-       setup = socdev->codec_data;
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
-
-       socdev->card->codec = codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       wm8728_socdev = socdev;
-       ret = -ENODEV;
-
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       if (setup->i2c_address) {
-               ret = wm8728_add_i2c_device(pdev, setup);
+       ret = i2c_add_driver(&wm8728_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8728 I2C driver: %d\n",
+                      ret);
        }
 #endif
 #if defined(CONFIG_SPI_MASTER)
-       if (setup->spi) {
-               ret = spi_register_driver(&wm8728_spi_driver);
-               if (ret != 0)
-                       printk(KERN_ERR "can't add spi driver");
+       ret = spi_register_driver(&wm8728_spi_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8728 SPI driver: %d\n",
+                      ret);
        }
 #endif
-
-       if (ret != 0)
-               kfree(codec);
-
        return ret;
 }
+module_init(wm8728_modinit);
 
-/* power down chip */
-static int wm8728_remove(struct platform_device *pdev)
+static void __exit wm8728_exit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec->control_data)
-               wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       i2c_unregister_device(codec->control_data);
        i2c_del_driver(&wm8728_i2c_driver);
 #endif
 #if defined(CONFIG_SPI_MASTER)
        spi_unregister_driver(&wm8728_spi_driver);
 #endif
-       kfree(codec);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8728 = {
-       .probe =        wm8728_probe,
-       .remove =       wm8728_remove,
-       .suspend =      wm8728_suspend,
-       .resume =       wm8728_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8728);
-
-static int __init wm8728_modinit(void)
-{
-       return snd_soc_register_dai(&wm8728_dai);
-}
-module_init(wm8728_modinit);
-
-static void __exit wm8728_exit(void)
-{
-       snd_soc_unregister_dai(&wm8728_dai);
 }
 module_exit(wm8728_exit);
 
index d269c132474b7e0e2c44ad78182b45d21208dd7f..8aea362ffd47e2c7672937e5c5e89db4bd099c6b 100644 (file)
 #define WM8728_DACCTL    0x02
 #define WM8728_IFCTL     0x03
 
-struct wm8728_setup_data {
-       int            spi;
-       int            i2c_bus;
-       unsigned short i2c_address;
-};
-
-extern struct snd_soc_dai wm8728_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8728;
-
 #endif
index 0ab9b6355297d9116aa2f27045ac2c8005c42f4c..631385802eb44a587f5fe375d8f1c61e89ba9d02 100644 (file)
@@ -32,9 +32,6 @@
 
 #include "wm8731.h"
 
-static struct snd_soc_codec *wm8731_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8731;
-
 #define WM8731_NUM_SUPPLIES 4
 static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = {
        "AVDD",
@@ -45,10 +42,11 @@ static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = {
 
 /* codec private data */
 struct wm8731_priv {
-       struct snd_soc_codec codec;
+       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;
 };
 
 
@@ -113,6 +111,7 @@ static const struct snd_kcontrol_new wm8731_input_mux_controls =
 SOC_DAPM_ENUM("Input Select", wm8731_enum[0]);
 
 static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("OSC", WM8731_PWR, 5, 1, NULL, 0),
 SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1,
        &wm8731_output_mixer_controls[0],
        ARRAY_SIZE(wm8731_output_mixer_controls)),
@@ -130,7 +129,18 @@ SND_SOC_DAPM_INPUT("RLINEIN"),
 SND_SOC_DAPM_INPUT("LLINEIN"),
 };
 
+static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
+                           struct snd_soc_dapm_widget *sink)
+{
+       struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(source->codec);
+
+       return wm8731->sysclk_type == WM8731_SYSCLK_MCLK;
+}
+
 static const struct snd_soc_dapm_route intercon[] = {
+       {"DAC", NULL, "OSC", wm8731_check_osc},
+       {"ADC", NULL, "OSC", wm8731_check_osc},
+
        /* output mixer */
        {"Output Mixer", "Line Bypass Switch", "Line Input"},
        {"Output Mixer", "HiFi Playback Switch", "DAC"},
@@ -222,9 +232,7 @@ static int wm8731_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_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = dai->codec;
        struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8731_IFACE) & 0xfff3;
        int i = get_coeff(wm8731->sysclk, params_rate(params));
@@ -252,9 +260,7 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
 static int wm8731_pcm_prepare(struct snd_pcm_substream *substream,
                              struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = dai->codec;
 
        /* set active */
        snd_soc_write(codec, WM8731_ACTIVE, 0x0001);
@@ -265,9 +271,7 @@ static int wm8731_pcm_prepare(struct snd_pcm_substream *substream,
 static void wm8731_shutdown(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = dai->codec;
 
        /* deactivate */
        if (!codec->active) {
@@ -294,6 +298,15 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        struct snd_soc_codec *codec = codec_dai->codec;
        struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
 
+       switch (clk_id) {
+       case WM8731_SYSCLK_XTAL:
+       case WM8731_SYSCLK_MCLK:
+               wm8731->sysclk_type = clk_id;
+               break;
+       default:
+               return -EINVAL;
+       }
+
        switch (freq) {
        case 11289600:
        case 12000000:
@@ -301,9 +314,14 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        case 16934400:
        case 18432000:
                wm8731->sysclk = freq;
-               return 0;
+               break;
+       default:
+               return -EINVAL;
        }
-       return -EINVAL;
+
+       snd_soc_dapm_sync(codec);
+
+       return 0;
 }
 
 
@@ -428,8 +446,8 @@ static struct snd_soc_dai_ops wm8731_dai_ops = {
        .set_fmt        = wm8731_set_dai_fmt,
 };
 
-struct snd_soc_dai wm8731_dai = {
-       .name = "WM8731",
+static struct snd_soc_dai_driver wm8731_dai = {
+       .name = "wm8731-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -445,24 +463,17 @@ struct snd_soc_dai wm8731_dai = {
        .ops = &wm8731_dai_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(wm8731_dai);
 
 #ifdef CONFIG_PM
-static int wm8731_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8731_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int wm8731_resume(struct platform_device *pdev)
+static int wm8731_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
@@ -472,88 +483,15 @@ static int wm8731_resume(struct platform_device *pdev)
 #define wm8731_resume NULL
 #endif
 
-static int wm8731_probe(struct platform_device *pdev)
+static int wm8731_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (wm8731_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8731_codec;
-       codec = wm8731_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       snd_soc_add_controls(codec, wm8731_snd_controls,
-                            ARRAY_SIZE(wm8731_snd_controls));
-       wm8731_add_widgets(codec);
-
-       return ret;
-
-pcm_err:
-       return ret;
-}
-
-/* power down chip */
-static int wm8731_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8731 = {
-       .probe =        wm8731_probe,
-       .remove =       wm8731_remove,
-       .suspend =      wm8731_suspend,
-       .resume =       wm8731_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);
-
-static int wm8731_register(struct wm8731_priv *wm8731,
-                          enum snd_soc_control_type control)
-{
-       int ret, i;
-       struct snd_soc_codec *codec = &wm8731->codec;
-
-       if (wm8731_codec) {
-               dev_err(codec->dev, "Another WM8731 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8731);
-       codec->name = "WM8731";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8731_set_bias_level;
-       codec->dai = &wm8731_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8731_CACHEREGNUM;
-       codec->reg_cache = &wm8731->reg_cache;
-
-       memcpy(codec->reg_cache, wm8731_reg, sizeof(wm8731_reg));
+       struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0, i;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8731->control_type);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++)
@@ -563,7 +501,7 @@ static int wm8731_register(struct wm8731_priv *wm8731,
                                 wm8731->supplies);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
@@ -579,8 +517,6 @@ static int wm8731_register(struct wm8731_priv *wm8731,
                goto err_regulator_enable;
        }
 
-       wm8731_dai.dev = codec->dev;
-
        wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* Latch the update bits */
@@ -592,79 +528,78 @@ static int wm8731_register(struct wm8731_priv *wm8731,
        /* Disable bypass path by default */
        snd_soc_update_bits(codec, WM8731_APANA, 0x4, 0);
 
-       wm8731_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err_regulator_enable;
-       }
-
-       ret = snd_soc_register_dai(&wm8731_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               snd_soc_unregister_codec(codec);
-               goto err_codec;
-       }
+       snd_soc_add_controls(codec, wm8731_snd_controls,
+                            ARRAY_SIZE(wm8731_snd_controls));
+       wm8731_add_widgets(codec);
 
        /* Regulators will have been enabled by bias management */
        regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
 
        return 0;
 
-err_codec:
-       snd_soc_unregister_codec(codec);
 err_regulator_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
 err_regulator_get:
        regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
-err:
+
        kfree(wm8731);
        return ret;
 }
 
-static void wm8731_unregister(struct wm8731_priv *wm8731)
+/* power down chip */
+static int wm8731_remove(struct snd_soc_codec *codec)
 {
-       wm8731_set_bias_level(&wm8731->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dai(&wm8731_dai);
-       snd_soc_unregister_codec(&wm8731->codec);
+       struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
+
+       wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
        regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
-       kfree(wm8731);
-       wm8731_codec = NULL;
+
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_wm8731 = {
+       .probe =        wm8731_probe,
+       .remove =       wm8731_remove,
+       .suspend =      wm8731_suspend,
+       .resume =       wm8731_resume,
+       .set_bias_level = wm8731_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8731_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8731_reg,
+};
+
 #if defined(CONFIG_SPI_MASTER)
 static int __devinit wm8731_spi_probe(struct spi_device *spi)
 {
-       struct snd_soc_codec *codec;
        struct wm8731_priv *wm8731;
+       int ret;
 
        wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
        if (wm8731 == NULL)
                return -ENOMEM;
 
-       codec = &wm8731->codec;
-       codec->control_data = spi;
-       codec->dev = &spi->dev;
-
-       dev_set_drvdata(&spi->dev, wm8731);
+       wm8731->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8731);
 
-       return wm8731_register(wm8731, SND_SOC_SPI);
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_wm8731, &wm8731_dai, 1);
+       if (ret < 0)
+               kfree(wm8731);
+       return ret;
 }
 
 static int __devexit wm8731_spi_remove(struct spi_device *spi)
 {
-       struct wm8731_priv *wm8731 = dev_get_drvdata(&spi->dev);
-
-       wm8731_unregister(wm8731);
-
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
 static struct spi_driver wm8731_spi_driver = {
        .driver = {
-               .name   = "wm8731",
-               .bus    = &spi_bus_type,
+               .name   = "wm8731-codec",
                .owner  = THIS_MODULE,
        },
        .probe          = wm8731_spi_probe,
@@ -677,26 +612,26 @@ static __devinit int wm8731_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8731_priv *wm8731;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
        if (wm8731 == NULL)
                return -ENOMEM;
 
-       codec = &wm8731->codec;
-
        i2c_set_clientdata(i2c, wm8731);
-       codec->control_data = i2c;
-
-       codec->dev = &i2c->dev;
+       wm8731->control_type = SND_SOC_I2C;
 
-       return wm8731_register(wm8731, SND_SOC_I2C);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8731, &wm8731_dai, 1);
+       if (ret < 0)
+               kfree(wm8731);
+       return ret;
 }
 
 static __devexit int wm8731_i2c_remove(struct i2c_client *client)
 {
-       struct wm8731_priv *wm8731 = i2c_get_clientdata(client);
-       wm8731_unregister(wm8731);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -708,7 +643,7 @@ MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id);
 
 static struct i2c_driver wm8731_i2c_driver = {
        .driver = {
-               .name = "wm8731",
+               .name = "wm8731-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8731_i2c_probe,
@@ -719,7 +654,7 @@ static struct i2c_driver wm8731_i2c_driver = {
 
 static int __init wm8731_modinit(void)
 {
-       int ret;
+       int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8731_i2c_driver);
        if (ret != 0) {
@@ -734,7 +669,7 @@ static int __init wm8731_modinit(void)
                       ret);
        }
 #endif
-       return 0;
+       return ret;
 }
 module_init(wm8731_modinit);
 
index cd7b806e8ad0b745db1116f40b1682733f8d1780..e9c0c76ab73bf4ca72f667e5ef2d2d063ff5028a 100644 (file)
 
 #define WM8731_CACHEREGNUM     10
 
-#define WM8731_SYSCLK  0
-#define WM8731_DAI             0
+#define WM8731_SYSCLK_XTAL 1
+#define WM8731_SYSCLK_MCLK 2
 
-extern struct snd_soc_dai wm8731_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8731;
+#define WM8731_DAI             0
 
 #endif
index b9ea8904ad4b2102a7f43f0b7655b0cd661290bf..90e31e9aa6f7c66346c8360a3c1ab900519e4a98 100644 (file)
 
 #include "wm8741.h"
 
-static struct snd_soc_codec *wm8741_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8741;
-
 #define WM8741_NUM_SUPPLIES 2
 static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = {
        "AVDD",
        "DVDD",
 };
 
-#define WM8741_NUM_RATES 4
+#define WM8741_NUM_RATES 6
 
 /* codec private data */
 struct wm8741_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
        u16 reg_cache[WM8741_REGISTER_COUNT];
        struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
        unsigned int sysclk;
-       unsigned int rate_constraint_list[WM8741_NUM_RATES];
-       struct snd_pcm_hw_constraint_list rate_constraint;
+       struct snd_pcm_hw_constraint_list *sysclk_constraints;
 };
 
 static const u16 wm8741_reg_defaults[WM8741_REGISTER_COUNT] = {
@@ -111,10 +107,84 @@ static struct {
        int value;
        int ratio;
 } lrclk_ratios[WM8741_NUM_RATES] = {
-       { 1, 256 },
-       { 2, 384 },
-       { 3, 512 },
-       { 4, 768 },
+       { 1, 128 },
+       { 2, 192 },
+       { 3, 256 },
+       { 4, 384 },
+       { 5, 512 },
+       { 6, 768 },
+};
+
+static unsigned int rates_11289[] = {
+       44100, 88235,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_11289 = {
+       .count  = ARRAY_SIZE(rates_11289),
+       .list   = rates_11289,
+};
+
+static unsigned int rates_12288[] = {
+       32000, 48000, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_12288 = {
+       .count  = ARRAY_SIZE(rates_12288),
+       .list   = rates_12288,
+};
+
+static unsigned int rates_16384[] = {
+       32000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_16384 = {
+       .count  = ARRAY_SIZE(rates_16384),
+       .list   = rates_16384,
+};
+
+static unsigned int rates_16934[] = {
+       44100, 88235,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_16934 = {
+       .count  = ARRAY_SIZE(rates_16934),
+       .list   = rates_16934,
+};
+
+static unsigned int rates_18432[] = {
+       48000, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_18432 = {
+       .count  = ARRAY_SIZE(rates_18432),
+       .list   = rates_18432,
+};
+
+static unsigned int rates_22579[] = {
+       44100, 88235, 1764000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_22579 = {
+       .count  = ARRAY_SIZE(rates_22579),
+       .list   = rates_22579,
+};
+
+static unsigned int rates_24576[] = {
+       32000, 48000, 96000, 192000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_24576 = {
+       .count  = ARRAY_SIZE(rates_24576),
+       .list   = rates_24576,
+};
+
+static unsigned int rates_36864[] = {
+       48000, 96000, 19200
+};
+
+static struct snd_pcm_hw_constraint_list constraints_36864 = {
+       .count  = ARRAY_SIZE(rates_36864),
+       .list   = rates_36864,
 };
 
 
@@ -135,7 +205,7 @@ static int wm8741_startup(struct snd_pcm_substream *substream,
 
        snd_pcm_hw_constraint_list(substream->runtime, 0,
                                   SNDRV_PCM_HW_PARAM_RATE,
-                                  &wm8741->rate_constraint);
+                                  wm8741->sysclk_constraints);
 
        return 0;
 }
@@ -145,8 +215,7 @@ static int wm8741_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1FC;
        int i;
@@ -196,47 +265,52 @@ static int wm8741_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
-       unsigned int val;
-       int i;
 
        dev_dbg(codec->dev, "wm8741_set_dai_sysclk info: freq=%dHz\n", freq);
 
-       wm8741->sysclk = freq;
-
-       wm8741->rate_constraint.count = 0;
-
-       for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {
-               dev_dbg(codec->dev, "index = %d, ratio = %d, freq = %d",
-                               i, lrclk_ratios[i].ratio, freq);
-
-               val = freq / lrclk_ratios[i].ratio;
-               /* Check that it's a standard rate since core can't
-                * cope with others and having the odd rates confuses
-                * constraint matching.
-                */
-               switch (val) {
-               case 32000:
-               case 44100:
-               case 48000:
-               case 64000:
-               case 88200:
-               case 96000:
-                       dev_dbg(codec->dev, "Supported sample rate: %dHz\n",
-                               val);
-                       wm8741->rate_constraint_list[i] = val;
-                       wm8741->rate_constraint.count++;
-                       break;
-               default:
-                       dev_dbg(codec->dev, "Skipping sample rate: %dHz\n",
-                               val);
-               }
+       switch (freq) {
+       case 11289600:
+               wm8741->sysclk_constraints = &constraints_11289;
+               wm8741->sysclk = freq;
+               return 0;
+
+       case 12288000:
+               wm8741->sysclk_constraints = &constraints_12288;
+               wm8741->sysclk = freq;
+               return 0;
+
+       case 16384000:
+               wm8741->sysclk_constraints = &constraints_16384;
+               wm8741->sysclk = freq;
+               return 0;
+
+       case 16934400:
+               wm8741->sysclk_constraints = &constraints_16934;
+               wm8741->sysclk = freq;
+               return 0;
+
+       case 18432000:
+               wm8741->sysclk_constraints = &constraints_18432;
+               wm8741->sysclk = freq;
+               return 0;
+
+       case 22579200:
+       case 33868800:
+               wm8741->sysclk_constraints = &constraints_22579;
+               wm8741->sysclk = freq;
+               return 0;
+
+       case 24576000:
+               wm8741->sysclk_constraints = &constraints_24576;
+               wm8741->sysclk = freq;
+               return 0;
+
+       case 36864000:
+               wm8741->sysclk_constraints = &constraints_36864;
+               wm8741->sysclk = freq;
+               return 0;
        }
-
-       /* Need at least one supported rate... */
-       if (wm8741->rate_constraint.count == 0)
-               return -EINVAL;
-
-       return 0;
+       return -EINVAL;
 }
 
 static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
@@ -314,8 +388,8 @@ static struct snd_soc_dai_ops wm8741_dai_ops = {
        .set_fmt        = wm8741_set_dai_fmt,
 };
 
-struct snd_soc_dai wm8741_dai = {
-       .name = "WM8741",
+static struct snd_soc_dai_driver wm8741_dai = {
+       .name = "wm8741",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,  /* Mono modes not yet supported */
@@ -325,13 +399,10 @@ struct snd_soc_dai wm8741_dai = {
        },
        .ops = &wm8741_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8741_dai);
 
 #ifdef CONFIG_PM
-static int wm8741_resume(struct platform_device *pdev)
+static int wm8741_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        u16 *cache = codec->reg_cache;
        int i;
 
@@ -348,189 +419,99 @@ static int wm8741_resume(struct platform_device *pdev)
 #define wm8741_resume NULL
 #endif
 
-static int wm8741_probe(struct platform_device *pdev)
+static int wm8741_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
+       struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
 
-       if (wm8741_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8741->control_type);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
-       socdev->card->codec = wm8741_codec;
-       codec = wm8741_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       ret = wm8741_reset(codec);
        if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
+               dev_err(codec->dev, "Failed to issue reset\n");
+               return ret;
        }
 
+       /* Change some default settings - latch VU */
+       wm8741->reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL;
+       wm8741->reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM;
+       wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL;
+       wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM;
+
        snd_soc_add_controls(codec, wm8741_snd_controls,
                             ARRAY_SIZE(wm8741_snd_controls));
        wm8741_add_widgets(codec);
 
-       return ret;
-
-pcm_err:
+       dev_dbg(codec->dev, "Successful registration\n");
        return ret;
 }
 
-static int wm8741_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8741 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm8741 = {
        .probe =        wm8741_probe,
-       .remove =       wm8741_remove,
        .resume =       wm8741_resume,
+       .reg_cache_size = ARRAY_SIZE(wm8741_reg_defaults),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = &wm8741_reg_defaults,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8741);
 
-static int wm8741_register(struct wm8741_priv *wm8741,
-                          enum snd_soc_control_type control)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static int wm8741_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
 {
-       int ret;
-       struct snd_soc_codec *codec = &wm8741->codec;
-       int i;
-
-       if (wm8741_codec) {
-               dev_err(codec->dev, "Another WM8741 is registered\n");
-               return -EINVAL;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8741);
-       codec->name = "WM8741";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = NULL;
-       codec->dai = &wm8741_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8741_REGISTER_COUNT;
-       codec->reg_cache = &wm8741->reg_cache;
-
-       wm8741->rate_constraint.list = &wm8741->rate_constraint_list[0];
-       wm8741->rate_constraint.count =
-               ARRAY_SIZE(wm8741->rate_constraint_list);
-
-       memcpy(codec->reg_cache, wm8741_reg_defaults,
-               sizeof(wm8741->reg_cache));
+       struct wm8741_priv *wm8741;
+       int ret, i;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
-       }
+       wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL);
+       if (wm8741 == NULL)
+               return -ENOMEM;
 
        for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
                wm8741->supplies[i].supply = wm8741_supply_names[i];
 
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8741->supplies),
+       ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8741->supplies),
                                 wm8741->supplies);
        if (ret != 0) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
                goto err;
        }
 
        ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies),
                                    wm8741->supplies);
        if (ret != 0) {
-               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
                goto err_get;
        }
 
-       ret = wm8741_reset(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset\n");
-               goto err_enable;
-       }
-
-       wm8741_dai.dev = codec->dev;
-
-       /* Change some default settings - latch VU */
-       wm8741->reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL;
-       wm8741->reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM;
-       wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL;
-       wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM;
-
-       wm8741_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               return ret;
-       }
-
-       ret = snd_soc_register_dai(&wm8741_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               snd_soc_unregister_codec(codec);
-               return ret;
-       }
+       i2c_set_clientdata(i2c, wm8741);
+       wm8741->control_type = SND_SOC_I2C;
 
-       dev_dbg(codec->dev, "Successful registration\n");
-       return 0;
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8741, &wm8741_dai, 1);
+       if (ret < 0)
+               goto err_enable;
+       return ret;
 
 err_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
 
 err_get:
        regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
-
 err:
        kfree(wm8741);
        return ret;
 }
 
-static void wm8741_unregister(struct wm8741_priv *wm8741)
-{
-       regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
-
-       snd_soc_unregister_dai(&wm8741_dai);
-       snd_soc_unregister_codec(&wm8741->codec);
-       kfree(wm8741);
-       wm8741_codec = NULL;
-}
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static __devinit int wm8741_i2c_probe(struct i2c_client *i2c,
-                                     const struct i2c_device_id *id)
-{
-       struct wm8741_priv *wm8741;
-       struct snd_soc_codec *codec;
-
-       wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL);
-       if (wm8741 == NULL)
-               return -ENOMEM;
-
-       codec = &wm8741->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
-       i2c_set_clientdata(i2c, wm8741);
-       codec->control_data = i2c;
-
-       codec->dev = &i2c->dev;
-
-       return wm8741_register(wm8741, SND_SOC_I2C);
-}
-
-static __devexit int wm8741_i2c_remove(struct i2c_client *client)
+static int wm8741_i2c_remove(struct i2c_client *client)
 {
        struct wm8741_priv *wm8741 = i2c_get_clientdata(client);
-       wm8741_unregister(wm8741);
+
+       snd_soc_unregister_codec(&client->dev);
+       regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -540,29 +521,28 @@ static const struct i2c_device_id wm8741_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id);
 
-
 static struct i2c_driver wm8741_i2c_driver = {
        .driver = {
-               .name = "WM8741",
+               .name = "wm8741-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8741_i2c_probe,
-       .remove =   __devexit_p(wm8741_i2c_remove),
+       .remove =   wm8741_i2c_remove,
        .id_table = wm8741_i2c_id,
 };
 #endif
 
 static int __init wm8741_modinit(void)
 {
-       int ret;
+       int ret = 0;
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8741_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8741 I2C driver: %d\n",
-                      ret);
-       }
+       if (ret != 0)
+               pr_err("Failed to register WM8741 I2C driver: %d\n", ret);
 #endif
-       return 0;
+
+       return ret;
 }
 module_init(wm8741_modinit);
 
index fdef6ecd1f6f14db43fe2a59b4f53e9d937d5b98..56c1b1d4a68100f52fcf6ec61363a9140e88e63a 100644 (file)
 
 #define  WM8741_SYSCLK 0
 
-extern struct snd_soc_dai wm8741_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8741;
-
 #endif
index e2c05e3e323a0bb24010d55bf7e8800c1b1c07c0..6c924cd2cfd45a2149f07ca917a4e36faf8149b0 100644 (file)
@@ -52,7 +52,7 @@ static const u16 wm8750_reg[] = {
 /* codec private data */
 struct wm8750_priv {
        unsigned int sysclk;
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
        u16 reg_cache[ARRAY_SIZE(wm8750_reg)];
 };
 
@@ -560,8 +560,7 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8750_IFACE) & 0x1f3;
        u16 srate = snd_soc_read(codec, WM8750_SRATE) & 0x1c0;
@@ -649,8 +648,8 @@ static struct snd_soc_dai_ops wm8750_dai_ops = {
        .set_sysclk     = wm8750_set_dai_sysclk,
 };
 
-struct snd_soc_dai wm8750_dai = {
-       .name = "WM8750",
+static struct snd_soc_dai_driver wm8750_dai = {
+       .name = "wm8750-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -665,21 +664,15 @@ struct snd_soc_dai wm8750_dai = {
                .formats = WM8750_FORMATS,},
        .ops = &wm8750_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8750_dai);
 
-static int wm8750_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8750_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8750_resume(struct platform_device *pdev)
+static int wm8750_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -698,100 +691,21 @@ static int wm8750_resume(struct platform_device *pdev)
        return 0;
 }
 
-static struct snd_soc_codec *wm8750_codec;
-
-static int wm8750_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (!wm8750_codec) {
-               dev_err(&pdev->dev, "WM8750 codec not yet registered\n");
-               return -EINVAL;
-       }
-
-       socdev->card->codec = wm8750_codec;
-       codec = wm8750_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8750: failed to create pcms\n");
-               goto err;
-       }
-
-       snd_soc_add_controls(codec, wm8750_snd_controls,
-                               ARRAY_SIZE(wm8750_snd_controls));
-       wm8750_add_widgets(codec);
-
-       return 0;
-
-err:
-       return ret;
-}
-
-/* power down chip */
-static int wm8750_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8750 = {
-       .probe          = wm8750_probe,
-       .remove         = wm8750_remove,
-       .suspend        = wm8750_suspend,
-       .resume         = wm8750_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750);
-
-/*
- * initialise the WM8750 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int wm8750_register(struct wm8750_priv *wm8750,
-                       enum snd_soc_control_type control)
+static int wm8750_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = &wm8750->codec;
-       int reg, ret = 0;
-
-       if (wm8750_codec) {
-               dev_err(codec->dev, "Multiple WM8750 devices not supported\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->name = "WM8750";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_STANDBY;
-       codec->set_bias_level = wm8750_set_bias_level;
-       codec->dai = &wm8750_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(wm8750->reg_cache) + 1;
-       codec->reg_cache = &wm8750->reg_cache;
-       snd_soc_codec_set_drvdata(codec, wm8750);
-
-       memcpy(codec->reg_cache, wm8750_reg, sizeof(wm8750->reg_cache));
+       struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec);
+       int reg, ret;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8750->control_type);
        if (ret < 0) {
                printk(KERN_ERR "wm8750: failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        ret = wm8750_reset(codec);
        if (ret < 0) {
                printk(KERN_ERR "wm8750: failed to reset: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        /* charge output caps */
@@ -815,150 +729,130 @@ static int wm8750_register(struct wm8750_priv *wm8750,
        reg = snd_soc_read(codec, WM8750_RINVOL);
        snd_soc_write(codec, WM8750_RINVOL, reg | 0x0100);
 
-       wm8750_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dais(&wm8750_dai, 1);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
-               goto err_codec;
-       }
-
-       return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm8750);
+       snd_soc_add_controls(codec, wm8750_snd_controls,
+                               ARRAY_SIZE(wm8750_snd_controls));
+       wm8750_add_widgets(codec);
        return ret;
 }
 
-static void wm8750_unregister(struct wm8750_priv *wm8750)
+static int wm8750_remove(struct snd_soc_codec *codec)
 {
-       wm8750_set_bias_level(&wm8750->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dais(&wm8750_dai, 1);
-       snd_soc_unregister_codec(&wm8750->codec);
-       kfree(wm8750);
-       wm8750_codec = NULL;
+       wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-/*
- * WM8750 2 wire address is determined by GPIO5
- * state during powerup.
- *    low  = 0x1a
- *    high = 0x1b
- */
+static struct snd_soc_codec_driver soc_codec_dev_wm8750 = {
+       .probe =        wm8750_probe,
+       .remove =       wm8750_remove,
+       .suspend =      wm8750_suspend,
+       .resume =       wm8750_resume,
+       .set_bias_level = wm8750_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8750_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8750_reg,
+};
 
-static int wm8750_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8750_spi_probe(struct spi_device *spi)
 {
-       struct snd_soc_codec *codec;
        struct wm8750_priv *wm8750;
+       int ret;
 
        wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL);
        if (wm8750 == NULL)
                return -ENOMEM;
 
-       codec = &wm8750->codec;
-       codec->control_data = i2c;
-       i2c_set_clientdata(i2c, wm8750);
-
-       codec->dev = &i2c->dev;
+       wm8750->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8750);
 
-       return wm8750_register(wm8750, SND_SOC_I2C);
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_wm8750, &wm8750_dai, 1);
+       if (ret < 0)
+               kfree(wm8750);
+       return ret;
 }
 
-static int wm8750_i2c_remove(struct i2c_client *client)
+static int __devexit wm8750_spi_remove(struct spi_device *spi)
 {
-       struct wm8750_priv *wm8750 = i2c_get_clientdata(client);
-       wm8750_unregister(wm8750);
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
-static const struct i2c_device_id wm8750_i2c_id[] = {
-       { "wm8750", 0 },
-       { "wm8987", 0 }, /* WM8987 is register compatible with WM8750 */
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id);
-
-static struct i2c_driver wm8750_i2c_driver = {
+static struct spi_driver wm8750_spi_driver = {
        .driver = {
-               .name = "WM8750 I2C Codec",
-               .owner = THIS_MODULE,
+               .name   = "wm8750-codec",
+               .owner  = THIS_MODULE,
        },
-       .probe =    wm8750_i2c_probe,
-       .remove =   wm8750_i2c_remove,
-       .id_table = wm8750_i2c_id,
+       .probe          = wm8750_spi_probe,
+       .remove         = __devexit_p(wm8750_spi_remove),
 };
-#endif
+#endif /* CONFIG_SPI_MASTER */
 
-#if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8750_spi_probe(struct spi_device *spi)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8750_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
-       struct snd_soc_codec *codec;
        struct wm8750_priv *wm8750;
+       int ret;
 
        wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL);
        if (wm8750 == NULL)
                return -ENOMEM;
 
-       codec = &wm8750->codec;
-       codec->control_data = spi;
-       codec->dev = &spi->dev;
-
-       dev_set_drvdata(&spi->dev, wm8750);
+       i2c_set_clientdata(i2c, wm8750);
+       wm8750->control_type = SND_SOC_I2C;
 
-       return wm8750_register(wm8750, SND_SOC_SPI);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8750, &wm8750_dai, 1);
+       if (ret < 0)
+               kfree(wm8750);
+       return ret;
 }
 
-static int __devexit wm8750_spi_remove(struct spi_device *spi)
+static __devexit int wm8750_i2c_remove(struct i2c_client *client)
 {
-       struct wm8750_priv *wm8750 = dev_get_drvdata(&spi->dev);
-       wm8750_unregister(wm8750);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
-static const struct spi_device_id wm8750_spi_id[] = {
+static const struct i2c_device_id wm8750_i2c_id[] = {
        { "wm8750", 0 },
        { "wm8987", 0 },
        { }
 };
-MODULE_DEVICE_TABLE(spi, wm8750_spi_id);
+MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id);
 
-static struct spi_driver wm8750_spi_driver = {
+static struct i2c_driver wm8750_i2c_driver = {
        .driver = {
-               .name   = "WM8750 SPI Codec",
-               .bus    = &spi_bus_type,
-               .owner  = THIS_MODULE,
+               .name = "wm8750-codec",
+               .owner = THIS_MODULE,
        },
-       .probe          = wm8750_spi_probe,
-       .remove         = __devexit_p(wm8750_spi_remove),
-       .id_table       = wm8750_spi_id,
+       .probe =    wm8750_i2c_probe,
+       .remove =   __devexit_p(wm8750_i2c_remove),
+       .id_table = wm8750_i2c_id,
 };
 #endif
 
 static int __init wm8750_modinit(void)
 {
-       int ret;
+       int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8750_i2c_driver);
-       if (ret != 0)
-               pr_err("Failed to register WM8750 I2C driver: %d\n", ret);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8750 I2C driver: %d\n",
+                      ret);
+       }
 #endif
 #if defined(CONFIG_SPI_MASTER)
        ret = spi_register_driver(&wm8750_spi_driver);
-       if (ret != 0)
-               pr_err("Failed to register WM8750 SPI driver: %d\n", ret);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8750 SPI driver: %d\n",
+                      ret);
+       }
 #endif
-       return 0;
+       return ret;
 }
 module_init(wm8750_modinit);
 
index 1dc100e19cfe3076019a4c564999f4e061844b4d..121427c047fbfd267cbf2fd2f44f588a6b5f6ff6 100644 (file)
 
 #define WM8750_SYSCLK  0
 
-struct wm8750_setup_data {
-       int spi;
-       int i2c_bus;
-       unsigned short i2c_address;
-};
-
-extern struct snd_soc_dai wm8750_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8750;
-
 #endif
index b59f349c52184fc9bf83a975f8e921f2fda92632..8f679a13f2bcaae23653adaffafff6fedcd8e66f 100644 (file)
@@ -57,7 +57,7 @@ module_param(caps_charge, int, 0);
 MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)");
 
 static void wm8753_set_dai_mode(struct snd_soc_codec *codec,
-       unsigned int mode);
+               struct snd_soc_dai *dai, unsigned int hifi);
 
 /*
  * wm8753 register cache
@@ -85,10 +85,11 @@ static const u16 wm8753_reg[] = {
 
 /* codec private data */
 struct wm8753_priv {
+       enum snd_soc_control_type control_type;
        unsigned int sysclk;
        unsigned int pcmclk;
-       struct snd_soc_codec codec;
        u16 reg_cache[ARRAY_SIZE(wm8753_reg)];
+       int dai_func;
 };
 
 /*
@@ -228,6 +229,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
        int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL);
+       struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
 
        if (((mode & 0xc) >> 2) == ucontrol->value.integer.value[0])
                return 0;
@@ -235,8 +237,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
        mode &= 0xfff3;
        mode |= (ucontrol->value.integer.value[0] << 2);
 
-       wm8753_write(codec, WM8753_IOCTL, mode);
-       wm8753_set_dai_mode(codec, ucontrol->value.integer.value[0]);
+       wm8753->dai_func =  ucontrol->value.integer.value[0];
        return 1;
 }
 
@@ -904,6 +905,13 @@ static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai,
        return 0;
 }
 
+static int wm8753_pcm_startup(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       wm8753_set_dai_mode(dai->codec, dai, 0);
+       return 0;
+}
+
 /*
  * Set PCM DAI bit size and sample rate.
  */
@@ -912,8 +920,7 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
        u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3;
        u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f;
@@ -1138,6 +1145,13 @@ static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
        return 0;
 }
 
+static int wm8753_i2s_startup(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       wm8753_set_dai_mode(dai->codec, dai, 1);
+       return 0;
+}
+
 /*
  * Set PCM DAI bit size and sample rate.
  */
@@ -1146,8 +1160,7 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
        u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0;
        u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3;
@@ -1240,12 +1253,12 @@ static int wm8753_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
        u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7;
+       struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
 
        /* the digital mute covers the HiFi and Voice DAC's on the WM8753.
         * make sure we check if they are not both active when we mute */
-       if (mute && dai->id == 1) {
-               if (!wm8753_dai[WM8753_DAI_VOICE].playback.active ||
-                       !wm8753_dai[WM8753_DAI_HIFI].playback.active)
+       if (mute && wm8753->dai_func == 1) {
+               if (!codec->active)
                        wm8753_write(codec, WM8753_DAC, mute_reg | 0x8);
        } else {
                if (mute)
@@ -1303,6 +1316,7 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec,
  * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture
  */
 static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = {
+       .startup = wm8753_i2s_startup,
        .hw_params      = wm8753_i2s_hw_params,
        .digital_mute   = wm8753_mute,
        .set_fmt        = wm8753_mode1h_set_dai_fmt,
@@ -1312,6 +1326,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = {
 };
 
 static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = {
+       .startup = wm8753_pcm_startup,
        .hw_params      = wm8753_pcm_hw_params,
        .digital_mute   = wm8753_mute,
        .set_fmt        = wm8753_mode1v_set_dai_fmt,
@@ -1321,6 +1336,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = {
 };
 
 static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = {
+       .startup = wm8753_pcm_startup,
        .hw_params      = wm8753_pcm_hw_params,
        .digital_mute   = wm8753_mute,
        .set_fmt        = wm8753_mode2_set_dai_fmt,
@@ -1330,6 +1346,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = {
 };
 
 static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3        = {
+       .startup = wm8753_i2s_startup,
        .hw_params      = wm8753_i2s_hw_params,
        .digital_mute   = wm8753_mute,
        .set_fmt        = wm8753_mode3_4_set_dai_fmt,
@@ -1339,6 +1356,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3   = {
 };
 
 static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4        = {
+       .startup = wm8753_i2s_startup,
        .hw_params      = wm8753_i2s_hw_params,
        .digital_mute   = wm8753_mute,
        .set_fmt        = wm8753_mode3_4_set_dai_fmt,
@@ -1347,10 +1365,9 @@ static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4  = {
        .set_sysclk     = wm8753_set_dai_sysclk,
 };
 
-static const struct snd_soc_dai wm8753_all_dai[] = {
+static struct snd_soc_dai_driver wm8753_all_dai[] = {
 /* DAI HiFi mode 1 */
-{      .name = "WM8753 HiFi",
-       .id = 1,
+{      .name = "wm8753-hifi",
        .playback = {
                .stream_name = "HiFi Playback",
                .channels_min = 1,
@@ -1366,8 +1383,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
        .ops = &wm8753_dai_ops_hifi_mode1,
 },
 /* DAI Voice mode 1 */
-{      .name = "WM8753 Voice",
-       .id = 1,
+{      .name = "wm8753-voice",
        .playback = {
                .stream_name = "Voice Playback",
                .channels_min = 1,
@@ -1383,12 +1399,10 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
        .ops = &wm8753_dai_ops_voice_mode1,
 },
 /* DAI HiFi mode 2 - dummy */
-{      .name = "WM8753 HiFi",
-       .id = 2,
+{      .name = "wm8753-hifi",
 },
 /* DAI Voice mode 2 */
-{      .name = "WM8753 Voice",
-       .id = 2,
+{      .name = "wm8753-voice",
        .playback = {
                .stream_name = "Voice Playback",
                .channels_min = 1,
@@ -1404,8 +1418,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
        .ops = &wm8753_dai_ops_voice_mode2,
 },
 /* DAI HiFi mode 3 */
-{      .name = "WM8753 HiFi",
-       .id = 3,
+{      .name = "wm8753-hifi",
        .playback = {
                .stream_name = "HiFi Playback",
                .channels_min = 1,
@@ -1421,12 +1434,10 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
        .ops = &wm8753_dai_ops_hifi_mode3,
 },
 /* DAI Voice mode 3 - dummy */
-{      .name = "WM8753 Voice",
-       .id = 3,
+{      .name = "wm8753-voice",
 },
 /* DAI HiFi mode 4 */
-{      .name = "WM8753 HiFi",
-       .id = 4,
+{      .name = "wm8753-hifi",
        .playback = {
                .stream_name = "HiFi Playback",
                .channels_min = 1,
@@ -1442,58 +1453,31 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
        .ops = &wm8753_dai_ops_hifi_mode4,
 },
 /* DAI Voice mode 4 - dummy */
-{      .name = "WM8753 Voice",
-       .id = 4,
+{      .name = "wm8753-voice",
 },
 };
 
-struct snd_soc_dai wm8753_dai[] = {
+static struct snd_soc_dai_driver wm8753_dai[] = {
        {
-               .name = "WM8753 DAI 0",
+               .name = "wm8753-aif0",
        },
        {
-               .name = "WM8753 DAI 1",
+               .name = "wm8753-aif1",
        },
 };
-EXPORT_SYMBOL_GPL(wm8753_dai);
 
-static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode)
+static void wm8753_set_dai_mode(struct snd_soc_codec *codec,
+               struct snd_soc_dai *dai, unsigned int hifi)
 {
-       if (mode < 4) {
-               int playback_active, capture_active, codec_active, pop_wait;
-               void *private_data;
-               struct list_head list;
-
-               playback_active = wm8753_dai[0].playback.active;
-               capture_active = wm8753_dai[0].capture.active;
-               codec_active = wm8753_dai[0].active;
-               private_data = wm8753_dai[0].private_data;
-               pop_wait = wm8753_dai[0].pop_wait;
-               list = wm8753_dai[0].list;
-               wm8753_dai[0] = wm8753_all_dai[mode << 1];
-               wm8753_dai[0].playback.active = playback_active;
-               wm8753_dai[0].capture.active = capture_active;
-               wm8753_dai[0].active = codec_active;
-               wm8753_dai[0].private_data = private_data;
-               wm8753_dai[0].pop_wait = pop_wait;
-               wm8753_dai[0].list = list;
-
-               playback_active = wm8753_dai[1].playback.active;
-               capture_active = wm8753_dai[1].capture.active;
-               codec_active = wm8753_dai[1].active;
-               private_data = wm8753_dai[1].private_data;
-               pop_wait = wm8753_dai[1].pop_wait;
-               list = wm8753_dai[1].list;
-               wm8753_dai[1] = wm8753_all_dai[(mode << 1) + 1];
-               wm8753_dai[1].playback.active = playback_active;
-               wm8753_dai[1].capture.active = capture_active;
-               wm8753_dai[1].active = codec_active;
-               wm8753_dai[1].private_data = private_data;
-               wm8753_dai[1].pop_wait = pop_wait;
-               wm8753_dai[1].list = list;
+       struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+
+       if (wm8753->dai_func < 4) {
+               if (hifi)
+                       dai->driver = &wm8753_all_dai[wm8753->dai_func << 1];
+               else
+                       dai->driver = &wm8753_all_dai[(wm8753->dai_func << 1) + 1];
        }
-       wm8753_dai[0].codec = codec;
-       wm8753_dai[1].codec = codec;
+       wm8753_write(codec, WM8753_IOCTL, wm8753->dai_func);
 }
 
 static void wm8753_work(struct work_struct *work)
@@ -1503,19 +1487,14 @@ static void wm8753_work(struct work_struct *work)
        wm8753_set_bias_level(codec, codec->bias_level);
 }
 
-static int wm8753_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8753_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8753_resume(struct platform_device *pdev)
+static int wm8753_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -1547,41 +1526,6 @@ static int wm8753_resume(struct platform_device *pdev)
        return 0;
 }
 
-static struct snd_soc_codec *wm8753_codec;
-
-static int wm8753_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (!wm8753_codec) {
-               dev_err(&pdev->dev, "WM8753 codec not yet registered\n");
-               return -EINVAL;
-       }
-
-       socdev->card->codec = wm8753_codec;
-       codec = wm8753_codec;
-
-       wm8753_set_dai_mode(codec, 0);
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8753: failed to create pcms\n");
-               goto pcm_err;
-       }
-
-       snd_soc_add_controls(codec, wm8753_snd_controls,
-                            ARRAY_SIZE(wm8753_snd_controls));
-       wm8753_add_widgets(codec);
-
-       return 0;
-
-pcm_err:
-       return ret;
-}
-
 /*
  * This function forces any delayed work to be queued and run.
  */
@@ -1601,62 +1545,28 @@ static int run_delayed_work(struct delayed_work *dwork)
        return ret;
 }
 
-/* power down chip */
-static int wm8753_remove(struct platform_device *pdev)
+static int wm8753_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8753 = {
-       .probe =        wm8753_probe,
-       .remove =       wm8753_remove,
-       .suspend =      wm8753_suspend,
-       .resume =       wm8753_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753);
+       struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0, reg;
 
-static int wm8753_register(struct wm8753_priv *wm8753)
-{
-       int ret, i;
-       struct snd_soc_codec *codec = &wm8753->codec;
-       u16 reg;
+       INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
 
-       if (wm8753_codec) {
-               dev_err(codec->dev, "Multiple WM8753 devices not supported\n");
-               ret = -EINVAL;
-               goto err;
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8753->control_type);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->name = "WM8753";
-       codec->owner = THIS_MODULE;
-       codec->read = wm8753_read_reg_cache;
-       codec->write = wm8753_write;
-       codec->bias_level = SND_SOC_BIAS_STANDBY;
-       codec->set_bias_level = wm8753_set_bias_level;
-       codec->dai = wm8753_dai;
-       codec->num_dai = 2;
-       codec->reg_cache_size = ARRAY_SIZE(wm8753->reg_cache) + 1;
-       codec->reg_cache = &wm8753->reg_cache;
-       snd_soc_codec_set_drvdata(codec, wm8753);
-
-       memcpy(codec->reg_cache, wm8753_reg, sizeof(wm8753->reg_cache));
-       INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
-
        ret = wm8753_reset(codec);
        if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset\n");
-               goto err;
+               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+               return ret;
        }
 
+       wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       wm8753->dai_func = 0;
+
        /* charge output caps */
        wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
        schedule_delayed_work(&codec->delayed_work,
@@ -1684,165 +1594,133 @@ static int wm8753_register(struct wm8753_priv *wm8753)
        reg = wm8753_read_reg_cache(codec, WM8753_RINVOL);
        wm8753_write(codec, WM8753_RINVOL, reg | 0x0100);
 
-       wm8753_codec = codec;
-
-       for (i = 0; i < ARRAY_SIZE(wm8753_dai); i++)
-               wm8753_dai[i].dev = codec->dev;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai));
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
-               goto err_codec;
-       }
+       snd_soc_add_controls(codec, wm8753_snd_controls,
+                            ARRAY_SIZE(wm8753_snd_controls));
+       wm8753_add_widgets(codec);
 
        return 0;
-
-err_codec:
-       run_delayed_work(&codec->delayed_work);
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm8753);
-       return ret;
 }
 
-static void wm8753_unregister(struct wm8753_priv *wm8753)
+/* power down chip */
+static int wm8753_remove(struct snd_soc_codec *codec)
 {
-       wm8753_set_bias_level(&wm8753->codec, SND_SOC_BIAS_OFF);
-       run_delayed_work(&wm8753->codec.delayed_work);
-       snd_soc_unregister_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai));
-       snd_soc_unregister_codec(&wm8753->codec);
-       kfree(wm8753);
-       wm8753_codec = NULL;
+       run_delayed_work(&codec->delayed_work);
+       wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
 }
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static struct snd_soc_codec_driver soc_codec_dev_wm8753 = {
+       .probe =        wm8753_probe,
+       .remove =       wm8753_remove,
+       .suspend =      wm8753_suspend,
+       .resume =       wm8753_resume,
+       .set_bias_level = wm8753_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8753_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8753_reg,
+};
 
-static int wm8753_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8753_spi_probe(struct spi_device *spi)
 {
-       struct snd_soc_codec *codec;
        struct wm8753_priv *wm8753;
+       int ret;
 
        wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL);
        if (wm8753 == NULL)
                return -ENOMEM;
 
-        codec = &wm8753->codec;
-        codec->hw_write = (hw_write_t)i2c_master_send;
-        codec->control_data = i2c;
-        i2c_set_clientdata(i2c, wm8753);
-
-        codec->dev = &i2c->dev;
+       wm8753->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8753);
 
-       return wm8753_register(wm8753);
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai));
+       if (ret < 0)
+               kfree(wm8753);
+       return ret;
 }
 
-static int wm8753_i2c_remove(struct i2c_client *client)
+static int __devexit wm8753_spi_remove(struct spi_device *spi)
 {
-        struct wm8753_priv *wm8753 = i2c_get_clientdata(client);
-        wm8753_unregister(wm8753);
-        return 0;
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
+       return 0;
 }
 
-static const struct i2c_device_id wm8753_i2c_id[] = {
-       { "wm8753", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id);
-
-static struct i2c_driver wm8753_i2c_driver = {
+static struct spi_driver wm8753_spi_driver = {
        .driver = {
-               .name = "wm8753",
-               .owner = THIS_MODULE,
+               .name   = "wm8753-codec",
+               .owner  = THIS_MODULE,
        },
-       .probe =    wm8753_i2c_probe,
-       .remove =   wm8753_i2c_remove,
-       .id_table = wm8753_i2c_id,
+       .probe          = wm8753_spi_probe,
+       .remove         = __devexit_p(wm8753_spi_remove),
 };
-#endif
-
-#if defined(CONFIG_SPI_MASTER)
-static int wm8753_spi_write(struct spi_device *spi, const char *data, int len)
-{
-       struct spi_transfer t;
-       struct spi_message m;
-       u8 msg[2];
-
-       if (len <= 0)
-               return 0;
+#endif /* CONFIG_SPI_MASTER */
 
-       msg[0] = data[0];
-       msg[1] = data[1];
-
-       spi_message_init(&m);
-       memset(&t, 0, (sizeof t));
-
-       t.tx_buf = &msg[0];
-       t.len = len;
-
-       spi_message_add_tail(&t, &m);
-       spi_sync(spi, &m);
-
-       return len;
-}
-
-static int __devinit wm8753_spi_probe(struct spi_device *spi)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8753_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
-       struct snd_soc_codec *codec;
        struct wm8753_priv *wm8753;
+       int ret;
 
        wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL);
        if (wm8753 == NULL)
                return -ENOMEM;
 
-       codec = &wm8753->codec;
-       codec->control_data = spi;
-       codec->hw_write = (hw_write_t)wm8753_spi_write;
-       codec->dev = &spi->dev;
+       i2c_set_clientdata(i2c, wm8753);
+       wm8753->control_type = SND_SOC_I2C;
 
-       dev_set_drvdata(&spi->dev, wm8753);
-
-       return wm8753_register(wm8753);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai));
+       if (ret < 0)
+               kfree(wm8753);
+       return ret;
 }
 
-static int __devexit wm8753_spi_remove(struct spi_device *spi)
+static __devexit int wm8753_i2c_remove(struct i2c_client *client)
 {
-       struct wm8753_priv *wm8753 = dev_get_drvdata(&spi->dev);
-       wm8753_unregister(wm8753);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
-static struct spi_driver wm8753_spi_driver = {
+static const struct i2c_device_id wm8753_i2c_id[] = {
+       { "wm8753", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id);
+
+static struct i2c_driver wm8753_i2c_driver = {
        .driver = {
-               .name   = "wm8753",
-               .bus    = &spi_bus_type,
-               .owner  = THIS_MODULE,
+               .name = "wm8753-codec",
+               .owner = THIS_MODULE,
        },
-       .probe          = wm8753_spi_probe,
-       .remove         = __devexit_p(wm8753_spi_remove),
+       .probe =    wm8753_i2c_probe,
+       .remove =   __devexit_p(wm8753_i2c_remove),
+       .id_table = wm8753_i2c_id,
 };
 #endif
 
 static int __init wm8753_modinit(void)
 {
-       int ret;
+       int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8753_i2c_driver);
-       if (ret != 0)
-               pr_err("Failed to register WM8753 I2C driver: %d\n", ret);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8753 I2C driver: %d\n",
+                      ret);
+       }
 #endif
 #if defined(CONFIG_SPI_MASTER)
        ret = spi_register_driver(&wm8753_spi_driver);
-       if (ret != 0)
-               pr_err("Failed to register WM8753 SPI driver: %d\n", ret);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8753 SPI driver: %d\n",
+                      ret);
+       }
 #endif
-       return 0;
+       return ret;
 }
 module_init(wm8753_modinit);
 
index 57b2ba244040dea6a26e806c57401cd22a27ebf3..94edac144bcbef3b94754f4d624352f230a4453c 100644 (file)
 #define WM8753_DAI_HIFI                0
 #define WM8753_DAI_VOICE               1
 
-extern struct snd_soc_dai wm8753_dai[2];
-extern struct snd_soc_codec_device soc_codec_dev_wm8753;
-
 #endif
index f8154e661524c64e1098f318d447ba7bfcda3616..04182c464e35ffeffb069ad06242dca74da52248 100644 (file)
 
 #include "wm8776.h"
 
-static struct snd_soc_codec *wm8776_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8776;
-
 /* codec private data */
 struct wm8776_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
        u16 reg_cache[WM8776_CACHEREGNUM];
        int sysclk[2];
 };
 
-#ifdef CONFIG_SPI_MASTER
-static int wm8776_spi_write(struct spi_device *spi, const char *data, int len);
-#endif
-
 static const u16 wm8776_reg[WM8776_CACHEREGNUM] = {
        0x79, 0x79, 0x79, 0xff, 0xff,  /* 4 */
        0xff, 0x00, 0x90, 0x00, 0x00,  /* 9 */
@@ -144,7 +137,7 @@ static int wm8776_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        struct snd_soc_codec *codec = dai->codec;
        int reg, iface, master;
 
-       switch (dai->id) {
+       switch (dai->driver->id) {
        case WM8776_DAI_DAC:
                reg = WM8776_DACIFCTRL;
                master = 0x80;
@@ -226,7 +219,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
 
        iface = 0;
 
-       switch (dai->id) {
+       switch (dai->driver->id) {
        case WM8776_DAI_DAC:
                iface_reg = WM8776_DACIFCTRL;
                master = 0x80;
@@ -260,7 +253,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
        /* Only need to set MCLK/LRCLK ratio if we're master */
        if (snd_soc_read(codec, WM8776_MSTRCTRL) & master) {
                for (i = 0; i < ARRAY_SIZE(mclk_ratios); i++) {
-                       if (wm8776->sysclk[dai->id] / params_rate(params)
+                       if (wm8776->sysclk[dai->driver->id] / params_rate(params)
                            == mclk_ratios[i])
                                break;
                }
@@ -268,7 +261,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
                if (i == ARRAY_SIZE(mclk_ratios)) {
                        dev_err(codec->dev,
                                "Unable to configure MCLK ratio %d/%d\n",
-                               wm8776->sysclk[dai->id], params_rate(params));
+                               wm8776->sysclk[dai->driver->id], params_rate(params));
                        return -EINVAL;
                }
 
@@ -298,9 +291,9 @@ static int wm8776_set_sysclk(struct snd_soc_dai *dai,
        struct snd_soc_codec *codec = dai->codec;
        struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
 
-       BUG_ON(dai->id >= ARRAY_SIZE(wm8776->sysclk));
+       BUG_ON(dai->driver->id >= ARRAY_SIZE(wm8776->sysclk));
 
-       wm8776->sysclk[dai->id] = freq;
+       wm8776->sysclk[dai->driver->id] = freq;
 
        return 0;
 }
@@ -350,10 +343,10 @@ static struct snd_soc_dai_ops wm8776_adc_ops = {
        .set_sysclk     = wm8776_set_sysclk,
 };
 
-struct snd_soc_dai wm8776_dai[] = {
+static struct snd_soc_dai_driver wm8776_dai[] = {
        {
-               .name = "WM8776 Playback",
-               .id = WM8776_DAI_DAC,
+               .name = "wm8776-hifi-playback",
+               .id     = WM8776_DAI_DAC,
                .playback = {
                        .stream_name = "Playback",
                        .channels_min = 2,
@@ -364,8 +357,8 @@ struct snd_soc_dai wm8776_dai[] = {
                .ops = &wm8776_dac_ops,
        },
        {
-               .name = "WM8776 Capture",
-               .id = WM8776_DAI_ADC,
+               .name = "wm8776-hifi-capture",
+               .id     = WM8776_DAI_ADC,
                .capture = {
                        .stream_name = "Capture",
                        .channels_min = 2,
@@ -376,23 +369,17 @@ struct snd_soc_dai wm8776_dai[] = {
                .ops = &wm8776_adc_ops,
        },
 };
-EXPORT_SYMBOL_GPL(wm8776_dai);
 
 #ifdef CONFIG_PM
-static int wm8776_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8776_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int wm8776_resume(struct platform_device *pdev)
+static int wm8776_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -415,27 +402,30 @@ static int wm8776_resume(struct platform_device *pdev)
 #define wm8776_resume NULL
 #endif
 
-static int wm8776_probe(struct platform_device *pdev)
+static int wm8776_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
+       struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
 
-       if (wm8776_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8776->control_type);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
-       socdev->card->codec = wm8776_codec;
-       codec = wm8776_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       ret = wm8776_reset(codec);
        if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
+               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+               return ret;
        }
 
+       wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* Latch the update bits; right channel only since we always
+        * update both. */
+       snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8776_DACRVOL, 0x100, 0x100);
+
        snd_soc_add_controls(codec, wm8776_snd_controls,
                             ARRAY_SIZE(wm8776_snd_controls));
        snd_soc_dapm_new_controls(codec, wm8776_dapm_widgets,
@@ -443,169 +433,56 @@ static int wm8776_probe(struct platform_device *pdev)
        snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes));
 
        return ret;
-
-pcm_err:
-       return ret;
 }
 
 /* power down chip */
-static int wm8776_remove(struct platform_device *pdev)
+static int wm8776_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
+       wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_wm8776 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm8776 = {
        .probe =        wm8776_probe,
        .remove =       wm8776_remove,
        .suspend =      wm8776_suspend,
        .resume =       wm8776_resume,
+       .set_bias_level = wm8776_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8776_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8776_reg,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8776);
-
-static int wm8776_register(struct wm8776_priv *wm8776,
-                          enum snd_soc_control_type control)
-{
-       int ret, i;
-       struct snd_soc_codec *codec = &wm8776->codec;
-
-       if (wm8776_codec) {
-               dev_err(codec->dev, "Another WM8776 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8776);
-       codec->name = "WM8776";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8776_set_bias_level;
-       codec->dai = wm8776_dai;
-       codec->num_dai = ARRAY_SIZE(wm8776_dai);
-       codec->reg_cache_size = WM8776_CACHEREGNUM;
-       codec->reg_cache = &wm8776->reg_cache;
-
-       memcpy(codec->reg_cache, wm8776_reg, sizeof(wm8776_reg));
-
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(wm8776_dai); i++)
-               wm8776_dai[i].dev = codec->dev;
-
-       ret = wm8776_reset(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
-               goto err;
-       }
-
-       wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       /* Latch the update bits; right channel only since we always
-        * update both. */
-       snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100);
-       snd_soc_update_bits(codec, WM8776_DACRVOL, 0x100, 0x100);
-
-       wm8776_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai));
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
-               goto err_codec;
-       }
-
-       return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm8776);
-       return ret;
-}
-
-static void wm8776_unregister(struct wm8776_priv *wm8776)
-{
-       wm8776_set_bias_level(&wm8776->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai));
-       snd_soc_unregister_codec(&wm8776->codec);
-       kfree(wm8776);
-       wm8776_codec = NULL;
-}
 
 #if defined(CONFIG_SPI_MASTER)
-static int wm8776_spi_write(struct spi_device *spi, const char *data, int len)
-{
-       struct spi_transfer t;
-       struct spi_message m;
-       u8 msg[2];
-
-       if (len <= 0)
-               return 0;
-
-       msg[0] = data[0];
-       msg[1] = data[1];
-
-       spi_message_init(&m);
-       memset(&t, 0, (sizeof t));
-
-       t.tx_buf = &msg[0];
-       t.len = len;
-
-       spi_message_add_tail(&t, &m);
-       spi_sync(spi, &m);
-
-       return len;
-}
-
 static int __devinit wm8776_spi_probe(struct spi_device *spi)
 {
-       struct snd_soc_codec *codec;
        struct wm8776_priv *wm8776;
+       int ret;
 
        wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);
        if (wm8776 == NULL)
                return -ENOMEM;
 
-       codec = &wm8776->codec;
-       codec->control_data = spi;
-       codec->hw_write = (hw_write_t)wm8776_spi_write;
-       codec->dev = &spi->dev;
+       wm8776->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8776);
 
-       dev_set_drvdata(&spi->dev, wm8776);
-
-       return wm8776_register(wm8776, SND_SOC_SPI);
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
+       if (ret < 0)
+               kfree(wm8776);
+       return ret;
 }
 
 static int __devexit wm8776_spi_remove(struct spi_device *spi)
 {
-       struct wm8776_priv *wm8776 = dev_get_drvdata(&spi->dev);
-
-       wm8776_unregister(wm8776);
-
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
 static struct spi_driver wm8776_spi_driver = {
        .driver = {
-               .name   = "wm8776",
-               .bus    = &spi_bus_type,
+               .name   = "wm8776-codec",
                .owner  = THIS_MODULE,
        },
        .probe          = wm8776_spi_probe,
@@ -618,27 +495,26 @@ static __devinit int wm8776_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8776_priv *wm8776;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);
        if (wm8776 == NULL)
                return -ENOMEM;
 
-       codec = &wm8776->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
        i2c_set_clientdata(i2c, wm8776);
-       codec->control_data = i2c;
-
-       codec->dev = &i2c->dev;
+       wm8776->control_type = SND_SOC_I2C;
 
-       return wm8776_register(wm8776, SND_SOC_I2C);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
+       if (ret < 0)
+               kfree(wm8776);
+       return ret;
 }
 
 static __devexit int wm8776_i2c_remove(struct i2c_client *client)
 {
-       struct wm8776_priv *wm8776 = i2c_get_clientdata(client);
-       wm8776_unregister(wm8776);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -650,7 +526,7 @@ MODULE_DEVICE_TABLE(i2c, wm8776_i2c_id);
 
 static struct i2c_driver wm8776_i2c_driver = {
        .driver = {
-               .name = "wm8776",
+               .name = "wm8776-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8776_i2c_probe,
@@ -661,22 +537,22 @@ static struct i2c_driver wm8776_i2c_driver = {
 
 static int __init wm8776_modinit(void)
 {
-       int ret;
+       int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8776_i2c_driver);
        if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8776 I2C driver: %d\n",
+               printk(KERN_ERR "Failed to register wm8776 I2C driver: %d\n",
                       ret);
        }
 #endif
 #if defined(CONFIG_SPI_MASTER)
        ret = spi_register_driver(&wm8776_spi_driver);
        if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8776 SPI driver: %d\n",
+               printk(KERN_ERR "Failed to register wm8776 SPI driver: %d\n",
                       ret);
        }
 #endif
-       return 0;
+       return ret;
 }
 module_init(wm8776_modinit);
 
index 6606d25d2d835be7f9558f23981c75b4522d3c9f..4cf1c8e0bfc9e093ecc8f449de7b1db8b1a2062b 100644 (file)
@@ -45,7 +45,4 @@
 #define WM8776_DAI_DAC 0
 #define WM8776_DAI_ADC 1
 
-extern struct snd_soc_dai wm8776_dai[];
-extern struct snd_soc_codec_device soc_codec_dev_wm8776;
-
 #endif
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
new file mode 100644 (file)
index 0000000..4599e8e
--- /dev/null
@@ -0,0 +1,833 @@
+/*
+ * wm8804.c  --  WM8804 S/PDIF transceiver 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/i2c.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/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8804.h"
+
+#define WM8804_NUM_SUPPLIES 2
+static const char *wm8804_supply_names[WM8804_NUM_SUPPLIES] = {
+       "PVDD",
+       "DVDD"
+};
+
+static const u8 wm8804_reg_defs[] = {
+       0x05,     /* R0  - RST/DEVID1 */
+       0x88,     /* R1  - DEVID2 */
+       0x04,     /* R2  - DEVREV */
+       0x21,     /* R3  - PLL1 */
+       0xFD,     /* R4  - PLL2 */
+       0x36,     /* R5  - PLL3 */
+       0x07,     /* R6  - PLL4 */
+       0x16,     /* R7  - PLL5 */
+       0x18,     /* R8  - PLL6 */
+       0xFF,     /* R9  - SPDMODE */
+       0x00,     /* R10 - INTMASK */
+       0x00,     /* R11 - INTSTAT */
+       0x00,     /* R12 - SPDSTAT */
+       0x00,     /* R13 - RXCHAN1 */
+       0x00,     /* R14 - RXCHAN2 */
+       0x00,     /* R15 - RXCHAN3 */
+       0x00,     /* R16 - RXCHAN4 */
+       0x00,     /* R17 - RXCHAN5 */
+       0x00,     /* R18 - SPDTX1 */
+       0x00,     /* R19 - SPDTX2 */
+       0x00,     /* R20 - SPDTX3 */
+       0x71,     /* R21 - SPDTX4 */
+       0x0B,     /* R22 - SPDTX5 */
+       0x70,     /* R23 - GPO0 */
+       0x57,     /* R24 - GPO1 */
+       0x00,     /* R25 */
+       0x42,     /* R26 - GPO2 */
+       0x06,     /* R27 - AIFTX */
+       0x06,     /* R28 - AIFRX */
+       0x80,     /* R29 - SPDRX1 */
+       0x07,     /* R30 - PWRDN */
+};
+
+struct wm8804_priv {
+       enum snd_soc_control_type control_type;
+       struct regulator_bulk_data supplies[WM8804_NUM_SUPPLIES];
+       struct notifier_block disable_nb[WM8804_NUM_SUPPLIES];
+       struct snd_soc_codec *codec;
+};
+
+static int txsrc_get(struct snd_kcontrol *kcontrol,
+                    struct snd_ctl_elem_value *ucontrol);
+
+static int txsrc_put(struct snd_kcontrol *kcontrol,
+                    struct snd_ctl_elem_value *ucontrol);
+
+/*
+ * 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 WM8804_REGULATOR_EVENT(n) \
+static int wm8804_regulator_event_##n(struct notifier_block *nb, \
+                                     unsigned long event, void *data)    \
+{ \
+       struct wm8804_priv *wm8804 = container_of(nb, struct wm8804_priv, \
+                                                 disable_nb[n]); \
+       if (event & REGULATOR_EVENT_DISABLE) { \
+               wm8804->codec->cache_sync = 1; \
+       } \
+       return 0; \
+}
+
+WM8804_REGULATOR_EVENT(0)
+WM8804_REGULATOR_EVENT(1)
+
+static const char *txsrc_text[] = { "S/PDIF RX", "AIF" };
+static const SOC_ENUM_SINGLE_EXT_DECL(txsrc, txsrc_text);
+
+static const struct snd_kcontrol_new wm8804_snd_controls[] = {
+       SOC_ENUM_EXT("Input Source", txsrc, txsrc_get, txsrc_put),
+       SOC_SINGLE("TX Playback Switch", WM8804_PWRDN, 2, 1, 1),
+       SOC_SINGLE("AIF Playback Switch", WM8804_PWRDN, 4, 1, 1)
+};
+
+static int txsrc_get(struct snd_kcontrol *kcontrol,
+                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec;
+       unsigned int src;
+
+       codec = snd_kcontrol_chip(kcontrol);
+       src = snd_soc_read(codec, WM8804_SPDTX4);
+       if (src & 0x40)
+               ucontrol->value.integer.value[0] = 1;
+       else
+               ucontrol->value.integer.value[0] = 0;
+
+       return 0;
+}
+
+static int txsrc_put(struct snd_kcontrol *kcontrol,
+                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec;
+       unsigned int src, txpwr;
+
+       codec = snd_kcontrol_chip(kcontrol);
+
+       if (ucontrol->value.integer.value[0] != 0
+                       && ucontrol->value.integer.value[0] != 1)
+               return -EINVAL;
+
+       src = snd_soc_read(codec, WM8804_SPDTX4);
+       switch ((src & 0x40) >> 6) {
+       case 0:
+               if (!ucontrol->value.integer.value[0])
+                       return 0;
+               break;
+       case 1:
+               if (ucontrol->value.integer.value[1])
+                       return 0;
+               break;
+       }
+
+       /* save the current power state of the transmitter */
+       txpwr = snd_soc_read(codec, WM8804_PWRDN) & 0x4;
+       /* power down the transmitter */
+       snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x4);
+       /* set the tx source */
+       snd_soc_update_bits(codec, WM8804_SPDTX4, 0x40,
+                           ucontrol->value.integer.value[0] << 6);
+
+       if (ucontrol->value.integer.value[0]) {
+               /* power down the receiver */
+               snd_soc_update_bits(codec, WM8804_PWRDN, 0x2, 0x2);
+               /* power up the AIF */
+               snd_soc_update_bits(codec, WM8804_PWRDN, 0x10, 0);
+       } else {
+               /* don't power down the AIF -- may be used as an output */
+               /* power up the receiver */
+               snd_soc_update_bits(codec, WM8804_PWRDN, 0x2, 0);
+       }
+
+       /* restore the transmitter's configuration */
+       snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, txpwr);
+
+       return 0;
+}
+
+static int wm8804_volatile(unsigned int reg)
+{
+       switch (reg) {
+       case WM8804_RST_DEVID1:
+       case WM8804_DEVID2:
+       case WM8804_DEVREV:
+       case WM8804_INTSTAT:
+       case WM8804_SPDSTAT:
+       case WM8804_RXCHAN1:
+       case WM8804_RXCHAN2:
+       case WM8804_RXCHAN3:
+       case WM8804_RXCHAN4:
+       case WM8804_RXCHAN5:
+               return 1;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int wm8804_reset(struct snd_soc_codec *codec)
+{
+       return snd_soc_write(codec, WM8804_RST_DEVID1, 0x0);
+}
+
+static int wm8804_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec;
+       u16 format, master, bcp, lrp;
+
+       codec = dai->codec;
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               format = 0x2;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               format = 0x0;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               format = 0x1;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               format = 0x3;
+               break;
+       default:
+               dev_err(dai->dev, "Unknown dai format\n");
+               return -EINVAL;
+       }
+
+       /* set data format */
+       snd_soc_update_bits(codec, WM8804_AIFTX, 0x3, format);
+       snd_soc_update_bits(codec, WM8804_AIFRX, 0x3, format);
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               master = 1;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               master = 0;
+               break;
+       default:
+               dev_err(dai->dev, "Unknown master/slave configuration\n");
+               return -EINVAL;
+       }
+
+       /* set master/slave mode */
+       snd_soc_update_bits(codec, WM8804_AIFRX, 0x40, master << 6);
+
+       bcp = lrp = 0;
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               bcp = lrp = 1;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               bcp = 1;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               lrp = 1;
+               break;
+       default:
+               dev_err(dai->dev, "Unknown polarity configuration\n");
+               return -EINVAL;
+       }
+
+       /* set frame inversion */
+       snd_soc_update_bits(codec, WM8804_AIFTX, 0x10 | 0x20,
+                           (bcp << 4) | (lrp << 5));
+       snd_soc_update_bits(codec, WM8804_AIFRX, 0x10 | 0x20,
+                           (bcp << 4) | (lrp << 5));
+       return 0;
+}
+
+static int wm8804_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec;
+       u16 blen;
+
+       codec = dai->codec;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               blen = 0x0;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               blen = 0x1;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               blen = 0x2;
+               break;
+       default:
+               dev_err(dai->dev, "Unsupported word length: %u\n",
+                       params_format(params));
+               return -EINVAL;
+       }
+
+       /* set word length */
+       snd_soc_update_bits(codec, WM8804_AIFTX, 0xc, blen << 2);
+       snd_soc_update_bits(codec, WM8804_AIFRX, 0xc, blen << 2);
+
+       return 0;
+}
+
+struct pll_div {
+       u32 prescale:1;
+       u32 mclkdiv:1;
+       u32 freqmode:2;
+       u32 n:4;
+       u32 k:22;
+};
+
+/* PLL rate to output rate divisions */
+static struct {
+       unsigned int div;
+       unsigned int freqmode;
+       unsigned int mclkdiv;
+} post_table[] = {
+       {  2,  0, 0 },
+       {  4,  0, 1 },
+       {  4,  1, 0 },
+       {  8,  1, 1 },
+       {  8,  2, 0 },
+       { 16,  2, 1 },
+       { 12,  3, 0 },
+       { 24,  3, 1 }
+};
+
+#define FIXED_PLL_SIZE ((1ULL << 22) * 10)
+static int pll_factors(struct pll_div *pll_div, unsigned int target,
+                      unsigned int source)
+{
+       u64 Kpart;
+       unsigned long int K, Ndiv, Nmod, tmp;
+       int i;
+
+       /*
+        * Scale the output frequency up; the PLL should run in the
+        * region of 90-100MHz.
+        */
+       for (i = 0; i < ARRAY_SIZE(post_table); i++) {
+               tmp = target * post_table[i].div;
+               if (tmp >= 90000000 && tmp <= 100000000) {
+                       pll_div->freqmode = post_table[i].freqmode;
+                       pll_div->mclkdiv = post_table[i].mclkdiv;
+                       target *= post_table[i].div;
+                       break;
+               }
+       }
+
+       if (i == ARRAY_SIZE(post_table)) {
+               pr_err("%s: Unable to scale output frequency: %uHz\n",
+                      __func__, target);
+               return -EINVAL;
+       }
+
+       pll_div->prescale = 0;
+       Ndiv = target / source;
+       if (Ndiv < 5) {
+               source >>= 1;
+               pll_div->prescale = 1;
+               Ndiv = target / source;
+       }
+
+       if (Ndiv < 5 || Ndiv > 13) {
+               pr_err("%s: WM8804 N value is not within the recommended range: %lu\n",
+                      __func__, Ndiv);
+               return -EINVAL;
+       }
+       pll_div->n = Ndiv;
+
+       Nmod = target % source;
+       Kpart = FIXED_PLL_SIZE * (u64)Nmod;
+
+       do_div(Kpart, source);
+
+       K = Kpart & 0xffffffff;
+       if ((K % 10) >= 5)
+               K += 5;
+       K /= 10;
+       pll_div->k = K;
+
+       return 0;
+}
+
+static int wm8804_set_pll(struct snd_soc_dai *dai, int pll_id,
+                         int source, unsigned int freq_in,
+                         unsigned int freq_out)
+{
+       struct snd_soc_codec *codec;
+
+       codec = dai->codec;
+       if (!freq_in || !freq_out) {
+               /* disable the PLL */
+               snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0x1);
+               return 0;
+       } else {
+               int ret;
+               struct pll_div pll_div;
+
+               ret = pll_factors(&pll_div, freq_out, freq_in);
+               if (ret)
+                       return ret;
+
+               /* power down the PLL before reprogramming it */
+               snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0x1);
+
+               if (!freq_in || !freq_out)
+                       return 0;
+
+               /* set PLLN and PRESCALE */
+               snd_soc_update_bits(codec, WM8804_PLL4, 0xf | 0x10,
+                                   pll_div.n | (pll_div.prescale << 4));
+               /* set mclkdiv and freqmode */
+               snd_soc_update_bits(codec, WM8804_PLL5, 0x3 | 0x8,
+                                   pll_div.freqmode | (pll_div.mclkdiv << 3));
+               /* set PLLK */
+               snd_soc_write(codec, WM8804_PLL1, pll_div.k & 0xff);
+               snd_soc_write(codec, WM8804_PLL2, (pll_div.k >> 8) & 0xff);
+               snd_soc_write(codec, WM8804_PLL3, pll_div.k >> 16);
+
+               /* power up the PLL */
+               snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0);
+       }
+
+       return 0;
+}
+
+static int wm8804_set_sysclk(struct snd_soc_dai *dai,
+                            int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec;
+
+       codec = dai->codec;
+
+       switch (clk_id) {
+       case WM8804_TX_CLKSRC_MCLK:
+               if ((freq >= 10000000 && freq <= 14400000)
+                               || (freq >= 16280000 && freq <= 27000000))
+                       snd_soc_update_bits(codec, WM8804_PLL6, 0x80, 0x80);
+               else {
+                       dev_err(dai->dev, "OSCCLOCK is not within the "
+                               "recommended range: %uHz\n", freq);
+                       return -EINVAL;
+               }
+               break;
+       case WM8804_TX_CLKSRC_PLL:
+               snd_soc_update_bits(codec, WM8804_PLL6, 0x80, 0);
+               break;
+       case WM8804_CLKOUT_SRC_CLK1:
+               snd_soc_update_bits(codec, WM8804_PLL6, 0x8, 0);
+               break;
+       case WM8804_CLKOUT_SRC_OSCCLK:
+               snd_soc_update_bits(codec, WM8804_PLL6, 0x8, 0x8);
+               break;
+       default:
+               dev_err(dai->dev, "Unknown clock source: %d\n", clk_id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int wm8804_set_clkdiv(struct snd_soc_dai *dai,
+                            int div_id, int div)
+{
+       struct snd_soc_codec *codec;
+
+       codec = dai->codec;
+       switch (div_id) {
+       case WM8804_CLKOUT_DIV:
+               snd_soc_update_bits(codec, WM8804_PLL5, 0x30,
+                                   (div & 0x3) << 4);
+               break;
+       default:
+               dev_err(dai->dev, "Unknown clock divider: %d\n", div_id);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static void wm8804_sync_cache(struct snd_soc_codec *codec)
+{
+       short i;
+       u8 *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 == WM8804_RST_DEVID1 || cache[i] == wm8804_reg_defs[i])
+                       continue;
+               snd_soc_write(codec, i, cache[i]);
+       }
+       codec->cache_sync = 0;
+}
+
+static int wm8804_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       int ret;
+       struct wm8804_priv *wm8804;
+
+       wm8804 = snd_soc_codec_get_drvdata(codec);
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               /* power up the OSC and the PLL */
+               snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0);
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
+                                                   wm8804->supplies);
+                       if (ret) {
+                               dev_err(codec->dev,
+                                       "Failed to enable supplies: %d\n",
+                                       ret);
+                               return ret;
+                       }
+                       wm8804_sync_cache(codec);
+               }
+               /* power down the OSC and the PLL */
+               snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0x9);
+               break;
+       case SND_SOC_BIAS_OFF:
+               /* power down the OSC and the PLL */
+               snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0x9);
+               regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies),
+                                      wm8804->supplies);
+               break;
+       }
+
+       codec->bias_level = level;
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm8804_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+       wm8804_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int wm8804_resume(struct snd_soc_codec *codec)
+{
+       wm8804_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       return 0;
+}
+#else
+#define wm8804_suspend NULL
+#define wm8804_resume NULL
+#endif
+
+static int wm8804_remove(struct snd_soc_codec *codec)
+{
+       struct wm8804_priv *wm8804;
+       int i;
+
+       wm8804 = snd_soc_codec_get_drvdata(codec);
+       wm8804_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i)
+               regulator_unregister_notifier(wm8804->supplies[i].consumer,
+                                             &wm8804->disable_nb[i]);
+       regulator_bulk_free(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
+       return 0;
+}
+
+static int wm8804_probe(struct snd_soc_codec *codec)
+{
+       struct wm8804_priv *wm8804;
+       int i, id1, id2, ret;
+
+       wm8804 = snd_soc_codec_get_drvdata(codec);
+       wm8804->codec = codec;
+
+       codec->idle_bias_off = 1;
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, wm8804->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(wm8804->supplies); i++)
+               wm8804->supplies[i].supply = wm8804_supply_names[i];
+
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8804->supplies),
+                                wm8804->supplies);
+       if (ret) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       wm8804->disable_nb[0].notifier_call = wm8804_regulator_event_0;
+       wm8804->disable_nb[1].notifier_call = wm8804_regulator_event_1;
+
+       /* This should really be moved into the regulator core */
+       for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) {
+               ret = regulator_register_notifier(wm8804->supplies[i].consumer,
+                                                 &wm8804->disable_nb[i]);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to register regulator notifier: %d\n",
+                               ret);
+               }
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
+                                   wm8804->supplies);
+       if (ret) {
+               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_reg_get;
+       }
+
+       id1 = snd_soc_read(codec, WM8804_RST_DEVID1);
+       if (id1 < 0) {
+               dev_err(codec->dev, "Failed to read device ID: %d\n", id1);
+               ret = id1;
+               goto err_reg_enable;
+       }
+
+       id2 = snd_soc_read(codec, WM8804_DEVID2);
+       if (id2 < 0) {
+               dev_err(codec->dev, "Failed to read device ID: %d\n", id2);
+               ret = id2;
+               goto err_reg_enable;
+       }
+
+       id2 = (id2 << 8) | id1;
+
+       if (id2 != ((wm8804_reg_defs[WM8804_DEVID2] << 8)
+                       | wm8804_reg_defs[WM8804_RST_DEVID1])) {
+               dev_err(codec->dev, "Invalid device ID: %#x\n", id2);
+               ret = -EINVAL;
+               goto err_reg_enable;
+       }
+
+       ret = snd_soc_read(codec, WM8804_DEVREV);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read device revision: %d\n",
+                       ret);
+               goto err_reg_enable;
+       }
+       dev_info(codec->dev, "revision %c\n", ret + 'A');
+
+       ret = wm8804_reset(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+               goto err_reg_enable;
+       }
+
+       wm8804_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       snd_soc_add_controls(codec, wm8804_snd_controls,
+                            ARRAY_SIZE(wm8804_snd_controls));
+       return 0;
+
+err_reg_enable:
+       regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
+err_reg_get:
+       regulator_bulk_free(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
+       return ret;
+}
+
+static struct snd_soc_dai_ops wm8804_dai_ops = {
+       .hw_params = wm8804_hw_params,
+       .set_fmt = wm8804_set_fmt,
+       .set_sysclk = wm8804_set_sysclk,
+       .set_clkdiv = wm8804_set_clkdiv,
+       .set_pll = wm8804_set_pll
+};
+
+#define WM8804_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver wm8804_dai = {
+       .name = "wm8804-spdif",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_192000,
+               .formats = WM8804_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_192000,
+               .formats = WM8804_FORMATS,
+       },
+       .ops = &wm8804_dai_ops,
+       .symmetric_rates = 1
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
+       .probe = wm8804_probe,
+       .remove = wm8804_remove,
+       .suspend = wm8804_suspend,
+       .resume = wm8804_resume,
+       .set_bias_level = wm8804_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8804_reg_defs),
+       .reg_word_size = sizeof(u8),
+       .reg_cache_default = wm8804_reg_defs,
+       .volatile_register = wm8804_volatile
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8804_spi_probe(struct spi_device *spi)
+{
+       struct wm8804_priv *wm8804;
+       int ret;
+
+       wm8804 = kzalloc(sizeof *wm8804, GFP_KERNEL);
+       if (!wm8804)
+               return -ENOMEM;
+
+       wm8804->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8804);
+
+       ret = snd_soc_register_codec(&spi->dev,
+                                    &soc_codec_dev_wm8804, &wm8804_dai, 1);
+       if (ret < 0)
+               kfree(wm8804);
+       return ret;
+}
+
+static int __devexit wm8804_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
+       return 0;
+}
+
+static struct spi_driver wm8804_spi_driver = {
+       .driver = {
+               .name = "wm8804",
+               .owner = THIS_MODULE,
+       },
+       .probe = wm8804_spi_probe,
+       .remove = __devexit_p(wm8804_spi_remove)
+};
+#endif
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8804_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8804_priv *wm8804;
+       int ret;
+
+       wm8804 = kzalloc(sizeof *wm8804, GFP_KERNEL);
+       if (!wm8804)
+               return -ENOMEM;
+
+       wm8804->control_type = SND_SOC_I2C;
+       i2c_set_clientdata(i2c, wm8804);
+
+       ret = snd_soc_register_codec(&i2c->dev,
+                                    &soc_codec_dev_wm8804, &wm8804_dai, 1);
+       if (ret < 0)
+               kfree(wm8804);
+       return ret;
+}
+
+static __devexit int wm8804_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 wm8804_i2c_id[] = {
+       { "wm8804", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8804_i2c_id);
+
+static struct i2c_driver wm8804_i2c_driver = {
+       .driver = {
+               .name = "wm8804",
+               .owner = THIS_MODULE,
+       },
+       .probe = wm8804_i2c_probe,
+       .remove = __devexit_p(wm8804_i2c_remove),
+       .id_table = wm8804_i2c_id
+};
+#endif
+
+static int __init wm8804_modinit(void)
+{
+       int ret = 0;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8804_i2c_driver);
+       if (ret) {
+               printk(KERN_ERR "Failed to register wm8804 I2C driver: %d\n",
+                      ret);
+       }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       ret = spi_register_driver(&wm8804_spi_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8804 SPI driver: %d\n",
+                      ret);
+       }
+#endif
+       return ret;
+}
+module_init(wm8804_modinit);
+
+static void __exit wm8804_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8804_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&wm8804_spi_driver);
+#endif
+}
+module_exit(wm8804_exit);
+
+MODULE_DESCRIPTION("ASoC WM8804 driver");
+MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8804.h b/sound/soc/codecs/wm8804.h
new file mode 100644 (file)
index 0000000..8ec14f5
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * wm8804.h  --  WM8804 S/PDIF transceiver 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 _WM8804_H
+#define _WM8804_H
+
+/*
+ * Register values.
+ */
+#define WM8804_RST_DEVID1                      0x00
+#define WM8804_DEVID2                          0x01
+#define WM8804_DEVREV                          0x02
+#define WM8804_PLL1                            0x03
+#define WM8804_PLL2                            0x04
+#define WM8804_PLL3                            0x05
+#define WM8804_PLL4                            0x06
+#define WM8804_PLL5                            0x07
+#define WM8804_PLL6                            0x08
+#define WM8804_SPDMODE                         0x09
+#define WM8804_INTMASK                         0x0A
+#define WM8804_INTSTAT                         0x0B
+#define WM8804_SPDSTAT                         0x0C
+#define WM8804_RXCHAN1                         0x0D
+#define WM8804_RXCHAN2                         0x0E
+#define WM8804_RXCHAN3                         0x0F
+#define WM8804_RXCHAN4                         0x10
+#define WM8804_RXCHAN5                         0x11
+#define WM8804_SPDTX1                          0x12
+#define WM8804_SPDTX2                          0x13
+#define WM8804_SPDTX3                          0x14
+#define WM8804_SPDTX4                          0x15
+#define WM8804_SPDTX5                          0x16
+#define WM8804_GPO0                            0x17
+#define WM8804_GPO1                            0x18
+#define WM8804_GPO2                            0x1A
+#define WM8804_AIFTX                           0x1B
+#define WM8804_AIFRX                           0x1C
+#define WM8804_SPDRX1                          0x1D
+#define WM8804_PWRDN                           0x1E
+
+#define WM8804_REGISTER_COUNT                  30
+#define WM8804_MAX_REGISTER                    0x1E
+
+#define WM8804_TX_CLKSRC_MCLK                  1
+#define WM8804_TX_CLKSRC_PLL                   2
+
+#define WM8804_CLKOUT_SRC_CLK1                 3
+#define WM8804_CLKOUT_SRC_OSCCLK               4
+
+#define WM8804_CLKOUT_DIV                      1
+
+#endif  /* _WM8804_H */
index 5da17a704e5a9ba2d40d27a14b24a0fff701594e..b4f11724a63ffc771c1a1d83909e31ae5cccaab7 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/spi/spi.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 
 #define WM8900_LRC_MASK 0xfc00
 
-struct snd_soc_codec_device soc_codec_dev_wm8900;
-
 struct wm8900_priv {
-       struct snd_soc_codec codec;
-
+       enum snd_soc_control_type control_type;
        u16 reg_cache[WM8900_MAXREG];
 
        u32 fll_in; /* FLL input frequency */
@@ -627,8 +625,7 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u16 reg;
 
        reg = snd_soc_read(codec, WM8900_REG_AUDIO1) & ~0x60;
@@ -1015,8 +1012,8 @@ static struct snd_soc_dai_ops wm8900_dai_ops = {
        .digital_mute   = wm8900_digital_mute,
 };
 
-struct snd_soc_dai wm8900_dai = {
-       .name = "WM8900 HiFi",
+static struct snd_soc_dai_driver wm8900_dai = {
+       .name = "wm8900-hifi",
        .playback = {
                .stream_name = "HiFi Playback",
                .channels_min = 1,
@@ -1033,7 +1030,6 @@ struct snd_soc_dai wm8900_dai = {
         },
        .ops = &wm8900_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8900_dai);
 
 static int wm8900_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
@@ -1128,10 +1124,8 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-static int wm8900_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8900_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
        int fll_out = wm8900->fll_out;
        int fll_in  = wm8900->fll_in;
@@ -1140,7 +1134,7 @@ static int wm8900_suspend(struct platform_device *pdev, pm_message_t state)
        /* Stop the FLL in an orderly fashion */
        ret = wm8900_set_fll(codec, 0, 0, 0);
        if (ret != 0) {
-               dev_err(&pdev->dev, "Failed to stop FLL\n");
+               dev_err(codec->dev, "Failed to stop FLL\n");
                return ret;
        }
 
@@ -1152,10 +1146,8 @@ static int wm8900_suspend(struct platform_device *pdev, pm_message_t state)
        return 0;
 }
 
-static int wm8900_resume(struct platform_device *pdev)
+static int wm8900_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
        u16 *cache;
        int i, ret;
@@ -1176,7 +1168,7 @@ static int wm8900_resume(struct platform_device *pdev)
 
                ret = wm8900_set_fll(codec, 0, fll_in, fll_out);
                if (ret != 0) {
-                       dev_err(&pdev->dev, "Failed to restart FLL\n");
+                       dev_err(codec->dev, "Failed to restart FLL\n");
                        return ret;
                }
        }
@@ -1186,60 +1178,32 @@ static int wm8900_resume(struct platform_device *pdev)
                        snd_soc_write(codec, i, cache[i]);
                kfree(cache);
        } else
-               dev_err(&pdev->dev, "Unable to allocate register cache\n");
+               dev_err(codec->dev, "Unable to allocate register cache\n");
 
        return 0;
 }
 
-static struct snd_soc_codec *wm8900_codec;
-
-static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
-                                     const struct i2c_device_id *id)
+static int wm8900_probe(struct snd_soc_codec *codec)
 {
-       struct wm8900_priv *wm8900;
-       struct snd_soc_codec *codec;
-       unsigned int reg;
-       int ret;
-
-       wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
-       if (wm8900 == NULL)
-               return -ENOMEM;
+       struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0, reg;
 
-       codec = &wm8900->codec;
-       snd_soc_codec_set_drvdata(codec, wm8900);
-       codec->reg_cache = &wm8900->reg_cache[0];
-       codec->reg_cache_size = WM8900_MAXREG;
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->name = "WM8900";
-       codec->owner = THIS_MODULE;
-       codec->dai = &wm8900_dai;
-       codec->num_dai = 1;
-       codec->control_data = i2c;
-       codec->set_bias_level = wm8900_set_bias_level;
-       codec->volatile_register = wm8900_volatile_register;
-       codec->dev = &i2c->dev;
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8900->control_type);
        if (ret != 0) {
-               dev_err(&i2c->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
        reg = snd_soc_read(codec, WM8900_REG_ID);
        if (reg != 0x8900) {
-               dev_err(&i2c->dev, "Device is not a WM8900 - ID %x\n", reg);
-               ret = -ENODEV;
-               goto err;
+               dev_err(codec->dev, "Device is not a WM8900 - ID %x\n", reg);
+               return -ENODEV;
        }
 
        /* Read back from the chip */
        reg = snd_soc_read(codec, WM8900_REG_POWER1);
        reg = (reg >> 12) & 0xf;
-       dev_info(&i2c->dev, "WM8900 revision %d\n", reg);
+       dev_info(codec->dev, "WM8900 revision %d\n", reg);
 
        wm8900_reset(codec);
 
@@ -1271,43 +1235,94 @@ static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
        /* Set the DAC and mixer output bias */
        snd_soc_write(codec, WM8900_REG_OUTBIASCTL, 0x81);
 
-       wm8900_dai.dev = &i2c->dev;
+       snd_soc_add_controls(codec, wm8900_snd_controls,
+                               ARRAY_SIZE(wm8900_snd_controls));
+       wm8900_add_widgets(codec);
 
-       wm8900_codec = codec;
+       return 0;
+}
 
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
+/* power down chip */
+static int wm8900_remove(struct snd_soc_codec *codec)
+{
+       wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
 
-       ret = snd_soc_register_dai(&wm8900_dai);
-       if (ret != 0) {
-               dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
+static struct snd_soc_codec_driver soc_codec_dev_wm8900 = {
+       .probe =        wm8900_probe,
+       .remove =       wm8900_remove,
+       .suspend =      wm8900_suspend,
+       .resume =       wm8900_resume,
+       .set_bias_level = wm8900_set_bias_level,
+       .volatile_register = wm8900_volatile_register,
+       .reg_cache_size = ARRAY_SIZE(wm8900_reg_defaults),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8900_reg_defaults,
+};
 
-       return ret;
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8900_spi_probe(struct spi_device *spi)
+{
+       struct wm8900_priv *wm8900;
+       int ret;
+
+       wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
+       if (wm8900 == NULL)
+               return -ENOMEM;
 
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm8900);
-       wm8900_codec = NULL;
+       wm8900->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8900);
+
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_wm8900, &wm8900_dai, 1);
+       if (ret < 0)
+               kfree(wm8900);
        return ret;
 }
 
-static __devexit int wm8900_i2c_remove(struct i2c_client *client)
+static int __devexit wm8900_spi_remove(struct spi_device *spi)
 {
-       snd_soc_unregister_dai(&wm8900_dai);
-       snd_soc_unregister_codec(wm8900_codec);
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
+       return 0;
+}
 
-       wm8900_set_bias_level(wm8900_codec, SND_SOC_BIAS_OFF);
+static struct spi_driver wm8900_spi_driver = {
+       .driver = {
+               .name   = "wm8900-codec",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = wm8900_spi_probe,
+       .remove         = __devexit_p(wm8900_spi_remove),
+};
+#endif /* CONFIG_SPI_MASTER */
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8900_priv *wm8900;
+       int ret;
+
+       wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
+       if (wm8900 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, wm8900);
+       wm8900->control_type = SND_SOC_I2C;
 
-       wm8900_dai.dev = NULL;
-       kfree(snd_soc_codec_get_drvdata(wm8900_codec));
-       wm8900_codec = NULL;
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8900, &wm8900_dai, 1);
+       if (ret < 0)
+               kfree(wm8900);
+       return ret;
+}
 
+static __devexit int wm8900_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -1319,71 +1334,44 @@ MODULE_DEVICE_TABLE(i2c, wm8900_i2c_id);
 
 static struct i2c_driver wm8900_i2c_driver = {
        .driver = {
-               .name = "WM8900",
+               .name = "wm8900-codec",
                .owner = THIS_MODULE,
        },
-       .probe = wm8900_i2c_probe,
-       .remove = __devexit_p(wm8900_i2c_remove),
+       .probe =    wm8900_i2c_probe,
+       .remove =   __devexit_p(wm8900_i2c_remove),
        .id_table = wm8900_i2c_id,
 };
+#endif
 
-static int wm8900_probe(struct platform_device *pdev)
+static int __init wm8900_modinit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
        int ret = 0;
-
-       if (!wm8900_codec) {
-               dev_err(&pdev->dev, "I2C client not yet instantiated\n");
-               return -ENODEV;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8900_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8900 I2C driver: %d\n",
+                      ret);
        }
-
-       codec = wm8900_codec;
-       socdev->card->codec = codec;
-
-       /* Register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "Failed to register new PCMs\n");
-               goto pcm_err;
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       ret = spi_register_driver(&wm8900_spi_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8900 SPI driver: %d\n",
+                      ret);
        }
-
-       snd_soc_add_controls(codec, wm8900_snd_controls,
-                               ARRAY_SIZE(wm8900_snd_controls));
-       wm8900_add_widgets(codec);
-
-pcm_err:
+#endif
        return ret;
 }
-
-/* power down chip */
-static int wm8900_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8900 = {
-       .probe =        wm8900_probe,
-       .remove =       wm8900_remove,
-       .suspend =      wm8900_suspend,
-       .resume =       wm8900_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900);
-
-static int __init wm8900_modinit(void)
-{
-       return i2c_add_driver(&wm8900_i2c_driver);
-}
 module_init(wm8900_modinit);
 
 static void __exit wm8900_exit(void)
 {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm8900_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&wm8900_spi_driver);
+#endif
 }
 module_exit(wm8900_exit);
 
index fd15007d10c7ec22950174758a9b688247eede08..583f257e799b4719371abb641d37535f46ba2ba3 100644 (file)
@@ -52,7 +52,4 @@
 #define WM8900_DAC_CLKDIV_5_5 0x14
 #define WM8900_DAC_CLKDIV_6   0x18
 
-extern struct snd_soc_dai wm8900_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8900;
-
 #endif
index bf08282d5ee56384023d7055ff3b355d817d8e05..622b60238a824e084099b3f290dc0dda6ebf6767 100644 (file)
@@ -213,10 +213,11 @@ static u16 wm8903_reg_defaults[] = {
 };
 
 struct wm8903_priv {
-       struct snd_soc_codec codec;
+
        u16 reg_cache[ARRAY_SIZE(wm8903_reg_defaults)];
 
        int sysclk;
+       int irq;
 
        /* Reference counts */
        int class_w_users;
@@ -252,7 +253,6 @@ static int wm8903_volatile_register(unsigned int reg)
 static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
 {
        u16 reg[5];
-       struct i2c_client *i2c = codec->control_data;
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 
        BUG_ON(start > 48);
@@ -262,7 +262,7 @@ static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
        snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0,
                      reg[0] | WM8903_WSEQ_ENA);
 
-       dev_dbg(&i2c->dev, "Starting sequence at %d\n", start);
+       dev_dbg(codec->dev, "Starting sequence at %d\n", start);
 
        snd_soc_write(codec, WM8903_WRITE_SEQUENCER_3,
                     start | WM8903_WSEQ_START);
@@ -277,7 +277,7 @@ static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
                reg[4] = snd_soc_read(codec, WM8903_WRITE_SEQUENCER_4);
        } while (reg[4] & WM8903_WSEQ_BUSY);
 
-       dev_dbg(&i2c->dev, "Sequence complete\n");
+       dev_dbg(codec->dev, "Sequence complete\n");
 
        /* Disable the sequencer again if we enabled it */
        snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0]);
@@ -422,7 +422,6 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
        struct snd_soc_codec *codec = widget->codec;
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-       struct i2c_client *i2c = codec->control_data;
        u16 reg;
        int ret;
 
@@ -431,7 +430,7 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
        /* Turn it off if we're about to enable bypass */
        if (ucontrol->value.integer.value[0]) {
                if (wm8903->class_w_users == 0) {
-                       dev_dbg(&i2c->dev, "Disabling Class W\n");
+                       dev_dbg(codec->dev, "Disabling Class W\n");
                        snd_soc_write(codec, WM8903_CLASS_W_0, reg &
                                     ~(WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V));
                }
@@ -444,14 +443,14 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
        /* If we've just disabled the last bypass path turn Class W on */
        if (!ucontrol->value.integer.value[0]) {
                if (wm8903->class_w_users == 1) {
-                       dev_dbg(&i2c->dev, "Enabling Class W\n");
+                       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);
                }
                wm8903->class_w_users--;
        }
 
-       dev_dbg(&i2c->dev, "Bypass use count now %d\n",
+       dev_dbg(codec->dev, "Bypass use count now %d\n",
                wm8903->class_w_users);
 
        return ret;
@@ -935,7 +934,6 @@ 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)
 {
-       struct i2c_client *i2c = codec->control_data;
        u16 reg, reg2;
 
        switch (level) {
@@ -974,7 +972,7 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec,
                        /* By default no bypass paths are enabled so
                         * enable Class W support.
                         */
-                       dev_dbg(&i2c->dev, "Enabling Class W\n");
+                       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);
                }
@@ -1228,10 +1226,8 @@ 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_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-       struct i2c_client *i2c = codec->control_data;
        struct snd_pcm_runtime *master_runtime;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -1245,7 +1241,7 @@ static int wm8903_startup(struct snd_pcm_substream *substream,
        if (wm8903->master_substream) {
                master_runtime = wm8903->master_substream->runtime;
 
-               dev_dbg(&i2c->dev, "Constraining to %d bits\n",
+               dev_dbg(codec->dev, "Constraining to %d bits\n",
                        master_runtime->sample_bits);
 
                snd_pcm_hw_constraint_minmax(substream->runtime,
@@ -1264,8 +1260,7 @@ 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_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -1284,10 +1279,8 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec =rtd->codec;
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-       struct i2c_client *i2c = codec->control_data;
        int fs = params_rate(params);
        int bclk;
        int bclk_div;
@@ -1306,7 +1299,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
        u16 dac_digital1 = snd_soc_read(codec, WM8903_DAC_DIGITAL_1);
 
        if (substream == wm8903->slave_substream) {
-               dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n");
+               dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n");
                return 0;
        }
 
@@ -1332,7 +1325,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
                switch (sample_rates[dsp_config].rate) {
                case 88200:
                case 96000:
-                       dev_err(&i2c->dev, "%dHz unsupported by ADC\n",
+                       dev_err(codec->dev, "%dHz unsupported by ADC\n",
                                fs);
                        return -EINVAL;
 
@@ -1340,7 +1333,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
                        break;
                }
 
-       dev_dbg(&i2c->dev, "DSP fs = %dHz\n", sample_rates[dsp_config].rate);
+       dev_dbg(codec->dev, "DSP fs = %dHz\n", sample_rates[dsp_config].rate);
        clock1 &= ~WM8903_SAMPLE_RATE_MASK;
        clock1 |= sample_rates[dsp_config].value;
 
@@ -1366,7 +1359,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       dev_dbg(&i2c->dev, "MCLK = %dHz, target sample rate = %dHz\n",
+       dev_dbg(codec->dev, "MCLK = %dHz, target sample rate = %dHz\n",
                wm8903->sysclk, fs);
 
        /* We may not have an MCLK which allows us to generate exactly
@@ -1401,12 +1394,12 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
        clock1 |= clk_sys_ratios[clk_config].rate << WM8903_CLK_SYS_RATE_SHIFT;
        clock1 |= clk_sys_ratios[clk_config].mode << WM8903_CLK_SYS_MODE_SHIFT;
 
-       dev_dbg(&i2c->dev, "CLK_SYS_RATE=%x, CLK_SYS_MODE=%x div=%d\n",
+       dev_dbg(codec->dev, "CLK_SYS_RATE=%x, CLK_SYS_MODE=%x div=%d\n",
                clk_sys_ratios[clk_config].rate,
                clk_sys_ratios[clk_config].mode,
                clk_sys_ratios[clk_config].div);
 
-       dev_dbg(&i2c->dev, "Actual CLK_SYS = %dHz\n", clk_sys);
+       dev_dbg(codec->dev, "Actual CLK_SYS = %dHz\n", clk_sys);
 
        /* We may not get quite the right frequency if using
         * approximate clocks so look for the closest match that is
@@ -1428,7 +1421,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
        aif2 &= ~WM8903_BCLK_DIV_MASK;
        aif3 &= ~WM8903_LRCLK_RATE_MASK;
 
-       dev_dbg(&i2c->dev, "BCLK ratio %d for %dHz - actual BCLK = %dHz\n",
+       dev_dbg(codec->dev, "BCLK ratio %d for %dHz - actual BCLK = %dHz\n",
                bclk_divs[bclk_div].ratio / 10, bclk,
                (clk_sys * 10) / bclk_divs[bclk_div].ratio);
 
@@ -1504,8 +1497,8 @@ EXPORT_SYMBOL_GPL(wm8903_mic_detect);
 
 static irqreturn_t wm8903_irq(int irq, void *data)
 {
-       struct wm8903_priv *wm8903 = data;
-       struct snd_soc_codec *codec = &wm8903->codec;
+       struct snd_soc_codec *codec = data;
+       struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
        int mic_report;
        int int_pol;
        int int_val = 0;
@@ -1586,8 +1579,8 @@ static struct snd_soc_dai_ops wm8903_dai_ops = {
        .set_sysclk     = wm8903_set_dai_sysclk,
 };
 
-struct snd_soc_dai wm8903_dai = {
-       .name = "WM8903",
+static struct snd_soc_dai_driver wm8903_dai = {
+       .name = "wm8903-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -1605,23 +1598,16 @@ struct snd_soc_dai wm8903_dai = {
        .ops = &wm8903_dai_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(wm8903_dai);
 
-static int wm8903_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8903_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int wm8903_resume(struct platform_device *pdev)
+static int wm8903_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-       struct i2c_client *i2c = codec->control_data;
        int i;
        u16 *reg_cache = codec->reg_cache;
        u16 *tmp_cache = kmemdup(reg_cache, sizeof(wm8903_reg_defaults),
@@ -1637,65 +1623,37 @@ static int wm8903_resume(struct platform_device *pdev)
                                snd_soc_write(codec, i, tmp_cache[i]);
                kfree(tmp_cache);
        } else {
-               dev_err(&i2c->dev, "Failed to allocate temporary cache\n");
+               dev_err(codec->dev, "Failed to allocate temporary cache\n");
        }
 
        return 0;
 }
 
-static struct snd_soc_codec *wm8903_codec;
-
-static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
-                                     const struct i2c_device_id *id)
+static int wm8903_probe(struct snd_soc_codec *codec)
 {
-       struct wm8903_platform_data *pdata = dev_get_platdata(&i2c->dev);
-       struct wm8903_priv *wm8903;
-       struct snd_soc_codec *codec;
+       struct wm8903_platform_data *pdata = dev_get_platdata(codec->dev);
+       struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
        int ret, i;
        int trigger, irq_pol;
        u16 val;
 
-       wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL);
-       if (wm8903 == NULL)
-               return -ENOMEM;
-
-       codec = &wm8903->codec;
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->dev = &i2c->dev;
-       codec->name = "WM8903";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8903_set_bias_level;
-       codec->dai = &wm8903_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(wm8903->reg_cache);
-       codec->reg_cache = &wm8903->reg_cache[0];
-       snd_soc_codec_set_drvdata(codec, wm8903);
-       codec->volatile_register = wm8903_volatile_register;
        init_completion(&wm8903->wseq);
 
-       i2c_set_clientdata(i2c, codec);
-       codec->control_data = i2c;
-
        ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
        if (ret != 0) {
-               dev_err(&i2c->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
        val = snd_soc_read(codec, WM8903_SW_RESET_AND_ID);
        if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) {
-               dev_err(&i2c->dev,
+               dev_err(codec->dev,
                        "Device with ID register %x is not a WM8903\n", val);
                return -ENODEV;
        }
 
        val = snd_soc_read(codec, WM8903_REVISION_NUMBER);
-       dev_info(&i2c->dev, "WM8903 revision %d\n",
+       dev_info(codec->dev, "WM8903 revision %d\n",
                 val & WM8903_CHIP_REV_MASK);
 
        wm8903_reset(codec);
@@ -1721,7 +1679,7 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
                wm8903->mic_delay = pdata->micdet_delay;
        }
        
-       if (i2c->irq) {
+       if (wm8903->irq) {
                if (pdata && pdata->irq_active_low) {
                        trigger = IRQF_TRIGGER_LOW;
                        irq_pol = WM8903_IRQ_POL;
@@ -1733,13 +1691,13 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
                snd_soc_update_bits(codec, WM8903_INTERRUPT_CONTROL,
                                    WM8903_IRQ_POL, irq_pol);
                
-               ret = request_threaded_irq(i2c->irq, NULL, wm8903_irq,
+               ret = request_threaded_irq(wm8903->irq, NULL, wm8903_irq,
                                           trigger | IRQF_ONESHOT,
-                                          "wm8903", wm8903);
+                                          "wm8903", codec);
                if (ret != 0) {
-                       dev_err(&i2c->dev, "Failed to request IRQ: %d\n",
+                       dev_err(codec->dev, "Failed to request IRQ: %d\n",
                                ret);
-                       goto err;
+                       return ret;
                }
 
                /* Enable write sequencer interrupts */
@@ -1781,133 +1739,96 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
        val |= WM8903_DAC_MUTEMODE;
        snd_soc_write(codec, WM8903_DAC_DIGITAL_1, val);
 
-       wm8903_dai.dev = &i2c->dev;
-       wm8903_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
-               goto err_irq;
-       }
-
-       ret = snd_soc_register_dai(&wm8903_dai);
-       if (ret != 0) {
-               dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
-
-       return ret;
+       snd_soc_add_controls(codec, wm8903_snd_controls,
+                               ARRAY_SIZE(wm8903_snd_controls));
+       wm8903_add_widgets(codec);
 
-err_codec:
-       snd_soc_unregister_codec(codec);
-err_irq:
-       if (i2c->irq)
-               free_irq(i2c->irq, wm8903);
-err:
-       wm8903_codec = NULL;
-       kfree(wm8903);
        return ret;
 }
 
-static __devexit int wm8903_i2c_remove(struct i2c_client *client)
+/* power down chip */
+static int wm8903_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       struct wm8903_priv *priv = snd_soc_codec_get_drvdata(codec);
+       wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
 
-       snd_soc_unregister_dai(&wm8903_dai);
-       snd_soc_unregister_codec(codec);
+static struct snd_soc_codec_driver soc_codec_dev_wm8903 = {
+       .probe =        wm8903_probe,
+       .remove =       wm8903_remove,
+       .suspend =      wm8903_suspend,
+       .resume =       wm8903_resume,
+       .set_bias_level = wm8903_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8903_reg_defaults),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8903_reg_defaults,
+       .volatile_register = wm8903_volatile_register,
+};
 
-       wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8903_priv *wm8903;
+       int ret;
 
-       if (client->irq)
-               free_irq(client->irq, priv);
+       wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL);
+       if (wm8903 == NULL)
+               return -ENOMEM;
 
-       kfree(priv);
+       i2c_set_clientdata(i2c, wm8903);
+       wm8903->irq = i2c->irq;
 
-       wm8903_codec = NULL;
-       wm8903_dai.dev = NULL;
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8903, &wm8903_dai, 1);
+       if (ret < 0)
+               kfree(wm8903);
+       return ret;
+}
 
+static __devexit int wm8903_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
-/* i2c codec control layer */
 static const struct i2c_device_id wm8903_i2c_id[] = {
-       { "wm8903", 0 },
-       { }
+       { "wm8903", 0 },
+       { }
 };
 MODULE_DEVICE_TABLE(i2c, wm8903_i2c_id);
 
 static struct i2c_driver wm8903_i2c_driver = {
        .driver = {
-               .name = "WM8903",
+               .name = "wm8903-codec",
                .owner = THIS_MODULE,
        },
-       .probe    = wm8903_i2c_probe,
-       .remove   = __devexit_p(wm8903_i2c_remove),
+       .probe =    wm8903_i2c_probe,
+       .remove =   __devexit_p(wm8903_i2c_remove),
        .id_table = wm8903_i2c_id,
 };
+#endif
 
-static int wm8903_probe(struct platform_device *pdev)
+static int __init wm8903_modinit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        int ret = 0;
-
-       if (!wm8903_codec) {
-               dev_err(&pdev->dev, "I2C device not yet probed\n");
-               goto err;
-       }
-
-       socdev->card->codec = wm8903_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to create pcms\n");
-               goto err;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8903_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8903 I2C driver: %d\n",
+                      ret);
        }
-
-       snd_soc_add_controls(socdev->card->codec, wm8903_snd_controls,
-                               ARRAY_SIZE(wm8903_snd_controls));
-       wm8903_add_widgets(socdev->card->codec);
-
+#endif
        return ret;
-
-err:
-       return ret;
-}
-
-/* power down chip */
-static int wm8903_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec->control_data)
-               wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8903 = {
-       .probe =        wm8903_probe,
-       .remove =       wm8903_remove,
-       .suspend =      wm8903_suspend,
-       .resume =       wm8903_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8903);
-
-static int __init wm8903_modinit(void)
-{
-       return i2c_add_driver(&wm8903_i2c_driver);
 }
 module_init(wm8903_modinit);
 
 static void __exit wm8903_exit(void)
 {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm8903_i2c_driver);
+#endif
 }
 module_exit(wm8903_exit);
 
index ce384a2ad820ec3b8bbf894f1bc9a8f246184862..996435e681e5e2a8bce5ca1d84aebbc0fe907066 100644 (file)
@@ -15,9 +15,6 @@
 
 #include <linux/i2c.h>
 
-extern struct snd_soc_dai wm8903_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8903;
-
 extern int wm8903_mic_detect(struct snd_soc_codec *codec,
                             struct snd_soc_jack *jack,
                             int det, int shrt);
index f7dcabf6283c165877fd5a12cd2adcd69f245e5e..33be84e506ea7d4e2927a4e44a06e49ab648f156 100644 (file)
@@ -31,9 +31,6 @@
 
 #include "wm8904.h"
 
-static struct snd_soc_codec *wm8904_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8904;
-
 enum wm8904_type {
        WM8904,
        WM8912,
@@ -52,10 +49,11 @@ static const char *wm8904_supply_names[WM8904_NUM_SUPPLIES] = {
 
 /* codec private data */
 struct wm8904_priv {
-       struct snd_soc_codec codec;
+
        u16 reg_cache[WM8904_MAX_REGISTER + 1];
 
        enum wm8904_type devtype;
+       void *control_data;
 
        struct regulator_bulk_data supplies[WM8904_NUM_SUPPLIES];
 
@@ -689,7 +687,7 @@ static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);  
+       struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
        struct wm8904_pdata *pdata = wm8904->pdata;
        int value = ucontrol->value.integer.value[0];
 
@@ -760,7 +758,7 @@ static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
                                         struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);  
+       struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
        struct wm8904_pdata *pdata = wm8904->pdata;
        int value = ucontrol->value.integer.value[0];
 
@@ -2218,8 +2216,8 @@ static struct snd_soc_dai_ops wm8904_dai_ops = {
        .digital_mute = wm8904_digital_mute,
 };
 
-struct snd_soc_dai wm8904_dai = {
-       .name = "WM8904",
+static struct snd_soc_dai_driver wm8904_dai = {
+       .name = "wm8904-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -2237,24 +2235,17 @@ struct snd_soc_dai wm8904_dai = {
        .ops = &wm8904_dai_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(wm8904_dai);
 
 #ifdef CONFIG_PM
-static int wm8904_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8904_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int wm8904_resume(struct platform_device *pdev)
+static int wm8904_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
@@ -2264,9 +2255,9 @@ static int wm8904_resume(struct platform_device *pdev)
 #define wm8904_resume NULL
 #endif
 
-static void wm8904_handle_retune_mobile_pdata(struct wm8904_priv *wm8904)
+static void wm8904_handle_retune_mobile_pdata(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = &wm8904->codec;
+       struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
        struct wm8904_pdata *pdata = wm8904->pdata;
        struct snd_kcontrol_new control =
                SOC_ENUM_EXT("EQ Mode",
@@ -2315,20 +2306,20 @@ static void wm8904_handle_retune_mobile_pdata(struct wm8904_priv *wm8904)
        wm8904->retune_mobile_enum.max = wm8904->num_retune_mobile_texts;
        wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts;
 
-       ret = snd_soc_add_controls(&wm8904->codec, &control, 1);
+       ret = snd_soc_add_controls(codec, &control, 1);
        if (ret != 0)
-               dev_err(wm8904->codec.dev,
+               dev_err(codec->dev,
                        "Failed to add ReTune Mobile control: %d\n", ret);
 }
 
-static void wm8904_handle_pdata(struct wm8904_priv *wm8904)
+static void wm8904_handle_pdata(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = &wm8904->codec;
+       struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
        struct wm8904_pdata *pdata = wm8904->pdata;
        int ret, i;
 
        if (!pdata) {
-               snd_soc_add_controls(&wm8904->codec, wm8904_eq_controls,
+               snd_soc_add_controls(codec, wm8904_eq_controls,
                                     ARRAY_SIZE(wm8904_eq_controls));
                return;
        }
@@ -2344,7 +2335,7 @@ static void wm8904_handle_pdata(struct wm8904_priv *wm8904)
                wm8904->drc_texts = kmalloc(sizeof(char *)
                                            * pdata->num_drc_cfgs, GFP_KERNEL);
                if (!wm8904->drc_texts) {
-                       dev_err(wm8904->codec.dev,
+                       dev_err(codec->dev,
                                "Failed to allocate %d DRC config texts\n",
                                pdata->num_drc_cfgs);
                        return;
@@ -2356,9 +2347,9 @@ static void wm8904_handle_pdata(struct wm8904_priv *wm8904)
                wm8904->drc_enum.max = pdata->num_drc_cfgs;
                wm8904->drc_enum.texts = wm8904->drc_texts;
 
-               ret = snd_soc_add_controls(&wm8904->codec, &control, 1);
+               ret = snd_soc_add_controls(codec, &control, 1);
                if (ret != 0)
-                       dev_err(wm8904->codec.dev,
+                       dev_err(codec->dev,
                                "Failed to add DRC mode control: %d\n", ret);
 
                wm8904_set_drc(codec);
@@ -2368,89 +2359,19 @@ static void wm8904_handle_pdata(struct wm8904_priv *wm8904)
                pdata->num_retune_mobile_cfgs);
 
        if (pdata->num_retune_mobile_cfgs)
-               wm8904_handle_retune_mobile_pdata(wm8904);
+               wm8904_handle_retune_mobile_pdata(codec);
        else
-               snd_soc_add_controls(&wm8904->codec, wm8904_eq_controls,
+               snd_soc_add_controls(codec, wm8904_eq_controls,
                                     ARRAY_SIZE(wm8904_eq_controls));
 }
 
-static int wm8904_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (wm8904_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
 
-       socdev->card->codec = wm8904_codec;
-       codec = wm8904_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       wm8904_handle_pdata(snd_soc_codec_get_drvdata(codec));
-
-       wm8904_add_widgets(codec);
-
-       return ret;
-
-pcm_err:
-       return ret;
-}
-
-static int wm8904_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8904 = {
-       .probe =        wm8904_probe,
-       .remove =       wm8904_remove,
-       .suspend =      wm8904_suspend,
-       .resume =       wm8904_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8904);
-
-static int wm8904_register(struct wm8904_priv *wm8904,
-                          enum snd_soc_control_type control)
+static int wm8904_probe(struct snd_soc_codec *codec)
 {
+       struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
        struct wm8904_pdata *pdata = wm8904->pdata;
-       int ret;
-       struct snd_soc_codec *codec = &wm8904->codec;
-       int i;
-
-       if (wm8904_codec) {
-               dev_err(codec->dev, "Another WM8904 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
+       int ret, i;
 
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8904);
-       codec->name = "WM8904";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8904_set_bias_level;
-       codec->dai = &wm8904_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8904_MAX_REGISTER;
-       codec->reg_cache = &wm8904->reg_cache;
-       codec->volatile_register = wm8904_volatile_register;
        codec->cache_sync = 1;
        codec->idle_bias_off = 1;
 
@@ -2463,16 +2384,13 @@ static int wm8904_register(struct wm8904_priv *wm8904,
        default:
                dev_err(codec->dev, "Unknown device type %d\n",
                        wm8904->devtype);
-               ret = -EINVAL;
-               goto err;
+               return -EINVAL;
        }
 
-       memcpy(codec->reg_cache, wm8904_reg, sizeof(wm8904_reg));
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        for (i = 0; i < ARRAY_SIZE(wm8904->supplies); i++)
@@ -2482,7 +2400,7 @@ static int wm8904_register(struct wm8904_priv *wm8904,
                                 wm8904->supplies);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies),
@@ -2517,8 +2435,6 @@ static int wm8904_register(struct wm8904_priv *wm8904,
                goto err_enable;
        }
 
-       wm8904_dai.dev = codec->dev;
-
        /* Change some default settings - latch VU and enable ZC */
        wm8904->reg_cache[WM8904_ADC_DIGITAL_VOLUME_LEFT] |= WM8904_ADC_VU;
        wm8904->reg_cache[WM8904_ADC_DIGITAL_VOLUME_RIGHT] |= WM8904_ADC_VU;
@@ -2563,72 +2479,68 @@ static int wm8904_register(struct wm8904_priv *wm8904,
        /* Bias level configuration will have done an extra enable */
        regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
 
-       wm8904_codec = codec;
+       wm8904_handle_pdata(codec);
 
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err_enable;
-       }
-
-       ret = snd_soc_register_dai(&wm8904_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
+       wm8904_add_widgets(codec);
 
        return 0;
 
-err_codec:
-       snd_soc_unregister_codec(codec);
 err_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
 err_get:
        regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
-err:
-       kfree(wm8904);
        return ret;
 }
 
-static void wm8904_unregister(struct wm8904_priv *wm8904)
+static int wm8904_remove(struct snd_soc_codec *codec)
 {
-       wm8904_set_bias_level(&wm8904->codec, SND_SOC_BIAS_OFF);
+       struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
+
+       wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF);
        regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
-       snd_soc_unregister_dai(&wm8904_dai);
-       snd_soc_unregister_codec(&wm8904->codec);
-       kfree(wm8904);
-       wm8904_codec = NULL;
+
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_wm8904 = {
+       .probe =        wm8904_probe,
+       .remove =       wm8904_remove,
+       .suspend =      wm8904_suspend,
+       .resume =       wm8904_resume,
+       .set_bias_level = wm8904_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8904_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8904_reg,
+       .volatile_register = wm8904_volatile_register,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8904_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8904_priv *wm8904;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8904 = kzalloc(sizeof(struct wm8904_priv), GFP_KERNEL);
        if (wm8904 == NULL)
                return -ENOMEM;
 
-       codec = &wm8904->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
        wm8904->devtype = id->driver_data;
-
        i2c_set_clientdata(i2c, wm8904);
-       codec->control_data = i2c;
+       wm8904->control_data = i2c;
        wm8904->pdata = i2c->dev.platform_data;
 
-       codec->dev = &i2c->dev;
-
-       return wm8904_register(wm8904, SND_SOC_I2C);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8904, &wm8904_dai, 1);
+       if (ret < 0)
+               kfree(wm8904);
+       return ret;
 }
 
 static __devexit int wm8904_i2c_remove(struct i2c_client *client)
 {
-       struct wm8904_priv *wm8904 = i2c_get_clientdata(client);
-       wm8904_unregister(wm8904);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -2641,7 +2553,7 @@ MODULE_DEVICE_TABLE(i2c, wm8904_i2c_id);
 
 static struct i2c_driver wm8904_i2c_driver = {
        .driver = {
-               .name = "WM8904",
+               .name = "wm8904-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8904_i2c_probe,
@@ -2652,15 +2564,15 @@ static struct i2c_driver wm8904_i2c_driver = {
 
 static int __init wm8904_modinit(void)
 {
-       int ret;
+       int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8904_i2c_driver);
        if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8904 I2C driver: %d\n",
+               printk(KERN_ERR "Failed to register wm8904 I2C driver: %d\n",
                       ret);
        }
 #endif
-       return 0;
+       return ret;
 }
 module_init(wm8904_modinit);
 
index abe5059b3004e3739878d5787754b6554233f12c..9e8c84188ba761bb0eb606029e7c80f8d34e8219 100644 (file)
@@ -21,9 +21,6 @@
 #define WM8904_FLL_LRCLK         3
 #define WM8904_FLL_FREE_RUNNING  4
 
-extern struct snd_soc_dai wm8904_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8904;
-
 /*
  * Register values.
  */
index f0c11138e61002cf2c6a0f419c64de177f0e9a62..2cb16f895c4607c9d323ea3cbb9d8e31c4741cb1 100644 (file)
@@ -44,7 +44,8 @@
 struct wm8940_priv {
        unsigned int sysclk;
        u16 reg_cache[WM8940_CACHEREGNUM];
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+       void *control_data;
 };
 
 static u16 wm8940_reg_defaults[] = {
@@ -365,8 +366,7 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFD9F;
        u16 addcntrl = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFF1;
        u16 companding =  snd_soc_read(codec,
@@ -636,8 +636,8 @@ static struct snd_soc_dai_ops wm8940_dai_ops = {
        .set_pll = wm8940_set_dai_pll,
 };
 
-struct snd_soc_dai wm8940_dai = {
-       .name = "WM8940",
+static struct snd_soc_dai_driver wm8940_dai = {
+       .name = "wm8940-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -655,20 +655,14 @@ struct snd_soc_dai wm8940_dai = {
        .ops = &wm8940_dai_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(wm8940_dai);
 
-static int wm8940_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8940_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        return wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF);
 }
 
-static int wm8940_resume(struct platform_device *pdev)
+static int wm8940_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        int ret;
        u8 data[3];
@@ -697,108 +691,26 @@ error_ret:
        return ret;
 }
 
-static struct snd_soc_codec *wm8940_codec;
-
-static int wm8940_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-
-       int ret = 0;
-
-       if (wm8940_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8940_codec;
-       codec = wm8940_codec;
-
-       mutex_init(&codec->mutex);
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       ret = snd_soc_add_controls(codec, wm8940_snd_controls,
-                            ARRAY_SIZE(wm8940_snd_controls));
-       if (ret)
-               goto error_free_pcms;
-       ret = wm8940_add_widgets(codec);
-       if (ret)
-               goto error_free_pcms;
-
-       return ret;
-
-error_free_pcms:
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-pcm_err:
-       return ret;
-}
-
-static int wm8940_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8940 = {
-       .probe = wm8940_probe,
-       .remove = wm8940_remove,
-       .suspend = wm8940_suspend,
-       .resume = wm8940_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8940);
-
-static int wm8940_register(struct wm8940_priv *wm8940,
-                          enum snd_soc_control_type control)
+static int wm8940_probe(struct snd_soc_codec *codec)
 {
-       struct wm8940_setup_data *pdata = wm8940->codec.dev->platform_data;
-       struct snd_soc_codec *codec = &wm8940->codec;
+       struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec);
+       struct wm8940_setup_data *pdata = codec->dev->platform_data;
        int ret;
        u16 reg;
-       if (wm8940_codec) {
-               dev_err(codec->dev, "Another WM8940 is registered\n");
-               return -EINVAL;
-       }
-
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8940);
-       codec->name = "WM8940";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8940_set_bias_level;
-       codec->dai = &wm8940_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults);
-       codec->reg_cache = &wm8940->reg_cache;
 
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
+       codec->control_data = wm8940->control_data;
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8940->control_type);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
        }
 
-       memcpy(codec->reg_cache, wm8940_reg_defaults,
-              sizeof(wm8940_reg_defaults));
-
        ret = wm8940_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset\n");
                return ret;
        }
 
-       wm8940_dai.dev = codec->dev;
-
        wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        ret = snd_soc_write(codec, WM8940_POWER1, 0x180);
@@ -814,64 +726,60 @@ static int wm8940_register(struct wm8940_priv *wm8940,
                        return ret;
        }
 
-
-       wm8940_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+       ret = snd_soc_add_controls(codec, wm8940_snd_controls,
+                            ARRAY_SIZE(wm8940_snd_controls));
+       if (ret)
                return ret;
-       }
-
-       ret = snd_soc_register_dai(&wm8940_dai);
-       if (ret) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               snd_soc_unregister_codec(codec);
+       ret = wm8940_add_widgets(codec);
+       if (ret)
                return ret;
-       }
 
-       return 0;
+       return ret;
+;
 }
 
-static void wm8940_unregister(struct wm8940_priv *wm8940)
+static int wm8940_remove(struct snd_soc_codec *codec)
 {
-       wm8940_set_bias_level(&wm8940->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dai(&wm8940_dai);
-       snd_soc_unregister_codec(&wm8940->codec);
-       kfree(wm8940);
-       wm8940_codec = NULL;
+       wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
 
-static int wm8940_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+static struct snd_soc_codec_driver soc_codec_dev_wm8940 = {
+       .probe =        wm8940_probe,
+       .remove =       wm8940_remove,
+       .suspend =      wm8940_suspend,
+       .resume =       wm8940_resume,
+       .set_bias_level = wm8940_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8940_reg_defaults,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8940_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
-       int ret;
        struct wm8940_priv *wm8940;
-       struct snd_soc_codec *codec;
+       int ret;
 
-       wm8940 = kzalloc(sizeof *wm8940, GFP_KERNEL);
+       wm8940 = kzalloc(sizeof(struct wm8940_priv), GFP_KERNEL);
        if (wm8940 == NULL)
                return -ENOMEM;
 
-       codec = &wm8940->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
        i2c_set_clientdata(i2c, wm8940);
-       codec->control_data = i2c;
-       codec->dev = &i2c->dev;
+       wm8940->control_data = i2c;
 
-       ret = wm8940_register(wm8940, SND_SOC_I2C);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8940, &wm8940_dai, 1);
        if (ret < 0)
                kfree(wm8940);
-
        return ret;
 }
 
-static int __devexit wm8940_i2c_remove(struct i2c_client *client)
+static __devexit int wm8940_i2c_remove(struct i2c_client *client)
 {
-       struct wm8940_priv *wm8940 = i2c_get_clientdata(client);
-
-       wm8940_unregister(wm8940);
-
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -883,29 +791,34 @@ MODULE_DEVICE_TABLE(i2c, wm8940_i2c_id);
 
 static struct i2c_driver wm8940_i2c_driver = {
        .driver = {
-               .name = "WM8940 I2C Codec",
+               .name = "wm8940-codec",
                .owner = THIS_MODULE,
        },
-       .probe = wm8940_i2c_probe,
-       .remove = __devexit_p(wm8940_i2c_remove),
+       .probe =    wm8940_i2c_probe,
+       .remove =   __devexit_p(wm8940_i2c_remove),
        .id_table = wm8940_i2c_id,
 };
+#endif
 
 static int __init wm8940_modinit(void)
 {
-       int ret;
-
+       int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8940_i2c_driver);
-       if (ret)
-               printk(KERN_ERR "Failed to register WM8940 I2C driver: %d\n",
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8940 I2C driver: %d\n",
                       ret);
+       }
+#endif
        return ret;
 }
 module_init(wm8940_modinit);
 
 static void __exit wm8940_exit(void)
 {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm8940_i2c_driver);
+#endif
 }
 module_exit(wm8940_exit);
 
index 8410eed3ef847958a5b54816be246f978d69535f..907fe192e9e02d04669783b0647ff1dcaff6cbab 100644 (file)
@@ -15,8 +15,6 @@ struct wm8940_setup_data {
 #define WM8940_VROI_30K 1
        unsigned int vroi:1;
 };
-extern struct snd_soc_dai wm8940_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8940;
 
 /* WM8940 register space */
 #define WM8940_SOFTRESET       0x00
index 5f025593d84d3f4b8bc47aedda98055cd900f8ca..f89ad6c9a80b9162e7040ea6fe76b434c9f743f1 100644 (file)
@@ -30,9 +30,6 @@
 
 #include "wm8955.h"
 
-static struct snd_soc_codec *wm8955_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8955;
-
 #define WM8955_NUM_SUPPLIES 4
 static const char *wm8955_supply_names[WM8955_NUM_SUPPLIES] = {
        "DCVDD",
@@ -43,7 +40,8 @@ static const char *wm8955_supply_names[WM8955_NUM_SUPPLIES] = {
 
 /* codec private data */
 struct wm8955_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+
        u16 reg_cache[WM8955_MAX_REGISTER + 1];
 
        unsigned int mclk_rate;
@@ -52,8 +50,6 @@ struct wm8955_priv {
        int fs;
 
        struct regulator_bulk_data supplies[WM8955_NUM_SUPPLIES];
-
-       struct wm8955_pdata *pdata;
 };
 
 static const u16 wm8955_reg[WM8955_MAX_REGISTER + 1] = {
@@ -870,8 +866,8 @@ static struct snd_soc_dai_ops wm8955_dai_ops = {
        .digital_mute = wm8955_digital_mute,
 };
 
-struct snd_soc_dai wm8955_dai = {
-       .name = "WM8955",
+static struct snd_soc_dai_driver wm8955_dai = {
+       .name = "wm8955-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -881,24 +877,17 @@ struct snd_soc_dai wm8955_dai = {
        },
        .ops = &wm8955_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8955_dai);
 
 #ifdef CONFIG_PM
-static int wm8955_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8955_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int wm8955_resume(struct platform_device *pdev)
+static int wm8955_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
@@ -908,86 +897,16 @@ static int wm8955_resume(struct platform_device *pdev)
 #define wm8955_resume NULL
 #endif
 
-static int wm8955_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (wm8955_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8955_codec;
-       codec = wm8955_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       wm8955_add_widgets(codec);
-
-       return ret;
-
-pcm_err:
-       return ret;
-}
-
-static int wm8955_remove(struct platform_device *pdev)
+static int wm8955_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8955 = {
-       .probe =        wm8955_probe,
-       .remove =       wm8955_remove,
-       .suspend =      wm8955_suspend,
-       .resume =       wm8955_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8955);
-
-static int wm8955_register(struct wm8955_priv *wm8955,
-                          enum snd_soc_control_type control)
-{
-       int ret;
-       struct snd_soc_codec *codec = &wm8955->codec;
-       int i;
-
-       if (wm8955_codec) {
-               dev_err(codec->dev, "Another WM8955 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8955);
-       codec->name = "WM8955";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8955_set_bias_level;
-       codec->dai = &wm8955_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8955_MAX_REGISTER;
-       codec->reg_cache = &wm8955->reg_cache;
-
-       memcpy(codec->reg_cache, wm8955_reg, sizeof(wm8955_reg));
+       struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
+       struct wm8955_pdata *pdata = dev_get_platdata(codec->dev);
+       int ret, i;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8955->control_type);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        for (i = 0; i < ARRAY_SIZE(wm8955->supplies); i++)
@@ -997,7 +916,7 @@ static int wm8955_register(struct wm8955_priv *wm8955,
                                 wm8955->supplies);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies),
@@ -1013,8 +932,6 @@ static int wm8955_register(struct wm8955_priv *wm8955,
                goto err_enable;
        }
 
-       wm8955_dai.dev = codec->dev;
-
        /* Change some default settings - latch VU and enable ZC */
        wm8955->reg_cache[WM8955_LEFT_DAC_VOLUME] |= WM8955_LDVU;
        wm8955->reg_cache[WM8955_RIGHT_DAC_VOLUME] |= WM8955_RDVU;
@@ -1028,12 +945,12 @@ static int wm8955_register(struct wm8955_priv *wm8955,
        wm8955->reg_cache[WM8955_BASS_CONTROL] |= WM8955_BB;
 
        /* Set platform data values */
-       if (wm8955->pdata) {
-               if (wm8955->pdata->out2_speaker)
+       if (pdata) {
+               if (pdata->out2_speaker)
                        wm8955->reg_cache[WM8955_ADDITIONAL_CONTROL_2]
                                |= WM8955_ROUT2INV;
 
-               if (wm8955->pdata->monoin_diff)
+               if (pdata->monoin_diff)
                        wm8955->reg_cache[WM8955_MONO_OUT_MIX_1]
                                |= WM8955_DMEN;
        }
@@ -1043,70 +960,60 @@ static int wm8955_register(struct wm8955_priv *wm8955,
        /* Bias level configuration will have done an extra enable */
        regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
 
-       wm8955_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err_enable;
-       }
-
-       ret = snd_soc_register_dai(&wm8955_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
-
+       wm8955_add_widgets(codec);
        return 0;
 
-err_codec:
-       snd_soc_unregister_codec(codec);
 err_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
 err_get:
        regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
-err:
-       kfree(wm8955);
        return ret;
 }
 
-static void wm8955_unregister(struct wm8955_priv *wm8955)
+static int wm8955_remove(struct snd_soc_codec *codec)
 {
-       wm8955_set_bias_level(&wm8955->codec, SND_SOC_BIAS_OFF);
+       struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
+
+       wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF);
        regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
-       snd_soc_unregister_dai(&wm8955_dai);
-       snd_soc_unregister_codec(&wm8955->codec);
-       kfree(wm8955);
-       wm8955_codec = NULL;
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_wm8955 = {
+       .probe =        wm8955_probe,
+       .remove =       wm8955_remove,
+       .suspend =      wm8955_suspend,
+       .resume =       wm8955_resume,
+       .set_bias_level = wm8955_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8955_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8955_reg,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8955_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8955_priv *wm8955;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8955 = kzalloc(sizeof(struct wm8955_priv), GFP_KERNEL);
        if (wm8955 == NULL)
                return -ENOMEM;
 
-       codec = &wm8955->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
        i2c_set_clientdata(i2c, wm8955);
-       codec->control_data = i2c;
-       wm8955->pdata = i2c->dev.platform_data;
-
-       codec->dev = &i2c->dev;
 
-       return wm8955_register(wm8955, SND_SOC_I2C);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8955, &wm8955_dai, 1);
+       if (ret < 0)
+               kfree(wm8955);
+       return ret;
 }
 
 static __devexit int wm8955_i2c_remove(struct i2c_client *client)
 {
-       struct wm8955_priv *wm8955 = i2c_get_clientdata(client);
-       wm8955_unregister(wm8955);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -1118,7 +1025,7 @@ MODULE_DEVICE_TABLE(i2c, wm8955_i2c_id);
 
 static struct i2c_driver wm8955_i2c_driver = {
        .driver = {
-               .name = "wm8955",
+               .name = "wm8955-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8955_i2c_probe,
@@ -1129,7 +1036,7 @@ static struct i2c_driver wm8955_i2c_driver = {
 
 static int __init wm8955_modinit(void)
 {
-       int ret;
+       int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8955_i2c_driver);
        if (ret != 0) {
@@ -1137,7 +1044,7 @@ static int __init wm8955_modinit(void)
                       ret);
        }
 #endif
-       return 0;
+       return ret;
 }
 module_init(wm8955_modinit);
 
index ae349c8531f61d3f6d492baea5c56d03cf357f5b..d13fd5c5fa630409d0400b48012c34cd91b8da0a 100644 (file)
@@ -15,9 +15,6 @@
 
 #define WM8955_CLK_MCLK 1
 
-extern struct snd_soc_dai wm8955_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8955;
-
 /*
  * Register values.
  */
index 3c6ee61f6c952220d05a648711eac86230b7cdfa..8d5efb333c33f260b271af07e9352b14679f0502 100644 (file)
@@ -29,8 +29,6 @@
 
 #define AUDIO_NAME "wm8960"
 
-struct snd_soc_codec_device soc_codec_dev_wm8960;
-
 /* R25 - Power 1 */
 #define WM8960_VMID_MASK 0x180
 #define WM8960_VREF      0x40
@@ -75,7 +73,10 @@ static const u16 wm8960_reg[WM8960_CACHEREGNUM] = {
 
 struct wm8960_priv {
        u16 reg_cache[WM8960_CACHEREGNUM];
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+       void *control_data;
+       int (*set_bias_level)(struct snd_soc_codec *,
+                             enum snd_soc_bias_level level);
        struct snd_soc_dapm_widget *lout1;
        struct snd_soc_dapm_widget *rout1;
        struct snd_soc_dapm_widget *out3;
@@ -507,8 +508,7 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3;
        int i;
@@ -849,6 +849,14 @@ static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
        return 0;
 }
 
+static int wm8960_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+
+       return wm8960->set_bias_level(codec, level);
+}
+
 #define WM8960_RATES SNDRV_PCM_RATE_8000_48000
 
 #define WM8960_FORMATS \
@@ -863,8 +871,8 @@ static struct snd_soc_dai_ops wm8960_dai_ops = {
        .set_pll = wm8960_set_dai_pll,
 };
 
-struct snd_soc_dai wm8960_dai = {
-       .name = "WM8960",
+static struct snd_soc_dai_driver wm8960_dai = {
+       .name = "wm8960-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -880,21 +888,18 @@ struct snd_soc_dai wm8960_dai = {
        .ops = &wm8960_dai_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(wm8960_dai);
 
-static int wm8960_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8960_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
 
-       codec->set_bias_level(codec, SND_SOC_BIAS_OFF);
+       wm8960->set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8960_resume(struct platform_device *pdev)
+static int wm8960_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -906,78 +911,19 @@ static int wm8960_resume(struct platform_device *pdev)
                codec->hw_write(codec->control_data, data, 2);
        }
 
-       codec->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
+       wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        return 0;
 }
 
-static struct snd_soc_codec *wm8960_codec;
-
-static int wm8960_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (wm8960_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8960_codec;
-       codec = wm8960_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       snd_soc_add_controls(codec, wm8960_snd_controls,
-                            ARRAY_SIZE(wm8960_snd_controls));
-       wm8960_add_widgets(codec);
-
-       return ret;
-
-pcm_err:
-       return ret;
-}
-
-/* power down chip */
-static int wm8960_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8960 = {
-       .probe =        wm8960_probe,
-       .remove =       wm8960_remove,
-       .suspend =      wm8960_suspend,
-       .resume =       wm8960_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8960);
-
-static int wm8960_register(struct wm8960_priv *wm8960,
-                          enum snd_soc_control_type control)
+static int wm8960_probe(struct snd_soc_codec *codec)
 {
-       struct wm8960_data *pdata = wm8960->codec.dev->platform_data;
-       struct snd_soc_codec *codec = &wm8960->codec;
+       struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+       struct wm8960_data *pdata = dev_get_platdata(codec->dev);
        int ret;
        u16 reg;
 
-       if (wm8960_codec) {
-               dev_err(codec->dev, "Another WM8960 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       codec->set_bias_level = wm8960_set_bias_level_out3;
+       wm8960->set_bias_level = wm8960_set_bias_level_out3;
+       codec->control_data = wm8960->control_data;
 
        if (!pdata) {
                dev_warn(codec->dev, "No platform data supplied\n");
@@ -988,39 +934,22 @@ static int wm8960_register(struct wm8960_priv *wm8960,
                }
 
                if (pdata->capless)
-                       codec->set_bias_level = wm8960_set_bias_level_capless;
+                       wm8960->set_bias_level = wm8960_set_bias_level_capless;
        }
 
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8960);
-       codec->name = "WM8960";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->dai = &wm8960_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8960_CACHEREGNUM;
-       codec->reg_cache = &wm8960->reg_cache;
-
-       memcpy(codec->reg_cache, wm8960_reg, sizeof(wm8960_reg));
-
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8960->control_type);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        ret = wm8960_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset\n");
-               goto err;
+               return ret;
        }
 
-       wm8960_dai.dev = codec->dev;
-
-       codec->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* Latch the update bits */
        reg = snd_soc_read(codec, WM8960_LINVOL);
@@ -1044,62 +973,58 @@ static int wm8960_register(struct wm8960_priv *wm8960,
        reg = snd_soc_read(codec, WM8960_ROUT2);
        snd_soc_write(codec, WM8960_ROUT2, reg | 0x100);
 
-       wm8960_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dai(&wm8960_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
+       snd_soc_add_controls(codec, wm8960_snd_controls,
+                                    ARRAY_SIZE(wm8960_snd_controls));
+       wm8960_add_widgets(codec);
 
        return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm8960);
-       return ret;
 }
 
-static void wm8960_unregister(struct wm8960_priv *wm8960)
+/* power down chip */
+static int wm8960_remove(struct snd_soc_codec *codec)
 {
-       wm8960->codec.set_bias_level(&wm8960->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dai(&wm8960_dai);
-       snd_soc_unregister_codec(&wm8960->codec);
-       kfree(wm8960);
-       wm8960_codec = NULL;
+       struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+
+       wm8960->set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_wm8960 = {
+       .probe =        wm8960_probe,
+       .remove =       wm8960_remove,
+       .suspend =      wm8960_suspend,
+       .resume =       wm8960_resume,
+       .set_bias_level = wm8960_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8960_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8960_reg,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8960_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8960_priv *wm8960;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8960 = kzalloc(sizeof(struct wm8960_priv), GFP_KERNEL);
        if (wm8960 == NULL)
                return -ENOMEM;
 
-       codec = &wm8960->codec;
-
        i2c_set_clientdata(i2c, wm8960);
-       codec->control_data = i2c;
-
-       codec->dev = &i2c->dev;
+       wm8960->control_data = i2c;
 
-       return wm8960_register(wm8960, SND_SOC_I2C);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8960, &wm8960_dai, 1);
+       if (ret < 0)
+               kfree(wm8960);
+       return ret;
 }
 
 static __devexit int wm8960_i2c_remove(struct i2c_client *client)
 {
-       struct wm8960_priv *wm8960 = i2c_get_clientdata(client);
-       wm8960_unregister(wm8960);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -1111,35 +1036,37 @@ MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id);
 
 static struct i2c_driver wm8960_i2c_driver = {
        .driver = {
-               .name = "wm8960",
+               .name = "wm8960-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8960_i2c_probe,
        .remove =   __devexit_p(wm8960_i2c_remove),
        .id_table = wm8960_i2c_id,
 };
+#endif
 
 static int __init wm8960_modinit(void)
 {
-       int ret;
-
+       int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8960_i2c_driver);
        if (ret != 0) {
                printk(KERN_ERR "Failed to register WM8960 I2C driver: %d\n",
                       ret);
        }
-
+#endif
        return ret;
 }
 module_init(wm8960_modinit);
 
 static void __exit wm8960_exit(void)
 {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm8960_i2c_driver);
+#endif
 }
 module_exit(wm8960_exit);
 
-
 MODULE_DESCRIPTION("ASoC WM8960 driver");
 MODULE_AUTHOR("Liam Girdwood");
 MODULE_LICENSE("GPL");
index a5ef65481b86e036bdad252b7aba50a6f14ec2e5..2d8163d7004b86a59c4f34522bd2f1d3f74a8e24 100644 (file)
 #define WM8960_OPCLK_DIV_5_5           (4 << 0)
 #define WM8960_OPCLK_DIV_6             (5 << 0)
 
-extern struct snd_soc_dai wm8960_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8960;
-
 #endif
index 2549d3a297ab957c3bacc608089beef0c688bff2..4f326f6041042742255731ba078574b37a48a6f3 100644 (file)
@@ -288,7 +288,7 @@ static u16 wm8961_reg_defaults[] = {
 };
 
 struct wm8961_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
        int sysclk;
        u16 reg_cache[WM8961_MAX_REGISTER];
 };
@@ -940,8 +940,8 @@ static struct snd_soc_dai_ops wm8961_dai_ops = {
        .set_clkdiv = wm8961_set_clkdiv,
 };
 
-struct snd_soc_dai wm8961_dai = {
-       .name = "WM8961",
+static struct snd_soc_dai_driver wm8961_dai = {
+       .name = "wm8961-hifi",
        .playback = {
                .stream_name = "HiFi Playback",
                .channels_min = 1,
@@ -956,140 +956,22 @@ struct snd_soc_dai wm8961_dai = {
                .formats = WM8961_FORMATS,},
        .ops = &wm8961_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8961_dai);
 
-
-static struct snd_soc_codec *wm8961_codec;
-
-static int wm8961_probe(struct platform_device *pdev)
+static int wm8961_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
        int ret = 0;
-
-       if (wm8961_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8961_codec;
-       codec = wm8961_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       snd_soc_add_controls(codec, wm8961_snd_controls,
-                               ARRAY_SIZE(wm8961_snd_controls));
-       snd_soc_dapm_new_controls(codec, wm8961_dapm_widgets,
-                                 ARRAY_SIZE(wm8961_dapm_widgets));
-       snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
-
-       return ret;
-
-pcm_err:
-       return ret;
-}
-
-static int wm8961_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int wm8961_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-       return 0;
-}
-
-static int wm8961_resume(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-       u16 *reg_cache = codec->reg_cache;
-       int i;
-
-       for (i = 0; i < codec->reg_cache_size; i++) {
-               if (reg_cache[i] == wm8961_reg_defaults[i])
-                       continue;
-
-               if (i == WM8961_SOFTWARE_RESET)
-                       continue;
-
-               snd_soc_write(codec, i, reg_cache[i]);
-       }
-
-       wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       return 0;
-}
-#else
-#define wm8961_suspend NULL
-#define wm8961_resume NULL
-#endif
-
-struct snd_soc_codec_device soc_codec_dev_wm8961 = {
-       .probe =        wm8961_probe,
-       .remove =       wm8961_remove,
-       .suspend =      wm8961_suspend,
-       .resume =       wm8961_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8961);
-
-static int wm8961_register(struct wm8961_priv *wm8961)
-{
-       struct snd_soc_codec *codec = &wm8961->codec;
-       int ret;
        u16 reg;
 
-       if (wm8961_codec) {
-               dev_err(codec->dev, "Another WM8961 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8961);
-       codec->name = "WM8961";
-       codec->owner = THIS_MODULE;
-       codec->dai = &wm8961_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(wm8961->reg_cache);
-       codec->reg_cache = &wm8961->reg_cache;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8961_set_bias_level;
-       codec->volatile_register = wm8961_volatile_register;
-
-       memcpy(codec->reg_cache, wm8961_reg_defaults,
-              sizeof(wm8961_reg_defaults));
-
        ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        reg = snd_soc_read(codec, WM8961_SOFTWARE_RESET);
        if (reg != 0x1801) {
                dev_err(codec->dev, "Device is not a WM8961: ID=0x%x\n", reg);
-               ret = -EINVAL;
-               goto err;
+               return -EINVAL;
        }
 
        /* This isn't volatile - readback doesn't correspond to write */
@@ -1102,7 +984,7 @@ static int wm8961_register(struct wm8961_priv *wm8961)
        ret = wm8961_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset\n");
-               goto err;
+               return ret;
        }
 
        /* Enable class W */
@@ -1140,64 +1022,89 @@ static int wm8961_register(struct wm8961_priv *wm8961)
 
        wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       wm8961_dai.dev = codec->dev;
+       snd_soc_add_controls(codec, wm8961_snd_controls,
+                               ARRAY_SIZE(wm8961_snd_controls));
+       snd_soc_dapm_new_controls(codec, wm8961_dapm_widgets,
+                                 ARRAY_SIZE(wm8961_dapm_widgets));
+       snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
 
-       wm8961_codec = codec;
+       return 0;
+}
 
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
+static int wm8961_remove(struct snd_soc_codec *codec)
+{
+       wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
 
-       ret = snd_soc_register_dai(&wm8961_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
+#ifdef CONFIG_PM
+static int wm8961_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+       wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm8961);
-       return ret;
 }
 
-static void wm8961_unregister(struct wm8961_priv *wm8961)
+static int wm8961_resume(struct snd_soc_codec *codec)
 {
-       wm8961_set_bias_level(&wm8961->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dai(&wm8961_dai);
-       snd_soc_unregister_codec(&wm8961->codec);
-       kfree(wm8961);
-       wm8961_codec = NULL;
+       u16 *reg_cache = codec->reg_cache;
+       int i;
+
+       for (i = 0; i < codec->driver->reg_cache_size; i++) {
+               if (reg_cache[i] == wm8961_reg_defaults[i])
+                       continue;
+
+               if (i == WM8961_SOFTWARE_RESET)
+                       continue;
+
+               snd_soc_write(codec, i, reg_cache[i]);
+       }
+
+       wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
 }
+#else
+#define wm8961_suspend NULL
+#define wm8961_resume NULL
+#endif
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8961 = {
+       .probe =        wm8961_probe,
+       .remove =       wm8961_remove,
+       .suspend =      wm8961_suspend,
+       .resume =       wm8961_resume,
+       .set_bias_level = wm8961_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8961_reg_defaults),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8961_reg_defaults,
+       .volatile_register = wm8961_volatile_register,
+};
 
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8961_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8961_priv *wm8961;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8961 = kzalloc(sizeof(struct wm8961_priv), GFP_KERNEL);
        if (wm8961 == NULL)
                return -ENOMEM;
 
-       codec = &wm8961->codec;
-
        i2c_set_clientdata(i2c, wm8961);
-       codec->control_data = i2c;
-
-       codec->dev = &i2c->dev;
 
-       return wm8961_register(wm8961);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8961, &wm8961_dai, 1);
+       if (ret < 0)
+               kfree(wm8961);
+       return ret;
 }
 
 static __devexit int wm8961_i2c_remove(struct i2c_client *client)
 {
-       struct wm8961_priv *wm8961 = i2c_get_clientdata(client);
-       wm8961_unregister(wm8961);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -1209,35 +1116,37 @@ MODULE_DEVICE_TABLE(i2c, wm8961_i2c_id);
 
 static struct i2c_driver wm8961_i2c_driver = {
        .driver = {
-               .name = "wm8961",
+               .name = "wm8961-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8961_i2c_probe,
        .remove =   __devexit_p(wm8961_i2c_remove),
        .id_table = wm8961_i2c_id,
 };
+#endif
 
 static int __init wm8961_modinit(void)
 {
-       int ret;
-
+       int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8961_i2c_driver);
        if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8961 I2C driver: %d\n",
+               printk(KERN_ERR "Failed to register wm8961 I2C driver: %d\n",
                       ret);
        }
-
+#endif
        return ret;
 }
 module_init(wm8961_modinit);
 
 static void __exit wm8961_exit(void)
 {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm8961_i2c_driver);
+#endif
 }
 module_exit(wm8961_exit);
 
-
 MODULE_DESCRIPTION("ASoC WM8961 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 MODULE_LICENSE("GPL");
index 5513bfd720d68c05167ffa6e6179c45eed322477..1d736e5701c85b7a2bdcb80f6efdcbf24a66822c 100644 (file)
@@ -11,9 +11,6 @@
 
 #include <sound/soc.h>
 
-extern struct snd_soc_codec_device soc_codec_dev_wm8961;
-extern struct snd_soc_dai wm8961_dai;
-
 #define WM8961_BCLK  1
 #define WM8961_LRCLK 2
 
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
new file mode 100644 (file)
index 0000000..894d0cd
--- /dev/null
@@ -0,0 +1,3977 @@
+/*
+ * wm8962.c  --  WM8962 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/gcd.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/workqueue.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 <sound/wm8962.h>
+
+#include "wm8962.h"
+
+#define WM8962_NUM_SUPPLIES 8
+static const char *wm8962_supply_names[WM8962_NUM_SUPPLIES] = {
+       "DCVDD",
+       "DBVDD",
+       "AVDD",
+       "CPVDD",
+       "MICVDD",
+       "PLLVDD",
+       "SPKVDD1",
+       "SPKVDD2",
+};
+
+/* codec private data */
+struct wm8962_priv {
+       struct snd_soc_codec *codec;
+
+       u16 reg_cache[WM8962_MAX_REGISTER + 1];
+
+       int sysclk;
+       int sysclk_rate;
+
+       int bclk;  /* Desired BCLK */
+       int lrclk;
+
+       int fll_src;
+       int fll_fref;
+       int fll_fout;
+
+       struct delayed_work mic_work;
+       struct snd_soc_jack *jack;
+
+       struct regulator_bulk_data supplies[WM8962_NUM_SUPPLIES];
+       struct notifier_block disable_nb[WM8962_NUM_SUPPLIES];
+
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+       struct input_dev *beep;
+       struct work_struct beep_work;
+       int beep_rate;
+#endif
+
+#ifdef CONFIG_GPIOLIB
+       struct gpio_chip gpio_chip;
+#endif
+};
+
+/* 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 WM8962_REGULATOR_EVENT(n) \
+static int wm8962_regulator_event_##n(struct notifier_block *nb, \
+                                   unsigned long event, void *data)    \
+{ \
+       struct wm8962_priv *wm8962 = container_of(nb, struct wm8962_priv, \
+                                                 disable_nb[n]); \
+       if (event & REGULATOR_EVENT_DISABLE) { \
+               wm8962->codec->cache_sync = 1; \
+       } \
+       return 0; \
+}
+
+WM8962_REGULATOR_EVENT(0)
+WM8962_REGULATOR_EVENT(1)
+WM8962_REGULATOR_EVENT(2)
+WM8962_REGULATOR_EVENT(3)
+WM8962_REGULATOR_EVENT(4)
+WM8962_REGULATOR_EVENT(5)
+WM8962_REGULATOR_EVENT(6)
+WM8962_REGULATOR_EVENT(7)
+
+static const u16 wm8962_reg[WM8962_MAX_REGISTER + 1] = {
+       [0] = 0x009F,     /* R0     - Left Input volume */
+       [1] = 0x049F,     /* R1     - Right Input volume */
+       [2] = 0x0000,     /* R2     - HPOUTL volume */
+       [3] = 0x0000,     /* R3     - HPOUTR volume */
+       [4] = 0x0020,     /* R4     - Clocking1 */
+       [5] = 0x0018,     /* R5     - ADC & DAC Control 1 */
+       [6] = 0x2008,     /* R6     - ADC & DAC Control 2 */
+       [7] = 0x000A,     /* R7     - Audio Interface 0 */
+       [8] = 0x01E4,     /* R8     - Clocking2 */
+       [9] = 0x0300,     /* R9     - Audio Interface 1 */
+       [10] = 0x00C0,    /* R10    - Left DAC volume */
+       [11] = 0x00C0,    /* R11    - Right DAC volume */
+
+       [14] = 0x0040,     /* R14    - Audio Interface 2 */
+       [15] = 0x6243,     /* R15    - Software Reset */
+
+       [17] = 0x007B,     /* R17    - ALC1 */
+       [18] = 0x0000,     /* R18    - ALC2 */
+       [19] = 0x1C32,     /* R19    - ALC3 */
+       [20] = 0x3200,     /* R20    - Noise Gate */
+       [21] = 0x00C0,     /* R21    - Left ADC volume */
+       [22] = 0x00C0,     /* R22    - Right ADC volume */
+       [23] = 0x0160,     /* R23    - Additional control(1) */
+       [24] = 0x0000,     /* R24    - Additional control(2) */
+       [25] = 0x0000,     /* R25    - Pwr Mgmt (1) */
+       [26] = 0x0000,     /* R26    - Pwr Mgmt (2) */
+       [27] = 0x0010,     /* R27    - Additional Control (3) */
+       [28] = 0x0000,     /* R28    - Anti-pop */
+
+       [30] = 0x005E,     /* R30    - Clocking 3 */
+       [31] = 0x0000,     /* R31    - Input mixer control (1) */
+       [32] = 0x0145,     /* R32    - Left input mixer volume */
+       [33] = 0x0145,     /* R33    - Right input mixer volume */
+       [34] = 0x0009,     /* R34    - Input mixer control (2) */
+       [35] = 0x0003,     /* R35    - Input bias control */
+       [37] = 0x0008,     /* R37    - Left input PGA control */
+       [38] = 0x0008,     /* R38    - Right input PGA control */
+
+       [40] = 0x0000,     /* R40    - SPKOUTL volume */
+       [41] = 0x0000,     /* R41    - SPKOUTR volume */
+
+       [47] = 0x0000,     /* R47    - Thermal Shutdown Status */
+       [48] = 0x8027,     /* R48    - Additional Control (4) */
+       [49] = 0x0010,     /* R49    - Class D Control 1 */
+
+       [51] = 0x0003,     /* R51    - Class D Control 2 */
+
+       [56] = 0x0506,     /* R56    - Clocking 4 */
+       [57] = 0x0000,     /* R57    - DAC DSP Mixing (1) */
+       [58] = 0x0000,     /* R58    - DAC DSP Mixing (2) */
+
+       [60] = 0x0300,     /* R60    - DC Servo 0 */
+       [61] = 0x0300,     /* R61    - DC Servo 1 */
+
+       [64] = 0x0810,     /* R64    - DC Servo 4 */
+
+       [66] = 0x0000,     /* R66    - DC Servo 6 */
+
+       [68] = 0x001B,     /* R68    - Analogue PGA Bias */
+       [69] = 0x0000,     /* R69    - Analogue HP 0 */
+
+       [71] = 0x01FB,     /* R71    - Analogue HP 2 */
+       [72] = 0x0000,     /* R72    - Charge Pump 1 */
+
+       [82] = 0x0004,     /* R82    - Charge Pump B */
+
+       [87] = 0x0000,     /* R87    - Write Sequencer Control 1 */
+
+       [90] = 0x0000,     /* R90    - Write Sequencer Control 2 */
+
+       [93] = 0x0000,     /* R93    - Write Sequencer Control 3 */
+       [94] = 0x0000,     /* R94    - Control Interface */
+
+       [99] = 0x0000,     /* R99    - Mixer Enables */
+       [100] = 0x0000,     /* R100   - Headphone Mixer (1) */
+       [101] = 0x0000,     /* R101   - Headphone Mixer (2) */
+       [102] = 0x013F,     /* R102   - Headphone Mixer (3) */
+       [103] = 0x013F,     /* R103   - Headphone Mixer (4) */
+
+       [105] = 0x0000,     /* R105   - Speaker Mixer (1) */
+       [106] = 0x0000,     /* R106   - Speaker Mixer (2) */
+       [107] = 0x013F,     /* R107   - Speaker Mixer (3) */
+       [108] = 0x013F,     /* R108   - Speaker Mixer (4) */
+       [109] = 0x0003,     /* R109   - Speaker Mixer (5) */
+       [110] = 0x0002,     /* R110   - Beep Generator (1) */
+
+       [115] = 0x0006,     /* R115   - Oscillator Trim (3) */
+       [116] = 0x0026,     /* R116   - Oscillator Trim (4) */
+
+       [119] = 0x0000,     /* R119   - Oscillator Trim (7) */
+
+       [124] = 0x0011,     /* R124   - Analogue Clocking1 */
+       [125] = 0x004B,     /* R125   - Analogue Clocking2 */
+       [126] = 0x000D,     /* R126   - Analogue Clocking3 */
+       [127] = 0x0000,     /* R127   - PLL Software Reset */
+
+       [129] = 0x0000,     /* R129   - PLL2 */
+
+       [131] = 0x0000,     /* R131   - PLL 4 */
+
+       [136] = 0x0067,     /* R136   - PLL 9 */
+       [137] = 0x001C,     /* R137   - PLL 10 */
+       [138] = 0x0071,     /* R138   - PLL 11 */
+       [139] = 0x00C7,     /* R139   - PLL 12 */
+       [140] = 0x0067,     /* R140   - PLL 13 */
+       [141] = 0x0048,     /* R141   - PLL 14 */
+       [142] = 0x0022,     /* R142   - PLL 15 */
+       [143] = 0x0097,     /* R143   - PLL 16 */
+
+       [155] = 0x000C,     /* R155   - FLL Control (1) */
+       [156] = 0x0039,     /* R156   - FLL Control (2) */
+       [157] = 0x0180,     /* R157   - FLL Control (3) */
+
+       [159] = 0x0032,     /* R159   - FLL Control (5) */
+       [160] = 0x0018,     /* R160   - FLL Control (6) */
+       [161] = 0x007D,     /* R161   - FLL Control (7) */
+       [162] = 0x0008,     /* R162   - FLL Control (8) */
+
+       [252] = 0x0005,     /* R252   - General test 1 */
+
+       [256] = 0x0000,     /* R256   - DF1 */
+       [257] = 0x0000,     /* R257   - DF2 */
+       [258] = 0x0000,     /* R258   - DF3 */
+       [259] = 0x0000,     /* R259   - DF4 */
+       [260] = 0x0000,     /* R260   - DF5 */
+       [261] = 0x0000,     /* R261   - DF6 */
+       [262] = 0x0000,     /* R262   - DF7 */
+
+       [264] = 0x0000,     /* R264   - LHPF1 */
+       [265] = 0x0000,     /* R265   - LHPF2 */
+
+       [268] = 0x0000,     /* R268   - THREED1 */
+       [269] = 0x0000,     /* R269   - THREED2 */
+       [270] = 0x0000,     /* R270   - THREED3 */
+       [271] = 0x0000,     /* R271   - THREED4 */
+
+       [276] = 0x000C,     /* R276   - DRC 1 */
+       [277] = 0x0925,     /* R277   - DRC 2 */
+       [278] = 0x0000,     /* R278   - DRC 3 */
+       [279] = 0x0000,     /* R279   - DRC 4 */
+       [280] = 0x0000,     /* R280   - DRC 5 */
+
+       [285] = 0x0000,     /* R285   - Tloopback */
+
+       [335] = 0x0004,     /* R335   - EQ1 */
+       [336] = 0x6318,     /* R336   - EQ2 */
+       [337] = 0x6300,     /* R337   - EQ3 */
+       [338] = 0x0FCA,     /* R338   - EQ4 */
+       [339] = 0x0400,     /* R339   - EQ5 */
+       [340] = 0x00D8,     /* R340   - EQ6 */
+       [341] = 0x1EB5,     /* R341   - EQ7 */
+       [342] = 0xF145,     /* R342   - EQ8 */
+       [343] = 0x0B75,     /* R343   - EQ9 */
+       [344] = 0x01C5,     /* R344   - EQ10 */
+       [345] = 0x1C58,     /* R345   - EQ11 */
+       [346] = 0xF373,     /* R346   - EQ12 */
+       [347] = 0x0A54,     /* R347   - EQ13 */
+       [348] = 0x0558,     /* R348   - EQ14 */
+       [349] = 0x168E,     /* R349   - EQ15 */
+       [350] = 0xF829,     /* R350   - EQ16 */
+       [351] = 0x07AD,     /* R351   - EQ17 */
+       [352] = 0x1103,     /* R352   - EQ18 */
+       [353] = 0x0564,     /* R353   - EQ19 */
+       [354] = 0x0559,     /* R354   - EQ20 */
+       [355] = 0x4000,     /* R355   - EQ21 */
+       [356] = 0x6318,     /* R356   - EQ22 */
+       [357] = 0x6300,     /* R357   - EQ23 */
+       [358] = 0x0FCA,     /* R358   - EQ24 */
+       [359] = 0x0400,     /* R359   - EQ25 */
+       [360] = 0x00D8,     /* R360   - EQ26 */
+       [361] = 0x1EB5,     /* R361   - EQ27 */
+       [362] = 0xF145,     /* R362   - EQ28 */
+       [363] = 0x0B75,     /* R363   - EQ29 */
+       [364] = 0x01C5,     /* R364   - EQ30 */
+       [365] = 0x1C58,     /* R365   - EQ31 */
+       [366] = 0xF373,     /* R366   - EQ32 */
+       [367] = 0x0A54,     /* R367   - EQ33 */
+       [368] = 0x0558,     /* R368   - EQ34 */
+       [369] = 0x168E,     /* R369   - EQ35 */
+       [370] = 0xF829,     /* R370   - EQ36 */
+       [371] = 0x07AD,     /* R371   - EQ37 */
+       [372] = 0x1103,     /* R372   - EQ38 */
+       [373] = 0x0564,     /* R373   - EQ39 */
+       [374] = 0x0559,     /* R374   - EQ40 */
+       [375] = 0x4000,     /* R375   - EQ41 */
+
+       [513] = 0x0000,     /* R513   - GPIO 2 */
+       [514] = 0x0000,     /* R514   - GPIO 3 */
+
+       [516] = 0x8100,     /* R516   - GPIO 5 */
+       [517] = 0x8100,     /* R517   - GPIO 6 */
+
+       [560] = 0x0000,     /* R560   - Interrupt Status 1 */
+       [561] = 0x0000,     /* R561   - Interrupt Status 2 */
+
+       [568] = 0x0030,     /* R568   - Interrupt Status 1 Mask */
+       [569] = 0xFFED,     /* R569   - Interrupt Status 2 Mask */
+
+       [576] = 0x0000,     /* R576   - Interrupt Control */
+
+       [584] = 0x002D,     /* R584   - IRQ Debounce */
+
+       [586] = 0x0000,     /* R586   -  MICINT Source Pol */
+
+       [768] = 0x1C00,     /* R768   - DSP2 Power Management */
+
+       [1037] = 0x0000,     /* R1037  - DSP2_ExecControl */
+
+       [8192] = 0x0000,     /* R8192  - DSP2 Instruction RAM 0 */
+
+       [9216] = 0x0030,     /* R9216  - DSP2 Address RAM 2 */
+       [9217] = 0x0000,     /* R9217  - DSP2 Address RAM 1 */
+       [9218] = 0x0000,     /* R9218  - DSP2 Address RAM 0 */
+
+       [12288] = 0x0000,     /* R12288 - DSP2 Data1 RAM 1 */
+       [12289] = 0x0000,     /* R12289 - DSP2 Data1 RAM 0 */
+
+       [13312] = 0x0000,     /* R13312 - DSP2 Data2 RAM 1 */
+       [13313] = 0x0000,     /* R13313 - DSP2 Data2 RAM 0 */
+
+       [14336] = 0x0000,     /* R14336 - DSP2 Data3 RAM 1 */
+       [14337] = 0x0000,     /* R14337 - DSP2 Data3 RAM 0 */
+
+       [15360] = 0x000A,     /* R15360 - DSP2 Coeff RAM 0 */
+
+       [16384] = 0x0000,     /* R16384 - RETUNEADC_SHARED_COEFF_1 */
+       [16385] = 0x0000,     /* R16385 - RETUNEADC_SHARED_COEFF_0 */
+       [16386] = 0x0000,     /* R16386 - RETUNEDAC_SHARED_COEFF_1 */
+       [16387] = 0x0000,     /* R16387 - RETUNEDAC_SHARED_COEFF_0 */
+       [16388] = 0x0000,     /* R16388 - SOUNDSTAGE_ENABLES_1 */
+       [16389] = 0x0000,     /* R16389 - SOUNDSTAGE_ENABLES_0 */
+
+       [16896] = 0x0002,     /* R16896 - HDBASS_AI_1 */
+       [16897] = 0xBD12,     /* R16897 - HDBASS_AI_0 */
+       [16898] = 0x007C,     /* R16898 - HDBASS_AR_1 */
+       [16899] = 0x586C,     /* R16899 - HDBASS_AR_0 */
+       [16900] = 0x0053,     /* R16900 - HDBASS_B_1 */
+       [16901] = 0x8121,     /* R16901 - HDBASS_B_0 */
+       [16902] = 0x003F,     /* R16902 - HDBASS_K_1 */
+       [16903] = 0x8BD8,     /* R16903 - HDBASS_K_0 */
+       [16904] = 0x0032,     /* R16904 - HDBASS_N1_1 */
+       [16905] = 0xF52D,     /* R16905 - HDBASS_N1_0 */
+       [16906] = 0x0065,     /* R16906 - HDBASS_N2_1 */
+       [16907] = 0xAC8C,     /* R16907 - HDBASS_N2_0 */
+       [16908] = 0x006B,     /* R16908 - HDBASS_N3_1 */
+       [16909] = 0xE087,     /* R16909 - HDBASS_N3_0 */
+       [16910] = 0x0072,     /* R16910 - HDBASS_N4_1 */
+       [16911] = 0x1483,     /* R16911 - HDBASS_N4_0 */
+       [16912] = 0x0072,     /* R16912 - HDBASS_N5_1 */
+       [16913] = 0x1483,     /* R16913 - HDBASS_N5_0 */
+       [16914] = 0x0043,     /* R16914 - HDBASS_X1_1 */
+       [16915] = 0x3525,     /* R16915 - HDBASS_X1_0 */
+       [16916] = 0x0006,     /* R16916 - HDBASS_X2_1 */
+       [16917] = 0x6A4A,     /* R16917 - HDBASS_X2_0 */
+       [16918] = 0x0043,     /* R16918 - HDBASS_X3_1 */
+       [16919] = 0x6079,     /* R16919 - HDBASS_X3_0 */
+       [16920] = 0x0008,     /* R16920 - HDBASS_ATK_1 */
+       [16921] = 0x0000,     /* R16921 - HDBASS_ATK_0 */
+       [16922] = 0x0001,     /* R16922 - HDBASS_DCY_1 */
+       [16923] = 0x0000,     /* R16923 - HDBASS_DCY_0 */
+       [16924] = 0x0059,     /* R16924 - HDBASS_PG_1 */
+       [16925] = 0x999A,     /* R16925 - HDBASS_PG_0 */
+
+       [17048] = 0x0083,     /* R17408 - HPF_C_1 */
+       [17049] = 0x98AD,     /* R17409 - HPF_C_0 */
+
+       [17920] = 0x007F,     /* R17920 - ADCL_RETUNE_C1_1 */
+       [17921] = 0xFFFF,     /* R17921 - ADCL_RETUNE_C1_0 */
+       [17922] = 0x0000,     /* R17922 - ADCL_RETUNE_C2_1 */
+       [17923] = 0x0000,     /* R17923 - ADCL_RETUNE_C2_0 */
+       [17924] = 0x0000,     /* R17924 - ADCL_RETUNE_C3_1 */
+       [17925] = 0x0000,     /* R17925 - ADCL_RETUNE_C3_0 */
+       [17926] = 0x0000,     /* R17926 - ADCL_RETUNE_C4_1 */
+       [17927] = 0x0000,     /* R17927 - ADCL_RETUNE_C4_0 */
+       [17928] = 0x0000,     /* R17928 - ADCL_RETUNE_C5_1 */
+       [17929] = 0x0000,     /* R17929 - ADCL_RETUNE_C5_0 */
+       [17930] = 0x0000,     /* R17930 - ADCL_RETUNE_C6_1 */
+       [17931] = 0x0000,     /* R17931 - ADCL_RETUNE_C6_0 */
+       [17932] = 0x0000,     /* R17932 - ADCL_RETUNE_C7_1 */
+       [17933] = 0x0000,     /* R17933 - ADCL_RETUNE_C7_0 */
+       [17934] = 0x0000,     /* R17934 - ADCL_RETUNE_C8_1 */
+       [17935] = 0x0000,     /* R17935 - ADCL_RETUNE_C8_0 */
+       [17936] = 0x0000,     /* R17936 - ADCL_RETUNE_C9_1 */
+       [17937] = 0x0000,     /* R17937 - ADCL_RETUNE_C9_0 */
+       [17938] = 0x0000,     /* R17938 - ADCL_RETUNE_C10_1 */
+       [17939] = 0x0000,     /* R17939 - ADCL_RETUNE_C10_0 */
+       [17940] = 0x0000,     /* R17940 - ADCL_RETUNE_C11_1 */
+       [17941] = 0x0000,     /* R17941 - ADCL_RETUNE_C11_0 */
+       [17942] = 0x0000,     /* R17942 - ADCL_RETUNE_C12_1 */
+       [17943] = 0x0000,     /* R17943 - ADCL_RETUNE_C12_0 */
+       [17944] = 0x0000,     /* R17944 - ADCL_RETUNE_C13_1 */
+       [17945] = 0x0000,     /* R17945 - ADCL_RETUNE_C13_0 */
+       [17946] = 0x0000,     /* R17946 - ADCL_RETUNE_C14_1 */
+       [17947] = 0x0000,     /* R17947 - ADCL_RETUNE_C14_0 */
+       [17948] = 0x0000,     /* R17948 - ADCL_RETUNE_C15_1 */
+       [17949] = 0x0000,     /* R17949 - ADCL_RETUNE_C15_0 */
+       [17950] = 0x0000,     /* R17950 - ADCL_RETUNE_C16_1 */
+       [17951] = 0x0000,     /* R17951 - ADCL_RETUNE_C16_0 */
+       [17952] = 0x0000,     /* R17952 - ADCL_RETUNE_C17_1 */
+       [17953] = 0x0000,     /* R17953 - ADCL_RETUNE_C17_0 */
+       [17954] = 0x0000,     /* R17954 - ADCL_RETUNE_C18_1 */
+       [17955] = 0x0000,     /* R17955 - ADCL_RETUNE_C18_0 */
+       [17956] = 0x0000,     /* R17956 - ADCL_RETUNE_C19_1 */
+       [17957] = 0x0000,     /* R17957 - ADCL_RETUNE_C19_0 */
+       [17958] = 0x0000,     /* R17958 - ADCL_RETUNE_C20_1 */
+       [17959] = 0x0000,     /* R17959 - ADCL_RETUNE_C20_0 */
+       [17960] = 0x0000,     /* R17960 - ADCL_RETUNE_C21_1 */
+       [17961] = 0x0000,     /* R17961 - ADCL_RETUNE_C21_0 */
+       [17962] = 0x0000,     /* R17962 - ADCL_RETUNE_C22_1 */
+       [17963] = 0x0000,     /* R17963 - ADCL_RETUNE_C22_0 */
+       [17964] = 0x0000,     /* R17964 - ADCL_RETUNE_C23_1 */
+       [17965] = 0x0000,     /* R17965 - ADCL_RETUNE_C23_0 */
+       [17966] = 0x0000,     /* R17966 - ADCL_RETUNE_C24_1 */
+       [17967] = 0x0000,     /* R17967 - ADCL_RETUNE_C24_0 */
+       [17968] = 0x0000,     /* R17968 - ADCL_RETUNE_C25_1 */
+       [17969] = 0x0000,     /* R17969 - ADCL_RETUNE_C25_0 */
+       [17970] = 0x0000,     /* R17970 - ADCL_RETUNE_C26_1 */
+       [17971] = 0x0000,     /* R17971 - ADCL_RETUNE_C26_0 */
+       [17972] = 0x0000,     /* R17972 - ADCL_RETUNE_C27_1 */
+       [17973] = 0x0000,     /* R17973 - ADCL_RETUNE_C27_0 */
+       [17974] = 0x0000,     /* R17974 - ADCL_RETUNE_C28_1 */
+       [17975] = 0x0000,     /* R17975 - ADCL_RETUNE_C28_0 */
+       [17976] = 0x0000,     /* R17976 - ADCL_RETUNE_C29_1 */
+       [17977] = 0x0000,     /* R17977 - ADCL_RETUNE_C29_0 */
+       [17978] = 0x0000,     /* R17978 - ADCL_RETUNE_C30_1 */
+       [17979] = 0x0000,     /* R17979 - ADCL_RETUNE_C30_0 */
+       [17980] = 0x0000,     /* R17980 - ADCL_RETUNE_C31_1 */
+       [17981] = 0x0000,     /* R17981 - ADCL_RETUNE_C31_0 */
+       [17982] = 0x0000,     /* R17982 - ADCL_RETUNE_C32_1 */
+       [17983] = 0x0000,     /* R17983 - ADCL_RETUNE_C32_0 */
+
+       [18432] = 0x0020,     /* R18432 - RETUNEADC_PG2_1 */
+       [18433] = 0x0000,     /* R18433 - RETUNEADC_PG2_0 */
+       [18434] = 0x0040,     /* R18434 - RETUNEADC_PG_1 */
+       [18435] = 0x0000,     /* R18435 - RETUNEADC_PG_0 */
+
+       [18944] = 0x007F,     /* R18944 - ADCR_RETUNE_C1_1 */
+       [18945] = 0xFFFF,     /* R18945 - ADCR_RETUNE_C1_0 */
+       [18946] = 0x0000,     /* R18946 - ADCR_RETUNE_C2_1 */
+       [18947] = 0x0000,     /* R18947 - ADCR_RETUNE_C2_0 */
+       [18948] = 0x0000,     /* R18948 - ADCR_RETUNE_C3_1 */
+       [18949] = 0x0000,     /* R18949 - ADCR_RETUNE_C3_0 */
+       [18950] = 0x0000,     /* R18950 - ADCR_RETUNE_C4_1 */
+       [18951] = 0x0000,     /* R18951 - ADCR_RETUNE_C4_0 */
+       [18952] = 0x0000,     /* R18952 - ADCR_RETUNE_C5_1 */
+       [18953] = 0x0000,     /* R18953 - ADCR_RETUNE_C5_0 */
+       [18954] = 0x0000,     /* R18954 - ADCR_RETUNE_C6_1 */
+       [18955] = 0x0000,     /* R18955 - ADCR_RETUNE_C6_0 */
+       [18956] = 0x0000,     /* R18956 - ADCR_RETUNE_C7_1 */
+       [18957] = 0x0000,     /* R18957 - ADCR_RETUNE_C7_0 */
+       [18958] = 0x0000,     /* R18958 - ADCR_RETUNE_C8_1 */
+       [18959] = 0x0000,     /* R18959 - ADCR_RETUNE_C8_0 */
+       [18960] = 0x0000,     /* R18960 - ADCR_RETUNE_C9_1 */
+       [18961] = 0x0000,     /* R18961 - ADCR_RETUNE_C9_0 */
+       [18962] = 0x0000,     /* R18962 - ADCR_RETUNE_C10_1 */
+       [18963] = 0x0000,     /* R18963 - ADCR_RETUNE_C10_0 */
+       [18964] = 0x0000,     /* R18964 - ADCR_RETUNE_C11_1 */
+       [18965] = 0x0000,     /* R18965 - ADCR_RETUNE_C11_0 */
+       [18966] = 0x0000,     /* R18966 - ADCR_RETUNE_C12_1 */
+       [18967] = 0x0000,     /* R18967 - ADCR_RETUNE_C12_0 */
+       [18968] = 0x0000,     /* R18968 - ADCR_RETUNE_C13_1 */
+       [18969] = 0x0000,     /* R18969 - ADCR_RETUNE_C13_0 */
+       [18970] = 0x0000,     /* R18970 - ADCR_RETUNE_C14_1 */
+       [18971] = 0x0000,     /* R18971 - ADCR_RETUNE_C14_0 */
+       [18972] = 0x0000,     /* R18972 - ADCR_RETUNE_C15_1 */
+       [18973] = 0x0000,     /* R18973 - ADCR_RETUNE_C15_0 */
+       [18974] = 0x0000,     /* R18974 - ADCR_RETUNE_C16_1 */
+       [18975] = 0x0000,     /* R18975 - ADCR_RETUNE_C16_0 */
+       [18976] = 0x0000,     /* R18976 - ADCR_RETUNE_C17_1 */
+       [18977] = 0x0000,     /* R18977 - ADCR_RETUNE_C17_0 */
+       [18978] = 0x0000,     /* R18978 - ADCR_RETUNE_C18_1 */
+       [18979] = 0x0000,     /* R18979 - ADCR_RETUNE_C18_0 */
+       [18980] = 0x0000,     /* R18980 - ADCR_RETUNE_C19_1 */
+       [18981] = 0x0000,     /* R18981 - ADCR_RETUNE_C19_0 */
+       [18982] = 0x0000,     /* R18982 - ADCR_RETUNE_C20_1 */
+       [18983] = 0x0000,     /* R18983 - ADCR_RETUNE_C20_0 */
+       [18984] = 0x0000,     /* R18984 - ADCR_RETUNE_C21_1 */
+       [18985] = 0x0000,     /* R18985 - ADCR_RETUNE_C21_0 */
+       [18986] = 0x0000,     /* R18986 - ADCR_RETUNE_C22_1 */
+       [18987] = 0x0000,     /* R18987 - ADCR_RETUNE_C22_0 */
+       [18988] = 0x0000,     /* R18988 - ADCR_RETUNE_C23_1 */
+       [18989] = 0x0000,     /* R18989 - ADCR_RETUNE_C23_0 */
+       [18990] = 0x0000,     /* R18990 - ADCR_RETUNE_C24_1 */
+       [18991] = 0x0000,     /* R18991 - ADCR_RETUNE_C24_0 */
+       [18992] = 0x0000,     /* R18992 - ADCR_RETUNE_C25_1 */
+       [18993] = 0x0000,     /* R18993 - ADCR_RETUNE_C25_0 */
+       [18994] = 0x0000,     /* R18994 - ADCR_RETUNE_C26_1 */
+       [18995] = 0x0000,     /* R18995 - ADCR_RETUNE_C26_0 */
+       [18996] = 0x0000,     /* R18996 - ADCR_RETUNE_C27_1 */
+       [18997] = 0x0000,     /* R18997 - ADCR_RETUNE_C27_0 */
+       [18998] = 0x0000,     /* R18998 - ADCR_RETUNE_C28_1 */
+       [18999] = 0x0000,     /* R18999 - ADCR_RETUNE_C28_0 */
+       [19000] = 0x0000,     /* R19000 - ADCR_RETUNE_C29_1 */
+       [19001] = 0x0000,     /* R19001 - ADCR_RETUNE_C29_0 */
+       [19002] = 0x0000,     /* R19002 - ADCR_RETUNE_C30_1 */
+       [19003] = 0x0000,     /* R19003 - ADCR_RETUNE_C30_0 */
+       [19004] = 0x0000,     /* R19004 - ADCR_RETUNE_C31_1 */
+       [19005] = 0x0000,     /* R19005 - ADCR_RETUNE_C31_0 */
+       [19006] = 0x0000,     /* R19006 - ADCR_RETUNE_C32_1 */
+       [19007] = 0x0000,     /* R19007 - ADCR_RETUNE_C32_0 */
+
+       [19456] = 0x007F,     /* R19456 - DACL_RETUNE_C1_1 */
+       [19457] = 0xFFFF,     /* R19457 - DACL_RETUNE_C1_0 */
+       [19458] = 0x0000,     /* R19458 - DACL_RETUNE_C2_1 */
+       [19459] = 0x0000,     /* R19459 - DACL_RETUNE_C2_0 */
+       [19460] = 0x0000,     /* R19460 - DACL_RETUNE_C3_1 */
+       [19461] = 0x0000,     /* R19461 - DACL_RETUNE_C3_0 */
+       [19462] = 0x0000,     /* R19462 - DACL_RETUNE_C4_1 */
+       [19463] = 0x0000,     /* R19463 - DACL_RETUNE_C4_0 */
+       [19464] = 0x0000,     /* R19464 - DACL_RETUNE_C5_1 */
+       [19465] = 0x0000,     /* R19465 - DACL_RETUNE_C5_0 */
+       [19466] = 0x0000,     /* R19466 - DACL_RETUNE_C6_1 */
+       [19467] = 0x0000,     /* R19467 - DACL_RETUNE_C6_0 */
+       [19468] = 0x0000,     /* R19468 - DACL_RETUNE_C7_1 */
+       [19469] = 0x0000,     /* R19469 - DACL_RETUNE_C7_0 */
+       [19470] = 0x0000,     /* R19470 - DACL_RETUNE_C8_1 */
+       [19471] = 0x0000,     /* R19471 - DACL_RETUNE_C8_0 */
+       [19472] = 0x0000,     /* R19472 - DACL_RETUNE_C9_1 */
+       [19473] = 0x0000,     /* R19473 - DACL_RETUNE_C9_0 */
+       [19474] = 0x0000,     /* R19474 - DACL_RETUNE_C10_1 */
+       [19475] = 0x0000,     /* R19475 - DACL_RETUNE_C10_0 */
+       [19476] = 0x0000,     /* R19476 - DACL_RETUNE_C11_1 */
+       [19477] = 0x0000,     /* R19477 - DACL_RETUNE_C11_0 */
+       [19478] = 0x0000,     /* R19478 - DACL_RETUNE_C12_1 */
+       [19479] = 0x0000,     /* R19479 - DACL_RETUNE_C12_0 */
+       [19480] = 0x0000,     /* R19480 - DACL_RETUNE_C13_1 */
+       [19481] = 0x0000,     /* R19481 - DACL_RETUNE_C13_0 */
+       [19482] = 0x0000,     /* R19482 - DACL_RETUNE_C14_1 */
+       [19483] = 0x0000,     /* R19483 - DACL_RETUNE_C14_0 */
+       [19484] = 0x0000,     /* R19484 - DACL_RETUNE_C15_1 */
+       [19485] = 0x0000,     /* R19485 - DACL_RETUNE_C15_0 */
+       [19486] = 0x0000,     /* R19486 - DACL_RETUNE_C16_1 */
+       [19487] = 0x0000,     /* R19487 - DACL_RETUNE_C16_0 */
+       [19488] = 0x0000,     /* R19488 - DACL_RETUNE_C17_1 */
+       [19489] = 0x0000,     /* R19489 - DACL_RETUNE_C17_0 */
+       [19490] = 0x0000,     /* R19490 - DACL_RETUNE_C18_1 */
+       [19491] = 0x0000,     /* R19491 - DACL_RETUNE_C18_0 */
+       [19492] = 0x0000,     /* R19492 - DACL_RETUNE_C19_1 */
+       [19493] = 0x0000,     /* R19493 - DACL_RETUNE_C19_0 */
+       [19494] = 0x0000,     /* R19494 - DACL_RETUNE_C20_1 */
+       [19495] = 0x0000,     /* R19495 - DACL_RETUNE_C20_0 */
+       [19496] = 0x0000,     /* R19496 - DACL_RETUNE_C21_1 */
+       [19497] = 0x0000,     /* R19497 - DACL_RETUNE_C21_0 */
+       [19498] = 0x0000,     /* R19498 - DACL_RETUNE_C22_1 */
+       [19499] = 0x0000,     /* R19499 - DACL_RETUNE_C22_0 */
+       [19500] = 0x0000,     /* R19500 - DACL_RETUNE_C23_1 */
+       [19501] = 0x0000,     /* R19501 - DACL_RETUNE_C23_0 */
+       [19502] = 0x0000,     /* R19502 - DACL_RETUNE_C24_1 */
+       [19503] = 0x0000,     /* R19503 - DACL_RETUNE_C24_0 */
+       [19504] = 0x0000,     /* R19504 - DACL_RETUNE_C25_1 */
+       [19505] = 0x0000,     /* R19505 - DACL_RETUNE_C25_0 */
+       [19506] = 0x0000,     /* R19506 - DACL_RETUNE_C26_1 */
+       [19507] = 0x0000,     /* R19507 - DACL_RETUNE_C26_0 */
+       [19508] = 0x0000,     /* R19508 - DACL_RETUNE_C27_1 */
+       [19509] = 0x0000,     /* R19509 - DACL_RETUNE_C27_0 */
+       [19510] = 0x0000,     /* R19510 - DACL_RETUNE_C28_1 */
+       [19511] = 0x0000,     /* R19511 - DACL_RETUNE_C28_0 */
+       [19512] = 0x0000,     /* R19512 - DACL_RETUNE_C29_1 */
+       [19513] = 0x0000,     /* R19513 - DACL_RETUNE_C29_0 */
+       [19514] = 0x0000,     /* R19514 - DACL_RETUNE_C30_1 */
+       [19515] = 0x0000,     /* R19515 - DACL_RETUNE_C30_0 */
+       [19516] = 0x0000,     /* R19516 - DACL_RETUNE_C31_1 */
+       [19517] = 0x0000,     /* R19517 - DACL_RETUNE_C31_0 */
+       [19518] = 0x0000,     /* R19518 - DACL_RETUNE_C32_1 */
+       [19519] = 0x0000,     /* R19519 - DACL_RETUNE_C32_0 */
+
+       [19968] = 0x0020,     /* R19968 - RETUNEDAC_PG2_1 */
+       [19969] = 0x0000,     /* R19969 - RETUNEDAC_PG2_0 */
+       [19970] = 0x0040,     /* R19970 - RETUNEDAC_PG_1 */
+       [19971] = 0x0000,     /* R19971 - RETUNEDAC_PG_0 */
+
+       [20480] = 0x007F,     /* R20480 - DACR_RETUNE_C1_1 */
+       [20481] = 0xFFFF,     /* R20481 - DACR_RETUNE_C1_0 */
+       [20482] = 0x0000,     /* R20482 - DACR_RETUNE_C2_1 */
+       [20483] = 0x0000,     /* R20483 - DACR_RETUNE_C2_0 */
+       [20484] = 0x0000,     /* R20484 - DACR_RETUNE_C3_1 */
+       [20485] = 0x0000,     /* R20485 - DACR_RETUNE_C3_0 */
+       [20486] = 0x0000,     /* R20486 - DACR_RETUNE_C4_1 */
+       [20487] = 0x0000,     /* R20487 - DACR_RETUNE_C4_0 */
+       [20488] = 0x0000,     /* R20488 - DACR_RETUNE_C5_1 */
+       [20489] = 0x0000,     /* R20489 - DACR_RETUNE_C5_0 */
+       [20490] = 0x0000,     /* R20490 - DACR_RETUNE_C6_1 */
+       [20491] = 0x0000,     /* R20491 - DACR_RETUNE_C6_0 */
+       [20492] = 0x0000,     /* R20492 - DACR_RETUNE_C7_1 */
+       [20493] = 0x0000,     /* R20493 - DACR_RETUNE_C7_0 */
+       [20494] = 0x0000,     /* R20494 - DACR_RETUNE_C8_1 */
+       [20495] = 0x0000,     /* R20495 - DACR_RETUNE_C8_0 */
+       [20496] = 0x0000,     /* R20496 - DACR_RETUNE_C9_1 */
+       [20497] = 0x0000,     /* R20497 - DACR_RETUNE_C9_0 */
+       [20498] = 0x0000,     /* R20498 - DACR_RETUNE_C10_1 */
+       [20499] = 0x0000,     /* R20499 - DACR_RETUNE_C10_0 */
+       [20500] = 0x0000,     /* R20500 - DACR_RETUNE_C11_1 */
+       [20501] = 0x0000,     /* R20501 - DACR_RETUNE_C11_0 */
+       [20502] = 0x0000,     /* R20502 - DACR_RETUNE_C12_1 */
+       [20503] = 0x0000,     /* R20503 - DACR_RETUNE_C12_0 */
+       [20504] = 0x0000,     /* R20504 - DACR_RETUNE_C13_1 */
+       [20505] = 0x0000,     /* R20505 - DACR_RETUNE_C13_0 */
+       [20506] = 0x0000,     /* R20506 - DACR_RETUNE_C14_1 */
+       [20507] = 0x0000,     /* R20507 - DACR_RETUNE_C14_0 */
+       [20508] = 0x0000,     /* R20508 - DACR_RETUNE_C15_1 */
+       [20509] = 0x0000,     /* R20509 - DACR_RETUNE_C15_0 */
+       [20510] = 0x0000,     /* R20510 - DACR_RETUNE_C16_1 */
+       [20511] = 0x0000,     /* R20511 - DACR_RETUNE_C16_0 */
+       [20512] = 0x0000,     /* R20512 - DACR_RETUNE_C17_1 */
+       [20513] = 0x0000,     /* R20513 - DACR_RETUNE_C17_0 */
+       [20514] = 0x0000,     /* R20514 - DACR_RETUNE_C18_1 */
+       [20515] = 0x0000,     /* R20515 - DACR_RETUNE_C18_0 */
+       [20516] = 0x0000,     /* R20516 - DACR_RETUNE_C19_1 */
+       [20517] = 0x0000,     /* R20517 - DACR_RETUNE_C19_0 */
+       [20518] = 0x0000,     /* R20518 - DACR_RETUNE_C20_1 */
+       [20519] = 0x0000,     /* R20519 - DACR_RETUNE_C20_0 */
+       [20520] = 0x0000,     /* R20520 - DACR_RETUNE_C21_1 */
+       [20521] = 0x0000,     /* R20521 - DACR_RETUNE_C21_0 */
+       [20522] = 0x0000,     /* R20522 - DACR_RETUNE_C22_1 */
+       [20523] = 0x0000,     /* R20523 - DACR_RETUNE_C22_0 */
+       [20524] = 0x0000,     /* R20524 - DACR_RETUNE_C23_1 */
+       [20525] = 0x0000,     /* R20525 - DACR_RETUNE_C23_0 */
+       [20526] = 0x0000,     /* R20526 - DACR_RETUNE_C24_1 */
+       [20527] = 0x0000,     /* R20527 - DACR_RETUNE_C24_0 */
+       [20528] = 0x0000,     /* R20528 - DACR_RETUNE_C25_1 */
+       [20529] = 0x0000,     /* R20529 - DACR_RETUNE_C25_0 */
+       [20530] = 0x0000,     /* R20530 - DACR_RETUNE_C26_1 */
+       [20531] = 0x0000,     /* R20531 - DACR_RETUNE_C26_0 */
+       [20532] = 0x0000,     /* R20532 - DACR_RETUNE_C27_1 */
+       [20533] = 0x0000,     /* R20533 - DACR_RETUNE_C27_0 */
+       [20534] = 0x0000,     /* R20534 - DACR_RETUNE_C28_1 */
+       [20535] = 0x0000,     /* R20535 - DACR_RETUNE_C28_0 */
+       [20536] = 0x0000,     /* R20536 - DACR_RETUNE_C29_1 */
+       [20537] = 0x0000,     /* R20537 - DACR_RETUNE_C29_0 */
+       [20538] = 0x0000,     /* R20538 - DACR_RETUNE_C30_1 */
+       [20539] = 0x0000,     /* R20539 - DACR_RETUNE_C30_0 */
+       [20540] = 0x0000,     /* R20540 - DACR_RETUNE_C31_1 */
+       [20541] = 0x0000,     /* R20541 - DACR_RETUNE_C31_0 */
+       [20542] = 0x0000,     /* R20542 - DACR_RETUNE_C32_1 */
+       [20543] = 0x0000,     /* R20543 - DACR_RETUNE_C32_0 */
+
+       [20992] = 0x008C,     /* R20992 - VSS_XHD2_1 */
+       [20993] = 0x0200,     /* R20993 - VSS_XHD2_0 */
+       [20994] = 0x0035,     /* R20994 - VSS_XHD3_1 */
+       [20995] = 0x0700,     /* R20995 - VSS_XHD3_0 */
+       [20996] = 0x003A,     /* R20996 - VSS_XHN1_1 */
+       [20997] = 0x4100,     /* R20997 - VSS_XHN1_0 */
+       [20998] = 0x008B,     /* R20998 - VSS_XHN2_1 */
+       [20999] = 0x7D00,     /* R20999 - VSS_XHN2_0 */
+       [21000] = 0x003A,     /* R21000 - VSS_XHN3_1 */
+       [21001] = 0x4100,     /* R21001 - VSS_XHN3_0 */
+       [21002] = 0x008C,     /* R21002 - VSS_XLA_1 */
+       [21003] = 0xFEE8,     /* R21003 - VSS_XLA_0 */
+       [21004] = 0x0078,     /* R21004 - VSS_XLB_1 */
+       [21005] = 0x0000,     /* R21005 - VSS_XLB_0 */
+       [21006] = 0x003F,     /* R21006 - VSS_XLG_1 */
+       [21007] = 0xB260,     /* R21007 - VSS_XLG_0 */
+       [21008] = 0x002D,     /* R21008 - VSS_PG2_1 */
+       [21009] = 0x1818,     /* R21009 - VSS_PG2_0 */
+       [21010] = 0x0020,     /* R21010 - VSS_PG_1 */
+       [21011] = 0x0000,     /* R21011 - VSS_PG_0 */
+       [21012] = 0x00F1,     /* R21012 - VSS_XTD1_1 */
+       [21013] = 0x8340,     /* R21013 - VSS_XTD1_0 */
+       [21014] = 0x00FB,     /* R21014 - VSS_XTD2_1 */
+       [21015] = 0x8300,     /* R21015 - VSS_XTD2_0 */
+       [21016] = 0x00EE,     /* R21016 - VSS_XTD3_1 */
+       [21017] = 0xAEC0,     /* R21017 - VSS_XTD3_0 */
+       [21018] = 0x00FB,     /* R21018 - VSS_XTD4_1 */
+       [21019] = 0xAC40,     /* R21019 - VSS_XTD4_0 */
+       [21020] = 0x00F1,     /* R21020 - VSS_XTD5_1 */
+       [21021] = 0x7F80,     /* R21021 - VSS_XTD5_0 */
+       [21022] = 0x00F4,     /* R21022 - VSS_XTD6_1 */
+       [21023] = 0x3B40,     /* R21023 - VSS_XTD6_0 */
+       [21024] = 0x00F5,     /* R21024 - VSS_XTD7_1 */
+       [21025] = 0xFB00,     /* R21025 - VSS_XTD7_0 */
+       [21026] = 0x00EA,     /* R21026 - VSS_XTD8_1 */
+       [21027] = 0x10C0,     /* R21027 - VSS_XTD8_0 */
+       [21028] = 0x00FC,     /* R21028 - VSS_XTD9_1 */
+       [21029] = 0xC580,     /* R21029 - VSS_XTD9_0 */
+       [21030] = 0x00E2,     /* R21030 - VSS_XTD10_1 */
+       [21031] = 0x75C0,     /* R21031 - VSS_XTD10_0 */
+       [21032] = 0x0004,     /* R21032 - VSS_XTD11_1 */
+       [21033] = 0xB480,     /* R21033 - VSS_XTD11_0 */
+       [21034] = 0x00D4,     /* R21034 - VSS_XTD12_1 */
+       [21035] = 0xF980,     /* R21035 - VSS_XTD12_0 */
+       [21036] = 0x0004,     /* R21036 - VSS_XTD13_1 */
+       [21037] = 0x9140,     /* R21037 - VSS_XTD13_0 */
+       [21038] = 0x00D8,     /* R21038 - VSS_XTD14_1 */
+       [21039] = 0xA480,     /* R21039 - VSS_XTD14_0 */
+       [21040] = 0x0002,     /* R21040 - VSS_XTD15_1 */
+       [21041] = 0x3DC0,     /* R21041 - VSS_XTD15_0 */
+       [21042] = 0x00CF,     /* R21042 - VSS_XTD16_1 */
+       [21043] = 0x7A80,     /* R21043 - VSS_XTD16_0 */
+       [21044] = 0x00DC,     /* R21044 - VSS_XTD17_1 */
+       [21045] = 0x0600,     /* R21045 - VSS_XTD17_0 */
+       [21046] = 0x00F2,     /* R21046 - VSS_XTD18_1 */
+       [21047] = 0xDAC0,     /* R21047 - VSS_XTD18_0 */
+       [21048] = 0x00BA,     /* R21048 - VSS_XTD19_1 */
+       [21049] = 0xF340,     /* R21049 - VSS_XTD19_0 */
+       [21050] = 0x000A,     /* R21050 - VSS_XTD20_1 */
+       [21051] = 0x7940,     /* R21051 - VSS_XTD20_0 */
+       [21052] = 0x001C,     /* R21052 - VSS_XTD21_1 */
+       [21053] = 0x0680,     /* R21053 - VSS_XTD21_0 */
+       [21054] = 0x00FD,     /* R21054 - VSS_XTD22_1 */
+       [21055] = 0x2D00,     /* R21055 - VSS_XTD22_0 */
+       [21056] = 0x001C,     /* R21056 - VSS_XTD23_1 */
+       [21057] = 0xE840,     /* R21057 - VSS_XTD23_0 */
+       [21058] = 0x000D,     /* R21058 - VSS_XTD24_1 */
+       [21059] = 0xDC40,     /* R21059 - VSS_XTD24_0 */
+       [21060] = 0x00FC,     /* R21060 - VSS_XTD25_1 */
+       [21061] = 0x9D00,     /* R21061 - VSS_XTD25_0 */
+       [21062] = 0x0009,     /* R21062 - VSS_XTD26_1 */
+       [21063] = 0x5580,     /* R21063 - VSS_XTD26_0 */
+       [21064] = 0x00FE,     /* R21064 - VSS_XTD27_1 */
+       [21065] = 0x7E80,     /* R21065 - VSS_XTD27_0 */
+       [21066] = 0x000E,     /* R21066 - VSS_XTD28_1 */
+       [21067] = 0xAB40,     /* R21067 - VSS_XTD28_0 */
+       [21068] = 0x00F9,     /* R21068 - VSS_XTD29_1 */
+       [21069] = 0x9880,     /* R21069 - VSS_XTD29_0 */
+       [21070] = 0x0009,     /* R21070 - VSS_XTD30_1 */
+       [21071] = 0x87C0,     /* R21071 - VSS_XTD30_0 */
+       [21072] = 0x00FD,     /* R21072 - VSS_XTD31_1 */
+       [21073] = 0x2C40,     /* R21073 - VSS_XTD31_0 */
+       [21074] = 0x0009,     /* R21074 - VSS_XTD32_1 */
+       [21075] = 0x4800,     /* R21075 - VSS_XTD32_0 */
+       [21076] = 0x0003,     /* R21076 - VSS_XTS1_1 */
+       [21077] = 0x5F40,     /* R21077 - VSS_XTS1_0 */
+       [21078] = 0x0000,     /* R21078 - VSS_XTS2_1 */
+       [21079] = 0x8700,     /* R21079 - VSS_XTS2_0 */
+       [21080] = 0x00FA,     /* R21080 - VSS_XTS3_1 */
+       [21081] = 0xE4C0,     /* R21081 - VSS_XTS3_0 */
+       [21082] = 0x0000,     /* R21082 - VSS_XTS4_1 */
+       [21083] = 0x0B40,     /* R21083 - VSS_XTS4_0 */
+       [21084] = 0x0004,     /* R21084 - VSS_XTS5_1 */
+       [21085] = 0xE180,     /* R21085 - VSS_XTS5_0 */
+       [21086] = 0x0001,     /* R21086 - VSS_XTS6_1 */
+       [21087] = 0x1F40,     /* R21087 - VSS_XTS6_0 */
+       [21088] = 0x00F8,     /* R21088 - VSS_XTS7_1 */
+       [21089] = 0xB000,     /* R21089 - VSS_XTS7_0 */
+       [21090] = 0x00FB,     /* R21090 - VSS_XTS8_1 */
+       [21091] = 0xCBC0,     /* R21091 - VSS_XTS8_0 */
+       [21092] = 0x0004,     /* R21092 - VSS_XTS9_1 */
+       [21093] = 0xF380,     /* R21093 - VSS_XTS9_0 */
+       [21094] = 0x0007,     /* R21094 - VSS_XTS10_1 */
+       [21095] = 0xDF40,     /* R21095 - VSS_XTS10_0 */
+       [21096] = 0x00FF,     /* R21096 - VSS_XTS11_1 */
+       [21097] = 0x0700,     /* R21097 - VSS_XTS11_0 */
+       [21098] = 0x00EF,     /* R21098 - VSS_XTS12_1 */
+       [21099] = 0xD700,     /* R21099 - VSS_XTS12_0 */
+       [21100] = 0x00FB,     /* R21100 - VSS_XTS13_1 */
+       [21101] = 0xAF40,     /* R21101 - VSS_XTS13_0 */
+       [21102] = 0x0010,     /* R21102 - VSS_XTS14_1 */
+       [21103] = 0x8A80,     /* R21103 - VSS_XTS14_0 */
+       [21104] = 0x0011,     /* R21104 - VSS_XTS15_1 */
+       [21105] = 0x07C0,     /* R21105 - VSS_XTS15_0 */
+       [21106] = 0x00E0,     /* R21106 - VSS_XTS16_1 */
+       [21107] = 0x0800,     /* R21107 - VSS_XTS16_0 */
+       [21108] = 0x00D2,     /* R21108 - VSS_XTS17_1 */
+       [21109] = 0x7600,     /* R21109 - VSS_XTS17_0 */
+       [21110] = 0x0020,     /* R21110 - VSS_XTS18_1 */
+       [21111] = 0xCF40,     /* R21111 - VSS_XTS18_0 */
+       [21112] = 0x0030,     /* R21112 - VSS_XTS19_1 */
+       [21113] = 0x2340,     /* R21113 - VSS_XTS19_0 */
+       [21114] = 0x00FD,     /* R21114 - VSS_XTS20_1 */
+       [21115] = 0x69C0,     /* R21115 - VSS_XTS20_0 */
+       [21116] = 0x0028,     /* R21116 - VSS_XTS21_1 */
+       [21117] = 0x3500,     /* R21117 - VSS_XTS21_0 */
+       [21118] = 0x0006,     /* R21118 - VSS_XTS22_1 */
+       [21119] = 0x3300,     /* R21119 - VSS_XTS22_0 */
+       [21120] = 0x00D9,     /* R21120 - VSS_XTS23_1 */
+       [21121] = 0xF6C0,     /* R21121 - VSS_XTS23_0 */
+       [21122] = 0x00F3,     /* R21122 - VSS_XTS24_1 */
+       [21123] = 0x3340,     /* R21123 - VSS_XTS24_0 */
+       [21124] = 0x000F,     /* R21124 - VSS_XTS25_1 */
+       [21125] = 0x4200,     /* R21125 - VSS_XTS25_0 */
+       [21126] = 0x0004,     /* R21126 - VSS_XTS26_1 */
+       [21127] = 0x0C80,     /* R21127 - VSS_XTS26_0 */
+       [21128] = 0x00FB,     /* R21128 - VSS_XTS27_1 */
+       [21129] = 0x3F80,     /* R21129 - VSS_XTS27_0 */
+       [21130] = 0x00F7,     /* R21130 - VSS_XTS28_1 */
+       [21131] = 0x57C0,     /* R21131 - VSS_XTS28_0 */
+       [21132] = 0x0003,     /* R21132 - VSS_XTS29_1 */
+       [21133] = 0x5400,     /* R21133 - VSS_XTS29_0 */
+       [21134] = 0x0000,     /* R21134 - VSS_XTS30_1 */
+       [21135] = 0xC6C0,     /* R21135 - VSS_XTS30_0 */
+       [21136] = 0x0003,     /* R21136 - VSS_XTS31_1 */
+       [21137] = 0x12C0,     /* R21137 - VSS_XTS31_0 */
+       [21138] = 0x00FD,     /* R21138 - VSS_XTS32_1 */
+       [21139] = 0x8580,     /* R21139 - VSS_XTS32_0 */
+};
+
+static const struct wm8962_reg_access {
+       u16 read;
+       u16 write;
+       u16 vol;
+} wm8962_reg_access[WM8962_MAX_REGISTER + 1] = {
+       [0] = { 0x00FF, 0x01FF, 0x0000 }, /* R0     - Left Input volume */
+       [1] = { 0xFEFF, 0x01FF, 0xFFFF }, /* R1     - Right Input volume */
+       [2] = { 0x00FF, 0x01FF, 0x0000 }, /* R2     - HPOUTL volume */
+       [3] = { 0x00FF, 0x01FF, 0x0000 }, /* R3     - HPOUTR volume */
+       [4] = { 0x07FE, 0x07FE, 0xFFFF }, /* R4     - Clocking1 */
+       [5] = { 0x007F, 0x007F, 0x0000 }, /* R5     - ADC & DAC Control 1 */
+       [6] = { 0x37ED, 0x37ED, 0x0000 }, /* R6     - ADC & DAC Control 2 */
+       [7] = { 0x1FFF, 0x1FFF, 0x0000 }, /* R7     - Audio Interface 0 */
+       [8] = { 0x0FEF, 0x0FEF, 0xFFFF }, /* R8     - Clocking2 */
+       [9] = { 0x0B9F, 0x039F, 0x0000 }, /* R9     - Audio Interface 1 */
+       [10] = { 0x00FF, 0x01FF, 0x0000 }, /* R10    - Left DAC volume */
+       [11] = { 0x00FF, 0x01FF, 0x0000 }, /* R11    - Right DAC volume */
+       [14] = { 0x07FF, 0x07FF, 0x0000 }, /* R14    - Audio Interface 2 */
+       [15] = { 0xFFFF, 0xFFFF, 0xFFFF }, /* R15    - Software Reset */
+       [17] = { 0x07FF, 0x07FF, 0x0000 }, /* R17    - ALC1 */
+       [18] = { 0xF8FF, 0x00FF, 0xFFFF }, /* R18    - ALC2 */
+       [19] = { 0x1DFF, 0x1DFF, 0x0000 }, /* R19    - ALC3 */
+       [20] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20    - Noise Gate */
+       [21] = { 0x00FF, 0x01FF, 0x0000 }, /* R21    - Left ADC volume */
+       [22] = { 0x00FF, 0x01FF, 0x0000 }, /* R22    - Right ADC volume */
+       [23] = { 0x0161, 0x0161, 0x0000 }, /* R23    - Additional control(1) */
+       [24] = { 0x0008, 0x0008, 0x0000 }, /* R24    - Additional control(2) */
+       [25] = { 0x07FE, 0x07FE, 0x0000 }, /* R25    - Pwr Mgmt (1) */
+       [26] = { 0x01FB, 0x01FB, 0x0000 }, /* R26    - Pwr Mgmt (2) */
+       [27] = { 0x0017, 0x0017, 0x0000 }, /* R27    - Additional Control (3) */
+       [28] = { 0x001C, 0x001C, 0x0000 }, /* R28    - Anti-pop */
+
+       [30] = { 0xFFFE, 0xFFFE, 0x0000 }, /* R30    - Clocking 3 */
+       [31] = { 0x000F, 0x000F, 0x0000 }, /* R31    - Input mixer control (1) */
+       [32] = { 0x01FF, 0x01FF, 0x0000 }, /* R32    - Left input mixer volume */
+       [33] = { 0x01FF, 0x01FF, 0x0000 }, /* R33    - Right input mixer volume */
+       [34] = { 0x003F, 0x003F, 0x0000 }, /* R34    - Input mixer control (2) */
+       [35] = { 0x003F, 0x003F, 0x0000 }, /* R35    - Input bias control */
+       [37] = { 0x001F, 0x001F, 0x0000 }, /* R37    - Left input PGA control */
+       [38] = { 0x001F, 0x001F, 0x0000 }, /* R38    - Right input PGA control */
+       [40] = { 0x00FF, 0x01FF, 0x0000 }, /* R40    - SPKOUTL volume */
+       [41] = { 0x00FF, 0x01FF, 0x0000 }, /* R41    - SPKOUTR volume */
+
+       [47] = { 0x000F, 0x0000, 0x0000 }, /* R47    - Thermal Shutdown Status */
+       [48] = { 0x7EC7, 0x7E07, 0xFFFF }, /* R48    - Additional Control (4) */
+       [49] = { 0x00D3, 0x00D7, 0xFFFF }, /* R49    - Class D Control 1 */
+       [51] = { 0x0047, 0x0047, 0x0000 }, /* R51    - Class D Control 2 */
+       [56] = { 0x001E, 0x001E, 0x0000 }, /* R56    - Clocking 4 */
+       [57] = { 0x02FC, 0x02FC, 0x0000 }, /* R57    - DAC DSP Mixing (1) */
+       [58] = { 0x00FC, 0x00FC, 0x0000 }, /* R58    - DAC DSP Mixing (2) */
+       [60] = { 0x00CC, 0x00CC, 0x0000 }, /* R60    - DC Servo 0 */
+       [61] = { 0x00DD, 0x00DD, 0x0000 }, /* R61    - DC Servo 1 */
+       [64] = { 0x3F80, 0x3F80, 0x0000 }, /* R64    - DC Servo 4 */
+       [66] = { 0x0780, 0x0000, 0xFFFF }, /* R66    - DC Servo 6 */
+       [68] = { 0x0007, 0x0007, 0x0000 }, /* R68    - Analogue PGA Bias */
+       [69] = { 0x00FF, 0x00FF, 0x0000 }, /* R69    - Analogue HP 0 */
+       [71] = { 0x01FF, 0x01FF, 0x0000 }, /* R71    - Analogue HP 2 */
+       [72] = { 0x0001, 0x0001, 0x0000 }, /* R72    - Charge Pump 1 */
+       [82] = { 0x0001, 0x0001, 0x0000 }, /* R82    - Charge Pump B */
+       [87] = { 0x00A0, 0x00A0, 0x0000 }, /* R87    - Write Sequencer Control 1 */
+       [90] = { 0x007F, 0x01FF, 0x0000 }, /* R90    - Write Sequencer Control 2 */
+       [93] = { 0x03F9, 0x0000, 0x0000 }, /* R93    - Write Sequencer Control 3 */
+       [94] = { 0x0070, 0x0070, 0x0000 }, /* R94    - Control Interface */
+       [99] = { 0x000F, 0x000F, 0x0000 }, /* R99    - Mixer Enables */
+       [100] = { 0x00BF, 0x00BF, 0x0000 }, /* R100   - Headphone Mixer (1) */
+       [101] = { 0x00BF, 0x00BF, 0x0000 }, /* R101   - Headphone Mixer (2) */
+       [102] = { 0x01FF, 0x01FF, 0x0000 }, /* R102   - Headphone Mixer (3) */
+       [103] = { 0x01FF, 0x01FF, 0x0000 }, /* R103   - Headphone Mixer (4) */
+       [105] = { 0x00BF, 0x00BF, 0x0000 }, /* R105   - Speaker Mixer (1) */
+       [106] = { 0x00BF, 0x00BF, 0x0000 }, /* R106   - Speaker Mixer (2) */
+       [107] = { 0x01FF, 0x01FF, 0x0000 }, /* R107   - Speaker Mixer (3) */
+       [108] = { 0x01FF, 0x01FF, 0x0000 }, /* R108   - Speaker Mixer (4) */
+       [109] = { 0x00F0, 0x00F0, 0x0000 }, /* R109   - Speaker Mixer (5) */
+       [110] = { 0x00F7, 0x00F7, 0x0000 }, /* R110   - Beep Generator (1) */
+       [115] = { 0x001F, 0x001F, 0x0000 }, /* R115   - Oscillator Trim (3) */
+       [116] = { 0x001F, 0x001F, 0x0000 }, /* R116   - Oscillator Trim (4) */
+       [119] = { 0x00FF, 0x00FF, 0x0000 }, /* R119   - Oscillator Trim (7) */
+       [124] = { 0x0079, 0x0079, 0x0000 }, /* R124   - Analogue Clocking1 */
+       [125] = { 0x00DF, 0x00DF, 0x0000 }, /* R125   - Analogue Clocking2 */
+       [126] = { 0x000D, 0x000D, 0x0000 }, /* R126   - Analogue Clocking3 */
+       [127] = { 0x0000, 0xFFFF, 0x0000 }, /* R127   - PLL Software Reset */
+       [129] = { 0x00B0, 0x00B0, 0x0000 }, /* R129   - PLL2 */
+       [131] = { 0x0003, 0x0003, 0x0000 }, /* R131   - PLL 4 */
+       [136] = { 0x005F, 0x005F, 0x0000 }, /* R136   - PLL 9 */
+       [137] = { 0x00FF, 0x00FF, 0x0000 }, /* R137   - PLL 10 */
+       [138] = { 0x00FF, 0x00FF, 0x0000 }, /* R138   - PLL 11 */
+       [139] = { 0x00FF, 0x00FF, 0x0000 }, /* R139   - PLL 12 */
+       [140] = { 0x005F, 0x005F, 0x0000 }, /* R140   - PLL 13 */
+       [141] = { 0x00FF, 0x00FF, 0x0000 }, /* R141   - PLL 14 */
+       [142] = { 0x00FF, 0x00FF, 0x0000 }, /* R142   - PLL 15 */
+       [143] = { 0x00FF, 0x00FF, 0x0000 }, /* R143   - PLL 16 */
+       [155] = { 0x0067, 0x0067, 0x0000 }, /* R155   - FLL Control (1) */
+       [156] = { 0x01FB, 0x01FB, 0x0000 }, /* R156   - FLL Control (2) */
+       [157] = { 0x0007, 0x0007, 0x0000 }, /* R157   - FLL Control (3) */
+       [159] = { 0x007F, 0x007F, 0x0000 }, /* R159   - FLL Control (5) */
+       [160] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R160   - FLL Control (6) */
+       [161] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R161   - FLL Control (7) */
+       [162] = { 0x03FF, 0x03FF, 0x0000 }, /* R162   - FLL Control (8) */
+       [252] = { 0x0005, 0x0005, 0x0000 }, /* R252   - General test 1 */
+       [256] = { 0x000F, 0x000F, 0x0000 }, /* R256   - DF1 */
+       [257] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R257   - DF2 */
+       [258] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R258   - DF3 */
+       [259] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R259   - DF4 */
+       [260] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R260   - DF5 */
+       [261] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R261   - DF6 */
+       [262] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R262   - DF7 */
+       [264] = { 0x0003, 0x0003, 0x0000 }, /* R264   - LHPF1 */
+       [265] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R265   - LHPF2 */
+       [268] = { 0x0077, 0x0077, 0x0000 }, /* R268   - THREED1 */
+       [269] = { 0xFFFC, 0xFFFC, 0x0000 }, /* R269   - THREED2 */
+       [270] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R270   - THREED3 */
+       [271] = { 0xFFFC, 0xFFFC, 0x0000 }, /* R271   - THREED4 */
+       [276] = { 0x7FFF, 0x7FFF, 0x0000 }, /* R276   - DRC 1 */
+       [277] = { 0x1FFF, 0x1FFF, 0x0000 }, /* R277   - DRC 2 */
+       [278] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R278   - DRC 3 */
+       [279] = { 0x07FF, 0x07FF, 0x0000 }, /* R279   - DRC 4 */
+       [280] = { 0x03FF, 0x03FF, 0x0000 }, /* R280   - DRC 5 */
+       [285] = { 0x0003, 0x0003, 0x0000 }, /* R285   - Tloopback */
+       [335] = { 0x0007, 0x0007, 0x0000 }, /* R335   - EQ1 */
+       [336] = { 0xFFFE, 0xFFFE, 0x0000 }, /* R336   - EQ2 */
+       [337] = { 0xFFC0, 0xFFC0, 0x0000 }, /* R337   - EQ3 */
+       [338] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R338   - EQ4 */
+       [339] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R339   - EQ5 */
+       [340] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R340   - EQ6 */
+       [341] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R341   - EQ7 */
+       [342] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R342   - EQ8 */
+       [343] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R343   - EQ9 */
+       [344] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R344   - EQ10 */
+       [345] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R345   - EQ11 */
+       [346] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R346   - EQ12 */
+       [347] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R347   - EQ13 */
+       [348] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R348   - EQ14 */
+       [349] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R349   - EQ15 */
+       [350] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R350   - EQ16 */
+       [351] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R351   - EQ17 */
+       [352] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R352   - EQ18 */
+       [353] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R353   - EQ19 */
+       [354] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R354   - EQ20 */
+       [355] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R355   - EQ21 */
+       [356] = { 0xFFFE, 0xFFFE, 0x0000 }, /* R356   - EQ22 */
+       [357] = { 0xFFC0, 0xFFC0, 0x0000 }, /* R357   - EQ23 */
+       [358] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R358   - EQ24 */
+       [359] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R359   - EQ25 */
+       [360] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R360   - EQ26 */
+       [361] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R361   - EQ27 */
+       [362] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R362   - EQ28 */
+       [363] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R363   - EQ29 */
+       [364] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R364   - EQ30 */
+       [365] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R365   - EQ31 */
+       [366] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R366   - EQ32 */
+       [367] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R367   - EQ33 */
+       [368] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R368   - EQ34 */
+       [369] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R369   - EQ35 */
+       [370] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R370   - EQ36 */
+       [371] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R371   - EQ37 */
+       [372] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R372   - EQ38 */
+       [373] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R373   - EQ39 */
+       [374] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R374   - EQ40 */
+       [375] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R375   - EQ41 */
+       [513] = { 0x045F, 0x045F, 0x0000 }, /* R513   - GPIO 2 */
+       [514] = { 0x045F, 0x045F, 0x0000 }, /* R514   - GPIO 3 */
+       [516] = { 0xE75F, 0xE75F, 0x0000 }, /* R516   - GPIO 5 */
+       [517] = { 0xE75F, 0xE75F, 0x0000 }, /* R517   - GPIO 6 */
+       [560] = { 0x0030, 0x0030, 0xFFFF }, /* R560   - Interrupt Status 1 */
+       [561] = { 0xFFED, 0xFFED, 0xFFFF }, /* R561   - Interrupt Status 2 */
+       [568] = { 0x0030, 0x0030, 0x0000 }, /* R568   - Interrupt Status 1 Mask */
+       [569] = { 0xFFED, 0xFFED, 0x0000 }, /* R569   - Interrupt Status 2 Mask */
+       [576] = { 0x0001, 0x0001, 0x0000 }, /* R576   - Interrupt Control */
+       [584] = { 0x002D, 0x002D, 0x0000 }, /* R584   - IRQ Debounce */
+       [586] = { 0xC000, 0xC000, 0x0000 }, /* R586   -  MICINT Source Pol */
+       [768] = { 0x0001, 0x0001, 0x0000 }, /* R768   - DSP2 Power Management */
+       [1037] = { 0x0000, 0x003F, 0x0000 }, /* R1037  - DSP2_ExecControl */
+       [4096] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4096  - Write Sequencer 0 */
+       [4097] = { 0x00FF, 0x00FF, 0x0000 }, /* R4097  - Write Sequencer 1 */
+       [4098] = { 0x070F, 0x070F, 0x0000 }, /* R4098  - Write Sequencer 2 */
+       [4099] = { 0x010F, 0x010F, 0x0000 }, /* R4099  - Write Sequencer 3 */
+       [4100] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4100  - Write Sequencer 4 */
+       [4101] = { 0x00FF, 0x00FF, 0x0000 }, /* R4101  - Write Sequencer 5 */
+       [4102] = { 0x070F, 0x070F, 0x0000 }, /* R4102  - Write Sequencer 6 */
+       [4103] = { 0x010F, 0x010F, 0x0000 }, /* R4103  - Write Sequencer 7 */
+       [4104] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4104  - Write Sequencer 8 */
+       [4105] = { 0x00FF, 0x00FF, 0x0000 }, /* R4105  - Write Sequencer 9 */
+       [4106] = { 0x070F, 0x070F, 0x0000 }, /* R4106  - Write Sequencer 10 */
+       [4107] = { 0x010F, 0x010F, 0x0000 }, /* R4107  - Write Sequencer 11 */
+       [4108] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4108  - Write Sequencer 12 */
+       [4109] = { 0x00FF, 0x00FF, 0x0000 }, /* R4109  - Write Sequencer 13 */
+       [4110] = { 0x070F, 0x070F, 0x0000 }, /* R4110  - Write Sequencer 14 */
+       [4111] = { 0x010F, 0x010F, 0x0000 }, /* R4111  - Write Sequencer 15 */
+       [4112] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4112  - Write Sequencer 16 */
+       [4113] = { 0x00FF, 0x00FF, 0x0000 }, /* R4113  - Write Sequencer 17 */
+       [4114] = { 0x070F, 0x070F, 0x0000 }, /* R4114  - Write Sequencer 18 */
+       [4115] = { 0x010F, 0x010F, 0x0000 }, /* R4115  - Write Sequencer 19 */
+       [4116] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4116  - Write Sequencer 20 */
+       [4117] = { 0x00FF, 0x00FF, 0x0000 }, /* R4117  - Write Sequencer 21 */
+       [4118] = { 0x070F, 0x070F, 0x0000 }, /* R4118  - Write Sequencer 22 */
+       [4119] = { 0x010F, 0x010F, 0x0000 }, /* R4119  - Write Sequencer 23 */
+       [4120] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4120  - Write Sequencer 24 */
+       [4121] = { 0x00FF, 0x00FF, 0x0000 }, /* R4121  - Write Sequencer 25 */
+       [4122] = { 0x070F, 0x070F, 0x0000 }, /* R4122  - Write Sequencer 26 */
+       [4123] = { 0x010F, 0x010F, 0x0000 }, /* R4123  - Write Sequencer 27 */
+       [4124] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4124  - Write Sequencer 28 */
+       [4125] = { 0x00FF, 0x00FF, 0x0000 }, /* R4125  - Write Sequencer 29 */
+       [4126] = { 0x070F, 0x070F, 0x0000 }, /* R4126  - Write Sequencer 30 */
+       [4127] = { 0x010F, 0x010F, 0x0000 }, /* R4127  - Write Sequencer 31 */
+       [4128] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4128  - Write Sequencer 32 */
+       [4129] = { 0x00FF, 0x00FF, 0x0000 }, /* R4129  - Write Sequencer 33 */
+       [4130] = { 0x070F, 0x070F, 0x0000 }, /* R4130  - Write Sequencer 34 */
+       [4131] = { 0x010F, 0x010F, 0x0000 }, /* R4131  - Write Sequencer 35 */
+       [4132] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4132  - Write Sequencer 36 */
+       [4133] = { 0x00FF, 0x00FF, 0x0000 }, /* R4133  - Write Sequencer 37 */
+       [4134] = { 0x070F, 0x070F, 0x0000 }, /* R4134  - Write Sequencer 38 */
+       [4135] = { 0x010F, 0x010F, 0x0000 }, /* R4135  - Write Sequencer 39 */
+       [4136] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4136  - Write Sequencer 40 */
+       [4137] = { 0x00FF, 0x00FF, 0x0000 }, /* R4137  - Write Sequencer 41 */
+       [4138] = { 0x070F, 0x070F, 0x0000 }, /* R4138  - Write Sequencer 42 */
+       [4139] = { 0x010F, 0x010F, 0x0000 }, /* R4139  - Write Sequencer 43 */
+       [4140] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4140  - Write Sequencer 44 */
+       [4141] = { 0x00FF, 0x00FF, 0x0000 }, /* R4141  - Write Sequencer 45 */
+       [4142] = { 0x070F, 0x070F, 0x0000 }, /* R4142  - Write Sequencer 46 */
+       [4143] = { 0x010F, 0x010F, 0x0000 }, /* R4143  - Write Sequencer 47 */
+       [4144] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4144  - Write Sequencer 48 */
+       [4145] = { 0x00FF, 0x00FF, 0x0000 }, /* R4145  - Write Sequencer 49 */
+       [4146] = { 0x070F, 0x070F, 0x0000 }, /* R4146  - Write Sequencer 50 */
+       [4147] = { 0x010F, 0x010F, 0x0000 }, /* R4147  - Write Sequencer 51 */
+       [4148] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4148  - Write Sequencer 52 */
+       [4149] = { 0x00FF, 0x00FF, 0x0000 }, /* R4149  - Write Sequencer 53 */
+       [4150] = { 0x070F, 0x070F, 0x0000 }, /* R4150  - Write Sequencer 54 */
+       [4151] = { 0x010F, 0x010F, 0x0000 }, /* R4151  - Write Sequencer 55 */
+       [4152] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4152  - Write Sequencer 56 */
+       [4153] = { 0x00FF, 0x00FF, 0x0000 }, /* R4153  - Write Sequencer 57 */
+       [4154] = { 0x070F, 0x070F, 0x0000 }, /* R4154  - Write Sequencer 58 */
+       [4155] = { 0x010F, 0x010F, 0x0000 }, /* R4155  - Write Sequencer 59 */
+       [4156] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4156  - Write Sequencer 60 */
+       [4157] = { 0x00FF, 0x00FF, 0x0000 }, /* R4157  - Write Sequencer 61 */
+       [4158] = { 0x070F, 0x070F, 0x0000 }, /* R4158  - Write Sequencer 62 */
+       [4159] = { 0x010F, 0x010F, 0x0000 }, /* R4159  - Write Sequencer 63 */
+       [4160] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4160  - Write Sequencer 64 */
+       [4161] = { 0x00FF, 0x00FF, 0x0000 }, /* R4161  - Write Sequencer 65 */
+       [4162] = { 0x070F, 0x070F, 0x0000 }, /* R4162  - Write Sequencer 66 */
+       [4163] = { 0x010F, 0x010F, 0x0000 }, /* R4163  - Write Sequencer 67 */
+       [4164] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4164  - Write Sequencer 68 */
+       [4165] = { 0x00FF, 0x00FF, 0x0000 }, /* R4165  - Write Sequencer 69 */
+       [4166] = { 0x070F, 0x070F, 0x0000 }, /* R4166  - Write Sequencer 70 */
+       [4167] = { 0x010F, 0x010F, 0x0000 }, /* R4167  - Write Sequencer 71 */
+       [4168] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4168  - Write Sequencer 72 */
+       [4169] = { 0x00FF, 0x00FF, 0x0000 }, /* R4169  - Write Sequencer 73 */
+       [4170] = { 0x070F, 0x070F, 0x0000 }, /* R4170  - Write Sequencer 74 */
+       [4171] = { 0x010F, 0x010F, 0x0000 }, /* R4171  - Write Sequencer 75 */
+       [4172] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4172  - Write Sequencer 76 */
+       [4173] = { 0x00FF, 0x00FF, 0x0000 }, /* R4173  - Write Sequencer 77 */
+       [4174] = { 0x070F, 0x070F, 0x0000 }, /* R4174  - Write Sequencer 78 */
+       [4175] = { 0x010F, 0x010F, 0x0000 }, /* R4175  - Write Sequencer 79 */
+       [4176] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4176  - Write Sequencer 80 */
+       [4177] = { 0x00FF, 0x00FF, 0x0000 }, /* R4177  - Write Sequencer 81 */
+       [4178] = { 0x070F, 0x070F, 0x0000 }, /* R4178  - Write Sequencer 82 */
+       [4179] = { 0x010F, 0x010F, 0x0000 }, /* R4179  - Write Sequencer 83 */
+       [4180] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4180  - Write Sequencer 84 */
+       [4181] = { 0x00FF, 0x00FF, 0x0000 }, /* R4181  - Write Sequencer 85 */
+       [4182] = { 0x070F, 0x070F, 0x0000 }, /* R4182  - Write Sequencer 86 */
+       [4183] = { 0x010F, 0x010F, 0x0000 }, /* R4183  - Write Sequencer 87 */
+       [4184] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4184  - Write Sequencer 88 */
+       [4185] = { 0x00FF, 0x00FF, 0x0000 }, /* R4185  - Write Sequencer 89 */
+       [4186] = { 0x070F, 0x070F, 0x0000 }, /* R4186  - Write Sequencer 90 */
+       [4187] = { 0x010F, 0x010F, 0x0000 }, /* R4187  - Write Sequencer 91 */
+       [4188] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4188  - Write Sequencer 92 */
+       [4189] = { 0x00FF, 0x00FF, 0x0000 }, /* R4189  - Write Sequencer 93 */
+       [4190] = { 0x070F, 0x070F, 0x0000 }, /* R4190  - Write Sequencer 94 */
+       [4191] = { 0x010F, 0x010F, 0x0000 }, /* R4191  - Write Sequencer 95 */
+       [4192] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4192  - Write Sequencer 96 */
+       [4193] = { 0x00FF, 0x00FF, 0x0000 }, /* R4193  - Write Sequencer 97 */
+       [4194] = { 0x070F, 0x070F, 0x0000 }, /* R4194  - Write Sequencer 98 */
+       [4195] = { 0x010F, 0x010F, 0x0000 }, /* R4195  - Write Sequencer 99 */
+       [4196] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4196  - Write Sequencer 100 */
+       [4197] = { 0x00FF, 0x00FF, 0x0000 }, /* R4197  - Write Sequencer 101 */
+       [4198] = { 0x070F, 0x070F, 0x0000 }, /* R4198  - Write Sequencer 102 */
+       [4199] = { 0x010F, 0x010F, 0x0000 }, /* R4199  - Write Sequencer 103 */
+       [4200] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4200  - Write Sequencer 104 */
+       [4201] = { 0x00FF, 0x00FF, 0x0000 }, /* R4201  - Write Sequencer 105 */
+       [4202] = { 0x070F, 0x070F, 0x0000 }, /* R4202  - Write Sequencer 106 */
+       [4203] = { 0x010F, 0x010F, 0x0000 }, /* R4203  - Write Sequencer 107 */
+       [4204] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4204  - Write Sequencer 108 */
+       [4205] = { 0x00FF, 0x00FF, 0x0000 }, /* R4205  - Write Sequencer 109 */
+       [4206] = { 0x070F, 0x070F, 0x0000 }, /* R4206  - Write Sequencer 110 */
+       [4207] = { 0x010F, 0x010F, 0x0000 }, /* R4207  - Write Sequencer 111 */
+       [4208] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4208  - Write Sequencer 112 */
+       [4209] = { 0x00FF, 0x00FF, 0x0000 }, /* R4209  - Write Sequencer 113 */
+       [4210] = { 0x070F, 0x070F, 0x0000 }, /* R4210  - Write Sequencer 114 */
+       [4211] = { 0x010F, 0x010F, 0x0000 }, /* R4211  - Write Sequencer 115 */
+       [4212] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4212  - Write Sequencer 116 */
+       [4213] = { 0x00FF, 0x00FF, 0x0000 }, /* R4213  - Write Sequencer 117 */
+       [4214] = { 0x070F, 0x070F, 0x0000 }, /* R4214  - Write Sequencer 118 */
+       [4215] = { 0x010F, 0x010F, 0x0000 }, /* R4215  - Write Sequencer 119 */
+       [4216] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4216  - Write Sequencer 120 */
+       [4217] = { 0x00FF, 0x00FF, 0x0000 }, /* R4217  - Write Sequencer 121 */
+       [4218] = { 0x070F, 0x070F, 0x0000 }, /* R4218  - Write Sequencer 122 */
+       [4219] = { 0x010F, 0x010F, 0x0000 }, /* R4219  - Write Sequencer 123 */
+       [4220] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4220  - Write Sequencer 124 */
+       [4221] = { 0x00FF, 0x00FF, 0x0000 }, /* R4221  - Write Sequencer 125 */
+       [4222] = { 0x070F, 0x070F, 0x0000 }, /* R4222  - Write Sequencer 126 */
+       [4223] = { 0x010F, 0x010F, 0x0000 }, /* R4223  - Write Sequencer 127 */
+       [4224] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4224  - Write Sequencer 128 */
+       [4225] = { 0x00FF, 0x00FF, 0x0000 }, /* R4225  - Write Sequencer 129 */
+       [4226] = { 0x070F, 0x070F, 0x0000 }, /* R4226  - Write Sequencer 130 */
+       [4227] = { 0x010F, 0x010F, 0x0000 }, /* R4227  - Write Sequencer 131 */
+       [4228] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4228  - Write Sequencer 132 */
+       [4229] = { 0x00FF, 0x00FF, 0x0000 }, /* R4229  - Write Sequencer 133 */
+       [4230] = { 0x070F, 0x070F, 0x0000 }, /* R4230  - Write Sequencer 134 */
+       [4231] = { 0x010F, 0x010F, 0x0000 }, /* R4231  - Write Sequencer 135 */
+       [4232] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4232  - Write Sequencer 136 */
+       [4233] = { 0x00FF, 0x00FF, 0x0000 }, /* R4233  - Write Sequencer 137 */
+       [4234] = { 0x070F, 0x070F, 0x0000 }, /* R4234  - Write Sequencer 138 */
+       [4235] = { 0x010F, 0x010F, 0x0000 }, /* R4235  - Write Sequencer 139 */
+       [4236] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4236  - Write Sequencer 140 */
+       [4237] = { 0x00FF, 0x00FF, 0x0000 }, /* R4237  - Write Sequencer 141 */
+       [4238] = { 0x070F, 0x070F, 0x0000 }, /* R4238  - Write Sequencer 142 */
+       [4239] = { 0x010F, 0x010F, 0x0000 }, /* R4239  - Write Sequencer 143 */
+       [4240] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4240  - Write Sequencer 144 */
+       [4241] = { 0x00FF, 0x00FF, 0x0000 }, /* R4241  - Write Sequencer 145 */
+       [4242] = { 0x070F, 0x070F, 0x0000 }, /* R4242  - Write Sequencer 146 */
+       [4243] = { 0x010F, 0x010F, 0x0000 }, /* R4243  - Write Sequencer 147 */
+       [4244] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4244  - Write Sequencer 148 */
+       [4245] = { 0x00FF, 0x00FF, 0x0000 }, /* R4245  - Write Sequencer 149 */
+       [4246] = { 0x070F, 0x070F, 0x0000 }, /* R4246  - Write Sequencer 150 */
+       [4247] = { 0x010F, 0x010F, 0x0000 }, /* R4247  - Write Sequencer 151 */
+       [4248] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4248  - Write Sequencer 152 */
+       [4249] = { 0x00FF, 0x00FF, 0x0000 }, /* R4249  - Write Sequencer 153 */
+       [4250] = { 0x070F, 0x070F, 0x0000 }, /* R4250  - Write Sequencer 154 */
+       [4251] = { 0x010F, 0x010F, 0x0000 }, /* R4251  - Write Sequencer 155 */
+       [4252] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4252  - Write Sequencer 156 */
+       [4253] = { 0x00FF, 0x00FF, 0x0000 }, /* R4253  - Write Sequencer 157 */
+       [4254] = { 0x070F, 0x070F, 0x0000 }, /* R4254  - Write Sequencer 158 */
+       [4255] = { 0x010F, 0x010F, 0x0000 }, /* R4255  - Write Sequencer 159 */
+       [4256] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4256  - Write Sequencer 160 */
+       [4257] = { 0x00FF, 0x00FF, 0x0000 }, /* R4257  - Write Sequencer 161 */
+       [4258] = { 0x070F, 0x070F, 0x0000 }, /* R4258  - Write Sequencer 162 */
+       [4259] = { 0x010F, 0x010F, 0x0000 }, /* R4259  - Write Sequencer 163 */
+       [4260] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4260  - Write Sequencer 164 */
+       [4261] = { 0x00FF, 0x00FF, 0x0000 }, /* R4261  - Write Sequencer 165 */
+       [4262] = { 0x070F, 0x070F, 0x0000 }, /* R4262  - Write Sequencer 166 */
+       [4263] = { 0x010F, 0x010F, 0x0000 }, /* R4263  - Write Sequencer 167 */
+       [4264] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4264  - Write Sequencer 168 */
+       [4265] = { 0x00FF, 0x00FF, 0x0000 }, /* R4265  - Write Sequencer 169 */
+       [4266] = { 0x070F, 0x070F, 0x0000 }, /* R4266  - Write Sequencer 170 */
+       [4267] = { 0x010F, 0x010F, 0x0000 }, /* R4267  - Write Sequencer 171 */
+       [4268] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4268  - Write Sequencer 172 */
+       [4269] = { 0x00FF, 0x00FF, 0x0000 }, /* R4269  - Write Sequencer 173 */
+       [4270] = { 0x070F, 0x070F, 0x0000 }, /* R4270  - Write Sequencer 174 */
+       [4271] = { 0x010F, 0x010F, 0x0000 }, /* R4271  - Write Sequencer 175 */
+       [4272] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4272  - Write Sequencer 176 */
+       [4273] = { 0x00FF, 0x00FF, 0x0000 }, /* R4273  - Write Sequencer 177 */
+       [4274] = { 0x070F, 0x070F, 0x0000 }, /* R4274  - Write Sequencer 178 */
+       [4275] = { 0x010F, 0x010F, 0x0000 }, /* R4275  - Write Sequencer 179 */
+       [4276] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4276  - Write Sequencer 180 */
+       [4277] = { 0x00FF, 0x00FF, 0x0000 }, /* R4277  - Write Sequencer 181 */
+       [4278] = { 0x070F, 0x070F, 0x0000 }, /* R4278  - Write Sequencer 182 */
+       [4279] = { 0x010F, 0x010F, 0x0000 }, /* R4279  - Write Sequencer 183 */
+       [4280] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4280  - Write Sequencer 184 */
+       [4281] = { 0x00FF, 0x00FF, 0x0000 }, /* R4281  - Write Sequencer 185 */
+       [4282] = { 0x070F, 0x070F, 0x0000 }, /* R4282  - Write Sequencer 186 */
+       [4283] = { 0x010F, 0x010F, 0x0000 }, /* R4283  - Write Sequencer 187 */
+       [4284] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4284  - Write Sequencer 188 */
+       [4285] = { 0x00FF, 0x00FF, 0x0000 }, /* R4285  - Write Sequencer 189 */
+       [4286] = { 0x070F, 0x070F, 0x0000 }, /* R4286  - Write Sequencer 190 */
+       [4287] = { 0x010F, 0x010F, 0x0000 }, /* R4287  - Write Sequencer 191 */
+       [4288] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4288  - Write Sequencer 192 */
+       [4289] = { 0x00FF, 0x00FF, 0x0000 }, /* R4289  - Write Sequencer 193 */
+       [4290] = { 0x070F, 0x070F, 0x0000 }, /* R4290  - Write Sequencer 194 */
+       [4291] = { 0x010F, 0x010F, 0x0000 }, /* R4291  - Write Sequencer 195 */
+       [4292] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4292  - Write Sequencer 196 */
+       [4293] = { 0x00FF, 0x00FF, 0x0000 }, /* R4293  - Write Sequencer 197 */
+       [4294] = { 0x070F, 0x070F, 0x0000 }, /* R4294  - Write Sequencer 198 */
+       [4295] = { 0x010F, 0x010F, 0x0000 }, /* R4295  - Write Sequencer 199 */
+       [4296] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4296  - Write Sequencer 200 */
+       [4297] = { 0x00FF, 0x00FF, 0x0000 }, /* R4297  - Write Sequencer 201 */
+       [4298] = { 0x070F, 0x070F, 0x0000 }, /* R4298  - Write Sequencer 202 */
+       [4299] = { 0x010F, 0x010F, 0x0000 }, /* R4299  - Write Sequencer 203 */
+       [4300] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4300  - Write Sequencer 204 */
+       [4301] = { 0x00FF, 0x00FF, 0x0000 }, /* R4301  - Write Sequencer 205 */
+       [4302] = { 0x070F, 0x070F, 0x0000 }, /* R4302  - Write Sequencer 206 */
+       [4303] = { 0x010F, 0x010F, 0x0000 }, /* R4303  - Write Sequencer 207 */
+       [4304] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4304  - Write Sequencer 208 */
+       [4305] = { 0x00FF, 0x00FF, 0x0000 }, /* R4305  - Write Sequencer 209 */
+       [4306] = { 0x070F, 0x070F, 0x0000 }, /* R4306  - Write Sequencer 210 */
+       [4307] = { 0x010F, 0x010F, 0x0000 }, /* R4307  - Write Sequencer 211 */
+       [4308] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4308  - Write Sequencer 212 */
+       [4309] = { 0x00FF, 0x00FF, 0x0000 }, /* R4309  - Write Sequencer 213 */
+       [4310] = { 0x070F, 0x070F, 0x0000 }, /* R4310  - Write Sequencer 214 */
+       [4311] = { 0x010F, 0x010F, 0x0000 }, /* R4311  - Write Sequencer 215 */
+       [4312] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4312  - Write Sequencer 216 */
+       [4313] = { 0x00FF, 0x00FF, 0x0000 }, /* R4313  - Write Sequencer 217 */
+       [4314] = { 0x070F, 0x070F, 0x0000 }, /* R4314  - Write Sequencer 218 */
+       [4315] = { 0x010F, 0x010F, 0x0000 }, /* R4315  - Write Sequencer 219 */
+       [4316] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4316  - Write Sequencer 220 */
+       [4317] = { 0x00FF, 0x00FF, 0x0000 }, /* R4317  - Write Sequencer 221 */
+       [4318] = { 0x070F, 0x070F, 0x0000 }, /* R4318  - Write Sequencer 222 */
+       [4319] = { 0x010F, 0x010F, 0x0000 }, /* R4319  - Write Sequencer 223 */
+       [4320] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4320  - Write Sequencer 224 */
+       [4321] = { 0x00FF, 0x00FF, 0x0000 }, /* R4321  - Write Sequencer 225 */
+       [4322] = { 0x070F, 0x070F, 0x0000 }, /* R4322  - Write Sequencer 226 */
+       [4323] = { 0x010F, 0x010F, 0x0000 }, /* R4323  - Write Sequencer 227 */
+       [4324] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4324  - Write Sequencer 228 */
+       [4325] = { 0x00FF, 0x00FF, 0x0000 }, /* R4325  - Write Sequencer 229 */
+       [4326] = { 0x070F, 0x070F, 0x0000 }, /* R4326  - Write Sequencer 230 */
+       [4327] = { 0x010F, 0x010F, 0x0000 }, /* R4327  - Write Sequencer 231 */
+       [4328] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4328  - Write Sequencer 232 */
+       [4329] = { 0x00FF, 0x00FF, 0x0000 }, /* R4329  - Write Sequencer 233 */
+       [4330] = { 0x070F, 0x070F, 0x0000 }, /* R4330  - Write Sequencer 234 */
+       [4331] = { 0x010F, 0x010F, 0x0000 }, /* R4331  - Write Sequencer 235 */
+       [4332] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4332  - Write Sequencer 236 */
+       [4333] = { 0x00FF, 0x00FF, 0x0000 }, /* R4333  - Write Sequencer 237 */
+       [4334] = { 0x070F, 0x070F, 0x0000 }, /* R4334  - Write Sequencer 238 */
+       [4335] = { 0x010F, 0x010F, 0x0000 }, /* R4335  - Write Sequencer 239 */
+       [4336] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4336  - Write Sequencer 240 */
+       [4337] = { 0x00FF, 0x00FF, 0x0000 }, /* R4337  - Write Sequencer 241 */
+       [4338] = { 0x070F, 0x070F, 0x0000 }, /* R4338  - Write Sequencer 242 */
+       [4339] = { 0x010F, 0x010F, 0x0000 }, /* R4339  - Write Sequencer 243 */
+       [4340] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4340  - Write Sequencer 244 */
+       [4341] = { 0x00FF, 0x00FF, 0x0000 }, /* R4341  - Write Sequencer 245 */
+       [4342] = { 0x070F, 0x070F, 0x0000 }, /* R4342  - Write Sequencer 246 */
+       [4343] = { 0x010F, 0x010F, 0x0000 }, /* R4343  - Write Sequencer 247 */
+       [4344] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4344  - Write Sequencer 248 */
+       [4345] = { 0x00FF, 0x00FF, 0x0000 }, /* R4345  - Write Sequencer 249 */
+       [4346] = { 0x070F, 0x070F, 0x0000 }, /* R4346  - Write Sequencer 250 */
+       [4347] = { 0x010F, 0x010F, 0x0000 }, /* R4347  - Write Sequencer 251 */
+       [4348] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4348  - Write Sequencer 252 */
+       [4349] = { 0x00FF, 0x00FF, 0x0000 }, /* R4349  - Write Sequencer 253 */
+       [4350] = { 0x070F, 0x070F, 0x0000 }, /* R4350  - Write Sequencer 254 */
+       [4351] = { 0x010F, 0x010F, 0x0000 }, /* R4351  - Write Sequencer 255 */
+       [4352] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4352  - Write Sequencer 256 */
+       [4353] = { 0x00FF, 0x00FF, 0x0000 }, /* R4353  - Write Sequencer 257 */
+       [4354] = { 0x070F, 0x070F, 0x0000 }, /* R4354  - Write Sequencer 258 */
+       [4355] = { 0x010F, 0x010F, 0x0000 }, /* R4355  - Write Sequencer 259 */
+       [4356] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4356  - Write Sequencer 260 */
+       [4357] = { 0x00FF, 0x00FF, 0x0000 }, /* R4357  - Write Sequencer 261 */
+       [4358] = { 0x070F, 0x070F, 0x0000 }, /* R4358  - Write Sequencer 262 */
+       [4359] = { 0x010F, 0x010F, 0x0000 }, /* R4359  - Write Sequencer 263 */
+       [4360] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4360  - Write Sequencer 264 */
+       [4361] = { 0x00FF, 0x00FF, 0x0000 }, /* R4361  - Write Sequencer 265 */
+       [4362] = { 0x070F, 0x070F, 0x0000 }, /* R4362  - Write Sequencer 266 */
+       [4363] = { 0x010F, 0x010F, 0x0000 }, /* R4363  - Write Sequencer 267 */
+       [4364] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4364  - Write Sequencer 268 */
+       [4365] = { 0x00FF, 0x00FF, 0x0000 }, /* R4365  - Write Sequencer 269 */
+       [4366] = { 0x070F, 0x070F, 0x0000 }, /* R4366  - Write Sequencer 270 */
+       [4367] = { 0x010F, 0x010F, 0x0000 }, /* R4367  - Write Sequencer 271 */
+       [4368] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4368  - Write Sequencer 272 */
+       [4369] = { 0x00FF, 0x00FF, 0x0000 }, /* R4369  - Write Sequencer 273 */
+       [4370] = { 0x070F, 0x070F, 0x0000 }, /* R4370  - Write Sequencer 274 */
+       [4371] = { 0x010F, 0x010F, 0x0000 }, /* R4371  - Write Sequencer 275 */
+       [4372] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4372  - Write Sequencer 276 */
+       [4373] = { 0x00FF, 0x00FF, 0x0000 }, /* R4373  - Write Sequencer 277 */
+       [4374] = { 0x070F, 0x070F, 0x0000 }, /* R4374  - Write Sequencer 278 */
+       [4375] = { 0x010F, 0x010F, 0x0000 }, /* R4375  - Write Sequencer 279 */
+       [4376] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4376  - Write Sequencer 280 */
+       [4377] = { 0x00FF, 0x00FF, 0x0000 }, /* R4377  - Write Sequencer 281 */
+       [4378] = { 0x070F, 0x070F, 0x0000 }, /* R4378  - Write Sequencer 282 */
+       [4379] = { 0x010F, 0x010F, 0x0000 }, /* R4379  - Write Sequencer 283 */
+       [4380] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4380  - Write Sequencer 284 */
+       [4381] = { 0x00FF, 0x00FF, 0x0000 }, /* R4381  - Write Sequencer 285 */
+       [4382] = { 0x070F, 0x070F, 0x0000 }, /* R4382  - Write Sequencer 286 */
+       [4383] = { 0x010F, 0x010F, 0x0000 }, /* R4383  - Write Sequencer 287 */
+       [4384] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4384  - Write Sequencer 288 */
+       [4385] = { 0x00FF, 0x00FF, 0x0000 }, /* R4385  - Write Sequencer 289 */
+       [4386] = { 0x070F, 0x070F, 0x0000 }, /* R4386  - Write Sequencer 290 */
+       [4387] = { 0x010F, 0x010F, 0x0000 }, /* R4387  - Write Sequencer 291 */
+       [4388] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4388  - Write Sequencer 292 */
+       [4389] = { 0x00FF, 0x00FF, 0x0000 }, /* R4389  - Write Sequencer 293 */
+       [4390] = { 0x070F, 0x070F, 0x0000 }, /* R4390  - Write Sequencer 294 */
+       [4391] = { 0x010F, 0x010F, 0x0000 }, /* R4391  - Write Sequencer 295 */
+       [4392] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4392  - Write Sequencer 296 */
+       [4393] = { 0x00FF, 0x00FF, 0x0000 }, /* R4393  - Write Sequencer 297 */
+       [4394] = { 0x070F, 0x070F, 0x0000 }, /* R4394  - Write Sequencer 298 */
+       [4395] = { 0x010F, 0x010F, 0x0000 }, /* R4395  - Write Sequencer 299 */
+       [4396] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4396  - Write Sequencer 300 */
+       [4397] = { 0x00FF, 0x00FF, 0x0000 }, /* R4397  - Write Sequencer 301 */
+       [4398] = { 0x070F, 0x070F, 0x0000 }, /* R4398  - Write Sequencer 302 */
+       [4399] = { 0x010F, 0x010F, 0x0000 }, /* R4399  - Write Sequencer 303 */
+       [4400] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4400  - Write Sequencer 304 */
+       [4401] = { 0x00FF, 0x00FF, 0x0000 }, /* R4401  - Write Sequencer 305 */
+       [4402] = { 0x070F, 0x070F, 0x0000 }, /* R4402  - Write Sequencer 306 */
+       [4403] = { 0x010F, 0x010F, 0x0000 }, /* R4403  - Write Sequencer 307 */
+       [4404] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4404  - Write Sequencer 308 */
+       [4405] = { 0x00FF, 0x00FF, 0x0000 }, /* R4405  - Write Sequencer 309 */
+       [4406] = { 0x070F, 0x070F, 0x0000 }, /* R4406  - Write Sequencer 310 */
+       [4407] = { 0x010F, 0x010F, 0x0000 }, /* R4407  - Write Sequencer 311 */
+       [4408] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4408  - Write Sequencer 312 */
+       [4409] = { 0x00FF, 0x00FF, 0x0000 }, /* R4409  - Write Sequencer 313 */
+       [4410] = { 0x070F, 0x070F, 0x0000 }, /* R4410  - Write Sequencer 314 */
+       [4411] = { 0x010F, 0x010F, 0x0000 }, /* R4411  - Write Sequencer 315 */
+       [4412] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4412  - Write Sequencer 316 */
+       [4413] = { 0x00FF, 0x00FF, 0x0000 }, /* R4413  - Write Sequencer 317 */
+       [4414] = { 0x070F, 0x070F, 0x0000 }, /* R4414  - Write Sequencer 318 */
+       [4415] = { 0x010F, 0x010F, 0x0000 }, /* R4415  - Write Sequencer 319 */
+       [4416] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4416  - Write Sequencer 320 */
+       [4417] = { 0x00FF, 0x00FF, 0x0000 }, /* R4417  - Write Sequencer 321 */
+       [4418] = { 0x070F, 0x070F, 0x0000 }, /* R4418  - Write Sequencer 322 */
+       [4419] = { 0x010F, 0x010F, 0x0000 }, /* R4419  - Write Sequencer 323 */
+       [4420] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4420  - Write Sequencer 324 */
+       [4421] = { 0x00FF, 0x00FF, 0x0000 }, /* R4421  - Write Sequencer 325 */
+       [4422] = { 0x070F, 0x070F, 0x0000 }, /* R4422  - Write Sequencer 326 */
+       [4423] = { 0x010F, 0x010F, 0x0000 }, /* R4423  - Write Sequencer 327 */
+       [4424] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4424  - Write Sequencer 328 */
+       [4425] = { 0x00FF, 0x00FF, 0x0000 }, /* R4425  - Write Sequencer 329 */
+       [4426] = { 0x070F, 0x070F, 0x0000 }, /* R4426  - Write Sequencer 330 */
+       [4427] = { 0x010F, 0x010F, 0x0000 }, /* R4427  - Write Sequencer 331 */
+       [4428] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4428  - Write Sequencer 332 */
+       [4429] = { 0x00FF, 0x00FF, 0x0000 }, /* R4429  - Write Sequencer 333 */
+       [4430] = { 0x070F, 0x070F, 0x0000 }, /* R4430  - Write Sequencer 334 */
+       [4431] = { 0x010F, 0x010F, 0x0000 }, /* R4431  - Write Sequencer 335 */
+       [4432] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4432  - Write Sequencer 336 */
+       [4433] = { 0x00FF, 0x00FF, 0x0000 }, /* R4433  - Write Sequencer 337 */
+       [4434] = { 0x070F, 0x070F, 0x0000 }, /* R4434  - Write Sequencer 338 */
+       [4435] = { 0x010F, 0x010F, 0x0000 }, /* R4435  - Write Sequencer 339 */
+       [4436] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4436  - Write Sequencer 340 */
+       [4437] = { 0x00FF, 0x00FF, 0x0000 }, /* R4437  - Write Sequencer 341 */
+       [4438] = { 0x070F, 0x070F, 0x0000 }, /* R4438  - Write Sequencer 342 */
+       [4439] = { 0x010F, 0x010F, 0x0000 }, /* R4439  - Write Sequencer 343 */
+       [4440] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4440  - Write Sequencer 344 */
+       [4441] = { 0x00FF, 0x00FF, 0x0000 }, /* R4441  - Write Sequencer 345 */
+       [4442] = { 0x070F, 0x070F, 0x0000 }, /* R4442  - Write Sequencer 346 */
+       [4443] = { 0x010F, 0x010F, 0x0000 }, /* R4443  - Write Sequencer 347 */
+       [4444] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4444  - Write Sequencer 348 */
+       [4445] = { 0x00FF, 0x00FF, 0x0000 }, /* R4445  - Write Sequencer 349 */
+       [4446] = { 0x070F, 0x070F, 0x0000 }, /* R4446  - Write Sequencer 350 */
+       [4447] = { 0x010F, 0x010F, 0x0000 }, /* R4447  - Write Sequencer 351 */
+       [4448] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4448  - Write Sequencer 352 */
+       [4449] = { 0x00FF, 0x00FF, 0x0000 }, /* R4449  - Write Sequencer 353 */
+       [4450] = { 0x070F, 0x070F, 0x0000 }, /* R4450  - Write Sequencer 354 */
+       [4451] = { 0x010F, 0x010F, 0x0000 }, /* R4451  - Write Sequencer 355 */
+       [4452] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4452  - Write Sequencer 356 */
+       [4453] = { 0x00FF, 0x00FF, 0x0000 }, /* R4453  - Write Sequencer 357 */
+       [4454] = { 0x070F, 0x070F, 0x0000 }, /* R4454  - Write Sequencer 358 */
+       [4455] = { 0x010F, 0x010F, 0x0000 }, /* R4455  - Write Sequencer 359 */
+       [4456] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4456  - Write Sequencer 360 */
+       [4457] = { 0x00FF, 0x00FF, 0x0000 }, /* R4457  - Write Sequencer 361 */
+       [4458] = { 0x070F, 0x070F, 0x0000 }, /* R4458  - Write Sequencer 362 */
+       [4459] = { 0x010F, 0x010F, 0x0000 }, /* R4459  - Write Sequencer 363 */
+       [4460] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4460  - Write Sequencer 364 */
+       [4461] = { 0x00FF, 0x00FF, 0x0000 }, /* R4461  - Write Sequencer 365 */
+       [4462] = { 0x070F, 0x070F, 0x0000 }, /* R4462  - Write Sequencer 366 */
+       [4463] = { 0x010F, 0x010F, 0x0000 }, /* R4463  - Write Sequencer 367 */
+       [4464] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4464  - Write Sequencer 368 */
+       [4465] = { 0x00FF, 0x00FF, 0x0000 }, /* R4465  - Write Sequencer 369 */
+       [4466] = { 0x070F, 0x070F, 0x0000 }, /* R4466  - Write Sequencer 370 */
+       [4467] = { 0x010F, 0x010F, 0x0000 }, /* R4467  - Write Sequencer 371 */
+       [4468] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4468  - Write Sequencer 372 */
+       [4469] = { 0x00FF, 0x00FF, 0x0000 }, /* R4469  - Write Sequencer 373 */
+       [4470] = { 0x070F, 0x070F, 0x0000 }, /* R4470  - Write Sequencer 374 */
+       [4471] = { 0x010F, 0x010F, 0x0000 }, /* R4471  - Write Sequencer 375 */
+       [4472] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4472  - Write Sequencer 376 */
+       [4473] = { 0x00FF, 0x00FF, 0x0000 }, /* R4473  - Write Sequencer 377 */
+       [4474] = { 0x070F, 0x070F, 0x0000 }, /* R4474  - Write Sequencer 378 */
+       [4475] = { 0x010F, 0x010F, 0x0000 }, /* R4475  - Write Sequencer 379 */
+       [4476] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4476  - Write Sequencer 380 */
+       [4477] = { 0x00FF, 0x00FF, 0x0000 }, /* R4477  - Write Sequencer 381 */
+       [4478] = { 0x070F, 0x070F, 0x0000 }, /* R4478  - Write Sequencer 382 */
+       [4479] = { 0x010F, 0x010F, 0x0000 }, /* R4479  - Write Sequencer 383 */
+       [4480] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4480  - Write Sequencer 384 */
+       [4481] = { 0x00FF, 0x00FF, 0x0000 }, /* R4481  - Write Sequencer 385 */
+       [4482] = { 0x070F, 0x070F, 0x0000 }, /* R4482  - Write Sequencer 386 */
+       [4483] = { 0x010F, 0x010F, 0x0000 }, /* R4483  - Write Sequencer 387 */
+       [4484] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4484  - Write Sequencer 388 */
+       [4485] = { 0x00FF, 0x00FF, 0x0000 }, /* R4485  - Write Sequencer 389 */
+       [4486] = { 0x070F, 0x070F, 0x0000 }, /* R4486  - Write Sequencer 390 */
+       [4487] = { 0x010F, 0x010F, 0x0000 }, /* R4487  - Write Sequencer 391 */
+       [4488] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4488  - Write Sequencer 392 */
+       [4489] = { 0x00FF, 0x00FF, 0x0000 }, /* R4489  - Write Sequencer 393 */
+       [4490] = { 0x070F, 0x070F, 0x0000 }, /* R4490  - Write Sequencer 394 */
+       [4491] = { 0x010F, 0x010F, 0x0000 }, /* R4491  - Write Sequencer 395 */
+       [4492] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4492  - Write Sequencer 396 */
+       [4493] = { 0x00FF, 0x00FF, 0x0000 }, /* R4493  - Write Sequencer 397 */
+       [4494] = { 0x070F, 0x070F, 0x0000 }, /* R4494  - Write Sequencer 398 */
+       [4495] = { 0x010F, 0x010F, 0x0000 }, /* R4495  - Write Sequencer 399 */
+       [4496] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4496  - Write Sequencer 400 */
+       [4497] = { 0x00FF, 0x00FF, 0x0000 }, /* R4497  - Write Sequencer 401 */
+       [4498] = { 0x070F, 0x070F, 0x0000 }, /* R4498  - Write Sequencer 402 */
+       [4499] = { 0x010F, 0x010F, 0x0000 }, /* R4499  - Write Sequencer 403 */
+       [4500] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4500  - Write Sequencer 404 */
+       [4501] = { 0x00FF, 0x00FF, 0x0000 }, /* R4501  - Write Sequencer 405 */
+       [4502] = { 0x070F, 0x070F, 0x0000 }, /* R4502  - Write Sequencer 406 */
+       [4503] = { 0x010F, 0x010F, 0x0000 }, /* R4503  - Write Sequencer 407 */
+       [4504] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4504  - Write Sequencer 408 */
+       [4505] = { 0x00FF, 0x00FF, 0x0000 }, /* R4505  - Write Sequencer 409 */
+       [4506] = { 0x070F, 0x070F, 0x0000 }, /* R4506  - Write Sequencer 410 */
+       [4507] = { 0x010F, 0x010F, 0x0000 }, /* R4507  - Write Sequencer 411 */
+       [4508] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4508  - Write Sequencer 412 */
+       [4509] = { 0x00FF, 0x00FF, 0x0000 }, /* R4509  - Write Sequencer 413 */
+       [4510] = { 0x070F, 0x070F, 0x0000 }, /* R4510  - Write Sequencer 414 */
+       [4511] = { 0x010F, 0x010F, 0x0000 }, /* R4511  - Write Sequencer 415 */
+       [4512] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4512  - Write Sequencer 416 */
+       [4513] = { 0x00FF, 0x00FF, 0x0000 }, /* R4513  - Write Sequencer 417 */
+       [4514] = { 0x070F, 0x070F, 0x0000 }, /* R4514  - Write Sequencer 418 */
+       [4515] = { 0x010F, 0x010F, 0x0000 }, /* R4515  - Write Sequencer 419 */
+       [4516] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4516  - Write Sequencer 420 */
+       [4517] = { 0x00FF, 0x00FF, 0x0000 }, /* R4517  - Write Sequencer 421 */
+       [4518] = { 0x070F, 0x070F, 0x0000 }, /* R4518  - Write Sequencer 422 */
+       [4519] = { 0x010F, 0x010F, 0x0000 }, /* R4519  - Write Sequencer 423 */
+       [4520] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4520  - Write Sequencer 424 */
+       [4521] = { 0x00FF, 0x00FF, 0x0000 }, /* R4521  - Write Sequencer 425 */
+       [4522] = { 0x070F, 0x070F, 0x0000 }, /* R4522  - Write Sequencer 426 */
+       [4523] = { 0x010F, 0x010F, 0x0000 }, /* R4523  - Write Sequencer 427 */
+       [4524] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4524  - Write Sequencer 428 */
+       [4525] = { 0x00FF, 0x00FF, 0x0000 }, /* R4525  - Write Sequencer 429 */
+       [4526] = { 0x070F, 0x070F, 0x0000 }, /* R4526  - Write Sequencer 430 */
+       [4527] = { 0x010F, 0x010F, 0x0000 }, /* R4527  - Write Sequencer 431 */
+       [4528] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4528  - Write Sequencer 432 */
+       [4529] = { 0x00FF, 0x00FF, 0x0000 }, /* R4529  - Write Sequencer 433 */
+       [4530] = { 0x070F, 0x070F, 0x0000 }, /* R4530  - Write Sequencer 434 */
+       [4531] = { 0x010F, 0x010F, 0x0000 }, /* R4531  - Write Sequencer 435 */
+       [4532] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4532  - Write Sequencer 436 */
+       [4533] = { 0x00FF, 0x00FF, 0x0000 }, /* R4533  - Write Sequencer 437 */
+       [4534] = { 0x070F, 0x070F, 0x0000 }, /* R4534  - Write Sequencer 438 */
+       [4535] = { 0x010F, 0x010F, 0x0000 }, /* R4535  - Write Sequencer 439 */
+       [4536] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4536  - Write Sequencer 440 */
+       [4537] = { 0x00FF, 0x00FF, 0x0000 }, /* R4537  - Write Sequencer 441 */
+       [4538] = { 0x070F, 0x070F, 0x0000 }, /* R4538  - Write Sequencer 442 */
+       [4539] = { 0x010F, 0x010F, 0x0000 }, /* R4539  - Write Sequencer 443 */
+       [4540] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4540  - Write Sequencer 444 */
+       [4541] = { 0x00FF, 0x00FF, 0x0000 }, /* R4541  - Write Sequencer 445 */
+       [4542] = { 0x070F, 0x070F, 0x0000 }, /* R4542  - Write Sequencer 446 */
+       [4543] = { 0x010F, 0x010F, 0x0000 }, /* R4543  - Write Sequencer 447 */
+       [4544] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4544  - Write Sequencer 448 */
+       [4545] = { 0x00FF, 0x00FF, 0x0000 }, /* R4545  - Write Sequencer 449 */
+       [4546] = { 0x070F, 0x070F, 0x0000 }, /* R4546  - Write Sequencer 450 */
+       [4547] = { 0x010F, 0x010F, 0x0000 }, /* R4547  - Write Sequencer 451 */
+       [4548] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4548  - Write Sequencer 452 */
+       [4549] = { 0x00FF, 0x00FF, 0x0000 }, /* R4549  - Write Sequencer 453 */
+       [4550] = { 0x070F, 0x070F, 0x0000 }, /* R4550  - Write Sequencer 454 */
+       [4551] = { 0x010F, 0x010F, 0x0000 }, /* R4551  - Write Sequencer 455 */
+       [4552] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4552  - Write Sequencer 456 */
+       [4553] = { 0x00FF, 0x00FF, 0x0000 }, /* R4553  - Write Sequencer 457 */
+       [4554] = { 0x070F, 0x070F, 0x0000 }, /* R4554  - Write Sequencer 458 */
+       [4555] = { 0x010F, 0x010F, 0x0000 }, /* R4555  - Write Sequencer 459 */
+       [4556] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4556  - Write Sequencer 460 */
+       [4557] = { 0x00FF, 0x00FF, 0x0000 }, /* R4557  - Write Sequencer 461 */
+       [4558] = { 0x070F, 0x070F, 0x0000 }, /* R4558  - Write Sequencer 462 */
+       [4559] = { 0x010F, 0x010F, 0x0000 }, /* R4559  - Write Sequencer 463 */
+       [4560] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4560  - Write Sequencer 464 */
+       [4561] = { 0x00FF, 0x00FF, 0x0000 }, /* R4561  - Write Sequencer 465 */
+       [4562] = { 0x070F, 0x070F, 0x0000 }, /* R4562  - Write Sequencer 466 */
+       [4563] = { 0x010F, 0x010F, 0x0000 }, /* R4563  - Write Sequencer 467 */
+       [4564] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4564  - Write Sequencer 468 */
+       [4565] = { 0x00FF, 0x00FF, 0x0000 }, /* R4565  - Write Sequencer 469 */
+       [4566] = { 0x070F, 0x070F, 0x0000 }, /* R4566  - Write Sequencer 470 */
+       [4567] = { 0x010F, 0x010F, 0x0000 }, /* R4567  - Write Sequencer 471 */
+       [4568] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4568  - Write Sequencer 472 */
+       [4569] = { 0x00FF, 0x00FF, 0x0000 }, /* R4569  - Write Sequencer 473 */
+       [4570] = { 0x070F, 0x070F, 0x0000 }, /* R4570  - Write Sequencer 474 */
+       [4571] = { 0x010F, 0x010F, 0x0000 }, /* R4571  - Write Sequencer 475 */
+       [4572] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4572  - Write Sequencer 476 */
+       [4573] = { 0x00FF, 0x00FF, 0x0000 }, /* R4573  - Write Sequencer 477 */
+       [4574] = { 0x070F, 0x070F, 0x0000 }, /* R4574  - Write Sequencer 478 */
+       [4575] = { 0x010F, 0x010F, 0x0000 }, /* R4575  - Write Sequencer 479 */
+       [4576] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4576  - Write Sequencer 480 */
+       [4577] = { 0x00FF, 0x00FF, 0x0000 }, /* R4577  - Write Sequencer 481 */
+       [4578] = { 0x070F, 0x070F, 0x0000 }, /* R4578  - Write Sequencer 482 */
+       [4579] = { 0x010F, 0x010F, 0x0000 }, /* R4579  - Write Sequencer 483 */
+       [4580] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4580  - Write Sequencer 484 */
+       [4581] = { 0x00FF, 0x00FF, 0x0000 }, /* R4581  - Write Sequencer 485 */
+       [4582] = { 0x070F, 0x070F, 0x0000 }, /* R4582  - Write Sequencer 486 */
+       [4583] = { 0x010F, 0x010F, 0x0000 }, /* R4583  - Write Sequencer 487 */
+       [4584] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4584  - Write Sequencer 488 */
+       [4585] = { 0x00FF, 0x00FF, 0x0000 }, /* R4585  - Write Sequencer 489 */
+       [4586] = { 0x070F, 0x070F, 0x0000 }, /* R4586  - Write Sequencer 490 */
+       [4587] = { 0x010F, 0x010F, 0x0000 }, /* R4587  - Write Sequencer 491 */
+       [4588] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4588  - Write Sequencer 492 */
+       [4589] = { 0x00FF, 0x00FF, 0x0000 }, /* R4589  - Write Sequencer 493 */
+       [4590] = { 0x070F, 0x070F, 0x0000 }, /* R4590  - Write Sequencer 494 */
+       [4591] = { 0x010F, 0x010F, 0x0000 }, /* R4591  - Write Sequencer 495 */
+       [4592] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4592  - Write Sequencer 496 */
+       [4593] = { 0x00FF, 0x00FF, 0x0000 }, /* R4593  - Write Sequencer 497 */
+       [4594] = { 0x070F, 0x070F, 0x0000 }, /* R4594  - Write Sequencer 498 */
+       [4595] = { 0x010F, 0x010F, 0x0000 }, /* R4595  - Write Sequencer 499 */
+       [4596] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4596  - Write Sequencer 500 */
+       [4597] = { 0x00FF, 0x00FF, 0x0000 }, /* R4597  - Write Sequencer 501 */
+       [4598] = { 0x070F, 0x070F, 0x0000 }, /* R4598  - Write Sequencer 502 */
+       [4599] = { 0x010F, 0x010F, 0x0000 }, /* R4599  - Write Sequencer 503 */
+       [4600] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4600  - Write Sequencer 504 */
+       [4601] = { 0x00FF, 0x00FF, 0x0000 }, /* R4601  - Write Sequencer 505 */
+       [4602] = { 0x070F, 0x070F, 0x0000 }, /* R4602  - Write Sequencer 506 */
+       [4603] = { 0x010F, 0x010F, 0x0000 }, /* R4603  - Write Sequencer 507 */
+       [4604] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4604  - Write Sequencer 508 */
+       [4605] = { 0x00FF, 0x00FF, 0x0000 }, /* R4605  - Write Sequencer 509 */
+       [4606] = { 0x070F, 0x070F, 0x0000 }, /* R4606  - Write Sequencer 510 */
+       [4607] = { 0x010F, 0x010F, 0x0000 }, /* R4607  - Write Sequencer 511 */
+       [8192] = { 0x03FF, 0x03FF, 0x0000 }, /* R8192  - DSP2 Instruction RAM 0 */
+       [9216] = { 0x003F, 0x003F, 0x0000 }, /* R9216  - DSP2 Address RAM 2 */
+       [9217] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R9217  - DSP2 Address RAM 1 */
+       [9218] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R9218  - DSP2 Address RAM 0 */
+       [12288] = { 0x00FF, 0x00FF, 0x0000 }, /* R12288 - DSP2 Data1 RAM 1 */
+       [12289] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R12289 - DSP2 Data1 RAM 0 */
+       [13312] = { 0x00FF, 0x00FF, 0x0000 }, /* R13312 - DSP2 Data2 RAM 1 */
+       [13313] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R13313 - DSP2 Data2 RAM 0 */
+       [14336] = { 0x00FF, 0x00FF, 0x0000 }, /* R14336 - DSP2 Data3 RAM 1 */
+       [14337] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R14337 - DSP2 Data3 RAM 0 */
+       [15360] = { 0x07FF, 0x07FF, 0x0000 }, /* R15360 - DSP2 Coeff RAM 0 */
+       [16384] = { 0x00FF, 0x00FF, 0x0000 }, /* R16384 - RETUNEADC_SHARED_COEFF_1 */
+       [16385] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16385 - RETUNEADC_SHARED_COEFF_0 */
+       [16386] = { 0x00FF, 0x00FF, 0x0000 }, /* R16386 - RETUNEDAC_SHARED_COEFF_1 */
+       [16387] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16387 - RETUNEDAC_SHARED_COEFF_0 */
+       [16388] = { 0x00FF, 0x00FF, 0x0000 }, /* R16388 - SOUNDSTAGE_ENABLES_1 */
+       [16389] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16389 - SOUNDSTAGE_ENABLES_0 */
+       [16896] = { 0x00FF, 0x00FF, 0x0000 }, /* R16896 - HDBASS_AI_1 */
+       [16897] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16897 - HDBASS_AI_0 */
+       [16898] = { 0x00FF, 0x00FF, 0x0000 }, /* R16898 - HDBASS_AR_1 */
+       [16899] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16899 - HDBASS_AR_0 */
+       [16900] = { 0x00FF, 0x00FF, 0x0000 }, /* R16900 - HDBASS_B_1 */
+       [16901] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16901 - HDBASS_B_0 */
+       [16902] = { 0x00FF, 0x00FF, 0x0000 }, /* R16902 - HDBASS_K_1 */
+       [16903] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16903 - HDBASS_K_0 */
+       [16904] = { 0x00FF, 0x00FF, 0x0000 }, /* R16904 - HDBASS_N1_1 */
+       [16905] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16905 - HDBASS_N1_0 */
+       [16906] = { 0x00FF, 0x00FF, 0x0000 }, /* R16906 - HDBASS_N2_1 */
+       [16907] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16907 - HDBASS_N2_0 */
+       [16908] = { 0x00FF, 0x00FF, 0x0000 }, /* R16908 - HDBASS_N3_1 */
+       [16909] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16909 - HDBASS_N3_0 */
+       [16910] = { 0x00FF, 0x00FF, 0x0000 }, /* R16910 - HDBASS_N4_1 */
+       [16911] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16911 - HDBASS_N4_0 */
+       [16912] = { 0x00FF, 0x00FF, 0x0000 }, /* R16912 - HDBASS_N5_1 */
+       [16913] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16913 - HDBASS_N5_0 */
+       [16914] = { 0x00FF, 0x00FF, 0x0000 }, /* R16914 - HDBASS_X1_1 */
+       [16915] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16915 - HDBASS_X1_0 */
+       [16916] = { 0x00FF, 0x00FF, 0x0000 }, /* R16916 - HDBASS_X2_1 */
+       [16917] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16917 - HDBASS_X2_0 */
+       [16918] = { 0x00FF, 0x00FF, 0x0000 }, /* R16918 - HDBASS_X3_1 */
+       [16919] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16919 - HDBASS_X3_0 */
+       [16920] = { 0x00FF, 0x00FF, 0x0000 }, /* R16920 - HDBASS_ATK_1 */
+       [16921] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16921 - HDBASS_ATK_0 */
+       [16922] = { 0x00FF, 0x00FF, 0x0000 }, /* R16922 - HDBASS_DCY_1 */
+       [16923] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16923 - HDBASS_DCY_0 */
+       [16924] = { 0x00FF, 0x00FF, 0x0000 }, /* R16924 - HDBASS_PG_1 */
+       [16925] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R16925 - HDBASS_PG_0 */
+       [17408] = { 0x00FF, 0x00FF, 0x0000 }, /* R17408 - HPF_C_1 */
+       [17409] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17409 - HPF_C_0 */
+       [17920] = { 0x00FF, 0x00FF, 0x0000 }, /* R17920 - ADCL_RETUNE_C1_1 */
+       [17921] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17921 - ADCL_RETUNE_C1_0 */
+       [17922] = { 0x00FF, 0x00FF, 0x0000 }, /* R17922 - ADCL_RETUNE_C2_1 */
+       [17923] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17923 - ADCL_RETUNE_C2_0 */
+       [17924] = { 0x00FF, 0x00FF, 0x0000 }, /* R17924 - ADCL_RETUNE_C3_1 */
+       [17925] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17925 - ADCL_RETUNE_C3_0 */
+       [17926] = { 0x00FF, 0x00FF, 0x0000 }, /* R17926 - ADCL_RETUNE_C4_1 */
+       [17927] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17927 - ADCL_RETUNE_C4_0 */
+       [17928] = { 0x00FF, 0x00FF, 0x0000 }, /* R17928 - ADCL_RETUNE_C5_1 */
+       [17929] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17929 - ADCL_RETUNE_C5_0 */
+       [17930] = { 0x00FF, 0x00FF, 0x0000 }, /* R17930 - ADCL_RETUNE_C6_1 */
+       [17931] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17931 - ADCL_RETUNE_C6_0 */
+       [17932] = { 0x00FF, 0x00FF, 0x0000 }, /* R17932 - ADCL_RETUNE_C7_1 */
+       [17933] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17933 - ADCL_RETUNE_C7_0 */
+       [17934] = { 0x00FF, 0x00FF, 0x0000 }, /* R17934 - ADCL_RETUNE_C8_1 */
+       [17935] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17935 - ADCL_RETUNE_C8_0 */
+       [17936] = { 0x00FF, 0x00FF, 0x0000 }, /* R17936 - ADCL_RETUNE_C9_1 */
+       [17937] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17937 - ADCL_RETUNE_C9_0 */
+       [17938] = { 0x00FF, 0x00FF, 0x0000 }, /* R17938 - ADCL_RETUNE_C10_1 */
+       [17939] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17939 - ADCL_RETUNE_C10_0 */
+       [17940] = { 0x00FF, 0x00FF, 0x0000 }, /* R17940 - ADCL_RETUNE_C11_1 */
+       [17941] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17941 - ADCL_RETUNE_C11_0 */
+       [17942] = { 0x00FF, 0x00FF, 0x0000 }, /* R17942 - ADCL_RETUNE_C12_1 */
+       [17943] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17943 - ADCL_RETUNE_C12_0 */
+       [17944] = { 0x00FF, 0x00FF, 0x0000 }, /* R17944 - ADCL_RETUNE_C13_1 */
+       [17945] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17945 - ADCL_RETUNE_C13_0 */
+       [17946] = { 0x00FF, 0x00FF, 0x0000 }, /* R17946 - ADCL_RETUNE_C14_1 */
+       [17947] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17947 - ADCL_RETUNE_C14_0 */
+       [17948] = { 0x00FF, 0x00FF, 0x0000 }, /* R17948 - ADCL_RETUNE_C15_1 */
+       [17949] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17949 - ADCL_RETUNE_C15_0 */
+       [17950] = { 0x00FF, 0x00FF, 0x0000 }, /* R17950 - ADCL_RETUNE_C16_1 */
+       [17951] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17951 - ADCL_RETUNE_C16_0 */
+       [17952] = { 0x00FF, 0x00FF, 0x0000 }, /* R17952 - ADCL_RETUNE_C17_1 */
+       [17953] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17953 - ADCL_RETUNE_C17_0 */
+       [17954] = { 0x00FF, 0x00FF, 0x0000 }, /* R17954 - ADCL_RETUNE_C18_1 */
+       [17955] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17955 - ADCL_RETUNE_C18_0 */
+       [17956] = { 0x00FF, 0x00FF, 0x0000 }, /* R17956 - ADCL_RETUNE_C19_1 */
+       [17957] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17957 - ADCL_RETUNE_C19_0 */
+       [17958] = { 0x00FF, 0x00FF, 0x0000 }, /* R17958 - ADCL_RETUNE_C20_1 */
+       [17959] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17959 - ADCL_RETUNE_C20_0 */
+       [17960] = { 0x00FF, 0x00FF, 0x0000 }, /* R17960 - ADCL_RETUNE_C21_1 */
+       [17961] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17961 - ADCL_RETUNE_C21_0 */
+       [17962] = { 0x00FF, 0x00FF, 0x0000 }, /* R17962 - ADCL_RETUNE_C22_1 */
+       [17963] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17963 - ADCL_RETUNE_C22_0 */
+       [17964] = { 0x00FF, 0x00FF, 0x0000 }, /* R17964 - ADCL_RETUNE_C23_1 */
+       [17965] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17965 - ADCL_RETUNE_C23_0 */
+       [17966] = { 0x00FF, 0x00FF, 0x0000 }, /* R17966 - ADCL_RETUNE_C24_1 */
+       [17967] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17967 - ADCL_RETUNE_C24_0 */
+       [17968] = { 0x00FF, 0x00FF, 0x0000 }, /* R17968 - ADCL_RETUNE_C25_1 */
+       [17969] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17969 - ADCL_RETUNE_C25_0 */
+       [17970] = { 0x00FF, 0x00FF, 0x0000 }, /* R17970 - ADCL_RETUNE_C26_1 */
+       [17971] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17971 - ADCL_RETUNE_C26_0 */
+       [17972] = { 0x00FF, 0x00FF, 0x0000 }, /* R17972 - ADCL_RETUNE_C27_1 */
+       [17973] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17973 - ADCL_RETUNE_C27_0 */
+       [17974] = { 0x00FF, 0x00FF, 0x0000 }, /* R17974 - ADCL_RETUNE_C28_1 */
+       [17975] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17975 - ADCL_RETUNE_C28_0 */
+       [17976] = { 0x00FF, 0x00FF, 0x0000 }, /* R17976 - ADCL_RETUNE_C29_1 */
+       [17977] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17977 - ADCL_RETUNE_C29_0 */
+       [17978] = { 0x00FF, 0x00FF, 0x0000 }, /* R17978 - ADCL_RETUNE_C30_1 */
+       [17979] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17979 - ADCL_RETUNE_C30_0 */
+       [17980] = { 0x00FF, 0x00FF, 0x0000 }, /* R17980 - ADCL_RETUNE_C31_1 */
+       [17981] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17981 - ADCL_RETUNE_C31_0 */
+       [17982] = { 0x00FF, 0x00FF, 0x0000 }, /* R17982 - ADCL_RETUNE_C32_1 */
+       [17983] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R17983 - ADCL_RETUNE_C32_0 */
+       [18432] = { 0x00FF, 0x00FF, 0x0000 }, /* R18432 - RETUNEADC_PG2_1 */
+       [18433] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18433 - RETUNEADC_PG2_0 */
+       [18434] = { 0x00FF, 0x00FF, 0x0000 }, /* R18434 - RETUNEADC_PG_1 */
+       [18435] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18435 - RETUNEADC_PG_0 */
+       [18944] = { 0x00FF, 0x00FF, 0x0000 }, /* R18944 - ADCR_RETUNE_C1_1 */
+       [18945] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18945 - ADCR_RETUNE_C1_0 */
+       [18946] = { 0x00FF, 0x00FF, 0x0000 }, /* R18946 - ADCR_RETUNE_C2_1 */
+       [18947] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18947 - ADCR_RETUNE_C2_0 */
+       [18948] = { 0x00FF, 0x00FF, 0x0000 }, /* R18948 - ADCR_RETUNE_C3_1 */
+       [18949] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18949 - ADCR_RETUNE_C3_0 */
+       [18950] = { 0x00FF, 0x00FF, 0x0000 }, /* R18950 - ADCR_RETUNE_C4_1 */
+       [18951] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18951 - ADCR_RETUNE_C4_0 */
+       [18952] = { 0x00FF, 0x00FF, 0x0000 }, /* R18952 - ADCR_RETUNE_C5_1 */
+       [18953] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18953 - ADCR_RETUNE_C5_0 */
+       [18954] = { 0x00FF, 0x00FF, 0x0000 }, /* R18954 - ADCR_RETUNE_C6_1 */
+       [18955] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18955 - ADCR_RETUNE_C6_0 */
+       [18956] = { 0x00FF, 0x00FF, 0x0000 }, /* R18956 - ADCR_RETUNE_C7_1 */
+       [18957] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18957 - ADCR_RETUNE_C7_0 */
+       [18958] = { 0x00FF, 0x00FF, 0x0000 }, /* R18958 - ADCR_RETUNE_C8_1 */
+       [18959] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18959 - ADCR_RETUNE_C8_0 */
+       [18960] = { 0x00FF, 0x00FF, 0x0000 }, /* R18960 - ADCR_RETUNE_C9_1 */
+       [18961] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18961 - ADCR_RETUNE_C9_0 */
+       [18962] = { 0x00FF, 0x00FF, 0x0000 }, /* R18962 - ADCR_RETUNE_C10_1 */
+       [18963] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18963 - ADCR_RETUNE_C10_0 */
+       [18964] = { 0x00FF, 0x00FF, 0x0000 }, /* R18964 - ADCR_RETUNE_C11_1 */
+       [18965] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18965 - ADCR_RETUNE_C11_0 */
+       [18966] = { 0x00FF, 0x00FF, 0x0000 }, /* R18966 - ADCR_RETUNE_C12_1 */
+       [18967] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18967 - ADCR_RETUNE_C12_0 */
+       [18968] = { 0x00FF, 0x00FF, 0x0000 }, /* R18968 - ADCR_RETUNE_C13_1 */
+       [18969] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18969 - ADCR_RETUNE_C13_0 */
+       [18970] = { 0x00FF, 0x00FF, 0x0000 }, /* R18970 - ADCR_RETUNE_C14_1 */
+       [18971] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18971 - ADCR_RETUNE_C14_0 */
+       [18972] = { 0x00FF, 0x00FF, 0x0000 }, /* R18972 - ADCR_RETUNE_C15_1 */
+       [18973] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18973 - ADCR_RETUNE_C15_0 */
+       [18974] = { 0x00FF, 0x00FF, 0x0000 }, /* R18974 - ADCR_RETUNE_C16_1 */
+       [18975] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18975 - ADCR_RETUNE_C16_0 */
+       [18976] = { 0x00FF, 0x00FF, 0x0000 }, /* R18976 - ADCR_RETUNE_C17_1 */
+       [18977] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18977 - ADCR_RETUNE_C17_0 */
+       [18978] = { 0x00FF, 0x00FF, 0x0000 }, /* R18978 - ADCR_RETUNE_C18_1 */
+       [18979] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18979 - ADCR_RETUNE_C18_0 */
+       [18980] = { 0x00FF, 0x00FF, 0x0000 }, /* R18980 - ADCR_RETUNE_C19_1 */
+       [18981] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18981 - ADCR_RETUNE_C19_0 */
+       [18982] = { 0x00FF, 0x00FF, 0x0000 }, /* R18982 - ADCR_RETUNE_C20_1 */
+       [18983] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18983 - ADCR_RETUNE_C20_0 */
+       [18984] = { 0x00FF, 0x00FF, 0x0000 }, /* R18984 - ADCR_RETUNE_C21_1 */
+       [18985] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18985 - ADCR_RETUNE_C21_0 */
+       [18986] = { 0x00FF, 0x00FF, 0x0000 }, /* R18986 - ADCR_RETUNE_C22_1 */
+       [18987] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18987 - ADCR_RETUNE_C22_0 */
+       [18988] = { 0x00FF, 0x00FF, 0x0000 }, /* R18988 - ADCR_RETUNE_C23_1 */
+       [18989] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18989 - ADCR_RETUNE_C23_0 */
+       [18990] = { 0x00FF, 0x00FF, 0x0000 }, /* R18990 - ADCR_RETUNE_C24_1 */
+       [18991] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18991 - ADCR_RETUNE_C24_0 */
+       [18992] = { 0x00FF, 0x00FF, 0x0000 }, /* R18992 - ADCR_RETUNE_C25_1 */
+       [18993] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18993 - ADCR_RETUNE_C25_0 */
+       [18994] = { 0x00FF, 0x00FF, 0x0000 }, /* R18994 - ADCR_RETUNE_C26_1 */
+       [18995] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18995 - ADCR_RETUNE_C26_0 */
+       [18996] = { 0x00FF, 0x00FF, 0x0000 }, /* R18996 - ADCR_RETUNE_C27_1 */
+       [18997] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18997 - ADCR_RETUNE_C27_0 */
+       [18998] = { 0x00FF, 0x00FF, 0x0000 }, /* R18998 - ADCR_RETUNE_C28_1 */
+       [18999] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R18999 - ADCR_RETUNE_C28_0 */
+       [19000] = { 0x00FF, 0x00FF, 0x0000 }, /* R19000 - ADCR_RETUNE_C29_1 */
+       [19001] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19001 - ADCR_RETUNE_C29_0 */
+       [19002] = { 0x00FF, 0x00FF, 0x0000 }, /* R19002 - ADCR_RETUNE_C30_1 */
+       [19003] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19003 - ADCR_RETUNE_C30_0 */
+       [19004] = { 0x00FF, 0x00FF, 0x0000 }, /* R19004 - ADCR_RETUNE_C31_1 */
+       [19005] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19005 - ADCR_RETUNE_C31_0 */
+       [19006] = { 0x00FF, 0x00FF, 0x0000 }, /* R19006 - ADCR_RETUNE_C32_1 */
+       [19007] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19007 - ADCR_RETUNE_C32_0 */
+       [19456] = { 0x00FF, 0x00FF, 0x0000 }, /* R19456 - DACL_RETUNE_C1_1 */
+       [19457] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19457 - DACL_RETUNE_C1_0 */
+       [19458] = { 0x00FF, 0x00FF, 0x0000 }, /* R19458 - DACL_RETUNE_C2_1 */
+       [19459] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19459 - DACL_RETUNE_C2_0 */
+       [19460] = { 0x00FF, 0x00FF, 0x0000 }, /* R19460 - DACL_RETUNE_C3_1 */
+       [19461] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19461 - DACL_RETUNE_C3_0 */
+       [19462] = { 0x00FF, 0x00FF, 0x0000 }, /* R19462 - DACL_RETUNE_C4_1 */
+       [19463] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19463 - DACL_RETUNE_C4_0 */
+       [19464] = { 0x00FF, 0x00FF, 0x0000 }, /* R19464 - DACL_RETUNE_C5_1 */
+       [19465] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19465 - DACL_RETUNE_C5_0 */
+       [19466] = { 0x00FF, 0x00FF, 0x0000 }, /* R19466 - DACL_RETUNE_C6_1 */
+       [19467] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19467 - DACL_RETUNE_C6_0 */
+       [19468] = { 0x00FF, 0x00FF, 0x0000 }, /* R19468 - DACL_RETUNE_C7_1 */
+       [19469] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19469 - DACL_RETUNE_C7_0 */
+       [19470] = { 0x00FF, 0x00FF, 0x0000 }, /* R19470 - DACL_RETUNE_C8_1 */
+       [19471] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19471 - DACL_RETUNE_C8_0 */
+       [19472] = { 0x00FF, 0x00FF, 0x0000 }, /* R19472 - DACL_RETUNE_C9_1 */
+       [19473] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19473 - DACL_RETUNE_C9_0 */
+       [19474] = { 0x00FF, 0x00FF, 0x0000 }, /* R19474 - DACL_RETUNE_C10_1 */
+       [19475] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19475 - DACL_RETUNE_C10_0 */
+       [19476] = { 0x00FF, 0x00FF, 0x0000 }, /* R19476 - DACL_RETUNE_C11_1 */
+       [19477] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19477 - DACL_RETUNE_C11_0 */
+       [19478] = { 0x00FF, 0x00FF, 0x0000 }, /* R19478 - DACL_RETUNE_C12_1 */
+       [19479] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19479 - DACL_RETUNE_C12_0 */
+       [19480] = { 0x00FF, 0x00FF, 0x0000 }, /* R19480 - DACL_RETUNE_C13_1 */
+       [19481] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19481 - DACL_RETUNE_C13_0 */
+       [19482] = { 0x00FF, 0x00FF, 0x0000 }, /* R19482 - DACL_RETUNE_C14_1 */
+       [19483] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19483 - DACL_RETUNE_C14_0 */
+       [19484] = { 0x00FF, 0x00FF, 0x0000 }, /* R19484 - DACL_RETUNE_C15_1 */
+       [19485] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19485 - DACL_RETUNE_C15_0 */
+       [19486] = { 0x00FF, 0x00FF, 0x0000 }, /* R19486 - DACL_RETUNE_C16_1 */
+       [19487] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19487 - DACL_RETUNE_C16_0 */
+       [19488] = { 0x00FF, 0x00FF, 0x0000 }, /* R19488 - DACL_RETUNE_C17_1 */
+       [19489] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19489 - DACL_RETUNE_C17_0 */
+       [19490] = { 0x00FF, 0x00FF, 0x0000 }, /* R19490 - DACL_RETUNE_C18_1 */
+       [19491] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19491 - DACL_RETUNE_C18_0 */
+       [19492] = { 0x00FF, 0x00FF, 0x0000 }, /* R19492 - DACL_RETUNE_C19_1 */
+       [19493] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19493 - DACL_RETUNE_C19_0 */
+       [19494] = { 0x00FF, 0x00FF, 0x0000 }, /* R19494 - DACL_RETUNE_C20_1 */
+       [19495] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19495 - DACL_RETUNE_C20_0 */
+       [19496] = { 0x00FF, 0x00FF, 0x0000 }, /* R19496 - DACL_RETUNE_C21_1 */
+       [19497] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19497 - DACL_RETUNE_C21_0 */
+       [19498] = { 0x00FF, 0x00FF, 0x0000 }, /* R19498 - DACL_RETUNE_C22_1 */
+       [19499] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19499 - DACL_RETUNE_C22_0 */
+       [19500] = { 0x00FF, 0x00FF, 0x0000 }, /* R19500 - DACL_RETUNE_C23_1 */
+       [19501] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19501 - DACL_RETUNE_C23_0 */
+       [19502] = { 0x00FF, 0x00FF, 0x0000 }, /* R19502 - DACL_RETUNE_C24_1 */
+       [19503] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19503 - DACL_RETUNE_C24_0 */
+       [19504] = { 0x00FF, 0x00FF, 0x0000 }, /* R19504 - DACL_RETUNE_C25_1 */
+       [19505] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19505 - DACL_RETUNE_C25_0 */
+       [19506] = { 0x00FF, 0x00FF, 0x0000 }, /* R19506 - DACL_RETUNE_C26_1 */
+       [19507] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19507 - DACL_RETUNE_C26_0 */
+       [19508] = { 0x00FF, 0x00FF, 0x0000 }, /* R19508 - DACL_RETUNE_C27_1 */
+       [19509] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19509 - DACL_RETUNE_C27_0 */
+       [19510] = { 0x00FF, 0x00FF, 0x0000 }, /* R19510 - DACL_RETUNE_C28_1 */
+       [19511] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19511 - DACL_RETUNE_C28_0 */
+       [19512] = { 0x00FF, 0x00FF, 0x0000 }, /* R19512 - DACL_RETUNE_C29_1 */
+       [19513] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19513 - DACL_RETUNE_C29_0 */
+       [19514] = { 0x00FF, 0x00FF, 0x0000 }, /* R19514 - DACL_RETUNE_C30_1 */
+       [19515] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19515 - DACL_RETUNE_C30_0 */
+       [19516] = { 0x00FF, 0x00FF, 0x0000 }, /* R19516 - DACL_RETUNE_C31_1 */
+       [19517] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19517 - DACL_RETUNE_C31_0 */
+       [19518] = { 0x00FF, 0x00FF, 0x0000 }, /* R19518 - DACL_RETUNE_C32_1 */
+       [19519] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19519 - DACL_RETUNE_C32_0 */
+       [19968] = { 0x00FF, 0x00FF, 0x0000 }, /* R19968 - RETUNEDAC_PG2_1 */
+       [19969] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19969 - RETUNEDAC_PG2_0 */
+       [19970] = { 0x00FF, 0x00FF, 0x0000 }, /* R19970 - RETUNEDAC_PG_1 */
+       [19971] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R19971 - RETUNEDAC_PG_0 */
+       [20480] = { 0x00FF, 0x00FF, 0x0000 }, /* R20480 - DACR_RETUNE_C1_1 */
+       [20481] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20481 - DACR_RETUNE_C1_0 */
+       [20482] = { 0x00FF, 0x00FF, 0x0000 }, /* R20482 - DACR_RETUNE_C2_1 */
+       [20483] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20483 - DACR_RETUNE_C2_0 */
+       [20484] = { 0x00FF, 0x00FF, 0x0000 }, /* R20484 - DACR_RETUNE_C3_1 */
+       [20485] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20485 - DACR_RETUNE_C3_0 */
+       [20486] = { 0x00FF, 0x00FF, 0x0000 }, /* R20486 - DACR_RETUNE_C4_1 */
+       [20487] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20487 - DACR_RETUNE_C4_0 */
+       [20488] = { 0x00FF, 0x00FF, 0x0000 }, /* R20488 - DACR_RETUNE_C5_1 */
+       [20489] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20489 - DACR_RETUNE_C5_0 */
+       [20490] = { 0x00FF, 0x00FF, 0x0000 }, /* R20490 - DACR_RETUNE_C6_1 */
+       [20491] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20491 - DACR_RETUNE_C6_0 */
+       [20492] = { 0x00FF, 0x00FF, 0x0000 }, /* R20492 - DACR_RETUNE_C7_1 */
+       [20493] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20493 - DACR_RETUNE_C7_0 */
+       [20494] = { 0x00FF, 0x00FF, 0x0000 }, /* R20494 - DACR_RETUNE_C8_1 */
+       [20495] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20495 - DACR_RETUNE_C8_0 */
+       [20496] = { 0x00FF, 0x00FF, 0x0000 }, /* R20496 - DACR_RETUNE_C9_1 */
+       [20497] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20497 - DACR_RETUNE_C9_0 */
+       [20498] = { 0x00FF, 0x00FF, 0x0000 }, /* R20498 - DACR_RETUNE_C10_1 */
+       [20499] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20499 - DACR_RETUNE_C10_0 */
+       [20500] = { 0x00FF, 0x00FF, 0x0000 }, /* R20500 - DACR_RETUNE_C11_1 */
+       [20501] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20501 - DACR_RETUNE_C11_0 */
+       [20502] = { 0x00FF, 0x00FF, 0x0000 }, /* R20502 - DACR_RETUNE_C12_1 */
+       [20503] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20503 - DACR_RETUNE_C12_0 */
+       [20504] = { 0x00FF, 0x00FF, 0x0000 }, /* R20504 - DACR_RETUNE_C13_1 */
+       [20505] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20505 - DACR_RETUNE_C13_0 */
+       [20506] = { 0x00FF, 0x00FF, 0x0000 }, /* R20506 - DACR_RETUNE_C14_1 */
+       [20507] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20507 - DACR_RETUNE_C14_0 */
+       [20508] = { 0x00FF, 0x00FF, 0x0000 }, /* R20508 - DACR_RETUNE_C15_1 */
+       [20509] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20509 - DACR_RETUNE_C15_0 */
+       [20510] = { 0x00FF, 0x00FF, 0x0000 }, /* R20510 - DACR_RETUNE_C16_1 */
+       [20511] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20511 - DACR_RETUNE_C16_0 */
+       [20512] = { 0x00FF, 0x00FF, 0x0000 }, /* R20512 - DACR_RETUNE_C17_1 */
+       [20513] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20513 - DACR_RETUNE_C17_0 */
+       [20514] = { 0x00FF, 0x00FF, 0x0000 }, /* R20514 - DACR_RETUNE_C18_1 */
+       [20515] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20515 - DACR_RETUNE_C18_0 */
+       [20516] = { 0x00FF, 0x00FF, 0x0000 }, /* R20516 - DACR_RETUNE_C19_1 */
+       [20517] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20517 - DACR_RETUNE_C19_0 */
+       [20518] = { 0x00FF, 0x00FF, 0x0000 }, /* R20518 - DACR_RETUNE_C20_1 */
+       [20519] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20519 - DACR_RETUNE_C20_0 */
+       [20520] = { 0x00FF, 0x00FF, 0x0000 }, /* R20520 - DACR_RETUNE_C21_1 */
+       [20521] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20521 - DACR_RETUNE_C21_0 */
+       [20522] = { 0x00FF, 0x00FF, 0x0000 }, /* R20522 - DACR_RETUNE_C22_1 */
+       [20523] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20523 - DACR_RETUNE_C22_0 */
+       [20524] = { 0x00FF, 0x00FF, 0x0000 }, /* R20524 - DACR_RETUNE_C23_1 */
+       [20525] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20525 - DACR_RETUNE_C23_0 */
+       [20526] = { 0x00FF, 0x00FF, 0x0000 }, /* R20526 - DACR_RETUNE_C24_1 */
+       [20527] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20527 - DACR_RETUNE_C24_0 */
+       [20528] = { 0x00FF, 0x00FF, 0x0000 }, /* R20528 - DACR_RETUNE_C25_1 */
+       [20529] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20529 - DACR_RETUNE_C25_0 */
+       [20530] = { 0x00FF, 0x00FF, 0x0000 }, /* R20530 - DACR_RETUNE_C26_1 */
+       [20531] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20531 - DACR_RETUNE_C26_0 */
+       [20532] = { 0x00FF, 0x00FF, 0x0000 }, /* R20532 - DACR_RETUNE_C27_1 */
+       [20533] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20533 - DACR_RETUNE_C27_0 */
+       [20534] = { 0x00FF, 0x00FF, 0x0000 }, /* R20534 - DACR_RETUNE_C28_1 */
+       [20535] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20535 - DACR_RETUNE_C28_0 */
+       [20536] = { 0x00FF, 0x00FF, 0x0000 }, /* R20536 - DACR_RETUNE_C29_1 */
+       [20537] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20537 - DACR_RETUNE_C29_0 */
+       [20538] = { 0x00FF, 0x00FF, 0x0000 }, /* R20538 - DACR_RETUNE_C30_1 */
+       [20539] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20539 - DACR_RETUNE_C30_0 */
+       [20540] = { 0x00FF, 0x00FF, 0x0000 }, /* R20540 - DACR_RETUNE_C31_1 */
+       [20541] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20541 - DACR_RETUNE_C31_0 */
+       [20542] = { 0x00FF, 0x00FF, 0x0000 }, /* R20542 - DACR_RETUNE_C32_1 */
+       [20543] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20543 - DACR_RETUNE_C32_0 */
+       [20992] = { 0x00FF, 0x00FF, 0x0000 }, /* R20992 - VSS_XHD2_1 */
+       [20993] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20993 - VSS_XHD2_0 */
+       [20994] = { 0x00FF, 0x00FF, 0x0000 }, /* R20994 - VSS_XHD3_1 */
+       [20995] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20995 - VSS_XHD3_0 */
+       [20996] = { 0x00FF, 0x00FF, 0x0000 }, /* R20996 - VSS_XHN1_1 */
+       [20997] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20997 - VSS_XHN1_0 */
+       [20998] = { 0x00FF, 0x00FF, 0x0000 }, /* R20998 - VSS_XHN2_1 */
+       [20999] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R20999 - VSS_XHN2_0 */
+       [21000] = { 0x00FF, 0x00FF, 0x0000 }, /* R21000 - VSS_XHN3_1 */
+       [21001] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21001 - VSS_XHN3_0 */
+       [21002] = { 0x00FF, 0x00FF, 0x0000 }, /* R21002 - VSS_XLA_1 */
+       [21003] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21003 - VSS_XLA_0 */
+       [21004] = { 0x00FF, 0x00FF, 0x0000 }, /* R21004 - VSS_XLB_1 */
+       [21005] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21005 - VSS_XLB_0 */
+       [21006] = { 0x00FF, 0x00FF, 0x0000 }, /* R21006 - VSS_XLG_1 */
+       [21007] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21007 - VSS_XLG_0 */
+       [21008] = { 0x00FF, 0x00FF, 0x0000 }, /* R21008 - VSS_PG2_1 */
+       [21009] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21009 - VSS_PG2_0 */
+       [21010] = { 0x00FF, 0x00FF, 0x0000 }, /* R21010 - VSS_PG_1 */
+       [21011] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21011 - VSS_PG_0 */
+       [21012] = { 0x00FF, 0x00FF, 0x0000 }, /* R21012 - VSS_XTD1_1 */
+       [21013] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21013 - VSS_XTD1_0 */
+       [21014] = { 0x00FF, 0x00FF, 0x0000 }, /* R21014 - VSS_XTD2_1 */
+       [21015] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21015 - VSS_XTD2_0 */
+       [21016] = { 0x00FF, 0x00FF, 0x0000 }, /* R21016 - VSS_XTD3_1 */
+       [21017] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21017 - VSS_XTD3_0 */
+       [21018] = { 0x00FF, 0x00FF, 0x0000 }, /* R21018 - VSS_XTD4_1 */
+       [21019] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21019 - VSS_XTD4_0 */
+       [21020] = { 0x00FF, 0x00FF, 0x0000 }, /* R21020 - VSS_XTD5_1 */
+       [21021] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21021 - VSS_XTD5_0 */
+       [21022] = { 0x00FF, 0x00FF, 0x0000 }, /* R21022 - VSS_XTD6_1 */
+       [21023] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21023 - VSS_XTD6_0 */
+       [21024] = { 0x00FF, 0x00FF, 0x0000 }, /* R21024 - VSS_XTD7_1 */
+       [21025] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21025 - VSS_XTD7_0 */
+       [21026] = { 0x00FF, 0x00FF, 0x0000 }, /* R21026 - VSS_XTD8_1 */
+       [21027] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21027 - VSS_XTD8_0 */
+       [21028] = { 0x00FF, 0x00FF, 0x0000 }, /* R21028 - VSS_XTD9_1 */
+       [21029] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21029 - VSS_XTD9_0 */
+       [21030] = { 0x00FF, 0x00FF, 0x0000 }, /* R21030 - VSS_XTD10_1 */
+       [21031] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21031 - VSS_XTD10_0 */
+       [21032] = { 0x00FF, 0x00FF, 0x0000 }, /* R21032 - VSS_XTD11_1 */
+       [21033] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21033 - VSS_XTD11_0 */
+       [21034] = { 0x00FF, 0x00FF, 0x0000 }, /* R21034 - VSS_XTD12_1 */
+       [21035] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21035 - VSS_XTD12_0 */
+       [21036] = { 0x00FF, 0x00FF, 0x0000 }, /* R21036 - VSS_XTD13_1 */
+       [21037] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21037 - VSS_XTD13_0 */
+       [21038] = { 0x00FF, 0x00FF, 0x0000 }, /* R21038 - VSS_XTD14_1 */
+       [21039] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21039 - VSS_XTD14_0 */
+       [21040] = { 0x00FF, 0x00FF, 0x0000 }, /* R21040 - VSS_XTD15_1 */
+       [21041] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21041 - VSS_XTD15_0 */
+       [21042] = { 0x00FF, 0x00FF, 0x0000 }, /* R21042 - VSS_XTD16_1 */
+       [21043] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21043 - VSS_XTD16_0 */
+       [21044] = { 0x00FF, 0x00FF, 0x0000 }, /* R21044 - VSS_XTD17_1 */
+       [21045] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21045 - VSS_XTD17_0 */
+       [21046] = { 0x00FF, 0x00FF, 0x0000 }, /* R21046 - VSS_XTD18_1 */
+       [21047] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21047 - VSS_XTD18_0 */
+       [21048] = { 0x00FF, 0x00FF, 0x0000 }, /* R21048 - VSS_XTD19_1 */
+       [21049] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21049 - VSS_XTD19_0 */
+       [21050] = { 0x00FF, 0x00FF, 0x0000 }, /* R21050 - VSS_XTD20_1 */
+       [21051] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21051 - VSS_XTD20_0 */
+       [21052] = { 0x00FF, 0x00FF, 0x0000 }, /* R21052 - VSS_XTD21_1 */
+       [21053] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21053 - VSS_XTD21_0 */
+       [21054] = { 0x00FF, 0x00FF, 0x0000 }, /* R21054 - VSS_XTD22_1 */
+       [21055] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21055 - VSS_XTD22_0 */
+       [21056] = { 0x00FF, 0x00FF, 0x0000 }, /* R21056 - VSS_XTD23_1 */
+       [21057] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21057 - VSS_XTD23_0 */
+       [21058] = { 0x00FF, 0x00FF, 0x0000 }, /* R21058 - VSS_XTD24_1 */
+       [21059] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21059 - VSS_XTD24_0 */
+       [21060] = { 0x00FF, 0x00FF, 0x0000 }, /* R21060 - VSS_XTD25_1 */
+       [21061] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21061 - VSS_XTD25_0 */
+       [21062] = { 0x00FF, 0x00FF, 0x0000 }, /* R21062 - VSS_XTD26_1 */
+       [21063] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21063 - VSS_XTD26_0 */
+       [21064] = { 0x00FF, 0x00FF, 0x0000 }, /* R21064 - VSS_XTD27_1 */
+       [21065] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21065 - VSS_XTD27_0 */
+       [21066] = { 0x00FF, 0x00FF, 0x0000 }, /* R21066 - VSS_XTD28_1 */
+       [21067] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21067 - VSS_XTD28_0 */
+       [21068] = { 0x00FF, 0x00FF, 0x0000 }, /* R21068 - VSS_XTD29_1 */
+       [21069] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21069 - VSS_XTD29_0 */
+       [21070] = { 0x00FF, 0x00FF, 0x0000 }, /* R21070 - VSS_XTD30_1 */
+       [21071] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21071 - VSS_XTD30_0 */
+       [21072] = { 0x00FF, 0x00FF, 0x0000 }, /* R21072 - VSS_XTD31_1 */
+       [21073] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21073 - VSS_XTD31_0 */
+       [21074] = { 0x00FF, 0x00FF, 0x0000 }, /* R21074 - VSS_XTD32_1 */
+       [21075] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21075 - VSS_XTD32_0 */
+       [21076] = { 0x00FF, 0x00FF, 0x0000 }, /* R21076 - VSS_XTS1_1 */
+       [21077] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21077 - VSS_XTS1_0 */
+       [21078] = { 0x00FF, 0x00FF, 0x0000 }, /* R21078 - VSS_XTS2_1 */
+       [21079] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21079 - VSS_XTS2_0 */
+       [21080] = { 0x00FF, 0x00FF, 0x0000 }, /* R21080 - VSS_XTS3_1 */
+       [21081] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21081 - VSS_XTS3_0 */
+       [21082] = { 0x00FF, 0x00FF, 0x0000 }, /* R21082 - VSS_XTS4_1 */
+       [21083] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21083 - VSS_XTS4_0 */
+       [21084] = { 0x00FF, 0x00FF, 0x0000 }, /* R21084 - VSS_XTS5_1 */
+       [21085] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21085 - VSS_XTS5_0 */
+       [21086] = { 0x00FF, 0x00FF, 0x0000 }, /* R21086 - VSS_XTS6_1 */
+       [21087] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21087 - VSS_XTS6_0 */
+       [21088] = { 0x00FF, 0x00FF, 0x0000 }, /* R21088 - VSS_XTS7_1 */
+       [21089] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21089 - VSS_XTS7_0 */
+       [21090] = { 0x00FF, 0x00FF, 0x0000 }, /* R21090 - VSS_XTS8_1 */
+       [21091] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21091 - VSS_XTS8_0 */
+       [21092] = { 0x00FF, 0x00FF, 0x0000 }, /* R21092 - VSS_XTS9_1 */
+       [21093] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21093 - VSS_XTS9_0 */
+       [21094] = { 0x00FF, 0x00FF, 0x0000 }, /* R21094 - VSS_XTS10_1 */
+       [21095] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21095 - VSS_XTS10_0 */
+       [21096] = { 0x00FF, 0x00FF, 0x0000 }, /* R21096 - VSS_XTS11_1 */
+       [21097] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21097 - VSS_XTS11_0 */
+       [21098] = { 0x00FF, 0x00FF, 0x0000 }, /* R21098 - VSS_XTS12_1 */
+       [21099] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21099 - VSS_XTS12_0 */
+       [21100] = { 0x00FF, 0x00FF, 0x0000 }, /* R21100 - VSS_XTS13_1 */
+       [21101] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21101 - VSS_XTS13_0 */
+       [21102] = { 0x00FF, 0x00FF, 0x0000 }, /* R21102 - VSS_XTS14_1 */
+       [21103] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21103 - VSS_XTS14_0 */
+       [21104] = { 0x00FF, 0x00FF, 0x0000 }, /* R21104 - VSS_XTS15_1 */
+       [21105] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21105 - VSS_XTS15_0 */
+       [21106] = { 0x00FF, 0x00FF, 0x0000 }, /* R21106 - VSS_XTS16_1 */
+       [21107] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21107 - VSS_XTS16_0 */
+       [21108] = { 0x00FF, 0x00FF, 0x0000 }, /* R21108 - VSS_XTS17_1 */
+       [21109] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21109 - VSS_XTS17_0 */
+       [21110] = { 0x00FF, 0x00FF, 0x0000 }, /* R21110 - VSS_XTS18_1 */
+       [21111] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21111 - VSS_XTS18_0 */
+       [21112] = { 0x00FF, 0x00FF, 0x0000 }, /* R21112 - VSS_XTS19_1 */
+       [21113] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21113 - VSS_XTS19_0 */
+       [21114] = { 0x00FF, 0x00FF, 0x0000 }, /* R21114 - VSS_XTS20_1 */
+       [21115] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21115 - VSS_XTS20_0 */
+       [21116] = { 0x00FF, 0x00FF, 0x0000 }, /* R21116 - VSS_XTS21_1 */
+       [21117] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21117 - VSS_XTS21_0 */
+       [21118] = { 0x00FF, 0x00FF, 0x0000 }, /* R21118 - VSS_XTS22_1 */
+       [21119] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21119 - VSS_XTS22_0 */
+       [21120] = { 0x00FF, 0x00FF, 0x0000 }, /* R21120 - VSS_XTS23_1 */
+       [21121] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21121 - VSS_XTS23_0 */
+       [21122] = { 0x00FF, 0x00FF, 0x0000 }, /* R21122 - VSS_XTS24_1 */
+       [21123] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21123 - VSS_XTS24_0 */
+       [21124] = { 0x00FF, 0x00FF, 0x0000 }, /* R21124 - VSS_XTS25_1 */
+       [21125] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21125 - VSS_XTS25_0 */
+       [21126] = { 0x00FF, 0x00FF, 0x0000 }, /* R21126 - VSS_XTS26_1 */
+       [21127] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21127 - VSS_XTS26_0 */
+       [21128] = { 0x00FF, 0x00FF, 0x0000 }, /* R21128 - VSS_XTS27_1 */
+       [21129] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21129 - VSS_XTS27_0 */
+       [21130] = { 0x00FF, 0x00FF, 0x0000 }, /* R21130 - VSS_XTS28_1 */
+       [21131] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21131 - VSS_XTS28_0 */
+       [21132] = { 0x00FF, 0x00FF, 0x0000 }, /* R21132 - VSS_XTS29_1 */
+       [21133] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21133 - VSS_XTS29_0 */
+       [21134] = { 0x00FF, 0x00FF, 0x0000 }, /* R21134 - VSS_XTS30_1 */
+       [21135] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21135 - VSS_XTS30_0 */
+       [21136] = { 0x00FF, 0x00FF, 0x0000 }, /* R21136 - VSS_XTS31_1 */
+       [21137] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21137 - VSS_XTS31_0 */
+       [21138] = { 0x00FF, 0x00FF, 0x0000 }, /* R21138 - VSS_XTS32_1 */
+       [21139] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21139 - VSS_XTS32_0 */
+};
+
+static int wm8962_volatile_register(unsigned int reg)
+{
+       if (wm8962_reg_access[reg].vol)
+               return 1;
+       else
+               return 0;
+}
+
+static int wm8962_readable_register(unsigned int reg)
+{
+       if (wm8962_reg_access[reg].read)
+               return 1;
+       else
+               return 0;
+}
+
+static int wm8962_reset(struct snd_soc_codec *codec)
+{
+       return snd_soc_write(codec, WM8962_SOFTWARE_RESET, 0);
+}
+
+static const DECLARE_TLV_DB_SCALE(inpga_tlv, -2325, 75, 0);
+static const DECLARE_TLV_DB_SCALE(mixin_tlv, -1500, 300, 0);
+static const unsigned int mixinpga_tlv[] = {
+       TLV_DB_RANGE_HEAD(7),
+       0, 1, TLV_DB_SCALE_ITEM(0, 600, 0),
+       2, 2, TLV_DB_SCALE_ITEM(1300, 1300, 0),
+       3, 4, TLV_DB_SCALE_ITEM(1800, 200, 0),
+       5, 5, TLV_DB_SCALE_ITEM(2400, 0, 0),
+       6, 7, TLV_DB_SCALE_ITEM(2700, 300, 0),
+};
+static const DECLARE_TLV_DB_SCALE(beep_tlv, -9600, 600, 1);
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(st_tlv, -3600, 300, 0);
+static const DECLARE_TLV_DB_SCALE(inmix_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+static const DECLARE_TLV_DB_SCALE(hp_tlv, -700, 100, 0);
+static const unsigned int classd_tlv[] = {
+       TLV_DB_RANGE_HEAD(7),
+       0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
+       7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0),
+};
+
+/* The VU bits for the headphones are in a different register to the mute
+ * bits and only take effect on the PGA if it is actually powered.
+ */
+static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       u16 *reg_cache = wm8962->reg_cache;
+       int ret;
+
+       /* Apply the update (if any) */
+        ret = snd_soc_put_volsw(kcontrol, ucontrol);
+       if (ret == 0)
+               return 0;
+
+       /* If the left PGA is enabled hit that VU bit... */
+       if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_HPOUTL_PGA_ENA)
+               return snd_soc_write(codec, WM8962_HPOUTL_VOLUME,
+                                    reg_cache[WM8962_HPOUTL_VOLUME]);
+
+       /* ...otherwise the right.  The VU is stereo. */
+       if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_HPOUTR_PGA_ENA)
+               return snd_soc_write(codec, WM8962_HPOUTR_VOLUME,
+                                    reg_cache[WM8962_HPOUTR_VOLUME]);
+
+       return 0;
+}
+
+/* The VU bits for the speakers are in a different register to the mute
+ * bits and only take effect on the PGA if it is actually powered.
+ */
+static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       u16 *reg_cache = wm8962->reg_cache;
+       int ret;
+
+       /* Apply the update (if any) */
+        ret = snd_soc_put_volsw(kcontrol, ucontrol);
+       if (ret == 0)
+               return 0;
+
+       /* If the left PGA is enabled hit that VU bit... */
+       if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTL_PGA_ENA)
+               return snd_soc_write(codec, WM8962_SPKOUTL_VOLUME,
+                                    reg_cache[WM8962_SPKOUTL_VOLUME]);
+
+       /* ...otherwise the right.  The VU is stereo. */
+       if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTR_PGA_ENA)
+               return snd_soc_write(codec, WM8962_SPKOUTR_VOLUME,
+                                    reg_cache[WM8962_SPKOUTR_VOLUME]);
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new wm8962_snd_controls[] = {
+SOC_DOUBLE("Input Mixer Switch", WM8962_INPUT_MIXER_CONTROL_1, 3, 2, 1, 1),
+
+SOC_SINGLE_TLV("MIXINL IN2L Volume", WM8962_LEFT_INPUT_MIXER_VOLUME, 6, 7, 0,
+              mixin_tlv),
+SOC_SINGLE_TLV("MIXINL PGA Volume", WM8962_LEFT_INPUT_MIXER_VOLUME, 3, 7, 0,
+              mixinpga_tlv),
+SOC_SINGLE_TLV("MIXINL IN3L Volume", WM8962_LEFT_INPUT_MIXER_VOLUME, 0, 7, 0,
+              mixin_tlv),
+
+SOC_SINGLE_TLV("MIXINR IN2R Volume", WM8962_RIGHT_INPUT_MIXER_VOLUME, 6, 7, 0,
+              mixin_tlv),
+SOC_SINGLE_TLV("MIXINR PGA Volume", WM8962_RIGHT_INPUT_MIXER_VOLUME, 3, 7, 0,
+              mixinpga_tlv),
+SOC_SINGLE_TLV("MIXINR IN3R Volume", WM8962_RIGHT_INPUT_MIXER_VOLUME, 0, 7, 0,
+              mixin_tlv),
+
+SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8962_LEFT_ADC_VOLUME,
+                WM8962_RIGHT_ADC_VOLUME, 1, 127, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("Capture Volume", WM8962_LEFT_INPUT_VOLUME,
+                WM8962_RIGHT_INPUT_VOLUME, 0, 63, 0, inpga_tlv),
+SOC_DOUBLE_R("Capture Switch", WM8962_LEFT_INPUT_VOLUME,
+            WM8962_RIGHT_INPUT_VOLUME, 7, 1, 1),
+SOC_DOUBLE_R("Capture ZC Switch", WM8962_LEFT_INPUT_VOLUME,
+            WM8962_RIGHT_INPUT_VOLUME, 6, 1, 1),
+
+SOC_DOUBLE_R_TLV("Sidetone Volume", WM8962_DAC_DSP_MIXING_1,
+                WM8962_DAC_DSP_MIXING_2, 4, 12, 0, st_tlv),
+
+SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8962_LEFT_DAC_VOLUME,
+                WM8962_RIGHT_DAC_VOLUME, 1, 127, 0, digital_tlv),
+SOC_SINGLE("DAC High Performance Switch", WM8962_ADC_DAC_CONTROL_2, 0, 1, 0),
+
+SOC_SINGLE("ADC High Performance Switch", WM8962_ADDITIONAL_CONTROL_1,
+          5, 1, 0),
+
+SOC_SINGLE_TLV("Beep Volume", WM8962_BEEP_GENERATOR_1, 4, 15, 0, beep_tlv),
+
+SOC_DOUBLE_R_TLV("Headphone Volume", WM8962_HPOUTL_VOLUME,
+                WM8962_HPOUTR_VOLUME, 0, 127, 0, out_tlv),
+SOC_DOUBLE_EXT("Headphone Switch", WM8962_PWR_MGMT_2, 1, 0, 1, 1,
+              snd_soc_get_volsw, wm8962_put_hp_sw),
+SOC_DOUBLE_R("Headphone ZC Switch", WM8962_HPOUTL_VOLUME, WM8962_HPOUTR_VOLUME,
+            7, 1, 0),
+SOC_DOUBLE_TLV("Headphone Aux Volume", WM8962_ANALOGUE_HP_2, 3, 6, 7, 0,
+              hp_tlv),
+
+SOC_DOUBLE_R("Headphone Mixer Switch", WM8962_HEADPHONE_MIXER_3,
+            WM8962_HEADPHONE_MIXER_4, 8, 1, 1),
+
+SOC_SINGLE_TLV("HPMIXL IN4L Volume", WM8962_HEADPHONE_MIXER_3,
+              3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("HPMIXL IN4R Volume", WM8962_HEADPHONE_MIXER_3,
+              0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("HPMIXL MIXINL Volume", WM8962_HEADPHONE_MIXER_3,
+              7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("HPMIXL MIXINR Volume", WM8962_HEADPHONE_MIXER_3,
+              6, 1, 1, inmix_tlv),
+
+SOC_SINGLE_TLV("HPMIXR IN4L Volume", WM8962_HEADPHONE_MIXER_4,
+              3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("HPMIXR IN4R Volume", WM8962_HEADPHONE_MIXER_4,
+              0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("HPMIXR MIXINL Volume", WM8962_HEADPHONE_MIXER_4,
+              7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("HPMIXR MIXINR Volume", WM8962_HEADPHONE_MIXER_4,
+              6, 1, 1, inmix_tlv),
+
+SOC_SINGLE_TLV("Speaker Boost Volume", WM8962_CLASS_D_CONTROL_2, 0, 7, 0,
+              classd_tlv),
+};
+
+static const struct snd_kcontrol_new wm8962_spk_mono_controls[] = {
+SOC_SINGLE_TLV("Speaker Volume", WM8962_SPKOUTL_VOLUME, 0, 127, 0, out_tlv),
+SOC_SINGLE_EXT("Speaker Switch", WM8962_CLASS_D_CONTROL_1, 1, 1, 1,
+              snd_soc_get_volsw, wm8962_put_spk_sw),
+SOC_SINGLE("Speaker ZC Switch", WM8962_SPKOUTL_VOLUME, 7, 1, 0),
+
+SOC_SINGLE("Speaker Mixer Switch", WM8962_SPEAKER_MIXER_3, 8, 1, 1),
+SOC_SINGLE_TLV("Speaker Mixer IN4L Volume", WM8962_SPEAKER_MIXER_3,
+              3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("Speaker Mixer IN4R Volume", WM8962_SPEAKER_MIXER_3,
+              0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("Speaker Mixer MIXINL Volume", WM8962_SPEAKER_MIXER_3,
+              7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("Speaker Mixer MIXINR Volume", WM8962_SPEAKER_MIXER_3,
+              6, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("Speaker Mixer DACL Volume", WM8962_SPEAKER_MIXER_5,
+              7, 1, 0, inmix_tlv),
+SOC_SINGLE_TLV("Speaker Mixer DACR Volume", WM8962_SPEAKER_MIXER_5,
+              6, 1, 0, inmix_tlv),
+};
+
+static const struct snd_kcontrol_new wm8962_spk_stereo_controls[] = {
+SOC_DOUBLE_R_TLV("Speaker Volume", WM8962_SPKOUTL_VOLUME,
+                WM8962_SPKOUTR_VOLUME, 0, 127, 0, out_tlv),
+SOC_DOUBLE_EXT("Speaker Switch", WM8962_CLASS_D_CONTROL_1, 1, 0, 1, 1,
+              snd_soc_get_volsw, wm8962_put_spk_sw),
+SOC_DOUBLE_R("Speaker ZC Switch", WM8962_SPKOUTL_VOLUME, WM8962_SPKOUTR_VOLUME,
+            7, 1, 0),
+
+SOC_DOUBLE_R("Speaker Mixer Switch", WM8962_SPEAKER_MIXER_3,
+            WM8962_SPEAKER_MIXER_4, 8, 1, 1),
+
+SOC_SINGLE_TLV("SPKOUTL Mixer IN4L Volume", WM8962_SPEAKER_MIXER_3,
+              3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer IN4R Volume", WM8962_SPEAKER_MIXER_3,
+              0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer MIXINL Volume", WM8962_SPEAKER_MIXER_3,
+              7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer MIXINR Volume", WM8962_SPEAKER_MIXER_3,
+              6, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer DACL Volume", WM8962_SPEAKER_MIXER_5,
+              7, 1, 0, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTL Mixer DACR Volume", WM8962_SPEAKER_MIXER_5,
+              6, 1, 0, inmix_tlv),
+
+SOC_SINGLE_TLV("SPKOUTR Mixer IN4L Volume", WM8962_SPEAKER_MIXER_4,
+              3, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer IN4R Volume", WM8962_SPEAKER_MIXER_4,
+              0, 7, 0, bypass_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer MIXINL Volume", WM8962_SPEAKER_MIXER_4,
+              7, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer MIXINR Volume", WM8962_SPEAKER_MIXER_4,
+              6, 1, 1, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer DACL Volume", WM8962_SPEAKER_MIXER_5,
+              5, 1, 0, inmix_tlv),
+SOC_SINGLE_TLV("SPKOUTR Mixer DACR Volume", WM8962_SPEAKER_MIXER_5,
+              4, 1, 0, inmix_tlv),
+};
+
+static int sysclk_event(struct snd_soc_dapm_widget *w,
+                       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       int src;
+       int fll;
+
+       src = snd_soc_read(codec, WM8962_CLOCKING2) & WM8962_SYSCLK_SRC_MASK;
+
+       switch (src) {
+       case 0:      /* MCLK */
+               fll = 0;
+               break;
+       case 0x200:  /* FLL */
+               fll = 1;
+               break;
+       default:
+               dev_err(codec->dev, "Unknown SYSCLK source %x\n", src);
+               return -EINVAL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (fll)
+                       snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+                                           WM8962_FLL_ENA, WM8962_FLL_ENA);
+               break;
+
+       case SND_SOC_DAPM_POST_PMD:
+               if (fll)
+                       snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+                                           WM8962_FLL_ENA, 0);
+               break;
+
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int cp_event(struct snd_soc_dapm_widget *w,
+                   struct snd_kcontrol *kcontrol, int event)
+{
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               msleep(5);
+               break;
+
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int hp_event(struct snd_soc_dapm_widget *w,
+                   struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       int timeout;
+       int reg;
+       int expected = (WM8962_DCS_STARTUP_DONE_HP1L |
+                       WM8962_DCS_STARTUP_DONE_HP1R);
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+                                   WM8962_HP1L_ENA | WM8962_HP1R_ENA,
+                                   WM8962_HP1L_ENA | WM8962_HP1R_ENA);
+               udelay(20);
+
+               snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+                                   WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY,
+                                   WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY);
+
+               /* Start the DC servo */
+               snd_soc_update_bits(codec, WM8962_DC_SERVO_1,
+                                   WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA |
+                                   WM8962_HP1L_DCS_STARTUP |
+                                   WM8962_HP1R_DCS_STARTUP,
+                                   WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA |
+                                   WM8962_HP1L_DCS_STARTUP |
+                                   WM8962_HP1R_DCS_STARTUP);
+
+               /* Wait for it to complete, should be well under 100ms */
+               timeout = 0;
+               do {
+                       msleep(1);
+                       reg = snd_soc_read(codec, WM8962_DC_SERVO_6);
+                       if (reg < 0) {
+                               dev_err(codec->dev,
+                                       "Failed to read DCS status: %d\n",
+                                       reg);
+                               continue;
+                       }
+                       dev_dbg(codec->dev, "DCS status: %x\n", reg);
+               } while (++timeout < 200 && (reg & expected) != expected);
+
+               if ((reg & expected) != expected)
+                       dev_err(codec->dev, "DC servo timed out\n");
+               else
+                       dev_dbg(codec->dev, "DC servo complete after %dms\n",
+                               timeout);
+
+               snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+                                   WM8962_HP1L_ENA_OUTP |
+                                   WM8962_HP1R_ENA_OUTP,
+                                   WM8962_HP1L_ENA_OUTP |
+                                   WM8962_HP1R_ENA_OUTP);
+               udelay(20);
+
+               snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+                                   WM8962_HP1L_RMV_SHORT |
+                                   WM8962_HP1R_RMV_SHORT,
+                                   WM8962_HP1L_RMV_SHORT |
+                                   WM8962_HP1R_RMV_SHORT);
+               break;
+
+       case SND_SOC_DAPM_PRE_PMD:
+               snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+                                   WM8962_HP1L_RMV_SHORT |
+                                   WM8962_HP1R_RMV_SHORT, 0);
+
+               udelay(20);
+
+               snd_soc_update_bits(codec, WM8962_DC_SERVO_1,
+                                   WM8962_HP1L_DCS_ENA | WM8962_HP1R_DCS_ENA |
+                                   WM8962_HP1L_DCS_STARTUP |
+                                   WM8962_HP1R_DCS_STARTUP,
+                                   0);
+
+               snd_soc_update_bits(codec, WM8962_ANALOGUE_HP_0,
+                                   WM8962_HP1L_ENA | WM8962_HP1R_ENA |
+                                   WM8962_HP1L_ENA_DLY | WM8962_HP1R_ENA_DLY |
+                                   WM8962_HP1L_ENA_OUTP |
+                                   WM8962_HP1R_ENA_OUTP, 0);
+                                   
+               break;
+
+       default:
+               BUG();
+               return -EINVAL;
+       
+       }
+
+       return 0;
+}
+
+/* VU bits for the output PGAs only take effect while the PGA is powered */
+static int out_pga_event(struct snd_soc_dapm_widget *w,
+                        struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       u16 *reg_cache = wm8962->reg_cache;
+       int reg;
+
+       switch (w->shift) {
+       case WM8962_HPOUTR_PGA_ENA_SHIFT:
+               reg = WM8962_HPOUTR_VOLUME;
+               break;
+       case WM8962_HPOUTL_PGA_ENA_SHIFT:
+               reg = WM8962_HPOUTL_VOLUME;
+               break;
+       case WM8962_SPKOUTR_PGA_ENA_SHIFT:
+               reg = WM8962_SPKOUTR_VOLUME;
+               break;
+       case WM8962_SPKOUTL_PGA_ENA_SHIFT:
+               reg = WM8962_SPKOUTL_VOLUME;
+               break;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               return snd_soc_write(codec, reg, reg_cache[reg]);
+       default:
+               BUG();
+               return -EINVAL;
+       }
+}
+
+static const char *st_text[] = { "None", "Right", "Left" };
+
+static const struct soc_enum str_enum =
+       SOC_ENUM_SINGLE(WM8962_DAC_DSP_MIXING_1, 2, 3, st_text);
+
+static const struct snd_kcontrol_new str_mux =
+       SOC_DAPM_ENUM("Right Sidetone", str_enum);
+
+static const struct soc_enum stl_enum =
+       SOC_ENUM_SINGLE(WM8962_DAC_DSP_MIXING_2, 2, 3, st_text);
+
+static const struct snd_kcontrol_new stl_mux =
+       SOC_DAPM_ENUM("Left Sidetone", stl_enum);
+
+static const char *outmux_text[] = { "DAC", "Mixer" };
+
+static const struct soc_enum spkoutr_enum =
+       SOC_ENUM_SINGLE(WM8962_SPEAKER_MIXER_2, 7, 2, outmux_text);
+
+static const struct snd_kcontrol_new spkoutr_mux =
+       SOC_DAPM_ENUM("SPKOUTR Mux", spkoutr_enum);
+
+static const struct soc_enum spkoutl_enum =
+       SOC_ENUM_SINGLE(WM8962_SPEAKER_MIXER_1, 7, 2, outmux_text);
+
+static const struct snd_kcontrol_new spkoutl_mux =
+       SOC_DAPM_ENUM("SPKOUTL Mux", spkoutl_enum);
+
+static const struct soc_enum hpoutr_enum =
+       SOC_ENUM_SINGLE(WM8962_HEADPHONE_MIXER_2, 7, 2, outmux_text);
+
+static const struct snd_kcontrol_new hpoutr_mux =
+       SOC_DAPM_ENUM("HPOUTR Mux", hpoutr_enum);
+
+static const struct soc_enum hpoutl_enum =
+       SOC_ENUM_SINGLE(WM8962_HEADPHONE_MIXER_1, 7, 2, outmux_text);
+
+static const struct snd_kcontrol_new hpoutl_mux =
+       SOC_DAPM_ENUM("HPOUTL Mux", hpoutl_enum);
+
+static const struct snd_kcontrol_new inpgal[] = {
+SOC_DAPM_SINGLE("IN1L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 3, 1, 0),
+SOC_DAPM_SINGLE("IN2L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 2, 1, 0),
+SOC_DAPM_SINGLE("IN3L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_LEFT_INPUT_PGA_CONTROL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new inpgar[] = {
+SOC_DAPM_SINGLE("IN1R Switch", WM8962_RIGHT_INPUT_PGA_CONTROL, 3, 1, 0),
+SOC_DAPM_SINGLE("IN2R Switch", WM8962_RIGHT_INPUT_PGA_CONTROL, 2, 1, 0),
+SOC_DAPM_SINGLE("IN3R Switch", WM8962_RIGHT_INPUT_PGA_CONTROL, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_RIGHT_INPUT_PGA_CONTROL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new mixinl[] = {
+SOC_DAPM_SINGLE("IN2L Switch", WM8962_INPUT_MIXER_CONTROL_2, 5, 1, 0),
+SOC_DAPM_SINGLE("IN3L Switch", WM8962_INPUT_MIXER_CONTROL_2, 4, 1, 0),
+SOC_DAPM_SINGLE("PGA Switch", WM8962_INPUT_MIXER_CONTROL_2, 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new mixinr[] = {
+SOC_DAPM_SINGLE("IN2R Switch", WM8962_INPUT_MIXER_CONTROL_2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN3R Switch", WM8962_INPUT_MIXER_CONTROL_2, 1, 1, 0),
+SOC_DAPM_SINGLE("PGA Switch", WM8962_INPUT_MIXER_CONTROL_2, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new hpmixl[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8962_HEADPHONE_MIXER_1, 5, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8962_HEADPHONE_MIXER_1, 4, 1, 0),
+SOC_DAPM_SINGLE("MIXINL Switch", WM8962_HEADPHONE_MIXER_1, 3, 1, 0),
+SOC_DAPM_SINGLE("MIXINR Switch", WM8962_HEADPHONE_MIXER_1, 2, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_HEADPHONE_MIXER_1, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_HEADPHONE_MIXER_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new hpmixr[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8962_HEADPHONE_MIXER_2, 5, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8962_HEADPHONE_MIXER_2, 4, 1, 0),
+SOC_DAPM_SINGLE("MIXINL Switch", WM8962_HEADPHONE_MIXER_2, 3, 1, 0),
+SOC_DAPM_SINGLE("MIXINR Switch", WM8962_HEADPHONE_MIXER_2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_HEADPHONE_MIXER_2, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_HEADPHONE_MIXER_2, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new spkmixl[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8962_SPEAKER_MIXER_1, 5, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8962_SPEAKER_MIXER_1, 4, 1, 0),
+SOC_DAPM_SINGLE("MIXINL Switch", WM8962_SPEAKER_MIXER_1, 3, 1, 0),
+SOC_DAPM_SINGLE("MIXINR Switch", WM8962_SPEAKER_MIXER_1, 2, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_SPEAKER_MIXER_1, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_SPEAKER_MIXER_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new spkmixr[] = {
+SOC_DAPM_SINGLE("DACL Switch", WM8962_SPEAKER_MIXER_2, 5, 1, 0),
+SOC_DAPM_SINGLE("DACR Switch", WM8962_SPEAKER_MIXER_2, 4, 1, 0),
+SOC_DAPM_SINGLE("MIXINL Switch", WM8962_SPEAKER_MIXER_2, 3, 1, 0),
+SOC_DAPM_SINGLE("MIXINR Switch", WM8962_SPEAKER_MIXER_2, 2, 1, 0),
+SOC_DAPM_SINGLE("IN4L Switch", WM8962_SPEAKER_MIXER_2, 1, 1, 0),
+SOC_DAPM_SINGLE("IN4R Switch", WM8962_SPEAKER_MIXER_2, 0, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8962_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+SND_SOC_DAPM_INPUT("IN3L"),
+SND_SOC_DAPM_INPUT("IN3R"),
+SND_SOC_DAPM_INPUT("IN4L"),
+SND_SOC_DAPM_INPUT("IN4R"),
+SND_SOC_DAPM_INPUT("Beep"),
+
+SND_SOC_DAPM_MICBIAS("MICBIAS", WM8962_PWR_MGMT_1, 1, 0),
+
+SND_SOC_DAPM_SUPPLY("Class G", WM8962_CHARGE_PUMP_B, 0, 1, NULL, 0),
+SND_SOC_DAPM_SUPPLY("SYSCLK", WM8962_CLOCKING2, 5, 0, sysclk_event,
+                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_SUPPLY("Charge Pump", WM8962_CHARGE_PUMP_1, 0, 0, cp_event,
+                   SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_SUPPLY("TOCLK", WM8962_ADDITIONAL_CONTROL_1, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("INPGAL", WM8962_LEFT_INPUT_PGA_CONTROL, 4, 0,
+                  inpgal, ARRAY_SIZE(inpgal)),
+SND_SOC_DAPM_MIXER("INPGAR", WM8962_RIGHT_INPUT_PGA_CONTROL, 4, 0,
+                  inpgar, ARRAY_SIZE(inpgar)),
+SND_SOC_DAPM_MIXER("MIXINL", WM8962_PWR_MGMT_1, 5, 0,
+                  mixinl, ARRAY_SIZE(mixinl)),
+SND_SOC_DAPM_MIXER("MIXINR", WM8962_PWR_MGMT_1, 4, 0,
+                  mixinr, ARRAY_SIZE(mixinr)),
+
+SND_SOC_DAPM_ADC("ADCL", "Capture", WM8962_PWR_MGMT_1, 3, 0),
+SND_SOC_DAPM_ADC("ADCR", "Capture", WM8962_PWR_MGMT_1, 2, 0),
+
+SND_SOC_DAPM_MUX("STL", SND_SOC_NOPM, 0, 0, &stl_mux),
+SND_SOC_DAPM_MUX("STR", SND_SOC_NOPM, 0, 0, &str_mux),
+
+SND_SOC_DAPM_DAC("DACL", "Playback", WM8962_PWR_MGMT_2, 8, 0),
+SND_SOC_DAPM_DAC("DACR", "Playback", WM8962_PWR_MGMT_2, 7, 0),
+
+SND_SOC_DAPM_PGA("Left Bypass", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Bypass", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("HPMIXL", WM8962_MIXER_ENABLES, 3, 0,
+                  hpmixl, ARRAY_SIZE(hpmixl)),
+SND_SOC_DAPM_MIXER("HPMIXR", WM8962_MIXER_ENABLES, 2, 0,
+                  hpmixr, ARRAY_SIZE(hpmixr)),
+
+SND_SOC_DAPM_MUX_E("HPOUTL PGA", WM8962_PWR_MGMT_2, 6, 0, &hpoutl_mux,
+                  out_pga_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_MUX_E("HPOUTR PGA", WM8962_PWR_MGMT_2, 5, 0, &hpoutr_mux,
+                  out_pga_event, SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_PGA_E("HPOUT", SND_SOC_NOPM, 0, 0, NULL, 0, hp_event,
+                  SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_OUTPUT("HPOUTL"),
+SND_SOC_DAPM_OUTPUT("HPOUTR"),
+};
+
+static const struct snd_soc_dapm_widget wm8962_dapm_spk_mono_widgets[] = {
+SND_SOC_DAPM_MIXER("Speaker Mixer", WM8962_MIXER_ENABLES, 1, 0,
+                  spkmixl, ARRAY_SIZE(spkmixl)),
+SND_SOC_DAPM_MUX_E("Speaker PGA", WM8962_PWR_MGMT_2, 4, 0, &spkoutl_mux,
+                  out_pga_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA("Speaker Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0),
+SND_SOC_DAPM_OUTPUT("SPKOUT"),
+};
+
+static const struct snd_soc_dapm_widget wm8962_dapm_spk_stereo_widgets[] = {
+SND_SOC_DAPM_MIXER("SPKOUTL Mixer", WM8962_MIXER_ENABLES, 1, 0,
+                  spkmixl, ARRAY_SIZE(spkmixl)),
+SND_SOC_DAPM_MIXER("SPKOUTR Mixer", WM8962_MIXER_ENABLES, 0, 0,
+                  spkmixr, ARRAY_SIZE(spkmixr)),
+
+SND_SOC_DAPM_MUX_E("SPKOUTL PGA", WM8962_PWR_MGMT_2, 4, 0, &spkoutl_mux,
+                  out_pga_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_MUX_E("SPKOUTR PGA", WM8962_PWR_MGMT_2, 3, 0, &spkoutr_mux,
+                  out_pga_event, SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_PGA("SPKOUTR Output", WM8962_CLASS_D_CONTROL_1, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SPKOUTL Output", WM8962_CLASS_D_CONTROL_1, 6, 0, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("SPKOUTL"),
+SND_SOC_DAPM_OUTPUT("SPKOUTR"),
+};
+
+static const struct snd_soc_dapm_route wm8962_intercon[] = {
+       { "INPGAL", "IN1L Switch", "IN1L" },
+       { "INPGAL", "IN2L Switch", "IN2L" },
+       { "INPGAL", "IN3L Switch", "IN3L" },
+       { "INPGAL", "IN4L Switch", "IN4L" },
+
+       { "INPGAR", "IN1R Switch", "IN1R" },
+       { "INPGAR", "IN2R Switch", "IN2R" },
+       { "INPGAR", "IN3R Switch", "IN3R" },
+       { "INPGAR", "IN4R Switch", "IN4R" },
+
+       { "MIXINL", "IN2L Switch", "IN2L" },
+       { "MIXINL", "IN3L Switch", "IN3L" },
+       { "MIXINL", "PGA Switch", "INPGAL" },
+
+       { "MIXINR", "IN2R Switch", "IN2R" },
+       { "MIXINR", "IN3R Switch", "IN3R" },
+       { "MIXINR", "PGA Switch", "INPGAR" },
+
+       { "MICBIAS", NULL, "SYSCLK" },
+
+       { "ADCL", NULL, "SYSCLK" },
+       { "ADCL", NULL, "TOCLK" },
+       { "ADCL", NULL, "MIXINL" },
+
+       { "ADCR", NULL, "SYSCLK" },
+       { "ADCR", NULL, "TOCLK" },
+       { "ADCR", NULL, "MIXINR" },
+
+       { "STL", "Left", "ADCL" },
+       { "STL", "Right", "ADCR" },
+
+       { "STR", "Left", "ADCL" },
+       { "STR", "Right", "ADCR" },
+
+       { "DACL", NULL, "SYSCLK" },
+       { "DACL", NULL, "TOCLK" },
+       { "DACL", NULL, "Beep" },
+       { "DACL", NULL, "STL" },
+
+       { "DACR", NULL, "SYSCLK" },
+       { "DACR", NULL, "TOCLK" },
+       { "DACR", NULL, "Beep" },
+       { "DACR", NULL, "STR" },
+
+       { "HPMIXL", "IN4L Switch", "IN4L" },
+       { "HPMIXL", "IN4R Switch", "IN4R" },
+       { "HPMIXL", "DACL Switch", "DACL" },
+       { "HPMIXL", "DACR Switch", "DACR" },
+       { "HPMIXL", "MIXINL Switch", "MIXINL" },
+       { "HPMIXL", "MIXINR Switch", "MIXINR" },
+
+       { "HPMIXR", "IN4L Switch", "IN4L" },
+       { "HPMIXR", "IN4R Switch", "IN4R" },
+       { "HPMIXR", "DACL Switch", "DACL" },
+       { "HPMIXR", "DACR Switch", "DACR" },
+       { "HPMIXR", "MIXINL Switch", "MIXINL" },
+       { "HPMIXR", "MIXINR Switch", "MIXINR" },
+
+       { "Left Bypass", NULL, "HPMIXL" },
+       { "Left Bypass", NULL, "Class G" },
+
+       { "Right Bypass", NULL, "HPMIXR" },
+       { "Right Bypass", NULL, "Class G" },
+
+       { "HPOUTL PGA", "Mixer", "Left Bypass" },
+       { "HPOUTL PGA", "DAC", "DACL" },
+
+       { "HPOUTR PGA", "Mixer", "Right Bypass" },
+       { "HPOUTR PGA", "DAC", "DACR" },
+
+       { "HPOUT", NULL, "HPOUTL PGA" },
+       { "HPOUT", NULL, "HPOUTR PGA" },
+       { "HPOUT", NULL, "Charge Pump" },
+       { "HPOUT", NULL, "SYSCLK" },
+       { "HPOUT", NULL, "TOCLK" },
+
+       { "HPOUTL", NULL, "HPOUT" },
+       { "HPOUTR", NULL, "HPOUT" },
+};
+
+static const struct snd_soc_dapm_route wm8962_spk_mono_intercon[] = {
+       { "Speaker Mixer", "IN4L Switch", "IN4L" },
+       { "Speaker Mixer", "IN4R Switch", "IN4R" },
+       { "Speaker Mixer", "DACL Switch", "DACL" },
+       { "Speaker Mixer", "DACR Switch", "DACR" },
+       { "Speaker Mixer", "MIXINL Switch", "MIXINL" },
+       { "Speaker Mixer", "MIXINR Switch", "MIXINR" },
+
+       { "Speaker PGA", "Mixer", "Speaker Mixer" },
+       { "Speaker PGA", "DAC", "DACL" },
+
+       { "Speaker Output", NULL, "Speaker PGA" },
+       { "Speaker Output", NULL, "SYSCLK" },
+       { "Speaker Output", NULL, "TOCLK" },
+
+       { "SPKOUT", NULL, "Speaker Output" },
+};
+
+static const struct snd_soc_dapm_route wm8962_spk_stereo_intercon[] = {
+       { "SPKOUTL Mixer", "IN4L Switch", "IN4L" },
+       { "SPKOUTL Mixer", "IN4R Switch", "IN4R" },
+       { "SPKOUTL Mixer", "DACL Switch", "DACL" },
+       { "SPKOUTL Mixer", "DACR Switch", "DACR" },
+       { "SPKOUTL Mixer", "MIXINL Switch", "MIXINL" },
+       { "SPKOUTL Mixer", "MIXINR Switch", "MIXINR" },
+
+       { "SPKOUTR Mixer", "IN4L Switch", "IN4L" },
+       { "SPKOUTR Mixer", "IN4R Switch", "IN4R" },
+       { "SPKOUTR Mixer", "DACL Switch", "DACL" },
+       { "SPKOUTR Mixer", "DACR Switch", "DACR" },
+       { "SPKOUTR Mixer", "MIXINL Switch", "MIXINL" },
+       { "SPKOUTR Mixer", "MIXINR Switch", "MIXINR" },
+
+       { "SPKOUTL PGA", "Mixer", "SPKOUTL Mixer" },
+       { "SPKOUTL PGA", "DAC", "DACL" },
+
+       { "SPKOUTR PGA", "Mixer", "SPKOUTR Mixer" },
+       { "SPKOUTR PGA", "DAC", "DACR" },
+
+       { "SPKOUTL Output", NULL, "SPKOUTL PGA" },
+       { "SPKOUTL Output", NULL, "SYSCLK" },
+       { "SPKOUTL Output", NULL, "TOCLK" },
+
+       { "SPKOUTR Output", NULL, "SPKOUTR PGA" },
+       { "SPKOUTR Output", NULL, "SYSCLK" },
+       { "SPKOUTR Output", NULL, "TOCLK" },
+
+       { "SPKOUTL", NULL, "SPKOUTL Output" },
+       { "SPKOUTR", NULL, "SPKOUTR Output" },
+};
+
+static int wm8962_add_widgets(struct snd_soc_codec *codec)
+{
+       struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+
+       snd_soc_add_controls(codec, wm8962_snd_controls,
+                            ARRAY_SIZE(wm8962_snd_controls));
+       if (pdata && pdata->spk_mono)
+               snd_soc_add_controls(codec, wm8962_spk_mono_controls,
+                                    ARRAY_SIZE(wm8962_spk_mono_controls));
+       else
+               snd_soc_add_controls(codec, wm8962_spk_stereo_controls,
+                                    ARRAY_SIZE(wm8962_spk_stereo_controls));
+
+
+       snd_soc_dapm_new_controls(codec, wm8962_dapm_widgets,
+                                 ARRAY_SIZE(wm8962_dapm_widgets));
+       if (pdata && pdata->spk_mono)
+               snd_soc_dapm_new_controls(codec, wm8962_dapm_spk_mono_widgets,
+                                         ARRAY_SIZE(wm8962_dapm_spk_mono_widgets));
+       else
+               snd_soc_dapm_new_controls(codec, wm8962_dapm_spk_stereo_widgets,
+                                         ARRAY_SIZE(wm8962_dapm_spk_stereo_widgets));
+
+       snd_soc_dapm_add_routes(codec, wm8962_intercon,
+                               ARRAY_SIZE(wm8962_intercon));
+       if (pdata && pdata->spk_mono)
+               snd_soc_dapm_add_routes(codec, wm8962_spk_mono_intercon,
+                                       ARRAY_SIZE(wm8962_spk_mono_intercon));
+       else
+               snd_soc_dapm_add_routes(codec, wm8962_spk_stereo_intercon,
+                                       ARRAY_SIZE(wm8962_spk_stereo_intercon));
+
+
+       snd_soc_dapm_disable_pin(codec, "Beep");
+
+       return 0;
+}
+
+static void wm8962_sync_cache(struct snd_soc_codec *codec)
+{
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       int i;
+
+       if (!codec->cache_sync)
+               return;
+
+       dev_dbg(codec->dev, "Syncing cache\n");
+
+       codec->cache_only = 0;
+
+       /* Sync back cached values if they're different from the
+        * hardware default.
+        */
+       for (i = 1; i < ARRAY_SIZE(wm8962->reg_cache); i++) {
+               if (i == WM8962_SOFTWARE_RESET)
+                       continue;
+               if (wm8962->reg_cache[i] == wm8962_reg[i])
+                       continue;
+
+               snd_soc_write(codec, i, wm8962->reg_cache[i]);
+       }
+
+       codec->cache_sync = 0;
+}
+
+/* -1 for reserved values */
+static const int bclk_divs[] = {
+       1, -1, 2, 3, 4, -1, 6, 8, -1, 12, 16, 24, -1, 32, 32, 32
+};
+
+static void wm8962_configure_bclk(struct snd_soc_codec *codec)
+{
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       int dspclk, i;
+       int clocking2 = 0;
+       int aif2 = 0;
+
+       if (!wm8962->bclk) {
+               dev_dbg(codec->dev, "No BCLK rate configured\n");
+               return;
+       }
+
+       dspclk = snd_soc_read(codec, WM8962_CLOCKING1);
+       if (dspclk < 0) {
+               dev_err(codec->dev, "Failed to read DSPCLK: %d\n", dspclk);
+               return;
+       }
+
+       dspclk = (dspclk & WM8962_DSPCLK_DIV_MASK) >> WM8962_DSPCLK_DIV_SHIFT;
+       switch (dspclk) {
+       case 0:
+               dspclk = wm8962->sysclk_rate;
+               break;
+       case 1:
+               dspclk = wm8962->sysclk_rate / 2;
+               break;
+       case 2:
+               dspclk = wm8962->sysclk_rate / 4;
+               break;
+       default:
+               dev_warn(codec->dev, "Unknown DSPCLK divisor read back\n");
+               dspclk = wm8962->sysclk;
+       }
+
+       dev_dbg(codec->dev, "DSPCLK is %dHz, BCLK %d\n", dspclk, wm8962->bclk);
+
+       /* We're expecting an exact match */
+       for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+               if (bclk_divs[i] < 0)
+                       continue;
+
+               if (dspclk / bclk_divs[i] == wm8962->bclk) {
+                       dev_dbg(codec->dev, "Selected BCLK_DIV %d for %dHz\n",
+                               bclk_divs[i], wm8962->bclk);
+                       clocking2 |= i;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(bclk_divs)) {
+               dev_err(codec->dev, "Unsupported BCLK ratio %d\n",
+                       dspclk / wm8962->bclk);
+               return;
+       }
+
+       aif2 |= wm8962->bclk / wm8962->lrclk;
+       dev_dbg(codec->dev, "Selected LRCLK divisor %d for %dHz\n",
+               wm8962->bclk / wm8962->lrclk, wm8962->lrclk);
+
+       snd_soc_update_bits(codec, WM8962_CLOCKING2,
+                           WM8962_BCLK_DIV_MASK, clocking2);
+       snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_2,
+                           WM8962_AIF_RATE_MASK, aif2);
+}
+
+static int wm8962_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       if (level == codec->bias_level)
+               return 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               /* VMID 2*50k */
+               snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
+                                   WM8962_VMID_SEL_MASK, 0x80);
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies),
+                                                   wm8962->supplies);
+                       if (ret != 0) {
+                               dev_err(codec->dev,
+                                       "Failed to enable supplies: %d\n",
+                                       ret);
+                               return ret;
+                       }
+
+                       wm8962_sync_cache(codec);
+
+                       snd_soc_update_bits(codec, WM8962_ANTI_POP,
+                                           WM8962_STARTUP_BIAS_ENA |
+                                           WM8962_VMID_BUF_ENA,
+                                           WM8962_STARTUP_BIAS_ENA |
+                                           WM8962_VMID_BUF_ENA);
+
+                       /* Bias enable at 2*50k for ramp */
+                       snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
+                                           WM8962_VMID_SEL_MASK |
+                                           WM8962_BIAS_ENA,
+                                           WM8962_BIAS_ENA | 0x180);
+
+                       msleep(5);
+
+                       snd_soc_update_bits(codec, WM8962_CLOCKING2,
+                                           WM8962_CLKREG_OVD,
+                                           WM8962_CLKREG_OVD);
+
+                       wm8962_configure_bclk(codec);
+               }
+
+               /* VMID 2*250k */
+               snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
+                                   WM8962_VMID_SEL_MASK, 0x100);
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
+                                   WM8962_VMID_SEL_MASK | WM8962_BIAS_ENA, 0);
+
+               snd_soc_update_bits(codec, WM8962_ANTI_POP,
+                                   WM8962_STARTUP_BIAS_ENA |
+                                   WM8962_VMID_BUF_ENA, 0);
+
+               regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies),
+                                      wm8962->supplies);
+               break;
+       }
+       codec->bias_level = level;
+       return 0;
+}
+
+static const struct {
+       int rate;
+       int reg;
+} sr_vals[] = {
+       { 48000, 0 },
+       { 44100, 0 },
+       { 32000, 1 },
+       { 22050, 2 },
+       { 24000, 2 },
+       { 16000, 3 },
+       { 11025, 4 },
+       { 12000, 4 },
+       { 8000,  5 },
+       { 88200, 6 },
+       { 96000, 6 },
+};
+
+static const int sysclk_rates[] = {
+       64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536,
+};
+
+static int wm8962_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 wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       int rate = params_rate(params);
+       int i;
+       int aif0 = 0;
+       int adctl3 = 0;
+       int clocking4 = 0;
+
+       wm8962->bclk = snd_soc_params_to_bclk(params);
+       wm8962->lrclk = params_rate(params);
+
+       for (i = 0; i < ARRAY_SIZE(sr_vals); i++) {
+               if (sr_vals[i].rate == rate) {
+                       adctl3 |= sr_vals[i].reg;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(sr_vals)) {
+               dev_err(codec->dev, "Unsupported rate %dHz\n", rate);
+               return -EINVAL;
+       }
+
+       if (rate % 8000 == 0)
+               adctl3 |= WM8962_SAMPLE_RATE_INT_MODE;
+
+       for (i = 0; i < ARRAY_SIZE(sysclk_rates); i++) {
+               if (sysclk_rates[i] == wm8962->sysclk_rate / rate) {
+                       clocking4 |= i << WM8962_SYSCLK_RATE_SHIFT;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(sysclk_rates)) {
+               dev_err(codec->dev, "Unsupported sysclk ratio %d\n",
+                       wm8962->sysclk_rate / rate);
+               return -EINVAL;
+       }
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               aif0 |= 0x40;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               aif0 |= 0x80;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               aif0 |= 0xc0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_0,
+                           WM8962_WL_MASK, aif0);
+       snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_3,
+                           WM8962_SAMPLE_RATE_INT_MODE |
+                           WM8962_SAMPLE_RATE_MASK, adctl3);
+       snd_soc_update_bits(codec, WM8962_CLOCKING_4,
+                           WM8962_SYSCLK_RATE_MASK, clocking4);
+
+       wm8962_configure_bclk(codec);
+
+       return 0;
+}
+
+static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+                                unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       int src;
+
+       switch (clk_id) {
+       case WM8962_SYSCLK_MCLK:
+               wm8962->sysclk = WM8962_SYSCLK_MCLK;
+               src = 0;
+               break;
+       case WM8962_SYSCLK_FLL:
+               wm8962->sysclk = WM8962_SYSCLK_FLL;
+               src = 1 << WM8962_SYSCLK_SRC_SHIFT;
+               WARN_ON(freq != wm8962->fll_fout);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_SYSCLK_SRC_MASK,
+                           src);
+
+       wm8962->sysclk_rate = freq;
+
+       return 0;
+}
+
+static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       int aif0 = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+               aif0 |= WM8962_LRCLK_INV;
+       case SND_SOC_DAIFMT_DSP_B:
+               aif0 |= 3;
+
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_NB_NF:
+               case SND_SOC_DAIFMT_IB_NF:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       case SND_SOC_DAIFMT_RIGHT_J:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               aif0 |= 1;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               aif0 |= 2;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               aif0 |= WM8962_BCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               aif0 |= WM8962_LRCLK_INV;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               aif0 |= WM8962_BCLK_INV | WM8962_LRCLK_INV;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               aif0 |= WM8962_MSTR;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8962_AUDIO_INTERFACE_0,
+                           WM8962_FMT_MASK | WM8962_BCLK_INV | WM8962_MSTR |
+                           WM8962_LRCLK_INV, aif0);
+
+       return 0;
+}
+
+struct _fll_div {
+       u16 fll_fratio;
+       u16 fll_outdiv;
+       u16 fll_refclk_div;
+       u16 n;
+       u16 theta;
+       u16 lambda;
+};
+
+/* The size in bits of the FLL divide multiplied by 10
+ * to allow rounding later */
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+static struct {
+       unsigned int min;
+       unsigned int max;
+       u16 fll_fratio;
+       int ratio;
+} fll_fratios[] = {
+       {       0,    64000, 4, 16 },
+       {   64000,   128000, 3,  8 },
+       {  128000,   256000, 2,  4 },
+       {  256000,  1000000, 1,  2 },
+       { 1000000, 13500000, 0,  1 },
+};
+
+static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
+                      unsigned int Fout)
+{
+       unsigned int target;
+       unsigned int div;
+       unsigned int fratio, gcd_fll;
+       int i;
+
+       /* Fref must be <=13.5MHz */
+       div = 1;
+       fll_div->fll_refclk_div = 0;
+       while ((Fref / div) > 13500000) {
+               div *= 2;
+               fll_div->fll_refclk_div++;
+
+               if (div > 4) {
+                       pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+                              Fref);
+                       return -EINVAL;
+               }
+       }
+
+       pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
+
+       /* Apply the division for our remaining calculations */
+       Fref /= div;
+
+       /* Fvco should be 90-100MHz; don't check the upper bound */
+       div = 2;
+       while (Fout * div < 90000000) {
+               div++;
+               if (div > 64) {
+                       pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
+                              Fout);
+                       return -EINVAL;
+               }
+       }
+       target = Fout * div;
+       fll_div->fll_outdiv = div - 1;
+
+       pr_debug("FLL Fvco=%dHz\n", target);
+
+       /* Find an appropraite FLL_FRATIO and factor it out of the target */
+       for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
+               if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
+                       fll_div->fll_fratio = fll_fratios[i].fll_fratio;
+                       fratio = fll_fratios[i].ratio;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(fll_fratios)) {
+               pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
+               return -EINVAL;
+       }
+
+       fll_div->n = target / (fratio * Fref);
+
+       if (target % Fref == 0) {
+               fll_div->theta = 0;
+               fll_div->lambda = 0;
+       } else {
+               gcd_fll = gcd(target, fratio * Fref);
+
+               fll_div->theta = (target - (fll_div->n * fratio * Fref))
+                       / gcd_fll;
+               fll_div->lambda = (fratio * Fref) / gcd_fll;
+       }
+
+       pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
+                fll_div->n, fll_div->theta, fll_div->lambda);
+       pr_debug("FLL_FRATIO=%x FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
+                fll_div->fll_fratio, fll_div->fll_outdiv,
+                fll_div->fll_refclk_div);
+
+       return 0;
+}
+
+static int wm8962_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
+                         unsigned int Fref, unsigned int Fout)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       struct _fll_div fll_div;
+       int ret;
+       int fll1 = snd_soc_read(codec, WM8962_FLL_CONTROL_1) & WM8962_FLL_ENA;
+
+       /* Any change? */
+       if (source == wm8962->fll_src && Fref == wm8962->fll_fref &&
+           Fout == wm8962->fll_fout)
+               return 0;
+
+       if (Fout == 0) {
+               dev_dbg(codec->dev, "FLL disabled\n");
+
+               wm8962->fll_fref = 0;
+               wm8962->fll_fout = 0;
+
+               snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+                                   WM8962_FLL_ENA, 0);
+
+               return 0;
+       }
+
+       ret = fll_factors(&fll_div, Fref, Fout);
+       if (ret != 0)
+               return ret;
+
+       switch (fll_id) {
+       case WM8962_FLL_MCLK:
+       case WM8962_FLL_BCLK:
+       case WM8962_FLL_OSC:
+               fll1 |= (fll_id - 1) << WM8962_FLL_REFCLK_SRC_SHIFT;
+               break;
+       case WM8962_FLL_INT:
+               snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+                                   WM8962_FLL_OSC_ENA, WM8962_FLL_OSC_ENA);
+               snd_soc_update_bits(codec, WM8962_FLL_CONTROL_5,
+                                   WM8962_FLL_FRC_NCO, WM8962_FLL_FRC_NCO);
+               break;
+       default:
+               dev_err(codec->dev, "Unknown FLL source %d\n", ret);
+               return -EINVAL;
+       }
+
+       if (fll_div.theta || fll_div.lambda)
+               fll1 |= WM8962_FLL_FRAC;
+
+       /* Stop the FLL while we reconfigure */
+       snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, WM8962_FLL_ENA, 0);
+
+       snd_soc_update_bits(codec, WM8962_FLL_CONTROL_2,
+                           WM8962_FLL_OUTDIV_MASK |
+                           WM8962_FLL_REFCLK_DIV_MASK,
+                           (fll_div.fll_outdiv << WM8962_FLL_OUTDIV_SHIFT) |
+                           (fll_div.fll_refclk_div));
+
+       snd_soc_update_bits(codec, WM8962_FLL_CONTROL_3,
+                           WM8962_FLL_FRATIO_MASK, fll_div.fll_fratio);
+
+       snd_soc_write(codec, WM8962_FLL_CONTROL_6, fll_div.theta);
+       snd_soc_write(codec, WM8962_FLL_CONTROL_7, fll_div.lambda);
+       snd_soc_write(codec, WM8962_FLL_CONTROL_8, fll_div.n);
+
+       snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
+                           WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK |
+                           WM8962_FLL_ENA, fll1);
+
+       dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
+
+       wm8962->fll_fref = Fref;
+       wm8962->fll_fout = Fout;
+       wm8962->fll_src = source;
+
+       return 0;
+}
+
+static int wm8962_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       int val;
+
+       if (mute)
+               val = WM8962_DAC_MUTE;
+       else
+               val = 0;
+
+       return snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1,
+                                  WM8962_DAC_MUTE, val);
+}
+
+#define WM8962_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8962_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 wm8962_dai_ops = {
+       .hw_params = wm8962_hw_params,
+       .set_sysclk = wm8962_set_dai_sysclk,
+       .set_fmt = wm8962_set_dai_fmt,
+       .set_pll = wm8962_set_fll,
+       .digital_mute = wm8962_mute,
+};
+
+static struct snd_soc_dai_driver wm8962_dai = {
+       .name = "wm8962",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = WM8962_RATES,
+               .formats = WM8962_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = WM8962_RATES,
+               .formats = WM8962_FORMATS,
+       },
+       .ops = &wm8962_dai_ops,
+       .symmetric_rates = 1,
+};
+
+static void wm8962_mic_work(struct work_struct *work)
+{
+       struct wm8962_priv *wm8962 = container_of(work,
+                                                 struct wm8962_priv,
+                                                 mic_work.work);
+       struct snd_soc_codec *codec = wm8962->codec;
+       int status = 0;
+       int irq_pol = 0;
+       int reg;
+
+       reg = snd_soc_read(codec, WM8962_ADDITIONAL_CONTROL_4);
+
+       if (reg & WM8962_MICDET_STS) {
+               status |= SND_JACK_MICROPHONE;
+               irq_pol |= WM8962_MICD_IRQ_POL;
+       }
+
+       if (reg & WM8962_MICSHORT_STS) {
+               status |= SND_JACK_BTN_0;
+               irq_pol |= WM8962_MICSCD_IRQ_POL;
+       }
+
+       snd_soc_jack_report(wm8962->jack, status,
+                           SND_JACK_MICROPHONE | SND_JACK_BTN_0);
+
+       snd_soc_update_bits(codec, WM8962_MICINT_SOURCE_POL,
+                           WM8962_MICSCD_IRQ_POL |
+                           WM8962_MICD_IRQ_POL, irq_pol);
+}
+
+static irqreturn_t wm8962_irq(int irq, void *data)
+{
+       struct snd_soc_codec *codec = data;
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       int mask;
+       int active;
+
+       mask = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2);
+
+       active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2);
+       active &= ~mask;
+
+       if (active & WM8962_FIFOS_ERR_EINT)
+               dev_err(codec->dev, "FIFO error\n");
+
+       if (active & WM8962_TEMP_SHUT_EINT)
+               dev_crit(codec->dev, "Thermal shutdown\n");
+
+       if (active & (WM8962_MICSCD_EINT | WM8962_MICD_EINT)) {
+               dev_dbg(codec->dev, "Microphone event detected\n");
+
+               schedule_delayed_work(&wm8962->mic_work,
+                                     msecs_to_jiffies(250));
+       }
+
+       /* Acknowledge the interrupts */
+       snd_soc_write(codec, WM8962_INTERRUPT_STATUS_2, active);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * wm8962_mic_detect - Enable microphone detection via the WM8962 IRQ
+ *
+ * @codec:  WM8962 codec
+ * @jack:   jack to report detection events on
+ *
+ * Enable microphone detection via IRQ on the WM8962.  If GPIOs are
+ * being used to bring out signals to the processor then only platform
+ * data configuration is needed for WM8962 and processor GPIOs should
+ * be configured using snd_soc_jack_add_gpios() instead.
+ *
+ * If no jack is supplied detection will be disabled.
+ */
+int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
+{
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       int irq_mask, enable;
+
+       wm8962->jack = jack;
+       if (jack) {
+               irq_mask = 0;
+               enable = WM8962_MICDET_ENA;
+       } else {
+               irq_mask = WM8962_MICD_EINT | WM8962_MICSCD_EINT;
+               enable = 0;
+       }
+
+       snd_soc_update_bits(codec, WM8962_INTERRUPT_STATUS_2_MASK,
+                           WM8962_MICD_EINT | WM8962_MICSCD_EINT, irq_mask);
+       snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4,
+                           WM8962_MICDET_ENA, enable);
+
+       /* Send an initial empty report */
+       snd_soc_jack_report(wm8962->jack, 0,
+                           SND_JACK_MICROPHONE | SND_JACK_BTN_0);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm8962_mic_detect);
+
+#ifdef CONFIG_PM
+static int wm8962_resume(struct snd_soc_codec *codec)
+{
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       u16 *reg_cache = codec->reg_cache;
+       int i;
+
+       /* Restore the registers */
+       for (i = 1; i < ARRAY_SIZE(wm8962->reg_cache); i++) {
+               switch (i) {
+               case WM8962_SOFTWARE_RESET:
+                       continue;
+               default:
+                       break;
+               }
+
+               if (reg_cache[i] != wm8962_reg[i])
+                       snd_soc_write(codec, i, reg_cache[i]);
+       }
+
+       return 0;
+}
+#else
+#define wm8962_resume NULL
+#endif
+
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+static int beep_rates[] = {
+       500, 1000, 2000, 4000,
+};
+
+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;
+       int i;
+       int reg = 0;
+       int best = 0;
+
+       if (wm8962->beep_rate) {
+               for (i = 0; i < ARRAY_SIZE(beep_rates); i++) {
+                       if (abs(wm8962->beep_rate - beep_rates[i]) <
+                           abs(wm8962->beep_rate - beep_rates[best]))
+                               best = i;
+               }
+
+               dev_dbg(codec->dev, "Set beep rate %dHz for requested %dHz\n",
+                       beep_rates[best], wm8962->beep_rate);
+
+               reg = WM8962_BEEP_ENA | (best << WM8962_BEEP_RATE_SHIFT);
+
+               snd_soc_dapm_enable_pin(codec, "Beep");
+       } else {
+               dev_dbg(codec->dev, "Disabling beep\n");
+               snd_soc_dapm_disable_pin(codec, "Beep");
+       }
+
+       snd_soc_update_bits(codec, WM8962_BEEP_GENERATOR_1,
+                           WM8962_BEEP_ENA | WM8962_BEEP_RATE_MASK, reg);
+
+       snd_soc_dapm_sync(codec);
+}
+
+/* For usability define a way of injecting beep events for the device -
+ * many systems will not have a keyboard.
+ */
+static int wm8962_beep_event(struct input_dev *dev, unsigned int type,
+                            unsigned int code, int hz)
+{
+       struct snd_soc_codec *codec = input_get_drvdata(dev);
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+
+       dev_dbg(codec->dev, "Beep event %x %x\n", code, hz);
+
+       switch (code) {
+       case SND_BELL:
+               if (hz)
+                       hz = 1000;
+       case SND_TONE:
+               break;
+       default:
+               return -1;
+       }
+
+       /* Kick the beep from a workqueue */
+       wm8962->beep_rate = hz;
+       schedule_work(&wm8962->beep_work);
+       return 0;
+}
+
+static ssize_t wm8962_beep_set(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t count)
+{
+       struct wm8962_priv *wm8962 = dev_get_drvdata(dev);
+       long int time;
+
+       strict_strtol(buf, 10, &time);
+
+       input_event(wm8962->beep, EV_SND, SND_TONE, time);
+
+       return count;
+}
+
+static DEVICE_ATTR(beep, 0200, NULL, wm8962_beep_set);
+
+static void wm8962_init_beep(struct snd_soc_codec *codec)
+{
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       wm8962->beep = input_allocate_device();
+       if (!wm8962->beep) {
+               dev_err(codec->dev, "Failed to allocate beep device\n");
+               return;
+       }
+
+       INIT_WORK(&wm8962->beep_work, wm8962_beep_work);
+       wm8962->beep_rate = 0;
+
+       wm8962->beep->name = "WM8962 Beep Generator";
+       wm8962->beep->phys = dev_name(codec->dev);
+       wm8962->beep->id.bustype = BUS_I2C;
+
+       wm8962->beep->evbit[0] = BIT_MASK(EV_SND);
+       wm8962->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
+       wm8962->beep->event = wm8962_beep_event;
+       wm8962->beep->dev.parent = codec->dev;
+       input_set_drvdata(wm8962->beep, codec);
+
+       ret = input_register_device(wm8962->beep);
+       if (ret != 0) {
+               input_free_device(wm8962->beep);
+               wm8962->beep = NULL;
+               dev_err(codec->dev, "Failed to register beep device\n");
+       }
+
+       ret = device_create_file(codec->dev, &dev_attr_beep);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to create keyclick file: %d\n",
+                       ret);
+       }
+}
+
+static void wm8962_free_beep(struct snd_soc_codec *codec)
+{
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+
+       device_remove_file(codec->dev, &dev_attr_beep);
+       input_unregister_device(wm8962->beep);
+       cancel_work_sync(&wm8962->beep_work);
+       wm8962->beep = NULL;
+
+       snd_soc_update_bits(codec, WM8962_BEEP_GENERATOR_1, WM8962_BEEP_ENA,0);
+}
+#else
+static void wm8962_init_beep(struct snd_soc_codec *codec)
+{
+}
+
+static void wm8962_free_beep(struct snd_soc_codec *codec)
+{
+}
+#endif
+
+static void wm8962_set_gpio_mode(struct snd_soc_codec *codec, int gpio)
+{
+       int mask = 0;
+       int val = 0;
+
+       /* Some of the GPIOs are behind MFP configuration and need to
+        * be put into GPIO mode. */
+       switch (gpio) {
+       case 2:
+               mask = WM8962_CLKOUT2_SEL_MASK;
+               val = 1 << WM8962_CLKOUT2_SEL_SHIFT;
+               break;
+       case 3:
+               mask = WM8962_CLKOUT3_SEL_MASK;
+               val = 1 << WM8962_CLKOUT3_SEL_SHIFT;
+               break;
+       default:
+               break;
+       }
+
+       if (mask)
+               snd_soc_update_bits(codec, WM8962_ANALOGUE_CLOCKING1,
+                                   mask, val);
+}
+
+#ifdef CONFIG_GPIOLIB
+static inline struct wm8962_priv *gpio_to_wm8962(struct gpio_chip *chip)
+{
+       return container_of(chip, struct wm8962_priv, gpio_chip);
+}
+
+static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
+       struct snd_soc_codec *codec = wm8962->codec;
+
+       /* The WM8962 GPIOs aren't linearly numbered.  For simplicity
+        * we export linear numbers and error out if the unsupported
+        * ones are requsted.
+        */
+       switch (offset + 1) {
+       case 2:
+       case 3:
+       case 5:
+       case 6:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       wm8962_set_gpio_mode(codec, offset + 1);
+
+       return 0;
+}
+
+static void wm8962_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
+       struct snd_soc_codec *codec = wm8962->codec;
+
+       snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset,
+                           WM8962_GP2_LVL, value << WM8962_GP2_LVL_SHIFT);
+}
+
+static int wm8962_gpio_direction_out(struct gpio_chip *chip,
+                                    unsigned offset, int value)
+{
+       struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
+       struct snd_soc_codec *codec = wm8962->codec;
+       int val;
+
+       /* Force function 1 (logic output) */
+       val = (1 << WM8962_GP2_FN_SHIFT) | (value << WM8962_GP2_LVL_SHIFT);
+
+       return snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset,
+                                  WM8962_GP2_FN_MASK | WM8962_GP2_LVL, val);
+}
+
+static struct gpio_chip wm8962_template_chip = {
+       .label                  = "wm8962",
+       .owner                  = THIS_MODULE,
+       .request                = wm8962_gpio_request,
+       .direction_output       = wm8962_gpio_direction_out,
+       .set                    = wm8962_gpio_set,
+       .can_sleep              = 1,
+};
+
+static void wm8962_init_gpio(struct snd_soc_codec *codec)
+{
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+       int ret;
+
+       wm8962->gpio_chip = wm8962_template_chip;
+       wm8962->gpio_chip.ngpio = WM8962_MAX_GPIO;
+       wm8962->gpio_chip.dev = codec->dev;
+
+       if (pdata && pdata->gpio_base)
+               wm8962->gpio_chip.base = pdata->gpio_base;
+       else
+               wm8962->gpio_chip.base = -1;
+
+       ret = gpiochip_add(&wm8962->gpio_chip);
+       if (ret != 0)
+               dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
+static void wm8962_free_gpio(struct snd_soc_codec *codec)
+{
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       ret = gpiochip_remove(&wm8962->gpio_chip);
+       if (ret != 0)
+               dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
+}
+#else
+static void wm8962_init_gpio(struct snd_soc_codec *codec)
+{
+}
+
+static void wm8962_free_gpio(struct snd_soc_codec *codec)
+{
+}
+#endif
+
+static int wm8962_probe(struct snd_soc_codec *codec)
+{
+       int ret;
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+       struct i2c_client *i2c = container_of(codec->dev, struct i2c_client,
+                                             dev);
+       int i, trigger, irq_pol;
+
+       wm8962->codec = codec;
+       INIT_DELAYED_WORK(&wm8962->mic_work, wm8962_mic_work);
+
+       codec->cache_sync = 1;
+       codec->idle_bias_off = 1;
+
+       ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               goto err;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++)
+               wm8962->supplies[i].supply = wm8962_supply_names[i];
+
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8962->supplies),
+                                wm8962->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               goto err;
+       }
+
+       wm8962->disable_nb[0].notifier_call = wm8962_regulator_event_0;
+       wm8962->disable_nb[1].notifier_call = wm8962_regulator_event_1;
+       wm8962->disable_nb[2].notifier_call = wm8962_regulator_event_2;
+       wm8962->disable_nb[3].notifier_call = wm8962_regulator_event_3;
+       wm8962->disable_nb[4].notifier_call = wm8962_regulator_event_4;
+       wm8962->disable_nb[5].notifier_call = wm8962_regulator_event_5;
+       wm8962->disable_nb[6].notifier_call = wm8962_regulator_event_6;
+       wm8962->disable_nb[7].notifier_call = wm8962_regulator_event_7;
+
+       /* This should really be moved into the regulator core */
+       for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) {
+               ret = regulator_register_notifier(wm8962->supplies[i].consumer,
+                                                 &wm8962->disable_nb[i]);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to register regulator notifier: %d\n",
+                               ret);
+               }
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies),
+                                   wm8962->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_get;
+       }
+
+       ret = snd_soc_read(codec, WM8962_SOFTWARE_RESET);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read ID register\n");
+               goto err_enable;
+       }
+       if (ret != wm8962_reg[WM8962_SOFTWARE_RESET]) {
+               dev_err(codec->dev, "Device is not a WM8962, ID %x != %x\n",
+                       ret, wm8962_reg[WM8962_SOFTWARE_RESET]);
+               ret = -EINVAL;
+               goto err_enable;
+       }
+
+       ret = snd_soc_read(codec, WM8962_RIGHT_INPUT_VOLUME);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read device revision: %d\n",
+                       ret);
+               goto err_enable;
+       }
+       
+       dev_info(codec->dev, "customer id %x revision %c\n",
+                (ret & WM8962_CUST_ID_MASK) >> WM8962_CUST_ID_SHIFT,
+                ((ret & WM8962_CHIP_REV_MASK) >> WM8962_CHIP_REV_SHIFT)
+                + 'A');
+
+       ret = wm8962_reset(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset\n");
+               goto err_enable;
+       }
+
+       /* SYSCLK defaults to on; make sure it is off so we can safely
+        * write to registers if the device is declocked.
+        */
+       snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_SYSCLK_ENA, 0);
+
+       regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+
+       if (pdata) {
+               /* Apply static configuration for GPIOs */
+               for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++)
+                       if (pdata->gpio_init[i]) {
+                               wm8962_set_gpio_mode(codec, i + 1);
+                               snd_soc_write(codec, 0x200 + i,
+                                             pdata->gpio_init[i] & 0xffff);
+                       }
+
+               /* Put the speakers into mono mode? */
+               if (pdata->spk_mono)
+                       wm8962->reg_cache[WM8962_CLASS_D_CONTROL_2]
+                               |= WM8962_SPK_MONO;
+
+               /* Micbias setup, detection enable and detection
+                * threasholds. */
+               if (pdata->mic_cfg)
+                       snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4,
+                                           WM8962_MICDET_ENA |
+                                           WM8962_MICDET_THR_MASK |
+                                           WM8962_MICSHORT_THR_MASK |
+                                           WM8962_MICBIAS_LVL,
+                                           pdata->mic_cfg);
+       }
+
+       /* Latch volume update bits */
+       wm8962->reg_cache[WM8962_LEFT_INPUT_VOLUME] |= WM8962_IN_VU;
+       wm8962->reg_cache[WM8962_RIGHT_INPUT_VOLUME] |= WM8962_IN_VU;
+       wm8962->reg_cache[WM8962_LEFT_ADC_VOLUME] |= WM8962_ADC_VU;
+       wm8962->reg_cache[WM8962_RIGHT_ADC_VOLUME] |= WM8962_ADC_VU;    
+       wm8962->reg_cache[WM8962_LEFT_DAC_VOLUME] |= WM8962_DAC_VU;
+       wm8962->reg_cache[WM8962_RIGHT_DAC_VOLUME] |= WM8962_DAC_VU;
+       wm8962->reg_cache[WM8962_SPKOUTL_VOLUME] |= WM8962_SPKOUT_VU;
+       wm8962->reg_cache[WM8962_SPKOUTR_VOLUME] |= WM8962_SPKOUT_VU;
+       wm8962->reg_cache[WM8962_HPOUTL_VOLUME] |= WM8962_HPOUT_VU;
+       wm8962->reg_cache[WM8962_HPOUTR_VOLUME] |= WM8962_HPOUT_VU;
+
+       wm8962_add_widgets(codec);
+
+       wm8962_init_beep(codec);
+       wm8962_init_gpio(codec);
+
+       if (i2c->irq) {
+               if (pdata && pdata->irq_active_low) {
+                       trigger = IRQF_TRIGGER_LOW;
+                       irq_pol = WM8962_IRQ_POL;
+               } else {
+                       trigger = IRQF_TRIGGER_HIGH;
+                       irq_pol = 0;
+               }
+
+               snd_soc_update_bits(codec, WM8962_INTERRUPT_CONTROL,
+                                   WM8962_IRQ_POL, irq_pol);
+
+               ret = request_threaded_irq(i2c->irq, NULL, wm8962_irq,
+                                          trigger | IRQF_ONESHOT,
+                                          "wm8962", codec);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Failed to request IRQ %d: %d\n",
+                               i2c->irq, ret);
+                       /* Non-fatal */
+               } else {
+                       /* Enable error reporting IRQs by default */
+                       snd_soc_update_bits(codec,
+                                           WM8962_INTERRUPT_STATUS_2_MASK,
+                                           WM8962_TEMP_SHUT_EINT |
+                                           WM8962_FIFOS_ERR_EINT, 0);
+               }
+       }
+
+       return 0;
+
+err_enable:
+       regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+err_get:
+       regulator_bulk_free(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+err:
+       kfree(wm8962);
+       return ret;
+}
+
+static int wm8962_remove(struct snd_soc_codec *codec)
+{
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       struct i2c_client *i2c = container_of(codec->dev, struct i2c_client,
+                                             dev);
+       int i;
+
+       if (i2c->irq)
+               free_irq(i2c->irq, codec);
+
+       cancel_delayed_work_sync(&wm8962->mic_work);
+
+       wm8962_free_gpio(codec);
+       wm8962_free_beep(codec);
+       for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++)
+               regulator_unregister_notifier(wm8962->supplies[i].consumer,
+                                             &wm8962->disable_nb[i]);
+       regulator_bulk_free(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8962 = {
+       .probe =        wm8962_probe,
+       .remove =       wm8962_remove,
+       .resume =       wm8962_resume,
+       .set_bias_level = wm8962_set_bias_level,
+       .reg_cache_size = WM8962_MAX_REGISTER + 1,
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8962_reg,
+       .volatile_register = wm8962_volatile_register,
+       .readable_register = wm8962_readable_register,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8962_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8962_priv *wm8962;
+       int ret;
+
+       wm8962 = kzalloc(sizeof(struct wm8962_priv), GFP_KERNEL);
+       if (wm8962 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, wm8962);
+
+       ret = snd_soc_register_codec(&i2c->dev,
+                                    &soc_codec_dev_wm8962, &wm8962_dai, 1);
+       if (ret < 0)
+               kfree(wm8962);
+
+       return ret;
+}
+
+static __devexit int wm8962_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 wm8962_i2c_id[] = {
+       { "wm8962", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8962_i2c_id);
+
+static struct i2c_driver wm8962_i2c_driver = {
+       .driver = {
+               .name = "wm8962",
+               .owner = THIS_MODULE,
+       },
+       .probe =    wm8962_i2c_probe,
+       .remove =   __devexit_p(wm8962_i2c_remove),
+       .id_table = wm8962_i2c_id,
+};
+#endif
+
+static int __init wm8962_modinit(void)
+{
+       int ret;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8962_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8962 I2C driver: %d\n",
+                      ret);
+       }
+#endif
+       return 0;
+}
+module_init(wm8962_modinit);
+
+static void __exit wm8962_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8962_i2c_driver);
+#endif
+}
+module_exit(wm8962_exit);
+
+MODULE_DESCRIPTION("ASoC WM8962 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8962.h b/sound/soc/codecs/wm8962.h
new file mode 100644 (file)
index 0000000..a1a5d52
--- /dev/null
@@ -0,0 +1,3780 @@
+/*
+ * wm8962.h  --  WM8962 ASoC 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.
+ */
+
+#ifndef _WM8962_H
+#define _WM8962_H
+
+#include <asm/types.h>
+#include <sound/soc.h>
+
+#define WM8962_SYSCLK_MCLK 1
+#define WM8962_SYSCLK_FLL  2
+#define WM8962_SYSCLK_PLL3 3
+
+#define WM8962_FLL  1
+
+#define WM8962_FLL_MCLK 1
+#define WM8962_FLL_BCLK 2
+#define WM8962_FLL_OSC  3
+#define WM8962_FLL_INT  4
+
+/*
+ * Register values.
+ */
+#define WM8962_LEFT_INPUT_VOLUME                0x00
+#define WM8962_RIGHT_INPUT_VOLUME               0x01
+#define WM8962_HPOUTL_VOLUME                    0x02
+#define WM8962_HPOUTR_VOLUME                    0x03
+#define WM8962_CLOCKING1                        0x04
+#define WM8962_ADC_DAC_CONTROL_1                0x05
+#define WM8962_ADC_DAC_CONTROL_2                0x06
+#define WM8962_AUDIO_INTERFACE_0                0x07
+#define WM8962_CLOCKING2                        0x08
+#define WM8962_AUDIO_INTERFACE_1                0x09
+#define WM8962_LEFT_DAC_VOLUME                  0x0A
+#define WM8962_RIGHT_DAC_VOLUME                 0x0B
+#define WM8962_AUDIO_INTERFACE_2                0x0E
+#define WM8962_SOFTWARE_RESET                   0x0F
+#define WM8962_ALC1                             0x11
+#define WM8962_ALC2                             0x12
+#define WM8962_ALC3                             0x13
+#define WM8962_NOISE_GATE                       0x14
+#define WM8962_LEFT_ADC_VOLUME                  0x15
+#define WM8962_RIGHT_ADC_VOLUME                 0x16
+#define WM8962_ADDITIONAL_CONTROL_1             0x17
+#define WM8962_ADDITIONAL_CONTROL_2             0x18
+#define WM8962_PWR_MGMT_1                       0x19
+#define WM8962_PWR_MGMT_2                       0x1A
+#define WM8962_ADDITIONAL_CONTROL_3             0x1B
+#define WM8962_ANTI_POP                         0x1C
+#define WM8962_CLOCKING_3                       0x1E
+#define WM8962_INPUT_MIXER_CONTROL_1            0x1F
+#define WM8962_LEFT_INPUT_MIXER_VOLUME          0x20
+#define WM8962_RIGHT_INPUT_MIXER_VOLUME         0x21
+#define WM8962_INPUT_MIXER_CONTROL_2            0x22
+#define WM8962_INPUT_BIAS_CONTROL               0x23
+#define WM8962_LEFT_INPUT_PGA_CONTROL           0x25
+#define WM8962_RIGHT_INPUT_PGA_CONTROL          0x26
+#define WM8962_SPKOUTL_VOLUME                   0x28
+#define WM8962_SPKOUTR_VOLUME                   0x29
+#define WM8962_THERMAL_SHUTDOWN_STATUS          0x2F
+#define WM8962_ADDITIONAL_CONTROL_4             0x30
+#define WM8962_CLASS_D_CONTROL_1                0x31
+#define WM8962_CLASS_D_CONTROL_2                0x33
+#define WM8962_CLOCKING_4                       0x38
+#define WM8962_DAC_DSP_MIXING_1                 0x39
+#define WM8962_DAC_DSP_MIXING_2                 0x3A
+#define WM8962_DC_SERVO_0                       0x3C
+#define WM8962_DC_SERVO_1                       0x3D
+#define WM8962_DC_SERVO_4                       0x40
+#define WM8962_DC_SERVO_6                       0x42
+#define WM8962_ANALOGUE_PGA_BIAS                0x44
+#define WM8962_ANALOGUE_HP_0                    0x45
+#define WM8962_ANALOGUE_HP_2                    0x47
+#define WM8962_CHARGE_PUMP_1                    0x48
+#define WM8962_CHARGE_PUMP_B                    0x52
+#define WM8962_WRITE_SEQUENCER_CONTROL_1        0x57
+#define WM8962_WRITE_SEQUENCER_CONTROL_2        0x5A
+#define WM8962_WRITE_SEQUENCER_CONTROL_3        0x5D
+#define WM8962_CONTROL_INTERFACE                0x5E
+#define WM8962_MIXER_ENABLES                    0x63
+#define WM8962_HEADPHONE_MIXER_1                0x64
+#define WM8962_HEADPHONE_MIXER_2                0x65
+#define WM8962_HEADPHONE_MIXER_3                0x66
+#define WM8962_HEADPHONE_MIXER_4                0x67
+#define WM8962_SPEAKER_MIXER_1                  0x69
+#define WM8962_SPEAKER_MIXER_2                  0x6A
+#define WM8962_SPEAKER_MIXER_3                  0x6B
+#define WM8962_SPEAKER_MIXER_4                  0x6C
+#define WM8962_SPEAKER_MIXER_5                  0x6D
+#define WM8962_BEEP_GENERATOR_1                 0x6E
+#define WM8962_OSCILLATOR_TRIM_3                0x73
+#define WM8962_OSCILLATOR_TRIM_4                0x74
+#define WM8962_OSCILLATOR_TRIM_7                0x77
+#define WM8962_ANALOGUE_CLOCKING1               0x7C
+#define WM8962_ANALOGUE_CLOCKING2               0x7D
+#define WM8962_ANALOGUE_CLOCKING3               0x7E
+#define WM8962_PLL_SOFTWARE_RESET               0x7F
+#define WM8962_PLL2                             0x81
+#define WM8962_PLL_4                            0x83
+#define WM8962_PLL_9                            0x88
+#define WM8962_PLL_10                           0x89
+#define WM8962_PLL_11                           0x8A
+#define WM8962_PLL_12                           0x8B
+#define WM8962_PLL_13                           0x8C
+#define WM8962_PLL_14                           0x8D
+#define WM8962_PLL_15                           0x8E
+#define WM8962_PLL_16                           0x8F
+#define WM8962_FLL_CONTROL_1                    0x9B
+#define WM8962_FLL_CONTROL_2                    0x9C
+#define WM8962_FLL_CONTROL_3                    0x9D
+#define WM8962_FLL_CONTROL_5                    0x9F
+#define WM8962_FLL_CONTROL_6                    0xA0
+#define WM8962_FLL_CONTROL_7                    0xA1
+#define WM8962_FLL_CONTROL_8                    0xA2
+#define WM8962_GENERAL_TEST_1                   0xFC
+#define WM8962_DF1                              0x100
+#define WM8962_DF2                              0x101
+#define WM8962_DF3                              0x102
+#define WM8962_DF4                              0x103
+#define WM8962_DF5                              0x104
+#define WM8962_DF6                              0x105
+#define WM8962_DF7                              0x106
+#define WM8962_LHPF1                            0x108
+#define WM8962_LHPF2                            0x109
+#define WM8962_THREED1                          0x10C
+#define WM8962_THREED2                          0x10D
+#define WM8962_THREED3                          0x10E
+#define WM8962_THREED4                          0x10F
+#define WM8962_DRC_1                            0x114
+#define WM8962_DRC_2                            0x115
+#define WM8962_DRC_3                            0x116
+#define WM8962_DRC_4                            0x117
+#define WM8962_DRC_5                            0x118
+#define WM8962_TLOOPBACK                        0x11D
+#define WM8962_EQ1                              0x14F
+#define WM8962_EQ2                              0x150
+#define WM8962_EQ3                              0x151
+#define WM8962_EQ4                              0x152
+#define WM8962_EQ5                              0x153
+#define WM8962_EQ6                              0x154
+#define WM8962_EQ7                              0x155
+#define WM8962_EQ8                              0x156
+#define WM8962_EQ9                              0x157
+#define WM8962_EQ10                             0x158
+#define WM8962_EQ11                             0x159
+#define WM8962_EQ12                             0x15A
+#define WM8962_EQ13                             0x15B
+#define WM8962_EQ14                             0x15C
+#define WM8962_EQ15                             0x15D
+#define WM8962_EQ16                             0x15E
+#define WM8962_EQ17                             0x15F
+#define WM8962_EQ18                             0x160
+#define WM8962_EQ19                             0x161
+#define WM8962_EQ20                             0x162
+#define WM8962_EQ21                             0x163
+#define WM8962_EQ22                             0x164
+#define WM8962_EQ23                             0x165
+#define WM8962_EQ24                             0x166
+#define WM8962_EQ25                             0x167
+#define WM8962_EQ26                             0x168
+#define WM8962_EQ27                             0x169
+#define WM8962_EQ28                             0x16A
+#define WM8962_EQ29                             0x16B
+#define WM8962_EQ30                             0x16C
+#define WM8962_EQ31                             0x16D
+#define WM8962_EQ32                             0x16E
+#define WM8962_EQ33                             0x16F
+#define WM8962_EQ34                             0x170
+#define WM8962_EQ35                             0x171
+#define WM8962_EQ36                             0x172
+#define WM8962_EQ37                             0x173
+#define WM8962_EQ38                             0x174
+#define WM8962_EQ39                             0x175
+#define WM8962_EQ40                             0x176
+#define WM8962_EQ41                             0x177
+#define WM8962_GPIO_BASE                       0x200
+#define WM8962_GPIO_2                           0x201
+#define WM8962_GPIO_3                           0x202
+#define WM8962_GPIO_5                           0x204
+#define WM8962_GPIO_6                           0x205
+#define WM8962_INTERRUPT_STATUS_1               0x230
+#define WM8962_INTERRUPT_STATUS_2               0x231
+#define WM8962_INTERRUPT_STATUS_1_MASK          0x238
+#define WM8962_INTERRUPT_STATUS_2_MASK          0x239
+#define WM8962_INTERRUPT_CONTROL                0x240
+#define WM8962_IRQ_DEBOUNCE                     0x248
+#define WM8962_MICINT_SOURCE_POL                0x24A
+#define WM8962_DSP2_POWER_MANAGEMENT            0x300
+#define WM8962_DSP2_EXECCONTROL                 0x40D
+#define WM8962_WRITE_SEQUENCER_0                0x1000
+#define WM8962_WRITE_SEQUENCER_1                0x1001
+#define WM8962_WRITE_SEQUENCER_2                0x1002
+#define WM8962_WRITE_SEQUENCER_3                0x1003
+#define WM8962_WRITE_SEQUENCER_4                0x1004
+#define WM8962_WRITE_SEQUENCER_5                0x1005
+#define WM8962_WRITE_SEQUENCER_6                0x1006
+#define WM8962_WRITE_SEQUENCER_7                0x1007
+#define WM8962_WRITE_SEQUENCER_8                0x1008
+#define WM8962_WRITE_SEQUENCER_9                0x1009
+#define WM8962_WRITE_SEQUENCER_10               0x100A
+#define WM8962_WRITE_SEQUENCER_11               0x100B
+#define WM8962_WRITE_SEQUENCER_12               0x100C
+#define WM8962_WRITE_SEQUENCER_13               0x100D
+#define WM8962_WRITE_SEQUENCER_14               0x100E
+#define WM8962_WRITE_SEQUENCER_15               0x100F
+#define WM8962_WRITE_SEQUENCER_16               0x1010
+#define WM8962_WRITE_SEQUENCER_17               0x1011
+#define WM8962_WRITE_SEQUENCER_18               0x1012
+#define WM8962_WRITE_SEQUENCER_19               0x1013
+#define WM8962_WRITE_SEQUENCER_20               0x1014
+#define WM8962_WRITE_SEQUENCER_21               0x1015
+#define WM8962_WRITE_SEQUENCER_22               0x1016
+#define WM8962_WRITE_SEQUENCER_23               0x1017
+#define WM8962_WRITE_SEQUENCER_24               0x1018
+#define WM8962_WRITE_SEQUENCER_25               0x1019
+#define WM8962_WRITE_SEQUENCER_26               0x101A
+#define WM8962_WRITE_SEQUENCER_27               0x101B
+#define WM8962_WRITE_SEQUENCER_28               0x101C
+#define WM8962_WRITE_SEQUENCER_29               0x101D
+#define WM8962_WRITE_SEQUENCER_30               0x101E
+#define WM8962_WRITE_SEQUENCER_31               0x101F
+#define WM8962_WRITE_SEQUENCER_32               0x1020
+#define WM8962_WRITE_SEQUENCER_33               0x1021
+#define WM8962_WRITE_SEQUENCER_34               0x1022
+#define WM8962_WRITE_SEQUENCER_35               0x1023
+#define WM8962_WRITE_SEQUENCER_36               0x1024
+#define WM8962_WRITE_SEQUENCER_37               0x1025
+#define WM8962_WRITE_SEQUENCER_38               0x1026
+#define WM8962_WRITE_SEQUENCER_39               0x1027
+#define WM8962_WRITE_SEQUENCER_40               0x1028
+#define WM8962_WRITE_SEQUENCER_41               0x1029
+#define WM8962_WRITE_SEQUENCER_42               0x102A
+#define WM8962_WRITE_SEQUENCER_43               0x102B
+#define WM8962_WRITE_SEQUENCER_44               0x102C
+#define WM8962_WRITE_SEQUENCER_45               0x102D
+#define WM8962_WRITE_SEQUENCER_46               0x102E
+#define WM8962_WRITE_SEQUENCER_47               0x102F
+#define WM8962_WRITE_SEQUENCER_48               0x1030
+#define WM8962_WRITE_SEQUENCER_49               0x1031
+#define WM8962_WRITE_SEQUENCER_50               0x1032
+#define WM8962_WRITE_SEQUENCER_51               0x1033
+#define WM8962_WRITE_SEQUENCER_52               0x1034
+#define WM8962_WRITE_SEQUENCER_53               0x1035
+#define WM8962_WRITE_SEQUENCER_54               0x1036
+#define WM8962_WRITE_SEQUENCER_55               0x1037
+#define WM8962_WRITE_SEQUENCER_56               0x1038
+#define WM8962_WRITE_SEQUENCER_57               0x1039
+#define WM8962_WRITE_SEQUENCER_58               0x103A
+#define WM8962_WRITE_SEQUENCER_59               0x103B
+#define WM8962_WRITE_SEQUENCER_60               0x103C
+#define WM8962_WRITE_SEQUENCER_61               0x103D
+#define WM8962_WRITE_SEQUENCER_62               0x103E
+#define WM8962_WRITE_SEQUENCER_63               0x103F
+#define WM8962_WRITE_SEQUENCER_64               0x1040
+#define WM8962_WRITE_SEQUENCER_65               0x1041
+#define WM8962_WRITE_SEQUENCER_66               0x1042
+#define WM8962_WRITE_SEQUENCER_67               0x1043
+#define WM8962_WRITE_SEQUENCER_68               0x1044
+#define WM8962_WRITE_SEQUENCER_69               0x1045
+#define WM8962_WRITE_SEQUENCER_70               0x1046
+#define WM8962_WRITE_SEQUENCER_71               0x1047
+#define WM8962_WRITE_SEQUENCER_72               0x1048
+#define WM8962_WRITE_SEQUENCER_73               0x1049
+#define WM8962_WRITE_SEQUENCER_74               0x104A
+#define WM8962_WRITE_SEQUENCER_75               0x104B
+#define WM8962_WRITE_SEQUENCER_76               0x104C
+#define WM8962_WRITE_SEQUENCER_77               0x104D
+#define WM8962_WRITE_SEQUENCER_78               0x104E
+#define WM8962_WRITE_SEQUENCER_79               0x104F
+#define WM8962_WRITE_SEQUENCER_80               0x1050
+#define WM8962_WRITE_SEQUENCER_81               0x1051
+#define WM8962_WRITE_SEQUENCER_82               0x1052
+#define WM8962_WRITE_SEQUENCER_83               0x1053
+#define WM8962_WRITE_SEQUENCER_84               0x1054
+#define WM8962_WRITE_SEQUENCER_85               0x1055
+#define WM8962_WRITE_SEQUENCER_86               0x1056
+#define WM8962_WRITE_SEQUENCER_87               0x1057
+#define WM8962_WRITE_SEQUENCER_88               0x1058
+#define WM8962_WRITE_SEQUENCER_89               0x1059
+#define WM8962_WRITE_SEQUENCER_90               0x105A
+#define WM8962_WRITE_SEQUENCER_91               0x105B
+#define WM8962_WRITE_SEQUENCER_92               0x105C
+#define WM8962_WRITE_SEQUENCER_93               0x105D
+#define WM8962_WRITE_SEQUENCER_94               0x105E
+#define WM8962_WRITE_SEQUENCER_95               0x105F
+#define WM8962_WRITE_SEQUENCER_96               0x1060
+#define WM8962_WRITE_SEQUENCER_97               0x1061
+#define WM8962_WRITE_SEQUENCER_98               0x1062
+#define WM8962_WRITE_SEQUENCER_99               0x1063
+#define WM8962_WRITE_SEQUENCER_100              0x1064
+#define WM8962_WRITE_SEQUENCER_101              0x1065
+#define WM8962_WRITE_SEQUENCER_102              0x1066
+#define WM8962_WRITE_SEQUENCER_103              0x1067
+#define WM8962_WRITE_SEQUENCER_104              0x1068
+#define WM8962_WRITE_SEQUENCER_105              0x1069
+#define WM8962_WRITE_SEQUENCER_106              0x106A
+#define WM8962_WRITE_SEQUENCER_107              0x106B
+#define WM8962_WRITE_SEQUENCER_108              0x106C
+#define WM8962_WRITE_SEQUENCER_109              0x106D
+#define WM8962_WRITE_SEQUENCER_110              0x106E
+#define WM8962_WRITE_SEQUENCER_111              0x106F
+#define WM8962_WRITE_SEQUENCER_112              0x1070
+#define WM8962_WRITE_SEQUENCER_113              0x1071
+#define WM8962_WRITE_SEQUENCER_114              0x1072
+#define WM8962_WRITE_SEQUENCER_115              0x1073
+#define WM8962_WRITE_SEQUENCER_116              0x1074
+#define WM8962_WRITE_SEQUENCER_117              0x1075
+#define WM8962_WRITE_SEQUENCER_118              0x1076
+#define WM8962_WRITE_SEQUENCER_119              0x1077
+#define WM8962_WRITE_SEQUENCER_120              0x1078
+#define WM8962_WRITE_SEQUENCER_121              0x1079
+#define WM8962_WRITE_SEQUENCER_122              0x107A
+#define WM8962_WRITE_SEQUENCER_123              0x107B
+#define WM8962_WRITE_SEQUENCER_124              0x107C
+#define WM8962_WRITE_SEQUENCER_125              0x107D
+#define WM8962_WRITE_SEQUENCER_126              0x107E
+#define WM8962_WRITE_SEQUENCER_127              0x107F
+#define WM8962_WRITE_SEQUENCER_128              0x1080
+#define WM8962_WRITE_SEQUENCER_129              0x1081
+#define WM8962_WRITE_SEQUENCER_130              0x1082
+#define WM8962_WRITE_SEQUENCER_131              0x1083
+#define WM8962_WRITE_SEQUENCER_132              0x1084
+#define WM8962_WRITE_SEQUENCER_133              0x1085
+#define WM8962_WRITE_SEQUENCER_134              0x1086
+#define WM8962_WRITE_SEQUENCER_135              0x1087
+#define WM8962_WRITE_SEQUENCER_136              0x1088
+#define WM8962_WRITE_SEQUENCER_137              0x1089
+#define WM8962_WRITE_SEQUENCER_138              0x108A
+#define WM8962_WRITE_SEQUENCER_139              0x108B
+#define WM8962_WRITE_SEQUENCER_140              0x108C
+#define WM8962_WRITE_SEQUENCER_141              0x108D
+#define WM8962_WRITE_SEQUENCER_142              0x108E
+#define WM8962_WRITE_SEQUENCER_143              0x108F
+#define WM8962_WRITE_SEQUENCER_144              0x1090
+#define WM8962_WRITE_SEQUENCER_145              0x1091
+#define WM8962_WRITE_SEQUENCER_146              0x1092
+#define WM8962_WRITE_SEQUENCER_147              0x1093
+#define WM8962_WRITE_SEQUENCER_148              0x1094
+#define WM8962_WRITE_SEQUENCER_149              0x1095
+#define WM8962_WRITE_SEQUENCER_150              0x1096
+#define WM8962_WRITE_SEQUENCER_151              0x1097
+#define WM8962_WRITE_SEQUENCER_152              0x1098
+#define WM8962_WRITE_SEQUENCER_153              0x1099
+#define WM8962_WRITE_SEQUENCER_154              0x109A
+#define WM8962_WRITE_SEQUENCER_155              0x109B
+#define WM8962_WRITE_SEQUENCER_156              0x109C
+#define WM8962_WRITE_SEQUENCER_157              0x109D
+#define WM8962_WRITE_SEQUENCER_158              0x109E
+#define WM8962_WRITE_SEQUENCER_159              0x109F
+#define WM8962_WRITE_SEQUENCER_160              0x10A0
+#define WM8962_WRITE_SEQUENCER_161              0x10A1
+#define WM8962_WRITE_SEQUENCER_162              0x10A2
+#define WM8962_WRITE_SEQUENCER_163              0x10A3
+#define WM8962_WRITE_SEQUENCER_164              0x10A4
+#define WM8962_WRITE_SEQUENCER_165              0x10A5
+#define WM8962_WRITE_SEQUENCER_166              0x10A6
+#define WM8962_WRITE_SEQUENCER_167              0x10A7
+#define WM8962_WRITE_SEQUENCER_168              0x10A8
+#define WM8962_WRITE_SEQUENCER_169              0x10A9
+#define WM8962_WRITE_SEQUENCER_170              0x10AA
+#define WM8962_WRITE_SEQUENCER_171              0x10AB
+#define WM8962_WRITE_SEQUENCER_172              0x10AC
+#define WM8962_WRITE_SEQUENCER_173              0x10AD
+#define WM8962_WRITE_SEQUENCER_174              0x10AE
+#define WM8962_WRITE_SEQUENCER_175              0x10AF
+#define WM8962_WRITE_SEQUENCER_176              0x10B0
+#define WM8962_WRITE_SEQUENCER_177              0x10B1
+#define WM8962_WRITE_SEQUENCER_178              0x10B2
+#define WM8962_WRITE_SEQUENCER_179              0x10B3
+#define WM8962_WRITE_SEQUENCER_180              0x10B4
+#define WM8962_WRITE_SEQUENCER_181              0x10B5
+#define WM8962_WRITE_SEQUENCER_182              0x10B6
+#define WM8962_WRITE_SEQUENCER_183              0x10B7
+#define WM8962_WRITE_SEQUENCER_184              0x10B8
+#define WM8962_WRITE_SEQUENCER_185              0x10B9
+#define WM8962_WRITE_SEQUENCER_186              0x10BA
+#define WM8962_WRITE_SEQUENCER_187              0x10BB
+#define WM8962_WRITE_SEQUENCER_188              0x10BC
+#define WM8962_WRITE_SEQUENCER_189              0x10BD
+#define WM8962_WRITE_SEQUENCER_190              0x10BE
+#define WM8962_WRITE_SEQUENCER_191              0x10BF
+#define WM8962_WRITE_SEQUENCER_192              0x10C0
+#define WM8962_WRITE_SEQUENCER_193              0x10C1
+#define WM8962_WRITE_SEQUENCER_194              0x10C2
+#define WM8962_WRITE_SEQUENCER_195              0x10C3
+#define WM8962_WRITE_SEQUENCER_196              0x10C4
+#define WM8962_WRITE_SEQUENCER_197              0x10C5
+#define WM8962_WRITE_SEQUENCER_198              0x10C6
+#define WM8962_WRITE_SEQUENCER_199              0x10C7
+#define WM8962_WRITE_SEQUENCER_200              0x10C8
+#define WM8962_WRITE_SEQUENCER_201              0x10C9
+#define WM8962_WRITE_SEQUENCER_202              0x10CA
+#define WM8962_WRITE_SEQUENCER_203              0x10CB
+#define WM8962_WRITE_SEQUENCER_204              0x10CC
+#define WM8962_WRITE_SEQUENCER_205              0x10CD
+#define WM8962_WRITE_SEQUENCER_206              0x10CE
+#define WM8962_WRITE_SEQUENCER_207              0x10CF
+#define WM8962_WRITE_SEQUENCER_208              0x10D0
+#define WM8962_WRITE_SEQUENCER_209              0x10D1
+#define WM8962_WRITE_SEQUENCER_210              0x10D2
+#define WM8962_WRITE_SEQUENCER_211              0x10D3
+#define WM8962_WRITE_SEQUENCER_212              0x10D4
+#define WM8962_WRITE_SEQUENCER_213              0x10D5
+#define WM8962_WRITE_SEQUENCER_214              0x10D6
+#define WM8962_WRITE_SEQUENCER_215              0x10D7
+#define WM8962_WRITE_SEQUENCER_216              0x10D8
+#define WM8962_WRITE_SEQUENCER_217              0x10D9
+#define WM8962_WRITE_SEQUENCER_218              0x10DA
+#define WM8962_WRITE_SEQUENCER_219              0x10DB
+#define WM8962_WRITE_SEQUENCER_220              0x10DC
+#define WM8962_WRITE_SEQUENCER_221              0x10DD
+#define WM8962_WRITE_SEQUENCER_222              0x10DE
+#define WM8962_WRITE_SEQUENCER_223              0x10DF
+#define WM8962_WRITE_SEQUENCER_224              0x10E0
+#define WM8962_WRITE_SEQUENCER_225              0x10E1
+#define WM8962_WRITE_SEQUENCER_226              0x10E2
+#define WM8962_WRITE_SEQUENCER_227              0x10E3
+#define WM8962_WRITE_SEQUENCER_228              0x10E4
+#define WM8962_WRITE_SEQUENCER_229              0x10E5
+#define WM8962_WRITE_SEQUENCER_230              0x10E6
+#define WM8962_WRITE_SEQUENCER_231              0x10E7
+#define WM8962_WRITE_SEQUENCER_232              0x10E8
+#define WM8962_WRITE_SEQUENCER_233              0x10E9
+#define WM8962_WRITE_SEQUENCER_234              0x10EA
+#define WM8962_WRITE_SEQUENCER_235              0x10EB
+#define WM8962_WRITE_SEQUENCER_236              0x10EC
+#define WM8962_WRITE_SEQUENCER_237              0x10ED
+#define WM8962_WRITE_SEQUENCER_238              0x10EE
+#define WM8962_WRITE_SEQUENCER_239              0x10EF
+#define WM8962_WRITE_SEQUENCER_240              0x10F0
+#define WM8962_WRITE_SEQUENCER_241              0x10F1
+#define WM8962_WRITE_SEQUENCER_242              0x10F2
+#define WM8962_WRITE_SEQUENCER_243              0x10F3
+#define WM8962_WRITE_SEQUENCER_244              0x10F4
+#define WM8962_WRITE_SEQUENCER_245              0x10F5
+#define WM8962_WRITE_SEQUENCER_246              0x10F6
+#define WM8962_WRITE_SEQUENCER_247              0x10F7
+#define WM8962_WRITE_SEQUENCER_248              0x10F8
+#define WM8962_WRITE_SEQUENCER_249              0x10F9
+#define WM8962_WRITE_SEQUENCER_250              0x10FA
+#define WM8962_WRITE_SEQUENCER_251              0x10FB
+#define WM8962_WRITE_SEQUENCER_252              0x10FC
+#define WM8962_WRITE_SEQUENCER_253              0x10FD
+#define WM8962_WRITE_SEQUENCER_254              0x10FE
+#define WM8962_WRITE_SEQUENCER_255              0x10FF
+#define WM8962_WRITE_SEQUENCER_256              0x1100
+#define WM8962_WRITE_SEQUENCER_257              0x1101
+#define WM8962_WRITE_SEQUENCER_258              0x1102
+#define WM8962_WRITE_SEQUENCER_259              0x1103
+#define WM8962_WRITE_SEQUENCER_260              0x1104
+#define WM8962_WRITE_SEQUENCER_261              0x1105
+#define WM8962_WRITE_SEQUENCER_262              0x1106
+#define WM8962_WRITE_SEQUENCER_263              0x1107
+#define WM8962_WRITE_SEQUENCER_264              0x1108
+#define WM8962_WRITE_SEQUENCER_265              0x1109
+#define WM8962_WRITE_SEQUENCER_266              0x110A
+#define WM8962_WRITE_SEQUENCER_267              0x110B
+#define WM8962_WRITE_SEQUENCER_268              0x110C
+#define WM8962_WRITE_SEQUENCER_269              0x110D
+#define WM8962_WRITE_SEQUENCER_270              0x110E
+#define WM8962_WRITE_SEQUENCER_271              0x110F
+#define WM8962_WRITE_SEQUENCER_272              0x1110
+#define WM8962_WRITE_SEQUENCER_273              0x1111
+#define WM8962_WRITE_SEQUENCER_274              0x1112
+#define WM8962_WRITE_SEQUENCER_275              0x1113
+#define WM8962_WRITE_SEQUENCER_276              0x1114
+#define WM8962_WRITE_SEQUENCER_277              0x1115
+#define WM8962_WRITE_SEQUENCER_278              0x1116
+#define WM8962_WRITE_SEQUENCER_279              0x1117
+#define WM8962_WRITE_SEQUENCER_280              0x1118
+#define WM8962_WRITE_SEQUENCER_281              0x1119
+#define WM8962_WRITE_SEQUENCER_282              0x111A
+#define WM8962_WRITE_SEQUENCER_283              0x111B
+#define WM8962_WRITE_SEQUENCER_284              0x111C
+#define WM8962_WRITE_SEQUENCER_285              0x111D
+#define WM8962_WRITE_SEQUENCER_286              0x111E
+#define WM8962_WRITE_SEQUENCER_287              0x111F
+#define WM8962_WRITE_SEQUENCER_288              0x1120
+#define WM8962_WRITE_SEQUENCER_289              0x1121
+#define WM8962_WRITE_SEQUENCER_290              0x1122
+#define WM8962_WRITE_SEQUENCER_291              0x1123
+#define WM8962_WRITE_SEQUENCER_292              0x1124
+#define WM8962_WRITE_SEQUENCER_293              0x1125
+#define WM8962_WRITE_SEQUENCER_294              0x1126
+#define WM8962_WRITE_SEQUENCER_295              0x1127
+#define WM8962_WRITE_SEQUENCER_296              0x1128
+#define WM8962_WRITE_SEQUENCER_297              0x1129
+#define WM8962_WRITE_SEQUENCER_298              0x112A
+#define WM8962_WRITE_SEQUENCER_299              0x112B
+#define WM8962_WRITE_SEQUENCER_300              0x112C
+#define WM8962_WRITE_SEQUENCER_301              0x112D
+#define WM8962_WRITE_SEQUENCER_302              0x112E
+#define WM8962_WRITE_SEQUENCER_303              0x112F
+#define WM8962_WRITE_SEQUENCER_304              0x1130
+#define WM8962_WRITE_SEQUENCER_305              0x1131
+#define WM8962_WRITE_SEQUENCER_306              0x1132
+#define WM8962_WRITE_SEQUENCER_307              0x1133
+#define WM8962_WRITE_SEQUENCER_308              0x1134
+#define WM8962_WRITE_SEQUENCER_309              0x1135
+#define WM8962_WRITE_SEQUENCER_310              0x1136
+#define WM8962_WRITE_SEQUENCER_311              0x1137
+#define WM8962_WRITE_SEQUENCER_312              0x1138
+#define WM8962_WRITE_SEQUENCER_313              0x1139
+#define WM8962_WRITE_SEQUENCER_314              0x113A
+#define WM8962_WRITE_SEQUENCER_315              0x113B
+#define WM8962_WRITE_SEQUENCER_316              0x113C
+#define WM8962_WRITE_SEQUENCER_317              0x113D
+#define WM8962_WRITE_SEQUENCER_318              0x113E
+#define WM8962_WRITE_SEQUENCER_319              0x113F
+#define WM8962_WRITE_SEQUENCER_320              0x1140
+#define WM8962_WRITE_SEQUENCER_321              0x1141
+#define WM8962_WRITE_SEQUENCER_322              0x1142
+#define WM8962_WRITE_SEQUENCER_323              0x1143
+#define WM8962_WRITE_SEQUENCER_324              0x1144
+#define WM8962_WRITE_SEQUENCER_325              0x1145
+#define WM8962_WRITE_SEQUENCER_326              0x1146
+#define WM8962_WRITE_SEQUENCER_327              0x1147
+#define WM8962_WRITE_SEQUENCER_328              0x1148
+#define WM8962_WRITE_SEQUENCER_329              0x1149
+#define WM8962_WRITE_SEQUENCER_330              0x114A
+#define WM8962_WRITE_SEQUENCER_331              0x114B
+#define WM8962_WRITE_SEQUENCER_332              0x114C
+#define WM8962_WRITE_SEQUENCER_333              0x114D
+#define WM8962_WRITE_SEQUENCER_334              0x114E
+#define WM8962_WRITE_SEQUENCER_335              0x114F
+#define WM8962_WRITE_SEQUENCER_336              0x1150
+#define WM8962_WRITE_SEQUENCER_337              0x1151
+#define WM8962_WRITE_SEQUENCER_338              0x1152
+#define WM8962_WRITE_SEQUENCER_339              0x1153
+#define WM8962_WRITE_SEQUENCER_340              0x1154
+#define WM8962_WRITE_SEQUENCER_341              0x1155
+#define WM8962_WRITE_SEQUENCER_342              0x1156
+#define WM8962_WRITE_SEQUENCER_343              0x1157
+#define WM8962_WRITE_SEQUENCER_344              0x1158
+#define WM8962_WRITE_SEQUENCER_345              0x1159
+#define WM8962_WRITE_SEQUENCER_346              0x115A
+#define WM8962_WRITE_SEQUENCER_347              0x115B
+#define WM8962_WRITE_SEQUENCER_348              0x115C
+#define WM8962_WRITE_SEQUENCER_349              0x115D
+#define WM8962_WRITE_SEQUENCER_350              0x115E
+#define WM8962_WRITE_SEQUENCER_351              0x115F
+#define WM8962_WRITE_SEQUENCER_352              0x1160
+#define WM8962_WRITE_SEQUENCER_353              0x1161
+#define WM8962_WRITE_SEQUENCER_354              0x1162
+#define WM8962_WRITE_SEQUENCER_355              0x1163
+#define WM8962_WRITE_SEQUENCER_356              0x1164
+#define WM8962_WRITE_SEQUENCER_357              0x1165
+#define WM8962_WRITE_SEQUENCER_358              0x1166
+#define WM8962_WRITE_SEQUENCER_359              0x1167
+#define WM8962_WRITE_SEQUENCER_360              0x1168
+#define WM8962_WRITE_SEQUENCER_361              0x1169
+#define WM8962_WRITE_SEQUENCER_362              0x116A
+#define WM8962_WRITE_SEQUENCER_363              0x116B
+#define WM8962_WRITE_SEQUENCER_364              0x116C
+#define WM8962_WRITE_SEQUENCER_365              0x116D
+#define WM8962_WRITE_SEQUENCER_366              0x116E
+#define WM8962_WRITE_SEQUENCER_367              0x116F
+#define WM8962_WRITE_SEQUENCER_368              0x1170
+#define WM8962_WRITE_SEQUENCER_369              0x1171
+#define WM8962_WRITE_SEQUENCER_370              0x1172
+#define WM8962_WRITE_SEQUENCER_371              0x1173
+#define WM8962_WRITE_SEQUENCER_372              0x1174
+#define WM8962_WRITE_SEQUENCER_373              0x1175
+#define WM8962_WRITE_SEQUENCER_374              0x1176
+#define WM8962_WRITE_SEQUENCER_375              0x1177
+#define WM8962_WRITE_SEQUENCER_376              0x1178
+#define WM8962_WRITE_SEQUENCER_377              0x1179
+#define WM8962_WRITE_SEQUENCER_378              0x117A
+#define WM8962_WRITE_SEQUENCER_379              0x117B
+#define WM8962_WRITE_SEQUENCER_380              0x117C
+#define WM8962_WRITE_SEQUENCER_381              0x117D
+#define WM8962_WRITE_SEQUENCER_382              0x117E
+#define WM8962_WRITE_SEQUENCER_383              0x117F
+#define WM8962_WRITE_SEQUENCER_384              0x1180
+#define WM8962_WRITE_SEQUENCER_385              0x1181
+#define WM8962_WRITE_SEQUENCER_386              0x1182
+#define WM8962_WRITE_SEQUENCER_387              0x1183
+#define WM8962_WRITE_SEQUENCER_388              0x1184
+#define WM8962_WRITE_SEQUENCER_389              0x1185
+#define WM8962_WRITE_SEQUENCER_390              0x1186
+#define WM8962_WRITE_SEQUENCER_391              0x1187
+#define WM8962_WRITE_SEQUENCER_392              0x1188
+#define WM8962_WRITE_SEQUENCER_393              0x1189
+#define WM8962_WRITE_SEQUENCER_394              0x118A
+#define WM8962_WRITE_SEQUENCER_395              0x118B
+#define WM8962_WRITE_SEQUENCER_396              0x118C
+#define WM8962_WRITE_SEQUENCER_397              0x118D
+#define WM8962_WRITE_SEQUENCER_398              0x118E
+#define WM8962_WRITE_SEQUENCER_399              0x118F
+#define WM8962_WRITE_SEQUENCER_400              0x1190
+#define WM8962_WRITE_SEQUENCER_401              0x1191
+#define WM8962_WRITE_SEQUENCER_402              0x1192
+#define WM8962_WRITE_SEQUENCER_403              0x1193
+#define WM8962_WRITE_SEQUENCER_404              0x1194
+#define WM8962_WRITE_SEQUENCER_405              0x1195
+#define WM8962_WRITE_SEQUENCER_406              0x1196
+#define WM8962_WRITE_SEQUENCER_407              0x1197
+#define WM8962_WRITE_SEQUENCER_408              0x1198
+#define WM8962_WRITE_SEQUENCER_409              0x1199
+#define WM8962_WRITE_SEQUENCER_410              0x119A
+#define WM8962_WRITE_SEQUENCER_411              0x119B
+#define WM8962_WRITE_SEQUENCER_412              0x119C
+#define WM8962_WRITE_SEQUENCER_413              0x119D
+#define WM8962_WRITE_SEQUENCER_414              0x119E
+#define WM8962_WRITE_SEQUENCER_415              0x119F
+#define WM8962_WRITE_SEQUENCER_416              0x11A0
+#define WM8962_WRITE_SEQUENCER_417              0x11A1
+#define WM8962_WRITE_SEQUENCER_418              0x11A2
+#define WM8962_WRITE_SEQUENCER_419              0x11A3
+#define WM8962_WRITE_SEQUENCER_420              0x11A4
+#define WM8962_WRITE_SEQUENCER_421              0x11A5
+#define WM8962_WRITE_SEQUENCER_422              0x11A6
+#define WM8962_WRITE_SEQUENCER_423              0x11A7
+#define WM8962_WRITE_SEQUENCER_424              0x11A8
+#define WM8962_WRITE_SEQUENCER_425              0x11A9
+#define WM8962_WRITE_SEQUENCER_426              0x11AA
+#define WM8962_WRITE_SEQUENCER_427              0x11AB
+#define WM8962_WRITE_SEQUENCER_428              0x11AC
+#define WM8962_WRITE_SEQUENCER_429              0x11AD
+#define WM8962_WRITE_SEQUENCER_430              0x11AE
+#define WM8962_WRITE_SEQUENCER_431              0x11AF
+#define WM8962_WRITE_SEQUENCER_432              0x11B0
+#define WM8962_WRITE_SEQUENCER_433              0x11B1
+#define WM8962_WRITE_SEQUENCER_434              0x11B2
+#define WM8962_WRITE_SEQUENCER_435              0x11B3
+#define WM8962_WRITE_SEQUENCER_436              0x11B4
+#define WM8962_WRITE_SEQUENCER_437              0x11B5
+#define WM8962_WRITE_SEQUENCER_438              0x11B6
+#define WM8962_WRITE_SEQUENCER_439              0x11B7
+#define WM8962_WRITE_SEQUENCER_440              0x11B8
+#define WM8962_WRITE_SEQUENCER_441              0x11B9
+#define WM8962_WRITE_SEQUENCER_442              0x11BA
+#define WM8962_WRITE_SEQUENCER_443              0x11BB
+#define WM8962_WRITE_SEQUENCER_444              0x11BC
+#define WM8962_WRITE_SEQUENCER_445              0x11BD
+#define WM8962_WRITE_SEQUENCER_446              0x11BE
+#define WM8962_WRITE_SEQUENCER_447              0x11BF
+#define WM8962_WRITE_SEQUENCER_448              0x11C0
+#define WM8962_WRITE_SEQUENCER_449              0x11C1
+#define WM8962_WRITE_SEQUENCER_450              0x11C2
+#define WM8962_WRITE_SEQUENCER_451              0x11C3
+#define WM8962_WRITE_SEQUENCER_452              0x11C4
+#define WM8962_WRITE_SEQUENCER_453              0x11C5
+#define WM8962_WRITE_SEQUENCER_454              0x11C6
+#define WM8962_WRITE_SEQUENCER_455              0x11C7
+#define WM8962_WRITE_SEQUENCER_456              0x11C8
+#define WM8962_WRITE_SEQUENCER_457              0x11C9
+#define WM8962_WRITE_SEQUENCER_458              0x11CA
+#define WM8962_WRITE_SEQUENCER_459              0x11CB
+#define WM8962_WRITE_SEQUENCER_460              0x11CC
+#define WM8962_WRITE_SEQUENCER_461              0x11CD
+#define WM8962_WRITE_SEQUENCER_462              0x11CE
+#define WM8962_WRITE_SEQUENCER_463              0x11CF
+#define WM8962_WRITE_SEQUENCER_464              0x11D0
+#define WM8962_WRITE_SEQUENCER_465              0x11D1
+#define WM8962_WRITE_SEQUENCER_466              0x11D2
+#define WM8962_WRITE_SEQUENCER_467              0x11D3
+#define WM8962_WRITE_SEQUENCER_468              0x11D4
+#define WM8962_WRITE_SEQUENCER_469              0x11D5
+#define WM8962_WRITE_SEQUENCER_470              0x11D6
+#define WM8962_WRITE_SEQUENCER_471              0x11D7
+#define WM8962_WRITE_SEQUENCER_472              0x11D8
+#define WM8962_WRITE_SEQUENCER_473              0x11D9
+#define WM8962_WRITE_SEQUENCER_474              0x11DA
+#define WM8962_WRITE_SEQUENCER_475              0x11DB
+#define WM8962_WRITE_SEQUENCER_476              0x11DC
+#define WM8962_WRITE_SEQUENCER_477              0x11DD
+#define WM8962_WRITE_SEQUENCER_478              0x11DE
+#define WM8962_WRITE_SEQUENCER_479              0x11DF
+#define WM8962_WRITE_SEQUENCER_480              0x11E0
+#define WM8962_WRITE_SEQUENCER_481              0x11E1
+#define WM8962_WRITE_SEQUENCER_482              0x11E2
+#define WM8962_WRITE_SEQUENCER_483              0x11E3
+#define WM8962_WRITE_SEQUENCER_484              0x11E4
+#define WM8962_WRITE_SEQUENCER_485              0x11E5
+#define WM8962_WRITE_SEQUENCER_486              0x11E6
+#define WM8962_WRITE_SEQUENCER_487              0x11E7
+#define WM8962_WRITE_SEQUENCER_488              0x11E8
+#define WM8962_WRITE_SEQUENCER_489              0x11E9
+#define WM8962_WRITE_SEQUENCER_490              0x11EA
+#define WM8962_WRITE_SEQUENCER_491              0x11EB
+#define WM8962_WRITE_SEQUENCER_492              0x11EC
+#define WM8962_WRITE_SEQUENCER_493              0x11ED
+#define WM8962_WRITE_SEQUENCER_494              0x11EE
+#define WM8962_WRITE_SEQUENCER_495              0x11EF
+#define WM8962_WRITE_SEQUENCER_496              0x11F0
+#define WM8962_WRITE_SEQUENCER_497              0x11F1
+#define WM8962_WRITE_SEQUENCER_498              0x11F2
+#define WM8962_WRITE_SEQUENCER_499              0x11F3
+#define WM8962_WRITE_SEQUENCER_500              0x11F4
+#define WM8962_WRITE_SEQUENCER_501              0x11F5
+#define WM8962_WRITE_SEQUENCER_502              0x11F6
+#define WM8962_WRITE_SEQUENCER_503              0x11F7
+#define WM8962_WRITE_SEQUENCER_504              0x11F8
+#define WM8962_WRITE_SEQUENCER_505              0x11F9
+#define WM8962_WRITE_SEQUENCER_506              0x11FA
+#define WM8962_WRITE_SEQUENCER_507              0x11FB
+#define WM8962_WRITE_SEQUENCER_508              0x11FC
+#define WM8962_WRITE_SEQUENCER_509              0x11FD
+#define WM8962_WRITE_SEQUENCER_510              0x11FE
+#define WM8962_WRITE_SEQUENCER_511              0x11FF
+#define WM8962_DSP2_INSTRUCTION_RAM_0           0x2000
+#define WM8962_DSP2_ADDRESS_RAM_2               0x2400
+#define WM8962_DSP2_ADDRESS_RAM_1               0x2401
+#define WM8962_DSP2_ADDRESS_RAM_0               0x2402
+#define WM8962_DSP2_DATA1_RAM_1                 0x3000
+#define WM8962_DSP2_DATA1_RAM_0                 0x3001
+#define WM8962_DSP2_DATA2_RAM_1                 0x3400
+#define WM8962_DSP2_DATA2_RAM_0                 0x3401
+#define WM8962_DSP2_DATA3_RAM_1                 0x3800
+#define WM8962_DSP2_DATA3_RAM_0                 0x3801
+#define WM8962_DSP2_COEFF_RAM_0                 0x3C00
+#define WM8962_RETUNEADC_SHARED_COEFF_1         0x4000
+#define WM8962_RETUNEADC_SHARED_COEFF_0         0x4001
+#define WM8962_RETUNEDAC_SHARED_COEFF_1         0x4002
+#define WM8962_RETUNEDAC_SHARED_COEFF_0         0x4003
+#define WM8962_SOUNDSTAGE_ENABLES_1             0x4004
+#define WM8962_SOUNDSTAGE_ENABLES_0             0x4005
+#define WM8962_HDBASS_AI_1                      0x4200
+#define WM8962_HDBASS_AI_0                      0x4201
+#define WM8962_HDBASS_AR_1                      0x4202
+#define WM8962_HDBASS_AR_0                      0x4203
+#define WM8962_HDBASS_B_1                       0x4204
+#define WM8962_HDBASS_B_0                       0x4205
+#define WM8962_HDBASS_K_1                       0x4206
+#define WM8962_HDBASS_K_0                       0x4207
+#define WM8962_HDBASS_N1_1                      0x4208
+#define WM8962_HDBASS_N1_0                      0x4209
+#define WM8962_HDBASS_N2_1                      0x420A
+#define WM8962_HDBASS_N2_0                      0x420B
+#define WM8962_HDBASS_N3_1                      0x420C
+#define WM8962_HDBASS_N3_0                      0x420D
+#define WM8962_HDBASS_N4_1                      0x420E
+#define WM8962_HDBASS_N4_0                      0x420F
+#define WM8962_HDBASS_N5_1                      0x4210
+#define WM8962_HDBASS_N5_0                      0x4211
+#define WM8962_HDBASS_X1_1                      0x4212
+#define WM8962_HDBASS_X1_0                      0x4213
+#define WM8962_HDBASS_X2_1                      0x4214
+#define WM8962_HDBASS_X2_0                      0x4215
+#define WM8962_HDBASS_X3_1                      0x4216
+#define WM8962_HDBASS_X3_0                      0x4217
+#define WM8962_HDBASS_ATK_1                     0x4218
+#define WM8962_HDBASS_ATK_0                     0x4219
+#define WM8962_HDBASS_DCY_1                     0x421A
+#define WM8962_HDBASS_DCY_0                     0x421B
+#define WM8962_HDBASS_PG_1                      0x421C
+#define WM8962_HDBASS_PG_0                      0x421D
+#define WM8962_HPF_C_1                          0x4400
+#define WM8962_HPF_C_0                          0x4401
+#define WM8962_ADCL_RETUNE_C1_1                 0x4600
+#define WM8962_ADCL_RETUNE_C1_0                 0x4601
+#define WM8962_ADCL_RETUNE_C2_1                 0x4602
+#define WM8962_ADCL_RETUNE_C2_0                 0x4603
+#define WM8962_ADCL_RETUNE_C3_1                 0x4604
+#define WM8962_ADCL_RETUNE_C3_0                 0x4605
+#define WM8962_ADCL_RETUNE_C4_1                 0x4606
+#define WM8962_ADCL_RETUNE_C4_0                 0x4607
+#define WM8962_ADCL_RETUNE_C5_1                 0x4608
+#define WM8962_ADCL_RETUNE_C5_0                 0x4609
+#define WM8962_ADCL_RETUNE_C6_1                 0x460A
+#define WM8962_ADCL_RETUNE_C6_0                 0x460B
+#define WM8962_ADCL_RETUNE_C7_1                 0x460C
+#define WM8962_ADCL_RETUNE_C7_0                 0x460D
+#define WM8962_ADCL_RETUNE_C8_1                 0x460E
+#define WM8962_ADCL_RETUNE_C8_0                 0x460F
+#define WM8962_ADCL_RETUNE_C9_1                 0x4610
+#define WM8962_ADCL_RETUNE_C9_0                 0x4611
+#define WM8962_ADCL_RETUNE_C10_1                0x4612
+#define WM8962_ADCL_RETUNE_C10_0                0x4613
+#define WM8962_ADCL_RETUNE_C11_1                0x4614
+#define WM8962_ADCL_RETUNE_C11_0                0x4615
+#define WM8962_ADCL_RETUNE_C12_1                0x4616
+#define WM8962_ADCL_RETUNE_C12_0                0x4617
+#define WM8962_ADCL_RETUNE_C13_1                0x4618
+#define WM8962_ADCL_RETUNE_C13_0                0x4619
+#define WM8962_ADCL_RETUNE_C14_1                0x461A
+#define WM8962_ADCL_RETUNE_C14_0                0x461B
+#define WM8962_ADCL_RETUNE_C15_1                0x461C
+#define WM8962_ADCL_RETUNE_C15_0                0x461D
+#define WM8962_ADCL_RETUNE_C16_1                0x461E
+#define WM8962_ADCL_RETUNE_C16_0                0x461F
+#define WM8962_ADCL_RETUNE_C17_1                0x4620
+#define WM8962_ADCL_RETUNE_C17_0                0x4621
+#define WM8962_ADCL_RETUNE_C18_1                0x4622
+#define WM8962_ADCL_RETUNE_C18_0                0x4623
+#define WM8962_ADCL_RETUNE_C19_1                0x4624
+#define WM8962_ADCL_RETUNE_C19_0                0x4625
+#define WM8962_ADCL_RETUNE_C20_1                0x4626
+#define WM8962_ADCL_RETUNE_C20_0                0x4627
+#define WM8962_ADCL_RETUNE_C21_1                0x4628
+#define WM8962_ADCL_RETUNE_C21_0                0x4629
+#define WM8962_ADCL_RETUNE_C22_1                0x462A
+#define WM8962_ADCL_RETUNE_C22_0                0x462B
+#define WM8962_ADCL_RETUNE_C23_1                0x462C
+#define WM8962_ADCL_RETUNE_C23_0                0x462D
+#define WM8962_ADCL_RETUNE_C24_1                0x462E
+#define WM8962_ADCL_RETUNE_C24_0                0x462F
+#define WM8962_ADCL_RETUNE_C25_1                0x4630
+#define WM8962_ADCL_RETUNE_C25_0                0x4631
+#define WM8962_ADCL_RETUNE_C26_1                0x4632
+#define WM8962_ADCL_RETUNE_C26_0                0x4633
+#define WM8962_ADCL_RETUNE_C27_1                0x4634
+#define WM8962_ADCL_RETUNE_C27_0                0x4635
+#define WM8962_ADCL_RETUNE_C28_1                0x4636
+#define WM8962_ADCL_RETUNE_C28_0                0x4637
+#define WM8962_ADCL_RETUNE_C29_1                0x4638
+#define WM8962_ADCL_RETUNE_C29_0                0x4639
+#define WM8962_ADCL_RETUNE_C30_1                0x463A
+#define WM8962_ADCL_RETUNE_C30_0                0x463B
+#define WM8962_ADCL_RETUNE_C31_1                0x463C
+#define WM8962_ADCL_RETUNE_C31_0                0x463D
+#define WM8962_ADCL_RETUNE_C32_1                0x463E
+#define WM8962_ADCL_RETUNE_C32_0                0x463F
+#define WM8962_RETUNEADC_PG2_1                  0x4800
+#define WM8962_RETUNEADC_PG2_0                  0x4801
+#define WM8962_RETUNEADC_PG_1                   0x4802
+#define WM8962_RETUNEADC_PG_0                   0x4803
+#define WM8962_ADCR_RETUNE_C1_1                 0x4A00
+#define WM8962_ADCR_RETUNE_C1_0                 0x4A01
+#define WM8962_ADCR_RETUNE_C2_1                 0x4A02
+#define WM8962_ADCR_RETUNE_C2_0                 0x4A03
+#define WM8962_ADCR_RETUNE_C3_1                 0x4A04
+#define WM8962_ADCR_RETUNE_C3_0                 0x4A05
+#define WM8962_ADCR_RETUNE_C4_1                 0x4A06
+#define WM8962_ADCR_RETUNE_C4_0                 0x4A07
+#define WM8962_ADCR_RETUNE_C5_1                 0x4A08
+#define WM8962_ADCR_RETUNE_C5_0                 0x4A09
+#define WM8962_ADCR_RETUNE_C6_1                 0x4A0A
+#define WM8962_ADCR_RETUNE_C6_0                 0x4A0B
+#define WM8962_ADCR_RETUNE_C7_1                 0x4A0C
+#define WM8962_ADCR_RETUNE_C7_0                 0x4A0D
+#define WM8962_ADCR_RETUNE_C8_1                 0x4A0E
+#define WM8962_ADCR_RETUNE_C8_0                 0x4A0F
+#define WM8962_ADCR_RETUNE_C9_1                 0x4A10
+#define WM8962_ADCR_RETUNE_C9_0                 0x4A11
+#define WM8962_ADCR_RETUNE_C10_1                0x4A12
+#define WM8962_ADCR_RETUNE_C10_0                0x4A13
+#define WM8962_ADCR_RETUNE_C11_1                0x4A14
+#define WM8962_ADCR_RETUNE_C11_0                0x4A15
+#define WM8962_ADCR_RETUNE_C12_1                0x4A16
+#define WM8962_ADCR_RETUNE_C12_0                0x4A17
+#define WM8962_ADCR_RETUNE_C13_1                0x4A18
+#define WM8962_ADCR_RETUNE_C13_0                0x4A19
+#define WM8962_ADCR_RETUNE_C14_1                0x4A1A
+#define WM8962_ADCR_RETUNE_C14_0                0x4A1B
+#define WM8962_ADCR_RETUNE_C15_1                0x4A1C
+#define WM8962_ADCR_RETUNE_C15_0                0x4A1D
+#define WM8962_ADCR_RETUNE_C16_1                0x4A1E
+#define WM8962_ADCR_RETUNE_C16_0                0x4A1F
+#define WM8962_ADCR_RETUNE_C17_1                0x4A20
+#define WM8962_ADCR_RETUNE_C17_0                0x4A21
+#define WM8962_ADCR_RETUNE_C18_1                0x4A22
+#define WM8962_ADCR_RETUNE_C18_0                0x4A23
+#define WM8962_ADCR_RETUNE_C19_1                0x4A24
+#define WM8962_ADCR_RETUNE_C19_0                0x4A25
+#define WM8962_ADCR_RETUNE_C20_1                0x4A26
+#define WM8962_ADCR_RETUNE_C20_0                0x4A27
+#define WM8962_ADCR_RETUNE_C21_1                0x4A28
+#define WM8962_ADCR_RETUNE_C21_0                0x4A29
+#define WM8962_ADCR_RETUNE_C22_1                0x4A2A
+#define WM8962_ADCR_RETUNE_C22_0                0x4A2B
+#define WM8962_ADCR_RETUNE_C23_1                0x4A2C
+#define WM8962_ADCR_RETUNE_C23_0                0x4A2D
+#define WM8962_ADCR_RETUNE_C24_1                0x4A2E
+#define WM8962_ADCR_RETUNE_C24_0                0x4A2F
+#define WM8962_ADCR_RETUNE_C25_1                0x4A30
+#define WM8962_ADCR_RETUNE_C25_0                0x4A31
+#define WM8962_ADCR_RETUNE_C26_1                0x4A32
+#define WM8962_ADCR_RETUNE_C26_0                0x4A33
+#define WM8962_ADCR_RETUNE_C27_1                0x4A34
+#define WM8962_ADCR_RETUNE_C27_0                0x4A35
+#define WM8962_ADCR_RETUNE_C28_1                0x4A36
+#define WM8962_ADCR_RETUNE_C28_0                0x4A37
+#define WM8962_ADCR_RETUNE_C29_1                0x4A38
+#define WM8962_ADCR_RETUNE_C29_0                0x4A39
+#define WM8962_ADCR_RETUNE_C30_1                0x4A3A
+#define WM8962_ADCR_RETUNE_C30_0                0x4A3B
+#define WM8962_ADCR_RETUNE_C31_1                0x4A3C
+#define WM8962_ADCR_RETUNE_C31_0                0x4A3D
+#define WM8962_ADCR_RETUNE_C32_1                0x4A3E
+#define WM8962_ADCR_RETUNE_C32_0                0x4A3F
+#define WM8962_DACL_RETUNE_C1_1                 0x4C00
+#define WM8962_DACL_RETUNE_C1_0                 0x4C01
+#define WM8962_DACL_RETUNE_C2_1                 0x4C02
+#define WM8962_DACL_RETUNE_C2_0                 0x4C03
+#define WM8962_DACL_RETUNE_C3_1                 0x4C04
+#define WM8962_DACL_RETUNE_C3_0                 0x4C05
+#define WM8962_DACL_RETUNE_C4_1                 0x4C06
+#define WM8962_DACL_RETUNE_C4_0                 0x4C07
+#define WM8962_DACL_RETUNE_C5_1                 0x4C08
+#define WM8962_DACL_RETUNE_C5_0                 0x4C09
+#define WM8962_DACL_RETUNE_C6_1                 0x4C0A
+#define WM8962_DACL_RETUNE_C6_0                 0x4C0B
+#define WM8962_DACL_RETUNE_C7_1                 0x4C0C
+#define WM8962_DACL_RETUNE_C7_0                 0x4C0D
+#define WM8962_DACL_RETUNE_C8_1                 0x4C0E
+#define WM8962_DACL_RETUNE_C8_0                 0x4C0F
+#define WM8962_DACL_RETUNE_C9_1                 0x4C10
+#define WM8962_DACL_RETUNE_C9_0                 0x4C11
+#define WM8962_DACL_RETUNE_C10_1                0x4C12
+#define WM8962_DACL_RETUNE_C10_0                0x4C13
+#define WM8962_DACL_RETUNE_C11_1                0x4C14
+#define WM8962_DACL_RETUNE_C11_0                0x4C15
+#define WM8962_DACL_RETUNE_C12_1                0x4C16
+#define WM8962_DACL_RETUNE_C12_0                0x4C17
+#define WM8962_DACL_RETUNE_C13_1                0x4C18
+#define WM8962_DACL_RETUNE_C13_0                0x4C19
+#define WM8962_DACL_RETUNE_C14_1                0x4C1A
+#define WM8962_DACL_RETUNE_C14_0                0x4C1B
+#define WM8962_DACL_RETUNE_C15_1                0x4C1C
+#define WM8962_DACL_RETUNE_C15_0                0x4C1D
+#define WM8962_DACL_RETUNE_C16_1                0x4C1E
+#define WM8962_DACL_RETUNE_C16_0                0x4C1F
+#define WM8962_DACL_RETUNE_C17_1                0x4C20
+#define WM8962_DACL_RETUNE_C17_0                0x4C21
+#define WM8962_DACL_RETUNE_C18_1                0x4C22
+#define WM8962_DACL_RETUNE_C18_0                0x4C23
+#define WM8962_DACL_RETUNE_C19_1                0x4C24
+#define WM8962_DACL_RETUNE_C19_0                0x4C25
+#define WM8962_DACL_RETUNE_C20_1                0x4C26
+#define WM8962_DACL_RETUNE_C20_0                0x4C27
+#define WM8962_DACL_RETUNE_C21_1                0x4C28
+#define WM8962_DACL_RETUNE_C21_0                0x4C29
+#define WM8962_DACL_RETUNE_C22_1                0x4C2A
+#define WM8962_DACL_RETUNE_C22_0                0x4C2B
+#define WM8962_DACL_RETUNE_C23_1                0x4C2C
+#define WM8962_DACL_RETUNE_C23_0                0x4C2D
+#define WM8962_DACL_RETUNE_C24_1                0x4C2E
+#define WM8962_DACL_RETUNE_C24_0                0x4C2F
+#define WM8962_DACL_RETUNE_C25_1                0x4C30
+#define WM8962_DACL_RETUNE_C25_0                0x4C31
+#define WM8962_DACL_RETUNE_C26_1                0x4C32
+#define WM8962_DACL_RETUNE_C26_0                0x4C33
+#define WM8962_DACL_RETUNE_C27_1                0x4C34
+#define WM8962_DACL_RETUNE_C27_0                0x4C35
+#define WM8962_DACL_RETUNE_C28_1                0x4C36
+#define WM8962_DACL_RETUNE_C28_0                0x4C37
+#define WM8962_DACL_RETUNE_C29_1                0x4C38
+#define WM8962_DACL_RETUNE_C29_0                0x4C39
+#define WM8962_DACL_RETUNE_C30_1                0x4C3A
+#define WM8962_DACL_RETUNE_C30_0                0x4C3B
+#define WM8962_DACL_RETUNE_C31_1                0x4C3C
+#define WM8962_DACL_RETUNE_C31_0                0x4C3D
+#define WM8962_DACL_RETUNE_C32_1                0x4C3E
+#define WM8962_DACL_RETUNE_C32_0                0x4C3F
+#define WM8962_RETUNEDAC_PG2_1                  0x4E00
+#define WM8962_RETUNEDAC_PG2_0                  0x4E01
+#define WM8962_RETUNEDAC_PG_1                   0x4E02
+#define WM8962_RETUNEDAC_PG_0                   0x4E03
+#define WM8962_DACR_RETUNE_C1_1                 0x5000
+#define WM8962_DACR_RETUNE_C1_0                 0x5001
+#define WM8962_DACR_RETUNE_C2_1                 0x5002
+#define WM8962_DACR_RETUNE_C2_0                 0x5003
+#define WM8962_DACR_RETUNE_C3_1                 0x5004
+#define WM8962_DACR_RETUNE_C3_0                 0x5005
+#define WM8962_DACR_RETUNE_C4_1                 0x5006
+#define WM8962_DACR_RETUNE_C4_0                 0x5007
+#define WM8962_DACR_RETUNE_C5_1                 0x5008
+#define WM8962_DACR_RETUNE_C5_0                 0x5009
+#define WM8962_DACR_RETUNE_C6_1                 0x500A
+#define WM8962_DACR_RETUNE_C6_0                 0x500B
+#define WM8962_DACR_RETUNE_C7_1                 0x500C
+#define WM8962_DACR_RETUNE_C7_0                 0x500D
+#define WM8962_DACR_RETUNE_C8_1                 0x500E
+#define WM8962_DACR_RETUNE_C8_0                 0x500F
+#define WM8962_DACR_RETUNE_C9_1                 0x5010
+#define WM8962_DACR_RETUNE_C9_0                 0x5011
+#define WM8962_DACR_RETUNE_C10_1                0x5012
+#define WM8962_DACR_RETUNE_C10_0                0x5013
+#define WM8962_DACR_RETUNE_C11_1                0x5014
+#define WM8962_DACR_RETUNE_C11_0                0x5015
+#define WM8962_DACR_RETUNE_C12_1                0x5016
+#define WM8962_DACR_RETUNE_C12_0                0x5017
+#define WM8962_DACR_RETUNE_C13_1                0x5018
+#define WM8962_DACR_RETUNE_C13_0                0x5019
+#define WM8962_DACR_RETUNE_C14_1                0x501A
+#define WM8962_DACR_RETUNE_C14_0                0x501B
+#define WM8962_DACR_RETUNE_C15_1                0x501C
+#define WM8962_DACR_RETUNE_C15_0                0x501D
+#define WM8962_DACR_RETUNE_C16_1                0x501E
+#define WM8962_DACR_RETUNE_C16_0                0x501F
+#define WM8962_DACR_RETUNE_C17_1                0x5020
+#define WM8962_DACR_RETUNE_C17_0                0x5021
+#define WM8962_DACR_RETUNE_C18_1                0x5022
+#define WM8962_DACR_RETUNE_C18_0                0x5023
+#define WM8962_DACR_RETUNE_C19_1                0x5024
+#define WM8962_DACR_RETUNE_C19_0                0x5025
+#define WM8962_DACR_RETUNE_C20_1                0x5026
+#define WM8962_DACR_RETUNE_C20_0                0x5027
+#define WM8962_DACR_RETUNE_C21_1                0x5028
+#define WM8962_DACR_RETUNE_C21_0                0x5029
+#define WM8962_DACR_RETUNE_C22_1                0x502A
+#define WM8962_DACR_RETUNE_C22_0                0x502B
+#define WM8962_DACR_RETUNE_C23_1                0x502C
+#define WM8962_DACR_RETUNE_C23_0                0x502D
+#define WM8962_DACR_RETUNE_C24_1                0x502E
+#define WM8962_DACR_RETUNE_C24_0                0x502F
+#define WM8962_DACR_RETUNE_C25_1                0x5030
+#define WM8962_DACR_RETUNE_C25_0                0x5031
+#define WM8962_DACR_RETUNE_C26_1                0x5032
+#define WM8962_DACR_RETUNE_C26_0                0x5033
+#define WM8962_DACR_RETUNE_C27_1                0x5034
+#define WM8962_DACR_RETUNE_C27_0                0x5035
+#define WM8962_DACR_RETUNE_C28_1                0x5036
+#define WM8962_DACR_RETUNE_C28_0                0x5037
+#define WM8962_DACR_RETUNE_C29_1                0x5038
+#define WM8962_DACR_RETUNE_C29_0                0x5039
+#define WM8962_DACR_RETUNE_C30_1                0x503A
+#define WM8962_DACR_RETUNE_C30_0                0x503B
+#define WM8962_DACR_RETUNE_C31_1                0x503C
+#define WM8962_DACR_RETUNE_C31_0                0x503D
+#define WM8962_DACR_RETUNE_C32_1                0x503E
+#define WM8962_DACR_RETUNE_C32_0                0x503F
+#define WM8962_VSS_XHD2_1                       0x5200
+#define WM8962_VSS_XHD2_0                       0x5201
+#define WM8962_VSS_XHD3_1                       0x5202
+#define WM8962_VSS_XHD3_0                       0x5203
+#define WM8962_VSS_XHN1_1                       0x5204
+#define WM8962_VSS_XHN1_0                       0x5205
+#define WM8962_VSS_XHN2_1                       0x5206
+#define WM8962_VSS_XHN2_0                       0x5207
+#define WM8962_VSS_XHN3_1                       0x5208
+#define WM8962_VSS_XHN3_0                       0x5209
+#define WM8962_VSS_XLA_1                        0x520A
+#define WM8962_VSS_XLA_0                        0x520B
+#define WM8962_VSS_XLB_1                        0x520C
+#define WM8962_VSS_XLB_0                        0x520D
+#define WM8962_VSS_XLG_1                        0x520E
+#define WM8962_VSS_XLG_0                        0x520F
+#define WM8962_VSS_PG2_1                        0x5210
+#define WM8962_VSS_PG2_0                        0x5211
+#define WM8962_VSS_PG_1                         0x5212
+#define WM8962_VSS_PG_0                         0x5213
+#define WM8962_VSS_XTD1_1                       0x5214
+#define WM8962_VSS_XTD1_0                       0x5215
+#define WM8962_VSS_XTD2_1                       0x5216
+#define WM8962_VSS_XTD2_0                       0x5217
+#define WM8962_VSS_XTD3_1                       0x5218
+#define WM8962_VSS_XTD3_0                       0x5219
+#define WM8962_VSS_XTD4_1                       0x521A
+#define WM8962_VSS_XTD4_0                       0x521B
+#define WM8962_VSS_XTD5_1                       0x521C
+#define WM8962_VSS_XTD5_0                       0x521D
+#define WM8962_VSS_XTD6_1                       0x521E
+#define WM8962_VSS_XTD6_0                       0x521F
+#define WM8962_VSS_XTD7_1                       0x5220
+#define WM8962_VSS_XTD7_0                       0x5221
+#define WM8962_VSS_XTD8_1                       0x5222
+#define WM8962_VSS_XTD8_0                       0x5223
+#define WM8962_VSS_XTD9_1                       0x5224
+#define WM8962_VSS_XTD9_0                       0x5225
+#define WM8962_VSS_XTD10_1                      0x5226
+#define WM8962_VSS_XTD10_0                      0x5227
+#define WM8962_VSS_XTD11_1                      0x5228
+#define WM8962_VSS_XTD11_0                      0x5229
+#define WM8962_VSS_XTD12_1                      0x522A
+#define WM8962_VSS_XTD12_0                      0x522B
+#define WM8962_VSS_XTD13_1                      0x522C
+#define WM8962_VSS_XTD13_0                      0x522D
+#define WM8962_VSS_XTD14_1                      0x522E
+#define WM8962_VSS_XTD14_0                      0x522F
+#define WM8962_VSS_XTD15_1                      0x5230
+#define WM8962_VSS_XTD15_0                      0x5231
+#define WM8962_VSS_XTD16_1                      0x5232
+#define WM8962_VSS_XTD16_0                      0x5233
+#define WM8962_VSS_XTD17_1                      0x5234
+#define WM8962_VSS_XTD17_0                      0x5235
+#define WM8962_VSS_XTD18_1                      0x5236
+#define WM8962_VSS_XTD18_0                      0x5237
+#define WM8962_VSS_XTD19_1                      0x5238
+#define WM8962_VSS_XTD19_0                      0x5239
+#define WM8962_VSS_XTD20_1                      0x523A
+#define WM8962_VSS_XTD20_0                      0x523B
+#define WM8962_VSS_XTD21_1                      0x523C
+#define WM8962_VSS_XTD21_0                      0x523D
+#define WM8962_VSS_XTD22_1                      0x523E
+#define WM8962_VSS_XTD22_0                      0x523F
+#define WM8962_VSS_XTD23_1                      0x5240
+#define WM8962_VSS_XTD23_0                      0x5241
+#define WM8962_VSS_XTD24_1                      0x5242
+#define WM8962_VSS_XTD24_0                      0x5243
+#define WM8962_VSS_XTD25_1                      0x5244
+#define WM8962_VSS_XTD25_0                      0x5245
+#define WM8962_VSS_XTD26_1                      0x5246
+#define WM8962_VSS_XTD26_0                      0x5247
+#define WM8962_VSS_XTD27_1                      0x5248
+#define WM8962_VSS_XTD27_0                      0x5249
+#define WM8962_VSS_XTD28_1                      0x524A
+#define WM8962_VSS_XTD28_0                      0x524B
+#define WM8962_VSS_XTD29_1                      0x524C
+#define WM8962_VSS_XTD29_0                      0x524D
+#define WM8962_VSS_XTD30_1                      0x524E
+#define WM8962_VSS_XTD30_0                      0x524F
+#define WM8962_VSS_XTD31_1                      0x5250
+#define WM8962_VSS_XTD31_0                      0x5251
+#define WM8962_VSS_XTD32_1                      0x5252
+#define WM8962_VSS_XTD32_0                      0x5253
+#define WM8962_VSS_XTS1_1                       0x5254
+#define WM8962_VSS_XTS1_0                       0x5255
+#define WM8962_VSS_XTS2_1                       0x5256
+#define WM8962_VSS_XTS2_0                       0x5257
+#define WM8962_VSS_XTS3_1                       0x5258
+#define WM8962_VSS_XTS3_0                       0x5259
+#define WM8962_VSS_XTS4_1                       0x525A
+#define WM8962_VSS_XTS4_0                       0x525B
+#define WM8962_VSS_XTS5_1                       0x525C
+#define WM8962_VSS_XTS5_0                       0x525D
+#define WM8962_VSS_XTS6_1                       0x525E
+#define WM8962_VSS_XTS6_0                       0x525F
+#define WM8962_VSS_XTS7_1                       0x5260
+#define WM8962_VSS_XTS7_0                       0x5261
+#define WM8962_VSS_XTS8_1                       0x5262
+#define WM8962_VSS_XTS8_0                       0x5263
+#define WM8962_VSS_XTS9_1                       0x5264
+#define WM8962_VSS_XTS9_0                       0x5265
+#define WM8962_VSS_XTS10_1                      0x5266
+#define WM8962_VSS_XTS10_0                      0x5267
+#define WM8962_VSS_XTS11_1                      0x5268
+#define WM8962_VSS_XTS11_0                      0x5269
+#define WM8962_VSS_XTS12_1                      0x526A
+#define WM8962_VSS_XTS12_0                      0x526B
+#define WM8962_VSS_XTS13_1                      0x526C
+#define WM8962_VSS_XTS13_0                      0x526D
+#define WM8962_VSS_XTS14_1                      0x526E
+#define WM8962_VSS_XTS14_0                      0x526F
+#define WM8962_VSS_XTS15_1                      0x5270
+#define WM8962_VSS_XTS15_0                      0x5271
+#define WM8962_VSS_XTS16_1                      0x5272
+#define WM8962_VSS_XTS16_0                      0x5273
+#define WM8962_VSS_XTS17_1                      0x5274
+#define WM8962_VSS_XTS17_0                      0x5275
+#define WM8962_VSS_XTS18_1                      0x5276
+#define WM8962_VSS_XTS18_0                      0x5277
+#define WM8962_VSS_XTS19_1                      0x5278
+#define WM8962_VSS_XTS19_0                      0x5279
+#define WM8962_VSS_XTS20_1                      0x527A
+#define WM8962_VSS_XTS20_0                      0x527B
+#define WM8962_VSS_XTS21_1                      0x527C
+#define WM8962_VSS_XTS21_0                      0x527D
+#define WM8962_VSS_XTS22_1                      0x527E
+#define WM8962_VSS_XTS22_0                      0x527F
+#define WM8962_VSS_XTS23_1                      0x5280
+#define WM8962_VSS_XTS23_0                      0x5281
+#define WM8962_VSS_XTS24_1                      0x5282
+#define WM8962_VSS_XTS24_0                      0x5283
+#define WM8962_VSS_XTS25_1                      0x5284
+#define WM8962_VSS_XTS25_0                      0x5285
+#define WM8962_VSS_XTS26_1                      0x5286
+#define WM8962_VSS_XTS26_0                      0x5287
+#define WM8962_VSS_XTS27_1                      0x5288
+#define WM8962_VSS_XTS27_0                      0x5289
+#define WM8962_VSS_XTS28_1                      0x528A
+#define WM8962_VSS_XTS28_0                      0x528B
+#define WM8962_VSS_XTS29_1                      0x528C
+#define WM8962_VSS_XTS29_0                      0x528D
+#define WM8962_VSS_XTS30_1                      0x528E
+#define WM8962_VSS_XTS30_0                      0x528F
+#define WM8962_VSS_XTS31_1                      0x5290
+#define WM8962_VSS_XTS31_0                      0x5291
+#define WM8962_VSS_XTS32_1                      0x5292
+#define WM8962_VSS_XTS32_0                      0x5293
+
+#define WM8962_REGISTER_COUNT                   1138
+#define WM8962_MAX_REGISTER                     0x5293
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Left Input volume
+ */
+#define WM8962_IN_VU                            0x0100  /* IN_VU */
+#define WM8962_IN_VU_MASK                       0x0100  /* IN_VU */
+#define WM8962_IN_VU_SHIFT                           8  /* IN_VU */
+#define WM8962_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM8962_INPGAL_MUTE                      0x0080  /* INPGAL_MUTE */
+#define WM8962_INPGAL_MUTE_MASK                 0x0080  /* INPGAL_MUTE */
+#define WM8962_INPGAL_MUTE_SHIFT                     7  /* INPGAL_MUTE */
+#define WM8962_INPGAL_MUTE_WIDTH                     1  /* INPGAL_MUTE */
+#define WM8962_INL_ZC                           0x0040  /* INL_ZC */
+#define WM8962_INL_ZC_MASK                      0x0040  /* INL_ZC */
+#define WM8962_INL_ZC_SHIFT                          6  /* INL_ZC */
+#define WM8962_INL_ZC_WIDTH                          1  /* INL_ZC */
+#define WM8962_INL_VOL_MASK                     0x003F  /* INL_VOL - [5:0] */
+#define WM8962_INL_VOL_SHIFT                         0  /* INL_VOL - [5:0] */
+#define WM8962_INL_VOL_WIDTH                         6  /* INL_VOL - [5:0] */
+
+/*
+ * R1 (0x01) - Right Input volume
+ */
+#define WM8962_CUST_ID_MASK                     0xF000  /* CUST_ID - [15:12] */
+#define WM8962_CUST_ID_SHIFT                        12  /* CUST_ID - [15:12] */
+#define WM8962_CUST_ID_WIDTH                         4  /* CUST_ID - [15:12] */
+#define WM8962_CHIP_REV_MASK                    0x0E00  /* CHIP_REV - [11:9] */
+#define WM8962_CHIP_REV_SHIFT                        9  /* CHIP_REV - [11:9] */
+#define WM8962_CHIP_REV_WIDTH                        3  /* CHIP_REV - [11:9] */
+#define WM8962_IN_VU                            0x0100  /* IN_VU */
+#define WM8962_IN_VU_MASK                       0x0100  /* IN_VU */
+#define WM8962_IN_VU_SHIFT                           8  /* IN_VU */
+#define WM8962_IN_VU_WIDTH                           1  /* IN_VU */
+#define WM8962_INPGAR_MUTE                      0x0080  /* INPGAR_MUTE */
+#define WM8962_INPGAR_MUTE_MASK                 0x0080  /* INPGAR_MUTE */
+#define WM8962_INPGAR_MUTE_SHIFT                     7  /* INPGAR_MUTE */
+#define WM8962_INPGAR_MUTE_WIDTH                     1  /* INPGAR_MUTE */
+#define WM8962_INR_ZC                           0x0040  /* INR_ZC */
+#define WM8962_INR_ZC_MASK                      0x0040  /* INR_ZC */
+#define WM8962_INR_ZC_SHIFT                          6  /* INR_ZC */
+#define WM8962_INR_ZC_WIDTH                          1  /* INR_ZC */
+#define WM8962_INR_VOL_MASK                     0x003F  /* INR_VOL - [5:0] */
+#define WM8962_INR_VOL_SHIFT                         0  /* INR_VOL - [5:0] */
+#define WM8962_INR_VOL_WIDTH                         6  /* INR_VOL - [5:0] */
+
+/*
+ * R2 (0x02) - HPOUTL volume
+ */
+#define WM8962_HPOUT_VU                         0x0100  /* HPOUT_VU */
+#define WM8962_HPOUT_VU_MASK                    0x0100  /* HPOUT_VU */
+#define WM8962_HPOUT_VU_SHIFT                        8  /* HPOUT_VU */
+#define WM8962_HPOUT_VU_WIDTH                        1  /* HPOUT_VU */
+#define WM8962_HPOUTL_ZC                        0x0080  /* HPOUTL_ZC */
+#define WM8962_HPOUTL_ZC_MASK                   0x0080  /* HPOUTL_ZC */
+#define WM8962_HPOUTL_ZC_SHIFT                       7  /* HPOUTL_ZC */
+#define WM8962_HPOUTL_ZC_WIDTH                       1  /* HPOUTL_ZC */
+#define WM8962_HPOUTL_VOL_MASK                  0x007F  /* HPOUTL_VOL - [6:0] */
+#define WM8962_HPOUTL_VOL_SHIFT                      0  /* HPOUTL_VOL - [6:0] */
+#define WM8962_HPOUTL_VOL_WIDTH                      7  /* HPOUTL_VOL - [6:0] */
+
+/*
+ * R3 (0x03) - HPOUTR volume
+ */
+#define WM8962_HPOUT_VU                         0x0100  /* HPOUT_VU */
+#define WM8962_HPOUT_VU_MASK                    0x0100  /* HPOUT_VU */
+#define WM8962_HPOUT_VU_SHIFT                        8  /* HPOUT_VU */
+#define WM8962_HPOUT_VU_WIDTH                        1  /* HPOUT_VU */
+#define WM8962_HPOUTR_ZC                        0x0080  /* HPOUTR_ZC */
+#define WM8962_HPOUTR_ZC_MASK                   0x0080  /* HPOUTR_ZC */
+#define WM8962_HPOUTR_ZC_SHIFT                       7  /* HPOUTR_ZC */
+#define WM8962_HPOUTR_ZC_WIDTH                       1  /* HPOUTR_ZC */
+#define WM8962_HPOUTR_VOL_MASK                  0x007F  /* HPOUTR_VOL - [6:0] */
+#define WM8962_HPOUTR_VOL_SHIFT                      0  /* HPOUTR_VOL - [6:0] */
+#define WM8962_HPOUTR_VOL_WIDTH                      7  /* HPOUTR_VOL - [6:0] */
+
+/*
+ * R4 (0x04) - Clocking1
+ */
+#define WM8962_DSPCLK_DIV_MASK                  0x0600  /* DSPCLK_DIV - [10:9] */
+#define WM8962_DSPCLK_DIV_SHIFT                      9  /* DSPCLK_DIV - [10:9] */
+#define WM8962_DSPCLK_DIV_WIDTH                      2  /* DSPCLK_DIV - [10:9] */
+#define WM8962_ADCSYS_CLK_DIV_MASK              0x01C0  /* ADCSYS_CLK_DIV - [8:6] */
+#define WM8962_ADCSYS_CLK_DIV_SHIFT                  6  /* ADCSYS_CLK_DIV - [8:6] */
+#define WM8962_ADCSYS_CLK_DIV_WIDTH                  3  /* ADCSYS_CLK_DIV - [8:6] */
+#define WM8962_DACSYS_CLK_DIV_MASK              0x0038  /* DACSYS_CLK_DIV - [5:3] */
+#define WM8962_DACSYS_CLK_DIV_SHIFT                  3  /* DACSYS_CLK_DIV - [5:3] */
+#define WM8962_DACSYS_CLK_DIV_WIDTH                  3  /* DACSYS_CLK_DIV - [5:3] */
+#define WM8962_MCLKDIV_MASK                     0x0006  /* MCLKDIV - [2:1] */
+#define WM8962_MCLKDIV_SHIFT                         1  /* MCLKDIV - [2:1] */
+#define WM8962_MCLKDIV_WIDTH                         2  /* MCLKDIV - [2:1] */
+
+/*
+ * R5 (0x05) - ADC & DAC Control 1
+ */
+#define WM8962_ADCR_DAT_INV                     0x0040  /* ADCR_DAT_INV */
+#define WM8962_ADCR_DAT_INV_MASK                0x0040  /* ADCR_DAT_INV */
+#define WM8962_ADCR_DAT_INV_SHIFT                    6  /* ADCR_DAT_INV */
+#define WM8962_ADCR_DAT_INV_WIDTH                    1  /* ADCR_DAT_INV */
+#define WM8962_ADCL_DAT_INV                     0x0020  /* ADCL_DAT_INV */
+#define WM8962_ADCL_DAT_INV_MASK                0x0020  /* ADCL_DAT_INV */
+#define WM8962_ADCL_DAT_INV_SHIFT                    5  /* ADCL_DAT_INV */
+#define WM8962_ADCL_DAT_INV_WIDTH                    1  /* ADCL_DAT_INV */
+#define WM8962_DAC_MUTE_RAMP                    0x0010  /* DAC_MUTE_RAMP */
+#define WM8962_DAC_MUTE_RAMP_MASK               0x0010  /* DAC_MUTE_RAMP */
+#define WM8962_DAC_MUTE_RAMP_SHIFT                   4  /* DAC_MUTE_RAMP */
+#define WM8962_DAC_MUTE_RAMP_WIDTH                   1  /* DAC_MUTE_RAMP */
+#define WM8962_DAC_MUTE                         0x0008  /* DAC_MUTE */
+#define WM8962_DAC_MUTE_MASK                    0x0008  /* DAC_MUTE */
+#define WM8962_DAC_MUTE_SHIFT                        3  /* DAC_MUTE */
+#define WM8962_DAC_MUTE_WIDTH                        1  /* DAC_MUTE */
+#define WM8962_DAC_DEEMP_MASK                   0x0006  /* DAC_DEEMP - [2:1] */
+#define WM8962_DAC_DEEMP_SHIFT                       1  /* DAC_DEEMP - [2:1] */
+#define WM8962_DAC_DEEMP_WIDTH                       2  /* DAC_DEEMP - [2:1] */
+#define WM8962_ADC_HPF_DIS                      0x0001  /* ADC_HPF_DIS */
+#define WM8962_ADC_HPF_DIS_MASK                 0x0001  /* ADC_HPF_DIS */
+#define WM8962_ADC_HPF_DIS_SHIFT                     0  /* ADC_HPF_DIS */
+#define WM8962_ADC_HPF_DIS_WIDTH                     1  /* ADC_HPF_DIS */
+
+/*
+ * R6 (0x06) - ADC & DAC Control 2
+ */
+#define WM8962_ADC_HPF_SR_MASK                  0x3000  /* ADC_HPF_SR - [13:12] */
+#define WM8962_ADC_HPF_SR_SHIFT                     12  /* ADC_HPF_SR - [13:12] */
+#define WM8962_ADC_HPF_SR_WIDTH                      2  /* ADC_HPF_SR - [13:12] */
+#define WM8962_ADC_HPF_MODE                     0x0400  /* ADC_HPF_MODE */
+#define WM8962_ADC_HPF_MODE_MASK                0x0400  /* ADC_HPF_MODE */
+#define WM8962_ADC_HPF_MODE_SHIFT                   10  /* ADC_HPF_MODE */
+#define WM8962_ADC_HPF_MODE_WIDTH                    1  /* ADC_HPF_MODE */
+#define WM8962_ADC_HPF_CUT_MASK                 0x0380  /* ADC_HPF_CUT - [9:7] */
+#define WM8962_ADC_HPF_CUT_SHIFT                     7  /* ADC_HPF_CUT - [9:7] */
+#define WM8962_ADC_HPF_CUT_WIDTH                     3  /* ADC_HPF_CUT - [9:7] */
+#define WM8962_DACR_DAT_INV                     0x0040  /* DACR_DAT_INV */
+#define WM8962_DACR_DAT_INV_MASK                0x0040  /* DACR_DAT_INV */
+#define WM8962_DACR_DAT_INV_SHIFT                    6  /* DACR_DAT_INV */
+#define WM8962_DACR_DAT_INV_WIDTH                    1  /* DACR_DAT_INV */
+#define WM8962_DACL_DAT_INV                     0x0020  /* DACL_DAT_INV */
+#define WM8962_DACL_DAT_INV_MASK                0x0020  /* DACL_DAT_INV */
+#define WM8962_DACL_DAT_INV_SHIFT                    5  /* DACL_DAT_INV */
+#define WM8962_DACL_DAT_INV_WIDTH                    1  /* DACL_DAT_INV */
+#define WM8962_DAC_UNMUTE_RAMP                  0x0008  /* DAC_UNMUTE_RAMP */
+#define WM8962_DAC_UNMUTE_RAMP_MASK             0x0008  /* DAC_UNMUTE_RAMP */
+#define WM8962_DAC_UNMUTE_RAMP_SHIFT                 3  /* DAC_UNMUTE_RAMP */
+#define WM8962_DAC_UNMUTE_RAMP_WIDTH                 1  /* DAC_UNMUTE_RAMP */
+#define WM8962_DAC_MUTERATE                     0x0004  /* DAC_MUTERATE */
+#define WM8962_DAC_MUTERATE_MASK                0x0004  /* DAC_MUTERATE */
+#define WM8962_DAC_MUTERATE_SHIFT                    2  /* DAC_MUTERATE */
+#define WM8962_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+#define WM8962_DAC_HP                           0x0001  /* DAC_HP */
+#define WM8962_DAC_HP_MASK                      0x0001  /* DAC_HP */
+#define WM8962_DAC_HP_SHIFT                          0  /* DAC_HP */
+#define WM8962_DAC_HP_WIDTH                          1  /* DAC_HP */
+
+/*
+ * R7 (0x07) - Audio Interface 0
+ */
+#define WM8962_AIFDAC_TDM_MODE                  0x1000  /* AIFDAC_TDM_MODE */
+#define WM8962_AIFDAC_TDM_MODE_MASK             0x1000  /* AIFDAC_TDM_MODE */
+#define WM8962_AIFDAC_TDM_MODE_SHIFT                12  /* AIFDAC_TDM_MODE */
+#define WM8962_AIFDAC_TDM_MODE_WIDTH                 1  /* AIFDAC_TDM_MODE */
+#define WM8962_AIFDAC_TDM_SLOT                  0x0800  /* AIFDAC_TDM_SLOT */
+#define WM8962_AIFDAC_TDM_SLOT_MASK             0x0800  /* AIFDAC_TDM_SLOT */
+#define WM8962_AIFDAC_TDM_SLOT_SHIFT                11  /* AIFDAC_TDM_SLOT */
+#define WM8962_AIFDAC_TDM_SLOT_WIDTH                 1  /* AIFDAC_TDM_SLOT */
+#define WM8962_AIFADC_TDM_MODE                  0x0400  /* AIFADC_TDM_MODE */
+#define WM8962_AIFADC_TDM_MODE_MASK             0x0400  /* AIFADC_TDM_MODE */
+#define WM8962_AIFADC_TDM_MODE_SHIFT                10  /* AIFADC_TDM_MODE */
+#define WM8962_AIFADC_TDM_MODE_WIDTH                 1  /* AIFADC_TDM_MODE */
+#define WM8962_AIFADC_TDM_SLOT                  0x0200  /* AIFADC_TDM_SLOT */
+#define WM8962_AIFADC_TDM_SLOT_MASK             0x0200  /* AIFADC_TDM_SLOT */
+#define WM8962_AIFADC_TDM_SLOT_SHIFT                 9  /* AIFADC_TDM_SLOT */
+#define WM8962_AIFADC_TDM_SLOT_WIDTH                 1  /* AIFADC_TDM_SLOT */
+#define WM8962_ADC_LRSWAP                       0x0100  /* ADC_LRSWAP */
+#define WM8962_ADC_LRSWAP_MASK                  0x0100  /* ADC_LRSWAP */
+#define WM8962_ADC_LRSWAP_SHIFT                      8  /* ADC_LRSWAP */
+#define WM8962_ADC_LRSWAP_WIDTH                      1  /* ADC_LRSWAP */
+#define WM8962_BCLK_INV                         0x0080  /* BCLK_INV */
+#define WM8962_BCLK_INV_MASK                    0x0080  /* BCLK_INV */
+#define WM8962_BCLK_INV_SHIFT                        7  /* BCLK_INV */
+#define WM8962_BCLK_INV_WIDTH                        1  /* BCLK_INV */
+#define WM8962_MSTR                             0x0040  /* MSTR */
+#define WM8962_MSTR_MASK                        0x0040  /* MSTR */
+#define WM8962_MSTR_SHIFT                            6  /* MSTR */
+#define WM8962_MSTR_WIDTH                            1  /* MSTR */
+#define WM8962_DAC_LRSWAP                       0x0020  /* DAC_LRSWAP */
+#define WM8962_DAC_LRSWAP_MASK                  0x0020  /* DAC_LRSWAP */
+#define WM8962_DAC_LRSWAP_SHIFT                      5  /* DAC_LRSWAP */
+#define WM8962_DAC_LRSWAP_WIDTH                      1  /* DAC_LRSWAP */
+#define WM8962_LRCLK_INV                        0x0010  /* LRCLK_INV */
+#define WM8962_LRCLK_INV_MASK                   0x0010  /* LRCLK_INV */
+#define WM8962_LRCLK_INV_SHIFT                       4  /* LRCLK_INV */
+#define WM8962_LRCLK_INV_WIDTH                       1  /* LRCLK_INV */
+#define WM8962_WL_MASK                          0x000C  /* WL - [3:2] */
+#define WM8962_WL_SHIFT                              2  /* WL - [3:2] */
+#define WM8962_WL_WIDTH                              2  /* WL - [3:2] */
+#define WM8962_FMT_MASK                         0x0003  /* FMT - [1:0] */
+#define WM8962_FMT_SHIFT                             0  /* FMT - [1:0] */
+#define WM8962_FMT_WIDTH                             2  /* FMT - [1:0] */
+
+/*
+ * R8 (0x08) - Clocking2
+ */
+#define WM8962_CLKREG_OVD                       0x0800  /* CLKREG_OVD */
+#define WM8962_CLKREG_OVD_MASK                  0x0800  /* CLKREG_OVD */
+#define WM8962_CLKREG_OVD_SHIFT                     11  /* CLKREG_OVD */
+#define WM8962_CLKREG_OVD_WIDTH                      1  /* CLKREG_OVD */
+#define WM8962_SYSCLK_SRC_MASK                  0x0600  /* SYSCLK_SRC - [10:9] */
+#define WM8962_SYSCLK_SRC_SHIFT                      9  /* SYSCLK_SRC - [10:9] */
+#define WM8962_SYSCLK_SRC_WIDTH                      2  /* SYSCLK_SRC - [10:9] */
+#define WM8962_CLASSD_CLK_DIV_MASK              0x01C0  /* CLASSD_CLK_DIV - [8:6] */
+#define WM8962_CLASSD_CLK_DIV_SHIFT                  6  /* CLASSD_CLK_DIV - [8:6] */
+#define WM8962_CLASSD_CLK_DIV_WIDTH                  3  /* CLASSD_CLK_DIV - [8:6] */
+#define WM8962_SYSCLK_ENA                       0x0020  /* SYSCLK_ENA */
+#define WM8962_SYSCLK_ENA_MASK                  0x0020  /* SYSCLK_ENA */
+#define WM8962_SYSCLK_ENA_SHIFT                      5  /* SYSCLK_ENA */
+#define WM8962_SYSCLK_ENA_WIDTH                      1  /* SYSCLK_ENA */
+#define WM8962_BCLK_DIV_MASK                    0x000F  /* BCLK_DIV - [3:0] */
+#define WM8962_BCLK_DIV_SHIFT                        0  /* BCLK_DIV - [3:0] */
+#define WM8962_BCLK_DIV_WIDTH                        4  /* BCLK_DIV - [3:0] */
+
+/*
+ * R9 (0x09) - Audio Interface 1
+ */
+#define WM8962_AUTOMUTE_STS                     0x0800  /* AUTOMUTE_STS */
+#define WM8962_AUTOMUTE_STS_MASK                0x0800  /* AUTOMUTE_STS */
+#define WM8962_AUTOMUTE_STS_SHIFT                   11  /* AUTOMUTE_STS */
+#define WM8962_AUTOMUTE_STS_WIDTH                    1  /* AUTOMUTE_STS */
+#define WM8962_DAC_AUTOMUTE_SAMPLES_MASK        0x0300  /* DAC_AUTOMUTE_SAMPLES - [9:8] */
+#define WM8962_DAC_AUTOMUTE_SAMPLES_SHIFT            8  /* DAC_AUTOMUTE_SAMPLES - [9:8] */
+#define WM8962_DAC_AUTOMUTE_SAMPLES_WIDTH            2  /* DAC_AUTOMUTE_SAMPLES - [9:8] */
+#define WM8962_DAC_AUTOMUTE                     0x0080  /* DAC_AUTOMUTE */
+#define WM8962_DAC_AUTOMUTE_MASK                0x0080  /* DAC_AUTOMUTE */
+#define WM8962_DAC_AUTOMUTE_SHIFT                    7  /* DAC_AUTOMUTE */
+#define WM8962_DAC_AUTOMUTE_WIDTH                    1  /* DAC_AUTOMUTE */
+#define WM8962_DAC_COMP                         0x0010  /* DAC_COMP */
+#define WM8962_DAC_COMP_MASK                    0x0010  /* DAC_COMP */
+#define WM8962_DAC_COMP_SHIFT                        4  /* DAC_COMP */
+#define WM8962_DAC_COMP_WIDTH                        1  /* DAC_COMP */
+#define WM8962_DAC_COMPMODE                     0x0008  /* DAC_COMPMODE */
+#define WM8962_DAC_COMPMODE_MASK                0x0008  /* DAC_COMPMODE */
+#define WM8962_DAC_COMPMODE_SHIFT                    3  /* DAC_COMPMODE */
+#define WM8962_DAC_COMPMODE_WIDTH                    1  /* DAC_COMPMODE */
+#define WM8962_ADC_COMP                         0x0004  /* ADC_COMP */
+#define WM8962_ADC_COMP_MASK                    0x0004  /* ADC_COMP */
+#define WM8962_ADC_COMP_SHIFT                        2  /* ADC_COMP */
+#define WM8962_ADC_COMP_WIDTH                        1  /* ADC_COMP */
+#define WM8962_ADC_COMPMODE                     0x0002  /* ADC_COMPMODE */
+#define WM8962_ADC_COMPMODE_MASK                0x0002  /* ADC_COMPMODE */
+#define WM8962_ADC_COMPMODE_SHIFT                    1  /* ADC_COMPMODE */
+#define WM8962_ADC_COMPMODE_WIDTH                    1  /* ADC_COMPMODE */
+#define WM8962_LOOPBACK                         0x0001  /* LOOPBACK */
+#define WM8962_LOOPBACK_MASK                    0x0001  /* LOOPBACK */
+#define WM8962_LOOPBACK_SHIFT                        0  /* LOOPBACK */
+#define WM8962_LOOPBACK_WIDTH                        1  /* LOOPBACK */
+
+/*
+ * R10 (0x0A) - Left DAC volume
+ */
+#define WM8962_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8962_DAC_VU_MASK                      0x0100  /* DAC_VU */
+#define WM8962_DAC_VU_SHIFT                          8  /* DAC_VU */
+#define WM8962_DAC_VU_WIDTH                          1  /* DAC_VU */
+#define WM8962_DACL_VOL_MASK                    0x00FF  /* DACL_VOL - [7:0] */
+#define WM8962_DACL_VOL_SHIFT                        0  /* DACL_VOL - [7:0] */
+#define WM8962_DACL_VOL_WIDTH                        8  /* DACL_VOL - [7:0] */
+
+/*
+ * R11 (0x0B) - Right DAC volume
+ */
+#define WM8962_DAC_VU                           0x0100  /* DAC_VU */
+#define WM8962_DAC_VU_MASK                      0x0100  /* DAC_VU */
+#define WM8962_DAC_VU_SHIFT                          8  /* DAC_VU */
+#define WM8962_DAC_VU_WIDTH                          1  /* DAC_VU */
+#define WM8962_DACR_VOL_MASK                    0x00FF  /* DACR_VOL - [7:0] */
+#define WM8962_DACR_VOL_SHIFT                        0  /* DACR_VOL - [7:0] */
+#define WM8962_DACR_VOL_WIDTH                        8  /* DACR_VOL - [7:0] */
+
+/*
+ * R14 (0x0E) - Audio Interface 2
+ */
+#define WM8962_AIF_RATE_MASK                    0x07FF  /* AIF_RATE - [10:0] */
+#define WM8962_AIF_RATE_SHIFT                        0  /* AIF_RATE - [10:0] */
+#define WM8962_AIF_RATE_WIDTH                       11  /* AIF_RATE - [10:0] */
+
+/*
+ * R15 (0x0F) - Software Reset
+ */
+#define WM8962_SW_RESET_MASK                    0xFFFF  /* SW_RESET - [15:0] */
+#define WM8962_SW_RESET_SHIFT                        0  /* SW_RESET - [15:0] */
+#define WM8962_SW_RESET_WIDTH                       16  /* SW_RESET - [15:0] */
+
+/*
+ * R17 (0x11) - ALC1
+ */
+#define WM8962_ALC_INACTIVE_ENA                 0x0400  /* ALC_INACTIVE_ENA */
+#define WM8962_ALC_INACTIVE_ENA_MASK            0x0400  /* ALC_INACTIVE_ENA */
+#define WM8962_ALC_INACTIVE_ENA_SHIFT               10  /* ALC_INACTIVE_ENA */
+#define WM8962_ALC_INACTIVE_ENA_WIDTH                1  /* ALC_INACTIVE_ENA */
+#define WM8962_ALC_LVL_MODE                     0x0200  /* ALC_LVL_MODE */
+#define WM8962_ALC_LVL_MODE_MASK                0x0200  /* ALC_LVL_MODE */
+#define WM8962_ALC_LVL_MODE_SHIFT                    9  /* ALC_LVL_MODE */
+#define WM8962_ALC_LVL_MODE_WIDTH                    1  /* ALC_LVL_MODE */
+#define WM8962_ALCL_ENA                         0x0100  /* ALCL_ENA */
+#define WM8962_ALCL_ENA_MASK                    0x0100  /* ALCL_ENA */
+#define WM8962_ALCL_ENA_SHIFT                        8  /* ALCL_ENA */
+#define WM8962_ALCL_ENA_WIDTH                        1  /* ALCL_ENA */
+#define WM8962_ALCR_ENA                         0x0080  /* ALCR_ENA */
+#define WM8962_ALCR_ENA_MASK                    0x0080  /* ALCR_ENA */
+#define WM8962_ALCR_ENA_SHIFT                        7  /* ALCR_ENA */
+#define WM8962_ALCR_ENA_WIDTH                        1  /* ALCR_ENA */
+#define WM8962_ALC_MAXGAIN_MASK                 0x0070  /* ALC_MAXGAIN - [6:4] */
+#define WM8962_ALC_MAXGAIN_SHIFT                     4  /* ALC_MAXGAIN - [6:4] */
+#define WM8962_ALC_MAXGAIN_WIDTH                     3  /* ALC_MAXGAIN - [6:4] */
+#define WM8962_ALC_LVL_MASK                     0x000F  /* ALC_LVL - [3:0] */
+#define WM8962_ALC_LVL_SHIFT                         0  /* ALC_LVL - [3:0] */
+#define WM8962_ALC_LVL_WIDTH                         4  /* ALC_LVL - [3:0] */
+
+/*
+ * R18 (0x12) - ALC2
+ */
+#define WM8962_ALC_LOCK_STS                     0x8000  /* ALC_LOCK_STS */
+#define WM8962_ALC_LOCK_STS_MASK                0x8000  /* ALC_LOCK_STS */
+#define WM8962_ALC_LOCK_STS_SHIFT                   15  /* ALC_LOCK_STS */
+#define WM8962_ALC_LOCK_STS_WIDTH                    1  /* ALC_LOCK_STS */
+#define WM8962_ALC_THRESH_STS                   0x4000  /* ALC_THRESH_STS */
+#define WM8962_ALC_THRESH_STS_MASK              0x4000  /* ALC_THRESH_STS */
+#define WM8962_ALC_THRESH_STS_SHIFT                 14  /* ALC_THRESH_STS */
+#define WM8962_ALC_THRESH_STS_WIDTH                  1  /* ALC_THRESH_STS */
+#define WM8962_ALC_SAT_STS                      0x2000  /* ALC_SAT_STS */
+#define WM8962_ALC_SAT_STS_MASK                 0x2000  /* ALC_SAT_STS */
+#define WM8962_ALC_SAT_STS_SHIFT                    13  /* ALC_SAT_STS */
+#define WM8962_ALC_SAT_STS_WIDTH                     1  /* ALC_SAT_STS */
+#define WM8962_ALC_PKOVR_STS                    0x1000  /* ALC_PKOVR_STS */
+#define WM8962_ALC_PKOVR_STS_MASK               0x1000  /* ALC_PKOVR_STS */
+#define WM8962_ALC_PKOVR_STS_SHIFT                  12  /* ALC_PKOVR_STS */
+#define WM8962_ALC_PKOVR_STS_WIDTH                   1  /* ALC_PKOVR_STS */
+#define WM8962_ALC_NGATE_STS                    0x0800  /* ALC_NGATE_STS */
+#define WM8962_ALC_NGATE_STS_MASK               0x0800  /* ALC_NGATE_STS */
+#define WM8962_ALC_NGATE_STS_SHIFT                  11  /* ALC_NGATE_STS */
+#define WM8962_ALC_NGATE_STS_WIDTH                   1  /* ALC_NGATE_STS */
+#define WM8962_ALC_ZC                           0x0080  /* ALC_ZC */
+#define WM8962_ALC_ZC_MASK                      0x0080  /* ALC_ZC */
+#define WM8962_ALC_ZC_SHIFT                          7  /* ALC_ZC */
+#define WM8962_ALC_ZC_WIDTH                          1  /* ALC_ZC */
+#define WM8962_ALC_MINGAIN_MASK                 0x0070  /* ALC_MINGAIN - [6:4] */
+#define WM8962_ALC_MINGAIN_SHIFT                     4  /* ALC_MINGAIN - [6:4] */
+#define WM8962_ALC_MINGAIN_WIDTH                     3  /* ALC_MINGAIN - [6:4] */
+#define WM8962_ALC_HLD_MASK                     0x000F  /* ALC_HLD - [3:0] */
+#define WM8962_ALC_HLD_SHIFT                         0  /* ALC_HLD - [3:0] */
+#define WM8962_ALC_HLD_WIDTH                         4  /* ALC_HLD - [3:0] */
+
+/*
+ * R19 (0x13) - ALC3
+ */
+#define WM8962_ALC_NGATE_GAIN_MASK              0x1C00  /* ALC_NGATE_GAIN - [12:10] */
+#define WM8962_ALC_NGATE_GAIN_SHIFT                 10  /* ALC_NGATE_GAIN - [12:10] */
+#define WM8962_ALC_NGATE_GAIN_WIDTH                  3  /* ALC_NGATE_GAIN - [12:10] */
+#define WM8962_ALC_MODE                         0x0100  /* ALC_MODE */
+#define WM8962_ALC_MODE_MASK                    0x0100  /* ALC_MODE */
+#define WM8962_ALC_MODE_SHIFT                        8  /* ALC_MODE */
+#define WM8962_ALC_MODE_WIDTH                        1  /* ALC_MODE */
+#define WM8962_ALC_DCY_MASK                     0x00F0  /* ALC_DCY - [7:4] */
+#define WM8962_ALC_DCY_SHIFT                         4  /* ALC_DCY - [7:4] */
+#define WM8962_ALC_DCY_WIDTH                         4  /* ALC_DCY - [7:4] */
+#define WM8962_ALC_ATK_MASK                     0x000F  /* ALC_ATK - [3:0] */
+#define WM8962_ALC_ATK_SHIFT                         0  /* ALC_ATK - [3:0] */
+#define WM8962_ALC_ATK_WIDTH                         4  /* ALC_ATK - [3:0] */
+
+/*
+ * R20 (0x14) - Noise Gate
+ */
+#define WM8962_ALC_NGATE_DCY_MASK               0xF000  /* ALC_NGATE_DCY - [15:12] */
+#define WM8962_ALC_NGATE_DCY_SHIFT                  12  /* ALC_NGATE_DCY - [15:12] */
+#define WM8962_ALC_NGATE_DCY_WIDTH                   4  /* ALC_NGATE_DCY - [15:12] */
+#define WM8962_ALC_NGATE_ATK_MASK               0x0F00  /* ALC_NGATE_ATK - [11:8] */
+#define WM8962_ALC_NGATE_ATK_SHIFT                   8  /* ALC_NGATE_ATK - [11:8] */
+#define WM8962_ALC_NGATE_ATK_WIDTH                   4  /* ALC_NGATE_ATK - [11:8] */
+#define WM8962_ALC_NGATE_THR_MASK               0x00F8  /* ALC_NGATE_THR - [7:3] */
+#define WM8962_ALC_NGATE_THR_SHIFT                   3  /* ALC_NGATE_THR - [7:3] */
+#define WM8962_ALC_NGATE_THR_WIDTH                   5  /* ALC_NGATE_THR - [7:3] */
+#define WM8962_ALC_NGATE_MODE_MASK              0x0006  /* ALC_NGATE_MODE - [2:1] */
+#define WM8962_ALC_NGATE_MODE_SHIFT                  1  /* ALC_NGATE_MODE - [2:1] */
+#define WM8962_ALC_NGATE_MODE_WIDTH                  2  /* ALC_NGATE_MODE - [2:1] */
+#define WM8962_ALC_NGATE_ENA                    0x0001  /* ALC_NGATE_ENA */
+#define WM8962_ALC_NGATE_ENA_MASK               0x0001  /* ALC_NGATE_ENA */
+#define WM8962_ALC_NGATE_ENA_SHIFT                   0  /* ALC_NGATE_ENA */
+#define WM8962_ALC_NGATE_ENA_WIDTH                   1  /* ALC_NGATE_ENA */
+
+/*
+ * R21 (0x15) - Left ADC volume
+ */
+#define WM8962_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8962_ADC_VU_MASK                      0x0100  /* ADC_VU */
+#define WM8962_ADC_VU_SHIFT                          8  /* ADC_VU */
+#define WM8962_ADC_VU_WIDTH                          1  /* ADC_VU */
+#define WM8962_ADCL_VOL_MASK                    0x00FF  /* ADCL_VOL - [7:0] */
+#define WM8962_ADCL_VOL_SHIFT                        0  /* ADCL_VOL - [7:0] */
+#define WM8962_ADCL_VOL_WIDTH                        8  /* ADCL_VOL - [7:0] */
+
+/*
+ * R22 (0x16) - Right ADC volume
+ */
+#define WM8962_ADC_VU                           0x0100  /* ADC_VU */
+#define WM8962_ADC_VU_MASK                      0x0100  /* ADC_VU */
+#define WM8962_ADC_VU_SHIFT                          8  /* ADC_VU */
+#define WM8962_ADC_VU_WIDTH                          1  /* ADC_VU */
+#define WM8962_ADCR_VOL_MASK                    0x00FF  /* ADCR_VOL - [7:0] */
+#define WM8962_ADCR_VOL_SHIFT                        0  /* ADCR_VOL - [7:0] */
+#define WM8962_ADCR_VOL_WIDTH                        8  /* ADCR_VOL - [7:0] */
+
+/*
+ * R23 (0x17) - Additional control(1)
+ */
+#define WM8962_THERR_ACT                        0x0100  /* THERR_ACT */
+#define WM8962_THERR_ACT_MASK                   0x0100  /* THERR_ACT */
+#define WM8962_THERR_ACT_SHIFT                       8  /* THERR_ACT */
+#define WM8962_THERR_ACT_WIDTH                       1  /* THERR_ACT */
+#define WM8962_ADC_BIAS                         0x0040  /* ADC_BIAS */
+#define WM8962_ADC_BIAS_MASK                    0x0040  /* ADC_BIAS */
+#define WM8962_ADC_BIAS_SHIFT                        6  /* ADC_BIAS */
+#define WM8962_ADC_BIAS_WIDTH                        1  /* ADC_BIAS */
+#define WM8962_ADC_HP                           0x0020  /* ADC_HP */
+#define WM8962_ADC_HP_MASK                      0x0020  /* ADC_HP */
+#define WM8962_ADC_HP_SHIFT                          5  /* ADC_HP */
+#define WM8962_ADC_HP_WIDTH                          1  /* ADC_HP */
+#define WM8962_TOCLK_ENA                        0x0001  /* TOCLK_ENA */
+#define WM8962_TOCLK_ENA_MASK                   0x0001  /* TOCLK_ENA */
+#define WM8962_TOCLK_ENA_SHIFT                       0  /* TOCLK_ENA */
+#define WM8962_TOCLK_ENA_WIDTH                       1  /* TOCLK_ENA */
+
+/*
+ * R24 (0x18) - Additional control(2)
+ */
+#define WM8962_AIF_TRI                          0x0008  /* AIF_TRI */
+#define WM8962_AIF_TRI_MASK                     0x0008  /* AIF_TRI */
+#define WM8962_AIF_TRI_SHIFT                         3  /* AIF_TRI */
+#define WM8962_AIF_TRI_WIDTH                         1  /* AIF_TRI */
+
+/*
+ * R25 (0x19) - Pwr Mgmt (1)
+ */
+#define WM8962_DMIC_ENA                         0x0400  /* DMIC_ENA */
+#define WM8962_DMIC_ENA_MASK                    0x0400  /* DMIC_ENA */
+#define WM8962_DMIC_ENA_SHIFT                       10  /* DMIC_ENA */
+#define WM8962_DMIC_ENA_WIDTH                        1  /* DMIC_ENA */
+#define WM8962_OPCLK_ENA                        0x0200  /* OPCLK_ENA */
+#define WM8962_OPCLK_ENA_MASK                   0x0200  /* OPCLK_ENA */
+#define WM8962_OPCLK_ENA_SHIFT                       9  /* OPCLK_ENA */
+#define WM8962_OPCLK_ENA_WIDTH                       1  /* OPCLK_ENA */
+#define WM8962_VMID_SEL_MASK                    0x0180  /* VMID_SEL - [8:7] */
+#define WM8962_VMID_SEL_SHIFT                        7  /* VMID_SEL - [8:7] */
+#define WM8962_VMID_SEL_WIDTH                        2  /* VMID_SEL - [8:7] */
+#define WM8962_BIAS_ENA                         0x0040  /* BIAS_ENA */
+#define WM8962_BIAS_ENA_MASK                    0x0040  /* BIAS_ENA */
+#define WM8962_BIAS_ENA_SHIFT                        6  /* BIAS_ENA */
+#define WM8962_BIAS_ENA_WIDTH                        1  /* BIAS_ENA */
+#define WM8962_INL_ENA                          0x0020  /* INL_ENA */
+#define WM8962_INL_ENA_MASK                     0x0020  /* INL_ENA */
+#define WM8962_INL_ENA_SHIFT                         5  /* INL_ENA */
+#define WM8962_INL_ENA_WIDTH                         1  /* INL_ENA */
+#define WM8962_INR_ENA                          0x0010  /* INR_ENA */
+#define WM8962_INR_ENA_MASK                     0x0010  /* INR_ENA */
+#define WM8962_INR_ENA_SHIFT                         4  /* INR_ENA */
+#define WM8962_INR_ENA_WIDTH                         1  /* INR_ENA */
+#define WM8962_ADCL_ENA                         0x0008  /* ADCL_ENA */
+#define WM8962_ADCL_ENA_MASK                    0x0008  /* ADCL_ENA */
+#define WM8962_ADCL_ENA_SHIFT                        3  /* ADCL_ENA */
+#define WM8962_ADCL_ENA_WIDTH                        1  /* ADCL_ENA */
+#define WM8962_ADCR_ENA                         0x0004  /* ADCR_ENA */
+#define WM8962_ADCR_ENA_MASK                    0x0004  /* ADCR_ENA */
+#define WM8962_ADCR_ENA_SHIFT                        2  /* ADCR_ENA */
+#define WM8962_ADCR_ENA_WIDTH                        1  /* ADCR_ENA */
+#define WM8962_MICBIAS_ENA                      0x0002  /* MICBIAS_ENA */
+#define WM8962_MICBIAS_ENA_MASK                 0x0002  /* MICBIAS_ENA */
+#define WM8962_MICBIAS_ENA_SHIFT                     1  /* MICBIAS_ENA */
+#define WM8962_MICBIAS_ENA_WIDTH                     1  /* MICBIAS_ENA */
+
+/*
+ * R26 (0x1A) - Pwr Mgmt (2)
+ */
+#define WM8962_DACL_ENA                         0x0100  /* DACL_ENA */
+#define WM8962_DACL_ENA_MASK                    0x0100  /* DACL_ENA */
+#define WM8962_DACL_ENA_SHIFT                        8  /* DACL_ENA */
+#define WM8962_DACL_ENA_WIDTH                        1  /* DACL_ENA */
+#define WM8962_DACR_ENA                         0x0080  /* DACR_ENA */
+#define WM8962_DACR_ENA_MASK                    0x0080  /* DACR_ENA */
+#define WM8962_DACR_ENA_SHIFT                        7  /* DACR_ENA */
+#define WM8962_DACR_ENA_WIDTH                        1  /* DACR_ENA */
+#define WM8962_HPOUTL_PGA_ENA                   0x0040  /* HPOUTL_PGA_ENA */
+#define WM8962_HPOUTL_PGA_ENA_MASK              0x0040  /* HPOUTL_PGA_ENA */
+#define WM8962_HPOUTL_PGA_ENA_SHIFT                  6  /* HPOUTL_PGA_ENA */
+#define WM8962_HPOUTL_PGA_ENA_WIDTH                  1  /* HPOUTL_PGA_ENA */
+#define WM8962_HPOUTR_PGA_ENA                   0x0020  /* HPOUTR_PGA_ENA */
+#define WM8962_HPOUTR_PGA_ENA_MASK              0x0020  /* HPOUTR_PGA_ENA */
+#define WM8962_HPOUTR_PGA_ENA_SHIFT                  5  /* HPOUTR_PGA_ENA */
+#define WM8962_HPOUTR_PGA_ENA_WIDTH                  1  /* HPOUTR_PGA_ENA */
+#define WM8962_SPKOUTL_PGA_ENA                  0x0010  /* SPKOUTL_PGA_ENA */
+#define WM8962_SPKOUTL_PGA_ENA_MASK             0x0010  /* SPKOUTL_PGA_ENA */
+#define WM8962_SPKOUTL_PGA_ENA_SHIFT                 4  /* SPKOUTL_PGA_ENA */
+#define WM8962_SPKOUTL_PGA_ENA_WIDTH                 1  /* SPKOUTL_PGA_ENA */
+#define WM8962_SPKOUTR_PGA_ENA                  0x0008  /* SPKOUTR_PGA_ENA */
+#define WM8962_SPKOUTR_PGA_ENA_MASK             0x0008  /* SPKOUTR_PGA_ENA */
+#define WM8962_SPKOUTR_PGA_ENA_SHIFT                 3  /* SPKOUTR_PGA_ENA */
+#define WM8962_SPKOUTR_PGA_ENA_WIDTH                 1  /* SPKOUTR_PGA_ENA */
+#define WM8962_HPOUTL_PGA_MUTE                  0x0002  /* HPOUTL_PGA_MUTE */
+#define WM8962_HPOUTL_PGA_MUTE_MASK             0x0002  /* HPOUTL_PGA_MUTE */
+#define WM8962_HPOUTL_PGA_MUTE_SHIFT                 1  /* HPOUTL_PGA_MUTE */
+#define WM8962_HPOUTL_PGA_MUTE_WIDTH                 1  /* HPOUTL_PGA_MUTE */
+#define WM8962_HPOUTR_PGA_MUTE                  0x0001  /* HPOUTR_PGA_MUTE */
+#define WM8962_HPOUTR_PGA_MUTE_MASK             0x0001  /* HPOUTR_PGA_MUTE */
+#define WM8962_HPOUTR_PGA_MUTE_SHIFT                 0  /* HPOUTR_PGA_MUTE */
+#define WM8962_HPOUTR_PGA_MUTE_WIDTH                 1  /* HPOUTR_PGA_MUTE */
+
+/*
+ * R27 (0x1B) - Additional Control (3)
+ */
+#define WM8962_SAMPLE_RATE_INT_MODE             0x0010  /* SAMPLE_RATE_INT_MODE */
+#define WM8962_SAMPLE_RATE_INT_MODE_MASK        0x0010  /* SAMPLE_RATE_INT_MODE */
+#define WM8962_SAMPLE_RATE_INT_MODE_SHIFT            4  /* SAMPLE_RATE_INT_MODE */
+#define WM8962_SAMPLE_RATE_INT_MODE_WIDTH            1  /* SAMPLE_RATE_INT_MODE */
+#define WM8962_SAMPLE_RATE_MASK                 0x0007  /* SAMPLE_RATE - [2:0] */
+#define WM8962_SAMPLE_RATE_SHIFT                     0  /* SAMPLE_RATE - [2:0] */
+#define WM8962_SAMPLE_RATE_WIDTH                     3  /* SAMPLE_RATE - [2:0] */
+
+/*
+ * R28 (0x1C) - Anti-pop
+ */
+#define WM8962_STARTUP_BIAS_ENA                 0x0010  /* STARTUP_BIAS_ENA */
+#define WM8962_STARTUP_BIAS_ENA_MASK            0x0010  /* STARTUP_BIAS_ENA */
+#define WM8962_STARTUP_BIAS_ENA_SHIFT                4  /* STARTUP_BIAS_ENA */
+#define WM8962_STARTUP_BIAS_ENA_WIDTH                1  /* STARTUP_BIAS_ENA */
+#define WM8962_VMID_BUF_ENA                     0x0008  /* VMID_BUF_ENA */
+#define WM8962_VMID_BUF_ENA_MASK                0x0008  /* VMID_BUF_ENA */
+#define WM8962_VMID_BUF_ENA_SHIFT                    3  /* VMID_BUF_ENA */
+#define WM8962_VMID_BUF_ENA_WIDTH                    1  /* VMID_BUF_ENA */
+#define WM8962_VMID_RAMP                        0x0004  /* VMID_RAMP */
+#define WM8962_VMID_RAMP_MASK                   0x0004  /* VMID_RAMP */
+#define WM8962_VMID_RAMP_SHIFT                       2  /* VMID_RAMP */
+#define WM8962_VMID_RAMP_WIDTH                       1  /* VMID_RAMP */
+
+/*
+ * R30 (0x1E) - Clocking 3
+ */
+#define WM8962_DBCLK_DIV_MASK                   0xE000  /* DBCLK_DIV - [15:13] */
+#define WM8962_DBCLK_DIV_SHIFT                      13  /* DBCLK_DIV - [15:13] */
+#define WM8962_DBCLK_DIV_WIDTH                       3  /* DBCLK_DIV - [15:13] */
+#define WM8962_OPCLK_DIV_MASK                   0x1C00  /* OPCLK_DIV - [12:10] */
+#define WM8962_OPCLK_DIV_SHIFT                      10  /* OPCLK_DIV - [12:10] */
+#define WM8962_OPCLK_DIV_WIDTH                       3  /* OPCLK_DIV - [12:10] */
+#define WM8962_TOCLK_DIV_MASK                   0x0380  /* TOCLK_DIV - [9:7] */
+#define WM8962_TOCLK_DIV_SHIFT                       7  /* TOCLK_DIV - [9:7] */
+#define WM8962_TOCLK_DIV_WIDTH                       3  /* TOCLK_DIV - [9:7] */
+#define WM8962_F256KCLK_DIV_MASK                0x007E  /* F256KCLK_DIV - [6:1] */
+#define WM8962_F256KCLK_DIV_SHIFT                    1  /* F256KCLK_DIV - [6:1] */
+#define WM8962_F256KCLK_DIV_WIDTH                    6  /* F256KCLK_DIV - [6:1] */
+
+/*
+ * R31 (0x1F) - Input mixer control (1)
+ */
+#define WM8962_MIXINL_MUTE                      0x0008  /* MIXINL_MUTE */
+#define WM8962_MIXINL_MUTE_MASK                 0x0008  /* MIXINL_MUTE */
+#define WM8962_MIXINL_MUTE_SHIFT                     3  /* MIXINL_MUTE */
+#define WM8962_MIXINL_MUTE_WIDTH                     1  /* MIXINL_MUTE */
+#define WM8962_MIXINR_MUTE                      0x0004  /* MIXINR_MUTE */
+#define WM8962_MIXINR_MUTE_MASK                 0x0004  /* MIXINR_MUTE */
+#define WM8962_MIXINR_MUTE_SHIFT                     2  /* MIXINR_MUTE */
+#define WM8962_MIXINR_MUTE_WIDTH                     1  /* MIXINR_MUTE */
+#define WM8962_MIXINL_ENA                       0x0002  /* MIXINL_ENA */
+#define WM8962_MIXINL_ENA_MASK                  0x0002  /* MIXINL_ENA */
+#define WM8962_MIXINL_ENA_SHIFT                      1  /* MIXINL_ENA */
+#define WM8962_MIXINL_ENA_WIDTH                      1  /* MIXINL_ENA */
+#define WM8962_MIXINR_ENA                       0x0001  /* MIXINR_ENA */
+#define WM8962_MIXINR_ENA_MASK                  0x0001  /* MIXINR_ENA */
+#define WM8962_MIXINR_ENA_SHIFT                      0  /* MIXINR_ENA */
+#define WM8962_MIXINR_ENA_WIDTH                      1  /* MIXINR_ENA */
+
+/*
+ * R32 (0x20) - Left input mixer volume
+ */
+#define WM8962_IN2L_MIXINL_VOL_MASK             0x01C0  /* IN2L_MIXINL_VOL - [8:6] */
+#define WM8962_IN2L_MIXINL_VOL_SHIFT                 6  /* IN2L_MIXINL_VOL - [8:6] */
+#define WM8962_IN2L_MIXINL_VOL_WIDTH                 3  /* IN2L_MIXINL_VOL - [8:6] */
+#define WM8962_INPGAL_MIXINL_VOL_MASK           0x0038  /* INPGAL_MIXINL_VOL - [5:3] */
+#define WM8962_INPGAL_MIXINL_VOL_SHIFT               3  /* INPGAL_MIXINL_VOL - [5:3] */
+#define WM8962_INPGAL_MIXINL_VOL_WIDTH               3  /* INPGAL_MIXINL_VOL - [5:3] */
+#define WM8962_IN3L_MIXINL_VOL_MASK             0x0007  /* IN3L_MIXINL_VOL - [2:0] */
+#define WM8962_IN3L_MIXINL_VOL_SHIFT                 0  /* IN3L_MIXINL_VOL - [2:0] */
+#define WM8962_IN3L_MIXINL_VOL_WIDTH                 3  /* IN3L_MIXINL_VOL - [2:0] */
+
+/*
+ * R33 (0x21) - Right input mixer volume
+ */
+#define WM8962_IN2R_MIXINR_VOL_MASK             0x01C0  /* IN2R_MIXINR_VOL - [8:6] */
+#define WM8962_IN2R_MIXINR_VOL_SHIFT                 6  /* IN2R_MIXINR_VOL - [8:6] */
+#define WM8962_IN2R_MIXINR_VOL_WIDTH                 3  /* IN2R_MIXINR_VOL - [8:6] */
+#define WM8962_INPGAR_MIXINR_VOL_MASK           0x0038  /* INPGAR_MIXINR_VOL - [5:3] */
+#define WM8962_INPGAR_MIXINR_VOL_SHIFT               3  /* INPGAR_MIXINR_VOL - [5:3] */
+#define WM8962_INPGAR_MIXINR_VOL_WIDTH               3  /* INPGAR_MIXINR_VOL - [5:3] */
+#define WM8962_IN3R_MIXINR_VOL_MASK             0x0007  /* IN3R_MIXINR_VOL - [2:0] */
+#define WM8962_IN3R_MIXINR_VOL_SHIFT                 0  /* IN3R_MIXINR_VOL - [2:0] */
+#define WM8962_IN3R_MIXINR_VOL_WIDTH                 3  /* IN3R_MIXINR_VOL - [2:0] */
+
+/*
+ * R34 (0x22) - Input mixer control (2)
+ */
+#define WM8962_IN2L_TO_MIXINL                   0x0020  /* IN2L_TO_MIXINL */
+#define WM8962_IN2L_TO_MIXINL_MASK              0x0020  /* IN2L_TO_MIXINL */
+#define WM8962_IN2L_TO_MIXINL_SHIFT                  5  /* IN2L_TO_MIXINL */
+#define WM8962_IN2L_TO_MIXINL_WIDTH                  1  /* IN2L_TO_MIXINL */
+#define WM8962_IN3L_TO_MIXINL                   0x0010  /* IN3L_TO_MIXINL */
+#define WM8962_IN3L_TO_MIXINL_MASK              0x0010  /* IN3L_TO_MIXINL */
+#define WM8962_IN3L_TO_MIXINL_SHIFT                  4  /* IN3L_TO_MIXINL */
+#define WM8962_IN3L_TO_MIXINL_WIDTH                  1  /* IN3L_TO_MIXINL */
+#define WM8962_INPGAL_TO_MIXINL                 0x0008  /* INPGAL_TO_MIXINL */
+#define WM8962_INPGAL_TO_MIXINL_MASK            0x0008  /* INPGAL_TO_MIXINL */
+#define WM8962_INPGAL_TO_MIXINL_SHIFT                3  /* INPGAL_TO_MIXINL */
+#define WM8962_INPGAL_TO_MIXINL_WIDTH                1  /* INPGAL_TO_MIXINL */
+#define WM8962_IN2R_TO_MIXINR                   0x0004  /* IN2R_TO_MIXINR */
+#define WM8962_IN2R_TO_MIXINR_MASK              0x0004  /* IN2R_TO_MIXINR */
+#define WM8962_IN2R_TO_MIXINR_SHIFT                  2  /* IN2R_TO_MIXINR */
+#define WM8962_IN2R_TO_MIXINR_WIDTH                  1  /* IN2R_TO_MIXINR */
+#define WM8962_IN3R_TO_MIXINR                   0x0002  /* IN3R_TO_MIXINR */
+#define WM8962_IN3R_TO_MIXINR_MASK              0x0002  /* IN3R_TO_MIXINR */
+#define WM8962_IN3R_TO_MIXINR_SHIFT                  1  /* IN3R_TO_MIXINR */
+#define WM8962_IN3R_TO_MIXINR_WIDTH                  1  /* IN3R_TO_MIXINR */
+#define WM8962_INPGAR_TO_MIXINR                 0x0001  /* INPGAR_TO_MIXINR */
+#define WM8962_INPGAR_TO_MIXINR_MASK            0x0001  /* INPGAR_TO_MIXINR */
+#define WM8962_INPGAR_TO_MIXINR_SHIFT                0  /* INPGAR_TO_MIXINR */
+#define WM8962_INPGAR_TO_MIXINR_WIDTH                1  /* INPGAR_TO_MIXINR */
+
+/*
+ * R35 (0x23) - Input bias control
+ */
+#define WM8962_MIXIN_BIAS_MASK                  0x0038  /* MIXIN_BIAS - [5:3] */
+#define WM8962_MIXIN_BIAS_SHIFT                      3  /* MIXIN_BIAS - [5:3] */
+#define WM8962_MIXIN_BIAS_WIDTH                      3  /* MIXIN_BIAS - [5:3] */
+#define WM8962_INPGA_BIAS_MASK                  0x0007  /* INPGA_BIAS - [2:0] */
+#define WM8962_INPGA_BIAS_SHIFT                      0  /* INPGA_BIAS - [2:0] */
+#define WM8962_INPGA_BIAS_WIDTH                      3  /* INPGA_BIAS - [2:0] */
+
+/*
+ * R37 (0x25) - Left input PGA control
+ */
+#define WM8962_INPGAL_ENA                       0x0010  /* INPGAL_ENA */
+#define WM8962_INPGAL_ENA_MASK                  0x0010  /* INPGAL_ENA */
+#define WM8962_INPGAL_ENA_SHIFT                      4  /* INPGAL_ENA */
+#define WM8962_INPGAL_ENA_WIDTH                      1  /* INPGAL_ENA */
+#define WM8962_IN1L_TO_INPGAL                   0x0008  /* IN1L_TO_INPGAL */
+#define WM8962_IN1L_TO_INPGAL_MASK              0x0008  /* IN1L_TO_INPGAL */
+#define WM8962_IN1L_TO_INPGAL_SHIFT                  3  /* IN1L_TO_INPGAL */
+#define WM8962_IN1L_TO_INPGAL_WIDTH                  1  /* IN1L_TO_INPGAL */
+#define WM8962_IN2L_TO_INPGAL                   0x0004  /* IN2L_TO_INPGAL */
+#define WM8962_IN2L_TO_INPGAL_MASK              0x0004  /* IN2L_TO_INPGAL */
+#define WM8962_IN2L_TO_INPGAL_SHIFT                  2  /* IN2L_TO_INPGAL */
+#define WM8962_IN2L_TO_INPGAL_WIDTH                  1  /* IN2L_TO_INPGAL */
+#define WM8962_IN3L_TO_INPGAL                   0x0002  /* IN3L_TO_INPGAL */
+#define WM8962_IN3L_TO_INPGAL_MASK              0x0002  /* IN3L_TO_INPGAL */
+#define WM8962_IN3L_TO_INPGAL_SHIFT                  1  /* IN3L_TO_INPGAL */
+#define WM8962_IN3L_TO_INPGAL_WIDTH                  1  /* IN3L_TO_INPGAL */
+#define WM8962_IN4L_TO_INPGAL                   0x0001  /* IN4L_TO_INPGAL */
+#define WM8962_IN4L_TO_INPGAL_MASK              0x0001  /* IN4L_TO_INPGAL */
+#define WM8962_IN4L_TO_INPGAL_SHIFT                  0  /* IN4L_TO_INPGAL */
+#define WM8962_IN4L_TO_INPGAL_WIDTH                  1  /* IN4L_TO_INPGAL */
+
+/*
+ * R38 (0x26) - Right input PGA control
+ */
+#define WM8962_INPGAR_ENA                       0x0010  /* INPGAR_ENA */
+#define WM8962_INPGAR_ENA_MASK                  0x0010  /* INPGAR_ENA */
+#define WM8962_INPGAR_ENA_SHIFT                      4  /* INPGAR_ENA */
+#define WM8962_INPGAR_ENA_WIDTH                      1  /* INPGAR_ENA */
+#define WM8962_IN1R_TO_INPGAR                   0x0008  /* IN1R_TO_INPGAR */
+#define WM8962_IN1R_TO_INPGAR_MASK              0x0008  /* IN1R_TO_INPGAR */
+#define WM8962_IN1R_TO_INPGAR_SHIFT                  3  /* IN1R_TO_INPGAR */
+#define WM8962_IN1R_TO_INPGAR_WIDTH                  1  /* IN1R_TO_INPGAR */
+#define WM8962_IN2R_TO_INPGAR                   0x0004  /* IN2R_TO_INPGAR */
+#define WM8962_IN2R_TO_INPGAR_MASK              0x0004  /* IN2R_TO_INPGAR */
+#define WM8962_IN2R_TO_INPGAR_SHIFT                  2  /* IN2R_TO_INPGAR */
+#define WM8962_IN2R_TO_INPGAR_WIDTH                  1  /* IN2R_TO_INPGAR */
+#define WM8962_IN3R_TO_INPGAR                   0x0002  /* IN3R_TO_INPGAR */
+#define WM8962_IN3R_TO_INPGAR_MASK              0x0002  /* IN3R_TO_INPGAR */
+#define WM8962_IN3R_TO_INPGAR_SHIFT                  1  /* IN3R_TO_INPGAR */
+#define WM8962_IN3R_TO_INPGAR_WIDTH                  1  /* IN3R_TO_INPGAR */
+#define WM8962_IN4R_TO_INPGAR                   0x0001  /* IN4R_TO_INPGAR */
+#define WM8962_IN4R_TO_INPGAR_MASK              0x0001  /* IN4R_TO_INPGAR */
+#define WM8962_IN4R_TO_INPGAR_SHIFT                  0  /* IN4R_TO_INPGAR */
+#define WM8962_IN4R_TO_INPGAR_WIDTH                  1  /* IN4R_TO_INPGAR */
+
+/*
+ * R40 (0x28) - SPKOUTL volume
+ */
+#define WM8962_SPKOUT_VU                        0x0100  /* SPKOUT_VU */
+#define WM8962_SPKOUT_VU_MASK                   0x0100  /* SPKOUT_VU */
+#define WM8962_SPKOUT_VU_SHIFT                       8  /* SPKOUT_VU */
+#define WM8962_SPKOUT_VU_WIDTH                       1  /* SPKOUT_VU */
+#define WM8962_SPKOUTL_ZC                       0x0080  /* SPKOUTL_ZC */
+#define WM8962_SPKOUTL_ZC_MASK                  0x0080  /* SPKOUTL_ZC */
+#define WM8962_SPKOUTL_ZC_SHIFT                      7  /* SPKOUTL_ZC */
+#define WM8962_SPKOUTL_ZC_WIDTH                      1  /* SPKOUTL_ZC */
+#define WM8962_SPKOUTL_VOL_MASK                 0x007F  /* SPKOUTL_VOL - [6:0] */
+#define WM8962_SPKOUTL_VOL_SHIFT                     0  /* SPKOUTL_VOL - [6:0] */
+#define WM8962_SPKOUTL_VOL_WIDTH                     7  /* SPKOUTL_VOL - [6:0] */
+
+/*
+ * R41 (0x29) - SPKOUTR volume
+ */
+#define WM8962_SPKOUTR_ZC                       0x0080  /* SPKOUTR_ZC */
+#define WM8962_SPKOUTR_ZC_MASK                  0x0080  /* SPKOUTR_ZC */
+#define WM8962_SPKOUTR_ZC_SHIFT                      7  /* SPKOUTR_ZC */
+#define WM8962_SPKOUTR_ZC_WIDTH                      1  /* SPKOUTR_ZC */
+#define WM8962_SPKOUTR_VOL_MASK                 0x007F  /* SPKOUTR_VOL - [6:0] */
+#define WM8962_SPKOUTR_VOL_SHIFT                     0  /* SPKOUTR_VOL - [6:0] */
+#define WM8962_SPKOUTR_VOL_WIDTH                     7  /* SPKOUTR_VOL - [6:0] */
+
+/*
+ * R47 (0x2F) - Thermal Shutdown Status
+ */
+#define WM8962_TEMP_ERR_HP                      0x0008  /* TEMP_ERR_HP */
+#define WM8962_TEMP_ERR_HP_MASK                 0x0008  /* TEMP_ERR_HP */
+#define WM8962_TEMP_ERR_HP_SHIFT                     3  /* TEMP_ERR_HP */
+#define WM8962_TEMP_ERR_HP_WIDTH                     1  /* TEMP_ERR_HP */
+#define WM8962_TEMP_WARN_HP                     0x0004  /* TEMP_WARN_HP */
+#define WM8962_TEMP_WARN_HP_MASK                0x0004  /* TEMP_WARN_HP */
+#define WM8962_TEMP_WARN_HP_SHIFT                    2  /* TEMP_WARN_HP */
+#define WM8962_TEMP_WARN_HP_WIDTH                    1  /* TEMP_WARN_HP */
+#define WM8962_TEMP_ERR_SPK                     0x0002  /* TEMP_ERR_SPK */
+#define WM8962_TEMP_ERR_SPK_MASK                0x0002  /* TEMP_ERR_SPK */
+#define WM8962_TEMP_ERR_SPK_SHIFT                    1  /* TEMP_ERR_SPK */
+#define WM8962_TEMP_ERR_SPK_WIDTH                    1  /* TEMP_ERR_SPK */
+#define WM8962_TEMP_WARN_SPK                    0x0001  /* TEMP_WARN_SPK */
+#define WM8962_TEMP_WARN_SPK_MASK               0x0001  /* TEMP_WARN_SPK */
+#define WM8962_TEMP_WARN_SPK_SHIFT                   0  /* TEMP_WARN_SPK */
+#define WM8962_TEMP_WARN_SPK_WIDTH                   1  /* TEMP_WARN_SPK */
+
+/*
+ * R48 (0x30) - Additional Control (4)
+ */
+#define WM8962_MICDET_THR_MASK                  0x7000  /* MICDET_THR - [14:12] */
+#define WM8962_MICDET_THR_SHIFT                     12  /* MICDET_THR - [14:12] */
+#define WM8962_MICDET_THR_WIDTH                      3  /* MICDET_THR - [14:12] */
+#define WM8962_MICSHORT_THR_MASK                0x0C00  /* MICSHORT_THR - [11:10] */
+#define WM8962_MICSHORT_THR_SHIFT                   10  /* MICSHORT_THR - [11:10] */
+#define WM8962_MICSHORT_THR_WIDTH                    2  /* MICSHORT_THR - [11:10] */
+#define WM8962_MICDET_ENA                       0x0200  /* MICDET_ENA */
+#define WM8962_MICDET_ENA_MASK                  0x0200  /* MICDET_ENA */
+#define WM8962_MICDET_ENA_SHIFT                      9  /* MICDET_ENA */
+#define WM8962_MICDET_ENA_WIDTH                      1  /* MICDET_ENA */
+#define WM8962_MICDET_STS                       0x0080  /* MICDET_STS */
+#define WM8962_MICDET_STS_MASK                  0x0080  /* MICDET_STS */
+#define WM8962_MICDET_STS_SHIFT                      7  /* MICDET_STS */
+#define WM8962_MICDET_STS_WIDTH                      1  /* MICDET_STS */
+#define WM8962_MICSHORT_STS                     0x0040  /* MICSHORT_STS */
+#define WM8962_MICSHORT_STS_MASK                0x0040  /* MICSHORT_STS */
+#define WM8962_MICSHORT_STS_SHIFT                    6  /* MICSHORT_STS */
+#define WM8962_MICSHORT_STS_WIDTH                    1  /* MICSHORT_STS */
+#define WM8962_TEMP_ENA_HP                      0x0004  /* TEMP_ENA_HP */
+#define WM8962_TEMP_ENA_HP_MASK                 0x0004  /* TEMP_ENA_HP */
+#define WM8962_TEMP_ENA_HP_SHIFT                     2  /* TEMP_ENA_HP */
+#define WM8962_TEMP_ENA_HP_WIDTH                     1  /* TEMP_ENA_HP */
+#define WM8962_TEMP_ENA_SPK                     0x0002  /* TEMP_ENA_SPK */
+#define WM8962_TEMP_ENA_SPK_MASK                0x0002  /* TEMP_ENA_SPK */
+#define WM8962_TEMP_ENA_SPK_SHIFT                    1  /* TEMP_ENA_SPK */
+#define WM8962_TEMP_ENA_SPK_WIDTH                    1  /* TEMP_ENA_SPK */
+#define WM8962_MICBIAS_LVL                      0x0001  /* MICBIAS_LVL */
+#define WM8962_MICBIAS_LVL_MASK                 0x0001  /* MICBIAS_LVL */
+#define WM8962_MICBIAS_LVL_SHIFT                     0  /* MICBIAS_LVL */
+#define WM8962_MICBIAS_LVL_WIDTH                     1  /* MICBIAS_LVL */
+
+/*
+ * R49 (0x31) - Class D Control 1
+ */
+#define WM8962_SPKOUTR_ENA                      0x0080  /* SPKOUTR_ENA */
+#define WM8962_SPKOUTR_ENA_MASK                 0x0080  /* SPKOUTR_ENA */
+#define WM8962_SPKOUTR_ENA_SHIFT                     7  /* SPKOUTR_ENA */
+#define WM8962_SPKOUTR_ENA_WIDTH                     1  /* SPKOUTR_ENA */
+#define WM8962_SPKOUTL_ENA                      0x0040  /* SPKOUTL_ENA */
+#define WM8962_SPKOUTL_ENA_MASK                 0x0040  /* SPKOUTL_ENA */
+#define WM8962_SPKOUTL_ENA_SHIFT                     6  /* SPKOUTL_ENA */
+#define WM8962_SPKOUTL_ENA_WIDTH                     1  /* SPKOUTL_ENA */
+#define WM8962_SPKOUTL_PGA_MUTE                 0x0002  /* SPKOUTL_PGA_MUTE */
+#define WM8962_SPKOUTL_PGA_MUTE_MASK            0x0002  /* SPKOUTL_PGA_MUTE */
+#define WM8962_SPKOUTL_PGA_MUTE_SHIFT                1  /* SPKOUTL_PGA_MUTE */
+#define WM8962_SPKOUTL_PGA_MUTE_WIDTH                1  /* SPKOUTL_PGA_MUTE */
+#define WM8962_SPKOUTR_PGA_MUTE                 0x0001  /* SPKOUTR_PGA_MUTE */
+#define WM8962_SPKOUTR_PGA_MUTE_MASK            0x0001  /* SPKOUTR_PGA_MUTE */
+#define WM8962_SPKOUTR_PGA_MUTE_SHIFT                0  /* SPKOUTR_PGA_MUTE */
+#define WM8962_SPKOUTR_PGA_MUTE_WIDTH                1  /* SPKOUTR_PGA_MUTE */
+
+/*
+ * R51 (0x33) - Class D Control 2
+ */
+#define WM8962_SPK_MONO                         0x0040  /* SPK_MONO */
+#define WM8962_SPK_MONO_MASK                    0x0040  /* SPK_MONO */
+#define WM8962_SPK_MONO_SHIFT                        6  /* SPK_MONO */
+#define WM8962_SPK_MONO_WIDTH                        1  /* SPK_MONO */
+#define WM8962_CLASSD_VOL_MASK                  0x0007  /* CLASSD_VOL - [2:0] */
+#define WM8962_CLASSD_VOL_SHIFT                      0  /* CLASSD_VOL - [2:0] */
+#define WM8962_CLASSD_VOL_WIDTH                      3  /* CLASSD_VOL - [2:0] */
+
+/*
+ * R56 (0x38) - Clocking 4
+ */
+#define WM8962_SYSCLK_RATE_MASK                 0x001E  /* SYSCLK_RATE - [4:1] */
+#define WM8962_SYSCLK_RATE_SHIFT                     1  /* SYSCLK_RATE - [4:1] */
+#define WM8962_SYSCLK_RATE_WIDTH                     4  /* SYSCLK_RATE - [4:1] */
+
+/*
+ * R57 (0x39) - DAC DSP Mixing (1)
+ */
+#define WM8962_DAC_MONOMIX                      0x0200  /* DAC_MONOMIX */
+#define WM8962_DAC_MONOMIX_MASK                 0x0200  /* DAC_MONOMIX */
+#define WM8962_DAC_MONOMIX_SHIFT                     9  /* DAC_MONOMIX */
+#define WM8962_DAC_MONOMIX_WIDTH                     1  /* DAC_MONOMIX */
+#define WM8962_ADCR_DAC_SVOL_MASK               0x00F0  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8962_ADCR_DAC_SVOL_SHIFT                   4  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8962_ADCR_DAC_SVOL_WIDTH                   4  /* ADCR_DAC_SVOL - [7:4] */
+#define WM8962_ADC_TO_DACR_MASK                 0x000C  /* ADC_TO_DACR - [3:2] */
+#define WM8962_ADC_TO_DACR_SHIFT                     2  /* ADC_TO_DACR - [3:2] */
+#define WM8962_ADC_TO_DACR_WIDTH                     2  /* ADC_TO_DACR - [3:2] */
+
+/*
+ * R58 (0x3A) - DAC DSP Mixing (2)
+ */
+#define WM8962_ADCL_DAC_SVOL_MASK               0x00F0  /* ADCL_DAC_SVOL - [7:4] */
+#define WM8962_ADCL_DAC_SVOL_SHIFT                   4  /* ADCL_DAC_SVOL - [7:4] */
+#define WM8962_ADCL_DAC_SVOL_WIDTH                   4  /* ADCL_DAC_SVOL - [7:4] */
+#define WM8962_ADC_TO_DACL_MASK                 0x000C  /* ADC_TO_DACL - [3:2] */
+#define WM8962_ADC_TO_DACL_SHIFT                     2  /* ADC_TO_DACL - [3:2] */
+#define WM8962_ADC_TO_DACL_WIDTH                     2  /* ADC_TO_DACL - [3:2] */
+
+/*
+ * R60 (0x3C) - DC Servo 0
+ */
+#define WM8962_INL_DCS_ENA                      0x0080  /* INL_DCS_ENA */
+#define WM8962_INL_DCS_ENA_MASK                 0x0080  /* INL_DCS_ENA */
+#define WM8962_INL_DCS_ENA_SHIFT                     7  /* INL_DCS_ENA */
+#define WM8962_INL_DCS_ENA_WIDTH                     1  /* INL_DCS_ENA */
+#define WM8962_INL_DCS_STARTUP                  0x0040  /* INL_DCS_STARTUP */
+#define WM8962_INL_DCS_STARTUP_MASK             0x0040  /* INL_DCS_STARTUP */
+#define WM8962_INL_DCS_STARTUP_SHIFT                 6  /* INL_DCS_STARTUP */
+#define WM8962_INL_DCS_STARTUP_WIDTH                 1  /* INL_DCS_STARTUP */
+#define WM8962_INR_DCS_ENA                      0x0008  /* INR_DCS_ENA */
+#define WM8962_INR_DCS_ENA_MASK                 0x0008  /* INR_DCS_ENA */
+#define WM8962_INR_DCS_ENA_SHIFT                     3  /* INR_DCS_ENA */
+#define WM8962_INR_DCS_ENA_WIDTH                     1  /* INR_DCS_ENA */
+#define WM8962_INR_DCS_STARTUP                  0x0004  /* INR_DCS_STARTUP */
+#define WM8962_INR_DCS_STARTUP_MASK             0x0004  /* INR_DCS_STARTUP */
+#define WM8962_INR_DCS_STARTUP_SHIFT                 2  /* INR_DCS_STARTUP */
+#define WM8962_INR_DCS_STARTUP_WIDTH                 1  /* INR_DCS_STARTUP */
+
+/*
+ * R61 (0x3D) - DC Servo 1
+ */
+#define WM8962_HP1L_DCS_ENA                     0x0080  /* HP1L_DCS_ENA */
+#define WM8962_HP1L_DCS_ENA_MASK                0x0080  /* HP1L_DCS_ENA */
+#define WM8962_HP1L_DCS_ENA_SHIFT                    7  /* HP1L_DCS_ENA */
+#define WM8962_HP1L_DCS_ENA_WIDTH                    1  /* HP1L_DCS_ENA */
+#define WM8962_HP1L_DCS_STARTUP                 0x0040  /* HP1L_DCS_STARTUP */
+#define WM8962_HP1L_DCS_STARTUP_MASK            0x0040  /* HP1L_DCS_STARTUP */
+#define WM8962_HP1L_DCS_STARTUP_SHIFT                6  /* HP1L_DCS_STARTUP */
+#define WM8962_HP1L_DCS_STARTUP_WIDTH                1  /* HP1L_DCS_STARTUP */
+#define WM8962_HP1L_DCS_SYNC                    0x0010  /* HP1L_DCS_SYNC */
+#define WM8962_HP1L_DCS_SYNC_MASK               0x0010  /* HP1L_DCS_SYNC */
+#define WM8962_HP1L_DCS_SYNC_SHIFT                   4  /* HP1L_DCS_SYNC */
+#define WM8962_HP1L_DCS_SYNC_WIDTH                   1  /* HP1L_DCS_SYNC */
+#define WM8962_HP1R_DCS_ENA                     0x0008  /* HP1R_DCS_ENA */
+#define WM8962_HP1R_DCS_ENA_MASK                0x0008  /* HP1R_DCS_ENA */
+#define WM8962_HP1R_DCS_ENA_SHIFT                    3  /* HP1R_DCS_ENA */
+#define WM8962_HP1R_DCS_ENA_WIDTH                    1  /* HP1R_DCS_ENA */
+#define WM8962_HP1R_DCS_STARTUP                 0x0004  /* HP1R_DCS_STARTUP */
+#define WM8962_HP1R_DCS_STARTUP_MASK            0x0004  /* HP1R_DCS_STARTUP */
+#define WM8962_HP1R_DCS_STARTUP_SHIFT                2  /* HP1R_DCS_STARTUP */
+#define WM8962_HP1R_DCS_STARTUP_WIDTH                1  /* HP1R_DCS_STARTUP */
+#define WM8962_HP1R_DCS_SYNC                    0x0001  /* HP1R_DCS_SYNC */
+#define WM8962_HP1R_DCS_SYNC_MASK               0x0001  /* HP1R_DCS_SYNC */
+#define WM8962_HP1R_DCS_SYNC_SHIFT                   0  /* HP1R_DCS_SYNC */
+#define WM8962_HP1R_DCS_SYNC_WIDTH                   1  /* HP1R_DCS_SYNC */
+
+/*
+ * R64 (0x40) - DC Servo 4
+ */
+#define WM8962_HP1_DCS_SYNC_STEPS_MASK          0x3F80  /* HP1_DCS_SYNC_STEPS - [13:7] */
+#define WM8962_HP1_DCS_SYNC_STEPS_SHIFT              7  /* HP1_DCS_SYNC_STEPS - [13:7] */
+#define WM8962_HP1_DCS_SYNC_STEPS_WIDTH              7  /* HP1_DCS_SYNC_STEPS - [13:7] */
+
+/*
+ * R66 (0x42) - DC Servo 6
+ */
+#define WM8962_DCS_STARTUP_DONE_INL             0x0400  /* DCS_STARTUP_DONE_INL */
+#define WM8962_DCS_STARTUP_DONE_INL_MASK        0x0400  /* DCS_STARTUP_DONE_INL */
+#define WM8962_DCS_STARTUP_DONE_INL_SHIFT           10  /* DCS_STARTUP_DONE_INL */
+#define WM8962_DCS_STARTUP_DONE_INL_WIDTH            1  /* DCS_STARTUP_DONE_INL */
+#define WM8962_DCS_STARTUP_DONE_INR             0x0200  /* DCS_STARTUP_DONE_INR */
+#define WM8962_DCS_STARTUP_DONE_INR_MASK        0x0200  /* DCS_STARTUP_DONE_INR */
+#define WM8962_DCS_STARTUP_DONE_INR_SHIFT            9  /* DCS_STARTUP_DONE_INR */
+#define WM8962_DCS_STARTUP_DONE_INR_WIDTH            1  /* DCS_STARTUP_DONE_INR */
+#define WM8962_DCS_STARTUP_DONE_HP1L            0x0100  /* DCS_STARTUP_DONE_HP1L */
+#define WM8962_DCS_STARTUP_DONE_HP1L_MASK       0x0100  /* DCS_STARTUP_DONE_HP1L */
+#define WM8962_DCS_STARTUP_DONE_HP1L_SHIFT           8  /* DCS_STARTUP_DONE_HP1L */
+#define WM8962_DCS_STARTUP_DONE_HP1L_WIDTH           1  /* DCS_STARTUP_DONE_HP1L */
+#define WM8962_DCS_STARTUP_DONE_HP1R            0x0080  /* DCS_STARTUP_DONE_HP1R */
+#define WM8962_DCS_STARTUP_DONE_HP1R_MASK       0x0080  /* DCS_STARTUP_DONE_HP1R */
+#define WM8962_DCS_STARTUP_DONE_HP1R_SHIFT           7  /* DCS_STARTUP_DONE_HP1R */
+#define WM8962_DCS_STARTUP_DONE_HP1R_WIDTH           1  /* DCS_STARTUP_DONE_HP1R */
+
+/*
+ * R68 (0x44) - Analogue PGA Bias
+ */
+#define WM8962_HP_PGAS_BIAS_MASK                0x0007  /* HP_PGAS_BIAS - [2:0] */
+#define WM8962_HP_PGAS_BIAS_SHIFT                    0  /* HP_PGAS_BIAS - [2:0] */
+#define WM8962_HP_PGAS_BIAS_WIDTH                    3  /* HP_PGAS_BIAS - [2:0] */
+
+/*
+ * R69 (0x45) - Analogue HP 0
+ */
+#define WM8962_HP1L_RMV_SHORT                   0x0080  /* HP1L_RMV_SHORT */
+#define WM8962_HP1L_RMV_SHORT_MASK              0x0080  /* HP1L_RMV_SHORT */
+#define WM8962_HP1L_RMV_SHORT_SHIFT                  7  /* HP1L_RMV_SHORT */
+#define WM8962_HP1L_RMV_SHORT_WIDTH                  1  /* HP1L_RMV_SHORT */
+#define WM8962_HP1L_ENA_OUTP                    0x0040  /* HP1L_ENA_OUTP */
+#define WM8962_HP1L_ENA_OUTP_MASK               0x0040  /* HP1L_ENA_OUTP */
+#define WM8962_HP1L_ENA_OUTP_SHIFT                   6  /* HP1L_ENA_OUTP */
+#define WM8962_HP1L_ENA_OUTP_WIDTH                   1  /* HP1L_ENA_OUTP */
+#define WM8962_HP1L_ENA_DLY                     0x0020  /* HP1L_ENA_DLY */
+#define WM8962_HP1L_ENA_DLY_MASK                0x0020  /* HP1L_ENA_DLY */
+#define WM8962_HP1L_ENA_DLY_SHIFT                    5  /* HP1L_ENA_DLY */
+#define WM8962_HP1L_ENA_DLY_WIDTH                    1  /* HP1L_ENA_DLY */
+#define WM8962_HP1L_ENA                         0x0010  /* HP1L_ENA */
+#define WM8962_HP1L_ENA_MASK                    0x0010  /* HP1L_ENA */
+#define WM8962_HP1L_ENA_SHIFT                        4  /* HP1L_ENA */
+#define WM8962_HP1L_ENA_WIDTH                        1  /* HP1L_ENA */
+#define WM8962_HP1R_RMV_SHORT                   0x0008  /* HP1R_RMV_SHORT */
+#define WM8962_HP1R_RMV_SHORT_MASK              0x0008  /* HP1R_RMV_SHORT */
+#define WM8962_HP1R_RMV_SHORT_SHIFT                  3  /* HP1R_RMV_SHORT */
+#define WM8962_HP1R_RMV_SHORT_WIDTH                  1  /* HP1R_RMV_SHORT */
+#define WM8962_HP1R_ENA_OUTP                    0x0004  /* HP1R_ENA_OUTP */
+#define WM8962_HP1R_ENA_OUTP_MASK               0x0004  /* HP1R_ENA_OUTP */
+#define WM8962_HP1R_ENA_OUTP_SHIFT                   2  /* HP1R_ENA_OUTP */
+#define WM8962_HP1R_ENA_OUTP_WIDTH                   1  /* HP1R_ENA_OUTP */
+#define WM8962_HP1R_ENA_DLY                     0x0002  /* HP1R_ENA_DLY */
+#define WM8962_HP1R_ENA_DLY_MASK                0x0002  /* HP1R_ENA_DLY */
+#define WM8962_HP1R_ENA_DLY_SHIFT                    1  /* HP1R_ENA_DLY */
+#define WM8962_HP1R_ENA_DLY_WIDTH                    1  /* HP1R_ENA_DLY */
+#define WM8962_HP1R_ENA                         0x0001  /* HP1R_ENA */
+#define WM8962_HP1R_ENA_MASK                    0x0001  /* HP1R_ENA */
+#define WM8962_HP1R_ENA_SHIFT                        0  /* HP1R_ENA */
+#define WM8962_HP1R_ENA_WIDTH                        1  /* HP1R_ENA */
+
+/*
+ * R71 (0x47) - Analogue HP 2
+ */
+#define WM8962_HP1L_VOL_MASK                    0x01C0  /* HP1L_VOL - [8:6] */
+#define WM8962_HP1L_VOL_SHIFT                        6  /* HP1L_VOL - [8:6] */
+#define WM8962_HP1L_VOL_WIDTH                        3  /* HP1L_VOL - [8:6] */
+#define WM8962_HP1R_VOL_MASK                    0x0038  /* HP1R_VOL - [5:3] */
+#define WM8962_HP1R_VOL_SHIFT                        3  /* HP1R_VOL - [5:3] */
+#define WM8962_HP1R_VOL_WIDTH                        3  /* HP1R_VOL - [5:3] */
+#define WM8962_HP_BIAS_BOOST_MASK               0x0007  /* HP_BIAS_BOOST - [2:0] */
+#define WM8962_HP_BIAS_BOOST_SHIFT                   0  /* HP_BIAS_BOOST - [2:0] */
+#define WM8962_HP_BIAS_BOOST_WIDTH                   3  /* HP_BIAS_BOOST - [2:0] */
+
+/*
+ * R72 (0x48) - Charge Pump 1
+ */
+#define WM8962_CP_ENA                           0x0001  /* CP_ENA */
+#define WM8962_CP_ENA_MASK                      0x0001  /* CP_ENA */
+#define WM8962_CP_ENA_SHIFT                          0  /* CP_ENA */
+#define WM8962_CP_ENA_WIDTH                          1  /* CP_ENA */
+
+/*
+ * R82 (0x52) - Charge Pump B
+ */
+#define WM8962_CP_DYN_PWR                       0x0001  /* CP_DYN_PWR */
+#define WM8962_CP_DYN_PWR_MASK                  0x0001  /* CP_DYN_PWR */
+#define WM8962_CP_DYN_PWR_SHIFT                      0  /* CP_DYN_PWR */
+#define WM8962_CP_DYN_PWR_WIDTH                      1  /* CP_DYN_PWR */
+
+/*
+ * R87 (0x57) - Write Sequencer Control 1
+ */
+#define WM8962_WSEQ_AUTOSEQ_ENA                 0x0080  /* WSEQ_AUTOSEQ_ENA */
+#define WM8962_WSEQ_AUTOSEQ_ENA_MASK            0x0080  /* WSEQ_AUTOSEQ_ENA */
+#define WM8962_WSEQ_AUTOSEQ_ENA_SHIFT                7  /* WSEQ_AUTOSEQ_ENA */
+#define WM8962_WSEQ_AUTOSEQ_ENA_WIDTH                1  /* WSEQ_AUTOSEQ_ENA */
+#define WM8962_WSEQ_ENA                         0x0020  /* WSEQ_ENA */
+#define WM8962_WSEQ_ENA_MASK                    0x0020  /* WSEQ_ENA */
+#define WM8962_WSEQ_ENA_SHIFT                        5  /* WSEQ_ENA */
+#define WM8962_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+
+/*
+ * R90 (0x5A) - Write Sequencer Control 2
+ */
+#define WM8962_WSEQ_ABORT                       0x0100  /* WSEQ_ABORT */
+#define WM8962_WSEQ_ABORT_MASK                  0x0100  /* WSEQ_ABORT */
+#define WM8962_WSEQ_ABORT_SHIFT                      8  /* WSEQ_ABORT */
+#define WM8962_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM8962_WSEQ_START                       0x0080  /* WSEQ_START */
+#define WM8962_WSEQ_START_MASK                  0x0080  /* WSEQ_START */
+#define WM8962_WSEQ_START_SHIFT                      7  /* WSEQ_START */
+#define WM8962_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM8962_WSEQ_START_INDEX_MASK            0x007F  /* WSEQ_START_INDEX - [6:0] */
+#define WM8962_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [6:0] */
+#define WM8962_WSEQ_START_INDEX_WIDTH                7  /* WSEQ_START_INDEX - [6:0] */
+
+/*
+ * R93 (0x5D) - Write Sequencer Control 3
+ */
+#define WM8962_WSEQ_CURRENT_INDEX_MASK          0x03F8  /* WSEQ_CURRENT_INDEX - [9:3] */
+#define WM8962_WSEQ_CURRENT_INDEX_SHIFT              3  /* WSEQ_CURRENT_INDEX - [9:3] */
+#define WM8962_WSEQ_CURRENT_INDEX_WIDTH              7  /* WSEQ_CURRENT_INDEX - [9:3] */
+#define WM8962_WSEQ_BUSY                        0x0001  /* WSEQ_BUSY */
+#define WM8962_WSEQ_BUSY_MASK                   0x0001  /* WSEQ_BUSY */
+#define WM8962_WSEQ_BUSY_SHIFT                       0  /* WSEQ_BUSY */
+#define WM8962_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+
+/*
+ * R94 (0x5E) - Control Interface
+ */
+#define WM8962_SPI_CONTRD                       0x0040  /* SPI_CONTRD */
+#define WM8962_SPI_CONTRD_MASK                  0x0040  /* SPI_CONTRD */
+#define WM8962_SPI_CONTRD_SHIFT                      6  /* SPI_CONTRD */
+#define WM8962_SPI_CONTRD_WIDTH                      1  /* SPI_CONTRD */
+#define WM8962_SPI_4WIRE                        0x0020  /* SPI_4WIRE */
+#define WM8962_SPI_4WIRE_MASK                   0x0020  /* SPI_4WIRE */
+#define WM8962_SPI_4WIRE_SHIFT                       5  /* SPI_4WIRE */
+#define WM8962_SPI_4WIRE_WIDTH                       1  /* SPI_4WIRE */
+#define WM8962_SPI_CFG                          0x0010  /* SPI_CFG */
+#define WM8962_SPI_CFG_MASK                     0x0010  /* SPI_CFG */
+#define WM8962_SPI_CFG_SHIFT                         4  /* SPI_CFG */
+#define WM8962_SPI_CFG_WIDTH                         1  /* SPI_CFG */
+
+/*
+ * R99 (0x63) - Mixer Enables
+ */
+#define WM8962_HPMIXL_ENA                       0x0008  /* HPMIXL_ENA */
+#define WM8962_HPMIXL_ENA_MASK                  0x0008  /* HPMIXL_ENA */
+#define WM8962_HPMIXL_ENA_SHIFT                      3  /* HPMIXL_ENA */
+#define WM8962_HPMIXL_ENA_WIDTH                      1  /* HPMIXL_ENA */
+#define WM8962_HPMIXR_ENA                       0x0004  /* HPMIXR_ENA */
+#define WM8962_HPMIXR_ENA_MASK                  0x0004  /* HPMIXR_ENA */
+#define WM8962_HPMIXR_ENA_SHIFT                      2  /* HPMIXR_ENA */
+#define WM8962_HPMIXR_ENA_WIDTH                      1  /* HPMIXR_ENA */
+#define WM8962_SPKMIXL_ENA                      0x0002  /* SPKMIXL_ENA */
+#define WM8962_SPKMIXL_ENA_MASK                 0x0002  /* SPKMIXL_ENA */
+#define WM8962_SPKMIXL_ENA_SHIFT                     1  /* SPKMIXL_ENA */
+#define WM8962_SPKMIXL_ENA_WIDTH                     1  /* SPKMIXL_ENA */
+#define WM8962_SPKMIXR_ENA                      0x0001  /* SPKMIXR_ENA */
+#define WM8962_SPKMIXR_ENA_MASK                 0x0001  /* SPKMIXR_ENA */
+#define WM8962_SPKMIXR_ENA_SHIFT                     0  /* SPKMIXR_ENA */
+#define WM8962_SPKMIXR_ENA_WIDTH                     1  /* SPKMIXR_ENA */
+
+/*
+ * R100 (0x64) - Headphone Mixer (1)
+ */
+#define WM8962_HPMIXL_TO_HPOUTL_PGA             0x0080  /* HPMIXL_TO_HPOUTL_PGA */
+#define WM8962_HPMIXL_TO_HPOUTL_PGA_MASK        0x0080  /* HPMIXL_TO_HPOUTL_PGA */
+#define WM8962_HPMIXL_TO_HPOUTL_PGA_SHIFT            7  /* HPMIXL_TO_HPOUTL_PGA */
+#define WM8962_HPMIXL_TO_HPOUTL_PGA_WIDTH            1  /* HPMIXL_TO_HPOUTL_PGA */
+#define WM8962_DACL_TO_HPMIXL                   0x0020  /* DACL_TO_HPMIXL */
+#define WM8962_DACL_TO_HPMIXL_MASK              0x0020  /* DACL_TO_HPMIXL */
+#define WM8962_DACL_TO_HPMIXL_SHIFT                  5  /* DACL_TO_HPMIXL */
+#define WM8962_DACL_TO_HPMIXL_WIDTH                  1  /* DACL_TO_HPMIXL */
+#define WM8962_DACR_TO_HPMIXL                   0x0010  /* DACR_TO_HPMIXL */
+#define WM8962_DACR_TO_HPMIXL_MASK              0x0010  /* DACR_TO_HPMIXL */
+#define WM8962_DACR_TO_HPMIXL_SHIFT                  4  /* DACR_TO_HPMIXL */
+#define WM8962_DACR_TO_HPMIXL_WIDTH                  1  /* DACR_TO_HPMIXL */
+#define WM8962_MIXINL_TO_HPMIXL                 0x0008  /* MIXINL_TO_HPMIXL */
+#define WM8962_MIXINL_TO_HPMIXL_MASK            0x0008  /* MIXINL_TO_HPMIXL */
+#define WM8962_MIXINL_TO_HPMIXL_SHIFT                3  /* MIXINL_TO_HPMIXL */
+#define WM8962_MIXINL_TO_HPMIXL_WIDTH                1  /* MIXINL_TO_HPMIXL */
+#define WM8962_MIXINR_TO_HPMIXL                 0x0004  /* MIXINR_TO_HPMIXL */
+#define WM8962_MIXINR_TO_HPMIXL_MASK            0x0004  /* MIXINR_TO_HPMIXL */
+#define WM8962_MIXINR_TO_HPMIXL_SHIFT                2  /* MIXINR_TO_HPMIXL */
+#define WM8962_MIXINR_TO_HPMIXL_WIDTH                1  /* MIXINR_TO_HPMIXL */
+#define WM8962_IN4L_TO_HPMIXL                   0x0002  /* IN4L_TO_HPMIXL */
+#define WM8962_IN4L_TO_HPMIXL_MASK              0x0002  /* IN4L_TO_HPMIXL */
+#define WM8962_IN4L_TO_HPMIXL_SHIFT                  1  /* IN4L_TO_HPMIXL */
+#define WM8962_IN4L_TO_HPMIXL_WIDTH                  1  /* IN4L_TO_HPMIXL */
+#define WM8962_IN4R_TO_HPMIXL                   0x0001  /* IN4R_TO_HPMIXL */
+#define WM8962_IN4R_TO_HPMIXL_MASK              0x0001  /* IN4R_TO_HPMIXL */
+#define WM8962_IN4R_TO_HPMIXL_SHIFT                  0  /* IN4R_TO_HPMIXL */
+#define WM8962_IN4R_TO_HPMIXL_WIDTH                  1  /* IN4R_TO_HPMIXL */
+
+/*
+ * R101 (0x65) - Headphone Mixer (2)
+ */
+#define WM8962_HPMIXR_TO_HPOUTR_PGA             0x0080  /* HPMIXR_TO_HPOUTR_PGA */
+#define WM8962_HPMIXR_TO_HPOUTR_PGA_MASK        0x0080  /* HPMIXR_TO_HPOUTR_PGA */
+#define WM8962_HPMIXR_TO_HPOUTR_PGA_SHIFT            7  /* HPMIXR_TO_HPOUTR_PGA */
+#define WM8962_HPMIXR_TO_HPOUTR_PGA_WIDTH            1  /* HPMIXR_TO_HPOUTR_PGA */
+#define WM8962_DACL_TO_HPMIXR                   0x0020  /* DACL_TO_HPMIXR */
+#define WM8962_DACL_TO_HPMIXR_MASK              0x0020  /* DACL_TO_HPMIXR */
+#define WM8962_DACL_TO_HPMIXR_SHIFT                  5  /* DACL_TO_HPMIXR */
+#define WM8962_DACL_TO_HPMIXR_WIDTH                  1  /* DACL_TO_HPMIXR */
+#define WM8962_DACR_TO_HPMIXR                   0x0010  /* DACR_TO_HPMIXR */
+#define WM8962_DACR_TO_HPMIXR_MASK              0x0010  /* DACR_TO_HPMIXR */
+#define WM8962_DACR_TO_HPMIXR_SHIFT                  4  /* DACR_TO_HPMIXR */
+#define WM8962_DACR_TO_HPMIXR_WIDTH                  1  /* DACR_TO_HPMIXR */
+#define WM8962_MIXINL_TO_HPMIXR                 0x0008  /* MIXINL_TO_HPMIXR */
+#define WM8962_MIXINL_TO_HPMIXR_MASK            0x0008  /* MIXINL_TO_HPMIXR */
+#define WM8962_MIXINL_TO_HPMIXR_SHIFT                3  /* MIXINL_TO_HPMIXR */
+#define WM8962_MIXINL_TO_HPMIXR_WIDTH                1  /* MIXINL_TO_HPMIXR */
+#define WM8962_MIXINR_TO_HPMIXR                 0x0004  /* MIXINR_TO_HPMIXR */
+#define WM8962_MIXINR_TO_HPMIXR_MASK            0x0004  /* MIXINR_TO_HPMIXR */
+#define WM8962_MIXINR_TO_HPMIXR_SHIFT                2  /* MIXINR_TO_HPMIXR */
+#define WM8962_MIXINR_TO_HPMIXR_WIDTH                1  /* MIXINR_TO_HPMIXR */
+#define WM8962_IN4L_TO_HPMIXR                   0x0002  /* IN4L_TO_HPMIXR */
+#define WM8962_IN4L_TO_HPMIXR_MASK              0x0002  /* IN4L_TO_HPMIXR */
+#define WM8962_IN4L_TO_HPMIXR_SHIFT                  1  /* IN4L_TO_HPMIXR */
+#define WM8962_IN4L_TO_HPMIXR_WIDTH                  1  /* IN4L_TO_HPMIXR */
+#define WM8962_IN4R_TO_HPMIXR                   0x0001  /* IN4R_TO_HPMIXR */
+#define WM8962_IN4R_TO_HPMIXR_MASK              0x0001  /* IN4R_TO_HPMIXR */
+#define WM8962_IN4R_TO_HPMIXR_SHIFT                  0  /* IN4R_TO_HPMIXR */
+#define WM8962_IN4R_TO_HPMIXR_WIDTH                  1  /* IN4R_TO_HPMIXR */
+
+/*
+ * R102 (0x66) - Headphone Mixer (3)
+ */
+#define WM8962_HPMIXL_MUTE                      0x0100  /* HPMIXL_MUTE */
+#define WM8962_HPMIXL_MUTE_MASK                 0x0100  /* HPMIXL_MUTE */
+#define WM8962_HPMIXL_MUTE_SHIFT                     8  /* HPMIXL_MUTE */
+#define WM8962_HPMIXL_MUTE_WIDTH                     1  /* HPMIXL_MUTE */
+#define WM8962_MIXINL_HPMIXL_VOL                0x0080  /* MIXINL_HPMIXL_VOL */
+#define WM8962_MIXINL_HPMIXL_VOL_MASK           0x0080  /* MIXINL_HPMIXL_VOL */
+#define WM8962_MIXINL_HPMIXL_VOL_SHIFT               7  /* MIXINL_HPMIXL_VOL */
+#define WM8962_MIXINL_HPMIXL_VOL_WIDTH               1  /* MIXINL_HPMIXL_VOL */
+#define WM8962_MIXINR_HPMIXL_VOL                0x0040  /* MIXINR_HPMIXL_VOL */
+#define WM8962_MIXINR_HPMIXL_VOL_MASK           0x0040  /* MIXINR_HPMIXL_VOL */
+#define WM8962_MIXINR_HPMIXL_VOL_SHIFT               6  /* MIXINR_HPMIXL_VOL */
+#define WM8962_MIXINR_HPMIXL_VOL_WIDTH               1  /* MIXINR_HPMIXL_VOL */
+#define WM8962_IN4L_HPMIXL_VOL_MASK             0x0038  /* IN4L_HPMIXL_VOL - [5:3] */
+#define WM8962_IN4L_HPMIXL_VOL_SHIFT                 3  /* IN4L_HPMIXL_VOL - [5:3] */
+#define WM8962_IN4L_HPMIXL_VOL_WIDTH                 3  /* IN4L_HPMIXL_VOL - [5:3] */
+#define WM8962_IN4R_HPMIXL_VOL_MASK             0x0007  /* IN4R_HPMIXL_VOL - [2:0] */
+#define WM8962_IN4R_HPMIXL_VOL_SHIFT                 0  /* IN4R_HPMIXL_VOL - [2:0] */
+#define WM8962_IN4R_HPMIXL_VOL_WIDTH                 3  /* IN4R_HPMIXL_VOL - [2:0] */
+
+/*
+ * R103 (0x67) - Headphone Mixer (4)
+ */
+#define WM8962_HPMIXR_MUTE                      0x0100  /* HPMIXR_MUTE */
+#define WM8962_HPMIXR_MUTE_MASK                 0x0100  /* HPMIXR_MUTE */
+#define WM8962_HPMIXR_MUTE_SHIFT                     8  /* HPMIXR_MUTE */
+#define WM8962_HPMIXR_MUTE_WIDTH                     1  /* HPMIXR_MUTE */
+#define WM8962_MIXINL_HPMIXR_VOL                0x0080  /* MIXINL_HPMIXR_VOL */
+#define WM8962_MIXINL_HPMIXR_VOL_MASK           0x0080  /* MIXINL_HPMIXR_VOL */
+#define WM8962_MIXINL_HPMIXR_VOL_SHIFT               7  /* MIXINL_HPMIXR_VOL */
+#define WM8962_MIXINL_HPMIXR_VOL_WIDTH               1  /* MIXINL_HPMIXR_VOL */
+#define WM8962_MIXINR_HPMIXR_VOL                0x0040  /* MIXINR_HPMIXR_VOL */
+#define WM8962_MIXINR_HPMIXR_VOL_MASK           0x0040  /* MIXINR_HPMIXR_VOL */
+#define WM8962_MIXINR_HPMIXR_VOL_SHIFT               6  /* MIXINR_HPMIXR_VOL */
+#define WM8962_MIXINR_HPMIXR_VOL_WIDTH               1  /* MIXINR_HPMIXR_VOL */
+#define WM8962_IN4L_HPMIXR_VOL_MASK             0x0038  /* IN4L_HPMIXR_VOL - [5:3] */
+#define WM8962_IN4L_HPMIXR_VOL_SHIFT                 3  /* IN4L_HPMIXR_VOL - [5:3] */
+#define WM8962_IN4L_HPMIXR_VOL_WIDTH                 3  /* IN4L_HPMIXR_VOL - [5:3] */
+#define WM8962_IN4R_HPMIXR_VOL_MASK             0x0007  /* IN4R_HPMIXR_VOL - [2:0] */
+#define WM8962_IN4R_HPMIXR_VOL_SHIFT                 0  /* IN4R_HPMIXR_VOL - [2:0] */
+#define WM8962_IN4R_HPMIXR_VOL_WIDTH                 3  /* IN4R_HPMIXR_VOL - [2:0] */
+
+/*
+ * R105 (0x69) - Speaker Mixer (1)
+ */
+#define WM8962_SPKMIXL_TO_SPKOUTL_PGA           0x0080  /* SPKMIXL_TO_SPKOUTL_PGA */
+#define WM8962_SPKMIXL_TO_SPKOUTL_PGA_MASK      0x0080  /* SPKMIXL_TO_SPKOUTL_PGA */
+#define WM8962_SPKMIXL_TO_SPKOUTL_PGA_SHIFT          7  /* SPKMIXL_TO_SPKOUTL_PGA */
+#define WM8962_SPKMIXL_TO_SPKOUTL_PGA_WIDTH          1  /* SPKMIXL_TO_SPKOUTL_PGA */
+#define WM8962_DACL_TO_SPKMIXL                  0x0020  /* DACL_TO_SPKMIXL */
+#define WM8962_DACL_TO_SPKMIXL_MASK             0x0020  /* DACL_TO_SPKMIXL */
+#define WM8962_DACL_TO_SPKMIXL_SHIFT                 5  /* DACL_TO_SPKMIXL */
+#define WM8962_DACL_TO_SPKMIXL_WIDTH                 1  /* DACL_TO_SPKMIXL */
+#define WM8962_DACR_TO_SPKMIXL                  0x0010  /* DACR_TO_SPKMIXL */
+#define WM8962_DACR_TO_SPKMIXL_MASK             0x0010  /* DACR_TO_SPKMIXL */
+#define WM8962_DACR_TO_SPKMIXL_SHIFT                 4  /* DACR_TO_SPKMIXL */
+#define WM8962_DACR_TO_SPKMIXL_WIDTH                 1  /* DACR_TO_SPKMIXL */
+#define WM8962_MIXINL_TO_SPKMIXL                0x0008  /* MIXINL_TO_SPKMIXL */
+#define WM8962_MIXINL_TO_SPKMIXL_MASK           0x0008  /* MIXINL_TO_SPKMIXL */
+#define WM8962_MIXINL_TO_SPKMIXL_SHIFT               3  /* MIXINL_TO_SPKMIXL */
+#define WM8962_MIXINL_TO_SPKMIXL_WIDTH               1  /* MIXINL_TO_SPKMIXL */
+#define WM8962_MIXINR_TO_SPKMIXL                0x0004  /* MIXINR_TO_SPKMIXL */
+#define WM8962_MIXINR_TO_SPKMIXL_MASK           0x0004  /* MIXINR_TO_SPKMIXL */
+#define WM8962_MIXINR_TO_SPKMIXL_SHIFT               2  /* MIXINR_TO_SPKMIXL */
+#define WM8962_MIXINR_TO_SPKMIXL_WIDTH               1  /* MIXINR_TO_SPKMIXL */
+#define WM8962_IN4L_TO_SPKMIXL                  0x0002  /* IN4L_TO_SPKMIXL */
+#define WM8962_IN4L_TO_SPKMIXL_MASK             0x0002  /* IN4L_TO_SPKMIXL */
+#define WM8962_IN4L_TO_SPKMIXL_SHIFT                 1  /* IN4L_TO_SPKMIXL */
+#define WM8962_IN4L_TO_SPKMIXL_WIDTH                 1  /* IN4L_TO_SPKMIXL */
+#define WM8962_IN4R_TO_SPKMIXL                  0x0001  /* IN4R_TO_SPKMIXL */
+#define WM8962_IN4R_TO_SPKMIXL_MASK             0x0001  /* IN4R_TO_SPKMIXL */
+#define WM8962_IN4R_TO_SPKMIXL_SHIFT                 0  /* IN4R_TO_SPKMIXL */
+#define WM8962_IN4R_TO_SPKMIXL_WIDTH                 1  /* IN4R_TO_SPKMIXL */
+
+/*
+ * R106 (0x6A) - Speaker Mixer (2)
+ */
+#define WM8962_SPKMIXR_TO_SPKOUTR_PGA           0x0080  /* SPKMIXR_TO_SPKOUTR_PGA */
+#define WM8962_SPKMIXR_TO_SPKOUTR_PGA_MASK      0x0080  /* SPKMIXR_TO_SPKOUTR_PGA */
+#define WM8962_SPKMIXR_TO_SPKOUTR_PGA_SHIFT          7  /* SPKMIXR_TO_SPKOUTR_PGA */
+#define WM8962_SPKMIXR_TO_SPKOUTR_PGA_WIDTH          1  /* SPKMIXR_TO_SPKOUTR_PGA */
+#define WM8962_DACL_TO_SPKMIXR                  0x0020  /* DACL_TO_SPKMIXR */
+#define WM8962_DACL_TO_SPKMIXR_MASK             0x0020  /* DACL_TO_SPKMIXR */
+#define WM8962_DACL_TO_SPKMIXR_SHIFT                 5  /* DACL_TO_SPKMIXR */
+#define WM8962_DACL_TO_SPKMIXR_WIDTH                 1  /* DACL_TO_SPKMIXR */
+#define WM8962_DACR_TO_SPKMIXR                  0x0010  /* DACR_TO_SPKMIXR */
+#define WM8962_DACR_TO_SPKMIXR_MASK             0x0010  /* DACR_TO_SPKMIXR */
+#define WM8962_DACR_TO_SPKMIXR_SHIFT                 4  /* DACR_TO_SPKMIXR */
+#define WM8962_DACR_TO_SPKMIXR_WIDTH                 1  /* DACR_TO_SPKMIXR */
+#define WM8962_MIXINL_TO_SPKMIXR                0x0008  /* MIXINL_TO_SPKMIXR */
+#define WM8962_MIXINL_TO_SPKMIXR_MASK           0x0008  /* MIXINL_TO_SPKMIXR */
+#define WM8962_MIXINL_TO_SPKMIXR_SHIFT               3  /* MIXINL_TO_SPKMIXR */
+#define WM8962_MIXINL_TO_SPKMIXR_WIDTH               1  /* MIXINL_TO_SPKMIXR */
+#define WM8962_MIXINR_TO_SPKMIXR                0x0004  /* MIXINR_TO_SPKMIXR */
+#define WM8962_MIXINR_TO_SPKMIXR_MASK           0x0004  /* MIXINR_TO_SPKMIXR */
+#define WM8962_MIXINR_TO_SPKMIXR_SHIFT               2  /* MIXINR_TO_SPKMIXR */
+#define WM8962_MIXINR_TO_SPKMIXR_WIDTH               1  /* MIXINR_TO_SPKMIXR */
+#define WM8962_IN4L_TO_SPKMIXR                  0x0002  /* IN4L_TO_SPKMIXR */
+#define WM8962_IN4L_TO_SPKMIXR_MASK             0x0002  /* IN4L_TO_SPKMIXR */
+#define WM8962_IN4L_TO_SPKMIXR_SHIFT                 1  /* IN4L_TO_SPKMIXR */
+#define WM8962_IN4L_TO_SPKMIXR_WIDTH                 1  /* IN4L_TO_SPKMIXR */
+#define WM8962_IN4R_TO_SPKMIXR                  0x0001  /* IN4R_TO_SPKMIXR */
+#define WM8962_IN4R_TO_SPKMIXR_MASK             0x0001  /* IN4R_TO_SPKMIXR */
+#define WM8962_IN4R_TO_SPKMIXR_SHIFT                 0  /* IN4R_TO_SPKMIXR */
+#define WM8962_IN4R_TO_SPKMIXR_WIDTH                 1  /* IN4R_TO_SPKMIXR */
+
+/*
+ * R107 (0x6B) - Speaker Mixer (3)
+ */
+#define WM8962_SPKMIXL_MUTE                     0x0100  /* SPKMIXL_MUTE */
+#define WM8962_SPKMIXL_MUTE_MASK                0x0100  /* SPKMIXL_MUTE */
+#define WM8962_SPKMIXL_MUTE_SHIFT                    8  /* SPKMIXL_MUTE */
+#define WM8962_SPKMIXL_MUTE_WIDTH                    1  /* SPKMIXL_MUTE */
+#define WM8962_MIXINL_SPKMIXL_VOL               0x0080  /* MIXINL_SPKMIXL_VOL */
+#define WM8962_MIXINL_SPKMIXL_VOL_MASK          0x0080  /* MIXINL_SPKMIXL_VOL */
+#define WM8962_MIXINL_SPKMIXL_VOL_SHIFT              7  /* MIXINL_SPKMIXL_VOL */
+#define WM8962_MIXINL_SPKMIXL_VOL_WIDTH              1  /* MIXINL_SPKMIXL_VOL */
+#define WM8962_MIXINR_SPKMIXL_VOL               0x0040  /* MIXINR_SPKMIXL_VOL */
+#define WM8962_MIXINR_SPKMIXL_VOL_MASK          0x0040  /* MIXINR_SPKMIXL_VOL */
+#define WM8962_MIXINR_SPKMIXL_VOL_SHIFT              6  /* MIXINR_SPKMIXL_VOL */
+#define WM8962_MIXINR_SPKMIXL_VOL_WIDTH              1  /* MIXINR_SPKMIXL_VOL */
+#define WM8962_IN4L_SPKMIXL_VOL_MASK            0x0038  /* IN4L_SPKMIXL_VOL - [5:3] */
+#define WM8962_IN4L_SPKMIXL_VOL_SHIFT                3  /* IN4L_SPKMIXL_VOL - [5:3] */
+#define WM8962_IN4L_SPKMIXL_VOL_WIDTH                3  /* IN4L_SPKMIXL_VOL - [5:3] */
+#define WM8962_IN4R_SPKMIXL_VOL_MASK            0x0007  /* IN4R_SPKMIXL_VOL - [2:0] */
+#define WM8962_IN4R_SPKMIXL_VOL_SHIFT                0  /* IN4R_SPKMIXL_VOL - [2:0] */
+#define WM8962_IN4R_SPKMIXL_VOL_WIDTH                3  /* IN4R_SPKMIXL_VOL - [2:0] */
+
+/*
+ * R108 (0x6C) - Speaker Mixer (4)
+ */
+#define WM8962_SPKMIXR_MUTE                     0x0100  /* SPKMIXR_MUTE */
+#define WM8962_SPKMIXR_MUTE_MASK                0x0100  /* SPKMIXR_MUTE */
+#define WM8962_SPKMIXR_MUTE_SHIFT                    8  /* SPKMIXR_MUTE */
+#define WM8962_SPKMIXR_MUTE_WIDTH                    1  /* SPKMIXR_MUTE */
+#define WM8962_MIXINL_SPKMIXR_VOL               0x0080  /* MIXINL_SPKMIXR_VOL */
+#define WM8962_MIXINL_SPKMIXR_VOL_MASK          0x0080  /* MIXINL_SPKMIXR_VOL */
+#define WM8962_MIXINL_SPKMIXR_VOL_SHIFT              7  /* MIXINL_SPKMIXR_VOL */
+#define WM8962_MIXINL_SPKMIXR_VOL_WIDTH              1  /* MIXINL_SPKMIXR_VOL */
+#define WM8962_MIXINR_SPKMIXR_VOL               0x0040  /* MIXINR_SPKMIXR_VOL */
+#define WM8962_MIXINR_SPKMIXR_VOL_MASK          0x0040  /* MIXINR_SPKMIXR_VOL */
+#define WM8962_MIXINR_SPKMIXR_VOL_SHIFT              6  /* MIXINR_SPKMIXR_VOL */
+#define WM8962_MIXINR_SPKMIXR_VOL_WIDTH              1  /* MIXINR_SPKMIXR_VOL */
+#define WM8962_IN4L_SPKMIXR_VOL_MASK            0x0038  /* IN4L_SPKMIXR_VOL - [5:3] */
+#define WM8962_IN4L_SPKMIXR_VOL_SHIFT                3  /* IN4L_SPKMIXR_VOL - [5:3] */
+#define WM8962_IN4L_SPKMIXR_VOL_WIDTH                3  /* IN4L_SPKMIXR_VOL - [5:3] */
+#define WM8962_IN4R_SPKMIXR_VOL_MASK            0x0007  /* IN4R_SPKMIXR_VOL - [2:0] */
+#define WM8962_IN4R_SPKMIXR_VOL_SHIFT                0  /* IN4R_SPKMIXR_VOL - [2:0] */
+#define WM8962_IN4R_SPKMIXR_VOL_WIDTH                3  /* IN4R_SPKMIXR_VOL - [2:0] */
+
+/*
+ * R109 (0x6D) - Speaker Mixer (5)
+ */
+#define WM8962_DACL_SPKMIXL_VOL                 0x0080  /* DACL_SPKMIXL_VOL */
+#define WM8962_DACL_SPKMIXL_VOL_MASK            0x0080  /* DACL_SPKMIXL_VOL */
+#define WM8962_DACL_SPKMIXL_VOL_SHIFT                7  /* DACL_SPKMIXL_VOL */
+#define WM8962_DACL_SPKMIXL_VOL_WIDTH                1  /* DACL_SPKMIXL_VOL */
+#define WM8962_DACR_SPKMIXL_VOL                 0x0040  /* DACR_SPKMIXL_VOL */
+#define WM8962_DACR_SPKMIXL_VOL_MASK            0x0040  /* DACR_SPKMIXL_VOL */
+#define WM8962_DACR_SPKMIXL_VOL_SHIFT                6  /* DACR_SPKMIXL_VOL */
+#define WM8962_DACR_SPKMIXL_VOL_WIDTH                1  /* DACR_SPKMIXL_VOL */
+#define WM8962_DACL_SPKMIXR_VOL                 0x0020  /* DACL_SPKMIXR_VOL */
+#define WM8962_DACL_SPKMIXR_VOL_MASK            0x0020  /* DACL_SPKMIXR_VOL */
+#define WM8962_DACL_SPKMIXR_VOL_SHIFT                5  /* DACL_SPKMIXR_VOL */
+#define WM8962_DACL_SPKMIXR_VOL_WIDTH                1  /* DACL_SPKMIXR_VOL */
+#define WM8962_DACR_SPKMIXR_VOL                 0x0010  /* DACR_SPKMIXR_VOL */
+#define WM8962_DACR_SPKMIXR_VOL_MASK            0x0010  /* DACR_SPKMIXR_VOL */
+#define WM8962_DACR_SPKMIXR_VOL_SHIFT                4  /* DACR_SPKMIXR_VOL */
+#define WM8962_DACR_SPKMIXR_VOL_WIDTH                1  /* DACR_SPKMIXR_VOL */
+
+/*
+ * R110 (0x6E) - Beep Generator (1)
+ */
+#define WM8962_BEEP_GAIN_MASK                   0x00F0  /* BEEP_GAIN - [7:4] */
+#define WM8962_BEEP_GAIN_SHIFT                       4  /* BEEP_GAIN - [7:4] */
+#define WM8962_BEEP_GAIN_WIDTH                       4  /* BEEP_GAIN - [7:4] */
+#define WM8962_BEEP_RATE_MASK                   0x0006  /* BEEP_RATE - [2:1] */
+#define WM8962_BEEP_RATE_SHIFT                       1  /* BEEP_RATE - [2:1] */
+#define WM8962_BEEP_RATE_WIDTH                       2  /* BEEP_RATE - [2:1] */
+#define WM8962_BEEP_ENA                         0x0001  /* BEEP_ENA */
+#define WM8962_BEEP_ENA_MASK                    0x0001  /* BEEP_ENA */
+#define WM8962_BEEP_ENA_SHIFT                        0  /* BEEP_ENA */
+#define WM8962_BEEP_ENA_WIDTH                        1  /* BEEP_ENA */
+
+/*
+ * R115 (0x73) - Oscillator Trim (3)
+ */
+#define WM8962_OSC_TRIM_XTI_MASK                0x001F  /* OSC_TRIM_XTI - [4:0] */
+#define WM8962_OSC_TRIM_XTI_SHIFT                    0  /* OSC_TRIM_XTI - [4:0] */
+#define WM8962_OSC_TRIM_XTI_WIDTH                    5  /* OSC_TRIM_XTI - [4:0] */
+
+/*
+ * R116 (0x74) - Oscillator Trim (4)
+ */
+#define WM8962_OSC_TRIM_XTO_MASK                0x001F  /* OSC_TRIM_XTO - [4:0] */
+#define WM8962_OSC_TRIM_XTO_SHIFT                    0  /* OSC_TRIM_XTO - [4:0] */
+#define WM8962_OSC_TRIM_XTO_WIDTH                    5  /* OSC_TRIM_XTO - [4:0] */
+
+/*
+ * R119 (0x77) - Oscillator Trim (7)
+ */
+#define WM8962_XTO_CAP_SEL_MASK                 0x00F0  /* XTO_CAP_SEL - [7:4] */
+#define WM8962_XTO_CAP_SEL_SHIFT                     4  /* XTO_CAP_SEL - [7:4] */
+#define WM8962_XTO_CAP_SEL_WIDTH                     4  /* XTO_CAP_SEL - [7:4] */
+#define WM8962_XTI_CAP_SEL_MASK                 0x000F  /* XTI_CAP_SEL - [3:0] */
+#define WM8962_XTI_CAP_SEL_SHIFT                     0  /* XTI_CAP_SEL - [3:0] */
+#define WM8962_XTI_CAP_SEL_WIDTH                     4  /* XTI_CAP_SEL - [3:0] */
+
+/*
+ * R124 (0x7C) - Analogue Clocking1
+ */
+#define WM8962_CLKOUT2_SEL_MASK                 0x0060  /* CLKOUT2_SEL - [6:5] */
+#define WM8962_CLKOUT2_SEL_SHIFT                     5  /* CLKOUT2_SEL - [6:5] */
+#define WM8962_CLKOUT2_SEL_WIDTH                     2  /* CLKOUT2_SEL - [6:5] */
+#define WM8962_CLKOUT3_SEL_MASK                 0x0018  /* CLKOUT3_SEL - [4:3] */
+#define WM8962_CLKOUT3_SEL_SHIFT                     3  /* CLKOUT3_SEL - [4:3] */
+#define WM8962_CLKOUT3_SEL_WIDTH                     2  /* CLKOUT3_SEL - [4:3] */
+#define WM8962_CLKOUT5_SEL                      0x0001  /* CLKOUT5_SEL */
+#define WM8962_CLKOUT5_SEL_MASK                 0x0001  /* CLKOUT5_SEL */
+#define WM8962_CLKOUT5_SEL_SHIFT                     0  /* CLKOUT5_SEL */
+#define WM8962_CLKOUT5_SEL_WIDTH                     1  /* CLKOUT5_SEL */
+
+/*
+ * R125 (0x7D) - Analogue Clocking2
+ */
+#define WM8962_PLL2_OUTDIV                      0x0080  /* PLL2_OUTDIV */
+#define WM8962_PLL2_OUTDIV_MASK                 0x0080  /* PLL2_OUTDIV */
+#define WM8962_PLL2_OUTDIV_SHIFT                     7  /* PLL2_OUTDIV */
+#define WM8962_PLL2_OUTDIV_WIDTH                     1  /* PLL2_OUTDIV */
+#define WM8962_PLL3_OUTDIV                      0x0040  /* PLL3_OUTDIV */
+#define WM8962_PLL3_OUTDIV_MASK                 0x0040  /* PLL3_OUTDIV */
+#define WM8962_PLL3_OUTDIV_SHIFT                     6  /* PLL3_OUTDIV */
+#define WM8962_PLL3_OUTDIV_WIDTH                     1  /* PLL3_OUTDIV */
+#define WM8962_PLL_SYSCLK_DIV_MASK              0x0018  /* PLL_SYSCLK_DIV - [4:3] */
+#define WM8962_PLL_SYSCLK_DIV_SHIFT                  3  /* PLL_SYSCLK_DIV - [4:3] */
+#define WM8962_PLL_SYSCLK_DIV_WIDTH                  2  /* PLL_SYSCLK_DIV - [4:3] */
+#define WM8962_CLKOUT3_DIV                      0x0004  /* CLKOUT3_DIV */
+#define WM8962_CLKOUT3_DIV_MASK                 0x0004  /* CLKOUT3_DIV */
+#define WM8962_CLKOUT3_DIV_SHIFT                     2  /* CLKOUT3_DIV */
+#define WM8962_CLKOUT3_DIV_WIDTH                     1  /* CLKOUT3_DIV */
+#define WM8962_CLKOUT2_DIV                      0x0002  /* CLKOUT2_DIV */
+#define WM8962_CLKOUT2_DIV_MASK                 0x0002  /* CLKOUT2_DIV */
+#define WM8962_CLKOUT2_DIV_SHIFT                     1  /* CLKOUT2_DIV */
+#define WM8962_CLKOUT2_DIV_WIDTH                     1  /* CLKOUT2_DIV */
+#define WM8962_CLKOUT5_DIV                      0x0001  /* CLKOUT5_DIV */
+#define WM8962_CLKOUT5_DIV_MASK                 0x0001  /* CLKOUT5_DIV */
+#define WM8962_CLKOUT5_DIV_SHIFT                     0  /* CLKOUT5_DIV */
+#define WM8962_CLKOUT5_DIV_WIDTH                     1  /* CLKOUT5_DIV */
+
+/*
+ * R126 (0x7E) - Analogue Clocking3
+ */
+#define WM8962_CLKOUT2_OE                       0x0008  /* CLKOUT2_OE */
+#define WM8962_CLKOUT2_OE_MASK                  0x0008  /* CLKOUT2_OE */
+#define WM8962_CLKOUT2_OE_SHIFT                      3  /* CLKOUT2_OE */
+#define WM8962_CLKOUT2_OE_WIDTH                      1  /* CLKOUT2_OE */
+#define WM8962_CLKOUT3_OE                       0x0004  /* CLKOUT3_OE */
+#define WM8962_CLKOUT3_OE_MASK                  0x0004  /* CLKOUT3_OE */
+#define WM8962_CLKOUT3_OE_SHIFT                      2  /* CLKOUT3_OE */
+#define WM8962_CLKOUT3_OE_WIDTH                      1  /* CLKOUT3_OE */
+#define WM8962_CLKOUT5_OE                       0x0001  /* CLKOUT5_OE */
+#define WM8962_CLKOUT5_OE_MASK                  0x0001  /* CLKOUT5_OE */
+#define WM8962_CLKOUT5_OE_SHIFT                      0  /* CLKOUT5_OE */
+#define WM8962_CLKOUT5_OE_WIDTH                      1  /* CLKOUT5_OE */
+
+/*
+ * R127 (0x7F) - PLL Software Reset
+ */
+#define WM8962_SW_RESET_PLL_MASK                0xFFFF  /* SW_RESET_PLL - [15:0] */
+#define WM8962_SW_RESET_PLL_SHIFT                    0  /* SW_RESET_PLL - [15:0] */
+#define WM8962_SW_RESET_PLL_WIDTH                   16  /* SW_RESET_PLL - [15:0] */
+
+/*
+ * R129 (0x81) - PLL2
+ */
+#define WM8962_OSC_ENA                          0x0080  /* OSC_ENA */
+#define WM8962_OSC_ENA_MASK                     0x0080  /* OSC_ENA */
+#define WM8962_OSC_ENA_SHIFT                         7  /* OSC_ENA */
+#define WM8962_OSC_ENA_WIDTH                         1  /* OSC_ENA */
+#define WM8962_PLL2_ENA                         0x0020  /* PLL2_ENA */
+#define WM8962_PLL2_ENA_MASK                    0x0020  /* PLL2_ENA */
+#define WM8962_PLL2_ENA_SHIFT                        5  /* PLL2_ENA */
+#define WM8962_PLL2_ENA_WIDTH                        1  /* PLL2_ENA */
+#define WM8962_PLL3_ENA                         0x0010  /* PLL3_ENA */
+#define WM8962_PLL3_ENA_MASK                    0x0010  /* PLL3_ENA */
+#define WM8962_PLL3_ENA_SHIFT                        4  /* PLL3_ENA */
+#define WM8962_PLL3_ENA_WIDTH                        1  /* PLL3_ENA */
+
+/*
+ * R131 (0x83) - PLL 4
+ */
+#define WM8962_PLL_CLK_SRC                      0x0002  /* PLL_CLK_SRC */
+#define WM8962_PLL_CLK_SRC_MASK                 0x0002  /* PLL_CLK_SRC */
+#define WM8962_PLL_CLK_SRC_SHIFT                     1  /* PLL_CLK_SRC */
+#define WM8962_PLL_CLK_SRC_WIDTH                     1  /* PLL_CLK_SRC */
+#define WM8962_FLL_TO_PLL3                      0x0001  /* FLL_TO_PLL3 */
+#define WM8962_FLL_TO_PLL3_MASK                 0x0001  /* FLL_TO_PLL3 */
+#define WM8962_FLL_TO_PLL3_SHIFT                     0  /* FLL_TO_PLL3 */
+#define WM8962_FLL_TO_PLL3_WIDTH                     1  /* FLL_TO_PLL3 */
+
+/*
+ * R136 (0x88) - PLL 9
+ */
+#define WM8962_PLL2_FRAC                        0x0040  /* PLL2_FRAC */
+#define WM8962_PLL2_FRAC_MASK                   0x0040  /* PLL2_FRAC */
+#define WM8962_PLL2_FRAC_SHIFT                       6  /* PLL2_FRAC */
+#define WM8962_PLL2_FRAC_WIDTH                       1  /* PLL2_FRAC */
+#define WM8962_PLL2_N_MASK                      0x001F  /* PLL2_N - [4:0] */
+#define WM8962_PLL2_N_SHIFT                          0  /* PLL2_N - [4:0] */
+#define WM8962_PLL2_N_WIDTH                          5  /* PLL2_N - [4:0] */
+
+/*
+ * R137 (0x89) - PLL 10
+ */
+#define WM8962_PLL2_K_MASK                      0x00FF  /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_SHIFT                          0  /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_WIDTH                          8  /* PLL2_K - [7:0] */
+
+/*
+ * R138 (0x8A) - PLL 11
+ */
+#define WM8962_PLL2_K_MASK                      0x00FF  /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_SHIFT                          0  /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_WIDTH                          8  /* PLL2_K - [7:0] */
+
+/*
+ * R139 (0x8B) - PLL 12
+ */
+#define WM8962_PLL2_K_MASK                      0x00FF  /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_SHIFT                          0  /* PLL2_K - [7:0] */
+#define WM8962_PLL2_K_WIDTH                          8  /* PLL2_K - [7:0] */
+
+/*
+ * R140 (0x8C) - PLL 13
+ */
+#define WM8962_PLL3_FRAC                        0x0040  /* PLL3_FRAC */
+#define WM8962_PLL3_FRAC_MASK                   0x0040  /* PLL3_FRAC */
+#define WM8962_PLL3_FRAC_SHIFT                       6  /* PLL3_FRAC */
+#define WM8962_PLL3_FRAC_WIDTH                       1  /* PLL3_FRAC */
+#define WM8962_PLL3_N_MASK                      0x001F  /* PLL3_N - [4:0] */
+#define WM8962_PLL3_N_SHIFT                          0  /* PLL3_N - [4:0] */
+#define WM8962_PLL3_N_WIDTH                          5  /* PLL3_N - [4:0] */
+
+/*
+ * R141 (0x8D) - PLL 14
+ */
+#define WM8962_PLL3_K_MASK                      0x00FF  /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_SHIFT                          0  /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_WIDTH                          8  /* PLL3_K - [7:0] */
+
+/*
+ * R142 (0x8E) - PLL 15
+ */
+#define WM8962_PLL3_K_MASK                      0x00FF  /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_SHIFT                          0  /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_WIDTH                          8  /* PLL3_K - [7:0] */
+
+/*
+ * R143 (0x8F) - PLL 16
+ */
+#define WM8962_PLL3_K_MASK                      0x00FF  /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_SHIFT                          0  /* PLL3_K - [7:0] */
+#define WM8962_PLL3_K_WIDTH                          8  /* PLL3_K - [7:0] */
+
+/*
+ * R155 (0x9B) - FLL Control (1)
+ */
+#define WM8962_FLL_REFCLK_SRC_MASK              0x0060  /* FLL_REFCLK_SRC - [6:5] */
+#define WM8962_FLL_REFCLK_SRC_SHIFT                  5  /* FLL_REFCLK_SRC - [6:5] */
+#define WM8962_FLL_REFCLK_SRC_WIDTH                  2  /* FLL_REFCLK_SRC - [6:5] */
+#define WM8962_FLL_FRAC                         0x0004  /* FLL_FRAC */
+#define WM8962_FLL_FRAC_MASK                    0x0004  /* FLL_FRAC */
+#define WM8962_FLL_FRAC_SHIFT                        2  /* FLL_FRAC */
+#define WM8962_FLL_FRAC_WIDTH                        1  /* FLL_FRAC */
+#define WM8962_FLL_OSC_ENA                      0x0002  /* FLL_OSC_ENA */
+#define WM8962_FLL_OSC_ENA_MASK                 0x0002  /* FLL_OSC_ENA */
+#define WM8962_FLL_OSC_ENA_SHIFT                     1  /* FLL_OSC_ENA */
+#define WM8962_FLL_OSC_ENA_WIDTH                     1  /* FLL_OSC_ENA */
+#define WM8962_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM8962_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM8962_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM8962_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R156 (0x9C) - FLL Control (2)
+ */
+#define WM8962_FLL_OUTDIV_MASK                  0x01F8  /* FLL_OUTDIV - [8:3] */
+#define WM8962_FLL_OUTDIV_SHIFT                      3  /* FLL_OUTDIV - [8:3] */
+#define WM8962_FLL_OUTDIV_WIDTH                      6  /* FLL_OUTDIV - [8:3] */
+#define WM8962_FLL_REFCLK_DIV_MASK              0x0003  /* FLL_REFCLK_DIV - [1:0] */
+#define WM8962_FLL_REFCLK_DIV_SHIFT                  0  /* FLL_REFCLK_DIV - [1:0] */
+#define WM8962_FLL_REFCLK_DIV_WIDTH                  2  /* FLL_REFCLK_DIV - [1:0] */
+
+/*
+ * R157 (0x9D) - FLL Control (3)
+ */
+#define WM8962_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM8962_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM8962_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R159 (0x9F) - FLL Control (5)
+ */
+#define WM8962_FLL_FRC_NCO_VAL_MASK             0x007E  /* FLL_FRC_NCO_VAL - [6:1] */
+#define WM8962_FLL_FRC_NCO_VAL_SHIFT                 1  /* FLL_FRC_NCO_VAL - [6:1] */
+#define WM8962_FLL_FRC_NCO_VAL_WIDTH                 6  /* FLL_FRC_NCO_VAL - [6:1] */
+#define WM8962_FLL_FRC_NCO                      0x0001  /* FLL_FRC_NCO */
+#define WM8962_FLL_FRC_NCO_MASK                 0x0001  /* FLL_FRC_NCO */
+#define WM8962_FLL_FRC_NCO_SHIFT                     0  /* FLL_FRC_NCO */
+#define WM8962_FLL_FRC_NCO_WIDTH                     1  /* FLL_FRC_NCO */
+
+/*
+ * R160 (0xA0) - FLL Control (6)
+ */
+#define WM8962_FLL_THETA_MASK                   0xFFFF  /* FLL_THETA - [15:0] */
+#define WM8962_FLL_THETA_SHIFT                       0  /* FLL_THETA - [15:0] */
+#define WM8962_FLL_THETA_WIDTH                      16  /* FLL_THETA - [15:0] */
+
+/*
+ * R161 (0xA1) - FLL Control (7)
+ */
+#define WM8962_FLL_LAMBDA_MASK                  0xFFFF  /* FLL_LAMBDA - [15:0] */
+#define WM8962_FLL_LAMBDA_SHIFT                      0  /* FLL_LAMBDA - [15:0] */
+#define WM8962_FLL_LAMBDA_WIDTH                     16  /* FLL_LAMBDA - [15:0] */
+
+/*
+ * R162 (0xA2) - FLL Control (8)
+ */
+#define WM8962_FLL_N_MASK                       0x03FF  /* FLL_N - [9:0] */
+#define WM8962_FLL_N_SHIFT                           0  /* FLL_N - [9:0] */
+#define WM8962_FLL_N_WIDTH                          10  /* FLL_N - [9:0] */
+
+/*
+ * R252 (0xFC) - General test 1
+ */
+#define WM8962_REG_SYNC                         0x0004  /* REG_SYNC */
+#define WM8962_REG_SYNC_MASK                    0x0004  /* REG_SYNC */
+#define WM8962_REG_SYNC_SHIFT                        2  /* REG_SYNC */
+#define WM8962_REG_SYNC_WIDTH                        1  /* REG_SYNC */
+#define WM8962_AUTO_INC                         0x0001  /* AUTO_INC */
+#define WM8962_AUTO_INC_MASK                    0x0001  /* AUTO_INC */
+#define WM8962_AUTO_INC_SHIFT                        0  /* AUTO_INC */
+#define WM8962_AUTO_INC_WIDTH                        1  /* AUTO_INC */
+
+/*
+ * R256 (0x100) - DF1
+ */
+#define WM8962_DRC_DF1_ENA                      0x0008  /* DRC_DF1_ENA */
+#define WM8962_DRC_DF1_ENA_MASK                 0x0008  /* DRC_DF1_ENA */
+#define WM8962_DRC_DF1_ENA_SHIFT                     3  /* DRC_DF1_ENA */
+#define WM8962_DRC_DF1_ENA_WIDTH                     1  /* DRC_DF1_ENA */
+#define WM8962_DF1_SHARED_COEFF                 0x0004  /* DF1_SHARED_COEFF */
+#define WM8962_DF1_SHARED_COEFF_MASK            0x0004  /* DF1_SHARED_COEFF */
+#define WM8962_DF1_SHARED_COEFF_SHIFT                2  /* DF1_SHARED_COEFF */
+#define WM8962_DF1_SHARED_COEFF_WIDTH                1  /* DF1_SHARED_COEFF */
+#define WM8962_DF1_SHARED_COEFF_SEL             0x0002  /* DF1_SHARED_COEFF_SEL */
+#define WM8962_DF1_SHARED_COEFF_SEL_MASK        0x0002  /* DF1_SHARED_COEFF_SEL */
+#define WM8962_DF1_SHARED_COEFF_SEL_SHIFT            1  /* DF1_SHARED_COEFF_SEL */
+#define WM8962_DF1_SHARED_COEFF_SEL_WIDTH            1  /* DF1_SHARED_COEFF_SEL */
+#define WM8962_DF1_ENA                          0x0001  /* DF1_ENA */
+#define WM8962_DF1_ENA_MASK                     0x0001  /* DF1_ENA */
+#define WM8962_DF1_ENA_SHIFT                         0  /* DF1_ENA */
+#define WM8962_DF1_ENA_WIDTH                         1  /* DF1_ENA */
+
+/*
+ * R257 (0x101) - DF2
+ */
+#define WM8962_DF1_COEFF_L0_MASK                0xFFFF  /* DF1_COEFF_L0 - [15:0] */
+#define WM8962_DF1_COEFF_L0_SHIFT                    0  /* DF1_COEFF_L0 - [15:0] */
+#define WM8962_DF1_COEFF_L0_WIDTH                   16  /* DF1_COEFF_L0 - [15:0] */
+
+/*
+ * R258 (0x102) - DF3
+ */
+#define WM8962_DF1_COEFF_L1_MASK                0xFFFF  /* DF1_COEFF_L1 - [15:0] */
+#define WM8962_DF1_COEFF_L1_SHIFT                    0  /* DF1_COEFF_L1 - [15:0] */
+#define WM8962_DF1_COEFF_L1_WIDTH                   16  /* DF1_COEFF_L1 - [15:0] */
+
+/*
+ * R259 (0x103) - DF4
+ */
+#define WM8962_DF1_COEFF_L2_MASK                0xFFFF  /* DF1_COEFF_L2 - [15:0] */
+#define WM8962_DF1_COEFF_L2_SHIFT                    0  /* DF1_COEFF_L2 - [15:0] */
+#define WM8962_DF1_COEFF_L2_WIDTH                   16  /* DF1_COEFF_L2 - [15:0] */
+
+/*
+ * R260 (0x104) - DF5
+ */
+#define WM8962_DF1_COEFF_R0_MASK                0xFFFF  /* DF1_COEFF_R0 - [15:0] */
+#define WM8962_DF1_COEFF_R0_SHIFT                    0  /* DF1_COEFF_R0 - [15:0] */
+#define WM8962_DF1_COEFF_R0_WIDTH                   16  /* DF1_COEFF_R0 - [15:0] */
+
+/*
+ * R261 (0x105) - DF6
+ */
+#define WM8962_DF1_COEFF_R1_MASK                0xFFFF  /* DF1_COEFF_R1 - [15:0] */
+#define WM8962_DF1_COEFF_R1_SHIFT                    0  /* DF1_COEFF_R1 - [15:0] */
+#define WM8962_DF1_COEFF_R1_WIDTH                   16  /* DF1_COEFF_R1 - [15:0] */
+
+/*
+ * R262 (0x106) - DF7
+ */
+#define WM8962_DF1_COEFF_R2_MASK                0xFFFF  /* DF1_COEFF_R2 - [15:0] */
+#define WM8962_DF1_COEFF_R2_SHIFT                    0  /* DF1_COEFF_R2 - [15:0] */
+#define WM8962_DF1_COEFF_R2_WIDTH                   16  /* DF1_COEFF_R2 - [15:0] */
+
+/*
+ * R264 (0x108) - LHPF1
+ */
+#define WM8962_LHPF_MODE                        0x0002  /* LHPF_MODE */
+#define WM8962_LHPF_MODE_MASK                   0x0002  /* LHPF_MODE */
+#define WM8962_LHPF_MODE_SHIFT                       1  /* LHPF_MODE */
+#define WM8962_LHPF_MODE_WIDTH                       1  /* LHPF_MODE */
+#define WM8962_LHPF_ENA                         0x0001  /* LHPF_ENA */
+#define WM8962_LHPF_ENA_MASK                    0x0001  /* LHPF_ENA */
+#define WM8962_LHPF_ENA_SHIFT                        0  /* LHPF_ENA */
+#define WM8962_LHPF_ENA_WIDTH                        1  /* LHPF_ENA */
+
+/*
+ * R265 (0x109) - LHPF2
+ */
+#define WM8962_LHPF_COEFF_MASK                  0xFFFF  /* LHPF_COEFF - [15:0] */
+#define WM8962_LHPF_COEFF_SHIFT                      0  /* LHPF_COEFF - [15:0] */
+#define WM8962_LHPF_COEFF_WIDTH                     16  /* LHPF_COEFF - [15:0] */
+
+/*
+ * R268 (0x10C) - THREED1
+ */
+#define WM8962_ADC_MONOMIX                      0x0040  /* ADC_MONOMIX */
+#define WM8962_ADC_MONOMIX_MASK                 0x0040  /* ADC_MONOMIX */
+#define WM8962_ADC_MONOMIX_SHIFT                     6  /* ADC_MONOMIX */
+#define WM8962_ADC_MONOMIX_WIDTH                     1  /* ADC_MONOMIX */
+#define WM8962_THREED_SIGN_L                    0x0020  /* THREED_SIGN_L */
+#define WM8962_THREED_SIGN_L_MASK               0x0020  /* THREED_SIGN_L */
+#define WM8962_THREED_SIGN_L_SHIFT                   5  /* THREED_SIGN_L */
+#define WM8962_THREED_SIGN_L_WIDTH                   1  /* THREED_SIGN_L */
+#define WM8962_THREED_SIGN_R                    0x0010  /* THREED_SIGN_R */
+#define WM8962_THREED_SIGN_R_MASK               0x0010  /* THREED_SIGN_R */
+#define WM8962_THREED_SIGN_R_SHIFT                   4  /* THREED_SIGN_R */
+#define WM8962_THREED_SIGN_R_WIDTH                   1  /* THREED_SIGN_R */
+#define WM8962_THREED_LHPF_MODE                 0x0004  /* THREED_LHPF_MODE */
+#define WM8962_THREED_LHPF_MODE_MASK            0x0004  /* THREED_LHPF_MODE */
+#define WM8962_THREED_LHPF_MODE_SHIFT                2  /* THREED_LHPF_MODE */
+#define WM8962_THREED_LHPF_MODE_WIDTH                1  /* THREED_LHPF_MODE */
+#define WM8962_THREED_LHPF_ENA                  0x0002  /* THREED_LHPF_ENA */
+#define WM8962_THREED_LHPF_ENA_MASK             0x0002  /* THREED_LHPF_ENA */
+#define WM8962_THREED_LHPF_ENA_SHIFT                 1  /* THREED_LHPF_ENA */
+#define WM8962_THREED_LHPF_ENA_WIDTH                 1  /* THREED_LHPF_ENA */
+#define WM8962_THREED_ENA                       0x0001  /* THREED_ENA */
+#define WM8962_THREED_ENA_MASK                  0x0001  /* THREED_ENA */
+#define WM8962_THREED_ENA_SHIFT                      0  /* THREED_ENA */
+#define WM8962_THREED_ENA_WIDTH                      1  /* THREED_ENA */
+
+/*
+ * R269 (0x10D) - THREED2
+ */
+#define WM8962_THREED_FGAINL_MASK               0xF800  /* THREED_FGAINL - [15:11] */
+#define WM8962_THREED_FGAINL_SHIFT                  11  /* THREED_FGAINL - [15:11] */
+#define WM8962_THREED_FGAINL_WIDTH                   5  /* THREED_FGAINL - [15:11] */
+#define WM8962_THREED_CGAINL_MASK               0x07C0  /* THREED_CGAINL - [10:6] */
+#define WM8962_THREED_CGAINL_SHIFT                   6  /* THREED_CGAINL - [10:6] */
+#define WM8962_THREED_CGAINL_WIDTH                   5  /* THREED_CGAINL - [10:6] */
+#define WM8962_THREED_DELAYL_MASK               0x003C  /* THREED_DELAYL - [5:2] */
+#define WM8962_THREED_DELAYL_SHIFT                   2  /* THREED_DELAYL - [5:2] */
+#define WM8962_THREED_DELAYL_WIDTH                   4  /* THREED_DELAYL - [5:2] */
+
+/*
+ * R270 (0x10E) - THREED3
+ */
+#define WM8962_THREED_LHPF_COEFF_MASK           0xFFFF  /* THREED_LHPF_COEFF - [15:0] */
+#define WM8962_THREED_LHPF_COEFF_SHIFT               0  /* THREED_LHPF_COEFF - [15:0] */
+#define WM8962_THREED_LHPF_COEFF_WIDTH              16  /* THREED_LHPF_COEFF - [15:0] */
+
+/*
+ * R271 (0x10F) - THREED4
+ */
+#define WM8962_THREED_FGAINR_MASK               0xF800  /* THREED_FGAINR - [15:11] */
+#define WM8962_THREED_FGAINR_SHIFT                  11  /* THREED_FGAINR - [15:11] */
+#define WM8962_THREED_FGAINR_WIDTH                   5  /* THREED_FGAINR - [15:11] */
+#define WM8962_THREED_CGAINR_MASK               0x07C0  /* THREED_CGAINR - [10:6] */
+#define WM8962_THREED_CGAINR_SHIFT                   6  /* THREED_CGAINR - [10:6] */
+#define WM8962_THREED_CGAINR_WIDTH                   5  /* THREED_CGAINR - [10:6] */
+#define WM8962_THREED_DELAYR_MASK               0x003C  /* THREED_DELAYR - [5:2] */
+#define WM8962_THREED_DELAYR_SHIFT                   2  /* THREED_DELAYR - [5:2] */
+#define WM8962_THREED_DELAYR_WIDTH                   4  /* THREED_DELAYR - [5:2] */
+
+/*
+ * R276 (0x114) - DRC 1
+ */
+#define WM8962_DRC_SIG_DET_RMS_MASK             0x7C00  /* DRC_SIG_DET_RMS - [14:10] */
+#define WM8962_DRC_SIG_DET_RMS_SHIFT                10  /* DRC_SIG_DET_RMS - [14:10] */
+#define WM8962_DRC_SIG_DET_RMS_WIDTH                 5  /* DRC_SIG_DET_RMS - [14:10] */
+#define WM8962_DRC_SIG_DET_PK_MASK              0x0300  /* DRC_SIG_DET_PK - [9:8] */
+#define WM8962_DRC_SIG_DET_PK_SHIFT                  8  /* DRC_SIG_DET_PK - [9:8] */
+#define WM8962_DRC_SIG_DET_PK_WIDTH                  2  /* DRC_SIG_DET_PK - [9:8] */
+#define WM8962_DRC_NG_ENA                       0x0080  /* DRC_NG_ENA */
+#define WM8962_DRC_NG_ENA_MASK                  0x0080  /* DRC_NG_ENA */
+#define WM8962_DRC_NG_ENA_SHIFT                      7  /* DRC_NG_ENA */
+#define WM8962_DRC_NG_ENA_WIDTH                      1  /* DRC_NG_ENA */
+#define WM8962_DRC_SIG_DET_MODE                 0x0040  /* DRC_SIG_DET_MODE */
+#define WM8962_DRC_SIG_DET_MODE_MASK            0x0040  /* DRC_SIG_DET_MODE */
+#define WM8962_DRC_SIG_DET_MODE_SHIFT                6  /* DRC_SIG_DET_MODE */
+#define WM8962_DRC_SIG_DET_MODE_WIDTH                1  /* DRC_SIG_DET_MODE */
+#define WM8962_DRC_SIG_DET                      0x0020  /* DRC_SIG_DET */
+#define WM8962_DRC_SIG_DET_MASK                 0x0020  /* DRC_SIG_DET */
+#define WM8962_DRC_SIG_DET_SHIFT                     5  /* DRC_SIG_DET */
+#define WM8962_DRC_SIG_DET_WIDTH                     1  /* DRC_SIG_DET */
+#define WM8962_DRC_KNEE2_OP_ENA                 0x0010  /* DRC_KNEE2_OP_ENA */
+#define WM8962_DRC_KNEE2_OP_ENA_MASK            0x0010  /* DRC_KNEE2_OP_ENA */
+#define WM8962_DRC_KNEE2_OP_ENA_SHIFT                4  /* DRC_KNEE2_OP_ENA */
+#define WM8962_DRC_KNEE2_OP_ENA_WIDTH                1  /* DRC_KNEE2_OP_ENA */
+#define WM8962_DRC_QR                           0x0008  /* DRC_QR */
+#define WM8962_DRC_QR_MASK                      0x0008  /* DRC_QR */
+#define WM8962_DRC_QR_SHIFT                          3  /* DRC_QR */
+#define WM8962_DRC_QR_WIDTH                          1  /* DRC_QR */
+#define WM8962_DRC_ANTICLIP                     0x0004  /* DRC_ANTICLIP */
+#define WM8962_DRC_ANTICLIP_MASK                0x0004  /* DRC_ANTICLIP */
+#define WM8962_DRC_ANTICLIP_SHIFT                    2  /* DRC_ANTICLIP */
+#define WM8962_DRC_ANTICLIP_WIDTH                    1  /* DRC_ANTICLIP */
+#define WM8962_DRC_MODE                         0x0002  /* DRC_MODE */
+#define WM8962_DRC_MODE_MASK                    0x0002  /* DRC_MODE */
+#define WM8962_DRC_MODE_SHIFT                        1  /* DRC_MODE */
+#define WM8962_DRC_MODE_WIDTH                        1  /* DRC_MODE */
+#define WM8962_DRC_ENA                          0x0001  /* DRC_ENA */
+#define WM8962_DRC_ENA_MASK                     0x0001  /* DRC_ENA */
+#define WM8962_DRC_ENA_SHIFT                         0  /* DRC_ENA */
+#define WM8962_DRC_ENA_WIDTH                         1  /* DRC_ENA */
+
+/*
+ * R277 (0x115) - DRC 2
+ */
+#define WM8962_DRC_ATK_MASK                     0x1E00  /* DRC_ATK - [12:9] */
+#define WM8962_DRC_ATK_SHIFT                         9  /* DRC_ATK - [12:9] */
+#define WM8962_DRC_ATK_WIDTH                         4  /* DRC_ATK - [12:9] */
+#define WM8962_DRC_DCY_MASK                     0x01E0  /* DRC_DCY - [8:5] */
+#define WM8962_DRC_DCY_SHIFT                         5  /* DRC_DCY - [8:5] */
+#define WM8962_DRC_DCY_WIDTH                         4  /* DRC_DCY - [8:5] */
+#define WM8962_DRC_MINGAIN_MASK                 0x001C  /* DRC_MINGAIN - [4:2] */
+#define WM8962_DRC_MINGAIN_SHIFT                     2  /* DRC_MINGAIN - [4:2] */
+#define WM8962_DRC_MINGAIN_WIDTH                     3  /* DRC_MINGAIN - [4:2] */
+#define WM8962_DRC_MAXGAIN_MASK                 0x0003  /* DRC_MAXGAIN - [1:0] */
+#define WM8962_DRC_MAXGAIN_SHIFT                     0  /* DRC_MAXGAIN - [1:0] */
+#define WM8962_DRC_MAXGAIN_WIDTH                     2  /* DRC_MAXGAIN - [1:0] */
+
+/*
+ * R278 (0x116) - DRC 3
+ */
+#define WM8962_DRC_NG_MINGAIN_MASK              0xF000  /* DRC_NG_MINGAIN - [15:12] */
+#define WM8962_DRC_NG_MINGAIN_SHIFT                 12  /* DRC_NG_MINGAIN - [15:12] */
+#define WM8962_DRC_NG_MINGAIN_WIDTH                  4  /* DRC_NG_MINGAIN - [15:12] */
+#define WM8962_DRC_QR_THR_MASK                  0x0C00  /* DRC_QR_THR - [11:10] */
+#define WM8962_DRC_QR_THR_SHIFT                     10  /* DRC_QR_THR - [11:10] */
+#define WM8962_DRC_QR_THR_WIDTH                      2  /* DRC_QR_THR - [11:10] */
+#define WM8962_DRC_QR_DCY_MASK                  0x0300  /* DRC_QR_DCY - [9:8] */
+#define WM8962_DRC_QR_DCY_SHIFT                      8  /* DRC_QR_DCY - [9:8] */
+#define WM8962_DRC_QR_DCY_WIDTH                      2  /* DRC_QR_DCY - [9:8] */
+#define WM8962_DRC_NG_EXP_MASK                  0x00C0  /* DRC_NG_EXP - [7:6] */
+#define WM8962_DRC_NG_EXP_SHIFT                      6  /* DRC_NG_EXP - [7:6] */
+#define WM8962_DRC_NG_EXP_WIDTH                      2  /* DRC_NG_EXP - [7:6] */
+#define WM8962_DRC_HI_COMP_MASK                 0x0038  /* DRC_HI_COMP - [5:3] */
+#define WM8962_DRC_HI_COMP_SHIFT                     3  /* DRC_HI_COMP - [5:3] */
+#define WM8962_DRC_HI_COMP_WIDTH                     3  /* DRC_HI_COMP - [5:3] */
+#define WM8962_DRC_LO_COMP_MASK                 0x0007  /* DRC_LO_COMP - [2:0] */
+#define WM8962_DRC_LO_COMP_SHIFT                     0  /* DRC_LO_COMP - [2:0] */
+#define WM8962_DRC_LO_COMP_WIDTH                     3  /* DRC_LO_COMP - [2:0] */
+
+/*
+ * R279 (0x117) - DRC 4
+ */
+#define WM8962_DRC_KNEE_IP_MASK                 0x07E0  /* DRC_KNEE_IP - [10:5] */
+#define WM8962_DRC_KNEE_IP_SHIFT                     5  /* DRC_KNEE_IP - [10:5] */
+#define WM8962_DRC_KNEE_IP_WIDTH                     6  /* DRC_KNEE_IP - [10:5] */
+#define WM8962_DRC_KNEE_OP_MASK                 0x001F  /* DRC_KNEE_OP - [4:0] */
+#define WM8962_DRC_KNEE_OP_SHIFT                     0  /* DRC_KNEE_OP - [4:0] */
+#define WM8962_DRC_KNEE_OP_WIDTH                     5  /* DRC_KNEE_OP - [4:0] */
+
+/*
+ * R280 (0x118) - DRC 5
+ */
+#define WM8962_DRC_KNEE2_IP_MASK                0x03E0  /* DRC_KNEE2_IP - [9:5] */
+#define WM8962_DRC_KNEE2_IP_SHIFT                    5  /* DRC_KNEE2_IP - [9:5] */
+#define WM8962_DRC_KNEE2_IP_WIDTH                    5  /* DRC_KNEE2_IP - [9:5] */
+#define WM8962_DRC_KNEE2_OP_MASK                0x001F  /* DRC_KNEE2_OP - [4:0] */
+#define WM8962_DRC_KNEE2_OP_SHIFT                    0  /* DRC_KNEE2_OP - [4:0] */
+#define WM8962_DRC_KNEE2_OP_WIDTH                    5  /* DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R285 (0x11D) - Tloopback
+ */
+#define WM8962_TLB_ENA                          0x0002  /* TLB_ENA */
+#define WM8962_TLB_ENA_MASK                     0x0002  /* TLB_ENA */
+#define WM8962_TLB_ENA_SHIFT                         1  /* TLB_ENA */
+#define WM8962_TLB_ENA_WIDTH                         1  /* TLB_ENA */
+#define WM8962_TLB_MODE                         0x0001  /* TLB_MODE */
+#define WM8962_TLB_MODE_MASK                    0x0001  /* TLB_MODE */
+#define WM8962_TLB_MODE_SHIFT                        0  /* TLB_MODE */
+#define WM8962_TLB_MODE_WIDTH                        1  /* TLB_MODE */
+
+/*
+ * R335 (0x14F) - EQ1
+ */
+#define WM8962_EQ_SHARED_COEFF                  0x0004  /* EQ_SHARED_COEFF */
+#define WM8962_EQ_SHARED_COEFF_MASK             0x0004  /* EQ_SHARED_COEFF */
+#define WM8962_EQ_SHARED_COEFF_SHIFT                 2  /* EQ_SHARED_COEFF */
+#define WM8962_EQ_SHARED_COEFF_WIDTH                 1  /* EQ_SHARED_COEFF */
+#define WM8962_EQ_SHARED_COEFF_SEL              0x0002  /* EQ_SHARED_COEFF_SEL */
+#define WM8962_EQ_SHARED_COEFF_SEL_MASK         0x0002  /* EQ_SHARED_COEFF_SEL */
+#define WM8962_EQ_SHARED_COEFF_SEL_SHIFT             1  /* EQ_SHARED_COEFF_SEL */
+#define WM8962_EQ_SHARED_COEFF_SEL_WIDTH             1  /* EQ_SHARED_COEFF_SEL */
+#define WM8962_EQ_ENA                           0x0001  /* EQ_ENA */
+#define WM8962_EQ_ENA_MASK                      0x0001  /* EQ_ENA */
+#define WM8962_EQ_ENA_SHIFT                          0  /* EQ_ENA */
+#define WM8962_EQ_ENA_WIDTH                          1  /* EQ_ENA */
+
+/*
+ * R336 (0x150) - EQ2
+ */
+#define WM8962_EQL_B1_GAIN_MASK                 0xF800  /* EQL_B1_GAIN - [15:11] */
+#define WM8962_EQL_B1_GAIN_SHIFT                    11  /* EQL_B1_GAIN - [15:11] */
+#define WM8962_EQL_B1_GAIN_WIDTH                     5  /* EQL_B1_GAIN - [15:11] */
+#define WM8962_EQL_B2_GAIN_MASK                 0x07C0  /* EQL_B2_GAIN - [10:6] */
+#define WM8962_EQL_B2_GAIN_SHIFT                     6  /* EQL_B2_GAIN - [10:6] */
+#define WM8962_EQL_B2_GAIN_WIDTH                     5  /* EQL_B2_GAIN - [10:6] */
+#define WM8962_EQL_B3_GAIN_MASK                 0x003E  /* EQL_B3_GAIN - [5:1] */
+#define WM8962_EQL_B3_GAIN_SHIFT                     1  /* EQL_B3_GAIN - [5:1] */
+#define WM8962_EQL_B3_GAIN_WIDTH                     5  /* EQL_B3_GAIN - [5:1] */
+
+/*
+ * R337 (0x151) - EQ3
+ */
+#define WM8962_EQL_B4_GAIN_MASK                 0xF800  /* EQL_B4_GAIN - [15:11] */
+#define WM8962_EQL_B4_GAIN_SHIFT                    11  /* EQL_B4_GAIN - [15:11] */
+#define WM8962_EQL_B4_GAIN_WIDTH                     5  /* EQL_B4_GAIN - [15:11] */
+#define WM8962_EQL_B5_GAIN_MASK                 0x07C0  /* EQL_B5_GAIN - [10:6] */
+#define WM8962_EQL_B5_GAIN_SHIFT                     6  /* EQL_B5_GAIN - [10:6] */
+#define WM8962_EQL_B5_GAIN_WIDTH                     5  /* EQL_B5_GAIN - [10:6] */
+
+/*
+ * R338 (0x152) - EQ4
+ */
+#define WM8962_EQL_B1_A_MASK                    0xFFFF  /* EQL_B1_A - [15:0] */
+#define WM8962_EQL_B1_A_SHIFT                        0  /* EQL_B1_A - [15:0] */
+#define WM8962_EQL_B1_A_WIDTH                       16  /* EQL_B1_A - [15:0] */
+
+/*
+ * R339 (0x153) - EQ5
+ */
+#define WM8962_EQL_B1_B_MASK                    0xFFFF  /* EQL_B1_B - [15:0] */
+#define WM8962_EQL_B1_B_SHIFT                        0  /* EQL_B1_B - [15:0] */
+#define WM8962_EQL_B1_B_WIDTH                       16  /* EQL_B1_B - [15:0] */
+
+/*
+ * R340 (0x154) - EQ6
+ */
+#define WM8962_EQL_B1_PG_MASK                   0xFFFF  /* EQL_B1_PG - [15:0] */
+#define WM8962_EQL_B1_PG_SHIFT                       0  /* EQL_B1_PG - [15:0] */
+#define WM8962_EQL_B1_PG_WIDTH                      16  /* EQL_B1_PG - [15:0] */
+
+/*
+ * R341 (0x155) - EQ7
+ */
+#define WM8962_EQL_B2_A_MASK                    0xFFFF  /* EQL_B2_A - [15:0] */
+#define WM8962_EQL_B2_A_SHIFT                        0  /* EQL_B2_A - [15:0] */
+#define WM8962_EQL_B2_A_WIDTH                       16  /* EQL_B2_A - [15:0] */
+
+/*
+ * R342 (0x156) - EQ8
+ */
+#define WM8962_EQL_B2_B_MASK                    0xFFFF  /* EQL_B2_B - [15:0] */
+#define WM8962_EQL_B2_B_SHIFT                        0  /* EQL_B2_B - [15:0] */
+#define WM8962_EQL_B2_B_WIDTH                       16  /* EQL_B2_B - [15:0] */
+
+/*
+ * R343 (0x157) - EQ9
+ */
+#define WM8962_EQL_B2_C_MASK                    0xFFFF  /* EQL_B2_C - [15:0] */
+#define WM8962_EQL_B2_C_SHIFT                        0  /* EQL_B2_C - [15:0] */
+#define WM8962_EQL_B2_C_WIDTH                       16  /* EQL_B2_C - [15:0] */
+
+/*
+ * R344 (0x158) - EQ10
+ */
+#define WM8962_EQL_B2_PG_MASK                   0xFFFF  /* EQL_B2_PG - [15:0] */
+#define WM8962_EQL_B2_PG_SHIFT                       0  /* EQL_B2_PG - [15:0] */
+#define WM8962_EQL_B2_PG_WIDTH                      16  /* EQL_B2_PG - [15:0] */
+
+/*
+ * R345 (0x159) - EQ11
+ */
+#define WM8962_EQL_B3_A_MASK                    0xFFFF  /* EQL_B3_A - [15:0] */
+#define WM8962_EQL_B3_A_SHIFT                        0  /* EQL_B3_A - [15:0] */
+#define WM8962_EQL_B3_A_WIDTH                       16  /* EQL_B3_A - [15:0] */
+
+/*
+ * R346 (0x15A) - EQ12
+ */
+#define WM8962_EQL_B3_B_MASK                    0xFFFF  /* EQL_B3_B - [15:0] */
+#define WM8962_EQL_B3_B_SHIFT                        0  /* EQL_B3_B - [15:0] */
+#define WM8962_EQL_B3_B_WIDTH                       16  /* EQL_B3_B - [15:0] */
+
+/*
+ * R347 (0x15B) - EQ13
+ */
+#define WM8962_EQL_B3_C_MASK                    0xFFFF  /* EQL_B3_C - [15:0] */
+#define WM8962_EQL_B3_C_SHIFT                        0  /* EQL_B3_C - [15:0] */
+#define WM8962_EQL_B3_C_WIDTH                       16  /* EQL_B3_C - [15:0] */
+
+/*
+ * R348 (0x15C) - EQ14
+ */
+#define WM8962_EQL_B3_PG_MASK                   0xFFFF  /* EQL_B3_PG - [15:0] */
+#define WM8962_EQL_B3_PG_SHIFT                       0  /* EQL_B3_PG - [15:0] */
+#define WM8962_EQL_B3_PG_WIDTH                      16  /* EQL_B3_PG - [15:0] */
+
+/*
+ * R349 (0x15D) - EQ15
+ */
+#define WM8962_EQL_B4_A_MASK                    0xFFFF  /* EQL_B4_A - [15:0] */
+#define WM8962_EQL_B4_A_SHIFT                        0  /* EQL_B4_A - [15:0] */
+#define WM8962_EQL_B4_A_WIDTH                       16  /* EQL_B4_A - [15:0] */
+
+/*
+ * R350 (0x15E) - EQ16
+ */
+#define WM8962_EQL_B4_B_MASK                    0xFFFF  /* EQL_B4_B - [15:0] */
+#define WM8962_EQL_B4_B_SHIFT                        0  /* EQL_B4_B - [15:0] */
+#define WM8962_EQL_B4_B_WIDTH                       16  /* EQL_B4_B - [15:0] */
+
+/*
+ * R351 (0x15F) - EQ17
+ */
+#define WM8962_EQL_B4_C_MASK                    0xFFFF  /* EQL_B4_C - [15:0] */
+#define WM8962_EQL_B4_C_SHIFT                        0  /* EQL_B4_C - [15:0] */
+#define WM8962_EQL_B4_C_WIDTH                       16  /* EQL_B4_C - [15:0] */
+
+/*
+ * R352 (0x160) - EQ18
+ */
+#define WM8962_EQL_B4_PG_MASK                   0xFFFF  /* EQL_B4_PG - [15:0] */
+#define WM8962_EQL_B4_PG_SHIFT                       0  /* EQL_B4_PG - [15:0] */
+#define WM8962_EQL_B4_PG_WIDTH                      16  /* EQL_B4_PG - [15:0] */
+
+/*
+ * R353 (0x161) - EQ19
+ */
+#define WM8962_EQL_B5_A_MASK                    0xFFFF  /* EQL_B5_A - [15:0] */
+#define WM8962_EQL_B5_A_SHIFT                        0  /* EQL_B5_A - [15:0] */
+#define WM8962_EQL_B5_A_WIDTH                       16  /* EQL_B5_A - [15:0] */
+
+/*
+ * R354 (0x162) - EQ20
+ */
+#define WM8962_EQL_B5_B_MASK                    0xFFFF  /* EQL_B5_B - [15:0] */
+#define WM8962_EQL_B5_B_SHIFT                        0  /* EQL_B5_B - [15:0] */
+#define WM8962_EQL_B5_B_WIDTH                       16  /* EQL_B5_B - [15:0] */
+
+/*
+ * R355 (0x163) - EQ21
+ */
+#define WM8962_EQL_B5_PG_MASK                   0xFFFF  /* EQL_B5_PG - [15:0] */
+#define WM8962_EQL_B5_PG_SHIFT                       0  /* EQL_B5_PG - [15:0] */
+#define WM8962_EQL_B5_PG_WIDTH                      16  /* EQL_B5_PG - [15:0] */
+
+/*
+ * R356 (0x164) - EQ22
+ */
+#define WM8962_EQR_B1_GAIN_MASK                 0xF800  /* EQR_B1_GAIN - [15:11] */
+#define WM8962_EQR_B1_GAIN_SHIFT                    11  /* EQR_B1_GAIN - [15:11] */
+#define WM8962_EQR_B1_GAIN_WIDTH                     5  /* EQR_B1_GAIN - [15:11] */
+#define WM8962_EQR_B2_GAIN_MASK                 0x07C0  /* EQR_B2_GAIN - [10:6] */
+#define WM8962_EQR_B2_GAIN_SHIFT                     6  /* EQR_B2_GAIN - [10:6] */
+#define WM8962_EQR_B2_GAIN_WIDTH                     5  /* EQR_B2_GAIN - [10:6] */
+#define WM8962_EQR_B3_GAIN_MASK                 0x003E  /* EQR_B3_GAIN - [5:1] */
+#define WM8962_EQR_B3_GAIN_SHIFT                     1  /* EQR_B3_GAIN - [5:1] */
+#define WM8962_EQR_B3_GAIN_WIDTH                     5  /* EQR_B3_GAIN - [5:1] */
+
+/*
+ * R357 (0x165) - EQ23
+ */
+#define WM8962_EQR_B4_GAIN_MASK                 0xF800  /* EQR_B4_GAIN - [15:11] */
+#define WM8962_EQR_B4_GAIN_SHIFT                    11  /* EQR_B4_GAIN - [15:11] */
+#define WM8962_EQR_B4_GAIN_WIDTH                     5  /* EQR_B4_GAIN - [15:11] */
+#define WM8962_EQR_B5_GAIN_MASK                 0x07C0  /* EQR_B5_GAIN - [10:6] */
+#define WM8962_EQR_B5_GAIN_SHIFT                     6  /* EQR_B5_GAIN - [10:6] */
+#define WM8962_EQR_B5_GAIN_WIDTH                     5  /* EQR_B5_GAIN - [10:6] */
+
+/*
+ * R358 (0x166) - EQ24
+ */
+#define WM8962_EQR_B1_A_MASK                    0xFFFF  /* EQR_B1_A - [15:0] */
+#define WM8962_EQR_B1_A_SHIFT                        0  /* EQR_B1_A - [15:0] */
+#define WM8962_EQR_B1_A_WIDTH                       16  /* EQR_B1_A - [15:0] */
+
+/*
+ * R359 (0x167) - EQ25
+ */
+#define WM8962_EQR_B1_B_MASK                    0xFFFF  /* EQR_B1_B - [15:0] */
+#define WM8962_EQR_B1_B_SHIFT                        0  /* EQR_B1_B - [15:0] */
+#define WM8962_EQR_B1_B_WIDTH                       16  /* EQR_B1_B - [15:0] */
+
+/*
+ * R360 (0x168) - EQ26
+ */
+#define WM8962_EQR_B1_PG_MASK                   0xFFFF  /* EQR_B1_PG - [15:0] */
+#define WM8962_EQR_B1_PG_SHIFT                       0  /* EQR_B1_PG - [15:0] */
+#define WM8962_EQR_B1_PG_WIDTH                      16  /* EQR_B1_PG - [15:0] */
+
+/*
+ * R361 (0x169) - EQ27
+ */
+#define WM8962_EQR_B2_A_MASK                    0xFFFF  /* EQR_B2_A - [15:0] */
+#define WM8962_EQR_B2_A_SHIFT                        0  /* EQR_B2_A - [15:0] */
+#define WM8962_EQR_B2_A_WIDTH                       16  /* EQR_B2_A - [15:0] */
+
+/*
+ * R362 (0x16A) - EQ28
+ */
+#define WM8962_EQR_B2_B_MASK                    0xFFFF  /* EQR_B2_B - [15:0] */
+#define WM8962_EQR_B2_B_SHIFT                        0  /* EQR_B2_B - [15:0] */
+#define WM8962_EQR_B2_B_WIDTH                       16  /* EQR_B2_B - [15:0] */
+
+/*
+ * R363 (0x16B) - EQ29
+ */
+#define WM8962_EQR_B2_C_MASK                    0xFFFF  /* EQR_B2_C - [15:0] */
+#define WM8962_EQR_B2_C_SHIFT                        0  /* EQR_B2_C - [15:0] */
+#define WM8962_EQR_B2_C_WIDTH                       16  /* EQR_B2_C - [15:0] */
+
+/*
+ * R364 (0x16C) - EQ30
+ */
+#define WM8962_EQR_B2_PG_MASK                   0xFFFF  /* EQR_B2_PG - [15:0] */
+#define WM8962_EQR_B2_PG_SHIFT                       0  /* EQR_B2_PG - [15:0] */
+#define WM8962_EQR_B2_PG_WIDTH                      16  /* EQR_B2_PG - [15:0] */
+
+/*
+ * R365 (0x16D) - EQ31
+ */
+#define WM8962_EQR_B3_A_MASK                    0xFFFF  /* EQR_B3_A - [15:0] */
+#define WM8962_EQR_B3_A_SHIFT                        0  /* EQR_B3_A - [15:0] */
+#define WM8962_EQR_B3_A_WIDTH                       16  /* EQR_B3_A - [15:0] */
+
+/*
+ * R366 (0x16E) - EQ32
+ */
+#define WM8962_EQR_B3_B_MASK                    0xFFFF  /* EQR_B3_B - [15:0] */
+#define WM8962_EQR_B3_B_SHIFT                        0  /* EQR_B3_B - [15:0] */
+#define WM8962_EQR_B3_B_WIDTH                       16  /* EQR_B3_B - [15:0] */
+
+/*
+ * R367 (0x16F) - EQ33
+ */
+#define WM8962_EQR_B3_C_MASK                    0xFFFF  /* EQR_B3_C - [15:0] */
+#define WM8962_EQR_B3_C_SHIFT                        0  /* EQR_B3_C - [15:0] */
+#define WM8962_EQR_B3_C_WIDTH                       16  /* EQR_B3_C - [15:0] */
+
+/*
+ * R368 (0x170) - EQ34
+ */
+#define WM8962_EQR_B3_PG_MASK                   0xFFFF  /* EQR_B3_PG - [15:0] */
+#define WM8962_EQR_B3_PG_SHIFT                       0  /* EQR_B3_PG - [15:0] */
+#define WM8962_EQR_B3_PG_WIDTH                      16  /* EQR_B3_PG - [15:0] */
+
+/*
+ * R369 (0x171) - EQ35
+ */
+#define WM8962_EQR_B4_A_MASK                    0xFFFF  /* EQR_B4_A - [15:0] */
+#define WM8962_EQR_B4_A_SHIFT                        0  /* EQR_B4_A - [15:0] */
+#define WM8962_EQR_B4_A_WIDTH                       16  /* EQR_B4_A - [15:0] */
+
+/*
+ * R370 (0x172) - EQ36
+ */
+#define WM8962_EQR_B4_B_MASK                    0xFFFF  /* EQR_B4_B - [15:0] */
+#define WM8962_EQR_B4_B_SHIFT                        0  /* EQR_B4_B - [15:0] */
+#define WM8962_EQR_B4_B_WIDTH                       16  /* EQR_B4_B - [15:0] */
+
+/*
+ * R371 (0x173) - EQ37
+ */
+#define WM8962_EQR_B4_C_MASK                    0xFFFF  /* EQR_B4_C - [15:0] */
+#define WM8962_EQR_B4_C_SHIFT                        0  /* EQR_B4_C - [15:0] */
+#define WM8962_EQR_B4_C_WIDTH                       16  /* EQR_B4_C - [15:0] */
+
+/*
+ * R372 (0x174) - EQ38
+ */
+#define WM8962_EQR_B4_PG_MASK                   0xFFFF  /* EQR_B4_PG - [15:0] */
+#define WM8962_EQR_B4_PG_SHIFT                       0  /* EQR_B4_PG - [15:0] */
+#define WM8962_EQR_B4_PG_WIDTH                      16  /* EQR_B4_PG - [15:0] */
+
+/*
+ * R373 (0x175) - EQ39
+ */
+#define WM8962_EQR_B5_A_MASK                    0xFFFF  /* EQR_B5_A - [15:0] */
+#define WM8962_EQR_B5_A_SHIFT                        0  /* EQR_B5_A - [15:0] */
+#define WM8962_EQR_B5_A_WIDTH                       16  /* EQR_B5_A - [15:0] */
+
+/*
+ * R374 (0x176) - EQ40
+ */
+#define WM8962_EQR_B5_B_MASK                    0xFFFF  /* EQR_B5_B - [15:0] */
+#define WM8962_EQR_B5_B_SHIFT                        0  /* EQR_B5_B - [15:0] */
+#define WM8962_EQR_B5_B_WIDTH                       16  /* EQR_B5_B - [15:0] */
+
+/*
+ * R375 (0x177) - EQ41
+ */
+#define WM8962_EQR_B5_PG_MASK                   0xFFFF  /* EQR_B5_PG - [15:0] */
+#define WM8962_EQR_B5_PG_SHIFT                       0  /* EQR_B5_PG - [15:0] */
+#define WM8962_EQR_B5_PG_WIDTH                      16  /* EQR_B5_PG - [15:0] */
+
+/*
+ * R513 (0x201) - GPIO 2
+ */
+#define WM8962_GP2_POL                          0x0400  /* GP2_POL */
+#define WM8962_GP2_POL_MASK                     0x0400  /* GP2_POL */
+#define WM8962_GP2_POL_SHIFT                        10  /* GP2_POL */
+#define WM8962_GP2_POL_WIDTH                         1  /* GP2_POL */
+#define WM8962_GP2_LVL                          0x0040  /* GP2_LVL */
+#define WM8962_GP2_LVL_MASK                     0x0040  /* GP2_LVL */
+#define WM8962_GP2_LVL_SHIFT                         6  /* GP2_LVL */
+#define WM8962_GP2_LVL_WIDTH                         1  /* GP2_LVL */
+#define WM8962_GP2_FN_MASK                      0x001F  /* GP2_FN - [4:0] */
+#define WM8962_GP2_FN_SHIFT                          0  /* GP2_FN - [4:0] */
+#define WM8962_GP2_FN_WIDTH                          5  /* GP2_FN - [4:0] */
+
+/*
+ * R514 (0x202) - GPIO 3
+ */
+#define WM8962_GP3_POL                          0x0400  /* GP3_POL */
+#define WM8962_GP3_POL_MASK                     0x0400  /* GP3_POL */
+#define WM8962_GP3_POL_SHIFT                        10  /* GP3_POL */
+#define WM8962_GP3_POL_WIDTH                         1  /* GP3_POL */
+#define WM8962_GP3_LVL                          0x0040  /* GP3_LVL */
+#define WM8962_GP3_LVL_MASK                     0x0040  /* GP3_LVL */
+#define WM8962_GP3_LVL_SHIFT                         6  /* GP3_LVL */
+#define WM8962_GP3_LVL_WIDTH                         1  /* GP3_LVL */
+#define WM8962_GP3_FN_MASK                      0x001F  /* GP3_FN - [4:0] */
+#define WM8962_GP3_FN_SHIFT                          0  /* GP3_FN - [4:0] */
+#define WM8962_GP3_FN_WIDTH                          5  /* GP3_FN - [4:0] */
+
+/*
+ * R516 (0x204) - GPIO 5
+ */
+#define WM8962_GP5_DIR                          0x8000  /* GP5_DIR */
+#define WM8962_GP5_DIR_MASK                     0x8000  /* GP5_DIR */
+#define WM8962_GP5_DIR_SHIFT                        15  /* GP5_DIR */
+#define WM8962_GP5_DIR_WIDTH                         1  /* GP5_DIR */
+#define WM8962_GP5_PU                           0x4000  /* GP5_PU */
+#define WM8962_GP5_PU_MASK                      0x4000  /* GP5_PU */
+#define WM8962_GP5_PU_SHIFT                         14  /* GP5_PU */
+#define WM8962_GP5_PU_WIDTH                          1  /* GP5_PU */
+#define WM8962_GP5_PD                           0x2000  /* GP5_PD */
+#define WM8962_GP5_PD_MASK                      0x2000  /* GP5_PD */
+#define WM8962_GP5_PD_SHIFT                         13  /* GP5_PD */
+#define WM8962_GP5_PD_WIDTH                          1  /* GP5_PD */
+#define WM8962_GP5_POL                          0x0400  /* GP5_POL */
+#define WM8962_GP5_POL_MASK                     0x0400  /* GP5_POL */
+#define WM8962_GP5_POL_SHIFT                        10  /* GP5_POL */
+#define WM8962_GP5_POL_WIDTH                         1  /* GP5_POL */
+#define WM8962_GP5_OP_CFG                       0x0200  /* GP5_OP_CFG */
+#define WM8962_GP5_OP_CFG_MASK                  0x0200  /* GP5_OP_CFG */
+#define WM8962_GP5_OP_CFG_SHIFT                      9  /* GP5_OP_CFG */
+#define WM8962_GP5_OP_CFG_WIDTH                      1  /* GP5_OP_CFG */
+#define WM8962_GP5_DB                           0x0100  /* GP5_DB */
+#define WM8962_GP5_DB_MASK                      0x0100  /* GP5_DB */
+#define WM8962_GP5_DB_SHIFT                          8  /* GP5_DB */
+#define WM8962_GP5_DB_WIDTH                          1  /* GP5_DB */
+#define WM8962_GP5_LVL                          0x0040  /* GP5_LVL */
+#define WM8962_GP5_LVL_MASK                     0x0040  /* GP5_LVL */
+#define WM8962_GP5_LVL_SHIFT                         6  /* GP5_LVL */
+#define WM8962_GP5_LVL_WIDTH                         1  /* GP5_LVL */
+#define WM8962_GP5_FN_MASK                      0x001F  /* GP5_FN - [4:0] */
+#define WM8962_GP5_FN_SHIFT                          0  /* GP5_FN - [4:0] */
+#define WM8962_GP5_FN_WIDTH                          5  /* GP5_FN - [4:0] */
+
+/*
+ * R517 (0x205) - GPIO 6
+ */
+#define WM8962_GP6_DIR                          0x8000  /* GP6_DIR */
+#define WM8962_GP6_DIR_MASK                     0x8000  /* GP6_DIR */
+#define WM8962_GP6_DIR_SHIFT                        15  /* GP6_DIR */
+#define WM8962_GP6_DIR_WIDTH                         1  /* GP6_DIR */
+#define WM8962_GP6_PU                           0x4000  /* GP6_PU */
+#define WM8962_GP6_PU_MASK                      0x4000  /* GP6_PU */
+#define WM8962_GP6_PU_SHIFT                         14  /* GP6_PU */
+#define WM8962_GP6_PU_WIDTH                          1  /* GP6_PU */
+#define WM8962_GP6_PD                           0x2000  /* GP6_PD */
+#define WM8962_GP6_PD_MASK                      0x2000  /* GP6_PD */
+#define WM8962_GP6_PD_SHIFT                         13  /* GP6_PD */
+#define WM8962_GP6_PD_WIDTH                          1  /* GP6_PD */
+#define WM8962_GP6_POL                          0x0400  /* GP6_POL */
+#define WM8962_GP6_POL_MASK                     0x0400  /* GP6_POL */
+#define WM8962_GP6_POL_SHIFT                        10  /* GP6_POL */
+#define WM8962_GP6_POL_WIDTH                         1  /* GP6_POL */
+#define WM8962_GP6_OP_CFG                       0x0200  /* GP6_OP_CFG */
+#define WM8962_GP6_OP_CFG_MASK                  0x0200  /* GP6_OP_CFG */
+#define WM8962_GP6_OP_CFG_SHIFT                      9  /* GP6_OP_CFG */
+#define WM8962_GP6_OP_CFG_WIDTH                      1  /* GP6_OP_CFG */
+#define WM8962_GP6_DB                           0x0100  /* GP6_DB */
+#define WM8962_GP6_DB_MASK                      0x0100  /* GP6_DB */
+#define WM8962_GP6_DB_SHIFT                          8  /* GP6_DB */
+#define WM8962_GP6_DB_WIDTH                          1  /* GP6_DB */
+#define WM8962_GP6_LVL                          0x0040  /* GP6_LVL */
+#define WM8962_GP6_LVL_MASK                     0x0040  /* GP6_LVL */
+#define WM8962_GP6_LVL_SHIFT                         6  /* GP6_LVL */
+#define WM8962_GP6_LVL_WIDTH                         1  /* GP6_LVL */
+#define WM8962_GP6_FN_MASK                      0x001F  /* GP6_FN - [4:0] */
+#define WM8962_GP6_FN_SHIFT                          0  /* GP6_FN - [4:0] */
+#define WM8962_GP6_FN_WIDTH                          5  /* GP6_FN - [4:0] */
+
+/*
+ * R560 (0x230) - Interrupt Status 1
+ */
+#define WM8962_GP6_EINT                         0x0020  /* GP6_EINT */
+#define WM8962_GP6_EINT_MASK                    0x0020  /* GP6_EINT */
+#define WM8962_GP6_EINT_SHIFT                        5  /* GP6_EINT */
+#define WM8962_GP6_EINT_WIDTH                        1  /* GP6_EINT */
+#define WM8962_GP5_EINT                         0x0010  /* GP5_EINT */
+#define WM8962_GP5_EINT_MASK                    0x0010  /* GP5_EINT */
+#define WM8962_GP5_EINT_SHIFT                        4  /* GP5_EINT */
+#define WM8962_GP5_EINT_WIDTH                        1  /* GP5_EINT */
+
+/*
+ * R561 (0x231) - Interrupt Status 2
+ */
+#define WM8962_MICSCD_EINT                      0x8000  /* MICSCD_EINT */
+#define WM8962_MICSCD_EINT_MASK                 0x8000  /* MICSCD_EINT */
+#define WM8962_MICSCD_EINT_SHIFT                    15  /* MICSCD_EINT */
+#define WM8962_MICSCD_EINT_WIDTH                     1  /* MICSCD_EINT */
+#define WM8962_MICD_EINT                        0x4000  /* MICD_EINT */
+#define WM8962_MICD_EINT_MASK                   0x4000  /* MICD_EINT */
+#define WM8962_MICD_EINT_SHIFT                      14  /* MICD_EINT */
+#define WM8962_MICD_EINT_WIDTH                       1  /* MICD_EINT */
+#define WM8962_FIFOS_ERR_EINT                   0x2000  /* FIFOS_ERR_EINT */
+#define WM8962_FIFOS_ERR_EINT_MASK              0x2000  /* FIFOS_ERR_EINT */
+#define WM8962_FIFOS_ERR_EINT_SHIFT                 13  /* FIFOS_ERR_EINT */
+#define WM8962_FIFOS_ERR_EINT_WIDTH                  1  /* FIFOS_ERR_EINT */
+#define WM8962_ALC_LOCK_EINT                    0x1000  /* ALC_LOCK_EINT */
+#define WM8962_ALC_LOCK_EINT_MASK               0x1000  /* ALC_LOCK_EINT */
+#define WM8962_ALC_LOCK_EINT_SHIFT                  12  /* ALC_LOCK_EINT */
+#define WM8962_ALC_LOCK_EINT_WIDTH                   1  /* ALC_LOCK_EINT */
+#define WM8962_ALC_THRESH_EINT                  0x0800  /* ALC_THRESH_EINT */
+#define WM8962_ALC_THRESH_EINT_MASK             0x0800  /* ALC_THRESH_EINT */
+#define WM8962_ALC_THRESH_EINT_SHIFT                11  /* ALC_THRESH_EINT */
+#define WM8962_ALC_THRESH_EINT_WIDTH                 1  /* ALC_THRESH_EINT */
+#define WM8962_ALC_SAT_EINT                     0x0400  /* ALC_SAT_EINT */
+#define WM8962_ALC_SAT_EINT_MASK                0x0400  /* ALC_SAT_EINT */
+#define WM8962_ALC_SAT_EINT_SHIFT                   10  /* ALC_SAT_EINT */
+#define WM8962_ALC_SAT_EINT_WIDTH                    1  /* ALC_SAT_EINT */
+#define WM8962_ALC_PKOVR_EINT                   0x0200  /* ALC_PKOVR_EINT */
+#define WM8962_ALC_PKOVR_EINT_MASK              0x0200  /* ALC_PKOVR_EINT */
+#define WM8962_ALC_PKOVR_EINT_SHIFT                  9  /* ALC_PKOVR_EINT */
+#define WM8962_ALC_PKOVR_EINT_WIDTH                  1  /* ALC_PKOVR_EINT */
+#define WM8962_ALC_NGATE_EINT                   0x0100  /* ALC_NGATE_EINT */
+#define WM8962_ALC_NGATE_EINT_MASK              0x0100  /* ALC_NGATE_EINT */
+#define WM8962_ALC_NGATE_EINT_SHIFT                  8  /* ALC_NGATE_EINT */
+#define WM8962_ALC_NGATE_EINT_WIDTH                  1  /* ALC_NGATE_EINT */
+#define WM8962_WSEQ_DONE_EINT                   0x0080  /* WSEQ_DONE_EINT */
+#define WM8962_WSEQ_DONE_EINT_MASK              0x0080  /* WSEQ_DONE_EINT */
+#define WM8962_WSEQ_DONE_EINT_SHIFT                  7  /* WSEQ_DONE_EINT */
+#define WM8962_WSEQ_DONE_EINT_WIDTH                  1  /* WSEQ_DONE_EINT */
+#define WM8962_DRC_ACTDET_EINT                  0x0040  /* DRC_ACTDET_EINT */
+#define WM8962_DRC_ACTDET_EINT_MASK             0x0040  /* DRC_ACTDET_EINT */
+#define WM8962_DRC_ACTDET_EINT_SHIFT                 6  /* DRC_ACTDET_EINT */
+#define WM8962_DRC_ACTDET_EINT_WIDTH                 1  /* DRC_ACTDET_EINT */
+#define WM8962_FLL_LOCK_EINT                    0x0020  /* FLL_LOCK_EINT */
+#define WM8962_FLL_LOCK_EINT_MASK               0x0020  /* FLL_LOCK_EINT */
+#define WM8962_FLL_LOCK_EINT_SHIFT                   5  /* FLL_LOCK_EINT */
+#define WM8962_FLL_LOCK_EINT_WIDTH                   1  /* FLL_LOCK_EINT */
+#define WM8962_PLL3_LOCK_EINT                   0x0008  /* PLL3_LOCK_EINT */
+#define WM8962_PLL3_LOCK_EINT_MASK              0x0008  /* PLL3_LOCK_EINT */
+#define WM8962_PLL3_LOCK_EINT_SHIFT                  3  /* PLL3_LOCK_EINT */
+#define WM8962_PLL3_LOCK_EINT_WIDTH                  1  /* PLL3_LOCK_EINT */
+#define WM8962_PLL2_LOCK_EINT                   0x0004  /* PLL2_LOCK_EINT */
+#define WM8962_PLL2_LOCK_EINT_MASK              0x0004  /* PLL2_LOCK_EINT */
+#define WM8962_PLL2_LOCK_EINT_SHIFT                  2  /* PLL2_LOCK_EINT */
+#define WM8962_PLL2_LOCK_EINT_WIDTH                  1  /* PLL2_LOCK_EINT */
+#define WM8962_TEMP_SHUT_EINT                   0x0001  /* TEMP_SHUT_EINT */
+#define WM8962_TEMP_SHUT_EINT_MASK              0x0001  /* TEMP_SHUT_EINT */
+#define WM8962_TEMP_SHUT_EINT_SHIFT                  0  /* TEMP_SHUT_EINT */
+#define WM8962_TEMP_SHUT_EINT_WIDTH                  1  /* TEMP_SHUT_EINT */
+
+/*
+ * R568 (0x238) - Interrupt Status 1 Mask
+ */
+#define WM8962_IM_GP6_EINT                      0x0020  /* IM_GP6_EINT */
+#define WM8962_IM_GP6_EINT_MASK                 0x0020  /* IM_GP6_EINT */
+#define WM8962_IM_GP6_EINT_SHIFT                     5  /* IM_GP6_EINT */
+#define WM8962_IM_GP6_EINT_WIDTH                     1  /* IM_GP6_EINT */
+#define WM8962_IM_GP5_EINT                      0x0010  /* IM_GP5_EINT */
+#define WM8962_IM_GP5_EINT_MASK                 0x0010  /* IM_GP5_EINT */
+#define WM8962_IM_GP5_EINT_SHIFT                     4  /* IM_GP5_EINT */
+#define WM8962_IM_GP5_EINT_WIDTH                     1  /* IM_GP5_EINT */
+
+/*
+ * R569 (0x239) - Interrupt Status 2 Mask
+ */
+#define WM8962_IM_MICSCD_EINT                   0x8000  /* IM_MICSCD_EINT */
+#define WM8962_IM_MICSCD_EINT_MASK              0x8000  /* IM_MICSCD_EINT */
+#define WM8962_IM_MICSCD_EINT_SHIFT                 15  /* IM_MICSCD_EINT */
+#define WM8962_IM_MICSCD_EINT_WIDTH                  1  /* IM_MICSCD_EINT */
+#define WM8962_IM_MICD_EINT                     0x4000  /* IM_MICD_EINT */
+#define WM8962_IM_MICD_EINT_MASK                0x4000  /* IM_MICD_EINT */
+#define WM8962_IM_MICD_EINT_SHIFT                   14  /* IM_MICD_EINT */
+#define WM8962_IM_MICD_EINT_WIDTH                    1  /* IM_MICD_EINT */
+#define WM8962_IM_FIFOS_ERR_EINT                0x2000  /* IM_FIFOS_ERR_EINT */
+#define WM8962_IM_FIFOS_ERR_EINT_MASK           0x2000  /* IM_FIFOS_ERR_EINT */
+#define WM8962_IM_FIFOS_ERR_EINT_SHIFT              13  /* IM_FIFOS_ERR_EINT */
+#define WM8962_IM_FIFOS_ERR_EINT_WIDTH               1  /* IM_FIFOS_ERR_EINT */
+#define WM8962_IM_ALC_LOCK_EINT                 0x1000  /* IM_ALC_LOCK_EINT */
+#define WM8962_IM_ALC_LOCK_EINT_MASK            0x1000  /* IM_ALC_LOCK_EINT */
+#define WM8962_IM_ALC_LOCK_EINT_SHIFT               12  /* IM_ALC_LOCK_EINT */
+#define WM8962_IM_ALC_LOCK_EINT_WIDTH                1  /* IM_ALC_LOCK_EINT */
+#define WM8962_IM_ALC_THRESH_EINT               0x0800  /* IM_ALC_THRESH_EINT */
+#define WM8962_IM_ALC_THRESH_EINT_MASK          0x0800  /* IM_ALC_THRESH_EINT */
+#define WM8962_IM_ALC_THRESH_EINT_SHIFT             11  /* IM_ALC_THRESH_EINT */
+#define WM8962_IM_ALC_THRESH_EINT_WIDTH              1  /* IM_ALC_THRESH_EINT */
+#define WM8962_IM_ALC_SAT_EINT                  0x0400  /* IM_ALC_SAT_EINT */
+#define WM8962_IM_ALC_SAT_EINT_MASK             0x0400  /* IM_ALC_SAT_EINT */
+#define WM8962_IM_ALC_SAT_EINT_SHIFT                10  /* IM_ALC_SAT_EINT */
+#define WM8962_IM_ALC_SAT_EINT_WIDTH                 1  /* IM_ALC_SAT_EINT */
+#define WM8962_IM_ALC_PKOVR_EINT                0x0200  /* IM_ALC_PKOVR_EINT */
+#define WM8962_IM_ALC_PKOVR_EINT_MASK           0x0200  /* IM_ALC_PKOVR_EINT */
+#define WM8962_IM_ALC_PKOVR_EINT_SHIFT               9  /* IM_ALC_PKOVR_EINT */
+#define WM8962_IM_ALC_PKOVR_EINT_WIDTH               1  /* IM_ALC_PKOVR_EINT */
+#define WM8962_IM_ALC_NGATE_EINT                0x0100  /* IM_ALC_NGATE_EINT */
+#define WM8962_IM_ALC_NGATE_EINT_MASK           0x0100  /* IM_ALC_NGATE_EINT */
+#define WM8962_IM_ALC_NGATE_EINT_SHIFT               8  /* IM_ALC_NGATE_EINT */
+#define WM8962_IM_ALC_NGATE_EINT_WIDTH               1  /* IM_ALC_NGATE_EINT */
+#define WM8962_IM_WSEQ_DONE_EINT                0x0080  /* IM_WSEQ_DONE_EINT */
+#define WM8962_IM_WSEQ_DONE_EINT_MASK           0x0080  /* IM_WSEQ_DONE_EINT */
+#define WM8962_IM_WSEQ_DONE_EINT_SHIFT               7  /* IM_WSEQ_DONE_EINT */
+#define WM8962_IM_WSEQ_DONE_EINT_WIDTH               1  /* IM_WSEQ_DONE_EINT */
+#define WM8962_IM_DRC_ACTDET_EINT               0x0040  /* IM_DRC_ACTDET_EINT */
+#define WM8962_IM_DRC_ACTDET_EINT_MASK          0x0040  /* IM_DRC_ACTDET_EINT */
+#define WM8962_IM_DRC_ACTDET_EINT_SHIFT              6  /* IM_DRC_ACTDET_EINT */
+#define WM8962_IM_DRC_ACTDET_EINT_WIDTH              1  /* IM_DRC_ACTDET_EINT */
+#define WM8962_IM_FLL_LOCK_EINT                 0x0020  /* IM_FLL_LOCK_EINT */
+#define WM8962_IM_FLL_LOCK_EINT_MASK            0x0020  /* IM_FLL_LOCK_EINT */
+#define WM8962_IM_FLL_LOCK_EINT_SHIFT                5  /* IM_FLL_LOCK_EINT */
+#define WM8962_IM_FLL_LOCK_EINT_WIDTH                1  /* IM_FLL_LOCK_EINT */
+#define WM8962_IM_PLL3_LOCK_EINT                0x0008  /* IM_PLL3_LOCK_EINT */
+#define WM8962_IM_PLL3_LOCK_EINT_MASK           0x0008  /* IM_PLL3_LOCK_EINT */
+#define WM8962_IM_PLL3_LOCK_EINT_SHIFT               3  /* IM_PLL3_LOCK_EINT */
+#define WM8962_IM_PLL3_LOCK_EINT_WIDTH               1  /* IM_PLL3_LOCK_EINT */
+#define WM8962_IM_PLL2_LOCK_EINT                0x0004  /* IM_PLL2_LOCK_EINT */
+#define WM8962_IM_PLL2_LOCK_EINT_MASK           0x0004  /* IM_PLL2_LOCK_EINT */
+#define WM8962_IM_PLL2_LOCK_EINT_SHIFT               2  /* IM_PLL2_LOCK_EINT */
+#define WM8962_IM_PLL2_LOCK_EINT_WIDTH               1  /* IM_PLL2_LOCK_EINT */
+#define WM8962_IM_TEMP_SHUT_EINT                0x0001  /* IM_TEMP_SHUT_EINT */
+#define WM8962_IM_TEMP_SHUT_EINT_MASK           0x0001  /* IM_TEMP_SHUT_EINT */
+#define WM8962_IM_TEMP_SHUT_EINT_SHIFT               0  /* IM_TEMP_SHUT_EINT */
+#define WM8962_IM_TEMP_SHUT_EINT_WIDTH               1  /* IM_TEMP_SHUT_EINT */
+
+/*
+ * R576 (0x240) - Interrupt Control
+ */
+#define WM8962_IRQ_POL                          0x0001  /* IRQ_POL */
+#define WM8962_IRQ_POL_MASK                     0x0001  /* IRQ_POL */
+#define WM8962_IRQ_POL_SHIFT                         0  /* IRQ_POL */
+#define WM8962_IRQ_POL_WIDTH                         1  /* IRQ_POL */
+
+/*
+ * R584 (0x248) - IRQ Debounce
+ */
+#define WM8962_FLL_LOCK_DB                      0x0020  /* FLL_LOCK_DB */
+#define WM8962_FLL_LOCK_DB_MASK                 0x0020  /* FLL_LOCK_DB */
+#define WM8962_FLL_LOCK_DB_SHIFT                     5  /* FLL_LOCK_DB */
+#define WM8962_FLL_LOCK_DB_WIDTH                     1  /* FLL_LOCK_DB */
+#define WM8962_PLL3_LOCK_DB                     0x0008  /* PLL3_LOCK_DB */
+#define WM8962_PLL3_LOCK_DB_MASK                0x0008  /* PLL3_LOCK_DB */
+#define WM8962_PLL3_LOCK_DB_SHIFT                    3  /* PLL3_LOCK_DB */
+#define WM8962_PLL3_LOCK_DB_WIDTH                    1  /* PLL3_LOCK_DB */
+#define WM8962_PLL2_LOCK_DB                     0x0004  /* PLL2_LOCK_DB */
+#define WM8962_PLL2_LOCK_DB_MASK                0x0004  /* PLL2_LOCK_DB */
+#define WM8962_PLL2_LOCK_DB_SHIFT                    2  /* PLL2_LOCK_DB */
+#define WM8962_PLL2_LOCK_DB_WIDTH                    1  /* PLL2_LOCK_DB */
+#define WM8962_TEMP_SHUT_DB                     0x0001  /* TEMP_SHUT_DB */
+#define WM8962_TEMP_SHUT_DB_MASK                0x0001  /* TEMP_SHUT_DB */
+#define WM8962_TEMP_SHUT_DB_SHIFT                    0  /* TEMP_SHUT_DB */
+#define WM8962_TEMP_SHUT_DB_WIDTH                    1  /* TEMP_SHUT_DB */
+
+/*
+ * R586 (0x24A) -  MICINT Source Pol
+ */
+#define WM8962_MICSCD_IRQ_POL                   0x8000  /* MICSCD_IRQ_POL */
+#define WM8962_MICSCD_IRQ_POL_MASK              0x8000  /* MICSCD_IRQ_POL */
+#define WM8962_MICSCD_IRQ_POL_SHIFT                 15  /* MICSCD_IRQ_POL */
+#define WM8962_MICSCD_IRQ_POL_WIDTH                  1  /* MICSCD_IRQ_POL */
+#define WM8962_MICD_IRQ_POL                     0x4000  /* MICD_IRQ_POL */
+#define WM8962_MICD_IRQ_POL_MASK                0x4000  /* MICD_IRQ_POL */
+#define WM8962_MICD_IRQ_POL_SHIFT                   14  /* MICD_IRQ_POL */
+#define WM8962_MICD_IRQ_POL_WIDTH                    1  /* MICD_IRQ_POL */
+
+/*
+ * R768 (0x300) - DSP2 Power Management
+ */
+#define WM8962_DSP2_ENA                         0x0001  /* DSP2_ENA */
+#define WM8962_DSP2_ENA_MASK                    0x0001  /* DSP2_ENA */
+#define WM8962_DSP2_ENA_SHIFT                        0  /* DSP2_ENA */
+#define WM8962_DSP2_ENA_WIDTH                        1  /* DSP2_ENA */
+
+/*
+ * R1037 (0x40D) - DSP2_ExecControl
+ */
+#define WM8962_DSP2_STOPC                       0x0020  /* DSP2_STOPC */
+#define WM8962_DSP2_STOPC_MASK                  0x0020  /* DSP2_STOPC */
+#define WM8962_DSP2_STOPC_SHIFT                      5  /* DSP2_STOPC */
+#define WM8962_DSP2_STOPC_WIDTH                      1  /* DSP2_STOPC */
+#define WM8962_DSP2_STOPS                       0x0010  /* DSP2_STOPS */
+#define WM8962_DSP2_STOPS_MASK                  0x0010  /* DSP2_STOPS */
+#define WM8962_DSP2_STOPS_SHIFT                      4  /* DSP2_STOPS */
+#define WM8962_DSP2_STOPS_WIDTH                      1  /* DSP2_STOPS */
+#define WM8962_DSP2_STOPI                       0x0008  /* DSP2_STOPI */
+#define WM8962_DSP2_STOPI_MASK                  0x0008  /* DSP2_STOPI */
+#define WM8962_DSP2_STOPI_SHIFT                      3  /* DSP2_STOPI */
+#define WM8962_DSP2_STOPI_WIDTH                      1  /* DSP2_STOPI */
+#define WM8962_DSP2_STOP                        0x0004  /* DSP2_STOP */
+#define WM8962_DSP2_STOP_MASK                   0x0004  /* DSP2_STOP */
+#define WM8962_DSP2_STOP_SHIFT                       2  /* DSP2_STOP */
+#define WM8962_DSP2_STOP_WIDTH                       1  /* DSP2_STOP */
+#define WM8962_DSP2_RUNR                        0x0002  /* DSP2_RUNR */
+#define WM8962_DSP2_RUNR_MASK                   0x0002  /* DSP2_RUNR */
+#define WM8962_DSP2_RUNR_SHIFT                       1  /* DSP2_RUNR */
+#define WM8962_DSP2_RUNR_WIDTH                       1  /* DSP2_RUNR */
+#define WM8962_DSP2_RUN                         0x0001  /* DSP2_RUN */
+#define WM8962_DSP2_RUN_MASK                    0x0001  /* DSP2_RUN */
+#define WM8962_DSP2_RUN_SHIFT                        0  /* DSP2_RUN */
+#define WM8962_DSP2_RUN_WIDTH                        1  /* DSP2_RUN */
+
+/*
+ * R8192 (0x2000) - DSP2 Instruction RAM 0
+ */
+#define WM8962_DSP2_INSTR_RAM_1024_10_9_0_MASK  0x03FF  /* DSP2_INSTR_RAM_1024_10_9_0 - [9:0] */
+#define WM8962_DSP2_INSTR_RAM_1024_10_9_0_SHIFT      0  /* DSP2_INSTR_RAM_1024_10_9_0 - [9:0] */
+#define WM8962_DSP2_INSTR_RAM_1024_10_9_0_WIDTH     10  /* DSP2_INSTR_RAM_1024_10_9_0 - [9:0] */
+
+/*
+ * R9216 (0x2400) - DSP2 Address RAM 2
+ */
+#define WM8962_DSP2_ADDR_RAM_1024_38_37_32_MASK 0x003F  /* DSP2_ADDR_RAM_1024_38_37_32 - [5:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_37_32_SHIFT      0  /* DSP2_ADDR_RAM_1024_38_37_32 - [5:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_37_32_WIDTH      6  /* DSP2_ADDR_RAM_1024_38_37_32 - [5:0] */
+
+/*
+ * R9217 (0x2401) - DSP2 Address RAM 1
+ */
+#define WM8962_DSP2_ADDR_RAM_1024_38_31_16_MASK 0xFFFF  /* DSP2_ADDR_RAM_1024_38_31_16 - [15:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_31_16_SHIFT      0  /* DSP2_ADDR_RAM_1024_38_31_16 - [15:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_31_16_WIDTH     16  /* DSP2_ADDR_RAM_1024_38_31_16 - [15:0] */
+
+/*
+ * R9218 (0x2402) - DSP2 Address RAM 0
+ */
+#define WM8962_DSP2_ADDR_RAM_1024_38_15_0_MASK  0xFFFF  /* DSP2_ADDR_RAM_1024_38_15_0 - [15:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_15_0_SHIFT      0  /* DSP2_ADDR_RAM_1024_38_15_0 - [15:0] */
+#define WM8962_DSP2_ADDR_RAM_1024_38_15_0_WIDTH     16  /* DSP2_ADDR_RAM_1024_38_15_0 - [15:0] */
+
+/*
+ * R12288 (0x3000) - DSP2 Data1 RAM 1
+ */
+#define WM8962_DSP2_DATA1_RAM_384_24_23_16_MASK 0x00FF  /* DSP2_DATA1_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA1_RAM_384_24_23_16_SHIFT      0  /* DSP2_DATA1_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA1_RAM_384_24_23_16_WIDTH      8  /* DSP2_DATA1_RAM_384_24_23_16 - [7:0] */
+
+/*
+ * R12289 (0x3001) - DSP2 Data1 RAM 0
+ */
+#define WM8962_DSP2_DATA1_RAM_384_24_15_0_MASK  0xFFFF  /* DSP2_DATA1_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA1_RAM_384_24_15_0_SHIFT      0  /* DSP2_DATA1_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA1_RAM_384_24_15_0_WIDTH     16  /* DSP2_DATA1_RAM_384_24_15_0 - [15:0] */
+
+/*
+ * R13312 (0x3400) - DSP2 Data2 RAM 1
+ */
+#define WM8962_DSP2_DATA2_RAM_384_24_23_16_MASK 0x00FF  /* DSP2_DATA2_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA2_RAM_384_24_23_16_SHIFT      0  /* DSP2_DATA2_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA2_RAM_384_24_23_16_WIDTH      8  /* DSP2_DATA2_RAM_384_24_23_16 - [7:0] */
+
+/*
+ * R13313 (0x3401) - DSP2 Data2 RAM 0
+ */
+#define WM8962_DSP2_DATA2_RAM_384_24_15_0_MASK  0xFFFF  /* DSP2_DATA2_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA2_RAM_384_24_15_0_SHIFT      0  /* DSP2_DATA2_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA2_RAM_384_24_15_0_WIDTH     16  /* DSP2_DATA2_RAM_384_24_15_0 - [15:0] */
+
+/*
+ * R14336 (0x3800) - DSP2 Data3 RAM 1
+ */
+#define WM8962_DSP2_DATA3_RAM_384_24_23_16_MASK 0x00FF  /* DSP2_DATA3_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA3_RAM_384_24_23_16_SHIFT      0  /* DSP2_DATA3_RAM_384_24_23_16 - [7:0] */
+#define WM8962_DSP2_DATA3_RAM_384_24_23_16_WIDTH      8  /* DSP2_DATA3_RAM_384_24_23_16 - [7:0] */
+
+/*
+ * R14337 (0x3801) - DSP2 Data3 RAM 0
+ */
+#define WM8962_DSP2_DATA3_RAM_384_24_15_0_MASK  0xFFFF  /* DSP2_DATA3_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA3_RAM_384_24_15_0_SHIFT      0  /* DSP2_DATA3_RAM_384_24_15_0 - [15:0] */
+#define WM8962_DSP2_DATA3_RAM_384_24_15_0_WIDTH     16  /* DSP2_DATA3_RAM_384_24_15_0 - [15:0] */
+
+/*
+ * R15360 (0x3C00) - DSP2 Coeff RAM 0
+ */
+#define WM8962_DSP2_CMAP_RAM_384_11_10_0_MASK   0x07FF  /* DSP2_CMAP_RAM_384_11_10_0 - [10:0] */
+#define WM8962_DSP2_CMAP_RAM_384_11_10_0_SHIFT       0  /* DSP2_CMAP_RAM_384_11_10_0 - [10:0] */
+#define WM8962_DSP2_CMAP_RAM_384_11_10_0_WIDTH      11  /* DSP2_CMAP_RAM_384_11_10_0 - [10:0] */
+
+/*
+ * R16384 (0x4000) - RETUNEADC_SHARED_COEFF_1
+ */
+#define WM8962_ADC_RETUNE_SCV                   0x0080  /* ADC_RETUNE_SCV */
+#define WM8962_ADC_RETUNE_SCV_MASK              0x0080  /* ADC_RETUNE_SCV */
+#define WM8962_ADC_RETUNE_SCV_SHIFT                  7  /* ADC_RETUNE_SCV */
+#define WM8962_ADC_RETUNE_SCV_WIDTH                  1  /* ADC_RETUNE_SCV */
+#define WM8962_RETUNEADC_SHARED_COEFF_22_16_MASK 0x007F  /* RETUNEADC_SHARED_COEFF_22_16 - [6:0] */
+#define WM8962_RETUNEADC_SHARED_COEFF_22_16_SHIFT      0  /* RETUNEADC_SHARED_COEFF_22_16 - [6:0] */
+#define WM8962_RETUNEADC_SHARED_COEFF_22_16_WIDTH      7  /* RETUNEADC_SHARED_COEFF_22_16 - [6:0] */
+
+/*
+ * R16385 (0x4001) - RETUNEADC_SHARED_COEFF_0
+ */
+#define WM8962_RETUNEADC_SHARED_COEFF_15_00_MASK 0xFFFF  /* RETUNEADC_SHARED_COEFF_15_00 - [15:0] */
+#define WM8962_RETUNEADC_SHARED_COEFF_15_00_SHIFT      0  /* RETUNEADC_SHARED_COEFF_15_00 - [15:0] */
+#define WM8962_RETUNEADC_SHARED_COEFF_15_00_WIDTH     16  /* RETUNEADC_SHARED_COEFF_15_00 - [15:0] */
+
+/*
+ * R16386 (0x4002) - RETUNEDAC_SHARED_COEFF_1
+ */
+#define WM8962_DAC_RETUNE_SCV                   0x0080  /* DAC_RETUNE_SCV */
+#define WM8962_DAC_RETUNE_SCV_MASK              0x0080  /* DAC_RETUNE_SCV */
+#define WM8962_DAC_RETUNE_SCV_SHIFT                  7  /* DAC_RETUNE_SCV */
+#define WM8962_DAC_RETUNE_SCV_WIDTH                  1  /* DAC_RETUNE_SCV */
+#define WM8962_RETUNEDAC_SHARED_COEFF_23_16_MASK 0x007F  /* RETUNEDAC_SHARED_COEFF_23_16 - [6:0] */
+#define WM8962_RETUNEDAC_SHARED_COEFF_23_16_SHIFT      0  /* RETUNEDAC_SHARED_COEFF_23_16 - [6:0] */
+#define WM8962_RETUNEDAC_SHARED_COEFF_23_16_WIDTH      7  /* RETUNEDAC_SHARED_COEFF_23_16 - [6:0] */
+
+/*
+ * R16387 (0x4003) - RETUNEDAC_SHARED_COEFF_0
+ */
+#define WM8962_RETUNEDAC_SHARED_COEFF_15_00_MASK 0xFFFF  /* RETUNEDAC_SHARED_COEFF_15_00 - [15:0] */
+#define WM8962_RETUNEDAC_SHARED_COEFF_15_00_SHIFT      0  /* RETUNEDAC_SHARED_COEFF_15_00 - [15:0] */
+#define WM8962_RETUNEDAC_SHARED_COEFF_15_00_WIDTH     16  /* RETUNEDAC_SHARED_COEFF_15_00 - [15:0] */
+
+/*
+ * R16388 (0x4004) - SOUNDSTAGE_ENABLES_1
+ */
+#define WM8962_SOUNDSTAGE_ENABLES_23_16_MASK    0x00FF  /* SOUNDSTAGE_ENABLES_23_16 - [7:0] */
+#define WM8962_SOUNDSTAGE_ENABLES_23_16_SHIFT        0  /* SOUNDSTAGE_ENABLES_23_16 - [7:0] */
+#define WM8962_SOUNDSTAGE_ENABLES_23_16_WIDTH        8  /* SOUNDSTAGE_ENABLES_23_16 - [7:0] */
+
+/*
+ * R16389 (0x4005) - SOUNDSTAGE_ENABLES_0
+ */
+#define WM8962_SOUNDSTAGE_ENABLES_15_06_MASK    0xFFC0  /* SOUNDSTAGE_ENABLES_15_06 - [15:6] */
+#define WM8962_SOUNDSTAGE_ENABLES_15_06_SHIFT        6  /* SOUNDSTAGE_ENABLES_15_06 - [15:6] */
+#define WM8962_SOUNDSTAGE_ENABLES_15_06_WIDTH       10  /* SOUNDSTAGE_ENABLES_15_06 - [15:6] */
+#define WM8962_RTN_ADC_ENA                      0x0020  /* RTN_ADC_ENA */
+#define WM8962_RTN_ADC_ENA_MASK                 0x0020  /* RTN_ADC_ENA */
+#define WM8962_RTN_ADC_ENA_SHIFT                     5  /* RTN_ADC_ENA */
+#define WM8962_RTN_ADC_ENA_WIDTH                     1  /* RTN_ADC_ENA */
+#define WM8962_RTN_DAC_ENA                      0x0010  /* RTN_DAC_ENA */
+#define WM8962_RTN_DAC_ENA_MASK                 0x0010  /* RTN_DAC_ENA */
+#define WM8962_RTN_DAC_ENA_SHIFT                     4  /* RTN_DAC_ENA */
+#define WM8962_RTN_DAC_ENA_WIDTH                     1  /* RTN_DAC_ENA */
+#define WM8962_HDBASS_ENA                       0x0008  /* HDBASS_ENA */
+#define WM8962_HDBASS_ENA_MASK                  0x0008  /* HDBASS_ENA */
+#define WM8962_HDBASS_ENA_SHIFT                      3  /* HDBASS_ENA */
+#define WM8962_HDBASS_ENA_WIDTH                      1  /* HDBASS_ENA */
+#define WM8962_HPF2_ENA                         0x0004  /* HPF2_ENA */
+#define WM8962_HPF2_ENA_MASK                    0x0004  /* HPF2_ENA */
+#define WM8962_HPF2_ENA_SHIFT                        2  /* HPF2_ENA */
+#define WM8962_HPF2_ENA_WIDTH                        1  /* HPF2_ENA */
+#define WM8962_HPF1_ENA                         0x0002  /* HPF1_ENA */
+#define WM8962_HPF1_ENA_MASK                    0x0002  /* HPF1_ENA */
+#define WM8962_HPF1_ENA_SHIFT                        1  /* HPF1_ENA */
+#define WM8962_HPF1_ENA_WIDTH                        1  /* HPF1_ENA */
+#define WM8962_VSS_ENA                          0x0001  /* VSS_ENA */
+#define WM8962_VSS_ENA_MASK                     0x0001  /* VSS_ENA */
+#define WM8962_VSS_ENA_SHIFT                         0  /* VSS_ENA */
+#define WM8962_VSS_ENA_WIDTH                         1  /* VSS_ENA */
+
+int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
+
+#endif
index a99620f335d2ab7fe7ace8dc37a5e1b6b637c61e..63f6dbf5d07021887084e57541591bf1fa570fb3 100644 (file)
 
 #include "wm8971.h"
 
-#define WM8971_VERSION "0.9"
-
 #define        WM8971_REG_COUNT                43
 
 static struct workqueue_struct *wm8971_workq = NULL;
 
 /* codec private data */
 struct wm8971_priv {
+       enum snd_soc_control_type control_type;
        unsigned int sysclk;
 };
 
@@ -492,8 +491,7 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8971_IFACE) & 0x1f3;
        u16 srate = snd_soc_read(codec, WM8971_SRATE) & 0x1c0;
@@ -573,8 +571,8 @@ static struct snd_soc_dai_ops wm8971_dai_ops = {
        .set_sysclk     = wm8971_set_dai_sysclk,
 };
 
-struct snd_soc_dai wm8971_dai = {
-       .name = "WM8971",
+static struct snd_soc_dai_driver wm8971_dai = {
+       .name = "wm8971-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -589,7 +587,6 @@ struct snd_soc_dai wm8971_dai = {
                .formats = WM8971_FORMATS,},
        .ops = &wm8971_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8971_dai);
 
 static void wm8971_work(struct work_struct *work)
 {
@@ -598,19 +595,14 @@ static void wm8971_work(struct work_struct *work)
        wm8971_set_bias_level(codec, codec->bias_level);
 }
 
-static int wm8971_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8971_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8971_resume(struct platform_device *pdev)
+static int wm8971_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -639,37 +631,24 @@ static int wm8971_resume(struct platform_device *pdev)
        return 0;
 }
 
-static int wm8971_init(struct snd_soc_device *socdev,
-                      enum snd_soc_control_type control)
+static int wm8971_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = socdev->card->codec;
-       int reg, ret = 0;
-
-       codec->name = "WM8971";
-       codec->owner = THIS_MODULE;
-       codec->set_bias_level = wm8971_set_bias_level;
-       codec->dai = &wm8971_dai;
-       codec->reg_cache_size = ARRAY_SIZE(wm8971_reg);
-       codec->num_dai = 1;
-       codec->reg_cache = kmemdup(wm8971_reg, sizeof(wm8971_reg), GFP_KERNEL);
-
-       if (codec->reg_cache == NULL)
-               return -ENOMEM;
+       struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0;
+       u16 reg;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8971->control_type);
        if (ret < 0) {
                printk(KERN_ERR "wm8971: failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
-       wm8971_reset(codec);
+       INIT_DELAYED_WORK(&codec->delayed_work, wm8971_work);
+       wm8971_workq = create_workqueue("wm8971");
+       if (wm8971_workq == NULL)
+               return -ENOMEM;
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8971: failed to create pcms\n");
-               goto err;
-       }
+       wm8971_reset(codec);
 
        /* charge output caps - set vmid to 5k for quick power up */
        reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
@@ -704,40 +683,54 @@ static int wm8971_init(struct snd_soc_device *socdev,
        wm8971_add_widgets(codec);
 
        return ret;
-
-err:
-       kfree(codec->reg_cache);
-       return ret;
 }
 
-/* If the i2c layer weren't so broken, we could pass this kind of data
-   around */
-static struct snd_soc_device *wm8971_socdev;
 
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+/* power down chip */
+static int wm8971_remove(struct snd_soc_codec *codec)
+{
+       wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       if (wm8971_workq)
+               destroy_workqueue(wm8971_workq);
+       return 0;
+}
 
-static int wm8971_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+static struct snd_soc_codec_driver soc_codec_dev_wm8971 = {
+       .probe =        wm8971_probe,
+       .remove =       wm8971_remove,
+       .suspend =      wm8971_suspend,
+       .resume =       wm8971_resume,
+       .set_bias_level = wm8971_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8971_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8971_reg,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8971_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
-       struct snd_soc_device *socdev = wm8971_socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct wm8971_priv *wm8971;
        int ret;
 
-       i2c_set_clientdata(i2c, codec);
+       wm8971 = kzalloc(sizeof(struct wm8971_priv), GFP_KERNEL);
+       if (wm8971 == NULL)
+               return -ENOMEM;
 
-       codec->control_data = i2c;
+       i2c_set_clientdata(i2c, wm8971);
 
-       ret = wm8971_init(socdev, SND_SOC_I2C);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8971, &wm8971_dai, 1);
        if (ret < 0)
-               pr_err("failed to initialise WM8971\n");
-
+               kfree(wm8971);
        return ret;
 }
 
-static int wm8971_i2c_remove(struct i2c_client *client)
+static __devexit int wm8971_i2c_remove(struct i2c_client *client)
 {
-       struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       kfree(codec->reg_cache);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -749,148 +742,34 @@ MODULE_DEVICE_TABLE(i2c, wm8971_i2c_id);
 
 static struct i2c_driver wm8971_i2c_driver = {
        .driver = {
-               .name = "WM8971 I2C Codec",
+               .name = "wm8971-codec",
                .owner = THIS_MODULE,
        },
-       .probe    = wm8971_i2c_probe,
-       .remove   = wm8971_i2c_remove,
+       .probe =    wm8971_i2c_probe,
+       .remove =   __devexit_p(wm8971_i2c_remove),
        .id_table = wm8971_i2c_id,
 };
-
-static int wm8971_add_i2c_device(struct platform_device *pdev,
-                                const struct wm8971_setup_data *setup)
-{
-       struct i2c_board_info info;
-       struct i2c_adapter *adapter;
-       struct i2c_client *client;
-       int ret;
-
-       ret = i2c_add_driver(&wm8971_i2c_driver);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "can't add i2c driver\n");
-               return ret;
-       }
-
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       info.addr = setup->i2c_address;
-       strlcpy(info.type, "wm8971", I2C_NAME_SIZE);
-
-       adapter = i2c_get_adapter(setup->i2c_bus);
-       if (!adapter) {
-               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
-                       setup->i2c_bus);
-               goto err_driver;
-       }
-
-       client = i2c_new_device(adapter, &info);
-       i2c_put_adapter(adapter);
-       if (!client) {
-               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
-                       (unsigned int)info.addr);
-               goto err_driver;
-       }
-
-       return 0;
-
-err_driver:
-       i2c_del_driver(&wm8971_i2c_driver);
-       return -ENODEV;
-}
-
 #endif
 
-static int wm8971_probe(struct platform_device *pdev)
+static int __init wm8971_modinit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct wm8971_setup_data *setup;
-       struct snd_soc_codec *codec;
-       struct wm8971_priv *wm8971;
        int ret = 0;
-
-       pr_info("WM8971 Audio Codec %s", WM8971_VERSION);
-
-       setup = socdev->codec_data;
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
-
-       wm8971 = kzalloc(sizeof(struct wm8971_priv), GFP_KERNEL);
-       if (wm8971 == NULL) {
-               kfree(codec);
-               return -ENOMEM;
-       }
-
-       snd_soc_codec_set_drvdata(codec, wm8971);
-       socdev->card->codec = codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-       wm8971_socdev = socdev;
-
-       INIT_DELAYED_WORK(&codec->delayed_work, wm8971_work);
-       wm8971_workq = create_workqueue("wm8971");
-       if (wm8971_workq == NULL) {
-               kfree(snd_soc_codec_get_drvdata(codec));
-               kfree(codec);
-               return -ENOMEM;
-       }
-
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
-       if (setup->i2c_address) {
-               ret = wm8971_add_i2c_device(pdev, setup);
-       }
-#endif
-       /* Add other interfaces here */
-
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8971_i2c_driver);
        if (ret != 0) {
-               destroy_workqueue(wm8971_workq);
-               kfree(snd_soc_codec_get_drvdata(codec));
-               kfree(codec);
+               printk(KERN_ERR "Failed to register WM8971 I2C driver: %d\n",
+                      ret);
        }
-
-       return ret;
-}
-
-/* power down chip */
-static int wm8971_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec->control_data)
-               wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       if (wm8971_workq)
-               destroy_workqueue(wm8971_workq);
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
-       i2c_unregister_device(codec->control_data);
-       i2c_del_driver(&wm8971_i2c_driver);
 #endif
-       kfree(snd_soc_codec_get_drvdata(codec));
-       kfree(codec);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8971 = {
-       .probe =        wm8971_probe,
-       .remove =       wm8971_remove,
-       .suspend =      wm8971_suspend,
-       .resume =       wm8971_resume,
-};
-
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8971);
-
-static int __init wm8971_modinit(void)
-{
-       return snd_soc_register_dai(&wm8971_dai);
+       return ret;
 }
 module_init(wm8971_modinit);
 
 static void __exit wm8971_exit(void)
 {
-       snd_soc_unregister_dai(&wm8971_dai);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8971_i2c_driver);
+#endif
 }
 module_exit(wm8971_exit);
 
index ef4f08f9f344b0a5b7146a4015a3686afebbab87..f31c38fddfc45eaedb118ed02279aed81aaa2775 100644 (file)
 
 #define WM8971_SYSCLK  0
 
-struct wm8971_setup_data {
-       int i2c_bus;
-       unsigned short i2c_address;
-};
-
-extern struct snd_soc_dai wm8971_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8971;
-
 #endif
index 1468fe10cbbe54d57ce5d072b5406261487d2bc8..b4363f6d19b3b2b8437dcce636aa9545d023544e 100644 (file)
@@ -51,12 +51,10 @@ static const u16 wm8974_reg[WM8974_CACHEREGNUM] = {
 #define WM8974_POWER1_BUFIOEN 0x04
 
 struct wm8974_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
        u16 reg_cache[WM8974_CACHEREGNUM];
 };
 
-static struct snd_soc_codec *wm8974_codec;
-
 #define wm8974_reset(c)        snd_soc_write(c, WM8974_RESET, 0)
 
 static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" };
@@ -566,8 +564,8 @@ static struct snd_soc_dai_ops wm8974_ops = {
        .set_pll = wm8974_set_dai_pll,
 };
 
-struct snd_soc_dai wm8974_dai = {
-       .name = "WM8974 HiFi",
+static struct snd_soc_dai_driver wm8974_dai = {
+       .name = "wm8974-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -583,21 +581,15 @@ struct snd_soc_dai wm8974_dai = {
        .ops = &wm8974_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(wm8974_dai);
 
-static int wm8974_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8974_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8974_resume(struct platform_device *pdev)
+static int wm8974_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -613,156 +605,72 @@ static int wm8974_resume(struct platform_device *pdev)
        return 0;
 }
 
-static int wm8974_probe(struct platform_device *pdev)
+static int wm8974_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
        int ret = 0;
 
-       if (wm8974_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
-       socdev->card->codec = wm8974_codec;
-       codec = wm8974_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       ret = wm8974_reset(codec);
        if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
+               dev_err(codec->dev, "Failed to issue reset\n");
+               return ret;
        }
 
+       wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
        snd_soc_add_controls(codec, wm8974_snd_controls,
                             ARRAY_SIZE(wm8974_snd_controls));
        wm8974_add_widgets(codec);
 
        return ret;
-
-pcm_err:
-       return ret;
 }
 
 /* power down chip */
-static int wm8974_remove(struct platform_device *pdev)
+static int wm8974_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
+       wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_wm8974 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm8974 = {
        .probe =        wm8974_probe,
        .remove =       wm8974_remove,
        .suspend =      wm8974_suspend,
        .resume =       wm8974_resume,
+       .set_bias_level = wm8974_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8974_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8974_reg,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8974);
-
-static __devinit int wm8974_register(struct wm8974_priv *wm8974)
-{
-       int ret;
-       struct snd_soc_codec *codec = &wm8974->codec;
-
-       if (wm8974_codec) {
-               dev_err(codec->dev, "Another WM8974 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8974);
-       codec->name = "WM8974";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8974_set_bias_level;
-       codec->dai = &wm8974_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8974_CACHEREGNUM;
-       codec->reg_cache = &wm8974->reg_cache;
-
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
-       }
-
-       memcpy(codec->reg_cache, wm8974_reg, sizeof(wm8974_reg));
-
-       ret = wm8974_reset(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset\n");
-               goto err;
-       }
-
-       wm8974_dai.dev = codec->dev;
-
-       wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       wm8974_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dai(&wm8974_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
-
-       return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm8974);
-       return ret;
-}
-
-static __devexit void wm8974_unregister(struct wm8974_priv *wm8974)
-{
-       wm8974_set_bias_level(&wm8974->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dai(&wm8974_dai);
-       snd_soc_unregister_codec(&wm8974->codec);
-       kfree(wm8974);
-       wm8974_codec = NULL;
-}
 
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8974_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8974_priv *wm8974;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8974 = kzalloc(sizeof(struct wm8974_priv), GFP_KERNEL);
        if (wm8974 == NULL)
                return -ENOMEM;
 
-       codec = &wm8974->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
        i2c_set_clientdata(i2c, wm8974);
-       codec->control_data = i2c;
-
-       codec->dev = &i2c->dev;
 
-       return wm8974_register(wm8974);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8974, &wm8974_dai, 1);
+       if (ret < 0)
+               kfree(wm8974);
+       return ret;
 }
 
 static __devexit int wm8974_i2c_remove(struct i2c_client *client)
 {
-       struct wm8974_priv *wm8974 = i2c_get_clientdata(client);
-       wm8974_unregister(wm8974);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -774,23 +682,34 @@ MODULE_DEVICE_TABLE(i2c, wm8974_i2c_id);
 
 static struct i2c_driver wm8974_i2c_driver = {
        .driver = {
-               .name = "WM8974",
+               .name = "wm8974-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8974_i2c_probe,
        .remove =   __devexit_p(wm8974_i2c_remove),
        .id_table = wm8974_i2c_id,
 };
+#endif
 
 static int __init wm8974_modinit(void)
 {
-       return i2c_add_driver(&wm8974_i2c_driver);
+       int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8974_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8974 I2C driver: %d\n",
+                      ret);
+       }
+#endif
+       return ret;
 }
 module_init(wm8974_modinit);
 
 static void __exit wm8974_exit(void)
 {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm8974_i2c_driver);
+#endif
 }
 module_exit(wm8974_exit);
 
index 896a7f0f3fc4b189e0537bb6f7765639e2957b65..3c94e7bb55a6b21e12170c736e95b75e8cf80b7a 100644 (file)
@@ -83,7 +83,4 @@
 #define WM8974_MCLKDIV_8       (6 << 5)
 #define WM8974_MCLKDIV_12      (7 << 5)
 
-extern struct snd_soc_dai wm8974_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8974;
-
 #endif
index 8a1ad778e7e345d42780fec7baccbb6e0f9b984e..13b979a71a7cfc6847a4f8cd72d21f10778c2dc4 100644 (file)
@@ -31,8 +31,6 @@
 
 #include "wm8978.h"
 
-static struct snd_soc_codec *wm8978_codec;
-
 /* wm8978 register cache. Note that register 0 is not included in the cache. */
 static const u16 wm8978_reg[WM8978_CACHEREGNUM] = {
        0x0000, 0x0000, 0x0000, 0x0000, /* 0x00...0x03 */
@@ -54,7 +52,8 @@ static const u16 wm8978_reg[WM8978_CACHEREGNUM] = {
 
 /* codec private data */
 struct wm8978_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+       void *control_data;
        unsigned int f_pllout;
        unsigned int f_mclk;
        unsigned int f_256fs;
@@ -374,8 +373,8 @@ struct wm8978_pll_div {
 
 #define FIXED_PLL_SIZE (1 << 24)
 
-static void pll_factors(struct wm8978_pll_div *pll_div, unsigned int target,
-                       unsigned int source)
+static void pll_factors(struct snd_soc_codec *codec,
+               struct wm8978_pll_div *pll_div, unsigned int target, unsigned int source)
 {
        u64 k_part;
        unsigned int k, n_div, n_mod;
@@ -390,7 +389,7 @@ static void pll_factors(struct wm8978_pll_div *pll_div, unsigned int target,
        }
 
        if (n_div < 6 || n_div > 12)
-               dev_warn(wm8978_codec->dev,
+               dev_warn(codec->dev,
                         "WM8978 N value exceeds recommended range! N = %u\n",
                         n_div);
 
@@ -505,7 +504,7 @@ static int wm8978_configure_pll(struct snd_soc_codec *codec)
        dev_dbg(codec->dev, "%s: f_MCLK=%uHz, f_PLLOUT=%uHz\n", __func__,
                wm8978->f_mclk, wm8978->f_pllout);
 
-       pll_factors(&pll_div, f2, wm8978->f_mclk);
+       pll_factors(codec, &pll_div, f2, wm8978->f_mclk);
 
        dev_dbg(codec->dev, "%s: calculated PLL N=0x%x, K=0x%x, div2=%d\n",
                __func__, pll_div.n, pll_div.k, pll_div.div2);
@@ -690,8 +689,7 @@ static int wm8978_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
        /* Word length mask = 0x60 */
        u16 iface_ctl = snd_soc_read(codec, WM8978_AUDIO_INTERFACE) & ~0x60;
@@ -875,9 +873,8 @@ static struct snd_soc_dai_ops wm8978_dai_ops = {
 };
 
 /* Also supports 12kHz */
-struct snd_soc_dai wm8978_dai = {
-       .name = "WM8978 HiFi",
-       .id = 1,
+static struct snd_soc_dai_driver wm8978_dai = {
+       .name = "wm8978-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -894,13 +891,9 @@ struct snd_soc_dai wm8978_dai = {
        },
        .ops = &wm8978_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8978_dai);
 
-static int wm8978_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8978_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF);
        /* Also switch PLL off */
        snd_soc_write(codec, WM8978_POWER_MANAGEMENT_1, 0);
@@ -908,10 +901,8 @@ static int wm8978_suspend(struct platform_device *pdev, pm_message_t state)
        return 0;
 }
 
-static int wm8978_resume(struct platform_device *pdev)
+static int wm8978_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
        int i;
        u16 *cache = codec->reg_cache;
@@ -933,54 +924,6 @@ static int wm8978_resume(struct platform_device *pdev)
        return 0;
 }
 
-static int wm8978_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (wm8978_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8978_codec;
-       codec = wm8978_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       snd_soc_add_controls(codec, wm8978_snd_controls,
-                            ARRAY_SIZE(wm8978_snd_controls));
-       wm8978_add_widgets(codec);
-
-pcm_err:
-       return ret;
-}
-
-/* power down chip */
-static int wm8978_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8978 = {
-       .probe          = wm8978_probe,
-       .remove         = wm8978_remove,
-       .suspend        = wm8978_suspend,
-       .resume         = wm8978_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8978);
-
 /*
  * These registers contain an "update" bit - bit 8. This means, for example,
  * that one can write new DAC digital volume for both channels, but only when
@@ -1000,44 +943,23 @@ static const int update_reg[] = {
        WM8978_ROUT2_SPK_CONTROL,
 };
 
-static __devinit int wm8978_register(struct wm8978_priv *wm8978)
+static int wm8978_probe(struct snd_soc_codec *codec)
 {
-       int ret, i;
-       struct snd_soc_codec *codec = &wm8978->codec;
-
-       if (wm8978_codec) {
-               dev_err(codec->dev, "Another WM8978 is registered\n");
-               return -EINVAL;
-       }
+       struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
+       int ret = 0, i;
 
        /*
         * Set default system clock to PLL, it is more precise, this is also the
         * default hardware setting
         */
        wm8978->sysclk = WM8978_PLL;
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8978);
-       codec->name = "WM8978";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8978_set_bias_level;
-       codec->dai = &wm8978_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = WM8978_CACHEREGNUM;
-       codec->reg_cache = &wm8978->reg_cache;
-
+       codec->control_data = wm8978->control_data;
        ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
-       memcpy(codec->reg_cache, wm8978_reg, sizeof(wm8978_reg));
-
        /*
         * Set the update bit in all registers, that have one. This way all
         * writes to those registers will also cause the update bit to be
@@ -1050,74 +972,61 @@ static __devinit int wm8978_register(struct wm8978_priv *wm8978)
        ret = snd_soc_write(codec, WM8978_RESET, 0);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset\n");
-               goto err;
+               return ret;
        }
 
-       wm8978_dai.dev = codec->dev;
-
        wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       wm8978_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dai(&wm8978_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
+       snd_soc_add_controls(codec, wm8978_snd_controls,
+                            ARRAY_SIZE(wm8978_snd_controls));
+       wm8978_add_widgets(codec);
 
        return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       return ret;
 }
 
-static __devexit void wm8978_unregister(struct wm8978_priv *wm8978)
+/* power down chip */
+static int wm8978_remove(struct snd_soc_codec *codec)
 {
-       wm8978_set_bias_level(&wm8978->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dai(&wm8978_dai);
-       snd_soc_unregister_codec(&wm8978->codec);
-       wm8978_codec = NULL;
+       wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_wm8978 = {
+       .probe =        wm8978_probe,
+       .remove =       wm8978_remove,
+       .suspend =      wm8978_suspend,
+       .resume =       wm8978_resume,
+       .set_bias_level = wm8978_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8978_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8978_reg,
+};
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8978_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
-       int ret;
        struct wm8978_priv *wm8978;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8978 = kzalloc(sizeof(struct wm8978_priv), GFP_KERNEL);
        if (wm8978 == NULL)
                return -ENOMEM;
 
-       codec = &wm8978->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
        i2c_set_clientdata(i2c, wm8978);
-       codec->control_data = i2c;
-
-       codec->dev = &i2c->dev;
+       wm8978->control_data = i2c;
 
-       ret = wm8978_register(wm8978);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8978, &wm8978_dai, 1);
        if (ret < 0)
                kfree(wm8978);
-
        return ret;
 }
 
 static __devexit int wm8978_i2c_remove(struct i2c_client *client)
 {
-       struct wm8978_priv *wm8978 = i2c_get_clientdata(client);
-       wm8978_unregister(wm8978);
-       kfree(wm8978);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -1129,23 +1038,34 @@ MODULE_DEVICE_TABLE(i2c, wm8978_i2c_id);
 
 static struct i2c_driver wm8978_i2c_driver = {
        .driver = {
-               .name = "WM8978",
+               .name = "wm8978",
                .owner = THIS_MODULE,
        },
        .probe =    wm8978_i2c_probe,
        .remove =   __devexit_p(wm8978_i2c_remove),
        .id_table = wm8978_i2c_id,
 };
+#endif
 
 static int __init wm8978_modinit(void)
 {
-       return i2c_add_driver(&wm8978_i2c_driver);
+       int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8978_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8978 I2C driver: %d\n",
+                      ret);
+       }
+#endif
+       return ret;
 }
 module_init(wm8978_modinit);
 
 static void __exit wm8978_exit(void)
 {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm8978_i2c_driver);
+#endif
 }
 module_exit(wm8978_exit);
 
index 56ec83270917db070872ea5a9756e83b9bf16220..c75525b7f154c9fe25e88a91cb55e99d7e0b37c2 100644 (file)
@@ -80,7 +80,4 @@ enum wm8978_sysclk_src {
        WM8978_MCLK
 };
 
-extern struct snd_soc_dai wm8978_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8978;
-
 #endif /* __WM8978_H__ */
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
new file mode 100644 (file)
index 0000000..fd2e7cc
--- /dev/null
@@ -0,0 +1,1192 @@
+/*
+ * wm8985.c  --  WM8985 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.
+ *
+ * TODO:
+ *  o Add OUT3/OUT4 mixer controls.
+ */
+
+#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/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 "wm8985.h"
+
+#define WM8985_NUM_SUPPLIES 4
+static const char *wm8985_supply_names[WM8985_NUM_SUPPLIES] = {
+       "DCVDD",
+       "DBVDD",
+       "AVDD1",
+       "AVDD2"
+};
+
+static const u16 wm8985_reg_defs[] = {
+       0x0000,     /* R0  - Software Reset */
+       0x0000,     /* R1  - Power management 1 */
+       0x0000,     /* R2  - Power management 2 */
+       0x0000,     /* R3  - Power management 3 */
+       0x0050,     /* R4  - Audio Interface */
+       0x0000,     /* R5  - Companding control */
+       0x0140,     /* R6  - Clock Gen control */
+       0x0000,     /* R7  - Additional control */
+       0x0000,     /* R8  - GPIO Control */
+       0x0000,     /* R9  - Jack Detect Control 1 */
+       0x0000,     /* R10 - DAC Control */
+       0x00FF,     /* R11 - Left DAC digital Vol */
+       0x00FF,     /* R12 - Right DAC digital vol */
+       0x0000,     /* R13 - Jack Detect Control 2 */
+       0x0100,     /* R14 - ADC Control */
+       0x00FF,     /* R15 - Left ADC Digital Vol */
+       0x00FF,     /* R16 - Right ADC Digital Vol */
+       0x0000,     /* R17 */
+       0x012C,     /* R18 - EQ1 - low shelf */
+       0x002C,     /* R19 - EQ2 - peak 1 */
+       0x002C,     /* R20 - EQ3 - peak 2 */
+       0x002C,     /* R21 - EQ4 - peak 3 */
+       0x002C,     /* R22 - EQ5 - high shelf */
+       0x0000,     /* R23 */
+       0x0032,     /* R24 - DAC Limiter 1 */
+       0x0000,     /* R25 - DAC Limiter 2 */
+       0x0000,     /* R26 */
+       0x0000,     /* R27 - Notch Filter 1 */
+       0x0000,     /* R28 - Notch Filter 2 */
+       0x0000,     /* R29 - Notch Filter 3 */
+       0x0000,     /* R30 - Notch Filter 4 */
+       0x0000,     /* R31 */
+       0x0038,     /* R32 - ALC control 1 */
+       0x000B,     /* R33 - ALC control 2 */
+       0x0032,     /* R34 - ALC control 3 */
+       0x0000,     /* R35 - Noise Gate */
+       0x0008,     /* R36 - PLL N */
+       0x000C,     /* R37 - PLL K 1 */
+       0x0093,     /* R38 - PLL K 2 */
+       0x00E9,     /* R39 - PLL K 3 */
+       0x0000,     /* R40 */
+       0x0000,     /* R41 - 3D control */
+       0x0000,     /* R42 - OUT4 to ADC */
+       0x0000,     /* R43 - Beep control */
+       0x0033,     /* R44 - Input ctrl */
+       0x0010,     /* R45 - Left INP PGA gain ctrl */
+       0x0010,     /* R46 - Right INP PGA gain ctrl */
+       0x0100,     /* R47 - Left ADC BOOST ctrl */
+       0x0100,     /* R48 - Right ADC BOOST ctrl */
+       0x0002,     /* R49 - Output ctrl */
+       0x0001,     /* R50 - Left mixer ctrl */
+       0x0001,     /* R51 - Right mixer ctrl */
+       0x0039,     /* R52 - LOUT1 (HP) volume ctrl */
+       0x0039,     /* R53 - ROUT1 (HP) volume ctrl */
+       0x0039,     /* R54 - LOUT2 (SPK) volume ctrl */
+       0x0039,     /* R55 - ROUT2 (SPK) volume ctrl */
+       0x0001,     /* R56 - OUT3 mixer ctrl */
+       0x0001,     /* R57 - OUT4 (MONO) mix ctrl */
+       0x0001,     /* R58 */
+       0x0000,     /* R59 */
+       0x0004,     /* R60 - OUTPUT ctrl */
+       0x0000,     /* R61 - BIAS CTRL */
+       0x0180,     /* R62 */
+       0x0000      /* R63 */
+};
+
+/*
+ * latch bit 8 of these registers to ensure instant
+ * volume updates
+ */
+static const int volume_update_regs[] = {
+       WM8985_LEFT_DAC_DIGITAL_VOL,
+       WM8985_RIGHT_DAC_DIGITAL_VOL,
+       WM8985_LEFT_ADC_DIGITAL_VOL,
+       WM8985_RIGHT_ADC_DIGITAL_VOL,
+       WM8985_LOUT2_SPK_VOLUME_CTRL,
+       WM8985_ROUT2_SPK_VOLUME_CTRL,
+       WM8985_LOUT1_HP_VOLUME_CTRL,
+       WM8985_ROUT1_HP_VOLUME_CTRL,
+       WM8985_LEFT_INP_PGA_GAIN_CTRL,
+       WM8985_RIGHT_INP_PGA_GAIN_CTRL
+};
+
+struct wm8985_priv {
+       enum snd_soc_control_type control_type;
+       struct regulator_bulk_data supplies[WM8985_NUM_SUPPLIES];
+       unsigned int sysclk;
+       unsigned int bclk;
+};
+
+static const struct {
+       int div;
+       int ratio;
+} fs_ratios[] = {
+       { 10, 128 },
+       { 15, 192 },
+       { 20, 256 },
+       { 30, 384 },
+       { 40, 512 },
+       { 60, 768 },
+       { 80, 1024 },
+       { 120, 1536 }
+};
+
+static const int srates[] = { 48000, 32000, 24000, 16000, 12000, 8000 };
+
+static const int bclk_divs[] = {
+       1, 2, 4, 8, 16, 32
+};
+
+static int eqmode_get(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_value *ucontrol);
+static int eqmode_put(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_value *ucontrol);
+
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1);
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -12700, 50, 1);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(lim_thresh_tlv, -600, 100, 0);
+static const DECLARE_TLV_DB_SCALE(lim_boost_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(alc_min_tlv, -1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(alc_max_tlv, -675, 600, 0);
+static const DECLARE_TLV_DB_SCALE(alc_tar_tlv, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(pga_vol_tlv, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, -1200, 300, 1);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(aux_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
+static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0);
+
+static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" };
+static const SOC_ENUM_SINGLE_DECL(alc_sel, WM8985_ALC_CONTROL_1, 7,
+                                 alc_sel_text);
+
+static const char *alc_mode_text[] = { "ALC", "Limiter" };
+static const SOC_ENUM_SINGLE_DECL(alc_mode, WM8985_ALC_CONTROL_3, 8,
+                                 alc_mode_text);
+
+static const char *filter_mode_text[] = { "Audio", "Application" };
+static const SOC_ENUM_SINGLE_DECL(filter_mode, WM8985_ADC_CONTROL, 7,
+                                 filter_mode_text);
+
+static const char *eq_bw_text[] = { "Narrow", "Wide" };
+static const char *eqmode_text[] = { "Capture", "Playback" };
+static const SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text);
+
+static const char *eq1_cutoff_text[] = {
+       "80Hz", "105Hz", "135Hz", "175Hz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8985_EQ1_LOW_SHELF, 5,
+                                 eq1_cutoff_text);
+static const char *eq2_cutoff_text[] = {
+       "230Hz", "300Hz", "385Hz", "500Hz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq2_bw, WM8985_EQ2_PEAK_1, 8, eq_bw_text);
+static const SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8985_EQ2_PEAK_1, 5,
+                                 eq2_cutoff_text);
+static const char *eq3_cutoff_text[] = {
+       "650Hz", "850Hz", "1.1kHz", "1.4kHz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq3_bw, WM8985_EQ3_PEAK_2, 8, eq_bw_text);
+static const SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8985_EQ3_PEAK_2, 5,
+                                 eq3_cutoff_text);
+static const char *eq4_cutoff_text[] = {
+       "1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq4_bw, WM8985_EQ4_PEAK_3, 8, eq_bw_text);
+static const SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8985_EQ4_PEAK_3, 5,
+                                 eq4_cutoff_text);
+static const char *eq5_cutoff_text[] = {
+       "5.3kHz", "6.9kHz", "9kHz", "11.7kHz"
+};
+static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8985_EQ5_HIGH_SHELF, 5,
+                                 eq5_cutoff_text);
+
+static const char *speaker_mode_text[] = { "Class A/B", "Class D" };
+static const SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text);
+
+static const char *depth_3d_text[] = {
+       "Off",
+       "6.67%",
+       "13.3%",
+       "20%",
+       "26.7%",
+       "33.3%",
+       "40%",
+       "46.6%",
+       "53.3%",
+       "60%",
+       "66.7%",
+       "73.3%",
+       "80%",
+       "86.7%",
+       "93.3%",
+       "100%"
+};
+static const SOC_ENUM_SINGLE_DECL(depth_3d, WM8985_3D_CONTROL, 0,
+                                 depth_3d_text);
+
+static const struct snd_kcontrol_new wm8985_snd_controls[] = {
+       SOC_SINGLE("Digital Loopback Switch", WM8985_COMPANDING_CONTROL,
+               0, 1, 0),
+
+       SOC_ENUM("ALC Capture Function", alc_sel),
+       SOC_SINGLE_TLV("ALC Capture Max Volume", WM8985_ALC_CONTROL_1,
+               3, 7, 0, alc_max_tlv),
+       SOC_SINGLE_TLV("ALC Capture Min Volume", WM8985_ALC_CONTROL_1,
+               0, 7, 0, alc_min_tlv),
+       SOC_SINGLE_TLV("ALC Capture Target Volume", WM8985_ALC_CONTROL_2,
+               0, 15, 0, alc_tar_tlv),
+       SOC_SINGLE("ALC Capture Attack", WM8985_ALC_CONTROL_3, 0, 10, 0),
+       SOC_SINGLE("ALC Capture Hold", WM8985_ALC_CONTROL_2, 4, 10, 0),
+       SOC_SINGLE("ALC Capture Decay", WM8985_ALC_CONTROL_3, 4, 10, 0),
+       SOC_ENUM("ALC Mode", alc_mode),
+       SOC_SINGLE("ALC Capture NG Switch", WM8985_NOISE_GATE,
+               3, 1, 0),
+       SOC_SINGLE("ALC Capture NG Threshold", WM8985_NOISE_GATE,
+               0, 7, 1),
+
+       SOC_DOUBLE_R_TLV("Capture Volume", WM8985_LEFT_ADC_DIGITAL_VOL,
+               WM8985_RIGHT_ADC_DIGITAL_VOL, 0, 255, 0, adc_tlv),
+       SOC_DOUBLE_R("Capture PGA ZC Switch", WM8985_LEFT_INP_PGA_GAIN_CTRL,
+               WM8985_RIGHT_INP_PGA_GAIN_CTRL, 7, 1, 0),
+       SOC_DOUBLE_R_TLV("Capture PGA Volume", WM8985_LEFT_INP_PGA_GAIN_CTRL,
+               WM8985_RIGHT_INP_PGA_GAIN_CTRL, 0, 63, 0, pga_vol_tlv),
+
+       SOC_DOUBLE_R_TLV("Capture PGA Boost Volume",
+               WM8985_LEFT_ADC_BOOST_CTRL, WM8985_RIGHT_ADC_BOOST_CTRL,
+               8, 1, 0, pga_boost_tlv),
+
+       SOC_DOUBLE("ADC Inversion Switch", WM8985_ADC_CONTROL, 0, 1, 1, 0),
+       SOC_SINGLE("ADC 128x Oversampling Switch", WM8985_ADC_CONTROL, 8, 1, 0),
+
+       SOC_DOUBLE_R_TLV("Playback Volume", WM8985_LEFT_DAC_DIGITAL_VOL,
+               WM8985_RIGHT_DAC_DIGITAL_VOL, 0, 255, 0, dac_tlv),
+
+       SOC_SINGLE("DAC Playback Limiter Switch", WM8985_DAC_LIMITER_1, 8, 1, 0),
+       SOC_SINGLE("DAC Playback Limiter Decay", WM8985_DAC_LIMITER_1, 4, 10, 0),
+       SOC_SINGLE("DAC Playback Limiter Attack", WM8985_DAC_LIMITER_1, 0, 11, 0),
+       SOC_SINGLE_TLV("DAC Playback Limiter Threshold", WM8985_DAC_LIMITER_2,
+               4, 7, 1, lim_thresh_tlv),
+       SOC_SINGLE_TLV("DAC Playback Limiter Boost Volume", WM8985_DAC_LIMITER_2,
+               0, 12, 0, lim_boost_tlv),
+       SOC_DOUBLE("DAC Inversion Switch", WM8985_DAC_CONTROL, 0, 1, 1, 0),
+       SOC_SINGLE("DAC Auto Mute Switch", WM8985_DAC_CONTROL, 2, 1, 0),
+       SOC_SINGLE("DAC 128x Oversampling Switch", WM8985_DAC_CONTROL, 3, 1, 0),
+
+       SOC_DOUBLE_R_TLV("Headphone Playback Volume", WM8985_LOUT1_HP_VOLUME_CTRL,
+               WM8985_ROUT1_HP_VOLUME_CTRL, 0, 63, 0, out_tlv),
+       SOC_DOUBLE_R("Headphone Playback ZC Switch", WM8985_LOUT1_HP_VOLUME_CTRL,
+               WM8985_ROUT1_HP_VOLUME_CTRL, 7, 1, 0),
+       SOC_DOUBLE_R("Headphone Switch", WM8985_LOUT1_HP_VOLUME_CTRL,
+               WM8985_ROUT1_HP_VOLUME_CTRL, 6, 1, 1),
+
+       SOC_DOUBLE_R_TLV("Speaker Playback Volume", WM8985_LOUT2_SPK_VOLUME_CTRL,
+               WM8985_ROUT2_SPK_VOLUME_CTRL, 0, 63, 0, out_tlv),
+       SOC_DOUBLE_R("Speaker Playback ZC Switch", WM8985_LOUT2_SPK_VOLUME_CTRL,
+               WM8985_ROUT2_SPK_VOLUME_CTRL, 7, 1, 0),
+       SOC_DOUBLE_R("Speaker Switch", WM8985_LOUT2_SPK_VOLUME_CTRL,
+               WM8985_ROUT2_SPK_VOLUME_CTRL, 6, 1, 1),
+
+       SOC_SINGLE("High Pass Filter Switch", WM8985_ADC_CONTROL, 8, 1, 0),
+       SOC_ENUM("High Pass Filter Mode", filter_mode),
+       SOC_SINGLE("High Pass Filter Cutoff", WM8985_ADC_CONTROL, 4, 7, 0),
+
+       SOC_DOUBLE_R_TLV("Aux Bypass Volume",
+               WM8985_LEFT_MIXER_CTRL, WM8985_RIGHT_MIXER_CTRL, 6, 7, 0,
+               aux_tlv),
+
+       SOC_DOUBLE_R_TLV("Input PGA Bypass Volume",
+               WM8985_LEFT_MIXER_CTRL, WM8985_RIGHT_MIXER_CTRL, 2, 7, 0,
+               bypass_tlv),
+
+       SOC_ENUM_EXT("Equalizer Function", eqmode, eqmode_get, eqmode_put),
+       SOC_ENUM("EQ1 Cutoff", eq1_cutoff),
+       SOC_SINGLE_TLV("EQ1 Volume", WM8985_EQ1_LOW_SHELF,  0, 24, 1, eq_tlv),
+       SOC_ENUM("EQ2 Bandwith", eq2_bw),
+       SOC_ENUM("EQ2 Cutoff", eq2_cutoff),
+       SOC_SINGLE_TLV("EQ2 Volume", WM8985_EQ2_PEAK_1, 0, 24, 1, eq_tlv),
+       SOC_ENUM("EQ3 Bandwith", eq3_bw),
+       SOC_ENUM("EQ3 Cutoff", eq3_cutoff),
+       SOC_SINGLE_TLV("EQ3 Volume", WM8985_EQ3_PEAK_2, 0, 24, 1, eq_tlv),
+       SOC_ENUM("EQ4 Bandwith", eq4_bw),
+       SOC_ENUM("EQ4 Cutoff", eq4_cutoff),
+       SOC_SINGLE_TLV("EQ4 Volume", WM8985_EQ4_PEAK_3, 0, 24, 1, eq_tlv),
+       SOC_ENUM("EQ5 Cutoff", eq5_cutoff),
+       SOC_SINGLE_TLV("EQ5 Volume", WM8985_EQ5_HIGH_SHELF, 0, 24, 1, eq_tlv),
+
+       SOC_ENUM("3D Depth", depth_3d),
+
+       SOC_ENUM("Speaker Mode", speaker_mode)
+};
+
+static const struct snd_kcontrol_new left_out_mixer[] = {
+       SOC_DAPM_SINGLE("Line Switch", WM8985_LEFT_MIXER_CTRL, 1, 1, 0),
+       SOC_DAPM_SINGLE("Aux Switch", WM8985_LEFT_MIXER_CTRL, 5, 1, 0),
+       SOC_DAPM_SINGLE("PCM Switch", WM8985_LEFT_MIXER_CTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_out_mixer[] = {
+       SOC_DAPM_SINGLE("Line Switch", WM8985_RIGHT_MIXER_CTRL, 1, 1, 0),
+       SOC_DAPM_SINGLE("Aux Switch", WM8985_RIGHT_MIXER_CTRL, 5, 1, 0),
+       SOC_DAPM_SINGLE("PCM Switch", WM8985_RIGHT_MIXER_CTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_input_mixer[] = {
+       SOC_DAPM_SINGLE("L2 Switch", WM8985_INPUT_CTRL, 2, 1, 0),
+       SOC_DAPM_SINGLE("MicN Switch", WM8985_INPUT_CTRL, 1, 1, 0),
+       SOC_DAPM_SINGLE("MicP Switch", WM8985_INPUT_CTRL, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_input_mixer[] = {
+       SOC_DAPM_SINGLE("R2 Switch", WM8985_INPUT_CTRL, 6, 1, 0),
+       SOC_DAPM_SINGLE("MicN Switch", WM8985_INPUT_CTRL, 5, 1, 0),
+       SOC_DAPM_SINGLE("MicP Switch", WM8985_INPUT_CTRL, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new left_boost_mixer[] = {
+       SOC_DAPM_SINGLE_TLV("L2 Volume", WM8985_LEFT_ADC_BOOST_CTRL,
+               4, 7, 0, boost_tlv),
+       SOC_DAPM_SINGLE_TLV("AUXL Volume", WM8985_LEFT_ADC_BOOST_CTRL,
+               0, 7, 0, boost_tlv)
+};
+
+static const struct snd_kcontrol_new right_boost_mixer[] = {
+       SOC_DAPM_SINGLE_TLV("R2 Volume", WM8985_RIGHT_ADC_BOOST_CTRL,
+               4, 7, 0, boost_tlv),
+       SOC_DAPM_SINGLE_TLV("AUXR Volume", WM8985_RIGHT_ADC_BOOST_CTRL,
+               0, 7, 0, boost_tlv)
+};
+
+static const struct snd_soc_dapm_widget wm8985_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8985_POWER_MANAGEMENT_3,
+               0, 0),
+       SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8985_POWER_MANAGEMENT_3,
+               1, 0),
+       SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8985_POWER_MANAGEMENT_2,
+               0, 0),
+       SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8985_POWER_MANAGEMENT_2,
+               1, 0),
+
+       SND_SOC_DAPM_MIXER("Left Output Mixer", WM8985_POWER_MANAGEMENT_3,
+               2, 0, left_out_mixer, ARRAY_SIZE(left_out_mixer)),
+       SND_SOC_DAPM_MIXER("Right Output Mixer", WM8985_POWER_MANAGEMENT_3,
+               3, 0, right_out_mixer, ARRAY_SIZE(right_out_mixer)),
+
+       SND_SOC_DAPM_MIXER("Left Input Mixer", WM8985_POWER_MANAGEMENT_2,
+               2, 0, left_input_mixer, ARRAY_SIZE(left_input_mixer)),
+       SND_SOC_DAPM_MIXER("Right Input Mixer", WM8985_POWER_MANAGEMENT_2,
+               3, 0, right_input_mixer, ARRAY_SIZE(right_input_mixer)),
+
+       SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8985_POWER_MANAGEMENT_2,
+               4, 0, left_boost_mixer, ARRAY_SIZE(left_boost_mixer)),
+       SND_SOC_DAPM_MIXER("Right Boost Mixer", WM8985_POWER_MANAGEMENT_2,
+               5, 0, right_boost_mixer, ARRAY_SIZE(right_boost_mixer)),
+
+       SND_SOC_DAPM_PGA("Left Capture PGA", WM8985_LEFT_INP_PGA_GAIN_CTRL,
+               6, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Capture PGA", WM8985_RIGHT_INP_PGA_GAIN_CTRL,
+               6, 1, NULL, 0),
+
+       SND_SOC_DAPM_PGA("Left Headphone Out", WM8985_POWER_MANAGEMENT_2,
+               7, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Headphone Out", WM8985_POWER_MANAGEMENT_2,
+               8, 0, NULL, 0),
+
+       SND_SOC_DAPM_PGA("Left Speaker Out", WM8985_POWER_MANAGEMENT_3,
+               5, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Right Speaker Out", WM8985_POWER_MANAGEMENT_3,
+               6, 0, NULL, 0),
+
+       SND_SOC_DAPM_MICBIAS("Mic Bias", WM8985_POWER_MANAGEMENT_1, 4, 0),
+
+       SND_SOC_DAPM_INPUT("LIN"),
+       SND_SOC_DAPM_INPUT("LIP"),
+       SND_SOC_DAPM_INPUT("RIN"),
+       SND_SOC_DAPM_INPUT("RIP"),
+       SND_SOC_DAPM_INPUT("AUXL"),
+       SND_SOC_DAPM_INPUT("AUXR"),
+       SND_SOC_DAPM_INPUT("L2"),
+       SND_SOC_DAPM_INPUT("R2"),
+       SND_SOC_DAPM_OUTPUT("HPL"),
+       SND_SOC_DAPM_OUTPUT("HPR"),
+       SND_SOC_DAPM_OUTPUT("SPKL"),
+       SND_SOC_DAPM_OUTPUT("SPKR")
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+       { "Right Output Mixer", "PCM Switch", "Right DAC" },
+       { "Right Output Mixer", "Aux Switch", "AUXR" },
+       { "Right Output Mixer", "Line Switch", "Right Boost Mixer" },
+
+       { "Left Output Mixer", "PCM Switch", "Left DAC" },
+       { "Left Output Mixer", "Aux Switch", "AUXL" },
+       { "Left Output Mixer", "Line Switch", "Left Boost Mixer" },
+
+       { "Right Headphone Out", NULL, "Right Output Mixer" },
+       { "HPR", NULL, "Right Headphone Out" },
+
+       { "Left Headphone Out", NULL, "Left Output Mixer" },
+       { "HPL", NULL, "Left Headphone Out" },
+
+       { "Right Speaker Out", NULL, "Right Output Mixer" },
+       { "SPKR", NULL, "Right Speaker Out" },
+
+       { "Left Speaker Out", NULL, "Left Output Mixer" },
+       { "SPKL", NULL, "Left Speaker Out" },
+
+       { "Right ADC", NULL, "Right Boost Mixer" },
+
+       { "Right Boost Mixer", "AUXR Volume", "AUXR" },
+       { "Right Boost Mixer", NULL, "Right Capture PGA" },
+       { "Right Boost Mixer", "R2 Volume", "R2" },
+
+       { "Left ADC", NULL, "Left Boost Mixer" },
+
+       { "Left Boost Mixer", "AUXL Volume", "AUXL" },
+       { "Left Boost Mixer", NULL, "Left Capture PGA" },
+       { "Left Boost Mixer", "L2 Volume", "L2" },
+
+       { "Right Capture PGA", NULL, "Right Input Mixer" },
+       { "Left Capture PGA", NULL, "Left Input Mixer" },
+
+       { "Right Input Mixer", "R2 Switch", "R2" },
+       { "Right Input Mixer", "MicN Switch", "RIN" },
+       { "Right Input Mixer", "MicP Switch", "RIP" },
+
+       { "Left Input Mixer", "L2 Switch", "L2" },
+       { "Left Input Mixer", "MicN Switch", "LIN" },
+       { "Left Input Mixer", "MicP Switch", "LIP" },
+};
+
+static int eqmode_get(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg;
+
+       reg = snd_soc_read(codec, WM8985_EQ1_LOW_SHELF);
+       if (reg & WM8985_EQ3DMODE)
+               ucontrol->value.integer.value[0] = 1;
+       else
+               ucontrol->value.integer.value[0] = 0;
+
+       return 0;
+}
+
+static int eqmode_put(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int regpwr2, regpwr3;
+       unsigned int reg_eq;
+
+       if (ucontrol->value.integer.value[0] != 0
+                       && ucontrol->value.integer.value[0] != 1)
+               return -EINVAL;
+
+       reg_eq = snd_soc_read(codec, WM8985_EQ1_LOW_SHELF);
+       switch ((reg_eq & WM8985_EQ3DMODE) >> WM8985_EQ3DMODE_SHIFT) {
+       case 0:
+               if (!ucontrol->value.integer.value[0])
+                       return 0;
+               break;
+       case 1:
+               if (ucontrol->value.integer.value[0])
+                       return 0;
+               break;
+       }
+
+       regpwr2 = snd_soc_read(codec, WM8985_POWER_MANAGEMENT_2);
+       regpwr3 = snd_soc_read(codec, WM8985_POWER_MANAGEMENT_3);
+       /* disable the DACs and ADCs */
+       snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_2,
+                           WM8985_ADCENR_MASK | WM8985_ADCENL_MASK, 0);
+       snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_3,
+                           WM8985_DACENR_MASK | WM8985_DACENL_MASK, 0);
+       snd_soc_update_bits(codec, WM8985_ADDITIONAL_CONTROL,
+                           WM8985_M128ENB_MASK, WM8985_M128ENB);
+       /* set the desired eqmode */
+       snd_soc_update_bits(codec, WM8985_EQ1_LOW_SHELF,
+                           WM8985_EQ3DMODE_MASK,
+                           ucontrol->value.integer.value[0]
+                           << WM8985_EQ3DMODE_SHIFT);
+       /* restore DAC/ADC configuration */
+       snd_soc_write(codec, WM8985_POWER_MANAGEMENT_2, regpwr2);
+       snd_soc_write(codec, WM8985_POWER_MANAGEMENT_3, regpwr3);
+       return 0;
+}
+
+static int wm8985_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, wm8985_dapm_widgets,
+                                 ARRAY_SIZE(wm8985_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, audio_map,
+                               ARRAY_SIZE(audio_map));
+       return 0;
+}
+
+static int wm8985_reset(struct snd_soc_codec *codec)
+{
+       return snd_soc_write(codec, WM8985_SOFTWARE_RESET, 0x0);
+}
+
+static int wm8985_dac_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+
+       return snd_soc_update_bits(codec, WM8985_DAC_CONTROL,
+                                  WM8985_SOFTMUTE_MASK,
+                                  !!mute << WM8985_SOFTMUTE_SHIFT);
+}
+
+static int wm8985_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec;
+       u16 format, master, bcp, lrp;
+
+       codec = dai->codec;
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               format = 0x2;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               format = 0x0;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               format = 0x1;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               format = 0x3;
+               break;
+       default:
+               dev_err(dai->dev, "Unknown dai format\n");
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
+                           WM8985_FMT_MASK, format << WM8985_FMT_SHIFT);
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               master = 1;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               master = 0;
+               break;
+       default:
+               dev_err(dai->dev, "Unknown master/slave configuration\n");
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+                           WM8985_MS_MASK, master << WM8985_MS_SHIFT);
+
+       /* frame inversion is not valid for dsp modes */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+       case SND_SOC_DAIFMT_DSP_B:
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+               case SND_SOC_DAIFMT_IB_IF:
+               case SND_SOC_DAIFMT_NB_IF:
+                       return -EINVAL;
+               default:
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+
+       bcp = lrp = 0;
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               bcp = lrp = 1;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               bcp = 1;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               lrp = 1;
+               break;
+       default:
+               dev_err(dai->dev, "Unknown polarity configuration\n");
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
+                           WM8985_LRP_MASK, lrp << WM8985_LRP_SHIFT);
+       snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
+                           WM8985_BCP_MASK, bcp << WM8985_BCP_SHIFT);
+       return 0;
+}
+
+static int wm8985_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       int i;
+       struct snd_soc_codec *codec;
+       struct wm8985_priv *wm8985;
+       u16 blen, srate_idx;
+       unsigned int tmp;
+       int srate_best;
+
+       codec = dai->codec;
+       wm8985 = snd_soc_codec_get_drvdata(codec);
+
+       wm8985->bclk = snd_soc_params_to_bclk(params);
+       if ((int)wm8985->bclk < 0)
+               return wm8985->bclk;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               blen = 0x0;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               blen = 0x1;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               blen = 0x2;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               blen = 0x3;
+               break;
+       default:
+               dev_err(dai->dev, "Unsupported word length %u\n",
+                       params_format(params));
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, WM8985_AUDIO_INTERFACE,
+                           WM8985_WL_MASK, blen << WM8985_WL_SHIFT);
+
+       /*
+        * match to the nearest possible sample rate and rely
+        * on the array index to configure the SR register
+        */
+       srate_idx = 0;
+       srate_best = abs(srates[0] - params_rate(params));
+       for (i = 1; i < ARRAY_SIZE(srates); ++i) {
+               if (abs(srates[i] - params_rate(params)) >= srate_best)
+                       continue;
+               srate_idx = i;
+               srate_best = abs(srates[i] - params_rate(params));
+       }
+
+       dev_dbg(dai->dev, "Selected SRATE = %d\n", srates[srate_idx]);
+       snd_soc_update_bits(codec, WM8985_ADDITIONAL_CONTROL,
+                           WM8985_SR_MASK, srate_idx << WM8985_SR_SHIFT);
+
+       dev_dbg(dai->dev, "Target BCLK = %uHz\n", wm8985->bclk);
+       dev_dbg(dai->dev, "SYSCLK = %uHz\n", wm8985->sysclk);
+
+       for (i = 0; i < ARRAY_SIZE(fs_ratios); ++i) {
+               if (wm8985->sysclk / params_rate(params)
+                               == fs_ratios[i].ratio)
+                       break;
+       }
+
+       if (i == ARRAY_SIZE(fs_ratios)) {
+               dev_err(dai->dev, "Unable to configure MCLK ratio %u/%u\n",
+                       wm8985->sysclk, params_rate(params));
+               return -EINVAL;
+       }
+
+       dev_dbg(dai->dev, "MCLK ratio = %dfs\n", fs_ratios[i].ratio);
+       snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+                           WM8985_MCLKDIV_MASK, i << WM8985_MCLKDIV_SHIFT);
+
+       /* select the appropriate bclk divider */
+       tmp = (wm8985->sysclk / fs_ratios[i].div) * 10;
+       for (i = 0; i < ARRAY_SIZE(bclk_divs); ++i) {
+               if (wm8985->bclk == tmp / bclk_divs[i])
+                       break;
+       }
+
+       if (i == ARRAY_SIZE(bclk_divs)) {
+               dev_err(dai->dev, "No matching BCLK divider found\n");
+               return -EINVAL;
+       }
+
+       dev_dbg(dai->dev, "BCLK div = %d\n", i);
+       snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+                           WM8985_BCLKDIV_MASK, i << WM8985_BCLKDIV_SHIFT);
+       return 0;
+}
+
+struct pll_div {
+       u32 div2:1;
+       u32 n:4;
+       u32 k:24;
+};
+
+#define FIXED_PLL_SIZE ((1ULL << 24) * 10)
+static int pll_factors(struct pll_div *pll_div, unsigned int target,
+                      unsigned int source)
+{
+       u64 Kpart;
+       unsigned long int K, Ndiv, Nmod;
+
+       pll_div->div2 = 0;
+       Ndiv = target / source;
+       if (Ndiv < 6) {
+               source >>= 1;
+               pll_div->div2 = 1;
+               Ndiv = target / source;
+       }
+
+       if (Ndiv < 6 || Ndiv > 12) {
+               printk(KERN_ERR "%s: WM8985 N value is not within"
+                      " the recommended range: %lu\n", __func__, Ndiv);
+               return -EINVAL;
+       }
+       pll_div->n = Ndiv;
+
+       Nmod = target % source;
+       Kpart = FIXED_PLL_SIZE * (u64)Nmod;
+
+       do_div(Kpart, source);
+
+       K = Kpart & 0xffffffff;
+       if ((K % 10) >= 5)
+               K += 5;
+       K /= 10;
+       pll_div->k = K;
+
+       return 0;
+}
+
+static int wm8985_set_pll(struct snd_soc_dai *dai, int pll_id,
+                         int source, unsigned int freq_in,
+                         unsigned int freq_out)
+{
+       int ret;
+       struct snd_soc_codec *codec;
+       struct pll_div pll_div;
+
+       codec = dai->codec;
+       if (freq_in && freq_out) {
+               ret = pll_factors(&pll_div, freq_out * 4 * 2, freq_in);
+               if (ret)
+                       return ret;
+       }
+
+       /* disable the PLL before reprogramming it */
+       snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+                           WM8985_PLLEN_MASK, 0);
+       
+       if (!freq_in || !freq_out)
+               return 0;
+
+       /* set PLLN and PRESCALE */
+       snd_soc_write(codec, WM8985_PLL_N,
+                     (pll_div.div2 << WM8985_PLL_PRESCALE_SHIFT)
+                     | pll_div.n);
+       /* set PLLK */
+       snd_soc_write(codec, WM8985_PLL_K_3, pll_div.k & 0x1ff);
+       snd_soc_write(codec, WM8985_PLL_K_2, (pll_div.k >> 9) & 0x1ff);
+       snd_soc_write(codec, WM8985_PLL_K_1, (pll_div.k >> 18));
+       /* set the source of the clock to be the PLL */
+       snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+                           WM8985_CLKSEL_MASK, WM8985_CLKSEL);
+       /* enable the PLL */
+       snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+                           WM8985_PLLEN_MASK, WM8985_PLLEN);
+       return 0;
+}
+
+static int wm8985_set_sysclk(struct snd_soc_dai *dai,
+                            int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec;
+       struct wm8985_priv *wm8985;
+
+       codec = dai->codec;
+       wm8985 = snd_soc_codec_get_drvdata(codec);
+
+       switch (clk_id) {
+       case WM8985_CLKSRC_MCLK:
+               snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+                                   WM8985_CLKSEL_MASK, 0);
+               snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+                                   WM8985_PLLEN_MASK, 0);
+               break;
+       case WM8985_CLKSRC_PLL:
+               snd_soc_update_bits(codec, WM8985_CLOCK_GEN_CONTROL,
+                                   WM8985_CLKSEL_MASK, WM8985_CLKSEL);
+               break;
+       default:
+               dev_err(dai->dev, "Unknown clock source %d\n", clk_id);
+               return -EINVAL;
+       }
+
+       wm8985->sysclk = freq;
+       return 0;
+}
+
+static void wm8985_sync_cache(struct snd_soc_codec *codec)
+{
+       short i;
+       u16 *cache;
+
+       if (!codec->cache_sync)
+               return;
+       codec->cache_only = 0;
+       /* restore cache */
+       cache = codec->reg_cache;
+       for (i = 0; i < codec->driver->reg_cache_size; i++) {
+               if (i == WM8985_SOFTWARE_RESET
+                               || cache[i] == wm8985_reg_defs[i])
+                       continue;
+               snd_soc_write(codec, i, cache[i]);
+       }
+       codec->cache_sync = 0;
+}
+
+static int wm8985_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       int ret;
+       struct wm8985_priv *wm8985;
+
+       wm8985 = snd_soc_codec_get_drvdata(codec);
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+       case SND_SOC_BIAS_PREPARE:
+               /* VMID at 75k */
+               snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+                                   WM8985_VMIDSEL_MASK,
+                                   1 << WM8985_VMIDSEL_SHIFT);
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->bias_level == SND_SOC_BIAS_OFF) {
+                       ret = regulator_bulk_enable(ARRAY_SIZE(wm8985->supplies),
+                                                   wm8985->supplies);
+                       if (ret) {
+                               dev_err(codec->dev,
+                                       "Failed to enable supplies: %d\n",
+                                       ret);
+                               return ret;
+                       }
+
+                       wm8985_sync_cache(codec);
+
+                       /* enable anti-pop features */
+                       snd_soc_update_bits(codec, WM8985_OUT4_TO_ADC,
+                                           WM8985_POBCTRL_MASK,
+                                           WM8985_POBCTRL);
+                       /* enable thermal shutdown */
+                       snd_soc_update_bits(codec, WM8985_OUTPUT_CTRL0,
+                                           WM8985_TSDEN_MASK, WM8985_TSDEN);
+                       snd_soc_update_bits(codec, WM8985_OUTPUT_CTRL0,
+                                           WM8985_TSOPCTRL_MASK,
+                                           WM8985_TSOPCTRL);
+                       /* enable BIASEN */
+                       snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+                                           WM8985_BIASEN_MASK, WM8985_BIASEN);
+                       /* VMID at 75k */
+                       snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+                                           WM8985_VMIDSEL_MASK,
+                                           1 << WM8985_VMIDSEL_SHIFT);
+                       msleep(500);
+                       /* disable anti-pop features */
+                       snd_soc_update_bits(codec, WM8985_OUT4_TO_ADC,
+                                           WM8985_POBCTRL_MASK, 0);
+               }
+               /* VMID at 300k */
+               snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+                                   WM8985_VMIDSEL_MASK,
+                                   2 << WM8985_VMIDSEL_SHIFT);
+               break;
+       case SND_SOC_BIAS_OFF:
+               /* disable thermal shutdown */
+               snd_soc_update_bits(codec, WM8985_OUTPUT_CTRL0,
+                                   WM8985_TSOPCTRL_MASK, 0);
+               snd_soc_update_bits(codec, WM8985_OUTPUT_CTRL0,
+                                   WM8985_TSDEN_MASK, 0);
+               /* disable VMIDSEL and BIASEN */
+               snd_soc_update_bits(codec, WM8985_POWER_MANAGEMENT_1,
+                                   WM8985_VMIDSEL_MASK | WM8985_BIASEN_MASK,
+                                   0);
+               snd_soc_write(codec, WM8985_POWER_MANAGEMENT_1, 0);
+               snd_soc_write(codec, WM8985_POWER_MANAGEMENT_2, 0);
+               snd_soc_write(codec, WM8985_POWER_MANAGEMENT_3, 0);
+
+               codec->cache_sync = 1;
+
+               regulator_bulk_disable(ARRAY_SIZE(wm8985->supplies),
+                                      wm8985->supplies);
+               break;
+       }
+
+       codec->bias_level = level;
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int wm8985_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+       wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int wm8985_resume(struct snd_soc_codec *codec)
+{
+       wm8985_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       return 0;
+}
+#else
+#define wm8985_suspend NULL
+#define wm8985_resume NULL
+#endif
+
+static int wm8985_remove(struct snd_soc_codec *codec)
+{
+       struct wm8985_priv *wm8985;
+
+       wm8985 = snd_soc_codec_get_drvdata(codec);
+       wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       regulator_bulk_free(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);
+       return 0;
+}
+
+static int wm8985_probe(struct snd_soc_codec *codec)
+{
+       size_t i;
+       struct wm8985_priv *wm8985;
+       int ret;
+       u16 *cache;
+
+       wm8985 = snd_soc_codec_get_drvdata(codec);
+
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8985->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(wm8985->supplies); i++)
+               wm8985->supplies[i].supply = wm8985_supply_names[i];
+
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8985->supplies),
+                                wm8985->supplies);
+       if (ret) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8985->supplies),
+                                   wm8985->supplies);
+       if (ret) {
+               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_reg_get;
+       }
+
+       ret = wm8985_reset(codec);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+               goto err_reg_enable;
+       }
+
+       cache = codec->reg_cache;
+       /* latch volume update bits */
+       for (i = 0; i < ARRAY_SIZE(volume_update_regs); ++i)
+               cache[volume_update_regs[i]] |= 0x100;
+       /* enable BIASCUT */
+       cache[WM8985_BIAS_CTRL] |= WM8985_BIASCUT;
+       codec->cache_sync = 1;
+
+       snd_soc_add_controls(codec, wm8985_snd_controls,
+                            ARRAY_SIZE(wm8985_snd_controls));
+       wm8985_add_widgets(codec);
+
+       wm8985_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       return 0;
+
+err_reg_enable:
+       regulator_bulk_disable(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);
+err_reg_get:
+       regulator_bulk_free(ARRAY_SIZE(wm8985->supplies), wm8985->supplies);
+       return ret;
+}
+
+static struct snd_soc_dai_ops wm8985_dai_ops = {
+       .digital_mute = wm8985_dac_mute,
+       .hw_params = wm8985_hw_params,
+       .set_fmt = wm8985_set_fmt,
+       .set_sysclk = wm8985_set_sysclk,
+       .set_pll = wm8985_set_pll
+};
+
+#define WM8985_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_driver wm8985_dai = {
+       .name = "wm8985-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = WM8985_FORMATS,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = WM8985_FORMATS,
+       },
+       .ops = &wm8985_dai_ops,
+       .symmetric_rates = 1
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8985 = {
+       .probe = wm8985_probe,
+       .remove = wm8985_remove,
+       .suspend = wm8985_suspend,
+       .resume = wm8985_resume,
+       .set_bias_level = wm8985_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8985_reg_defs),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8985_reg_defs
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8985_spi_probe(struct spi_device *spi)
+{
+       struct wm8985_priv *wm8985;
+       int ret;
+
+       wm8985 = kzalloc(sizeof *wm8985, GFP_KERNEL);
+       if (!wm8985)
+               return -ENOMEM;
+
+       wm8985->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8985);
+
+       ret = snd_soc_register_codec(&spi->dev,
+                                    &soc_codec_dev_wm8985, &wm8985_dai, 1);
+       if (ret < 0)
+               kfree(wm8985);
+       return ret;
+}
+
+static int __devexit wm8985_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
+       return 0;
+}
+
+static struct spi_driver wm8985_spi_driver = {
+       .driver = {
+               .name = "wm8985",
+               .owner = THIS_MODULE,
+       },
+       .probe = wm8985_spi_probe,
+       .remove = __devexit_p(wm8985_spi_remove)
+};
+#endif
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8985_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct wm8985_priv *wm8985;
+       int ret;
+
+       wm8985 = kzalloc(sizeof *wm8985, GFP_KERNEL);
+       if (!wm8985)
+               return -ENOMEM;
+
+       wm8985->control_type = SND_SOC_I2C;
+       i2c_set_clientdata(i2c, wm8985);
+
+       ret = snd_soc_register_codec(&i2c->dev,
+                                    &soc_codec_dev_wm8985, &wm8985_dai, 1);
+       if (ret < 0)
+               kfree(wm8985);
+       return ret;
+}
+
+static __devexit int wm8985_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 wm8985_i2c_id[] = {
+       { "wm8985", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8985_i2c_id);
+
+static struct i2c_driver wm8985_i2c_driver = {
+       .driver = {
+               .name = "wm8985",
+               .owner = THIS_MODULE,
+       },
+       .probe = wm8985_i2c_probe,
+       .remove = __devexit_p(wm8985_i2c_remove),
+       .id_table = wm8985_i2c_id
+};
+#endif
+
+static int __init wm8985_modinit(void)
+{
+       int ret = 0;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       ret = i2c_add_driver(&wm8985_i2c_driver);
+       if (ret) {
+               printk(KERN_ERR "Failed to register wm8985 I2C driver: %d\n",
+                      ret);
+       }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       ret = spi_register_driver(&wm8985_spi_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register wm8985 SPI driver: %d\n",
+                      ret);
+       }
+#endif
+       return ret;
+}
+module_init(wm8985_modinit);
+
+static void __exit wm8985_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+       i2c_del_driver(&wm8985_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+       spi_unregister_driver(&wm8985_spi_driver);
+#endif
+}
+module_exit(wm8985_exit);
+
+MODULE_DESCRIPTION("ASoC WM8985 driver");
+MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8985.h b/sound/soc/codecs/wm8985.h
new file mode 100644 (file)
index 0000000..2e71ff5
--- /dev/null
@@ -0,0 +1,1045 @@
+/*
+ * wm8985.h  --  WM8985 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 _WM8985_H
+#define _WM8985_H
+
+#define WM8985_SOFTWARE_RESET                   0x00
+#define WM8985_POWER_MANAGEMENT_1               0x01
+#define WM8985_POWER_MANAGEMENT_2               0x02
+#define WM8985_POWER_MANAGEMENT_3               0x03
+#define WM8985_AUDIO_INTERFACE                  0x04
+#define WM8985_COMPANDING_CONTROL               0x05
+#define WM8985_CLOCK_GEN_CONTROL                0x06
+#define WM8985_ADDITIONAL_CONTROL               0x07
+#define WM8985_GPIO_CONTROL                     0x08
+#define WM8985_JACK_DETECT_CONTROL_1            0x09
+#define WM8985_DAC_CONTROL                      0x0A
+#define WM8985_LEFT_DAC_DIGITAL_VOL             0x0B
+#define WM8985_RIGHT_DAC_DIGITAL_VOL            0x0C
+#define WM8985_JACK_DETECT_CONTROL_2            0x0D
+#define WM8985_ADC_CONTROL                      0x0E
+#define WM8985_LEFT_ADC_DIGITAL_VOL             0x0F
+#define WM8985_RIGHT_ADC_DIGITAL_VOL            0x10
+#define WM8985_EQ1_LOW_SHELF                    0x12
+#define WM8985_EQ2_PEAK_1                       0x13
+#define WM8985_EQ3_PEAK_2                       0x14
+#define WM8985_EQ4_PEAK_3                       0x15
+#define WM8985_EQ5_HIGH_SHELF                   0x16
+#define WM8985_DAC_LIMITER_1                    0x18
+#define WM8985_DAC_LIMITER_2                    0x19
+#define WM8985_NOTCH_FILTER_1                   0x1B
+#define WM8985_NOTCH_FILTER_2                   0x1C
+#define WM8985_NOTCH_FILTER_3                   0x1D
+#define WM8985_NOTCH_FILTER_4                   0x1E
+#define WM8985_ALC_CONTROL_1                    0x20
+#define WM8985_ALC_CONTROL_2                    0x21
+#define WM8985_ALC_CONTROL_3                    0x22
+#define WM8985_NOISE_GATE                       0x23
+#define WM8985_PLL_N                            0x24
+#define WM8985_PLL_K_1                          0x25
+#define WM8985_PLL_K_2                          0x26
+#define WM8985_PLL_K_3                          0x27
+#define WM8985_3D_CONTROL                       0x29
+#define WM8985_OUT4_TO_ADC                      0x2A
+#define WM8985_BEEP_CONTROL                     0x2B
+#define WM8985_INPUT_CTRL                       0x2C
+#define WM8985_LEFT_INP_PGA_GAIN_CTRL           0x2D
+#define WM8985_RIGHT_INP_PGA_GAIN_CTRL          0x2E
+#define WM8985_LEFT_ADC_BOOST_CTRL              0x2F
+#define WM8985_RIGHT_ADC_BOOST_CTRL             0x30
+#define WM8985_OUTPUT_CTRL0                     0x31
+#define WM8985_LEFT_MIXER_CTRL                  0x32
+#define WM8985_RIGHT_MIXER_CTRL                 0x33
+#define WM8985_LOUT1_HP_VOLUME_CTRL             0x34
+#define WM8985_ROUT1_HP_VOLUME_CTRL             0x35
+#define WM8985_LOUT2_SPK_VOLUME_CTRL            0x36
+#define WM8985_ROUT2_SPK_VOLUME_CTRL            0x37
+#define WM8985_OUT3_MIXER_CTRL                  0x38
+#define WM8985_OUT4_MONO_MIX_CTRL               0x39
+#define WM8985_OUTPUT_CTRL1                     0x3C
+#define WM8985_BIAS_CTRL                        0x3D
+
+#define WM8985_REGISTER_COUNT                   59
+#define WM8985_MAX_REGISTER                     0x3F
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM8985_SOFTWARE_RESET_MASK              0x01FF  /* SOFTWARE_RESET - [8:0] */
+#define WM8985_SOFTWARE_RESET_SHIFT                  0  /* SOFTWARE_RESET - [8:0] */
+#define WM8985_SOFTWARE_RESET_WIDTH                  9  /* SOFTWARE_RESET - [8:0] */
+
+/*
+ * R1 (0x01) - Power management 1
+ */
+#define WM8985_OUT4MIXEN                        0x0080  /* OUT4MIXEN */
+#define WM8985_OUT4MIXEN_MASK                   0x0080  /* OUT4MIXEN */
+#define WM8985_OUT4MIXEN_SHIFT                       7  /* OUT4MIXEN */
+#define WM8985_OUT4MIXEN_WIDTH                       1  /* OUT4MIXEN */
+#define WM8985_OUT3MIXEN                        0x0040  /* OUT3MIXEN */
+#define WM8985_OUT3MIXEN_MASK                   0x0040  /* OUT3MIXEN */
+#define WM8985_OUT3MIXEN_SHIFT                       6  /* OUT3MIXEN */
+#define WM8985_OUT3MIXEN_WIDTH                       1  /* OUT3MIXEN */
+#define WM8985_PLLEN                            0x0020  /* PLLEN */
+#define WM8985_PLLEN_MASK                       0x0020  /* PLLEN */
+#define WM8985_PLLEN_SHIFT                           5  /* PLLEN */
+#define WM8985_PLLEN_WIDTH                           1  /* PLLEN */
+#define WM8985_MICBEN                           0x0010  /* MICBEN */
+#define WM8985_MICBEN_MASK                      0x0010  /* MICBEN */
+#define WM8985_MICBEN_SHIFT                          4  /* MICBEN */
+#define WM8985_MICBEN_WIDTH                          1  /* MICBEN */
+#define WM8985_BIASEN                           0x0008  /* BIASEN */
+#define WM8985_BIASEN_MASK                      0x0008  /* BIASEN */
+#define WM8985_BIASEN_SHIFT                          3  /* BIASEN */
+#define WM8985_BIASEN_WIDTH                          1  /* BIASEN */
+#define WM8985_BUFIOEN                          0x0004  /* BUFIOEN */
+#define WM8985_BUFIOEN_MASK                     0x0004  /* BUFIOEN */
+#define WM8985_BUFIOEN_SHIFT                         2  /* BUFIOEN */
+#define WM8985_BUFIOEN_WIDTH                         1  /* BUFIOEN */
+#define WM8985_VMIDSEL                          0x0003  /* VMIDSEL */
+#define WM8985_VMIDSEL_MASK                     0x0003  /* VMIDSEL - [1:0] */
+#define WM8985_VMIDSEL_SHIFT                         0  /* VMIDSEL - [1:0] */
+#define WM8985_VMIDSEL_WIDTH                         2  /* VMIDSEL - [1:0] */
+
+/*
+ * R2 (0x02) - Power management 2
+ */
+#define WM8985_ROUT1EN                          0x0100  /* ROUT1EN */
+#define WM8985_ROUT1EN_MASK                     0x0100  /* ROUT1EN */
+#define WM8985_ROUT1EN_SHIFT                         8  /* ROUT1EN */
+#define WM8985_ROUT1EN_WIDTH                         1  /* ROUT1EN */
+#define WM8985_LOUT1EN                          0x0080  /* LOUT1EN */
+#define WM8985_LOUT1EN_MASK                     0x0080  /* LOUT1EN */
+#define WM8985_LOUT1EN_SHIFT                         7  /* LOUT1EN */
+#define WM8985_LOUT1EN_WIDTH                         1  /* LOUT1EN */
+#define WM8985_SLEEP                            0x0040  /* SLEEP */
+#define WM8985_SLEEP_MASK                       0x0040  /* SLEEP */
+#define WM8985_SLEEP_SHIFT                           6  /* SLEEP */
+#define WM8985_SLEEP_WIDTH                           1  /* SLEEP */
+#define WM8985_BOOSTENR                         0x0020  /* BOOSTENR */
+#define WM8985_BOOSTENR_MASK                    0x0020  /* BOOSTENR */
+#define WM8985_BOOSTENR_SHIFT                        5  /* BOOSTENR */
+#define WM8985_BOOSTENR_WIDTH                        1  /* BOOSTENR */
+#define WM8985_BOOSTENL                         0x0010  /* BOOSTENL */
+#define WM8985_BOOSTENL_MASK                    0x0010  /* BOOSTENL */
+#define WM8985_BOOSTENL_SHIFT                        4  /* BOOSTENL */
+#define WM8985_BOOSTENL_WIDTH                        1  /* BOOSTENL */
+#define WM8985_INPGAENR                         0x0008  /* INPGAENR */
+#define WM8985_INPGAENR_MASK                    0x0008  /* INPGAENR */
+#define WM8985_INPGAENR_SHIFT                        3  /* INPGAENR */
+#define WM8985_INPGAENR_WIDTH                        1  /* INPGAENR */
+#define WM8985_INPPGAENL                        0x0004  /* INPPGAENL */
+#define WM8985_INPPGAENL_MASK                   0x0004  /* INPPGAENL */
+#define WM8985_INPPGAENL_SHIFT                       2  /* INPPGAENL */
+#define WM8985_INPPGAENL_WIDTH                       1  /* INPPGAENL */
+#define WM8985_ADCENR                           0x0002  /* ADCENR */
+#define WM8985_ADCENR_MASK                      0x0002  /* ADCENR */
+#define WM8985_ADCENR_SHIFT                          1  /* ADCENR */
+#define WM8985_ADCENR_WIDTH                          1  /* ADCENR */
+#define WM8985_ADCENL                           0x0001  /* ADCENL */
+#define WM8985_ADCENL_MASK                      0x0001  /* ADCENL */
+#define WM8985_ADCENL_SHIFT                          0  /* ADCENL */
+#define WM8985_ADCENL_WIDTH                          1  /* ADCENL */
+
+/*
+ * R3 (0x03) - Power management 3
+ */
+#define WM8985_OUT4EN                           0x0100  /* OUT4EN */
+#define WM8985_OUT4EN_MASK                      0x0100  /* OUT4EN */
+#define WM8985_OUT4EN_SHIFT                          8  /* OUT4EN */
+#define WM8985_OUT4EN_WIDTH                          1  /* OUT4EN */
+#define WM8985_OUT3EN                           0x0080  /* OUT3EN */
+#define WM8985_OUT3EN_MASK                      0x0080  /* OUT3EN */
+#define WM8985_OUT3EN_SHIFT                          7  /* OUT3EN */
+#define WM8985_OUT3EN_WIDTH                          1  /* OUT3EN */
+#define WM8985_ROUT2EN                          0x0040  /* ROUT2EN */
+#define WM8985_ROUT2EN_MASK                     0x0040  /* ROUT2EN */
+#define WM8985_ROUT2EN_SHIFT                         6  /* ROUT2EN */
+#define WM8985_ROUT2EN_WIDTH                         1  /* ROUT2EN */
+#define WM8985_LOUT2EN                          0x0020  /* LOUT2EN */
+#define WM8985_LOUT2EN_MASK                     0x0020  /* LOUT2EN */
+#define WM8985_LOUT2EN_SHIFT                         5  /* LOUT2EN */
+#define WM8985_LOUT2EN_WIDTH                         1  /* LOUT2EN */
+#define WM8985_RMIXEN                           0x0008  /* RMIXEN */
+#define WM8985_RMIXEN_MASK                      0x0008  /* RMIXEN */
+#define WM8985_RMIXEN_SHIFT                          3  /* RMIXEN */
+#define WM8985_RMIXEN_WIDTH                          1  /* RMIXEN */
+#define WM8985_LMIXEN                           0x0004  /* LMIXEN */
+#define WM8985_LMIXEN_MASK                      0x0004  /* LMIXEN */
+#define WM8985_LMIXEN_SHIFT                          2  /* LMIXEN */
+#define WM8985_LMIXEN_WIDTH                          1  /* LMIXEN */
+#define WM8985_DACENR                           0x0002  /* DACENR */
+#define WM8985_DACENR_MASK                      0x0002  /* DACENR */
+#define WM8985_DACENR_SHIFT                          1  /* DACENR */
+#define WM8985_DACENR_WIDTH                          1  /* DACENR */
+#define WM8985_DACENL                           0x0001  /* DACENL */
+#define WM8985_DACENL_MASK                      0x0001  /* DACENL */
+#define WM8985_DACENL_SHIFT                          0  /* DACENL */
+#define WM8985_DACENL_WIDTH                          1  /* DACENL */
+
+/*
+ * R4 (0x04) - Audio Interface
+ */
+#define WM8985_BCP                              0x0100  /* BCP */
+#define WM8985_BCP_MASK                         0x0100  /* BCP */
+#define WM8985_BCP_SHIFT                             8  /* BCP */
+#define WM8985_BCP_WIDTH                             1  /* BCP */
+#define WM8985_LRP                              0x0080  /* LRP */
+#define WM8985_LRP_MASK                         0x0080  /* LRP */
+#define WM8985_LRP_SHIFT                             7  /* LRP */
+#define WM8985_LRP_WIDTH                             1  /* LRP */
+#define WM8985_WL_MASK                          0x0060  /* WL - [6:5] */
+#define WM8985_WL_SHIFT                              5  /* WL - [6:5] */
+#define WM8985_WL_WIDTH                              2  /* WL - [6:5] */
+#define WM8985_FMT_MASK                         0x0018  /* FMT - [4:3] */
+#define WM8985_FMT_SHIFT                             3  /* FMT - [4:3] */
+#define WM8985_FMT_WIDTH                             2  /* FMT - [4:3] */
+#define WM8985_DLRSWAP                          0x0004  /* DLRSWAP */
+#define WM8985_DLRSWAP_MASK                     0x0004  /* DLRSWAP */
+#define WM8985_DLRSWAP_SHIFT                         2  /* DLRSWAP */
+#define WM8985_DLRSWAP_WIDTH                         1  /* DLRSWAP */
+#define WM8985_ALRSWAP                          0x0002  /* ALRSWAP */
+#define WM8985_ALRSWAP_MASK                     0x0002  /* ALRSWAP */
+#define WM8985_ALRSWAP_SHIFT                         1  /* ALRSWAP */
+#define WM8985_ALRSWAP_WIDTH                         1  /* ALRSWAP */
+#define WM8985_MONO                             0x0001  /* MONO */
+#define WM8985_MONO_MASK                        0x0001  /* MONO */
+#define WM8985_MONO_SHIFT                            0  /* MONO */
+#define WM8985_MONO_WIDTH                            1  /* MONO */
+
+/*
+ * R5 (0x05) - Companding control
+ */
+#define WM8985_WL8                              0x0020  /* WL8 */
+#define WM8985_WL8_MASK                         0x0020  /* WL8 */
+#define WM8985_WL8_SHIFT                             5  /* WL8 */
+#define WM8985_WL8_WIDTH                             1  /* WL8 */
+#define WM8985_DAC_COMP_MASK                    0x0018  /* DAC_COMP - [4:3] */
+#define WM8985_DAC_COMP_SHIFT                        3  /* DAC_COMP - [4:3] */
+#define WM8985_DAC_COMP_WIDTH                        2  /* DAC_COMP - [4:3] */
+#define WM8985_ADC_COMP_MASK                    0x0006  /* ADC_COMP - [2:1] */
+#define WM8985_ADC_COMP_SHIFT                        1  /* ADC_COMP - [2:1] */
+#define WM8985_ADC_COMP_WIDTH                        2  /* ADC_COMP - [2:1] */
+#define WM8985_LOOPBACK                         0x0001  /* LOOPBACK */
+#define WM8985_LOOPBACK_MASK                    0x0001  /* LOOPBACK */
+#define WM8985_LOOPBACK_SHIFT                        0  /* LOOPBACK */
+#define WM8985_LOOPBACK_WIDTH                        1  /* LOOPBACK */
+
+/*
+ * R6 (0x06) - Clock Gen control
+ */
+#define WM8985_CLKSEL                           0x0100  /* CLKSEL */
+#define WM8985_CLKSEL_MASK                      0x0100  /* CLKSEL */
+#define WM8985_CLKSEL_SHIFT                          8  /* CLKSEL */
+#define WM8985_CLKSEL_WIDTH                          1  /* CLKSEL */
+#define WM8985_MCLKDIV_MASK                     0x00E0  /* MCLKDIV - [7:5] */
+#define WM8985_MCLKDIV_SHIFT                         5  /* MCLKDIV - [7:5] */
+#define WM8985_MCLKDIV_WIDTH                         3  /* MCLKDIV - [7:5] */
+#define WM8985_BCLKDIV_MASK                     0x001C  /* BCLKDIV - [4:2] */
+#define WM8985_BCLKDIV_SHIFT                         2  /* BCLKDIV - [4:2] */
+#define WM8985_BCLKDIV_WIDTH                         3  /* BCLKDIV - [4:2] */
+#define WM8985_MS                               0x0001  /* MS */
+#define WM8985_MS_MASK                          0x0001  /* MS */
+#define WM8985_MS_SHIFT                              0  /* MS */
+#define WM8985_MS_WIDTH                              1  /* MS */
+
+/*
+ * R7 (0x07) - Additional control
+ */
+#define WM8985_M128ENB                          0x0100  /* M128ENB */
+#define WM8985_M128ENB_MASK                     0x0100  /* M128ENB */
+#define WM8985_M128ENB_SHIFT                         8  /* M128ENB */
+#define WM8985_M128ENB_WIDTH                         1  /* M128ENB */
+#define WM8985_DCLKDIV_MASK                     0x00F0  /* DCLKDIV - [7:4] */
+#define WM8985_DCLKDIV_SHIFT                         4  /* DCLKDIV - [7:4] */
+#define WM8985_DCLKDIV_WIDTH                         4  /* DCLKDIV - [7:4] */
+#define WM8985_SR_MASK                          0x000E  /* SR - [3:1] */
+#define WM8985_SR_SHIFT                              1  /* SR - [3:1] */
+#define WM8985_SR_WIDTH                              3  /* SR - [3:1] */
+#define WM8985_SLOWCLKEN                        0x0001  /* SLOWCLKEN */
+#define WM8985_SLOWCLKEN_MASK                   0x0001  /* SLOWCLKEN */
+#define WM8985_SLOWCLKEN_SHIFT                       0  /* SLOWCLKEN */
+#define WM8985_SLOWCLKEN_WIDTH                       1  /* SLOWCLKEN */
+
+/*
+ * R8 (0x08) - GPIO Control
+ */
+#define WM8985_GPIO1GP                          0x0100  /* GPIO1GP */
+#define WM8985_GPIO1GP_MASK                     0x0100  /* GPIO1GP */
+#define WM8985_GPIO1GP_SHIFT                         8  /* GPIO1GP */
+#define WM8985_GPIO1GP_WIDTH                         1  /* GPIO1GP */
+#define WM8985_GPIO1GPU                         0x0080  /* GPIO1GPU */
+#define WM8985_GPIO1GPU_MASK                    0x0080  /* GPIO1GPU */
+#define WM8985_GPIO1GPU_SHIFT                        7  /* GPIO1GPU */
+#define WM8985_GPIO1GPU_WIDTH                        1  /* GPIO1GPU */
+#define WM8985_GPIO1GPD                         0x0040  /* GPIO1GPD */
+#define WM8985_GPIO1GPD_MASK                    0x0040  /* GPIO1GPD */
+#define WM8985_GPIO1GPD_SHIFT                        6  /* GPIO1GPD */
+#define WM8985_GPIO1GPD_WIDTH                        1  /* GPIO1GPD */
+#define WM8985_GPIO1POL                         0x0008  /* GPIO1POL */
+#define WM8985_GPIO1POL_MASK                    0x0008  /* GPIO1POL */
+#define WM8985_GPIO1POL_SHIFT                        3  /* GPIO1POL */
+#define WM8985_GPIO1POL_WIDTH                        1  /* GPIO1POL */
+#define WM8985_GPIO1SEL_MASK                    0x0007  /* GPIO1SEL - [2:0] */
+#define WM8985_GPIO1SEL_SHIFT                        0  /* GPIO1SEL - [2:0] */
+#define WM8985_GPIO1SEL_WIDTH                        3  /* GPIO1SEL - [2:0] */
+
+/*
+ * R9 (0x09) - Jack Detect Control 1
+ */
+#define WM8985_JD_EN                            0x0040  /* JD_EN */
+#define WM8985_JD_EN_MASK                       0x0040  /* JD_EN */
+#define WM8985_JD_EN_SHIFT                           6  /* JD_EN */
+#define WM8985_JD_EN_WIDTH                           1  /* JD_EN */
+#define WM8985_JD_SEL_MASK                      0x0030  /* JD_SEL - [5:4] */
+#define WM8985_JD_SEL_SHIFT                          4  /* JD_SEL - [5:4] */
+#define WM8985_JD_SEL_WIDTH                          2  /* JD_SEL - [5:4] */
+
+/*
+ * R10 (0x0A) - DAC Control
+ */
+#define WM8985_SOFTMUTE                         0x0040  /* SOFTMUTE */
+#define WM8985_SOFTMUTE_MASK                    0x0040  /* SOFTMUTE */
+#define WM8985_SOFTMUTE_SHIFT                        6  /* SOFTMUTE */
+#define WM8985_SOFTMUTE_WIDTH                        1  /* SOFTMUTE */
+#define WM8985_DACOSR128                        0x0008  /* DACOSR128 */
+#define WM8985_DACOSR128_MASK                   0x0008  /* DACOSR128 */
+#define WM8985_DACOSR128_SHIFT                       3  /* DACOSR128 */
+#define WM8985_DACOSR128_WIDTH                       1  /* DACOSR128 */
+#define WM8985_AMUTE                            0x0004  /* AMUTE */
+#define WM8985_AMUTE_MASK                       0x0004  /* AMUTE */
+#define WM8985_AMUTE_SHIFT                           2  /* AMUTE */
+#define WM8985_AMUTE_WIDTH                           1  /* AMUTE */
+#define WM8985_DACPOLR                          0x0002  /* DACPOLR */
+#define WM8985_DACPOLR_MASK                     0x0002  /* DACPOLR */
+#define WM8985_DACPOLR_SHIFT                         1  /* DACPOLR */
+#define WM8985_DACPOLR_WIDTH                         1  /* DACPOLR */
+#define WM8985_DACPOLL                          0x0001  /* DACPOLL */
+#define WM8985_DACPOLL_MASK                     0x0001  /* DACPOLL */
+#define WM8985_DACPOLL_SHIFT                         0  /* DACPOLL */
+#define WM8985_DACPOLL_WIDTH                         1  /* DACPOLL */
+
+/*
+ * R11 (0x0B) - Left DAC digital Vol
+ */
+#define WM8985_DACVU                            0x0100  /* DACVU */
+#define WM8985_DACVU_MASK                       0x0100  /* DACVU */
+#define WM8985_DACVU_SHIFT                           8  /* DACVU */
+#define WM8985_DACVU_WIDTH                           1  /* DACVU */
+#define WM8985_DACVOLL_MASK                     0x00FF  /* DACVOLL - [7:0] */
+#define WM8985_DACVOLL_SHIFT                         0  /* DACVOLL - [7:0] */
+#define WM8985_DACVOLL_WIDTH                         8  /* DACVOLL - [7:0] */
+
+/*
+ * R12 (0x0C) - Right DAC digital vol
+ */
+#define WM8985_DACVU                            0x0100  /* DACVU */
+#define WM8985_DACVU_MASK                       0x0100  /* DACVU */
+#define WM8985_DACVU_SHIFT                           8  /* DACVU */
+#define WM8985_DACVU_WIDTH                           1  /* DACVU */
+#define WM8985_DACVOLR_MASK                     0x00FF  /* DACVOLR - [7:0] */
+#define WM8985_DACVOLR_SHIFT                         0  /* DACVOLR - [7:0] */
+#define WM8985_DACVOLR_WIDTH                         8  /* DACVOLR - [7:0] */
+
+/*
+ * R13 (0x0D) - Jack Detect Control 2
+ */
+#define WM8985_JD_EN1_MASK                      0x00F0  /* JD_EN1 - [7:4] */
+#define WM8985_JD_EN1_SHIFT                          4  /* JD_EN1 - [7:4] */
+#define WM8985_JD_EN1_WIDTH                          4  /* JD_EN1 - [7:4] */
+#define WM8985_JD_EN0_MASK                      0x000F  /* JD_EN0 - [3:0] */
+#define WM8985_JD_EN0_SHIFT                          0  /* JD_EN0 - [3:0] */
+#define WM8985_JD_EN0_WIDTH                          4  /* JD_EN0 - [3:0] */
+
+/*
+ * R14 (0x0E) - ADC Control
+ */
+#define WM8985_HPFEN                            0x0100  /* HPFEN */
+#define WM8985_HPFEN_MASK                       0x0100  /* HPFEN */
+#define WM8985_HPFEN_SHIFT                           8  /* HPFEN */
+#define WM8985_HPFEN_WIDTH                           1  /* HPFEN */
+#define WM8985_HPFAPP                           0x0080  /* HPFAPP */
+#define WM8985_HPFAPP_MASK                      0x0080  /* HPFAPP */
+#define WM8985_HPFAPP_SHIFT                          7  /* HPFAPP */
+#define WM8985_HPFAPP_WIDTH                          1  /* HPFAPP */
+#define WM8985_HPFCUT_MASK                      0x0070  /* HPFCUT - [6:4] */
+#define WM8985_HPFCUT_SHIFT                          4  /* HPFCUT - [6:4] */
+#define WM8985_HPFCUT_WIDTH                          3  /* HPFCUT - [6:4] */
+#define WM8985_ADCOSR128                        0x0008  /* ADCOSR128 */
+#define WM8985_ADCOSR128_MASK                   0x0008  /* ADCOSR128 */
+#define WM8985_ADCOSR128_SHIFT                       3  /* ADCOSR128 */
+#define WM8985_ADCOSR128_WIDTH                       1  /* ADCOSR128 */
+#define WM8985_ADCRPOL                          0x0002  /* ADCRPOL */
+#define WM8985_ADCRPOL_MASK                     0x0002  /* ADCRPOL */
+#define WM8985_ADCRPOL_SHIFT                         1  /* ADCRPOL */
+#define WM8985_ADCRPOL_WIDTH                         1  /* ADCRPOL */
+#define WM8985_ADCLPOL                          0x0001  /* ADCLPOL */
+#define WM8985_ADCLPOL_MASK                     0x0001  /* ADCLPOL */
+#define WM8985_ADCLPOL_SHIFT                         0  /* ADCLPOL */
+#define WM8985_ADCLPOL_WIDTH                         1  /* ADCLPOL */
+
+/*
+ * R15 (0x0F) - Left ADC Digital Vol
+ */
+#define WM8985_ADCVU                            0x0100  /* ADCVU */
+#define WM8985_ADCVU_MASK                       0x0100  /* ADCVU */
+#define WM8985_ADCVU_SHIFT                           8  /* ADCVU */
+#define WM8985_ADCVU_WIDTH                           1  /* ADCVU */
+#define WM8985_ADCVOLL_MASK                     0x00FF  /* ADCVOLL - [7:0] */
+#define WM8985_ADCVOLL_SHIFT                         0  /* ADCVOLL - [7:0] */
+#define WM8985_ADCVOLL_WIDTH                         8  /* ADCVOLL - [7:0] */
+
+/*
+ * R16 (0x10) - Right ADC Digital Vol
+ */
+#define WM8985_ADCVU                            0x0100  /* ADCVU */
+#define WM8985_ADCVU_MASK                       0x0100  /* ADCVU */
+#define WM8985_ADCVU_SHIFT                           8  /* ADCVU */
+#define WM8985_ADCVU_WIDTH                           1  /* ADCVU */
+#define WM8985_ADCVOLR_MASK                     0x00FF  /* ADCVOLR - [7:0] */
+#define WM8985_ADCVOLR_SHIFT                         0  /* ADCVOLR - [7:0] */
+#define WM8985_ADCVOLR_WIDTH                         8  /* ADCVOLR - [7:0] */
+
+/*
+ * R18 (0x12) - EQ1 - low shelf
+ */
+#define WM8985_EQ3DMODE                         0x0100  /* EQ3DMODE */
+#define WM8985_EQ3DMODE_MASK                    0x0100  /* EQ3DMODE */
+#define WM8985_EQ3DMODE_SHIFT                        8  /* EQ3DMODE */
+#define WM8985_EQ3DMODE_WIDTH                        1  /* EQ3DMODE */
+#define WM8985_EQ1C_MASK                        0x0060  /* EQ1C - [6:5] */
+#define WM8985_EQ1C_SHIFT                            5  /* EQ1C - [6:5] */
+#define WM8985_EQ1C_WIDTH                            2  /* EQ1C - [6:5] */
+#define WM8985_EQ1G_MASK                        0x001F  /* EQ1G - [4:0] */
+#define WM8985_EQ1G_SHIFT                            0  /* EQ1G - [4:0] */
+#define WM8985_EQ1G_WIDTH                            5  /* EQ1G - [4:0] */
+
+/*
+ * R19 (0x13) - EQ2 - peak 1
+ */
+#define WM8985_EQ2BW                            0x0100  /* EQ2BW */
+#define WM8985_EQ2BW_MASK                       0x0100  /* EQ2BW */
+#define WM8985_EQ2BW_SHIFT                           8  /* EQ2BW */
+#define WM8985_EQ2BW_WIDTH                           1  /* EQ2BW */
+#define WM8985_EQ2C_MASK                        0x0060  /* EQ2C - [6:5] */
+#define WM8985_EQ2C_SHIFT                            5  /* EQ2C - [6:5] */
+#define WM8985_EQ2C_WIDTH                            2  /* EQ2C - [6:5] */
+#define WM8985_EQ2G_MASK                        0x001F  /* EQ2G - [4:0] */
+#define WM8985_EQ2G_SHIFT                            0  /* EQ2G - [4:0] */
+#define WM8985_EQ2G_WIDTH                            5  /* EQ2G - [4:0] */
+
+/*
+ * R20 (0x14) - EQ3 - peak 2
+ */
+#define WM8985_EQ3BW                            0x0100  /* EQ3BW */
+#define WM8985_EQ3BW_MASK                       0x0100  /* EQ3BW */
+#define WM8985_EQ3BW_SHIFT                           8  /* EQ3BW */
+#define WM8985_EQ3BW_WIDTH                           1  /* EQ3BW */
+#define WM8985_EQ3C_MASK                        0x0060  /* EQ3C - [6:5] */
+#define WM8985_EQ3C_SHIFT                            5  /* EQ3C - [6:5] */
+#define WM8985_EQ3C_WIDTH                            2  /* EQ3C - [6:5] */
+#define WM8985_EQ3G_MASK                        0x001F  /* EQ3G - [4:0] */
+#define WM8985_EQ3G_SHIFT                            0  /* EQ3G - [4:0] */
+#define WM8985_EQ3G_WIDTH                            5  /* EQ3G - [4:0] */
+
+/*
+ * R21 (0x15) - EQ4 - peak 3
+ */
+#define WM8985_EQ4BW                            0x0100  /* EQ4BW */
+#define WM8985_EQ4BW_MASK                       0x0100  /* EQ4BW */
+#define WM8985_EQ4BW_SHIFT                           8  /* EQ4BW */
+#define WM8985_EQ4BW_WIDTH                           1  /* EQ4BW */
+#define WM8985_EQ4C_MASK                        0x0060  /* EQ4C - [6:5] */
+#define WM8985_EQ4C_SHIFT                            5  /* EQ4C - [6:5] */
+#define WM8985_EQ4C_WIDTH                            2  /* EQ4C - [6:5] */
+#define WM8985_EQ4G_MASK                        0x001F  /* EQ4G - [4:0] */
+#define WM8985_EQ4G_SHIFT                            0  /* EQ4G - [4:0] */
+#define WM8985_EQ4G_WIDTH                            5  /* EQ4G - [4:0] */
+
+/*
+ * R22 (0x16) - EQ5 - high shelf
+ */
+#define WM8985_EQ5C_MASK                        0x0060  /* EQ5C - [6:5] */
+#define WM8985_EQ5C_SHIFT                            5  /* EQ5C - [6:5] */
+#define WM8985_EQ5C_WIDTH                            2  /* EQ5C - [6:5] */
+#define WM8985_EQ5G_MASK                        0x001F  /* EQ5G - [4:0] */
+#define WM8985_EQ5G_SHIFT                            0  /* EQ5G - [4:0] */
+#define WM8985_EQ5G_WIDTH                            5  /* EQ5G - [4:0] */
+
+/*
+ * R24 (0x18) - DAC Limiter 1
+ */
+#define WM8985_LIMEN                            0x0100  /* LIMEN */
+#define WM8985_LIMEN_MASK                       0x0100  /* LIMEN */
+#define WM8985_LIMEN_SHIFT                           8  /* LIMEN */
+#define WM8985_LIMEN_WIDTH                           1  /* LIMEN */
+#define WM8985_LIMDCY_MASK                      0x00F0  /* LIMDCY - [7:4] */
+#define WM8985_LIMDCY_SHIFT                          4  /* LIMDCY - [7:4] */
+#define WM8985_LIMDCY_WIDTH                          4  /* LIMDCY - [7:4] */
+#define WM8985_LIMATK_MASK                      0x000F  /* LIMATK - [3:0] */
+#define WM8985_LIMATK_SHIFT                          0  /* LIMATK - [3:0] */
+#define WM8985_LIMATK_WIDTH                          4  /* LIMATK - [3:0] */
+
+/*
+ * R25 (0x19) - DAC Limiter 2
+ */
+#define WM8985_LIMLVL_MASK                      0x0070  /* LIMLVL - [6:4] */
+#define WM8985_LIMLVL_SHIFT                          4  /* LIMLVL - [6:4] */
+#define WM8985_LIMLVL_WIDTH                          3  /* LIMLVL - [6:4] */
+#define WM8985_LIMBOOST_MASK                    0x000F  /* LIMBOOST - [3:0] */
+#define WM8985_LIMBOOST_SHIFT                        0  /* LIMBOOST - [3:0] */
+#define WM8985_LIMBOOST_WIDTH                        4  /* LIMBOOST - [3:0] */
+
+/*
+ * R27 (0x1B) - Notch Filter 1
+ */
+#define WM8985_NFU                              0x0100  /* NFU */
+#define WM8985_NFU_MASK                         0x0100  /* NFU */
+#define WM8985_NFU_SHIFT                             8  /* NFU */
+#define WM8985_NFU_WIDTH                             1  /* NFU */
+#define WM8985_NFEN                             0x0080  /* NFEN */
+#define WM8985_NFEN_MASK                        0x0080  /* NFEN */
+#define WM8985_NFEN_SHIFT                            7  /* NFEN */
+#define WM8985_NFEN_WIDTH                            1  /* NFEN */
+#define WM8985_NFA0_13_7_MASK                   0x007F  /* NFA0(13:7) - [6:0] */
+#define WM8985_NFA0_13_7_SHIFT                       0  /* NFA0(13:7) - [6:0] */
+#define WM8985_NFA0_13_7_WIDTH                       7  /* NFA0(13:7) - [6:0] */
+
+/*
+ * R28 (0x1C) - Notch Filter 2
+ */
+#define WM8985_NFU                              0x0100  /* NFU */
+#define WM8985_NFU_MASK                         0x0100  /* NFU */
+#define WM8985_NFU_SHIFT                             8  /* NFU */
+#define WM8985_NFU_WIDTH                             1  /* NFU */
+#define WM8985_NFA0_6_0_MASK                    0x007F  /* NFA0(6:0) - [6:0] */
+#define WM8985_NFA0_6_0_SHIFT                        0  /* NFA0(6:0) - [6:0] */
+#define WM8985_NFA0_6_0_WIDTH                        7  /* NFA0(6:0) - [6:0] */
+
+/*
+ * R29 (0x1D) - Notch Filter 3
+ */
+#define WM8985_NFU                              0x0100  /* NFU */
+#define WM8985_NFU_MASK                         0x0100  /* NFU */
+#define WM8985_NFU_SHIFT                             8  /* NFU */
+#define WM8985_NFU_WIDTH                             1  /* NFU */
+#define WM8985_NFA1_13_7_MASK                   0x007F  /* NFA1(13:7) - [6:0] */
+#define WM8985_NFA1_13_7_SHIFT                       0  /* NFA1(13:7) - [6:0] */
+#define WM8985_NFA1_13_7_WIDTH                       7  /* NFA1(13:7) - [6:0] */
+
+/*
+ * R30 (0x1E) - Notch Filter 4
+ */
+#define WM8985_NFU                              0x0100  /* NFU */
+#define WM8985_NFU_MASK                         0x0100  /* NFU */
+#define WM8985_NFU_SHIFT                             8  /* NFU */
+#define WM8985_NFU_WIDTH                             1  /* NFU */
+#define WM8985_NFA1_6_0_MASK                    0x007F  /* NFA1(6:0) - [6:0] */
+#define WM8985_NFA1_6_0_SHIFT                        0  /* NFA1(6:0) - [6:0] */
+#define WM8985_NFA1_6_0_WIDTH                        7  /* NFA1(6:0) - [6:0] */
+
+/*
+ * R32 (0x20) - ALC control 1
+ */
+#define WM8985_ALCSEL_MASK                      0x0180  /* ALCSEL - [8:7] */
+#define WM8985_ALCSEL_SHIFT                          7  /* ALCSEL - [8:7] */
+#define WM8985_ALCSEL_WIDTH                          2  /* ALCSEL - [8:7] */
+#define WM8985_ALCMAX_MASK                      0x0038  /* ALCMAX - [5:3] */
+#define WM8985_ALCMAX_SHIFT                          3  /* ALCMAX - [5:3] */
+#define WM8985_ALCMAX_WIDTH                          3  /* ALCMAX - [5:3] */
+#define WM8985_ALCMIN_MASK                      0x0007  /* ALCMIN - [2:0] */
+#define WM8985_ALCMIN_SHIFT                          0  /* ALCMIN - [2:0] */
+#define WM8985_ALCMIN_WIDTH                          3  /* ALCMIN - [2:0] */
+
+/*
+ * R33 (0x21) - ALC control 2
+ */
+#define WM8985_ALCHLD_MASK                      0x00F0  /* ALCHLD - [7:4] */
+#define WM8985_ALCHLD_SHIFT                          4  /* ALCHLD - [7:4] */
+#define WM8985_ALCHLD_WIDTH                          4  /* ALCHLD - [7:4] */
+#define WM8985_ALCLVL_MASK                      0x000F  /* ALCLVL - [3:0] */
+#define WM8985_ALCLVL_SHIFT                          0  /* ALCLVL - [3:0] */
+#define WM8985_ALCLVL_WIDTH                          4  /* ALCLVL - [3:0] */
+
+/*
+ * R34 (0x22) - ALC control 3
+ */
+#define WM8985_ALCMODE                          0x0100  /* ALCMODE */
+#define WM8985_ALCMODE_MASK                     0x0100  /* ALCMODE */
+#define WM8985_ALCMODE_SHIFT                         8  /* ALCMODE */
+#define WM8985_ALCMODE_WIDTH                         1  /* ALCMODE */
+#define WM8985_ALCDCY_MASK                      0x00F0  /* ALCDCY - [7:4] */
+#define WM8985_ALCDCY_SHIFT                          4  /* ALCDCY - [7:4] */
+#define WM8985_ALCDCY_WIDTH                          4  /* ALCDCY - [7:4] */
+#define WM8985_ALCATK_MASK                      0x000F  /* ALCATK - [3:0] */
+#define WM8985_ALCATK_SHIFT                          0  /* ALCATK - [3:0] */
+#define WM8985_ALCATK_WIDTH                          4  /* ALCATK - [3:0] */
+
+/*
+ * R35 (0x23) - Noise Gate
+ */
+#define WM8985_NGEN                             0x0008  /* NGEN */
+#define WM8985_NGEN_MASK                        0x0008  /* NGEN */
+#define WM8985_NGEN_SHIFT                            3  /* NGEN */
+#define WM8985_NGEN_WIDTH                            1  /* NGEN */
+#define WM8985_NGTH_MASK                        0x0007  /* NGTH - [2:0] */
+#define WM8985_NGTH_SHIFT                            0  /* NGTH - [2:0] */
+#define WM8985_NGTH_WIDTH                            3  /* NGTH - [2:0] */
+
+/*
+ * R36 (0x24) - PLL N
+ */
+#define WM8985_PLL_PRESCALE                     0x0010  /* PLL_PRESCALE */
+#define WM8985_PLL_PRESCALE_MASK                0x0010  /* PLL_PRESCALE */
+#define WM8985_PLL_PRESCALE_SHIFT                    4  /* PLL_PRESCALE */
+#define WM8985_PLL_PRESCALE_WIDTH                    1  /* PLL_PRESCALE */
+#define WM8985_PLLN_MASK                        0x000F  /* PLLN - [3:0] */
+#define WM8985_PLLN_SHIFT                            0  /* PLLN - [3:0] */
+#define WM8985_PLLN_WIDTH                            4  /* PLLN - [3:0] */
+
+/*
+ * R37 (0x25) - PLL K 1
+ */
+#define WM8985_PLLK_23_18_MASK                  0x003F  /* PLLK(23:18) - [5:0] */
+#define WM8985_PLLK_23_18_SHIFT                      0  /* PLLK(23:18) - [5:0] */
+#define WM8985_PLLK_23_18_WIDTH                      6  /* PLLK(23:18) - [5:0] */
+
+/*
+ * R38 (0x26) - PLL K 2
+ */
+#define WM8985_PLLK_17_9_MASK                   0x01FF  /* PLLK(17:9) - [8:0] */
+#define WM8985_PLLK_17_9_SHIFT                       0  /* PLLK(17:9) - [8:0] */
+#define WM8985_PLLK_17_9_WIDTH                       9  /* PLLK(17:9) - [8:0] */
+
+/*
+ * R39 (0x27) - PLL K 3
+ */
+#define WM8985_PLLK_8_0_MASK                    0x01FF  /* PLLK(8:0) - [8:0] */
+#define WM8985_PLLK_8_0_SHIFT                        0  /* PLLK(8:0) - [8:0] */
+#define WM8985_PLLK_8_0_WIDTH                        9  /* PLLK(8:0) - [8:0] */
+
+/*
+ * R41 (0x29) - 3D control
+ */
+#define WM8985_DEPTH3D_MASK                     0x000F  /* DEPTH3D - [3:0] */
+#define WM8985_DEPTH3D_SHIFT                         0  /* DEPTH3D - [3:0] */
+#define WM8985_DEPTH3D_WIDTH                         4  /* DEPTH3D - [3:0] */
+
+/*
+ * R42 (0x2A) - OUT4 to ADC
+ */
+#define WM8985_OUT4_2ADCVOL_MASK                0x01C0  /* OUT4_2ADCVOL - [8:6] */
+#define WM8985_OUT4_2ADCVOL_SHIFT                    6  /* OUT4_2ADCVOL - [8:6] */
+#define WM8985_OUT4_2ADCVOL_WIDTH                    3  /* OUT4_2ADCVOL - [8:6] */
+#define WM8985_OUT4_2LNR                        0x0020  /* OUT4_2LNR */
+#define WM8985_OUT4_2LNR_MASK                   0x0020  /* OUT4_2LNR */
+#define WM8985_OUT4_2LNR_SHIFT                       5  /* OUT4_2LNR */
+#define WM8985_OUT4_2LNR_WIDTH                       1  /* OUT4_2LNR */
+#define WM8985_POBCTRL                          0x0004  /* POBCTRL */
+#define WM8985_POBCTRL_MASK                     0x0004  /* POBCTRL */
+#define WM8985_POBCTRL_SHIFT                         2  /* POBCTRL */
+#define WM8985_POBCTRL_WIDTH                         1  /* POBCTRL */
+#define WM8985_DELEN                            0x0002  /* DELEN */
+#define WM8985_DELEN_MASK                       0x0002  /* DELEN */
+#define WM8985_DELEN_SHIFT                           1  /* DELEN */
+#define WM8985_DELEN_WIDTH                           1  /* DELEN */
+#define WM8985_OUT1DEL                          0x0001  /* OUT1DEL */
+#define WM8985_OUT1DEL_MASK                     0x0001  /* OUT1DEL */
+#define WM8985_OUT1DEL_SHIFT                         0  /* OUT1DEL */
+#define WM8985_OUT1DEL_WIDTH                         1  /* OUT1DEL */
+
+/*
+ * R43 (0x2B) - Beep control
+ */
+#define WM8985_BYPL2RMIX                        0x0100  /* BYPL2RMIX */
+#define WM8985_BYPL2RMIX_MASK                   0x0100  /* BYPL2RMIX */
+#define WM8985_BYPL2RMIX_SHIFT                       8  /* BYPL2RMIX */
+#define WM8985_BYPL2RMIX_WIDTH                       1  /* BYPL2RMIX */
+#define WM8985_BYPR2LMIX                        0x0080  /* BYPR2LMIX */
+#define WM8985_BYPR2LMIX_MASK                   0x0080  /* BYPR2LMIX */
+#define WM8985_BYPR2LMIX_SHIFT                       7  /* BYPR2LMIX */
+#define WM8985_BYPR2LMIX_WIDTH                       1  /* BYPR2LMIX */
+#define WM8985_MUTERPGA2INV                     0x0020  /* MUTERPGA2INV */
+#define WM8985_MUTERPGA2INV_MASK                0x0020  /* MUTERPGA2INV */
+#define WM8985_MUTERPGA2INV_SHIFT                    5  /* MUTERPGA2INV */
+#define WM8985_MUTERPGA2INV_WIDTH                    1  /* MUTERPGA2INV */
+#define WM8985_INVROUT2                         0x0010  /* INVROUT2 */
+#define WM8985_INVROUT2_MASK                    0x0010  /* INVROUT2 */
+#define WM8985_INVROUT2_SHIFT                        4  /* INVROUT2 */
+#define WM8985_INVROUT2_WIDTH                        1  /* INVROUT2 */
+#define WM8985_BEEPVOL_MASK                     0x000E  /* BEEPVOL - [3:1] */
+#define WM8985_BEEPVOL_SHIFT                         1  /* BEEPVOL - [3:1] */
+#define WM8985_BEEPVOL_WIDTH                         3  /* BEEPVOL - [3:1] */
+#define WM8985_BEEPEN                           0x0001  /* BEEPEN */
+#define WM8985_BEEPEN_MASK                      0x0001  /* BEEPEN */
+#define WM8985_BEEPEN_SHIFT                          0  /* BEEPEN */
+#define WM8985_BEEPEN_WIDTH                          1  /* BEEPEN */
+
+/*
+ * R44 (0x2C) - Input ctrl
+ */
+#define WM8985_MBVSEL                           0x0100  /* MBVSEL */
+#define WM8985_MBVSEL_MASK                      0x0100  /* MBVSEL */
+#define WM8985_MBVSEL_SHIFT                          8  /* MBVSEL */
+#define WM8985_MBVSEL_WIDTH                          1  /* MBVSEL */
+#define WM8985_R2_2INPPGA                       0x0040  /* R2_2INPPGA */
+#define WM8985_R2_2INPPGA_MASK                  0x0040  /* R2_2INPPGA */
+#define WM8985_R2_2INPPGA_SHIFT                      6  /* R2_2INPPGA */
+#define WM8985_R2_2INPPGA_WIDTH                      1  /* R2_2INPPGA */
+#define WM8985_RIN2INPPGA                       0x0020  /* RIN2INPPGA */
+#define WM8985_RIN2INPPGA_MASK                  0x0020  /* RIN2INPPGA */
+#define WM8985_RIN2INPPGA_SHIFT                      5  /* RIN2INPPGA */
+#define WM8985_RIN2INPPGA_WIDTH                      1  /* RIN2INPPGA */
+#define WM8985_RIP2INPPGA                       0x0010  /* RIP2INPPGA */
+#define WM8985_RIP2INPPGA_MASK                  0x0010  /* RIP2INPPGA */
+#define WM8985_RIP2INPPGA_SHIFT                      4  /* RIP2INPPGA */
+#define WM8985_RIP2INPPGA_WIDTH                      1  /* RIP2INPPGA */
+#define WM8985_L2_2INPPGA                       0x0004  /* L2_2INPPGA */
+#define WM8985_L2_2INPPGA_MASK                  0x0004  /* L2_2INPPGA */
+#define WM8985_L2_2INPPGA_SHIFT                      2  /* L2_2INPPGA */
+#define WM8985_L2_2INPPGA_WIDTH                      1  /* L2_2INPPGA */
+#define WM8985_LIN2INPPGA                       0x0002  /* LIN2INPPGA */
+#define WM8985_LIN2INPPGA_MASK                  0x0002  /* LIN2INPPGA */
+#define WM8985_LIN2INPPGA_SHIFT                      1  /* LIN2INPPGA */
+#define WM8985_LIN2INPPGA_WIDTH                      1  /* LIN2INPPGA */
+#define WM8985_LIP2INPPGA                       0x0001  /* LIP2INPPGA */
+#define WM8985_LIP2INPPGA_MASK                  0x0001  /* LIP2INPPGA */
+#define WM8985_LIP2INPPGA_SHIFT                      0  /* LIP2INPPGA */
+#define WM8985_LIP2INPPGA_WIDTH                      1  /* LIP2INPPGA */
+
+/*
+ * R45 (0x2D) - Left INP PGA gain ctrl
+ */
+#define WM8985_INPGAVU                          0x0100  /* INPGAVU */
+#define WM8985_INPGAVU_MASK                     0x0100  /* INPGAVU */
+#define WM8985_INPGAVU_SHIFT                         8  /* INPGAVU */
+#define WM8985_INPGAVU_WIDTH                         1  /* INPGAVU */
+#define WM8985_INPPGAZCL                        0x0080  /* INPPGAZCL */
+#define WM8985_INPPGAZCL_MASK                   0x0080  /* INPPGAZCL */
+#define WM8985_INPPGAZCL_SHIFT                       7  /* INPPGAZCL */
+#define WM8985_INPPGAZCL_WIDTH                       1  /* INPPGAZCL */
+#define WM8985_INPPGAMUTEL                      0x0040  /* INPPGAMUTEL */
+#define WM8985_INPPGAMUTEL_MASK                 0x0040  /* INPPGAMUTEL */
+#define WM8985_INPPGAMUTEL_SHIFT                     6  /* INPPGAMUTEL */
+#define WM8985_INPPGAMUTEL_WIDTH                     1  /* INPPGAMUTEL */
+#define WM8985_INPPGAVOLL_MASK                  0x003F  /* INPPGAVOLL - [5:0] */
+#define WM8985_INPPGAVOLL_SHIFT                      0  /* INPPGAVOLL - [5:0] */
+#define WM8985_INPPGAVOLL_WIDTH                      6  /* INPPGAVOLL - [5:0] */
+
+/*
+ * R46 (0x2E) - Right INP PGA gain ctrl
+ */
+#define WM8985_INPGAVU                          0x0100  /* INPGAVU */
+#define WM8985_INPGAVU_MASK                     0x0100  /* INPGAVU */
+#define WM8985_INPGAVU_SHIFT                         8  /* INPGAVU */
+#define WM8985_INPGAVU_WIDTH                         1  /* INPGAVU */
+#define WM8985_INPPGAZCR                        0x0080  /* INPPGAZCR */
+#define WM8985_INPPGAZCR_MASK                   0x0080  /* INPPGAZCR */
+#define WM8985_INPPGAZCR_SHIFT                       7  /* INPPGAZCR */
+#define WM8985_INPPGAZCR_WIDTH                       1  /* INPPGAZCR */
+#define WM8985_INPPGAMUTER                      0x0040  /* INPPGAMUTER */
+#define WM8985_INPPGAMUTER_MASK                 0x0040  /* INPPGAMUTER */
+#define WM8985_INPPGAMUTER_SHIFT                     6  /* INPPGAMUTER */
+#define WM8985_INPPGAMUTER_WIDTH                     1  /* INPPGAMUTER */
+#define WM8985_INPPGAVOLR_MASK                  0x003F  /* INPPGAVOLR - [5:0] */
+#define WM8985_INPPGAVOLR_SHIFT                      0  /* INPPGAVOLR - [5:0] */
+#define WM8985_INPPGAVOLR_WIDTH                      6  /* INPPGAVOLR - [5:0] */
+
+/*
+ * R47 (0x2F) - Left ADC BOOST ctrl
+ */
+#define WM8985_PGABOOSTL                        0x0100  /* PGABOOSTL */
+#define WM8985_PGABOOSTL_MASK                   0x0100  /* PGABOOSTL */
+#define WM8985_PGABOOSTL_SHIFT                       8  /* PGABOOSTL */
+#define WM8985_PGABOOSTL_WIDTH                       1  /* PGABOOSTL */
+#define WM8985_L2_2BOOSTVOL_MASK                0x0070  /* L2_2BOOSTVOL - [6:4] */
+#define WM8985_L2_2BOOSTVOL_SHIFT                    4  /* L2_2BOOSTVOL - [6:4] */
+#define WM8985_L2_2BOOSTVOL_WIDTH                    3  /* L2_2BOOSTVOL - [6:4] */
+#define WM8985_AUXL2BOOSTVOL_MASK               0x0007  /* AUXL2BOOSTVOL - [2:0] */
+#define WM8985_AUXL2BOOSTVOL_SHIFT                   0  /* AUXL2BOOSTVOL - [2:0] */
+#define WM8985_AUXL2BOOSTVOL_WIDTH                   3  /* AUXL2BOOSTVOL - [2:0] */
+
+/*
+ * R48 (0x30) - Right ADC BOOST ctrl
+ */
+#define WM8985_PGABOOSTR                        0x0100  /* PGABOOSTR */
+#define WM8985_PGABOOSTR_MASK                   0x0100  /* PGABOOSTR */
+#define WM8985_PGABOOSTR_SHIFT                       8  /* PGABOOSTR */
+#define WM8985_PGABOOSTR_WIDTH                       1  /* PGABOOSTR */
+#define WM8985_R2_2BOOSTVOL_MASK                0x0070  /* R2_2BOOSTVOL - [6:4] */
+#define WM8985_R2_2BOOSTVOL_SHIFT                    4  /* R2_2BOOSTVOL - [6:4] */
+#define WM8985_R2_2BOOSTVOL_WIDTH                    3  /* R2_2BOOSTVOL - [6:4] */
+#define WM8985_AUXR2BOOSTVOL_MASK               0x0007  /* AUXR2BOOSTVOL - [2:0] */
+#define WM8985_AUXR2BOOSTVOL_SHIFT                   0  /* AUXR2BOOSTVOL - [2:0] */
+#define WM8985_AUXR2BOOSTVOL_WIDTH                   3  /* AUXR2BOOSTVOL - [2:0] */
+
+/*
+ * R49 (0x31) - Output ctrl
+ */
+#define WM8985_DACL2RMIX                        0x0040  /* DACL2RMIX */
+#define WM8985_DACL2RMIX_MASK                   0x0040  /* DACL2RMIX */
+#define WM8985_DACL2RMIX_SHIFT                       6  /* DACL2RMIX */
+#define WM8985_DACL2RMIX_WIDTH                       1  /* DACL2RMIX */
+#define WM8985_DACR2LMIX                        0x0020  /* DACR2LMIX */
+#define WM8985_DACR2LMIX_MASK                   0x0020  /* DACR2LMIX */
+#define WM8985_DACR2LMIX_SHIFT                       5  /* DACR2LMIX */
+#define WM8985_DACR2LMIX_WIDTH                       1  /* DACR2LMIX */
+#define WM8985_OUT4BOOST                        0x0010  /* OUT4BOOST */
+#define WM8985_OUT4BOOST_MASK                   0x0010  /* OUT4BOOST */
+#define WM8985_OUT4BOOST_SHIFT                       4  /* OUT4BOOST */
+#define WM8985_OUT4BOOST_WIDTH                       1  /* OUT4BOOST */
+#define WM8985_OUT3BOOST                        0x0008  /* OUT3BOOST */
+#define WM8985_OUT3BOOST_MASK                   0x0008  /* OUT3BOOST */
+#define WM8985_OUT3BOOST_SHIFT                       3  /* OUT3BOOST */
+#define WM8985_OUT3BOOST_WIDTH                       1  /* OUT3BOOST */
+#define WM8985_TSOPCTRL                         0x0004  /* TSOPCTRL */
+#define WM8985_TSOPCTRL_MASK                    0x0004  /* TSOPCTRL */
+#define WM8985_TSOPCTRL_SHIFT                        2  /* TSOPCTRL */
+#define WM8985_TSOPCTRL_WIDTH                        1  /* TSOPCTRL */
+#define WM8985_TSDEN                            0x0002  /* TSDEN */
+#define WM8985_TSDEN_MASK                       0x0002  /* TSDEN */
+#define WM8985_TSDEN_SHIFT                           1  /* TSDEN */
+#define WM8985_TSDEN_WIDTH                           1  /* TSDEN */
+#define WM8985_VROI                             0x0001  /* VROI */
+#define WM8985_VROI_MASK                        0x0001  /* VROI */
+#define WM8985_VROI_SHIFT                            0  /* VROI */
+#define WM8985_VROI_WIDTH                            1  /* VROI */
+
+/*
+ * R50 (0x32) - Left mixer ctrl
+ */
+#define WM8985_AUXLMIXVOL_MASK                  0x01C0  /* AUXLMIXVOL - [8:6] */
+#define WM8985_AUXLMIXVOL_SHIFT                      6  /* AUXLMIXVOL - [8:6] */
+#define WM8985_AUXLMIXVOL_WIDTH                      3  /* AUXLMIXVOL - [8:6] */
+#define WM8985_AUXL2LMIX                        0x0020  /* AUXL2LMIX */
+#define WM8985_AUXL2LMIX_MASK                   0x0020  /* AUXL2LMIX */
+#define WM8985_AUXL2LMIX_SHIFT                       5  /* AUXL2LMIX */
+#define WM8985_AUXL2LMIX_WIDTH                       1  /* AUXL2LMIX */
+#define WM8985_BYPLMIXVOL_MASK                  0x001C  /* BYPLMIXVOL - [4:2] */
+#define WM8985_BYPLMIXVOL_SHIFT                      2  /* BYPLMIXVOL - [4:2] */
+#define WM8985_BYPLMIXVOL_WIDTH                      3  /* BYPLMIXVOL - [4:2] */
+#define WM8985_BYPL2LMIX                        0x0002  /* BYPL2LMIX */
+#define WM8985_BYPL2LMIX_MASK                   0x0002  /* BYPL2LMIX */
+#define WM8985_BYPL2LMIX_SHIFT                       1  /* BYPL2LMIX */
+#define WM8985_BYPL2LMIX_WIDTH                       1  /* BYPL2LMIX */
+#define WM8985_DACL2LMIX                        0x0001  /* DACL2LMIX */
+#define WM8985_DACL2LMIX_MASK                   0x0001  /* DACL2LMIX */
+#define WM8985_DACL2LMIX_SHIFT                       0  /* DACL2LMIX */
+#define WM8985_DACL2LMIX_WIDTH                       1  /* DACL2LMIX */
+
+/*
+ * R51 (0x33) - Right mixer ctrl
+ */
+#define WM8985_AUXRMIXVOL_MASK                  0x01C0  /* AUXRMIXVOL - [8:6] */
+#define WM8985_AUXRMIXVOL_SHIFT                      6  /* AUXRMIXVOL - [8:6] */
+#define WM8985_AUXRMIXVOL_WIDTH                      3  /* AUXRMIXVOL - [8:6] */
+#define WM8985_AUXR2RMIX                        0x0020  /* AUXR2RMIX */
+#define WM8985_AUXR2RMIX_MASK                   0x0020  /* AUXR2RMIX */
+#define WM8985_AUXR2RMIX_SHIFT                       5  /* AUXR2RMIX */
+#define WM8985_AUXR2RMIX_WIDTH                       1  /* AUXR2RMIX */
+#define WM8985_BYPRMIXVOL_MASK                  0x001C  /* BYPRMIXVOL - [4:2] */
+#define WM8985_BYPRMIXVOL_SHIFT                      2  /* BYPRMIXVOL - [4:2] */
+#define WM8985_BYPRMIXVOL_WIDTH                      3  /* BYPRMIXVOL - [4:2] */
+#define WM8985_BYPR2RMIX                        0x0002  /* BYPR2RMIX */
+#define WM8985_BYPR2RMIX_MASK                   0x0002  /* BYPR2RMIX */
+#define WM8985_BYPR2RMIX_SHIFT                       1  /* BYPR2RMIX */
+#define WM8985_BYPR2RMIX_WIDTH                       1  /* BYPR2RMIX */
+#define WM8985_DACR2RMIX                        0x0001  /* DACR2RMIX */
+#define WM8985_DACR2RMIX_MASK                   0x0001  /* DACR2RMIX */
+#define WM8985_DACR2RMIX_SHIFT                       0  /* DACR2RMIX */
+#define WM8985_DACR2RMIX_WIDTH                       1  /* DACR2RMIX */
+
+/*
+ * R52 (0x34) - LOUT1 (HP) volume ctrl
+ */
+#define WM8985_OUT1VU                           0x0100  /* OUT1VU */
+#define WM8985_OUT1VU_MASK                      0x0100  /* OUT1VU */
+#define WM8985_OUT1VU_SHIFT                          8  /* OUT1VU */
+#define WM8985_OUT1VU_WIDTH                          1  /* OUT1VU */
+#define WM8985_LOUT1ZC                          0x0080  /* LOUT1ZC */
+#define WM8985_LOUT1ZC_MASK                     0x0080  /* LOUT1ZC */
+#define WM8985_LOUT1ZC_SHIFT                         7  /* LOUT1ZC */
+#define WM8985_LOUT1ZC_WIDTH                         1  /* LOUT1ZC */
+#define WM8985_LOUT1MUTE                        0x0040  /* LOUT1MUTE */
+#define WM8985_LOUT1MUTE_MASK                   0x0040  /* LOUT1MUTE */
+#define WM8985_LOUT1MUTE_SHIFT                       6  /* LOUT1MUTE */
+#define WM8985_LOUT1MUTE_WIDTH                       1  /* LOUT1MUTE */
+#define WM8985_LOUT1VOL_MASK                    0x003F  /* LOUT1VOL - [5:0] */
+#define WM8985_LOUT1VOL_SHIFT                        0  /* LOUT1VOL - [5:0] */
+#define WM8985_LOUT1VOL_WIDTH                        6  /* LOUT1VOL - [5:0] */
+
+/*
+ * R53 (0x35) - ROUT1 (HP) volume ctrl
+ */
+#define WM8985_OUT1VU                           0x0100  /* OUT1VU */
+#define WM8985_OUT1VU_MASK                      0x0100  /* OUT1VU */
+#define WM8985_OUT1VU_SHIFT                          8  /* OUT1VU */
+#define WM8985_OUT1VU_WIDTH                          1  /* OUT1VU */
+#define WM8985_ROUT1ZC                          0x0080  /* ROUT1ZC */
+#define WM8985_ROUT1ZC_MASK                     0x0080  /* ROUT1ZC */
+#define WM8985_ROUT1ZC_SHIFT                         7  /* ROUT1ZC */
+#define WM8985_ROUT1ZC_WIDTH                         1  /* ROUT1ZC */
+#define WM8985_ROUT1MUTE                        0x0040  /* ROUT1MUTE */
+#define WM8985_ROUT1MUTE_MASK                   0x0040  /* ROUT1MUTE */
+#define WM8985_ROUT1MUTE_SHIFT                       6  /* ROUT1MUTE */
+#define WM8985_ROUT1MUTE_WIDTH                       1  /* ROUT1MUTE */
+#define WM8985_ROUT1VOL_MASK                    0x003F  /* ROUT1VOL - [5:0] */
+#define WM8985_ROUT1VOL_SHIFT                        0  /* ROUT1VOL - [5:0] */
+#define WM8985_ROUT1VOL_WIDTH                        6  /* ROUT1VOL - [5:0] */
+
+/*
+ * R54 (0x36) - LOUT2 (SPK) volume ctrl
+ */
+#define WM8985_OUT2VU                           0x0100  /* OUT2VU */
+#define WM8985_OUT2VU_MASK                      0x0100  /* OUT2VU */
+#define WM8985_OUT2VU_SHIFT                          8  /* OUT2VU */
+#define WM8985_OUT2VU_WIDTH                          1  /* OUT2VU */
+#define WM8985_LOUT2ZC                          0x0080  /* LOUT2ZC */
+#define WM8985_LOUT2ZC_MASK                     0x0080  /* LOUT2ZC */
+#define WM8985_LOUT2ZC_SHIFT                         7  /* LOUT2ZC */
+#define WM8985_LOUT2ZC_WIDTH                         1  /* LOUT2ZC */
+#define WM8985_LOUT2MUTE                        0x0040  /* LOUT2MUTE */
+#define WM8985_LOUT2MUTE_MASK                   0x0040  /* LOUT2MUTE */
+#define WM8985_LOUT2MUTE_SHIFT                       6  /* LOUT2MUTE */
+#define WM8985_LOUT2MUTE_WIDTH                       1  /* LOUT2MUTE */
+#define WM8985_LOUT2VOL_MASK                    0x003F  /* LOUT2VOL - [5:0] */
+#define WM8985_LOUT2VOL_SHIFT                        0  /* LOUT2VOL - [5:0] */
+#define WM8985_LOUT2VOL_WIDTH                        6  /* LOUT2VOL - [5:0] */
+
+/*
+ * R55 (0x37) - ROUT2 (SPK) volume ctrl
+ */
+#define WM8985_OUT2VU                           0x0100  /* OUT2VU */
+#define WM8985_OUT2VU_MASK                      0x0100  /* OUT2VU */
+#define WM8985_OUT2VU_SHIFT                          8  /* OUT2VU */
+#define WM8985_OUT2VU_WIDTH                          1  /* OUT2VU */
+#define WM8985_ROUT2ZC                          0x0080  /* ROUT2ZC */
+#define WM8985_ROUT2ZC_MASK                     0x0080  /* ROUT2ZC */
+#define WM8985_ROUT2ZC_SHIFT                         7  /* ROUT2ZC */
+#define WM8985_ROUT2ZC_WIDTH                         1  /* ROUT2ZC */
+#define WM8985_ROUT2MUTE                        0x0040  /* ROUT2MUTE */
+#define WM8985_ROUT2MUTE_MASK                   0x0040  /* ROUT2MUTE */
+#define WM8985_ROUT2MUTE_SHIFT                       6  /* ROUT2MUTE */
+#define WM8985_ROUT2MUTE_WIDTH                       1  /* ROUT2MUTE */
+#define WM8985_ROUT2VOL_MASK                    0x003F  /* ROUT2VOL - [5:0] */
+#define WM8985_ROUT2VOL_SHIFT                        0  /* ROUT2VOL - [5:0] */
+#define WM8985_ROUT2VOL_WIDTH                        6  /* ROUT2VOL - [5:0] */
+
+/*
+ * R56 (0x38) - OUT3 mixer ctrl
+ */
+#define WM8985_OUT3MUTE                         0x0040  /* OUT3MUTE */
+#define WM8985_OUT3MUTE_MASK                    0x0040  /* OUT3MUTE */
+#define WM8985_OUT3MUTE_SHIFT                        6  /* OUT3MUTE */
+#define WM8985_OUT3MUTE_WIDTH                        1  /* OUT3MUTE */
+#define WM8985_OUT4_2OUT3                       0x0008  /* OUT4_2OUT3 */
+#define WM8985_OUT4_2OUT3_MASK                  0x0008  /* OUT4_2OUT3 */
+#define WM8985_OUT4_2OUT3_SHIFT                      3  /* OUT4_2OUT3 */
+#define WM8985_OUT4_2OUT3_WIDTH                      1  /* OUT4_2OUT3 */
+#define WM8985_BYPL2OUT3                        0x0004  /* BYPL2OUT3 */
+#define WM8985_BYPL2OUT3_MASK                   0x0004  /* BYPL2OUT3 */
+#define WM8985_BYPL2OUT3_SHIFT                       2  /* BYPL2OUT3 */
+#define WM8985_BYPL2OUT3_WIDTH                       1  /* BYPL2OUT3 */
+#define WM8985_LMIX2OUT3                        0x0002  /* LMIX2OUT3 */
+#define WM8985_LMIX2OUT3_MASK                   0x0002  /* LMIX2OUT3 */
+#define WM8985_LMIX2OUT3_SHIFT                       1  /* LMIX2OUT3 */
+#define WM8985_LMIX2OUT3_WIDTH                       1  /* LMIX2OUT3 */
+#define WM8985_LDAC2OUT3                        0x0001  /* LDAC2OUT3 */
+#define WM8985_LDAC2OUT3_MASK                   0x0001  /* LDAC2OUT3 */
+#define WM8985_LDAC2OUT3_SHIFT                       0  /* LDAC2OUT3 */
+#define WM8985_LDAC2OUT3_WIDTH                       1  /* LDAC2OUT3 */
+
+/*
+ * R57 (0x39) - OUT4 (MONO) mix ctrl
+ */
+#define WM8985_OUT3_2OUT4                       0x0080  /* OUT3_2OUT4 */
+#define WM8985_OUT3_2OUT4_MASK                  0x0080  /* OUT3_2OUT4 */
+#define WM8985_OUT3_2OUT4_SHIFT                      7  /* OUT3_2OUT4 */
+#define WM8985_OUT3_2OUT4_WIDTH                      1  /* OUT3_2OUT4 */
+#define WM8985_OUT4MUTE                         0x0040  /* OUT4MUTE */
+#define WM8985_OUT4MUTE_MASK                    0x0040  /* OUT4MUTE */
+#define WM8985_OUT4MUTE_SHIFT                        6  /* OUT4MUTE */
+#define WM8985_OUT4MUTE_WIDTH                        1  /* OUT4MUTE */
+#define WM8985_OUT4ATTN                         0x0020  /* OUT4ATTN */
+#define WM8985_OUT4ATTN_MASK                    0x0020  /* OUT4ATTN */
+#define WM8985_OUT4ATTN_SHIFT                        5  /* OUT4ATTN */
+#define WM8985_OUT4ATTN_WIDTH                        1  /* OUT4ATTN */
+#define WM8985_LMIX2OUT4                        0x0010  /* LMIX2OUT4 */
+#define WM8985_LMIX2OUT4_MASK                   0x0010  /* LMIX2OUT4 */
+#define WM8985_LMIX2OUT4_SHIFT                       4  /* LMIX2OUT4 */
+#define WM8985_LMIX2OUT4_WIDTH                       1  /* LMIX2OUT4 */
+#define WM8985_LDAC2OUT4                        0x0008  /* LDAC2OUT4 */
+#define WM8985_LDAC2OUT4_MASK                   0x0008  /* LDAC2OUT4 */
+#define WM8985_LDAC2OUT4_SHIFT                       3  /* LDAC2OUT4 */
+#define WM8985_LDAC2OUT4_WIDTH                       1  /* LDAC2OUT4 */
+#define WM8985_BYPR2OUT4                        0x0004  /* BYPR2OUT4 */
+#define WM8985_BYPR2OUT4_MASK                   0x0004  /* BYPR2OUT4 */
+#define WM8985_BYPR2OUT4_SHIFT                       2  /* BYPR2OUT4 */
+#define WM8985_BYPR2OUT4_WIDTH                       1  /* BYPR2OUT4 */
+#define WM8985_RMIX2OUT4                        0x0002  /* RMIX2OUT4 */
+#define WM8985_RMIX2OUT4_MASK                   0x0002  /* RMIX2OUT4 */
+#define WM8985_RMIX2OUT4_SHIFT                       1  /* RMIX2OUT4 */
+#define WM8985_RMIX2OUT4_WIDTH                       1  /* RMIX2OUT4 */
+#define WM8985_RDAC2OUT4                        0x0001  /* RDAC2OUT4 */
+#define WM8985_RDAC2OUT4_MASK                   0x0001  /* RDAC2OUT4 */
+#define WM8985_RDAC2OUT4_SHIFT                       0  /* RDAC2OUT4 */
+#define WM8985_RDAC2OUT4_WIDTH                       1  /* RDAC2OUT4 */
+
+/*
+ * R60 (0x3C) - OUTPUT ctrl
+ */
+#define WM8985_VIDBUFFTST_MASK                  0x01E0  /* VIDBUFFTST - [8:5] */
+#define WM8985_VIDBUFFTST_SHIFT                      5  /* VIDBUFFTST - [8:5] */
+#define WM8985_VIDBUFFTST_WIDTH                      4  /* VIDBUFFTST - [8:5] */
+#define WM8985_HPTOG                            0x0008  /* HPTOG */
+#define WM8985_HPTOG_MASK                       0x0008  /* HPTOG */
+#define WM8985_HPTOG_SHIFT                           3  /* HPTOG */
+#define WM8985_HPTOG_WIDTH                           1  /* HPTOG */
+
+/*
+ * R61 (0x3D) - BIAS CTRL
+ */
+#define WM8985_BIASCUT                          0x0100  /* BIASCUT */
+#define WM8985_BIASCUT_MASK                     0x0100  /* BIASCUT */
+#define WM8985_BIASCUT_SHIFT                         8  /* BIASCUT */
+#define WM8985_BIASCUT_WIDTH                         1  /* BIASCUT */
+#define WM8985_HALFIPBIAS                       0x0080  /* HALFIPBIAS */
+#define WM8985_HALFIPBIAS_MASK                  0x0080  /* HALFIPBIAS */
+#define WM8985_HALFIPBIAS_SHIFT                      7  /* HALFIPBIAS */
+#define WM8985_HALFIPBIAS_WIDTH                      1  /* HALFIPBIAS */
+#define WM8985_VBBIASTST_MASK                   0x0060  /* VBBIASTST - [6:5] */
+#define WM8985_VBBIASTST_SHIFT                       5  /* VBBIASTST - [6:5] */
+#define WM8985_VBBIASTST_WIDTH                       2  /* VBBIASTST - [6:5] */
+#define WM8985_BUFBIAS_MASK                     0x0018  /* BUFBIAS - [4:3] */
+#define WM8985_BUFBIAS_SHIFT                         3  /* BUFBIAS - [4:3] */
+#define WM8985_BUFBIAS_WIDTH                         2  /* BUFBIAS - [4:3] */
+#define WM8985_ADCBIAS_MASK                     0x0006  /* ADCBIAS - [2:1] */
+#define WM8985_ADCBIAS_SHIFT                         1  /* ADCBIAS - [2:1] */
+#define WM8985_ADCBIAS_WIDTH                         2  /* ADCBIAS - [2:1] */
+#define WM8985_HALFOPBIAS                       0x0001  /* HALFOPBIAS */
+#define WM8985_HALFOPBIAS_MASK                  0x0001  /* HALFOPBIAS */
+#define WM8985_HALFOPBIAS_SHIFT                      0  /* HALFOPBIAS */
+#define WM8985_HALFOPBIAS_WIDTH                      1  /* HALFOPBIAS */
+
+enum clk_src {
+       WM8985_CLKSRC_MCLK,
+       WM8985_CLKSRC_PLL
+};
+
+#define WM8985_PLL 0
+
+#endif
index 19ad590ca0b390065850ce4ab8b0e4e2fd5d841a..d7f2597119703e983cccbaf4485109dd2f439130 100644 (file)
@@ -52,7 +52,7 @@ static const u16 wm8988_reg[] = {
 /* codec private data */
 struct wm8988_priv {
        unsigned int sysclk;
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
        struct snd_pcm_hw_constraint_list *sysclk_constraints;
        u16 reg_cache[WM8988_NUM_REG];
 };
@@ -608,8 +608,7 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8988_IFACE) & 0x1f3;
        u16 srate = snd_soc_read(codec, WM8988_SRATE) & 0x180;
@@ -711,8 +710,8 @@ static struct snd_soc_dai_ops wm8988_ops = {
        .digital_mute = wm8988_mute,
 };
 
-struct snd_soc_dai wm8988_dai = {
-       .name = "WM8988",
+static struct snd_soc_dai_driver wm8988_dai = {
+       .name = "wm8988-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -730,21 +729,15 @@ struct snd_soc_dai wm8988_dai = {
        .ops = &wm8988_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(wm8988_dai);
 
-static int wm8988_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8988_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8988_resume(struct platform_device *pdev)
+static int wm8988_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -763,99 +756,22 @@ static int wm8988_resume(struct platform_device *pdev)
        return 0;
 }
 
-static struct snd_soc_codec *wm8988_codec;
-
-static int wm8988_probe(struct platform_device *pdev)
+static int wm8988_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
+       struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
-
-       if (wm8988_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8988_codec;
-       codec = wm8988_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
-       }
-
-       snd_soc_add_controls(codec, wm8988_snd_controls,
-                               ARRAY_SIZE(wm8988_snd_controls));
-       snd_soc_dapm_new_controls(codec, wm8988_dapm_widgets,
-                                 ARRAY_SIZE(wm8988_dapm_widgets));
-       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
-
-       return ret;
-
-pcm_err:
-       return ret;
-}
-
-static int wm8988_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8988 = {
-       .probe =        wm8988_probe,
-       .remove =       wm8988_remove,
-       .suspend =      wm8988_suspend,
-       .resume =       wm8988_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8988);
-
-static int wm8988_register(struct wm8988_priv *wm8988,
-                          enum snd_soc_control_type control)
-{
-       struct snd_soc_codec *codec = &wm8988->codec;
-       int ret;
        u16 reg;
 
-       if (wm8988_codec) {
-               dev_err(codec->dev, "Another WM8988 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8988);
-       codec->name = "WM8988";
-       codec->owner = THIS_MODULE;
-       codec->dai = &wm8988_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(wm8988->reg_cache);
-       codec->reg_cache = &wm8988->reg_cache;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8988_set_bias_level;
-
-       memcpy(codec->reg_cache, wm8988_reg,
-              sizeof(wm8988_reg));
-
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8988->control_type);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
+               return ret;
        }
 
        ret = wm8988_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset\n");
-               goto err;
+               return ret;
        }
 
        /* set the update bits (we always update left then right) */
@@ -870,139 +786,132 @@ static int wm8988_register(struct wm8988_priv *wm8988,
        reg = snd_soc_read(codec, WM8988_RINVOL);
        snd_soc_write(codec, WM8988_RINVOL, reg | 0x0100);
 
-       wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_STANDBY);
-
-       wm8988_dai.dev = codec->dev;
-
-       wm8988_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
+       wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       ret = snd_soc_register_dai(&wm8988_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
+       snd_soc_add_controls(codec, wm8988_snd_controls,
+                               ARRAY_SIZE(wm8988_snd_controls));
+       snd_soc_dapm_new_controls(codec, wm8988_dapm_widgets,
+                                 ARRAY_SIZE(wm8988_dapm_widgets));
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
 
        return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm8988);
-       return ret;
 }
 
-static void wm8988_unregister(struct wm8988_priv *wm8988)
+static int wm8988_remove(struct snd_soc_codec *codec)
 {
-       wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dai(&wm8988_dai);
-       snd_soc_unregister_codec(&wm8988->codec);
-       kfree(wm8988);
-       wm8988_codec = NULL;
+       wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
 
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static int wm8988_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+static struct snd_soc_codec_driver soc_codec_dev_wm8988 = {
+       .probe =        wm8988_probe,
+       .remove =       wm8988_remove,
+       .suspend =      wm8988_suspend,
+       .resume =       wm8988_resume,
+       .set_bias_level = wm8988_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8988_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8988_reg,
+};
+
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit wm8988_spi_probe(struct spi_device *spi)
 {
        struct wm8988_priv *wm8988;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL);
        if (wm8988 == NULL)
                return -ENOMEM;
 
-       codec = &wm8988->codec;
-
-       i2c_set_clientdata(i2c, wm8988);
-       codec->control_data = i2c;
-
-       codec->dev = &i2c->dev;
+       wm8988->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8988);
 
-       return wm8988_register(wm8988, SND_SOC_I2C);
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_wm8988, &wm8988_dai, 1);
+       if (ret < 0)
+               kfree(wm8988);
+       return ret;
 }
 
-static int wm8988_i2c_remove(struct i2c_client *client)
+static int __devexit wm8988_spi_remove(struct spi_device *spi)
 {
-       struct wm8988_priv *wm8988 = i2c_get_clientdata(client);
-       wm8988_unregister(wm8988);
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
-static const struct i2c_device_id wm8988_i2c_id[] = {
-       { "wm8988", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8988_i2c_id);
-
-static struct i2c_driver wm8988_i2c_driver = {
+static struct spi_driver wm8988_spi_driver = {
        .driver = {
-               .name = "WM8988",
-               .owner = THIS_MODULE,
+               .name   = "wm8988-codec",
+               .owner  = THIS_MODULE,
        },
-       .probe = wm8988_i2c_probe,
-       .remove = wm8988_i2c_remove,
-       .id_table = wm8988_i2c_id,
+       .probe          = wm8988_spi_probe,
+       .remove         = __devexit_p(wm8988_spi_remove),
 };
-#endif
+#endif /* CONFIG_SPI_MASTER */
 
-#if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8988_spi_probe(struct spi_device *spi)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8988_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
        struct wm8988_priv *wm8988;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL);
        if (wm8988 == NULL)
                return -ENOMEM;
 
-       codec = &wm8988->codec;
-       codec->control_data = spi;
-       codec->dev = &spi->dev;
-
-       dev_set_drvdata(&spi->dev, wm8988);
+       i2c_set_clientdata(i2c, wm8988);
+       wm8988->control_type = SND_SOC_I2C;
 
-       return wm8988_register(wm8988, SND_SOC_SPI);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8988, &wm8988_dai, 1);
+       if (ret < 0)
+               kfree(wm8988);
+       return ret;
 }
 
-static int __devexit wm8988_spi_remove(struct spi_device *spi)
+static __devexit int wm8988_i2c_remove(struct i2c_client *client)
 {
-       struct wm8988_priv *wm8988 = dev_get_drvdata(&spi->dev);
-
-       wm8988_unregister(wm8988);
-
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
-static struct spi_driver wm8988_spi_driver = {
+static const struct i2c_device_id wm8988_i2c_id[] = {
+       { "wm8988", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8988_i2c_id);
+
+static struct i2c_driver wm8988_i2c_driver = {
        .driver = {
-               .name   = "wm8988",
-               .bus    = &spi_bus_type,
-               .owner  = THIS_MODULE,
+               .name = "wm8988-codec",
+               .owner = THIS_MODULE,
        },
-       .probe          = wm8988_spi_probe,
-       .remove         = __devexit_p(wm8988_spi_remove),
+       .probe =    wm8988_i2c_probe,
+       .remove =   __devexit_p(wm8988_i2c_remove),
+       .id_table = wm8988_i2c_id,
 };
 #endif
 
 static int __init wm8988_modinit(void)
 {
-       int ret;
-
+       int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8988_i2c_driver);
-       if (ret != 0)
-               pr_err("WM8988: Unable to register I2C driver: %d\n", ret);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8988 I2C driver: %d\n",
+                      ret);
+       }
 #endif
 #if defined(CONFIG_SPI_MASTER)
        ret = spi_register_driver(&wm8988_spi_driver);
-       if (ret != 0)
-               pr_err("WM8988: Unable to register SPI driver: %d\n", ret);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register WM8988 SPI driver: %d\n",
+                      ret);
+       }
 #endif
        return ret;
 }
index 4552d37fdd415a3a68a91143f24d97f3bda929e8..5c04024e5f9f8c22b28bd09752237562c6092fba 100644 (file)
@@ -54,7 +54,4 @@
 
 #define WM8988_SYSCLK  0
 
-extern struct snd_soc_dai wm8988_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8988;
-
 #endif
index dd8d909788c1fe2b305d5b6af4f5eb4f58062cbd..264828e4e67c8be0d7e43a8ffd6d2f4d96498d74 100644 (file)
@@ -32,6 +32,7 @@
 
 /* codec private data */
 struct wm8990_priv {
+       enum snd_soc_control_type control_type;
        unsigned int sysclk;
        unsigned int pcmclk;
 };
@@ -1114,8 +1115,7 @@ static int wm8990_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u16 audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1);
 
        audio1 &= ~WM8990_AIF_WL_MASK;
@@ -1293,10 +1293,9 @@ static struct snd_soc_dai_ops wm8990_dai_ops = {
        .set_sysclk     = wm8990_set_dai_sysclk,
 };
 
-struct snd_soc_dai wm8990_dai = {
+static struct snd_soc_dai_driver wm8990_dai = {
 /* ADC/DAC on primary */
-       .name = "WM8990 ADC/DAC Primary",
-       .id = 1,
+       .name = "wm8990-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -1311,21 +1310,15 @@ struct snd_soc_dai wm8990_dai = {
                .formats = WM8990_FORMATS,},
        .ops = &wm8990_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm8990_dai);
 
-static int wm8990_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8990_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm8990_resume(struct platform_device *pdev)
+static int wm8990_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -1347,40 +1340,20 @@ static int wm8990_resume(struct platform_device *pdev)
  * initialise the WM8990 driver
  * register the mixer and dsp interfaces with the kernel
  */
-static int wm8990_init(struct snd_soc_device *socdev)
+static int wm8990_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = socdev->card->codec;
+       int ret;
        u16 reg;
-       int ret = 0;
-
-       codec->name = "WM8990";
-       codec->owner = THIS_MODULE;
-       codec->set_bias_level = wm8990_set_bias_level;
-       codec->dai = &wm8990_dai;
-       codec->num_dai = 2;
-       codec->reg_cache_size = ARRAY_SIZE(wm8990_reg);
-       codec->reg_cache = kmemdup(wm8990_reg, sizeof(wm8990_reg), GFP_KERNEL);
-
-       if (codec->reg_cache == NULL)
-               return -ENOMEM;
 
        ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
        if (ret < 0) {
                printk(KERN_ERR "wm8990: failed to set cache I/O: %d\n", ret);
-               goto pcm_err;
+               return ret;
        }
 
        wm8990_reset(codec);
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               printk(KERN_ERR "wm8990: failed to create pcms\n");
-               goto pcm_err;
-       }
-
        /* charge output caps */
-       codec->bias_level = SND_SOC_BIAS_OFF;
        wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        reg = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_4);
@@ -1400,47 +1373,51 @@ static int wm8990_init(struct snd_soc_device *socdev)
                                ARRAY_SIZE(wm8990_snd_controls));
        wm8990_add_widgets(codec);
 
-       return ret;
+       return 0;
+}
 
-pcm_err:
-       kfree(codec->reg_cache);
-       return ret;
+/* power down chip */
+static int wm8990_remove(struct snd_soc_codec *codec)
+{
+       wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
 
-/* If the i2c layer weren't so broken, we could pass this kind of data
-   around */
-static struct snd_soc_device *wm8990_socdev;
+static struct snd_soc_codec_driver soc_codec_dev_wm8990 = {
+       .probe =        wm8990_probe,
+       .remove =       wm8990_remove,
+       .suspend =      wm8990_suspend,
+       .resume =       wm8990_resume,
+       .set_bias_level = wm8990_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8990_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8990_reg,
+};
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-/*
- * WM891 2 wire address is determined by GPIO5
- * state during powerup.
- *    low  = 0x34
- *    high = 0x36
- */
-
-static int wm8990_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+static __devinit int wm8990_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
-       struct snd_soc_device *socdev = wm8990_socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct wm8990_priv *wm8990;
        int ret;
 
-       i2c_set_clientdata(i2c, codec);
-       codec->control_data = i2c;
+       wm8990 = kzalloc(sizeof(struct wm8990_priv), GFP_KERNEL);
+       if (wm8990 == NULL)
+               return -ENOMEM;
 
-       ret = wm8990_init(socdev);
-       if (ret < 0)
-               pr_err("failed to initialise WM8990\n");
+       i2c_set_clientdata(i2c, wm8990);
 
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8990, &wm8990_dai, 1);
+       if (ret < 0)
+               kfree(wm8990);
        return ret;
 }
 
-static int wm8990_i2c_remove(struct i2c_client *client)
+static __devexit int wm8990_i2c_remove(struct i2c_client *client)
 {
-       struct snd_soc_codec *codec = i2c_get_clientdata(client);
-       kfree(codec->reg_cache);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -1452,134 +1429,34 @@ MODULE_DEVICE_TABLE(i2c, wm8990_i2c_id);
 
 static struct i2c_driver wm8990_i2c_driver = {
        .driver = {
-               .name = "WM8990 I2C Codec",
+               .name = "wm8990-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8990_i2c_probe,
-       .remove =   wm8990_i2c_remove,
+       .remove =   __devexit_p(wm8990_i2c_remove),
        .id_table = wm8990_i2c_id,
 };
-
-static int wm8990_add_i2c_device(struct platform_device *pdev,
-                                const struct wm8990_setup_data *setup)
-{
-       struct i2c_board_info info;
-       struct i2c_adapter *adapter;
-       struct i2c_client *client;
-       int ret;
-
-       ret = i2c_add_driver(&wm8990_i2c_driver);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "can't add i2c driver\n");
-               return ret;
-       }
-
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       info.addr = setup->i2c_address;
-       strlcpy(info.type, "wm8990", I2C_NAME_SIZE);
-
-       adapter = i2c_get_adapter(setup->i2c_bus);
-       if (!adapter) {
-               dev_err(&pdev->dev, "can't get i2c adapter %d\n",
-                       setup->i2c_bus);
-               goto err_driver;
-       }
-
-       client = i2c_new_device(adapter, &info);
-       i2c_put_adapter(adapter);
-       if (!client) {
-               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
-                       (unsigned int)info.addr);
-               goto err_driver;
-       }
-
-       return 0;
-
-err_driver:
-       i2c_del_driver(&wm8990_i2c_driver);
-       return -ENODEV;
-}
 #endif
 
-static int wm8990_probe(struct platform_device *pdev)
+static int __init wm8990_modinit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct wm8990_setup_data *setup;
-       struct snd_soc_codec *codec;
-       struct wm8990_priv *wm8990;
-       int ret;
-
-       setup = socdev->codec_data;
-       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (codec == NULL)
-               return -ENOMEM;
-
-       wm8990 = kzalloc(sizeof(struct wm8990_priv), GFP_KERNEL);
-       if (wm8990 == NULL) {
-               kfree(codec);
-               return -ENOMEM;
-       }
-
-       snd_soc_codec_set_drvdata(codec, wm8990);
-       socdev->card->codec = codec;
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-       wm8990_socdev = socdev;
-
-       ret = -ENODEV;
-
+       int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       if (setup->i2c_address) {
-               codec->hw_write = (hw_write_t)i2c_master_send;
-               ret = wm8990_add_i2c_device(pdev, setup);
-       }
-#endif
-
+       ret = i2c_add_driver(&wm8990_i2c_driver);
        if (ret != 0) {
-               kfree(snd_soc_codec_get_drvdata(codec));
-               kfree(codec);
+               printk(KERN_ERR "Failed to register wm8990 I2C driver: %d\n",
+                      ret);
        }
+#endif
        return ret;
 }
+module_init(wm8990_modinit);
 
-/* power down chip */
-static int wm8990_remove(struct platform_device *pdev)
+static void __exit wm8990_exit(void)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec->control_data)
-               wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-       i2c_unregister_device(codec->control_data);
        i2c_del_driver(&wm8990_i2c_driver);
 #endif
-       kfree(snd_soc_codec_get_drvdata(codec));
-       kfree(codec);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8990 = {
-       .probe =        wm8990_probe,
-       .remove =       wm8990_remove,
-       .suspend =      wm8990_suspend,
-       .resume =       wm8990_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990);
-
-static int __init wm8990_modinit(void)
-{
-       return snd_soc_register_dai(&wm8990_dai);
-}
-module_init(wm8990_modinit);
-
-static void __exit wm8990_exit(void)
-{
-       snd_soc_unregister_dai(&wm8990_dai);
 }
 module_exit(wm8990_exit);
 
index 7114ddc88b4ba5fb6c2dff17712b7b05c36ac39c..77c98a4bfe9cdf34876e30866e73046d50748c85 100644 (file)
 #define WM8990_INMIXR_PWR_BIT                  2
 #define WM8990_AINRMUX_PWR_BIT                 3
 
-struct wm8990_setup_data {
-       unsigned i2c_bus;
-       unsigned short i2c_address;
-};
-
 #define WM8990_MCLK_DIV 0
 #define WM8990_DACCLK_DIV 1
 #define WM8990_ADCCLK_DIV 2
 #define WM8990_BCLK_DIV 3
 
-extern struct snd_soc_dai wm8990_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8990;
-
 #endif /* __WM8990REGISTERDEFS_H__ */
 /*------------------------------ END OF FILE ---------------------------------*/
index d8d300c6175fb2b48db37207885f9110b2a8768c..589e3fa24734c721cce8e8fac6b3f9f72a50373b 100644 (file)
@@ -229,7 +229,7 @@ struct wm8993_priv {
        u16 reg_cache[WM8993_REGISTER_COUNT];
        struct regulator_bulk_data supplies[WM8993_NUM_SUPPLIES];
        struct wm8993_platform_data pdata;
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
        int master;
        int sysclk_source;
        int tdm_slots;
@@ -367,10 +367,9 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
        return 0;
 }
 
-static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
+static int _wm8993_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
                          unsigned int Fref, unsigned int Fout)
 {
-       struct snd_soc_codec *codec = dai->codec;
        struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
        u16 reg1, reg4, reg5;
        struct _fll_div fll_div;
@@ -456,6 +455,12 @@ static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
        return 0;
 }
 
+static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
+                         unsigned int Fref, unsigned int Fout)
+{
+       return _wm8993_set_fll(dai->codec, fll_id, source, Fref, Fout);
+}
+
 static int configure_clock(struct snd_soc_codec *codec)
 {
        struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
@@ -1394,8 +1399,8 @@ static struct snd_soc_dai_ops wm8993_ops = {
                        SNDRV_PCM_FMTBIT_S24_LE |\
                        SNDRV_PCM_FMTBIT_S32_LE)
 
-struct snd_soc_dai wm8993_dai = {
-       .name = "WM8993",
+static struct snd_soc_dai_driver wm8993_dai = {
+       .name = "wm8993-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -1413,32 +1418,81 @@ struct snd_soc_dai wm8993_dai = {
        .ops = &wm8993_ops,
        .symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(wm8993_dai);
-
-static struct snd_soc_codec *wm8993_codec;
 
-static int wm8993_probe(struct platform_device *pdev)
+static int wm8993_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       struct wm8993_priv *wm8993;
-       int ret = 0;
+       struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
+       int ret, i, val;
+
+       wm8993->hubs_data.hp_startup_mode = 1;
+       wm8993->hubs_data.dcs_codes = -2;
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(wm8993->supplies); i++)
+               wm8993->supplies[i].supply = wm8993_supply_names[i];
 
-       if (!wm8993_codec) {
-               dev_err(&pdev->dev, "I2C device not yet probed\n");
-               goto err;
+       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8993->supplies),
+                                wm8993->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
        }
 
-       socdev->card->codec = wm8993_codec;
-       codec = wm8993_codec;
-       wm8993 = snd_soc_codec_get_drvdata(codec);
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies),
+                                   wm8993->supplies);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+               goto err_get;
+       }
 
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms\n");
-               goto err;
+       val = snd_soc_read(codec, WM8993_SOFTWARE_RESET);
+       if (val != wm8993_reg_defaults[WM8993_SOFTWARE_RESET]) {
+               dev_err(codec->dev, "Invalid ID register value %x\n", val);
+               ret = -EINVAL;
+               goto err_enable;
        }
 
+       ret = snd_soc_write(codec, WM8993_SOFTWARE_RESET, 0xffff);
+       if (ret != 0)
+               goto err_enable;
+
+       codec->cache_only = 1;
+
+       /* By default we're using the output mixers */
+       wm8993->class_w_users = 2;
+
+       /* Latch volume update bits and default ZC on */
+       snd_soc_update_bits(codec, WM8993_RIGHT_DAC_DIGITAL_VOLUME,
+                           WM8993_DAC_VU, WM8993_DAC_VU);
+       snd_soc_update_bits(codec, WM8993_RIGHT_ADC_DIGITAL_VOLUME,
+                           WM8993_ADC_VU, WM8993_ADC_VU);
+
+       /* Manualy manage the HPOUT sequencing for independent stereo
+        * control. */
+       snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
+                           WM8993_HPOUT1_AUTO_PU, 0);
+
+       /* Use automatic clock configuration */
+       snd_soc_update_bits(codec, WM8993_CLOCKING_4, WM8993_SR_MODE, 0);
+
+       wm_hubs_handle_analogue_pdata(codec, wm8993->pdata.lineout1_diff,
+                                     wm8993->pdata.lineout2_diff,
+                                     wm8993->pdata.lineout1fb,
+                                     wm8993->pdata.lineout2fb,
+                                     wm8993->pdata.jd_scthr,
+                                     wm8993->pdata.jd_thr,
+                                     wm8993->pdata.micbias1_lvl,
+                                     wm8993->pdata.micbias2_lvl);
+
+       ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       if (ret != 0)
+               goto err_enable;
+
        snd_soc_add_controls(codec, wm8993_snd_controls,
                             ARRAY_SIZE(wm8993_snd_controls));
        if (wm8993->pdata.num_retune_configs != 0) {
@@ -1457,36 +1511,36 @@ static int wm8993_probe(struct platform_device *pdev)
        wm_hubs_add_analogue_routes(codec, wm8993->pdata.lineout1_diff,
                                    wm8993->pdata.lineout2_diff);
 
-       return ret;
+       return 0;
 
-err:
+err_enable:
+       regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
+err_get:
+       regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
        return ret;
 }
 
-static int wm8993_remove(struct platform_device *pdev)
+static int wm8993_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
+       struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
 
+       wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
        return 0;
 }
 
 #ifdef CONFIG_PM
-static int wm8993_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8993_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
        int fll_fout = wm8993->fll_fout;
        int fll_fref  = wm8993->fll_fref;
        int ret;
 
        /* Stop the FLL in an orderly fashion */
-       ret = wm8993_set_fll(codec->dai, 0, 0, 0, 0);
+       ret = _wm8993_set_fll(codec, 0, 0, 0, 0);
        if (ret != 0) {
-               dev_err(&pdev->dev, "Failed to stop FLL\n");
+               dev_err(codec->dev, "Failed to stop FLL\n");
                return ret;
        }
 
@@ -1498,10 +1552,8 @@ static int wm8993_suspend(struct platform_device *pdev, pm_message_t state)
        return 0;
 }
 
-static int wm8993_resume(struct platform_device *pdev)
+static int wm8993_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
@@ -1515,7 +1567,7 @@ static int wm8993_resume(struct platform_device *pdev)
                wm8993->fll_fref = 0;
                wm8993->fll_fout = 0;
 
-               ret = wm8993_set_fll(codec->dai, 0, wm8993->fll_src,
+               ret = _wm8993_set_fll(codec, 0, wm8993->fll_src,
                                     fll_fref, fll_fout);
                if (ret != 0)
                        dev_err(codec->dev, "Failed to restart FLL\n");
@@ -1528,162 +1580,42 @@ static int wm8993_resume(struct platform_device *pdev)
 #define wm8993_resume NULL
 #endif
 
-struct snd_soc_codec_device soc_codec_dev_wm8993 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm8993 = {
        .probe =        wm8993_probe,
        .remove =       wm8993_remove,
        .suspend =      wm8993_suspend,
        .resume =       wm8993_resume,
+       .set_bias_level = wm8993_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm8993_reg_defaults),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8993_reg_defaults,
+       .volatile_register = wm8993_volatile,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8993);
 
-static int wm8993_i2c_probe(struct i2c_client *i2c,
-                           const struct i2c_device_id *id)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int wm8993_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
 {
        struct wm8993_priv *wm8993;
-       struct snd_soc_codec *codec;
-       unsigned int val;
        int ret;
-       int i;
-
-       if (wm8993_codec) {
-               dev_err(&i2c->dev, "A WM8993 is already registered\n");
-               return -EINVAL;
-       }
 
        wm8993 = kzalloc(sizeof(struct wm8993_priv), GFP_KERNEL);
        if (wm8993 == NULL)
                return -ENOMEM;
 
-       codec = &wm8993->codec;
-       if (i2c->dev.platform_data)
-               memcpy(&wm8993->pdata, i2c->dev.platform_data,
-                      sizeof(wm8993->pdata));
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->name = "WM8993";
-       codec->volatile_register = wm8993_volatile;
-       codec->reg_cache = wm8993->reg_cache;
-       codec->reg_cache_size = ARRAY_SIZE(wm8993->reg_cache);
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8993_set_bias_level;
-       codec->dai = &wm8993_dai;
-       codec->num_dai = 1;
-       snd_soc_codec_set_drvdata(codec, wm8993);
-
-       wm8993->hubs_data.hp_startup_mode = 1;
-       wm8993->hubs_data.dcs_codes = -2;
-
-       memcpy(wm8993->reg_cache, wm8993_reg_defaults,
-              sizeof(wm8993->reg_cache));
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
-       }
-
        i2c_set_clientdata(i2c, wm8993);
-       codec->control_data = i2c;
-       wm8993_codec = codec;
-
-       codec->dev = &i2c->dev;
-
-       for (i = 0; i < ARRAY_SIZE(wm8993->supplies); i++)
-               wm8993->supplies[i].supply = wm8993_supply_names[i];
-
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8993->supplies),
-                                wm8993->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               goto err;
-       }
-
-       ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies),
-                                   wm8993->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
-               goto err_get;
-       }
-
-       val = snd_soc_read(codec, WM8993_SOFTWARE_RESET);
-       if (val != wm8993_reg_defaults[WM8993_SOFTWARE_RESET]) {
-               dev_err(codec->dev, "Invalid ID register value %x\n", val);
-               ret = -EINVAL;
-               goto err_enable;
-       }
-
-       ret = snd_soc_write(codec, WM8993_SOFTWARE_RESET, 0xffff);
-       if (ret != 0)
-               goto err_enable;
-
-       codec->cache_only = 1;
-
-       /* By default we're using the output mixers */
-       wm8993->class_w_users = 2;
-
-       /* Latch volume update bits and default ZC on */
-       snd_soc_update_bits(codec, WM8993_RIGHT_DAC_DIGITAL_VOLUME,
-                           WM8993_DAC_VU, WM8993_DAC_VU);
-       snd_soc_update_bits(codec, WM8993_RIGHT_ADC_DIGITAL_VOLUME,
-                           WM8993_ADC_VU, WM8993_ADC_VU);
 
-       /* Manualy manage the HPOUT sequencing for independent stereo
-        * control. */
-       snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
-                           WM8993_HPOUT1_AUTO_PU, 0);
-
-       /* Use automatic clock configuration */
-       snd_soc_update_bits(codec, WM8993_CLOCKING_4, WM8993_SR_MODE, 0);
-
-       wm_hubs_handle_analogue_pdata(codec, wm8993->pdata.lineout1_diff,
-                                     wm8993->pdata.lineout2_diff,
-                                     wm8993->pdata.lineout1fb,
-                                     wm8993->pdata.lineout2fb,
-                                     wm8993->pdata.jd_scthr,
-                                     wm8993->pdata.jd_thr,
-                                     wm8993->pdata.micbias1_lvl,
-                                     wm8993->pdata.micbias2_lvl);
-                            
-       ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-       if (ret != 0)
-               goto err_enable;
-
-       wm8993_dai.dev = codec->dev;
-
-       ret = snd_soc_register_dai(&wm8993_dai);
-       if (ret != 0)
-               goto err_bias;
-
-       ret = snd_soc_register_codec(codec);
-
-       return 0;
-
-err_bias:
-       wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
-err_enable:
-       regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
-err_get:
-       regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
-err:
-       wm8993_codec = NULL;
-       kfree(wm8993);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8993, &wm8993_dai, 1);
+       if (ret < 0)
+               kfree(wm8993);
        return ret;
 }
 
-static int wm8993_i2c_remove(struct i2c_client *client)
+static __devexit int wm8993_i2c_remove(struct i2c_client *client)
 {
-       struct wm8993_priv *wm8993 = i2c_get_clientdata(client);
-
-       snd_soc_unregister_codec(&wm8993->codec);
-       snd_soc_unregister_dai(&wm8993_dai);
-
-       wm8993_set_bias_level(&wm8993->codec, SND_SOC_BIAS_OFF);
-       regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
-       kfree(wm8993);
-
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -1695,30 +1627,34 @@ MODULE_DEVICE_TABLE(i2c, wm8993_i2c_id);
 
 static struct i2c_driver wm8993_i2c_driver = {
        .driver = {
-               .name = "WM8993",
+               .name = "wm8993-codec",
                .owner = THIS_MODULE,
        },
-       .probe = wm8993_i2c_probe,
-       .remove = wm8993_i2c_remove,
+       .probe =    wm8993_i2c_probe,
+       .remove =   __devexit_p(wm8993_i2c_remove),
        .id_table = wm8993_i2c_id,
 };
-
+#endif
 
 static int __init wm8993_modinit(void)
 {
-       int ret;
-
+       int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8993_i2c_driver);
-       if (ret != 0)
-               pr_err("WM8993: Unable to register I2C driver: %d\n", ret);
-
+       if (ret != 0) {
+               pr_err("WM8993: Unable to register I2C driver: %d\n",
+                      ret);
+       }
+#endif
        return ret;
 }
 module_init(wm8993_modinit);
 
 static void __exit wm8993_exit(void)
 {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm8993_i2c_driver);
+#endif
 }
 module_exit(wm8993_exit);
 
index 30e71ca88dad1a790a59a6bad2730634f922b7ec..2184617b96117bfabac14cc7411eb24d2dadb317 100644 (file)
@@ -1,9 +1,6 @@
 #ifndef WM8993_H
 #define WM8993_H
 
-extern struct snd_soc_dai wm8993_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm8993;
-
 #define WM8993_SYSCLK_MCLK     1
 #define WM8993_SYSCLK_FLL      2
 
index 522249d5c2b463d9917e751bc0cac0fa9711c1da..0db59c3aa5d4dbb6cd2a821d29eaa75887290977 100644 (file)
@@ -36,9 +36,6 @@
 #include "wm8994.h"
 #include "wm_hubs.h"
 
-static struct snd_soc_codec *wm8994_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8994;
-
 struct fll_config {
        int src;
        int in;
@@ -71,7 +68,9 @@ struct wm8994_micdet {
 /* codec private data */
 struct wm8994_priv {
        struct wm_hubs_data hubs;
-       struct snd_soc_codec codec;
+       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];
@@ -99,1581 +98,1580 @@ struct wm8994_priv {
        struct wm8994_pdata *pdata;
 };
 
-static struct {
-       unsigned short  readable;   /* Mask of readable bits */
-       unsigned short  writable;   /* Mask of writable bits */
-       unsigned short  vol;        /* Mask of volatile bits */
+static const struct {
+       unsigned short readable;   /* Mask of readable bits */
+       unsigned short writable;   /* Mask of writable bits */
 } access_masks[] = {
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R0     - Software Reset */
-       { 0x3B37, 0x3B37, 0x0000 }, /* R1     - Power Management (1) */
-       { 0x6BF0, 0x6BF0, 0x0000 }, /* R2     - Power Management (2) */
-       { 0x3FF0, 0x3FF0, 0x0000 }, /* R3     - Power Management (3) */
-       { 0x3F3F, 0x3F3F, 0x0000 }, /* R4     - Power Management (4) */
-       { 0x3F0F, 0x3F0F, 0x0000 }, /* R5     - Power Management (5) */
-       { 0x003F, 0x003F, 0x0000 }, /* R6     - Power Management (6) */
-       { 0x0000, 0x0000, 0x0000 }, /* R7 */
-       { 0x0000, 0x0000, 0x0000 }, /* R8 */
-       { 0x0000, 0x0000, 0x0000 }, /* R9 */
-       { 0x0000, 0x0000, 0x0000 }, /* R10 */
-       { 0x0000, 0x0000, 0x0000 }, /* R11 */
-       { 0x0000, 0x0000, 0x0000 }, /* R12 */
-       { 0x0000, 0x0000, 0x0000 }, /* R13 */
-       { 0x0000, 0x0000, 0x0000 }, /* R14 */
-       { 0x0000, 0x0000, 0x0000 }, /* R15 */
-       { 0x0000, 0x0000, 0x0000 }, /* R16 */
-       { 0x0000, 0x0000, 0x0000 }, /* R17 */
-       { 0x0000, 0x0000, 0x0000 }, /* R18 */
-       { 0x0000, 0x0000, 0x0000 }, /* R19 */
-       { 0x0000, 0x0000, 0x0000 }, /* R20 */
-       { 0x01C0, 0x01C0, 0x0000 }, /* R21    - Input Mixer (1) */
-       { 0x0000, 0x0000, 0x0000 }, /* R22 */
-       { 0x0000, 0x0000, 0x0000 }, /* R23 */
-       { 0x00DF, 0x01DF, 0x0000 }, /* R24    - Left Line Input 1&2 Volume */
-       { 0x00DF, 0x01DF, 0x0000 }, /* R25    - Left Line Input 3&4 Volume */
-       { 0x00DF, 0x01DF, 0x0000 }, /* R26    - Right Line Input 1&2 Volume */
-       { 0x00DF, 0x01DF, 0x0000 }, /* R27    - Right Line Input 3&4 Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R28    - Left Output Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R29    - Right Output Volume */
-       { 0x0077, 0x0077, 0x0000 }, /* R30    - Line Outputs Volume */
-       { 0x0030, 0x0030, 0x0000 }, /* R31    - HPOUT2 Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R32    - Left OPGA Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R33    - Right OPGA Volume */
-       { 0x007F, 0x007F, 0x0000 }, /* R34    - SPKMIXL Attenuation */
-       { 0x017F, 0x017F, 0x0000 }, /* R35    - SPKMIXR Attenuation */
-       { 0x003F, 0x003F, 0x0000 }, /* R36    - SPKOUT Mixers */
-       { 0x003F, 0x003F, 0x0000 }, /* R37    - ClassD */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R38    - Speaker Volume Left */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R39    - Speaker Volume Right */
-       { 0x00FF, 0x00FF, 0x0000 }, /* R40    - Input Mixer (2) */
-       { 0x01B7, 0x01B7, 0x0000 }, /* R41    - Input Mixer (3) */
-       { 0x01B7, 0x01B7, 0x0000 }, /* R42    - Input Mixer (4) */
-       { 0x01C7, 0x01C7, 0x0000 }, /* R43    - Input Mixer (5) */
-       { 0x01C7, 0x01C7, 0x0000 }, /* R44    - Input Mixer (6) */
-       { 0x01FF, 0x01FF, 0x0000 }, /* R45    - Output Mixer (1) */
-       { 0x01FF, 0x01FF, 0x0000 }, /* R46    - Output Mixer (2) */
-       { 0x0FFF, 0x0FFF, 0x0000 }, /* R47    - Output Mixer (3) */
-       { 0x0FFF, 0x0FFF, 0x0000 }, /* R48    - Output Mixer (4) */
-       { 0x0FFF, 0x0FFF, 0x0000 }, /* R49    - Output Mixer (5) */
-       { 0x0FFF, 0x0FFF, 0x0000 }, /* R50    - Output Mixer (6) */
-       { 0x0038, 0x0038, 0x0000 }, /* R51    - HPOUT2 Mixer */
-       { 0x0077, 0x0077, 0x0000 }, /* R52    - Line Mixer (1) */
-       { 0x0077, 0x0077, 0x0000 }, /* R53    - Line Mixer (2) */
-       { 0x03FF, 0x03FF, 0x0000 }, /* R54    - Speaker Mixer */
-       { 0x00C1, 0x00C1, 0x0000 }, /* R55    - Additional Control */
-       { 0x00F0, 0x00F0, 0x0000 }, /* R56    - AntiPOP (1) */
-       { 0x01EF, 0x01EF, 0x0000 }, /* R57    - AntiPOP (2) */
-       { 0x00FF, 0x00FF, 0x0000 }, /* R58    - MICBIAS */
-       { 0x000F, 0x000F, 0x0000 }, /* R59    - LDO 1 */
-       { 0x0007, 0x0007, 0x0000 }, /* R60    - LDO 2 */
-       { 0x0000, 0x0000, 0x0000 }, /* R61 */
-       { 0x0000, 0x0000, 0x0000 }, /* R62 */
-       { 0x0000, 0x0000, 0x0000 }, /* R63 */
-       { 0x0000, 0x0000, 0x0000 }, /* R64 */
-       { 0x0000, 0x0000, 0x0000 }, /* R65 */
-       { 0x0000, 0x0000, 0x0000 }, /* R66 */
-       { 0x0000, 0x0000, 0x0000 }, /* R67 */
-       { 0x0000, 0x0000, 0x0000 }, /* R68 */
-       { 0x0000, 0x0000, 0x0000 }, /* R69 */
-       { 0x0000, 0x0000, 0x0000 }, /* R70 */
-       { 0x0000, 0x0000, 0x0000 }, /* R71 */
-       { 0x0000, 0x0000, 0x0000 }, /* R72 */
-       { 0x0000, 0x0000, 0x0000 }, /* R73 */
-       { 0x0000, 0x0000, 0x0000 }, /* R74 */
-       { 0x0000, 0x0000, 0x0000 }, /* R75 */
-       { 0x8000, 0x8000, 0x0000 }, /* R76    - Charge Pump (1) */
-       { 0x0000, 0x0000, 0x0000 }, /* R77 */
-       { 0x0000, 0x0000, 0x0000 }, /* R78 */
-       { 0x0000, 0x0000, 0x0000 }, /* R79 */
-       { 0x0000, 0x0000, 0x0000 }, /* R80 */
-       { 0x0301, 0x0301, 0x0000 }, /* R81    - Class W (1) */
-       { 0x0000, 0x0000, 0x0000 }, /* R82 */
-       { 0x0000, 0x0000, 0x0000 }, /* R83 */
-       { 0x333F, 0x333F, 0x0000 }, /* R84    - DC Servo (1) */
-       { 0x0FEF, 0x0FEF, 0x0000 }, /* R85    - DC Servo (2) */
-       { 0x0000, 0x0000, 0x0000 }, /* R86 */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R87    - DC Servo (4) */
-       { 0x0333, 0x0000, 0x0000 }, /* R88    - DC Servo Readback */
-       { 0x0000, 0x0000, 0x0000 }, /* R89 */
-       { 0x0000, 0x0000, 0x0000 }, /* R90 */
-       { 0x0000, 0x0000, 0x0000 }, /* R91 */
-       { 0x0000, 0x0000, 0x0000 }, /* R92 */
-       { 0x0000, 0x0000, 0x0000 }, /* R93 */
-       { 0x0000, 0x0000, 0x0000 }, /* R94 */
-       { 0x0000, 0x0000, 0x0000 }, /* R95 */
-       { 0x00EE, 0x00EE, 0x0000 }, /* R96    - Analogue HP (1) */
-       { 0x0000, 0x0000, 0x0000 }, /* R97 */
-       { 0x0000, 0x0000, 0x0000 }, /* R98 */
-       { 0x0000, 0x0000, 0x0000 }, /* R99 */
-       { 0x0000, 0x0000, 0x0000 }, /* R100 */
-       { 0x0000, 0x0000, 0x0000 }, /* R101 */
-       { 0x0000, 0x0000, 0x0000 }, /* R102 */
-       { 0x0000, 0x0000, 0x0000 }, /* R103 */
-       { 0x0000, 0x0000, 0x0000 }, /* R104 */
-       { 0x0000, 0x0000, 0x0000 }, /* R105 */
-       { 0x0000, 0x0000, 0x0000 }, /* R106 */
-       { 0x0000, 0x0000, 0x0000 }, /* R107 */
-       { 0x0000, 0x0000, 0x0000 }, /* R108 */
-       { 0x0000, 0x0000, 0x0000 }, /* R109 */
-       { 0x0000, 0x0000, 0x0000 }, /* R110 */
-       { 0x0000, 0x0000, 0x0000 }, /* R111 */
-       { 0x0000, 0x0000, 0x0000 }, /* R112 */
-       { 0x0000, 0x0000, 0x0000 }, /* R113 */
-       { 0x0000, 0x0000, 0x0000 }, /* R114 */
-       { 0x0000, 0x0000, 0x0000 }, /* R115 */
-       { 0x0000, 0x0000, 0x0000 }, /* R116 */
-       { 0x0000, 0x0000, 0x0000 }, /* R117 */
-       { 0x0000, 0x0000, 0x0000 }, /* R118 */
-       { 0x0000, 0x0000, 0x0000 }, /* R119 */
-       { 0x0000, 0x0000, 0x0000 }, /* R120 */
-       { 0x0000, 0x0000, 0x0000 }, /* R121 */
-       { 0x0000, 0x0000, 0x0000 }, /* R122 */
-       { 0x0000, 0x0000, 0x0000 }, /* R123 */
-       { 0x0000, 0x0000, 0x0000 }, /* R124 */
-       { 0x0000, 0x0000, 0x0000 }, /* R125 */
-       { 0x0000, 0x0000, 0x0000 }, /* R126 */
-       { 0x0000, 0x0000, 0x0000 }, /* R127 */
-       { 0x0000, 0x0000, 0x0000 }, /* R128 */
-       { 0x0000, 0x0000, 0x0000 }, /* R129 */
-       { 0x0000, 0x0000, 0x0000 }, /* R130 */
-       { 0x0000, 0x0000, 0x0000 }, /* R131 */
-       { 0x0000, 0x0000, 0x0000 }, /* R132 */
-       { 0x0000, 0x0000, 0x0000 }, /* R133 */
-       { 0x0000, 0x0000, 0x0000 }, /* R134 */
-       { 0x0000, 0x0000, 0x0000 }, /* R135 */
-       { 0x0000, 0x0000, 0x0000 }, /* R136 */
-       { 0x0000, 0x0000, 0x0000 }, /* R137 */
-       { 0x0000, 0x0000, 0x0000 }, /* R138 */
-       { 0x0000, 0x0000, 0x0000 }, /* R139 */
-       { 0x0000, 0x0000, 0x0000 }, /* R140 */
-       { 0x0000, 0x0000, 0x0000 }, /* R141 */
-       { 0x0000, 0x0000, 0x0000 }, /* R142 */
-       { 0x0000, 0x0000, 0x0000 }, /* R143 */
-       { 0x0000, 0x0000, 0x0000 }, /* R144 */
-       { 0x0000, 0x0000, 0x0000 }, /* R145 */
-       { 0x0000, 0x0000, 0x0000 }, /* R146 */
-       { 0x0000, 0x0000, 0x0000 }, /* R147 */
-       { 0x0000, 0x0000, 0x0000 }, /* R148 */
-       { 0x0000, 0x0000, 0x0000 }, /* R149 */
-       { 0x0000, 0x0000, 0x0000 }, /* R150 */
-       { 0x0000, 0x0000, 0x0000 }, /* R151 */
-       { 0x0000, 0x0000, 0x0000 }, /* R152 */
-       { 0x0000, 0x0000, 0x0000 }, /* R153 */
-       { 0x0000, 0x0000, 0x0000 }, /* R154 */
-       { 0x0000, 0x0000, 0x0000 }, /* R155 */
-       { 0x0000, 0x0000, 0x0000 }, /* R156 */
-       { 0x0000, 0x0000, 0x0000 }, /* R157 */
-       { 0x0000, 0x0000, 0x0000 }, /* R158 */
-       { 0x0000, 0x0000, 0x0000 }, /* R159 */
-       { 0x0000, 0x0000, 0x0000 }, /* R160 */
-       { 0x0000, 0x0000, 0x0000 }, /* R161 */
-       { 0x0000, 0x0000, 0x0000 }, /* R162 */
-       { 0x0000, 0x0000, 0x0000 }, /* R163 */
-       { 0x0000, 0x0000, 0x0000 }, /* R164 */
-       { 0x0000, 0x0000, 0x0000 }, /* R165 */
-       { 0x0000, 0x0000, 0x0000 }, /* R166 */
-       { 0x0000, 0x0000, 0x0000 }, /* R167 */
-       { 0x0000, 0x0000, 0x0000 }, /* R168 */
-       { 0x0000, 0x0000, 0x0000 }, /* R169 */
-       { 0x0000, 0x0000, 0x0000 }, /* R170 */
-       { 0x0000, 0x0000, 0x0000 }, /* R171 */
-       { 0x0000, 0x0000, 0x0000 }, /* R172 */
-       { 0x0000, 0x0000, 0x0000 }, /* R173 */
-       { 0x0000, 0x0000, 0x0000 }, /* R174 */
-       { 0x0000, 0x0000, 0x0000 }, /* R175 */
-       { 0x0000, 0x0000, 0x0000 }, /* R176 */
-       { 0x0000, 0x0000, 0x0000 }, /* R177 */
-       { 0x0000, 0x0000, 0x0000 }, /* R178 */
-       { 0x0000, 0x0000, 0x0000 }, /* R179 */
-       { 0x0000, 0x0000, 0x0000 }, /* R180 */
-       { 0x0000, 0x0000, 0x0000 }, /* R181 */
-       { 0x0000, 0x0000, 0x0000 }, /* R182 */
-       { 0x0000, 0x0000, 0x0000 }, /* R183 */
-       { 0x0000, 0x0000, 0x0000 }, /* R184 */
-       { 0x0000, 0x0000, 0x0000 }, /* R185 */
-       { 0x0000, 0x0000, 0x0000 }, /* R186 */
-       { 0x0000, 0x0000, 0x0000 }, /* R187 */
-       { 0x0000, 0x0000, 0x0000 }, /* R188 */
-       { 0x0000, 0x0000, 0x0000 }, /* R189 */
-       { 0x0000, 0x0000, 0x0000 }, /* R190 */
-       { 0x0000, 0x0000, 0x0000 }, /* R191 */
-       { 0x0000, 0x0000, 0x0000 }, /* R192 */
-       { 0x0000, 0x0000, 0x0000 }, /* R193 */
-       { 0x0000, 0x0000, 0x0000 }, /* R194 */
-       { 0x0000, 0x0000, 0x0000 }, /* R195 */
-       { 0x0000, 0x0000, 0x0000 }, /* R196 */
-       { 0x0000, 0x0000, 0x0000 }, /* R197 */
-       { 0x0000, 0x0000, 0x0000 }, /* R198 */
-       { 0x0000, 0x0000, 0x0000 }, /* R199 */
-       { 0x0000, 0x0000, 0x0000 }, /* R200 */
-       { 0x0000, 0x0000, 0x0000 }, /* R201 */
-       { 0x0000, 0x0000, 0x0000 }, /* R202 */
-       { 0x0000, 0x0000, 0x0000 }, /* R203 */
-       { 0x0000, 0x0000, 0x0000 }, /* R204 */
-       { 0x0000, 0x0000, 0x0000 }, /* R205 */
-       { 0x0000, 0x0000, 0x0000 }, /* R206 */
-       { 0x0000, 0x0000, 0x0000 }, /* R207 */
-       { 0x0000, 0x0000, 0x0000 }, /* R208 */
-       { 0x0000, 0x0000, 0x0000 }, /* R209 */
-       { 0x0000, 0x0000, 0x0000 }, /* R210 */
-       { 0x0000, 0x0000, 0x0000 }, /* R211 */
-       { 0x0000, 0x0000, 0x0000 }, /* R212 */
-       { 0x0000, 0x0000, 0x0000 }, /* R213 */
-       { 0x0000, 0x0000, 0x0000 }, /* R214 */
-       { 0x0000, 0x0000, 0x0000 }, /* R215 */
-       { 0x0000, 0x0000, 0x0000 }, /* R216 */
-       { 0x0000, 0x0000, 0x0000 }, /* R217 */
-       { 0x0000, 0x0000, 0x0000 }, /* R218 */
-       { 0x0000, 0x0000, 0x0000 }, /* R219 */
-       { 0x0000, 0x0000, 0x0000 }, /* R220 */
-       { 0x0000, 0x0000, 0x0000 }, /* R221 */
-       { 0x0000, 0x0000, 0x0000 }, /* R222 */
-       { 0x0000, 0x0000, 0x0000 }, /* R223 */
-       { 0x0000, 0x0000, 0x0000 }, /* R224 */
-       { 0x0000, 0x0000, 0x0000 }, /* R225 */
-       { 0x0000, 0x0000, 0x0000 }, /* R226 */
-       { 0x0000, 0x0000, 0x0000 }, /* R227 */
-       { 0x0000, 0x0000, 0x0000 }, /* R228 */
-       { 0x0000, 0x0000, 0x0000 }, /* R229 */
-       { 0x0000, 0x0000, 0x0000 }, /* R230 */
-       { 0x0000, 0x0000, 0x0000 }, /* R231 */
-       { 0x0000, 0x0000, 0x0000 }, /* R232 */
-       { 0x0000, 0x0000, 0x0000 }, /* R233 */
-       { 0x0000, 0x0000, 0x0000 }, /* R234 */
-       { 0x0000, 0x0000, 0x0000 }, /* R235 */
-       { 0x0000, 0x0000, 0x0000 }, /* R236 */
-       { 0x0000, 0x0000, 0x0000 }, /* R237 */
-       { 0x0000, 0x0000, 0x0000 }, /* R238 */
-       { 0x0000, 0x0000, 0x0000 }, /* R239 */
-       { 0x0000, 0x0000, 0x0000 }, /* R240 */
-       { 0x0000, 0x0000, 0x0000 }, /* R241 */
-       { 0x0000, 0x0000, 0x0000 }, /* R242 */
-       { 0x0000, 0x0000, 0x0000 }, /* R243 */
-       { 0x0000, 0x0000, 0x0000 }, /* R244 */
-       { 0x0000, 0x0000, 0x0000 }, /* R245 */
-       { 0x0000, 0x0000, 0x0000 }, /* R246 */
-       { 0x0000, 0x0000, 0x0000 }, /* R247 */
-       { 0x0000, 0x0000, 0x0000 }, /* R248 */
-       { 0x0000, 0x0000, 0x0000 }, /* R249 */
-       { 0x0000, 0x0000, 0x0000 }, /* R250 */
-       { 0x0000, 0x0000, 0x0000 }, /* R251 */
-       { 0x0000, 0x0000, 0x0000 }, /* R252 */
-       { 0x0000, 0x0000, 0x0000 }, /* R253 */
-       { 0x0000, 0x0000, 0x0000 }, /* R254 */
-       { 0x0000, 0x0000, 0x0000 }, /* R255 */
-       { 0x000F, 0x0000, 0x0000 }, /* R256   - Chip Revision */
-       { 0x0074, 0x0074, 0x0000 }, /* R257   - Control Interface */
-       { 0x0000, 0x0000, 0x0000 }, /* R258 */
-       { 0x0000, 0x0000, 0x0000 }, /* R259 */
-       { 0x0000, 0x0000, 0x0000 }, /* R260 */
-       { 0x0000, 0x0000, 0x0000 }, /* R261 */
-       { 0x0000, 0x0000, 0x0000 }, /* R262 */
-       { 0x0000, 0x0000, 0x0000 }, /* R263 */
-       { 0x0000, 0x0000, 0x0000 }, /* R264 */
-       { 0x0000, 0x0000, 0x0000 }, /* R265 */
-       { 0x0000, 0x0000, 0x0000 }, /* R266 */
-       { 0x0000, 0x0000, 0x0000 }, /* R267 */
-       { 0x0000, 0x0000, 0x0000 }, /* R268 */
-       { 0x0000, 0x0000, 0x0000 }, /* R269 */
-       { 0x0000, 0x0000, 0x0000 }, /* R270 */
-       { 0x0000, 0x0000, 0x0000 }, /* R271 */
-       { 0x807F, 0x837F, 0x0000 }, /* R272   - Write Sequencer Ctrl (1) */
-       { 0x017F, 0x0000, 0x0000 }, /* R273   - Write Sequencer Ctrl (2) */
-       { 0x0000, 0x0000, 0x0000 }, /* R274 */
-       { 0x0000, 0x0000, 0x0000 }, /* R275 */
-       { 0x0000, 0x0000, 0x0000 }, /* R276 */
-       { 0x0000, 0x0000, 0x0000 }, /* R277 */
-       { 0x0000, 0x0000, 0x0000 }, /* R278 */
-       { 0x0000, 0x0000, 0x0000 }, /* R279 */
-       { 0x0000, 0x0000, 0x0000 }, /* R280 */
-       { 0x0000, 0x0000, 0x0000 }, /* R281 */
-       { 0x0000, 0x0000, 0x0000 }, /* R282 */
-       { 0x0000, 0x0000, 0x0000 }, /* R283 */
-       { 0x0000, 0x0000, 0x0000 }, /* R284 */
-       { 0x0000, 0x0000, 0x0000 }, /* R285 */
-       { 0x0000, 0x0000, 0x0000 }, /* R286 */
-       { 0x0000, 0x0000, 0x0000 }, /* R287 */
-       { 0x0000, 0x0000, 0x0000 }, /* R288 */
-       { 0x0000, 0x0000, 0x0000 }, /* R289 */
-       { 0x0000, 0x0000, 0x0000 }, /* R290 */
-       { 0x0000, 0x0000, 0x0000 }, /* R291 */
-       { 0x0000, 0x0000, 0x0000 }, /* R292 */
-       { 0x0000, 0x0000, 0x0000 }, /* R293 */
-       { 0x0000, 0x0000, 0x0000 }, /* R294 */
-       { 0x0000, 0x0000, 0x0000 }, /* R295 */
-       { 0x0000, 0x0000, 0x0000 }, /* R296 */
-       { 0x0000, 0x0000, 0x0000 }, /* R297 */
-       { 0x0000, 0x0000, 0x0000 }, /* R298 */
-       { 0x0000, 0x0000, 0x0000 }, /* R299 */
-       { 0x0000, 0x0000, 0x0000 }, /* R300 */
-       { 0x0000, 0x0000, 0x0000 }, /* R301 */
-       { 0x0000, 0x0000, 0x0000 }, /* R302 */
-       { 0x0000, 0x0000, 0x0000 }, /* R303 */
-       { 0x0000, 0x0000, 0x0000 }, /* R304 */
-       { 0x0000, 0x0000, 0x0000 }, /* R305 */
-       { 0x0000, 0x0000, 0x0000 }, /* R306 */
-       { 0x0000, 0x0000, 0x0000 }, /* R307 */
-       { 0x0000, 0x0000, 0x0000 }, /* R308 */
-       { 0x0000, 0x0000, 0x0000 }, /* R309 */
-       { 0x0000, 0x0000, 0x0000 }, /* R310 */
-       { 0x0000, 0x0000, 0x0000 }, /* R311 */
-       { 0x0000, 0x0000, 0x0000 }, /* R312 */
-       { 0x0000, 0x0000, 0x0000 }, /* R313 */
-       { 0x0000, 0x0000, 0x0000 }, /* R314 */
-       { 0x0000, 0x0000, 0x0000 }, /* R315 */
-       { 0x0000, 0x0000, 0x0000 }, /* R316 */
-       { 0x0000, 0x0000, 0x0000 }, /* R317 */
-       { 0x0000, 0x0000, 0x0000 }, /* R318 */
-       { 0x0000, 0x0000, 0x0000 }, /* R319 */
-       { 0x0000, 0x0000, 0x0000 }, /* R320 */
-       { 0x0000, 0x0000, 0x0000 }, /* R321 */
-       { 0x0000, 0x0000, 0x0000 }, /* R322 */
-       { 0x0000, 0x0000, 0x0000 }, /* R323 */
-       { 0x0000, 0x0000, 0x0000 }, /* R324 */
-       { 0x0000, 0x0000, 0x0000 }, /* R325 */
-       { 0x0000, 0x0000, 0x0000 }, /* R326 */
-       { 0x0000, 0x0000, 0x0000 }, /* R327 */
-       { 0x0000, 0x0000, 0x0000 }, /* R328 */
-       { 0x0000, 0x0000, 0x0000 }, /* R329 */
-       { 0x0000, 0x0000, 0x0000 }, /* R330 */
-       { 0x0000, 0x0000, 0x0000 }, /* R331 */
-       { 0x0000, 0x0000, 0x0000 }, /* R332 */
-       { 0x0000, 0x0000, 0x0000 }, /* R333 */
-       { 0x0000, 0x0000, 0x0000 }, /* R334 */
-       { 0x0000, 0x0000, 0x0000 }, /* R335 */
-       { 0x0000, 0x0000, 0x0000 }, /* R336 */
-       { 0x0000, 0x0000, 0x0000 }, /* R337 */
-       { 0x0000, 0x0000, 0x0000 }, /* R338 */
-       { 0x0000, 0x0000, 0x0000 }, /* R339 */
-       { 0x0000, 0x0000, 0x0000 }, /* R340 */
-       { 0x0000, 0x0000, 0x0000 }, /* R341 */
-       { 0x0000, 0x0000, 0x0000 }, /* R342 */
-       { 0x0000, 0x0000, 0x0000 }, /* R343 */
-       { 0x0000, 0x0000, 0x0000 }, /* R344 */
-       { 0x0000, 0x0000, 0x0000 }, /* R345 */
-       { 0x0000, 0x0000, 0x0000 }, /* R346 */
-       { 0x0000, 0x0000, 0x0000 }, /* R347 */
-       { 0x0000, 0x0000, 0x0000 }, /* R348 */
-       { 0x0000, 0x0000, 0x0000 }, /* R349 */
-       { 0x0000, 0x0000, 0x0000 }, /* R350 */
-       { 0x0000, 0x0000, 0x0000 }, /* R351 */
-       { 0x0000, 0x0000, 0x0000 }, /* R352 */
-       { 0x0000, 0x0000, 0x0000 }, /* R353 */
-       { 0x0000, 0x0000, 0x0000 }, /* R354 */
-       { 0x0000, 0x0000, 0x0000 }, /* R355 */
-       { 0x0000, 0x0000, 0x0000 }, /* R356 */
-       { 0x0000, 0x0000, 0x0000 }, /* R357 */
-       { 0x0000, 0x0000, 0x0000 }, /* R358 */
-       { 0x0000, 0x0000, 0x0000 }, /* R359 */
-       { 0x0000, 0x0000, 0x0000 }, /* R360 */
-       { 0x0000, 0x0000, 0x0000 }, /* R361 */
-       { 0x0000, 0x0000, 0x0000 }, /* R362 */
-       { 0x0000, 0x0000, 0x0000 }, /* R363 */
-       { 0x0000, 0x0000, 0x0000 }, /* R364 */
-       { 0x0000, 0x0000, 0x0000 }, /* R365 */
-       { 0x0000, 0x0000, 0x0000 }, /* R366 */
-       { 0x0000, 0x0000, 0x0000 }, /* R367 */
-       { 0x0000, 0x0000, 0x0000 }, /* R368 */
-       { 0x0000, 0x0000, 0x0000 }, /* R369 */
-       { 0x0000, 0x0000, 0x0000 }, /* R370 */
-       { 0x0000, 0x0000, 0x0000 }, /* R371 */
-       { 0x0000, 0x0000, 0x0000 }, /* R372 */
-       { 0x0000, 0x0000, 0x0000 }, /* R373 */
-       { 0x0000, 0x0000, 0x0000 }, /* R374 */
-       { 0x0000, 0x0000, 0x0000 }, /* R375 */
-       { 0x0000, 0x0000, 0x0000 }, /* R376 */
-       { 0x0000, 0x0000, 0x0000 }, /* R377 */
-       { 0x0000, 0x0000, 0x0000 }, /* R378 */
-       { 0x0000, 0x0000, 0x0000 }, /* R379 */
-       { 0x0000, 0x0000, 0x0000 }, /* R380 */
-       { 0x0000, 0x0000, 0x0000 }, /* R381 */
-       { 0x0000, 0x0000, 0x0000 }, /* R382 */
-       { 0x0000, 0x0000, 0x0000 }, /* R383 */
-       { 0x0000, 0x0000, 0x0000 }, /* R384 */
-       { 0x0000, 0x0000, 0x0000 }, /* R385 */
-       { 0x0000, 0x0000, 0x0000 }, /* R386 */
-       { 0x0000, 0x0000, 0x0000 }, /* R387 */
-       { 0x0000, 0x0000, 0x0000 }, /* R388 */
-       { 0x0000, 0x0000, 0x0000 }, /* R389 */
-       { 0x0000, 0x0000, 0x0000 }, /* R390 */
-       { 0x0000, 0x0000, 0x0000 }, /* R391 */
-       { 0x0000, 0x0000, 0x0000 }, /* R392 */
-       { 0x0000, 0x0000, 0x0000 }, /* R393 */
-       { 0x0000, 0x0000, 0x0000 }, /* R394 */
-       { 0x0000, 0x0000, 0x0000 }, /* R395 */
-       { 0x0000, 0x0000, 0x0000 }, /* R396 */
-       { 0x0000, 0x0000, 0x0000 }, /* R397 */
-       { 0x0000, 0x0000, 0x0000 }, /* R398 */
-       { 0x0000, 0x0000, 0x0000 }, /* R399 */
-       { 0x0000, 0x0000, 0x0000 }, /* R400 */
-       { 0x0000, 0x0000, 0x0000 }, /* R401 */
-       { 0x0000, 0x0000, 0x0000 }, /* R402 */
-       { 0x0000, 0x0000, 0x0000 }, /* R403 */
-       { 0x0000, 0x0000, 0x0000 }, /* R404 */
-       { 0x0000, 0x0000, 0x0000 }, /* R405 */
-       { 0x0000, 0x0000, 0x0000 }, /* R406 */
-       { 0x0000, 0x0000, 0x0000 }, /* R407 */
-       { 0x0000, 0x0000, 0x0000 }, /* R408 */
-       { 0x0000, 0x0000, 0x0000 }, /* R409 */
-       { 0x0000, 0x0000, 0x0000 }, /* R410 */
-       { 0x0000, 0x0000, 0x0000 }, /* R411 */
-       { 0x0000, 0x0000, 0x0000 }, /* R412 */
-       { 0x0000, 0x0000, 0x0000 }, /* R413 */
-       { 0x0000, 0x0000, 0x0000 }, /* R414 */
-       { 0x0000, 0x0000, 0x0000 }, /* R415 */
-       { 0x0000, 0x0000, 0x0000 }, /* R416 */
-       { 0x0000, 0x0000, 0x0000 }, /* R417 */
-       { 0x0000, 0x0000, 0x0000 }, /* R418 */
-       { 0x0000, 0x0000, 0x0000 }, /* R419 */
-       { 0x0000, 0x0000, 0x0000 }, /* R420 */
-       { 0x0000, 0x0000, 0x0000 }, /* R421 */
-       { 0x0000, 0x0000, 0x0000 }, /* R422 */
-       { 0x0000, 0x0000, 0x0000 }, /* R423 */
-       { 0x0000, 0x0000, 0x0000 }, /* R424 */
-       { 0x0000, 0x0000, 0x0000 }, /* R425 */
-       { 0x0000, 0x0000, 0x0000 }, /* R426 */
-       { 0x0000, 0x0000, 0x0000 }, /* R427 */
-       { 0x0000, 0x0000, 0x0000 }, /* R428 */
-       { 0x0000, 0x0000, 0x0000 }, /* R429 */
-       { 0x0000, 0x0000, 0x0000 }, /* R430 */
-       { 0x0000, 0x0000, 0x0000 }, /* R431 */
-       { 0x0000, 0x0000, 0x0000 }, /* R432 */
-       { 0x0000, 0x0000, 0x0000 }, /* R433 */
-       { 0x0000, 0x0000, 0x0000 }, /* R434 */
-       { 0x0000, 0x0000, 0x0000 }, /* R435 */
-       { 0x0000, 0x0000, 0x0000 }, /* R436 */
-       { 0x0000, 0x0000, 0x0000 }, /* R437 */
-       { 0x0000, 0x0000, 0x0000 }, /* R438 */
-       { 0x0000, 0x0000, 0x0000 }, /* R439 */
-       { 0x0000, 0x0000, 0x0000 }, /* R440 */
-       { 0x0000, 0x0000, 0x0000 }, /* R441 */
-       { 0x0000, 0x0000, 0x0000 }, /* R442 */
-       { 0x0000, 0x0000, 0x0000 }, /* R443 */
-       { 0x0000, 0x0000, 0x0000 }, /* R444 */
-       { 0x0000, 0x0000, 0x0000 }, /* R445 */
-       { 0x0000, 0x0000, 0x0000 }, /* R446 */
-       { 0x0000, 0x0000, 0x0000 }, /* R447 */
-       { 0x0000, 0x0000, 0x0000 }, /* R448 */
-       { 0x0000, 0x0000, 0x0000 }, /* R449 */
-       { 0x0000, 0x0000, 0x0000 }, /* R450 */
-       { 0x0000, 0x0000, 0x0000 }, /* R451 */
-       { 0x0000, 0x0000, 0x0000 }, /* R452 */
-       { 0x0000, 0x0000, 0x0000 }, /* R453 */
-       { 0x0000, 0x0000, 0x0000 }, /* R454 */
-       { 0x0000, 0x0000, 0x0000 }, /* R455 */
-       { 0x0000, 0x0000, 0x0000 }, /* R456 */
-       { 0x0000, 0x0000, 0x0000 }, /* R457 */
-       { 0x0000, 0x0000, 0x0000 }, /* R458 */
-       { 0x0000, 0x0000, 0x0000 }, /* R459 */
-       { 0x0000, 0x0000, 0x0000 }, /* R460 */
-       { 0x0000, 0x0000, 0x0000 }, /* R461 */
-       { 0x0000, 0x0000, 0x0000 }, /* R462 */
-       { 0x0000, 0x0000, 0x0000 }, /* R463 */
-       { 0x0000, 0x0000, 0x0000 }, /* R464 */
-       { 0x0000, 0x0000, 0x0000 }, /* R465 */
-       { 0x0000, 0x0000, 0x0000 }, /* R466 */
-       { 0x0000, 0x0000, 0x0000 }, /* R467 */
-       { 0x0000, 0x0000, 0x0000 }, /* R468 */
-       { 0x0000, 0x0000, 0x0000 }, /* R469 */
-       { 0x0000, 0x0000, 0x0000 }, /* R470 */
-       { 0x0000, 0x0000, 0x0000 }, /* R471 */
-       { 0x0000, 0x0000, 0x0000 }, /* R472 */
-       { 0x0000, 0x0000, 0x0000 }, /* R473 */
-       { 0x0000, 0x0000, 0x0000 }, /* R474 */
-       { 0x0000, 0x0000, 0x0000 }, /* R475 */
-       { 0x0000, 0x0000, 0x0000 }, /* R476 */
-       { 0x0000, 0x0000, 0x0000 }, /* R477 */
-       { 0x0000, 0x0000, 0x0000 }, /* R478 */
-       { 0x0000, 0x0000, 0x0000 }, /* R479 */
-       { 0x0000, 0x0000, 0x0000 }, /* R480 */
-       { 0x0000, 0x0000, 0x0000 }, /* R481 */
-       { 0x0000, 0x0000, 0x0000 }, /* R482 */
-       { 0x0000, 0x0000, 0x0000 }, /* R483 */
-       { 0x0000, 0x0000, 0x0000 }, /* R484 */
-       { 0x0000, 0x0000, 0x0000 }, /* R485 */
-       { 0x0000, 0x0000, 0x0000 }, /* R486 */
-       { 0x0000, 0x0000, 0x0000 }, /* R487 */
-       { 0x0000, 0x0000, 0x0000 }, /* R488 */
-       { 0x0000, 0x0000, 0x0000 }, /* R489 */
-       { 0x0000, 0x0000, 0x0000 }, /* R490 */
-       { 0x0000, 0x0000, 0x0000 }, /* R491 */
-       { 0x0000, 0x0000, 0x0000 }, /* R492 */
-       { 0x0000, 0x0000, 0x0000 }, /* R493 */
-       { 0x0000, 0x0000, 0x0000 }, /* R494 */
-       { 0x0000, 0x0000, 0x0000 }, /* R495 */
-       { 0x0000, 0x0000, 0x0000 }, /* R496 */
-       { 0x0000, 0x0000, 0x0000 }, /* R497 */
-       { 0x0000, 0x0000, 0x0000 }, /* R498 */
-       { 0x0000, 0x0000, 0x0000 }, /* R499 */
-       { 0x0000, 0x0000, 0x0000 }, /* R500 */
-       { 0x0000, 0x0000, 0x0000 }, /* R501 */
-       { 0x0000, 0x0000, 0x0000 }, /* R502 */
-       { 0x0000, 0x0000, 0x0000 }, /* R503 */
-       { 0x0000, 0x0000, 0x0000 }, /* R504 */
-       { 0x0000, 0x0000, 0x0000 }, /* R505 */
-       { 0x0000, 0x0000, 0x0000 }, /* R506 */
-       { 0x0000, 0x0000, 0x0000 }, /* R507 */
-       { 0x0000, 0x0000, 0x0000 }, /* R508 */
-       { 0x0000, 0x0000, 0x0000 }, /* R509 */
-       { 0x0000, 0x0000, 0x0000 }, /* R510 */
-       { 0x0000, 0x0000, 0x0000 }, /* R511 */
-       { 0x001F, 0x001F, 0x0000 }, /* R512   - AIF1 Clocking (1) */
-       { 0x003F, 0x003F, 0x0000 }, /* R513   - AIF1 Clocking (2) */
-       { 0x0000, 0x0000, 0x0000 }, /* R514 */
-       { 0x0000, 0x0000, 0x0000 }, /* R515 */
-       { 0x001F, 0x001F, 0x0000 }, /* R516   - AIF2 Clocking (1) */
-       { 0x003F, 0x003F, 0x0000 }, /* R517   - AIF2 Clocking (2) */
-       { 0x0000, 0x0000, 0x0000 }, /* R518 */
-       { 0x0000, 0x0000, 0x0000 }, /* R519 */
-       { 0x001F, 0x001F, 0x0000 }, /* R520   - Clocking (1) */
-       { 0x0777, 0x0777, 0x0000 }, /* R521   - Clocking (2) */
-       { 0x0000, 0x0000, 0x0000 }, /* R522 */
-       { 0x0000, 0x0000, 0x0000 }, /* R523 */
-       { 0x0000, 0x0000, 0x0000 }, /* R524 */
-       { 0x0000, 0x0000, 0x0000 }, /* R525 */
-       { 0x0000, 0x0000, 0x0000 }, /* R526 */
-       { 0x0000, 0x0000, 0x0000 }, /* R527 */
-       { 0x00FF, 0x00FF, 0x0000 }, /* R528   - AIF1 Rate */
-       { 0x00FF, 0x00FF, 0x0000 }, /* R529   - AIF2 Rate */
-       { 0x000F, 0x0000, 0x0000 }, /* R530   - Rate Status */
-       { 0x0000, 0x0000, 0x0000 }, /* R531 */
-       { 0x0000, 0x0000, 0x0000 }, /* R532 */
-       { 0x0000, 0x0000, 0x0000 }, /* R533 */
-       { 0x0000, 0x0000, 0x0000 }, /* R534 */
-       { 0x0000, 0x0000, 0x0000 }, /* R535 */
-       { 0x0000, 0x0000, 0x0000 }, /* R536 */
-       { 0x0000, 0x0000, 0x0000 }, /* R537 */
-       { 0x0000, 0x0000, 0x0000 }, /* R538 */
-       { 0x0000, 0x0000, 0x0000 }, /* R539 */
-       { 0x0000, 0x0000, 0x0000 }, /* R540 */
-       { 0x0000, 0x0000, 0x0000 }, /* R541 */
-       { 0x0000, 0x0000, 0x0000 }, /* R542 */
-       { 0x0000, 0x0000, 0x0000 }, /* R543 */
-       { 0x0007, 0x0007, 0x0000 }, /* R544   - FLL1 Control (1) */
-       { 0x3F77, 0x3F77, 0x0000 }, /* R545   - FLL1 Control (2) */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R546   - FLL1 Control (3) */
-       { 0x7FEF, 0x7FEF, 0x0000 }, /* R547   - FLL1 Control (4) */
-       { 0x1FDB, 0x1FDB, 0x0000 }, /* R548   - FLL1 Control (5) */
-       { 0x0000, 0x0000, 0x0000 }, /* R549 */
-       { 0x0000, 0x0000, 0x0000 }, /* R550 */
-       { 0x0000, 0x0000, 0x0000 }, /* R551 */
-       { 0x0000, 0x0000, 0x0000 }, /* R552 */
-       { 0x0000, 0x0000, 0x0000 }, /* R553 */
-       { 0x0000, 0x0000, 0x0000 }, /* R554 */
-       { 0x0000, 0x0000, 0x0000 }, /* R555 */
-       { 0x0000, 0x0000, 0x0000 }, /* R556 */
-       { 0x0000, 0x0000, 0x0000 }, /* R557 */
-       { 0x0000, 0x0000, 0x0000 }, /* R558 */
-       { 0x0000, 0x0000, 0x0000 }, /* R559 */
-       { 0x0000, 0x0000, 0x0000 }, /* R560 */
-       { 0x0000, 0x0000, 0x0000 }, /* R561 */
-       { 0x0000, 0x0000, 0x0000 }, /* R562 */
-       { 0x0000, 0x0000, 0x0000 }, /* R563 */
-       { 0x0000, 0x0000, 0x0000 }, /* R564 */
-       { 0x0000, 0x0000, 0x0000 }, /* R565 */
-       { 0x0000, 0x0000, 0x0000 }, /* R566 */
-       { 0x0000, 0x0000, 0x0000 }, /* R567 */
-       { 0x0000, 0x0000, 0x0000 }, /* R568 */
-       { 0x0000, 0x0000, 0x0000 }, /* R569 */
-       { 0x0000, 0x0000, 0x0000 }, /* R570 */
-       { 0x0000, 0x0000, 0x0000 }, /* R571 */
-       { 0x0000, 0x0000, 0x0000 }, /* R572 */
-       { 0x0000, 0x0000, 0x0000 }, /* R573 */
-       { 0x0000, 0x0000, 0x0000 }, /* R574 */
-       { 0x0000, 0x0000, 0x0000 }, /* R575 */
-       { 0x0007, 0x0007, 0x0000 }, /* R576   - FLL2 Control (1) */
-       { 0x3F77, 0x3F77, 0x0000 }, /* R577   - FLL2 Control (2) */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R578   - FLL2 Control (3) */
-       { 0x7FEF, 0x7FEF, 0x0000 }, /* R579   - FLL2 Control (4) */
-       { 0x1FDB, 0x1FDB, 0x0000 }, /* R580   - FLL2 Control (5) */
-       { 0x0000, 0x0000, 0x0000 }, /* R581 */
-       { 0x0000, 0x0000, 0x0000 }, /* R582 */
-       { 0x0000, 0x0000, 0x0000 }, /* R583 */
-       { 0x0000, 0x0000, 0x0000 }, /* R584 */
-       { 0x0000, 0x0000, 0x0000 }, /* R585 */
-       { 0x0000, 0x0000, 0x0000 }, /* R586 */
-       { 0x0000, 0x0000, 0x0000 }, /* R587 */
-       { 0x0000, 0x0000, 0x0000 }, /* R588 */
-       { 0x0000, 0x0000, 0x0000 }, /* R589 */
-       { 0x0000, 0x0000, 0x0000 }, /* R590 */
-       { 0x0000, 0x0000, 0x0000 }, /* R591 */
-       { 0x0000, 0x0000, 0x0000 }, /* R592 */
-       { 0x0000, 0x0000, 0x0000 }, /* R593 */
-       { 0x0000, 0x0000, 0x0000 }, /* R594 */
-       { 0x0000, 0x0000, 0x0000 }, /* R595 */
-       { 0x0000, 0x0000, 0x0000 }, /* R596 */
-       { 0x0000, 0x0000, 0x0000 }, /* R597 */
-       { 0x0000, 0x0000, 0x0000 }, /* R598 */
-       { 0x0000, 0x0000, 0x0000 }, /* R599 */
-       { 0x0000, 0x0000, 0x0000 }, /* R600 */
-       { 0x0000, 0x0000, 0x0000 }, /* R601 */
-       { 0x0000, 0x0000, 0x0000 }, /* R602 */
-       { 0x0000, 0x0000, 0x0000 }, /* R603 */
-       { 0x0000, 0x0000, 0x0000 }, /* R604 */
-       { 0x0000, 0x0000, 0x0000 }, /* R605 */
-       { 0x0000, 0x0000, 0x0000 }, /* R606 */
-       { 0x0000, 0x0000, 0x0000 }, /* R607 */
-       { 0x0000, 0x0000, 0x0000 }, /* R608 */
-       { 0x0000, 0x0000, 0x0000 }, /* R609 */
-       { 0x0000, 0x0000, 0x0000 }, /* R610 */
-       { 0x0000, 0x0000, 0x0000 }, /* R611 */
-       { 0x0000, 0x0000, 0x0000 }, /* R612 */
-       { 0x0000, 0x0000, 0x0000 }, /* R613 */
-       { 0x0000, 0x0000, 0x0000 }, /* R614 */
-       { 0x0000, 0x0000, 0x0000 }, /* R615 */
-       { 0x0000, 0x0000, 0x0000 }, /* R616 */
-       { 0x0000, 0x0000, 0x0000 }, /* R617 */
-       { 0x0000, 0x0000, 0x0000 }, /* R618 */
-       { 0x0000, 0x0000, 0x0000 }, /* R619 */
-       { 0x0000, 0x0000, 0x0000 }, /* R620 */
-       { 0x0000, 0x0000, 0x0000 }, /* R621 */
-       { 0x0000, 0x0000, 0x0000 }, /* R622 */
-       { 0x0000, 0x0000, 0x0000 }, /* R623 */
-       { 0x0000, 0x0000, 0x0000 }, /* R624 */
-       { 0x0000, 0x0000, 0x0000 }, /* R625 */
-       { 0x0000, 0x0000, 0x0000 }, /* R626 */
-       { 0x0000, 0x0000, 0x0000 }, /* R627 */
-       { 0x0000, 0x0000, 0x0000 }, /* R628 */
-       { 0x0000, 0x0000, 0x0000 }, /* R629 */
-       { 0x0000, 0x0000, 0x0000 }, /* R630 */
-       { 0x0000, 0x0000, 0x0000 }, /* R631 */
-       { 0x0000, 0x0000, 0x0000 }, /* R632 */
-       { 0x0000, 0x0000, 0x0000 }, /* R633 */
-       { 0x0000, 0x0000, 0x0000 }, /* R634 */
-       { 0x0000, 0x0000, 0x0000 }, /* R635 */
-       { 0x0000, 0x0000, 0x0000 }, /* R636 */
-       { 0x0000, 0x0000, 0x0000 }, /* R637 */
-       { 0x0000, 0x0000, 0x0000 }, /* R638 */
-       { 0x0000, 0x0000, 0x0000 }, /* R639 */
-       { 0x0000, 0x0000, 0x0000 }, /* R640 */
-       { 0x0000, 0x0000, 0x0000 }, /* R641 */
-       { 0x0000, 0x0000, 0x0000 }, /* R642 */
-       { 0x0000, 0x0000, 0x0000 }, /* R643 */
-       { 0x0000, 0x0000, 0x0000 }, /* R644 */
-       { 0x0000, 0x0000, 0x0000 }, /* R645 */
-       { 0x0000, 0x0000, 0x0000 }, /* R646 */
-       { 0x0000, 0x0000, 0x0000 }, /* R647 */
-       { 0x0000, 0x0000, 0x0000 }, /* R648 */
-       { 0x0000, 0x0000, 0x0000 }, /* R649 */
-       { 0x0000, 0x0000, 0x0000 }, /* R650 */
-       { 0x0000, 0x0000, 0x0000 }, /* R651 */
-       { 0x0000, 0x0000, 0x0000 }, /* R652 */
-       { 0x0000, 0x0000, 0x0000 }, /* R653 */
-       { 0x0000, 0x0000, 0x0000 }, /* R654 */
-       { 0x0000, 0x0000, 0x0000 }, /* R655 */
-       { 0x0000, 0x0000, 0x0000 }, /* R656 */
-       { 0x0000, 0x0000, 0x0000 }, /* R657 */
-       { 0x0000, 0x0000, 0x0000 }, /* R658 */
-       { 0x0000, 0x0000, 0x0000 }, /* R659 */
-       { 0x0000, 0x0000, 0x0000 }, /* R660 */
-       { 0x0000, 0x0000, 0x0000 }, /* R661 */
-       { 0x0000, 0x0000, 0x0000 }, /* R662 */
-       { 0x0000, 0x0000, 0x0000 }, /* R663 */
-       { 0x0000, 0x0000, 0x0000 }, /* R664 */
-       { 0x0000, 0x0000, 0x0000 }, /* R665 */
-       { 0x0000, 0x0000, 0x0000 }, /* R666 */
-       { 0x0000, 0x0000, 0x0000 }, /* R667 */
-       { 0x0000, 0x0000, 0x0000 }, /* R668 */
-       { 0x0000, 0x0000, 0x0000 }, /* R669 */
-       { 0x0000, 0x0000, 0x0000 }, /* R670 */
-       { 0x0000, 0x0000, 0x0000 }, /* R671 */
-       { 0x0000, 0x0000, 0x0000 }, /* R672 */
-       { 0x0000, 0x0000, 0x0000 }, /* R673 */
-       { 0x0000, 0x0000, 0x0000 }, /* R674 */
-       { 0x0000, 0x0000, 0x0000 }, /* R675 */
-       { 0x0000, 0x0000, 0x0000 }, /* R676 */
-       { 0x0000, 0x0000, 0x0000 }, /* R677 */
-       { 0x0000, 0x0000, 0x0000 }, /* R678 */
-       { 0x0000, 0x0000, 0x0000 }, /* R679 */
-       { 0x0000, 0x0000, 0x0000 }, /* R680 */
-       { 0x0000, 0x0000, 0x0000 }, /* R681 */
-       { 0x0000, 0x0000, 0x0000 }, /* R682 */
-       { 0x0000, 0x0000, 0x0000 }, /* R683 */
-       { 0x0000, 0x0000, 0x0000 }, /* R684 */
-       { 0x0000, 0x0000, 0x0000 }, /* R685 */
-       { 0x0000, 0x0000, 0x0000 }, /* R686 */
-       { 0x0000, 0x0000, 0x0000 }, /* R687 */
-       { 0x0000, 0x0000, 0x0000 }, /* R688 */
-       { 0x0000, 0x0000, 0x0000 }, /* R689 */
-       { 0x0000, 0x0000, 0x0000 }, /* R690 */
-       { 0x0000, 0x0000, 0x0000 }, /* R691 */
-       { 0x0000, 0x0000, 0x0000 }, /* R692 */
-       { 0x0000, 0x0000, 0x0000 }, /* R693 */
-       { 0x0000, 0x0000, 0x0000 }, /* R694 */
-       { 0x0000, 0x0000, 0x0000 }, /* R695 */
-       { 0x0000, 0x0000, 0x0000 }, /* R696 */
-       { 0x0000, 0x0000, 0x0000 }, /* R697 */
-       { 0x0000, 0x0000, 0x0000 }, /* R698 */
-       { 0x0000, 0x0000, 0x0000 }, /* R699 */
-       { 0x0000, 0x0000, 0x0000 }, /* R700 */
-       { 0x0000, 0x0000, 0x0000 }, /* R701 */
-       { 0x0000, 0x0000, 0x0000 }, /* R702 */
-       { 0x0000, 0x0000, 0x0000 }, /* R703 */
-       { 0x0000, 0x0000, 0x0000 }, /* R704 */
-       { 0x0000, 0x0000, 0x0000 }, /* R705 */
-       { 0x0000, 0x0000, 0x0000 }, /* R706 */
-       { 0x0000, 0x0000, 0x0000 }, /* R707 */
-       { 0x0000, 0x0000, 0x0000 }, /* R708 */
-       { 0x0000, 0x0000, 0x0000 }, /* R709 */
-       { 0x0000, 0x0000, 0x0000 }, /* R710 */
-       { 0x0000, 0x0000, 0x0000 }, /* R711 */
-       { 0x0000, 0x0000, 0x0000 }, /* R712 */
-       { 0x0000, 0x0000, 0x0000 }, /* R713 */
-       { 0x0000, 0x0000, 0x0000 }, /* R714 */
-       { 0x0000, 0x0000, 0x0000 }, /* R715 */
-       { 0x0000, 0x0000, 0x0000 }, /* R716 */
-       { 0x0000, 0x0000, 0x0000 }, /* R717 */
-       { 0x0000, 0x0000, 0x0000 }, /* R718 */
-       { 0x0000, 0x0000, 0x0000 }, /* R719 */
-       { 0x0000, 0x0000, 0x0000 }, /* R720 */
-       { 0x0000, 0x0000, 0x0000 }, /* R721 */
-       { 0x0000, 0x0000, 0x0000 }, /* R722 */
-       { 0x0000, 0x0000, 0x0000 }, /* R723 */
-       { 0x0000, 0x0000, 0x0000 }, /* R724 */
-       { 0x0000, 0x0000, 0x0000 }, /* R725 */
-       { 0x0000, 0x0000, 0x0000 }, /* R726 */
-       { 0x0000, 0x0000, 0x0000 }, /* R727 */
-       { 0x0000, 0x0000, 0x0000 }, /* R728 */
-       { 0x0000, 0x0000, 0x0000 }, /* R729 */
-       { 0x0000, 0x0000, 0x0000 }, /* R730 */
-       { 0x0000, 0x0000, 0x0000 }, /* R731 */
-       { 0x0000, 0x0000, 0x0000 }, /* R732 */
-       { 0x0000, 0x0000, 0x0000 }, /* R733 */
-       { 0x0000, 0x0000, 0x0000 }, /* R734 */
-       { 0x0000, 0x0000, 0x0000 }, /* R735 */
-       { 0x0000, 0x0000, 0x0000 }, /* R736 */
-       { 0x0000, 0x0000, 0x0000 }, /* R737 */
-       { 0x0000, 0x0000, 0x0000 }, /* R738 */
-       { 0x0000, 0x0000, 0x0000 }, /* R739 */
-       { 0x0000, 0x0000, 0x0000 }, /* R740 */
-       { 0x0000, 0x0000, 0x0000 }, /* R741 */
-       { 0x0000, 0x0000, 0x0000 }, /* R742 */
-       { 0x0000, 0x0000, 0x0000 }, /* R743 */
-       { 0x0000, 0x0000, 0x0000 }, /* R744 */
-       { 0x0000, 0x0000, 0x0000 }, /* R745 */
-       { 0x0000, 0x0000, 0x0000 }, /* R746 */
-       { 0x0000, 0x0000, 0x0000 }, /* R747 */
-       { 0x0000, 0x0000, 0x0000 }, /* R748 */
-       { 0x0000, 0x0000, 0x0000 }, /* R749 */
-       { 0x0000, 0x0000, 0x0000 }, /* R750 */
-       { 0x0000, 0x0000, 0x0000 }, /* R751 */
-       { 0x0000, 0x0000, 0x0000 }, /* R752 */
-       { 0x0000, 0x0000, 0x0000 }, /* R753 */
-       { 0x0000, 0x0000, 0x0000 }, /* R754 */
-       { 0x0000, 0x0000, 0x0000 }, /* R755 */
-       { 0x0000, 0x0000, 0x0000 }, /* R756 */
-       { 0x0000, 0x0000, 0x0000 }, /* R757 */
-       { 0x0000, 0x0000, 0x0000 }, /* R758 */
-       { 0x0000, 0x0000, 0x0000 }, /* R759 */
-       { 0x0000, 0x0000, 0x0000 }, /* R760 */
-       { 0x0000, 0x0000, 0x0000 }, /* R761 */
-       { 0x0000, 0x0000, 0x0000 }, /* R762 */
-       { 0x0000, 0x0000, 0x0000 }, /* R763 */
-       { 0x0000, 0x0000, 0x0000 }, /* R764 */
-       { 0x0000, 0x0000, 0x0000 }, /* R765 */
-       { 0x0000, 0x0000, 0x0000 }, /* R766 */
-       { 0x0000, 0x0000, 0x0000 }, /* R767 */
-       { 0xE1F8, 0xE1F8, 0x0000 }, /* R768   - AIF1 Control (1) */
-       { 0xCD1F, 0xCD1F, 0x0000 }, /* R769   - AIF1 Control (2) */
-       { 0xF000, 0xF000, 0x0000 }, /* R770   - AIF1 Master/Slave */
-       { 0x01F0, 0x01F0, 0x0000 }, /* R771   - AIF1 BCLK */
-       { 0x0FFF, 0x0FFF, 0x0000 }, /* R772   - AIF1ADC LRCLK */
-       { 0x0FFF, 0x0FFF, 0x0000 }, /* R773   - AIF1DAC LRCLK */
-       { 0x0003, 0x0003, 0x0000 }, /* R774   - AIF1DAC Data */
-       { 0x0003, 0x0003, 0x0000 }, /* R775   - AIF1ADC Data */
-       { 0x0000, 0x0000, 0x0000 }, /* R776 */
-       { 0x0000, 0x0000, 0x0000 }, /* R777 */
-       { 0x0000, 0x0000, 0x0000 }, /* R778 */
-       { 0x0000, 0x0000, 0x0000 }, /* R779 */
-       { 0x0000, 0x0000, 0x0000 }, /* R780 */
-       { 0x0000, 0x0000, 0x0000 }, /* R781 */
-       { 0x0000, 0x0000, 0x0000 }, /* R782 */
-       { 0x0000, 0x0000, 0x0000 }, /* R783 */
-       { 0xF1F8, 0xF1F8, 0x0000 }, /* R784   - AIF2 Control (1) */
-       { 0xFD1F, 0xFD1F, 0x0000 }, /* R785   - AIF2 Control (2) */
-       { 0xF000, 0xF000, 0x0000 }, /* R786   - AIF2 Master/Slave */
-       { 0x01F0, 0x01F0, 0x0000 }, /* R787   - AIF2 BCLK */
-       { 0x0FFF, 0x0FFF, 0x0000 }, /* R788   - AIF2ADC LRCLK */
-       { 0x0FFF, 0x0FFF, 0x0000 }, /* R789   - AIF2DAC LRCLK */
-       { 0x0003, 0x0003, 0x0000 }, /* R790   - AIF2DAC Data */
-       { 0x0003, 0x0003, 0x0000 }, /* R791   - AIF2ADC Data */
-       { 0x0000, 0x0000, 0x0000 }, /* R792 */
-       { 0x0000, 0x0000, 0x0000 }, /* R793 */
-       { 0x0000, 0x0000, 0x0000 }, /* R794 */
-       { 0x0000, 0x0000, 0x0000 }, /* R795 */
-       { 0x0000, 0x0000, 0x0000 }, /* R796 */
-       { 0x0000, 0x0000, 0x0000 }, /* R797 */
-       { 0x0000, 0x0000, 0x0000 }, /* R798 */
-       { 0x0000, 0x0000, 0x0000 }, /* R799 */
-       { 0x0000, 0x0000, 0x0000 }, /* R800 */
-       { 0x0000, 0x0000, 0x0000 }, /* R801 */
-       { 0x0000, 0x0000, 0x0000 }, /* R802 */
-       { 0x0000, 0x0000, 0x0000 }, /* R803 */
-       { 0x0000, 0x0000, 0x0000 }, /* R804 */
-       { 0x0000, 0x0000, 0x0000 }, /* R805 */
-       { 0x0000, 0x0000, 0x0000 }, /* R806 */
-       { 0x0000, 0x0000, 0x0000 }, /* R807 */
-       { 0x0000, 0x0000, 0x0000 }, /* R808 */
-       { 0x0000, 0x0000, 0x0000 }, /* R809 */
-       { 0x0000, 0x0000, 0x0000 }, /* R810 */
-       { 0x0000, 0x0000, 0x0000 }, /* R811 */
-       { 0x0000, 0x0000, 0x0000 }, /* R812 */
-       { 0x0000, 0x0000, 0x0000 }, /* R813 */
-       { 0x0000, 0x0000, 0x0000 }, /* R814 */
-       { 0x0000, 0x0000, 0x0000 }, /* R815 */
-       { 0x0000, 0x0000, 0x0000 }, /* R816 */
-       { 0x0000, 0x0000, 0x0000 }, /* R817 */
-       { 0x0000, 0x0000, 0x0000 }, /* R818 */
-       { 0x0000, 0x0000, 0x0000 }, /* R819 */
-       { 0x0000, 0x0000, 0x0000 }, /* R820 */
-       { 0x0000, 0x0000, 0x0000 }, /* R821 */
-       { 0x0000, 0x0000, 0x0000 }, /* R822 */
-       { 0x0000, 0x0000, 0x0000 }, /* R823 */
-       { 0x0000, 0x0000, 0x0000 }, /* R824 */
-       { 0x0000, 0x0000, 0x0000 }, /* R825 */
-       { 0x0000, 0x0000, 0x0000 }, /* R826 */
-       { 0x0000, 0x0000, 0x0000 }, /* R827 */
-       { 0x0000, 0x0000, 0x0000 }, /* R828 */
-       { 0x0000, 0x0000, 0x0000 }, /* R829 */
-       { 0x0000, 0x0000, 0x0000 }, /* R830 */
-       { 0x0000, 0x0000, 0x0000 }, /* R831 */
-       { 0x0000, 0x0000, 0x0000 }, /* R832 */
-       { 0x0000, 0x0000, 0x0000 }, /* R833 */
-       { 0x0000, 0x0000, 0x0000 }, /* R834 */
-       { 0x0000, 0x0000, 0x0000 }, /* R835 */
-       { 0x0000, 0x0000, 0x0000 }, /* R836 */
-       { 0x0000, 0x0000, 0x0000 }, /* R837 */
-       { 0x0000, 0x0000, 0x0000 }, /* R838 */
-       { 0x0000, 0x0000, 0x0000 }, /* R839 */
-       { 0x0000, 0x0000, 0x0000 }, /* R840 */
-       { 0x0000, 0x0000, 0x0000 }, /* R841 */
-       { 0x0000, 0x0000, 0x0000 }, /* R842 */
-       { 0x0000, 0x0000, 0x0000 }, /* R843 */
-       { 0x0000, 0x0000, 0x0000 }, /* R844 */
-       { 0x0000, 0x0000, 0x0000 }, /* R845 */
-       { 0x0000, 0x0000, 0x0000 }, /* R846 */
-       { 0x0000, 0x0000, 0x0000 }, /* R847 */
-       { 0x0000, 0x0000, 0x0000 }, /* R848 */
-       { 0x0000, 0x0000, 0x0000 }, /* R849 */
-       { 0x0000, 0x0000, 0x0000 }, /* R850 */
-       { 0x0000, 0x0000, 0x0000 }, /* R851 */
-       { 0x0000, 0x0000, 0x0000 }, /* R852 */
-       { 0x0000, 0x0000, 0x0000 }, /* R853 */
-       { 0x0000, 0x0000, 0x0000 }, /* R854 */
-       { 0x0000, 0x0000, 0x0000 }, /* R855 */
-       { 0x0000, 0x0000, 0x0000 }, /* R856 */
-       { 0x0000, 0x0000, 0x0000 }, /* R857 */
-       { 0x0000, 0x0000, 0x0000 }, /* R858 */
-       { 0x0000, 0x0000, 0x0000 }, /* R859 */
-       { 0x0000, 0x0000, 0x0000 }, /* R860 */
-       { 0x0000, 0x0000, 0x0000 }, /* R861 */
-       { 0x0000, 0x0000, 0x0000 }, /* R862 */
-       { 0x0000, 0x0000, 0x0000 }, /* R863 */
-       { 0x0000, 0x0000, 0x0000 }, /* R864 */
-       { 0x0000, 0x0000, 0x0000 }, /* R865 */
-       { 0x0000, 0x0000, 0x0000 }, /* R866 */
-       { 0x0000, 0x0000, 0x0000 }, /* R867 */
-       { 0x0000, 0x0000, 0x0000 }, /* R868 */
-       { 0x0000, 0x0000, 0x0000 }, /* R869 */
-       { 0x0000, 0x0000, 0x0000 }, /* R870 */
-       { 0x0000, 0x0000, 0x0000 }, /* R871 */
-       { 0x0000, 0x0000, 0x0000 }, /* R872 */
-       { 0x0000, 0x0000, 0x0000 }, /* R873 */
-       { 0x0000, 0x0000, 0x0000 }, /* R874 */
-       { 0x0000, 0x0000, 0x0000 }, /* R875 */
-       { 0x0000, 0x0000, 0x0000 }, /* R876 */
-       { 0x0000, 0x0000, 0x0000 }, /* R877 */
-       { 0x0000, 0x0000, 0x0000 }, /* R878 */
-       { 0x0000, 0x0000, 0x0000 }, /* R879 */
-       { 0x0000, 0x0000, 0x0000 }, /* R880 */
-       { 0x0000, 0x0000, 0x0000 }, /* R881 */
-       { 0x0000, 0x0000, 0x0000 }, /* R882 */
-       { 0x0000, 0x0000, 0x0000 }, /* R883 */
-       { 0x0000, 0x0000, 0x0000 }, /* R884 */
-       { 0x0000, 0x0000, 0x0000 }, /* R885 */
-       { 0x0000, 0x0000, 0x0000 }, /* R886 */
-       { 0x0000, 0x0000, 0x0000 }, /* R887 */
-       { 0x0000, 0x0000, 0x0000 }, /* R888 */
-       { 0x0000, 0x0000, 0x0000 }, /* R889 */
-       { 0x0000, 0x0000, 0x0000 }, /* R890 */
-       { 0x0000, 0x0000, 0x0000 }, /* R891 */
-       { 0x0000, 0x0000, 0x0000 }, /* R892 */
-       { 0x0000, 0x0000, 0x0000 }, /* R893 */
-       { 0x0000, 0x0000, 0x0000 }, /* R894 */
-       { 0x0000, 0x0000, 0x0000 }, /* R895 */
-       { 0x0000, 0x0000, 0x0000 }, /* R896 */
-       { 0x0000, 0x0000, 0x0000 }, /* R897 */
-       { 0x0000, 0x0000, 0x0000 }, /* R898 */
-       { 0x0000, 0x0000, 0x0000 }, /* R899 */
-       { 0x0000, 0x0000, 0x0000 }, /* R900 */
-       { 0x0000, 0x0000, 0x0000 }, /* R901 */
-       { 0x0000, 0x0000, 0x0000 }, /* R902 */
-       { 0x0000, 0x0000, 0x0000 }, /* R903 */
-       { 0x0000, 0x0000, 0x0000 }, /* R904 */
-       { 0x0000, 0x0000, 0x0000 }, /* R905 */
-       { 0x0000, 0x0000, 0x0000 }, /* R906 */
-       { 0x0000, 0x0000, 0x0000 }, /* R907 */
-       { 0x0000, 0x0000, 0x0000 }, /* R908 */
-       { 0x0000, 0x0000, 0x0000 }, /* R909 */
-       { 0x0000, 0x0000, 0x0000 }, /* R910 */
-       { 0x0000, 0x0000, 0x0000 }, /* R911 */
-       { 0x0000, 0x0000, 0x0000 }, /* R912 */
-       { 0x0000, 0x0000, 0x0000 }, /* R913 */
-       { 0x0000, 0x0000, 0x0000 }, /* R914 */
-       { 0x0000, 0x0000, 0x0000 }, /* R915 */
-       { 0x0000, 0x0000, 0x0000 }, /* R916 */
-       { 0x0000, 0x0000, 0x0000 }, /* R917 */
-       { 0x0000, 0x0000, 0x0000 }, /* R918 */
-       { 0x0000, 0x0000, 0x0000 }, /* R919 */
-       { 0x0000, 0x0000, 0x0000 }, /* R920 */
-       { 0x0000, 0x0000, 0x0000 }, /* R921 */
-       { 0x0000, 0x0000, 0x0000 }, /* R922 */
-       { 0x0000, 0x0000, 0x0000 }, /* R923 */
-       { 0x0000, 0x0000, 0x0000 }, /* R924 */
-       { 0x0000, 0x0000, 0x0000 }, /* R925 */
-       { 0x0000, 0x0000, 0x0000 }, /* R926 */
-       { 0x0000, 0x0000, 0x0000 }, /* R927 */
-       { 0x0000, 0x0000, 0x0000 }, /* R928 */
-       { 0x0000, 0x0000, 0x0000 }, /* R929 */
-       { 0x0000, 0x0000, 0x0000 }, /* R930 */
-       { 0x0000, 0x0000, 0x0000 }, /* R931 */
-       { 0x0000, 0x0000, 0x0000 }, /* R932 */
-       { 0x0000, 0x0000, 0x0000 }, /* R933 */
-       { 0x0000, 0x0000, 0x0000 }, /* R934 */
-       { 0x0000, 0x0000, 0x0000 }, /* R935 */
-       { 0x0000, 0x0000, 0x0000 }, /* R936 */
-       { 0x0000, 0x0000, 0x0000 }, /* R937 */
-       { 0x0000, 0x0000, 0x0000 }, /* R938 */
-       { 0x0000, 0x0000, 0x0000 }, /* R939 */
-       { 0x0000, 0x0000, 0x0000 }, /* R940 */
-       { 0x0000, 0x0000, 0x0000 }, /* R941 */
-       { 0x0000, 0x0000, 0x0000 }, /* R942 */
-       { 0x0000, 0x0000, 0x0000 }, /* R943 */
-       { 0x0000, 0x0000, 0x0000 }, /* R944 */
-       { 0x0000, 0x0000, 0x0000 }, /* R945 */
-       { 0x0000, 0x0000, 0x0000 }, /* R946 */
-       { 0x0000, 0x0000, 0x0000 }, /* R947 */
-       { 0x0000, 0x0000, 0x0000 }, /* R948 */
-       { 0x0000, 0x0000, 0x0000 }, /* R949 */
-       { 0x0000, 0x0000, 0x0000 }, /* R950 */
-       { 0x0000, 0x0000, 0x0000 }, /* R951 */
-       { 0x0000, 0x0000, 0x0000 }, /* R952 */
-       { 0x0000, 0x0000, 0x0000 }, /* R953 */
-       { 0x0000, 0x0000, 0x0000 }, /* R954 */
-       { 0x0000, 0x0000, 0x0000 }, /* R955 */
-       { 0x0000, 0x0000, 0x0000 }, /* R956 */
-       { 0x0000, 0x0000, 0x0000 }, /* R957 */
-       { 0x0000, 0x0000, 0x0000 }, /* R958 */
-       { 0x0000, 0x0000, 0x0000 }, /* R959 */
-       { 0x0000, 0x0000, 0x0000 }, /* R960 */
-       { 0x0000, 0x0000, 0x0000 }, /* R961 */
-       { 0x0000, 0x0000, 0x0000 }, /* R962 */
-       { 0x0000, 0x0000, 0x0000 }, /* R963 */
-       { 0x0000, 0x0000, 0x0000 }, /* R964 */
-       { 0x0000, 0x0000, 0x0000 }, /* R965 */
-       { 0x0000, 0x0000, 0x0000 }, /* R966 */
-       { 0x0000, 0x0000, 0x0000 }, /* R967 */
-       { 0x0000, 0x0000, 0x0000 }, /* R968 */
-       { 0x0000, 0x0000, 0x0000 }, /* R969 */
-       { 0x0000, 0x0000, 0x0000 }, /* R970 */
-       { 0x0000, 0x0000, 0x0000 }, /* R971 */
-       { 0x0000, 0x0000, 0x0000 }, /* R972 */
-       { 0x0000, 0x0000, 0x0000 }, /* R973 */
-       { 0x0000, 0x0000, 0x0000 }, /* R974 */
-       { 0x0000, 0x0000, 0x0000 }, /* R975 */
-       { 0x0000, 0x0000, 0x0000 }, /* R976 */
-       { 0x0000, 0x0000, 0x0000 }, /* R977 */
-       { 0x0000, 0x0000, 0x0000 }, /* R978 */
-       { 0x0000, 0x0000, 0x0000 }, /* R979 */
-       { 0x0000, 0x0000, 0x0000 }, /* R980 */
-       { 0x0000, 0x0000, 0x0000 }, /* R981 */
-       { 0x0000, 0x0000, 0x0000 }, /* R982 */
-       { 0x0000, 0x0000, 0x0000 }, /* R983 */
-       { 0x0000, 0x0000, 0x0000 }, /* R984 */
-       { 0x0000, 0x0000, 0x0000 }, /* R985 */
-       { 0x0000, 0x0000, 0x0000 }, /* R986 */
-       { 0x0000, 0x0000, 0x0000 }, /* R987 */
-       { 0x0000, 0x0000, 0x0000 }, /* R988 */
-       { 0x0000, 0x0000, 0x0000 }, /* R989 */
-       { 0x0000, 0x0000, 0x0000 }, /* R990 */
-       { 0x0000, 0x0000, 0x0000 }, /* R991 */
-       { 0x0000, 0x0000, 0x0000 }, /* R992 */
-       { 0x0000, 0x0000, 0x0000 }, /* R993 */
-       { 0x0000, 0x0000, 0x0000 }, /* R994 */
-       { 0x0000, 0x0000, 0x0000 }, /* R995 */
-       { 0x0000, 0x0000, 0x0000 }, /* R996 */
-       { 0x0000, 0x0000, 0x0000 }, /* R997 */
-       { 0x0000, 0x0000, 0x0000 }, /* R998 */
-       { 0x0000, 0x0000, 0x0000 }, /* R999 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1000 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1001 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1002 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1003 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1004 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1005 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1006 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1007 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1008 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1009 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1010 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1011 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1012 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1013 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1014 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1015 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1016 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1017 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1018 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1019 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1020 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1021 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1022 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1023 */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1024  - AIF1 ADC1 Left Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1025  - AIF1 ADC1 Right Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1026  - AIF1 DAC1 Left Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1027  - AIF1 DAC1 Right Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1028  - AIF1 ADC2 Left Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1029  - AIF1 ADC2 Right Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1030  - AIF1 DAC2 Left Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1031  - AIF1 DAC2 Right Volume */
-       { 0x0000, 0x0000, 0x0000 }, /* R1032 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1033 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1034 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1035 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1036 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1037 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1038 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1039 */
-       { 0xF800, 0xF800, 0x0000 }, /* R1040  - AIF1 ADC1 Filters */
-       { 0x7800, 0x7800, 0x0000 }, /* R1041  - AIF1 ADC2 Filters */
-       { 0x0000, 0x0000, 0x0000 }, /* R1042 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1043 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1044 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1045 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1046 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1047 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1048 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1049 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1050 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1051 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1052 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1053 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1054 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1055 */
-       { 0x02B6, 0x02B6, 0x0000 }, /* R1056  - AIF1 DAC1 Filters (1) */
-       { 0x3F00, 0x3F00, 0x0000 }, /* R1057  - AIF1 DAC1 Filters (2) */
-       { 0x02B6, 0x02B6, 0x0000 }, /* R1058  - AIF1 DAC2 Filters (1) */
-       { 0x3F00, 0x3F00, 0x0000 }, /* R1059  - AIF1 DAC2 Filters (2) */
-       { 0x0000, 0x0000, 0x0000 }, /* R1060 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1061 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1062 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1063 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1064 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1065 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1066 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1067 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1068 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1069 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1070 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1071 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1072 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1073 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1074 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1075 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1076 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1077 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1078 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1079 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1080 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1081 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1082 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1083 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1084 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1085 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1086 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1087 */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1088  - AIF1 DRC1 (1) */
-       { 0x1FFF, 0x1FFF, 0x0000 }, /* R1089  - AIF1 DRC1 (2) */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1090  - AIF1 DRC1 (3) */
-       { 0x07FF, 0x07FF, 0x0000 }, /* R1091  - AIF1 DRC1 (4) */
-       { 0x03FF, 0x03FF, 0x0000 }, /* R1092  - AIF1 DRC1 (5) */
-       { 0x0000, 0x0000, 0x0000 }, /* R1093 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1094 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1095 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1096 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1097 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1098 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1099 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1100 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1101 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1102 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1103 */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1104  - AIF1 DRC2 (1) */
-       { 0x1FFF, 0x1FFF, 0x0000 }, /* R1105  - AIF1 DRC2 (2) */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1106  - AIF1 DRC2 (3) */
-       { 0x07FF, 0x07FF, 0x0000 }, /* R1107  - AIF1 DRC2 (4) */
-       { 0x03FF, 0x03FF, 0x0000 }, /* R1108  - AIF1 DRC2 (5) */
-       { 0x0000, 0x0000, 0x0000 }, /* R1109 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1110 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1111 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1112 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1113 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1114 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1115 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1116 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1117 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1118 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1119 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1120 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1121 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1122 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1123 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1124 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1125 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1126 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1127 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1128 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1129 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1130 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1131 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1132 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1133 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1134 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1135 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1136 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1137 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1138 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1139 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1140 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1141 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1142 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1143 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1144 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1145 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1146 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1147 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1148 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1149 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1150 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1151 */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1152  - AIF1 DAC1 EQ Gains (1) */
-       { 0xFFC0, 0xFFC0, 0x0000 }, /* R1153  - AIF1 DAC1 EQ Gains (2) */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1154  - AIF1 DAC1 EQ Band 1 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1155  - AIF1 DAC1 EQ Band 1 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1156  - AIF1 DAC1 EQ Band 1 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1157  - AIF1 DAC1 EQ Band 2 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1158  - AIF1 DAC1 EQ Band 2 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1159  - AIF1 DAC1 EQ Band 2 C */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1160  - AIF1 DAC1 EQ Band 2 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1161  - AIF1 DAC1 EQ Band 3 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1162  - AIF1 DAC1 EQ Band 3 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1163  - AIF1 DAC1 EQ Band 3 C */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1164  - AIF1 DAC1 EQ Band 3 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1165  - AIF1 DAC1 EQ Band 4 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1166  - AIF1 DAC1 EQ Band 4 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1167  - AIF1 DAC1 EQ Band 4 C */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1168  - AIF1 DAC1 EQ Band 4 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1169  - AIF1 DAC1 EQ Band 5 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1170  - AIF1 DAC1 EQ Band 5 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1171  - AIF1 DAC1 EQ Band 5 PG */
-       { 0x0000, 0x0000, 0x0000 }, /* R1172 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1173 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1174 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1175 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1176 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1177 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1178 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1179 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1180 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1181 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1182 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1183 */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1184  - AIF1 DAC2 EQ Gains (1) */
-       { 0xFFC0, 0xFFC0, 0x0000 }, /* R1185  - AIF1 DAC2 EQ Gains (2) */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1186  - AIF1 DAC2 EQ Band 1 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1187  - AIF1 DAC2 EQ Band 1 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1188  - AIF1 DAC2 EQ Band 1 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1189  - AIF1 DAC2 EQ Band 2 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1190  - AIF1 DAC2 EQ Band 2 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1191  - AIF1 DAC2 EQ Band 2 C */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1192  - AIF1 DAC2 EQ Band 2 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1193  - AIF1 DAC2 EQ Band 3 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1194  - AIF1 DAC2 EQ Band 3 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1195  - AIF1 DAC2 EQ Band 3 C */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1196  - AIF1 DAC2 EQ Band 3 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1197  - AIF1 DAC2 EQ Band 4 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1198  - AIF1 DAC2 EQ Band 4 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1199  - AIF1 DAC2 EQ Band 4 C */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1200  - AIF1 DAC2 EQ Band 4 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1201  - AIF1 DAC2 EQ Band 5 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1202  - AIF1 DAC2 EQ Band 5 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1203  - AIF1 DAC2 EQ Band 5 PG */
-       { 0x0000, 0x0000, 0x0000 }, /* R1204 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1205 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1206 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1207 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1208 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1209 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1210 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1211 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1212 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1213 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1214 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1215 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1216 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1217 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1218 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1219 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1220 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1221 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1222 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1223 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1224 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1225 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1226 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1227 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1228 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1229 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1230 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1231 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1232 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1233 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1234 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1235 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1236 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1237 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1238 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1239 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1240 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1241 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1242 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1243 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1244 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1245 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1246 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1247 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1248 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1249 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1250 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1251 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1252 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1253 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1254 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1255 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1256 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1257 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1258 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1259 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1260 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1261 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1262 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1263 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1264 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1265 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1266 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1267 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1268 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1269 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1270 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1271 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1272 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1273 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1274 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1275 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1276 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1277 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1278 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1279 */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1280  - AIF2 ADC Left Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1281  - AIF2 ADC Right Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1282  - AIF2 DAC Left Volume */
-       { 0x00FF, 0x01FF, 0x0000 }, /* R1283  - AIF2 DAC Right Volume */
-       { 0x0000, 0x0000, 0x0000 }, /* R1284 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1285 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1286 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1287 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1288 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1289 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1290 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1291 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1292 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1293 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1294 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1295 */
-       { 0xF800, 0xF800, 0x0000 }, /* R1296  - AIF2 ADC Filters */
-       { 0x0000, 0x0000, 0x0000 }, /* R1297 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1298 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1299 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1300 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1301 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1302 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1303 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1304 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1305 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1306 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1307 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1308 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1309 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1310 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1311 */
-       { 0x02B6, 0x02B6, 0x0000 }, /* R1312  - AIF2 DAC Filters (1) */
-       { 0x3F00, 0x3F00, 0x0000 }, /* R1313  - AIF2 DAC Filters (2) */
-       { 0x0000, 0x0000, 0x0000 }, /* R1314 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1315 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1316 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1317 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1318 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1319 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1320 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1321 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1322 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1323 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1324 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1325 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1326 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1327 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1328 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1329 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1330 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1331 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1332 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1333 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1334 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1335 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1336 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1337 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1338 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1339 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1340 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1341 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1342 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1343 */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1344  - AIF2 DRC (1) */
-       { 0x1FFF, 0x1FFF, 0x0000 }, /* R1345  - AIF2 DRC (2) */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1346  - AIF2 DRC (3) */
-       { 0x07FF, 0x07FF, 0x0000 }, /* R1347  - AIF2 DRC (4) */
-       { 0x03FF, 0x03FF, 0x0000 }, /* R1348  - AIF2 DRC (5) */
-       { 0x0000, 0x0000, 0x0000 }, /* R1349 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1350 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1351 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1352 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1353 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1354 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1355 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1356 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1357 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1358 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1359 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1360 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1361 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1362 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1363 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1364 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1365 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1366 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1367 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1368 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1369 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1370 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1371 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1372 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1373 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1374 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1375 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1376 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1377 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1378 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1379 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1380 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1381 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1382 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1383 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1384 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1385 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1386 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1387 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1388 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1389 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1390 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1391 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1392 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1393 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1394 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1395 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1396 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1397 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1398 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1399 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1400 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1401 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1402 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1403 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1404 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1405 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1406 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1407 */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1408  - AIF2 EQ Gains (1) */
-       { 0xFFC0, 0xFFC0, 0x0000 }, /* R1409  - AIF2 EQ Gains (2) */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1410  - AIF2 EQ Band 1 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1411  - AIF2 EQ Band 1 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1412  - AIF2 EQ Band 1 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1413  - AIF2 EQ Band 2 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1414  - AIF2 EQ Band 2 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1415  - AIF2 EQ Band 2 C */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1416  - AIF2 EQ Band 2 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1417  - AIF2 EQ Band 3 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1418  - AIF2 EQ Band 3 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1419  - AIF2 EQ Band 3 C */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1420  - AIF2 EQ Band 3 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1421  - AIF2 EQ Band 4 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1422  - AIF2 EQ Band 4 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1423  - AIF2 EQ Band 4 C */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1424  - AIF2 EQ Band 4 PG */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1425  - AIF2 EQ Band 5 A */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1426  - AIF2 EQ Band 5 B */
-       { 0xFFFF, 0xFFFF, 0x0000 }, /* R1427  - AIF2 EQ Band 5 PG */
-       { 0x0000, 0x0000, 0x0000 }, /* R1428 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1429 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1430 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1431 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1432 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1433 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1434 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1435 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1436 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1437 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1438 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1439 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1440 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1441 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1442 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1443 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1444 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1445 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1446 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1447 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1448 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1449 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1450 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1451 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1452 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1453 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1454 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1455 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1456 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1457 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1458 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1459 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1460 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1461 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1462 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1463 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1464 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1465 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1466 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1467 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1468 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1469 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1470 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1471 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1472 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1473 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1474 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1475 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1476 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1477 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1478 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1479 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1480 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1481 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1482 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1483 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1484 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1485 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1486 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1487 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1488 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1489 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1490 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1491 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1492 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1493 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1494 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1495 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1496 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1497 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1498 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1499 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1500 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1501 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1502 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1503 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1504 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1505 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1506 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1507 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1508 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1509 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1510 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1511 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1512 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1513 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1514 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1515 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1516 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1517 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1518 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1519 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1520 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1521 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1522 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1523 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1524 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1525 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1526 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1527 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1528 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1529 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1530 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1531 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1532 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1533 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1534 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1535 */
-       { 0x01EF, 0x01EF, 0x0000 }, /* R1536  - DAC1 Mixer Volumes */
-       { 0x0037, 0x0037, 0x0000 }, /* R1537  - DAC1 Left Mixer Routing */
-       { 0x0037, 0x0037, 0x0000 }, /* R1538  - DAC1 Right Mixer Routing */
-       { 0x01EF, 0x01EF, 0x0000 }, /* R1539  - DAC2 Mixer Volumes */
-       { 0x0037, 0x0037, 0x0000 }, /* R1540  - DAC2 Left Mixer Routing */
-       { 0x0037, 0x0037, 0x0000 }, /* R1541  - DAC2 Right Mixer Routing */
-       { 0x0003, 0x0003, 0x0000 }, /* R1542  - AIF1 ADC1 Left Mixer Routing */
-       { 0x0003, 0x0003, 0x0000 }, /* R1543  - AIF1 ADC1 Right Mixer Routing */
-       { 0x0003, 0x0003, 0x0000 }, /* R1544  - AIF1 ADC2 Left Mixer Routing */
-       { 0x0003, 0x0003, 0x0000 }, /* R1545  - AIF1 ADC2 Right mixer Routing */
-       { 0x0000, 0x0000, 0x0000 }, /* R1546 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1547 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1548 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1549 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1550 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1551 */
-       { 0x02FF, 0x03FF, 0x0000 }, /* R1552  - DAC1 Left Volume */
-       { 0x02FF, 0x03FF, 0x0000 }, /* R1553  - DAC1 Right Volume */
-       { 0x02FF, 0x03FF, 0x0000 }, /* R1554  - DAC2 Left Volume */
-       { 0x02FF, 0x03FF, 0x0000 }, /* R1555  - DAC2 Right Volume */
-       { 0x0003, 0x0003, 0x0000 }, /* R1556  - DAC Softmute */
-       { 0x0000, 0x0000, 0x0000 }, /* R1557 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1558 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1559 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1560 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1561 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1562 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1563 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1564 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1565 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1566 */
-       { 0x0000, 0x0000, 0x0000 }, /* R1567 */
-       { 0x0003, 0x0003, 0x0000 }, /* R1568  - Oversampling */
-       { 0x03C3, 0x03C3, 0x0000 }, /* R1569  - Sidetone */
+       { 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)
@@ -1902,8 +1900,6 @@ static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol,
        return snd_soc_put_volsw(kcontrol, ucontrol);
 }
 
-
-
 static void wm8994_set_drc(struct snd_soc_codec *codec, int drc)
 {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
@@ -1942,7 +1938,7 @@ static int wm8994_put_drc_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_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994_pdata *pdata = wm8994->pdata;
        int drc = wm8994_get_drc(kcontrol->id.name);
        int value = ucontrol->value.integer.value[0];
@@ -2045,7 +2041,7 @@ static int wm8994_put_retune_mobile_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_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994_pdata *pdata = wm8994->pdata;
        int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
        int value = ucontrol->value.integer.value[0];
@@ -2067,7 +2063,7 @@ static int wm8994_get_retune_mobile_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_priv *wm8994 =snd_soc_codec_get_drvdata(codec);
        int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
 
        ucontrol->value.enumerated.item[0] = wm8994->retune_mobile_cfg[block];
@@ -2075,6 +2071,22 @@ static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+static const char *aifdac_src_text[] = {
+       "Left", "Right"
+};
+
+static const struct soc_enum aif1dacl_src =
+       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 15, 2, aifdac_src_text);
+
+static const struct soc_enum aif1dacr_src =
+       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 14, 2, aifdac_src_text);
+
+static const struct soc_enum aif2dacl_src =
+       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 15, 2, aifdac_src_text);
+
+static const struct soc_enum aif2dacr_src =
+       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 14, 2, aifdac_src_text);
+
 static const struct snd_kcontrol_new wm8994_snd_controls[] = {
 SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME,
                 WM8994_AIF1_ADC1_RIGHT_VOLUME,
@@ -2086,6 +2098,11 @@ SOC_DOUBLE_R_TLV("AIF2ADC Volume", WM8994_AIF2_ADC_LEFT_VOLUME,
                 WM8994_AIF2_ADC_RIGHT_VOLUME,
                 1, 119, 0, digital_tlv),
 
+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_DOUBLE_R_TLV("AIF1DAC1 Volume", WM8994_AIF1_DAC1_LEFT_VOLUME,
                 WM8994_AIF1_DAC1_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
 SOC_DOUBLE_R_TLV("AIF1DAC2 Volume", WM8994_AIF1_DAC2_LEFT_VOLUME,
@@ -2881,10 +2898,9 @@ static int wm8994_get_fll_config(struct fll_div *fll,
        return 0;
 }
 
-static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
+static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                          unsigned int freq_in, unsigned int freq_out)
 {
-       struct snd_soc_codec *codec = dai->codec;
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        int reg_offset, ret;
        struct fll_div fll;
@@ -2995,8 +3011,15 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
        return 0;
 }
 
+
 static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 };
 
+static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
+                         unsigned int freq_in, unsigned int freq_out)
+{
+       return _wm8994_set_fll(dai->codec, id, src, freq_in, freq_out);
+}
+
 static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
                int clk_id, unsigned int freq, int dir)
 {
@@ -3313,20 +3336,24 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
                bclk_reg = WM8994_AIF1_BCLK;
                rate_reg = WM8994_AIF1_RATE;
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
-                   wm8994->lrclk_shared[0])
+                   wm8994->lrclk_shared[0]) {
                        lrclk_reg = WM8994_AIF1DAC_LRCLK;
-               else
+               } else {
                        lrclk_reg = WM8994_AIF1ADC_LRCLK;
+                       dev_dbg(codec->dev, "AIF1 using split LRCLK\n");
+               }
                break;
        case 2:
                aif1_reg = WM8994_AIF2_CONTROL_1;
                bclk_reg = WM8994_AIF2_BCLK;
                rate_reg = WM8994_AIF2_RATE;
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
-                   wm8994->lrclk_shared[1])
+                   wm8994->lrclk_shared[1]) {
                        lrclk_reg = WM8994_AIF2DAC_LRCLK;
-               else
+               } else {
                        lrclk_reg = WM8994_AIF2ADC_LRCLK;
+                       dev_dbg(codec->dev, "AIF2 using split LRCLK\n");
+               }
                break;
        default:
                return -EINVAL;
@@ -3491,7 +3518,7 @@ static int wm8994_set_tristate(struct snd_soc_dai *codec_dai, int tristate)
 #define WM8994_RATES SNDRV_PCM_RATE_8000_96000
 
 #define WM8994_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
-                       SNDRV_PCM_FMTBIT_S24_LE)
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
 static struct snd_soc_dai_ops wm8994_aif1_dai_ops = {
        .set_sysclk     = wm8994_set_dai_sysclk,
@@ -3515,9 +3542,9 @@ static struct snd_soc_dai_ops wm8994_aif3_dai_ops = {
        .set_tristate   = wm8994_set_tristate,
 };
 
-struct snd_soc_dai wm8994_dai[] = {
+static struct snd_soc_dai_driver wm8994_dai[] = {
        {
-               .name = "WM8994 AIF1",
+               .name = "wm8994-aif1",
                .id = 1,
                .playback = {
                        .stream_name = "AIF1 Playback",
@@ -3536,7 +3563,7 @@ struct snd_soc_dai wm8994_dai[] = {
                .ops = &wm8994_aif1_dai_ops,
        },
        {
-               .name = "WM8994 AIF2",
+               .name = "wm8994-aif2",
                .id = 2,
                .playback = {
                        .stream_name = "AIF2 Playback",
@@ -3555,7 +3582,7 @@ struct snd_soc_dai wm8994_dai[] = {
                .ops = &wm8994_aif2_dai_ops,
        },
        {
-               .name = "WM8994 AIF3",
+               .name = "wm8994-aif3",
                .id = 3,
                .playback = {
                        .stream_name = "AIF3 Playback",
@@ -3574,20 +3601,17 @@ struct snd_soc_dai wm8994_dai[] = {
                .ops = &wm8994_aif3_dai_ops,
        }
 };
-EXPORT_SYMBOL_GPL(wm8994_dai);
 
 #ifdef CONFIG_PM
-static int wm8994_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        int i, ret;
 
        for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
                memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i],
                       sizeof(struct fll_config));
-               ret = wm8994_set_fll(&codec->dai[0], i + 1, 0, 0, 0);
+               ret = _wm8994_set_fll(codec, i + 1, 0, 0, 0);
                if (ret < 0)
                        dev_warn(codec->dev, "Failed to stop FLL%d: %d\n",
                                 i + 1, ret);
@@ -3598,10 +3622,8 @@ static int wm8994_suspend(struct platform_device *pdev, pm_message_t state)
        return 0;
 }
 
-static int wm8994_resume(struct platform_device *pdev)
+static int wm8994_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        u16 *reg_cache = codec->reg_cache;
        int i, ret;
@@ -3630,7 +3652,7 @@ static int wm8994_resume(struct platform_device *pdev)
                if (!wm8994->fll_suspend[i].out)
                        continue;
 
-               ret = wm8994_set_fll(&codec->dai[0], i + 1,
+               ret = _wm8994_set_fll(codec, i + 1,
                                     wm8994->fll_suspend[i].src,
                                     wm8994->fll_suspend[i].in,
                                     wm8994->fll_suspend[i].out);
@@ -3648,7 +3670,7 @@ static int wm8994_resume(struct platform_device *pdev)
 
 static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
 {
-       struct snd_soc_codec *codec = &wm8994->codec;
+       struct snd_soc_codec *codec = wm8994->codec;
        struct wm8994_pdata *pdata = wm8994->pdata;
        struct snd_kcontrol_new controls[] = {
                SOC_ENUM_EXT("AIF1.1 EQ Mode",
@@ -3706,16 +3728,16 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
        wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts;
        wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts;
 
-       ret = snd_soc_add_controls(&wm8994->codec, controls,
+       ret = snd_soc_add_controls(wm8994->codec, controls,
                                   ARRAY_SIZE(controls));
        if (ret != 0)
-               dev_err(wm8994->codec.dev,
+               dev_err(wm8994->codec->dev,
                        "Failed to add ReTune Mobile controls: %d\n", ret);
 }
 
 static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
 {
-       struct snd_soc_codec *codec = &wm8994->codec;
+       struct snd_soc_codec *codec = wm8994->codec;
        struct wm8994_pdata *pdata = wm8994->pdata;
        int ret, i;
 
@@ -3747,7 +3769,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
                wm8994->drc_texts = kmalloc(sizeof(char *)
                                            * pdata->num_drc_cfgs, GFP_KERNEL);
                if (!wm8994->drc_texts) {
-                       dev_err(wm8994->codec.dev,
+                       dev_err(wm8994->codec->dev,
                                "Failed to allocate %d DRC config texts\n",
                                pdata->num_drc_cfgs);
                        return;
@@ -3759,10 +3781,10 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
                wm8994->drc_enum.max = pdata->num_drc_cfgs;
                wm8994->drc_enum.texts = wm8994->drc_texts;
 
-               ret = snd_soc_add_controls(&wm8994->codec, controls,
+               ret = snd_soc_add_controls(wm8994->codec, controls,
                                           ARRAY_SIZE(controls));
                if (ret != 0)
-                       dev_err(wm8994->codec.dev,
+                       dev_err(wm8994->codec->dev,
                                "Failed to add DRC mode controls: %d\n", ret);
 
                for (i = 0; i < WM8994_NUM_DRC; i++)
@@ -3775,62 +3797,10 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
        if (pdata->num_retune_mobile_cfgs)
                wm8994_handle_retune_mobile_pdata(wm8994);
        else
-               snd_soc_add_controls(&wm8994->codec, wm8994_eq_controls,
+               snd_soc_add_controls(wm8994->codec, wm8994_eq_controls,
                                     ARRAY_SIZE(wm8994_eq_controls));
 }
 
-static int wm8994_probe(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
-
-       if (wm8994_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
-       }
-
-       socdev->card->codec = wm8994_codec;
-       codec = wm8994_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               return ret;
-       }
-
-       wm8994_handle_pdata(snd_soc_codec_get_drvdata(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,
-                                 ARRAY_SIZE(wm8994_dapm_widgets));
-       wm_hubs_add_analogue_routes(codec, 0, 0);
-       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
-
-       return 0;
-}
-
-static int wm8994_remove(struct platform_device *pdev)
-{
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
-       return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_wm8994 = {
-       .probe =        wm8994_probe,
-       .remove =       wm8994_remove,
-       .suspend =      wm8994_suspend,
-       .resume =       wm8994_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8994);
-
 /**
  * wm8994_mic_detect - Enable microphone detection via the WM8994 IRQ
  *
@@ -3842,7 +3812,7 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8994);
  *
  * Enable microphone detection via IRQ on the WM8994.  If GPIOs are
  * being used to bring out signals to the processor then only platform
- * data configuration is needed for WM8903 and processor GPIOs should
+ * data configuration is needed for WM8994 and processor GPIOs should
  * be configured using snd_soc_jack_add_gpios() instead.
  *
  * Configuration of detection levels is available via the micbias1_lvl
@@ -3889,7 +3859,7 @@ EXPORT_SYMBOL_GPL(wm8994_mic_detect);
 static irqreturn_t wm8994_mic_irq(int irq, void *data)
 {
        struct wm8994_priv *priv = data;
-       struct snd_soc_codec *codec = &priv->codec;
+       struct snd_soc_codec *codec = priv->codec;
        int reg;
        int report;
 
@@ -3921,46 +3891,20 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int wm8994_codec_probe(struct platform_device *pdev)
+static int wm8994_codec_probe(struct snd_soc_codec *codec)
 {
-       int ret;
        struct wm8994_priv *wm8994;
-       struct snd_soc_codec *codec;
-       int i;
+       int ret, i;
 
-       if (wm8994_codec) {
-               dev_err(&pdev->dev, "Another WM8994 is registered\n");
-               return -EINVAL;
-       }
+       codec->control_data = dev_get_drvdata(codec->dev->parent);
 
        wm8994 = kzalloc(sizeof(struct wm8994_priv), GFP_KERNEL);
-       if (!wm8994) {
-               dev_err(&pdev->dev, "Failed to allocate private data\n");
+       if (wm8994 == NULL)
                return -ENOMEM;
-       }
-
-       codec = &wm8994->codec;
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
        snd_soc_codec_set_drvdata(codec, wm8994);
-       codec->control_data = dev_get_drvdata(pdev->dev.parent);
-       codec->name = "WM8994";
-       codec->owner = THIS_MODULE;
-       codec->read = wm8994_read;
-       codec->write = wm8994_write;
-       codec->readable_register = wm8994_readable;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8994_set_bias_level;
-       codec->dai = &wm8994_dai[0];
-       codec->num_dai = 3;
-       codec->reg_cache_size = WM8994_MAX_REGISTER;
-       codec->reg_cache = &wm8994->reg_cache;
-       codec->dev = &pdev->dev;
-
-       wm8994->pdata = pdev->dev.parent->platform_data;
+
+       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,
@@ -3996,25 +3940,25 @@ static int wm8994_codec_probe(struct platform_device *pdev)
        ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC1_DET,
                                 wm8994_mic_irq, "Mic 1 detect", wm8994);
        if (ret != 0)
-               dev_warn(&pdev->dev,
+               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(&pdev->dev,
+               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(&pdev->dev,
+               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(&pdev->dev,
+               dev_warn(codec->dev,
                         "Failed to request Mic2 short IRQ: %d\n", ret);
 
        /* Remember if AIFnLRCLK is configured as a GPIO.  This should be
@@ -4045,13 +3989,8 @@ static int wm8994_codec_probe(struct platform_device *pdev)
                wm8994->lrclk_shared[1] = 0;
        }
 
-       for (i = 0; i < ARRAY_SIZE(wm8994_dai); i++)
-               wm8994_dai[i].dev = codec->dev;
-
        wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       wm8994_codec = codec;
-
        /* Latch volume updates (right only; we always do left then right). */
        snd_soc_update_bits(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME,
                            WM8994_AIF1DAC1_VU, WM8994_AIF1DAC1_VU);
@@ -4088,24 +4027,18 @@ static int wm8994_codec_probe(struct platform_device *pdev)
 
        wm8994_update_class_w(codec);
 
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err_irq;
-       }
-
-       ret = snd_soc_register_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai));
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
-               goto err_codec;
-       }
+       wm8994_handle_pdata(wm8994);
 
-       platform_set_drvdata(pdev, wm8994);
+       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,
+                                 ARRAY_SIZE(wm8994_dapm_widgets));
+       wm_hubs_add_analogue_routes(codec, 0, 0);
+       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
 
        return 0;
 
-err_codec:
-       snd_soc_unregister_codec(codec);
 err_irq:
        wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994);
        wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994);
@@ -4116,31 +4049,50 @@ err:
        return ret;
 }
 
-static int __devexit wm8994_codec_remove(struct platform_device *pdev)
+static int  wm8994_codec_remove(struct snd_soc_codec *codec)
 {
-       struct wm8994_priv *wm8994 = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = &wm8994->codec;
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai));
-       snd_soc_unregister_codec(&wm8994->codec);
+
        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);
        kfree(wm8994);
-       wm8994_codec = NULL;
 
        return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_wm8994 = {
+       .probe =        wm8994_codec_probe,
+       .remove =       wm8994_codec_remove,
+       .suspend =      wm8994_suspend,
+       .resume =       wm8994_resume,
+       .read = wm8994_read,
+       .write = wm8994_write,
+       .set_bias_level = wm8994_set_bias_level,
+};
+
+static int __devinit wm8994_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8994,
+                       wm8994_dai, ARRAY_SIZE(wm8994_dai));
+}
+
+static int __devexit wm8994_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
 static struct platform_driver wm8994_codec_driver = {
        .driver = {
                   .name = "wm8994-codec",
                   .owner = THIS_MODULE,
                   },
-       .probe = wm8994_codec_probe,
-       .remove = __devexit_p(wm8994_codec_remove),
+       .probe = wm8994_probe,
+       .remove = __devexit_p(wm8994_remove),
 };
 
 static __init int wm8994_init(void)
index 2e0ca67a8df7ad8f83c83c822190ae09d9395acf..d8dce260c430c31fa7544a63d5202a01aab10566 100644 (file)
@@ -11,9 +11,6 @@
 
 #include <sound/soc.h>
 
-extern struct snd_soc_codec_device soc_codec_dev_wm8994;
-extern struct snd_soc_dai wm8994_dai[];
-
 /* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */
 #define WM8994_SYSCLK_MCLK1 1
 #define WM8994_SYSCLK_MCLK2 2
index 76b37ff6c264915c3c4fdc470ebdfe2c3ec1cc0a..ecc7c37180c7ad2158f11b9de1579bde332cb44d 100644 (file)
@@ -156,7 +156,8 @@ static struct {
 };
 
 struct wm9081_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+       void *control_data;
        u16 reg_cache[WM9081_MAX_REGISTER + 1];
        int sysclk_source;
        int mclk_rate;
@@ -1212,8 +1213,8 @@ static struct snd_soc_dai_ops wm9081_dai_ops = {
 /* We report two channels because the CODEC processes a stereo signal, even
  * though it is only capable of handling a mono output.
  */
-struct snd_soc_dai wm9081_dai = {
-       .name = "WM9081",
+static struct snd_soc_dai_driver wm9081_dai = {
+       .name = "wm9081-hifi",
        .playback = {
                .stream_name = "HiFi Playback",
                .channels_min = 1,
@@ -1223,34 +1224,42 @@ struct snd_soc_dai wm9081_dai = {
        },
        .ops = &wm9081_dai_ops,
 };
-EXPORT_SYMBOL_GPL(wm9081_dai);
 
-
-static struct snd_soc_codec *wm9081_codec;
-
-static int wm9081_probe(struct platform_device *pdev)
+static int wm9081_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       struct wm9081_priv *wm9081;
-       int ret = 0;
+       struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+       u16 reg;
 
-       if (wm9081_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
+       codec->control_data = wm9081->control_data;
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm9081->control_type);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
-       socdev->card->codec = wm9081_codec;
-       codec = wm9081_codec;
-       wm9081 = snd_soc_codec_get_drvdata(codec);
+       reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET);
+       if (reg != 0x9081) {
+               dev_err(codec->dev, "Device is not a WM9081: ID=0x%x\n", reg);
+               ret = -EINVAL;
+               return ret;
+       }
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       ret = wm9081_reset(codec);
        if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
+               dev_err(codec->dev, "Failed to issue reset\n");
+               return ret;
        }
 
+       wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* Enable zero cross by default */
+       reg = snd_soc_read(codec, WM9081_ANALOGUE_LINEOUT);
+       snd_soc_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC);
+       reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_PGA);
+       snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_PGA,
+                    reg | WM9081_SPKPGAZC);
+
        snd_soc_add_controls(codec, wm9081_snd_controls,
                             ARRAY_SIZE(wm9081_snd_controls));
        if (!wm9081->retune) {
@@ -1265,40 +1274,28 @@ static int wm9081_probe(struct platform_device *pdev)
        snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
 
        return ret;
-
-pcm_err:
-       return ret;
 }
 
-static int wm9081_remove(struct platform_device *pdev)
+static int wm9081_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
+       wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
 #ifdef CONFIG_PM
-static int wm9081_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm9081_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int wm9081_resume(struct platform_device *pdev)
+static int wm9081_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        u16 *reg_cache = codec->reg_cache;
        int i;
 
-       for (i = 0; i < codec->reg_cache_size; i++) {
+       for (i = 0; i < codec->driver->reg_cache_size; i++) {
                if (i == WM9081_SOFTWARE_RESET)
                        continue;
 
@@ -1314,133 +1311,43 @@ static int wm9081_resume(struct platform_device *pdev)
 #define wm9081_resume NULL
 #endif
 
-struct snd_soc_codec_device soc_codec_dev_wm9081 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm9081 = {
        .probe =        wm9081_probe,
        .remove =       wm9081_remove,
        .suspend =      wm9081_suspend,
        .resume =       wm9081_resume,
+       .set_bias_level = wm9081_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm9081_reg_defaults),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm9081_reg_defaults,
+       .volatile_register = wm9081_volatile_register,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm9081);
-
-static int wm9081_register(struct wm9081_priv *wm9081,
-                          enum snd_soc_control_type control)
-{
-       struct snd_soc_codec *codec = &wm9081->codec;
-       int ret;
-       u16 reg;
-
-       if (wm9081_codec) {
-               dev_err(codec->dev, "Another WM9081 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm9081);
-       codec->name = "WM9081";
-       codec->owner = THIS_MODULE;
-       codec->dai = &wm9081_dai;
-       codec->num_dai = 1;
-       codec->reg_cache_size = ARRAY_SIZE(wm9081->reg_cache);
-       codec->reg_cache = &wm9081->reg_cache;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm9081_set_bias_level;
-       codec->volatile_register = wm9081_volatile_register;
-
-       memcpy(codec->reg_cache, wm9081_reg_defaults,
-              sizeof(wm9081_reg_defaults));
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
-       }
-
-       reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET);
-       if (reg != 0x9081) {
-               dev_err(codec->dev, "Device is not a WM9081: ID=0x%x\n", reg);
-               ret = -EINVAL;
-               goto err;
-       }
-
-       ret = wm9081_reset(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset\n");
-               goto err;
-       }
-
-       wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       /* Enable zero cross by default */
-       reg = snd_soc_read(codec, WM9081_ANALOGUE_LINEOUT);
-       snd_soc_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC);
-       reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_PGA);
-       snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_PGA,
-                    reg | WM9081_SPKPGAZC);
-
-       wm9081_dai.dev = codec->dev;
-
-       wm9081_codec = codec;
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-               goto err;
-       }
-
-       ret = snd_soc_register_dai(&wm9081_dai);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
-
-       return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm9081);
-       return ret;
-}
-
-static void wm9081_unregister(struct wm9081_priv *wm9081)
-{
-       wm9081_set_bias_level(&wm9081->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dai(&wm9081_dai);
-       snd_soc_unregister_codec(&wm9081->codec);
-       kfree(wm9081);
-       wm9081_codec = NULL;
-}
 
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm9081_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm9081_priv *wm9081;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm9081 = kzalloc(sizeof(struct wm9081_priv), GFP_KERNEL);
        if (wm9081 == NULL)
                return -ENOMEM;
 
-       codec = &wm9081->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-       wm9081->retune = i2c->dev.platform_data;
-
        i2c_set_clientdata(i2c, wm9081);
-       codec->control_data = i2c;
-
-       codec->dev = &i2c->dev;
+       wm9081->control_data = i2c;
 
-       return wm9081_register(wm9081, SND_SOC_I2C);
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm9081, &wm9081_dai, 1);
+       if (ret < 0)
+               kfree(wm9081);
+       return ret;
 }
 
 static __devexit int wm9081_i2c_remove(struct i2c_client *client)
 {
-       struct wm9081_priv *wm9081 = i2c_get_clientdata(client);
-       wm9081_unregister(wm9081);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -1452,31 +1359,34 @@ MODULE_DEVICE_TABLE(i2c, wm9081_i2c_id);
 
 static struct i2c_driver wm9081_i2c_driver = {
        .driver = {
-               .name = "wm9081",
+               .name = "wm9081-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm9081_i2c_probe,
        .remove =   __devexit_p(wm9081_i2c_remove),
        .id_table = wm9081_i2c_id,
 };
+#endif
 
 static int __init wm9081_modinit(void)
 {
-       int ret;
-
+       int ret = 0;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm9081_i2c_driver);
        if (ret != 0) {
                printk(KERN_ERR "Failed to register WM9081 I2C driver: %d\n",
                       ret);
        }
-
+#endif
        return ret;
 }
 module_init(wm9081_modinit);
 
 static void __exit wm9081_exit(void)
 {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        i2c_del_driver(&wm9081_i2c_driver);
+#endif
 }
 module_exit(wm9081_exit);
 
index 42d3bc757021f554b1f94f44b02e01f4d4496142..871cccb066dcbeba2f6b83a265ffaed86135e19f 100644 (file)
@@ -15,9 +15,6 @@
 
 #include <sound/soc.h>
 
-extern struct snd_soc_dai wm9081_dai;
-extern struct snd_soc_codec_device soc_codec_dev_wm9081;
-
 /*
  * SYSCLK sources
  */
index 1592250daec0ff0eda0896536d2a8d1234951b17..7a1825418ee49a47d0d4bcbbb8ce8b28d298b143 100644 (file)
@@ -34,8 +34,6 @@
 
 #include "wm9090.h"
 
-static struct snd_soc_codec *wm9090_codec;
-
 static const u16 wm9090_reg_defaults[] = {
        0x9093,     /* R0   - Software Reset */
        0x0006,     /* R1   - Power Management (1) */
@@ -142,15 +140,10 @@ static const u16 wm9090_reg_defaults[] = {
 
 /* This struct is used to save the context */
 struct wm9090_priv {
-       /* We're not really registering as a CODEC since ASoC core
-        * does not yet support multiple CODECs but having the CODEC
-        * structure means we can reuse some of the ASoC core
-        * features.
-        */
-       struct snd_soc_codec codec;
        struct mutex mutex;
        u16 reg_cache[WM9090_MAX_REGISTER + 1];
        struct wm9090_platform_data pdata;
+       void *control_data;
 };
 
 static int wm9090_volatile(unsigned int reg)
@@ -523,7 +516,7 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_STANDBY:
                if (codec->bias_level == SND_SOC_BIAS_OFF) {
                        /* Restore the register cache */
-                       for (i = 1; i < codec->reg_cache_size; i++) {
+                       for (i = 1; i < codec->driver->reg_cache_size; i++) {
                                if (reg_cache[i] == wm9090_reg_defaults[i])
                                        continue;
                                if (wm9090_volatile(i))
@@ -556,51 +549,67 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-static int wm9090_probe(struct platform_device *pdev)
+static int wm9090_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
-       int ret = 0;
+       struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec);
+       int ret;
 
-       if (wm9090_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
+       codec->control_data = wm9090->control_data;
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
-       socdev->card->codec = wm9090_codec;
-       codec = wm9090_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
+       ret = snd_soc_read(codec, WM9090_SOFTWARE_RESET);
+       if (ret < 0)
+               return ret;
+       if (ret != wm9090_reg_defaults[WM9090_SOFTWARE_RESET]) {
+               dev_err(codec->dev, "Device is not a WM9090, ID=%x\n", ret);
+               return -EINVAL;
        }
 
+       ret = snd_soc_write(codec, WM9090_SOFTWARE_RESET, 0);
+       if (ret < 0)
+               return ret;
+
+       /* Configure some defaults; they will be written out when we
+        * bring the bias up.
+        */
+       wm9090->reg_cache[WM9090_IN1_LINE_INPUT_A_VOLUME] |= WM9090_IN1_VU
+               | WM9090_IN1A_ZC;
+       wm9090->reg_cache[WM9090_IN1_LINE_INPUT_B_VOLUME] |= WM9090_IN1_VU
+               | WM9090_IN1B_ZC;
+       wm9090->reg_cache[WM9090_IN2_LINE_INPUT_A_VOLUME] |= WM9090_IN2_VU
+               | WM9090_IN2A_ZC;
+       wm9090->reg_cache[WM9090_IN2_LINE_INPUT_B_VOLUME] |= WM9090_IN2_VU
+               | WM9090_IN2B_ZC;
+       wm9090->reg_cache[WM9090_SPEAKER_VOLUME_LEFT] |=
+               WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC;
+       wm9090->reg_cache[WM9090_LEFT_OUTPUT_VOLUME] |=
+               WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC;
+       wm9090->reg_cache[WM9090_RIGHT_OUTPUT_VOLUME] |=
+               WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC;
+
+       wm9090->reg_cache[WM9090_CLOCKING_1] |= WM9090_TOCLK_ENA;
+
+       wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
        wm9090_add_controls(codec);
 
        return 0;
-
-pcm_err:
-       return ret;
 }
 
 #ifdef CONFIG_PM
-static int wm9090_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm9090_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int wm9090_resume(struct platform_device *pdev)
+static int wm9090_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
@@ -610,29 +619,29 @@ static int wm9090_resume(struct platform_device *pdev)
 #define wm9090_resume NULL
 #endif
 
-static int wm9090_remove(struct platform_device *pdev)
+static int wm9090_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
+       wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_wm9090 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm9090 = {
        .probe =        wm9090_probe,
        .remove =       wm9090_remove,
        .suspend =      wm9090_suspend,
        .resume =       wm9090_resume,
+       .set_bias_level = wm9090_set_bias_level,
+       .reg_cache_size = (WM9090_MAX_REGISTER + 1),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm9090_reg_defaults,
+       .volatile_register = wm9090_volatile,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm9090);
 
 static int wm9090_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct wm9090_priv *wm9090;
-       struct snd_soc_codec *codec;
        int ret;
 
        wm9090 = kzalloc(sizeof(*wm9090), GFP_KERNEL);
@@ -640,102 +649,28 @@ static int wm9090_i2c_probe(struct i2c_client *i2c,
                dev_err(&i2c->dev, "Can not allocate memory\n");
                return -ENOMEM;
        }
-       codec = &wm9090->codec;
 
        if (i2c->dev.platform_data)
                memcpy(&wm9090->pdata, i2c->dev.platform_data,
                       sizeof(wm9090->pdata));
 
-       wm9090_codec = codec;
-
        i2c_set_clientdata(i2c, wm9090);
+       wm9090->control_data = i2c;
+       mutex_init(&wm9090->mutex);
 
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       codec->control_data = i2c;
-       snd_soc_codec_set_drvdata(codec, wm9090);
-       codec->dev = &i2c->dev;
-       codec->name = "WM9090";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm9090_set_bias_level,
-       codec->reg_cache_size = WM9090_MAX_REGISTER + 1;
-       codec->reg_cache = &wm9090->reg_cache;
-       codec->volatile_register = wm9090_volatile;
-
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
-       }
-
-       memcpy(&wm9090->reg_cache, wm9090_reg_defaults,
-              sizeof(wm9090->reg_cache));
-
-       ret = snd_soc_read(codec, WM9090_SOFTWARE_RESET);
-       if (ret < 0)
-               goto err;
-       if (ret != wm9090_reg_defaults[WM9090_SOFTWARE_RESET]) {
-               dev_err(&i2c->dev, "Device is not a WM9090, ID=%x\n", ret);
-               ret = -EINVAL;
-               goto err;
-       }
-
-       ret = snd_soc_write(codec, WM9090_SOFTWARE_RESET, 0);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm9090,  NULL, 0);
        if (ret < 0)
-               goto err;
-
-       /* Configure some defaults; they will be written out when we
-        * bring the bias up.
-        */
-       wm9090->reg_cache[WM9090_IN1_LINE_INPUT_A_VOLUME] |= WM9090_IN1_VU
-               | WM9090_IN1A_ZC;
-       wm9090->reg_cache[WM9090_IN1_LINE_INPUT_B_VOLUME] |= WM9090_IN1_VU
-               | WM9090_IN1B_ZC;
-       wm9090->reg_cache[WM9090_IN2_LINE_INPUT_A_VOLUME] |= WM9090_IN2_VU
-               | WM9090_IN2A_ZC;
-       wm9090->reg_cache[WM9090_IN2_LINE_INPUT_B_VOLUME] |= WM9090_IN2_VU
-               | WM9090_IN2B_ZC;
-       wm9090->reg_cache[WM9090_SPEAKER_VOLUME_LEFT] |=
-               WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC;
-       wm9090->reg_cache[WM9090_LEFT_OUTPUT_VOLUME] |= 
-               WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC;
-       wm9090->reg_cache[WM9090_RIGHT_OUTPUT_VOLUME] |=
-               WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC;
-
-       wm9090->reg_cache[WM9090_CLOCKING_1] |= WM9090_TOCLK_ENA;
-
-       wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       ret = snd_soc_register_codec(codec);
-       if (ret != 0) {
-               dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
-               goto err_bias;
-       }
-
-       return 0;
-
-err_bias:
-       wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
-err:
-       kfree(wm9090);
-       i2c_set_clientdata(i2c, NULL);
-       wm9090_codec = NULL;
-
+               kfree(wm9090);
        return ret;
 }
 
 static int wm9090_i2c_remove(struct i2c_client *i2c)
 {
        struct wm9090_priv *wm9090 = i2c_get_clientdata(i2c);
-       struct snd_soc_codec *codec = &wm9090->codec;
 
-       snd_soc_unregister_codec(codec);
-       wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       snd_soc_unregister_codec(&i2c->dev);
        kfree(wm9090);
-       wm9090_codec = NULL;
 
        return 0;
 }
@@ -748,7 +683,7 @@ MODULE_DEVICE_TABLE(i2c, wm9090_id);
 
 static struct i2c_driver wm9090_i2c_driver = {
        .driver = {
-               .name = "wm9090",
+               .name = "wm9090-codec",
                .owner = THIS_MODULE,
        },
        .probe = wm9090_i2c_probe,
index b08eab932a5b795ed037f7dac8843f88fa2eb172..29b9d9fc70b4cc20501d2529cfcbcc6c949dffdb 100644 (file)
@@ -23,8 +23,6 @@
 #ifndef __WM9090_H
 #define __WM9090_H
 
-extern struct snd_soc_codec_device soc_codec_dev_wm9090;
-
 /*
  * Register values.
  */
index 8793341849d1bafdc2e13f1c7564bd655cf440fe..a144acda751cb7578954abe12310a0759bd1dec4 100644 (file)
@@ -248,8 +248,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        int reg;
        u16 vra;
 
@@ -273,9 +272,9 @@ static struct snd_soc_dai_ops wm9705_dai_ops = {
        .prepare        = ac97_prepare,
 };
 
-struct snd_soc_dai wm9705_dai[] = {
+static struct snd_soc_dai_driver wm9705_dai[] = {
        {
-               .name = "AC97 HiFi",
+               .name = "wm9705-hifi",
                .ac97_control = 1,
                .playback = {
                        .stream_name = "HiFi Playback",
@@ -294,7 +293,7 @@ struct snd_soc_dai wm9705_dai[] = {
                .ops = &wm9705_dai_ops,
        },
        {
-               .name = "AC97 Aux",
+               .name = "wm9705-aux",
                .playback = {
                        .stream_name = "Aux Playback",
                        .channels_min = 1,
@@ -304,7 +303,6 @@ struct snd_soc_dai wm9705_dai[] = {
                },
        }
 };
-EXPORT_SYMBOL_GPL(wm9705_dai);
 
 static int wm9705_reset(struct snd_soc_codec *codec)
 {
@@ -318,20 +316,15 @@ static int wm9705_reset(struct snd_soc_codec *codec)
 }
 
 #ifdef CONFIG_PM
-static int wm9705_soc_suspend(struct platform_device *pdev, pm_message_t msg)
+static int wm9705_soc_suspend(struct snd_soc_codec *codec, pm_message_t msg)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        soc_ac97_ops.write(codec->ac97, AC97_POWERDOWN, 0xffff);
 
        return 0;
 }
 
-static int wm9705_soc_resume(struct platform_device *pdev)
+static int wm9705_soc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i, ret;
        u16 *cache = codec->reg_cache;
 
@@ -352,49 +345,18 @@ static int wm9705_soc_resume(struct platform_device *pdev)
 #define wm9705_soc_resume NULL
 #endif
 
-static int wm9705_soc_probe(struct platform_device *pdev)
+static int wm9705_soc_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
        int ret = 0;
 
        printk(KERN_INFO "WM9705 SoC Audio Codec\n");
 
-       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec),
-                                     GFP_KERNEL);
-       if (socdev->card->codec == NULL)
-               return -ENOMEM;
-       codec = socdev->card->codec;
-       mutex_init(&codec->mutex);
-
-       codec->reg_cache = kmemdup(wm9705_reg, sizeof(wm9705_reg), GFP_KERNEL);
-       if (codec->reg_cache == NULL) {
-               ret = -ENOMEM;
-               goto cache_err;
-       }
-       codec->reg_cache_size = sizeof(wm9705_reg);
-       codec->reg_cache_step = 2;
-
-       codec->name = "WM9705";
-       codec->owner = THIS_MODULE;
-       codec->dai = wm9705_dai;
-       codec->num_dai = ARRAY_SIZE(wm9705_dai);
-       codec->write = ac97_write;
-       codec->read = ac97_read;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0) {
                printk(KERN_ERR "wm9705: failed to register AC97 codec\n");
-               goto codec_err;
+               return ret;
        }
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0)
-               goto pcm_err;
-
        ret = wm9705_reset(codec);
        if (ret)
                goto reset_err;
@@ -406,40 +368,62 @@ static int wm9705_soc_probe(struct platform_device *pdev)
        return 0;
 
 reset_err:
-       snd_soc_free_pcms(socdev);
-pcm_err:
        snd_soc_free_ac97_codec(codec);
-codec_err:
-       kfree(codec->reg_cache);
-cache_err:
-       kfree(socdev->card->codec);
-       socdev->card->codec = NULL;
        return ret;
 }
 
-static int wm9705_soc_remove(struct platform_device *pdev)
+static int wm9705_soc_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec == NULL)
-               return 0;
-
-       snd_soc_dapm_free(socdev);
-       snd_soc_free_pcms(socdev);
        snd_soc_free_ac97_codec(codec);
-       kfree(codec->reg_cache);
-       kfree(codec);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_wm9705 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm9705 = {
        .probe =        wm9705_soc_probe,
        .remove =       wm9705_soc_remove,
        .suspend =      wm9705_soc_suspend,
        .resume =       wm9705_soc_resume,
+       .read = ac97_read,
+       .write = ac97_write,
+       .reg_cache_size = ARRAY_SIZE(wm9705_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_step = 2,
+       .reg_cache_default = wm9705_reg,
+};
+
+static __devinit int wm9705_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_wm9705, wm9705_dai, ARRAY_SIZE(wm9705_dai));
+}
+
+static int __devexit wm9705_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver wm9705_codec_driver = {
+       .driver = {
+                       .name = "wm9705-codec",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = wm9705_probe,
+       .remove = __devexit_p(wm9705_remove),
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm9705);
+
+static int __init wm9705_init(void)
+{
+       return platform_driver_register(&wm9705_codec_driver);
+}
+module_init(wm9705_init);
+
+static void __exit wm9705_exit(void)
+{
+       platform_driver_unregister(&wm9705_codec_driver);
+}
+module_exit(wm9705_exit);
 
 MODULE_DESCRIPTION("ASoC WM9705 driver");
 MODULE_AUTHOR("Ian Molton");
index d380f110f9e29c311f4ecbe83986fa6750ccb03b..23ea9ce473593b09e1ad753d271dc55f732c73df 100644 (file)
@@ -8,7 +8,4 @@
 #define WM9705_DAI_AC97_HIFI   0
 #define WM9705_DAI_AC97_AUX    1
 
-extern struct snd_soc_dai wm9705_dai[2];
-extern struct snd_soc_codec_device soc_codec_dev_wm9705;
-
 #endif
index 28790a2ffe8dab5c5663059bebadf4a491b3fdc2..d2f224d62744011dba3e2536edd05a87c17aa3b0 100644 (file)
@@ -478,8 +478,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec =rtd->codec;
        int reg;
        u16 vra;
 
@@ -499,8 +498,7 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream,
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_codec *codec = socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
        u16 vra, xsle;
 
        vra = ac97_read(codec, AC97_EXTENDED_STATUS);
@@ -526,9 +524,9 @@ static struct snd_soc_dai_ops wm9712_dai_ops_aux = {
        .prepare        = ac97_aux_prepare,
 };
 
-struct snd_soc_dai wm9712_dai[] = {
+static struct snd_soc_dai_driver wm9712_dai[] = {
 {
-       .name = "AC97 HiFi",
+       .name = "wm9712-hifi",
        .ac97_control = 1,
        .playback = {
                .stream_name = "HiFi Playback",
@@ -545,7 +543,7 @@ struct snd_soc_dai wm9712_dai[] = {
        .ops = &wm9712_dai_ops_hifi,
 },
 {
-       .name = "AC97 Aux",
+       .name = "wm9712-aux",
        .playback = {
                .stream_name = "Aux Playback",
                .channels_min = 1,
@@ -555,7 +553,6 @@ struct snd_soc_dai wm9712_dai[] = {
        .ops = &wm9712_dai_ops_aux,
 }
 };
-EXPORT_SYMBOL_GPL(wm9712_dai);
 
 static int wm9712_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
@@ -597,20 +594,15 @@ err:
        return -EIO;
 }
 
-static int wm9712_soc_suspend(struct platform_device *pdev,
+static int wm9712_soc_suspend(struct snd_soc_codec *codec,
        pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm9712_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-static int wm9712_soc_resume(struct platform_device *pdev)
+static int wm9712_soc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i, ret;
        u16 *cache = codec->reg_cache;
 
@@ -635,51 +627,18 @@ static int wm9712_soc_resume(struct platform_device *pdev)
        return ret;
 }
 
-static int wm9712_soc_probe(struct platform_device *pdev)
+static int wm9712_soc_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
        int ret = 0;
 
        printk(KERN_INFO "WM9711/WM9712 SoC Audio Codec %s\n", WM9712_VERSION);
 
-       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec),
-                                     GFP_KERNEL);
-       if (socdev->card->codec == NULL)
-               return -ENOMEM;
-       codec = socdev->card->codec;
-       mutex_init(&codec->mutex);
-
-       codec->reg_cache = kmemdup(wm9712_reg, sizeof(wm9712_reg), GFP_KERNEL);
-
-       if (codec->reg_cache == NULL) {
-               ret = -ENOMEM;
-               goto cache_err;
-       }
-       codec->reg_cache_size = sizeof(wm9712_reg);
-       codec->reg_cache_step = 2;
-
-       codec->name = "WM9712";
-       codec->owner = THIS_MODULE;
-       codec->dai = wm9712_dai;
-       codec->num_dai = ARRAY_SIZE(wm9712_dai);
-       codec->write = ac97_write;
-       codec->read = ac97_read;
-       codec->set_bias_level = wm9712_set_bias_level;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0) {
                printk(KERN_ERR "wm9712: failed to register AC97 codec\n");
-               goto codec_err;
+               return ret;
        }
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0)
-               goto pcm_err;
-
        ret = wm9712_reset(codec, 0);
        if (ret < 0) {
                printk(KERN_ERR "Failed to reset WM9712: AC97 link error\n");
@@ -697,42 +656,63 @@ static int wm9712_soc_probe(struct platform_device *pdev)
        return 0;
 
 reset_err:
-       snd_soc_free_pcms(socdev);
-pcm_err:
        snd_soc_free_ac97_codec(codec);
-
-codec_err:
-       kfree(codec->reg_cache);
-
-cache_err:
-       kfree(socdev->card->codec);
-       socdev->card->codec = NULL;
        return ret;
 }
 
-static int wm9712_soc_remove(struct platform_device *pdev)
+static int wm9712_soc_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec == NULL)
-               return 0;
-
-       snd_soc_dapm_free(socdev);
-       snd_soc_free_pcms(socdev);
        snd_soc_free_ac97_codec(codec);
-       kfree(codec->reg_cache);
-       kfree(codec);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_wm9712 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm9712 = {
        .probe =        wm9712_soc_probe,
        .remove =       wm9712_soc_remove,
        .suspend =      wm9712_soc_suspend,
        .resume =       wm9712_soc_resume,
+       .read = ac97_read,
+       .write = ac97_write,
+       .set_bias_level = wm9712_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm9712_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_step = 2,
+       .reg_cache_default = wm9712_reg,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm9712);
+
+static __devinit int wm9712_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_wm9712, wm9712_dai, ARRAY_SIZE(wm9712_dai));
+}
+
+static int __devexit wm9712_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver wm9712_codec_driver = {
+       .driver = {
+                       .name = "wm9712-codec",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = wm9712_probe,
+       .remove = __devexit_p(wm9712_remove),
+};
+
+static int __init wm9712_init(void)
+{
+       return platform_driver_register(&wm9712_codec_driver);
+}
+module_init(wm9712_init);
+
+static void __exit wm9712_exit(void)
+{
+       platform_driver_unregister(&wm9712_codec_driver);
+}
+module_exit(wm9712_exit);
 
 MODULE_DESCRIPTION("ASoC WM9711/WM9712 driver");
 MODULE_AUTHOR("Liam Girdwood");
index d29e8a18ca6d2abc6aa67d1c717f571978703a82..fb69c3aa4ed01d1f554c1f27b8267d5a0806be24 100644 (file)
@@ -8,7 +8,4 @@
 #define WM9712_DAI_AC97_HIFI   0
 #define WM9712_DAI_AC97_AUX            1
 
-extern struct snd_soc_dai wm9712_dai[2];
-extern struct snd_soc_codec_device soc_codec_dev_wm9712;
-
 #endif
index 34e0c91092fa1f2cd7e03c0905a0b30fd404250c..7da13b07a53dfdbc5559e9eb21f140334145ed10 100644 (file)
@@ -1057,9 +1057,9 @@ static struct snd_soc_dai_ops wm9713_dai_ops_voice = {
        .set_tristate   = wm9713_set_dai_tristate,
 };
 
-struct snd_soc_dai wm9713_dai[] = {
+static struct snd_soc_dai_driver wm9713_dai[] = {
 {
-       .name = "AC97 HiFi",
+       .name = "wm9713-hifi",
        .ac97_control = 1,
        .playback = {
                .stream_name = "HiFi Playback",
@@ -1076,7 +1076,7 @@ struct snd_soc_dai wm9713_dai[] = {
        .ops = &wm9713_dai_ops_hifi,
        },
        {
-       .name = "AC97 Aux",
+       .name = "wm9713-aux",
        .playback = {
                .stream_name = "Aux Playback",
                .channels_min = 1,
@@ -1086,7 +1086,7 @@ struct snd_soc_dai wm9713_dai[] = {
        .ops = &wm9713_dai_ops_aux,
        },
        {
-       .name = "WM9713 Voice",
+       .name = "wm9713-voice",
        .playback = {
                .stream_name = "Voice Playback",
                .channels_min = 1,
@@ -1103,7 +1103,6 @@ struct snd_soc_dai wm9713_dai[] = {
        .symmetric_rates = 1,
        },
 };
-EXPORT_SYMBOL_GPL(wm9713_dai);
 
 int wm9713_reset(struct snd_soc_codec *codec, int try_warm)
 {
@@ -1152,11 +1151,9 @@ static int wm9713_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
-static int wm9713_soc_suspend(struct platform_device *pdev,
+static int wm9713_soc_suspend(struct snd_soc_codec *codec,
        pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        u16 reg;
 
        /* Disable everything except touchpanel - that will be handled
@@ -1171,10 +1168,8 @@ static int wm9713_soc_suspend(struct platform_device *pdev,
        return 0;
 }
 
-static int wm9713_soc_resume(struct platform_device *pdev)
+static int wm9713_soc_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
        int i, ret;
        u16 *cache = codec->reg_cache;
@@ -1204,53 +1199,20 @@ static int wm9713_soc_resume(struct platform_device *pdev)
        return ret;
 }
 
-static int wm9713_soc_probe(struct platform_device *pdev)
+static int wm9713_soc_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
+       struct wm9713_priv *wm9713;
        int ret = 0, reg;
 
-       socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec),
-                                     GFP_KERNEL);
-       if (socdev->card->codec == NULL)
+       wm9713 = kzalloc(sizeof(struct wm9713_priv), GFP_KERNEL);
+       if (wm9713 == NULL)
                return -ENOMEM;
-       codec = socdev->card->codec;
-       mutex_init(&codec->mutex);
-
-       codec->reg_cache = kmemdup(wm9713_reg, sizeof(wm9713_reg), GFP_KERNEL);
-       if (codec->reg_cache == NULL) {
-               ret = -ENOMEM;
-               goto cache_err;
-       }
-       codec->reg_cache_size = sizeof(wm9713_reg);
-       codec->reg_cache_step = 2;
-
-       snd_soc_codec_set_drvdata(codec, kzalloc(sizeof(struct wm9713_priv),
-                                                GFP_KERNEL));
-       if (snd_soc_codec_get_drvdata(codec) == NULL) {
-               ret = -ENOMEM;
-               goto priv_err;
-       }
-
-       codec->name = "WM9713";
-       codec->owner = THIS_MODULE;
-       codec->dai = wm9713_dai;
-       codec->num_dai = ARRAY_SIZE(wm9713_dai);
-       codec->write = ac97_write;
-       codec->read = ac97_read;
-       codec->set_bias_level = wm9713_set_bias_level;
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
+       snd_soc_codec_set_drvdata(codec, wm9713);
 
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0)
                goto codec_err;
 
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-       if (ret < 0)
-               goto pcm_err;
-
        /* do a cold reset for the controller and then try
         * a warm reset followed by an optional cold reset for codec */
        wm9713_reset(codec, 0);
@@ -1273,46 +1235,67 @@ static int wm9713_soc_probe(struct platform_device *pdev)
        return 0;
 
 reset_err:
-       snd_soc_free_pcms(socdev);
-pcm_err:
        snd_soc_free_ac97_codec(codec);
-
 codec_err:
-       kfree(snd_soc_codec_get_drvdata(codec));
-
-priv_err:
-       kfree(codec->reg_cache);
-
-cache_err:
-       kfree(socdev->card->codec);
-       socdev->card->codec = NULL;
+       kfree(wm9713);
        return ret;
 }
 
-static int wm9713_soc_remove(struct platform_device *pdev)
+static int wm9713_soc_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       if (codec == NULL)
-               return 0;
-
-       snd_soc_dapm_free(socdev);
-       snd_soc_free_pcms(socdev);
+       struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
        snd_soc_free_ac97_codec(codec);
-       kfree(snd_soc_codec_get_drvdata(codec));
-       kfree(codec->reg_cache);
-       kfree(codec);
+       kfree(wm9713);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_wm9713 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm9713 = {
        .probe =        wm9713_soc_probe,
        .remove =       wm9713_soc_remove,
        .suspend =      wm9713_soc_suspend,
        .resume =       wm9713_soc_resume,
+       .read = ac97_read,
+       .write = ac97_write,
+       .set_bias_level = wm9713_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(wm9713_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_step = 2,
+       .reg_cache_default = wm9713_reg,
+};
+
+static __devinit int wm9713_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_wm9713, wm9713_dai, ARRAY_SIZE(wm9713_dai));
+}
+
+static int __devexit wm9713_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver wm9713_codec_driver = {
+       .driver = {
+                       .name = "wm9713-codec",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = wm9713_probe,
+       .remove = __devexit_p(wm9713_remove),
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm9713);
+
+static int __init wm9713_init(void)
+{
+       return platform_driver_register(&wm9713_codec_driver);
+}
+module_init(wm9713_init);
+
+static void __exit wm9713_exit(void)
+{
+       platform_driver_unregister(&wm9713_codec_driver);
+}
+module_exit(wm9713_exit);
 
 MODULE_DESCRIPTION("ASoC WM9713/WM9714 driver");
 MODULE_AUTHOR("Liam Girdwood");
index 63b8d81756e3a50daaeffd777da56539a6f2ad9f..793da863a03d94096aa130f5f88757ef5f23eb9c 100644 (file)
@@ -45,9 +45,6 @@
 #define WM9713_DAI_AC97_AUX            1
 #define WM9713_DAI_PCM_VOICE   2
 
-extern struct snd_soc_codec_device soc_codec_dev_wm9713;
-extern struct snd_soc_dai wm9713_dai[3];
-
 int wm9713_reset(struct snd_soc_codec *codec,  int try_warm);
 
 #endif
index 97f74d6a33e6b56cc87ec542b259bcf4c59c91cb..2b07b17a6b2d68f3173380bc16de4eb07b921689 100644 (file)
 #include <mach/mux.h>
 
 #include "../codecs/tlv320aic3x.h"
-#include "../codecs/cq93vc.h"
-#include "../codecs/spdif_transciever.h"
 #include "davinci-pcm.h"
 #include "davinci-i2s.h"
 #include "davinci-mcasp.h"
-#include "davinci-vcif.h"
 
 #define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \
                SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF)
@@ -41,8 +38,8 @@ static int evm_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret = 0;
        unsigned sysclk;
 
@@ -87,7 +84,7 @@ static int evm_spdif_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
        /* set cpu DAI configuration */
        return snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT);
@@ -132,8 +129,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
 };
 
 /* Logic for a aic3x as connected on a davinci-evm */
-static int evm_aic3x_init(struct snd_soc_codec *codec)
+static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        /* Add davinci-evm specific widgets */
        snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
                                  ARRAY_SIZE(aic3x_dapm_widgets));
@@ -161,8 +160,10 @@ static int evm_aic3x_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link evm_dai = {
        .name = "TLV320AIC3X",
        .stream_name = "AIC3X",
-       .cpu_dai = &davinci_i2s_dai,
-       .codec_dai = &aic3x_dai,
+       .cpu_dai_name = "davinci-mcasp.0",
+       .codec_dai_name = "tlv320aic3x-hifi",
+       .codec_name = "tlv320aic3x-codec.0-001a",
+       .platform_name = "davinci-pcm-audio",
        .init = evm_aic3x_init,
        .ops = &evm_ops,
 };
@@ -171,40 +172,49 @@ static struct snd_soc_dai_link dm365_evm_dai = {
 #ifdef CONFIG_SND_DM365_AIC3X_CODEC
        .name = "TLV320AIC3X",
        .stream_name = "AIC3X",
-       .cpu_dai = &davinci_i2s_dai,
-       .codec_dai = &aic3x_dai,
+       .cpu_dai_name = "davinci-i2s",
+       .codec_dai_name = "tlv320aic3x-hifi",
        .init = evm_aic3x_init,
+       .codec_name = "tlv320aic3x-codec.0-001a",
        .ops = &evm_ops,
 #elif defined(CONFIG_SND_DM365_VOICE_CODEC)
        .name = "Voice Codec - CQ93VC",
        .stream_name = "CQ93",
-       .cpu_dai = &davinci_vcif_dai,
-       .codec_dai = &cq93vc_dai,
+       .cpu_dai_name = "davinci-vcif",
+       .codec_dai_name = "cq93vc-hifi",
+       .codec_name = "cq93vc-codec",
 #endif
+       .platform_name = "davinci-pcm-audio",
 };
 
 static struct snd_soc_dai_link dm6467_evm_dai[] = {
        {
                .name = "TLV320AIC3X",
                .stream_name = "AIC3X",
-               .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_I2S_DAI],
-               .codec_dai = &aic3x_dai,
+               .cpu_dai_name= "davinci-mcasp.0",
+               .codec_dai_name = "tlv320aic3x-hifi",
+               .platform_name ="davinci-pcm-audio",
+               .codec_name = "tlv320aic3x-codec.0-001a",
                .init = evm_aic3x_init,
                .ops = &evm_ops,
        },
        {
                .name = "McASP",
                .stream_name = "spdif",
-               .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_DIT_DAI],
-               .codec_dai = &dit_stub_dai,
+               .cpu_dai_name= "davinci-mcasp.1",
+               .codec_dai_name = "dit-hifi",
+               .codec_name = "spdif_dit",
+               .platform_name = "davinci-pcm-audio",
                .ops = &evm_spdif_ops,
        },
 };
 static struct snd_soc_dai_link da8xx_evm_dai = {
        .name = "TLV320AIC3X",
        .stream_name = "AIC3X",
-       .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_I2S_DAI],
-       .codec_dai = &aic3x_dai,
+       .cpu_dai_name= "davinci-mcasp.0",
+       .codec_dai_name = "tlv320aic3x-hifi",
+       .codec_name = "tlv320aic3x-codec.0-001a",
+       .platform_name = "davinci-pcm-audio",
        .init = evm_aic3x_init,
        .ops = &evm_ops,
 };
@@ -212,7 +222,6 @@ static struct snd_soc_dai_link da8xx_evm_dai = {
 /* davinci dm6446, dm355 evm audio machine driver */
 static struct snd_soc_card snd_soc_card_evm = {
        .name = "DaVinci EVM",
-       .platform = &davinci_soc_platform,
        .dai_link = &evm_dai,
        .num_links = 1,
 };
@@ -220,16 +229,13 @@ static struct snd_soc_card snd_soc_card_evm = {
 /* davinci dm365 evm audio machine driver */
 static struct snd_soc_card dm365_snd_soc_card_evm = {
        .name = "DaVinci DM365 EVM",
-       .platform = &davinci_soc_platform,
        .dai_link = &dm365_evm_dai,
        .num_links = 1,
 };
 
-
 /* davinci dm6467 evm audio machine driver */
 static struct snd_soc_card dm6467_snd_soc_card_evm = {
        .name = "DaVinci DM6467 EVM",
-       .platform = &davinci_soc_platform,
        .dai_link = dm6467_evm_dai,
        .num_links = ARRAY_SIZE(dm6467_evm_dai),
 };
@@ -237,82 +243,40 @@ static struct snd_soc_card dm6467_snd_soc_card_evm = {
 static struct snd_soc_card da830_snd_soc_card = {
        .name = "DA830/OMAP-L137 EVM",
        .dai_link = &da8xx_evm_dai,
-       .platform = &davinci_soc_platform,
        .num_links = 1,
 };
 
 static struct snd_soc_card da850_snd_soc_card = {
        .name = "DA850/OMAP-L138 EVM",
        .dai_link = &da8xx_evm_dai,
-       .platform = &davinci_soc_platform,
        .num_links = 1,
 };
 
-static struct aic3x_setup_data aic3x_setup;
-
-/* evm audio subsystem */
-static struct snd_soc_device evm_snd_devdata = {
-       .card = &snd_soc_card_evm,
-       .codec_dev = &soc_codec_dev_aic3x,
-       .codec_data = &aic3x_setup,
-};
-
-/* evm audio subsystem */
-static struct snd_soc_device dm365_evm_snd_devdata = {
-       .card = &dm365_snd_soc_card_evm,
-#ifdef CONFIG_SND_DM365_AIC3X_CODEC
-       .codec_dev = &soc_codec_dev_aic3x,
-       .codec_data = &aic3x_setup,
-#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
-       .codec_dev = &soc_codec_dev_cq93vc,
-#endif
-};
-
-/* evm audio subsystem */
-static struct snd_soc_device dm6467_evm_snd_devdata = {
-       .card = &dm6467_snd_soc_card_evm,
-       .codec_dev = &soc_codec_dev_aic3x,
-       .codec_data = &aic3x_setup,
-};
-
-/* evm audio subsystem */
-static struct snd_soc_device da830_evm_snd_devdata = {
-       .card = &da830_snd_soc_card,
-       .codec_dev = &soc_codec_dev_aic3x,
-       .codec_data = &aic3x_setup,
-};
-
-static struct snd_soc_device da850_evm_snd_devdata = {
-       .card           = &da850_snd_soc_card,
-       .codec_dev      = &soc_codec_dev_aic3x,
-       .codec_data     = &aic3x_setup,
-};
-
 static struct platform_device *evm_snd_device;
 
 static int __init evm_init(void)
 {
-       struct snd_soc_device *evm_snd_dev_data;
+       struct snd_soc_card *evm_snd_dev_data;
        int index;
        int ret;
 
        if (machine_is_davinci_evm()) {
-               evm_snd_dev_data = &evm_snd_devdata;
+               evm_snd_dev_data = &snd_soc_card_evm;
                index = 0;
        } else if (machine_is_davinci_dm355_evm()) {
-               evm_snd_dev_data = &evm_snd_devdata;
+               evm_snd_dev_data = &snd_soc_card_evm;
                index = 1;
        } else if (machine_is_davinci_dm365_evm()) {
-               evm_snd_dev_data = &dm365_evm_snd_devdata;
+               evm_snd_dev_data = &dm365_snd_soc_card_evm;
                index = 0;
        } else if (machine_is_davinci_dm6467_evm()) {
-               evm_snd_dev_data = &dm6467_evm_snd_devdata;
+               evm_snd_dev_data = &dm6467_snd_soc_card_evm;
                index = 0;
        } else if (machine_is_davinci_da830_evm()) {
-               evm_snd_dev_data = &da830_evm_snd_devdata;
+               evm_snd_dev_data = &da830_snd_soc_card;
                index = 1;
        } else if (machine_is_davinci_da850_evm()) {
-               evm_snd_dev_data = &da850_evm_snd_devdata;
+               evm_snd_dev_data = &da850_snd_soc_card;
                index = 0;
        } else
                return -EINVAL;
@@ -322,7 +286,6 @@ static int __init evm_init(void)
                return -ENOMEM;
 
        platform_set_drvdata(evm_snd_device, evm_snd_dev_data);
-       evm_snd_dev_data->dev = &evm_snd_device->dev;
        ret = platform_device_add(evm_snd_device);
        if (ret)
                platform_device_put(evm_snd_device);
index 9e8932abf158b7f8d22660081fd73183a73a4469..d46b545d41f432f037c58eb6c3b4b0f1b13cc2a2 100644 (file)
@@ -183,8 +183,7 @@ static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev,
                struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_platform *platform = socdev->card->platform;
+       struct snd_soc_platform *platform = rtd->platform;
        int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
        u32 spcr;
        u32 mask = playback ? DAVINCI_MCBSP_SPCR_XRST : DAVINCI_MCBSP_SPCR_RRST;
@@ -205,8 +204,8 @@ static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev,
        if (playback) {
                /* Stop the DMA to avoid data loss */
                /* while the transmitter is out of reset to handle XSYNCERR */
-               if (platform->pcm_ops->trigger) {
-                       int ret = platform->pcm_ops->trigger(substream,
+               if (platform->driver->ops->trigger) {
+                       int ret = platform->driver->ops->trigger(substream,
                                SNDRV_PCM_TRIGGER_STOP);
                        if (ret < 0)
                                printk(KERN_DEBUG "Playback DMA stop failed\n");
@@ -227,8 +226,8 @@ static void davinci_mcbsp_start(struct davinci_mcbsp_dev *dev,
                toggle_clock(dev, playback);
 
                /* Restart the DMA */
-               if (platform->pcm_ops->trigger) {
-                       int ret = platform->pcm_ops->trigger(substream,
+               if (platform->driver->ops->trigger) {
+                       int ret = platform->driver->ops->trigger(substream,
                                SNDRV_PCM_TRIGGER_START);
                        if (ret < 0)
                                printk(KERN_DEBUG "Playback DMA start failed\n");
@@ -263,7 +262,7 @@ static void davinci_mcbsp_stop(struct davinci_mcbsp_dev *dev, int playback)
 static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                                   unsigned int fmt)
 {
-       struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
        unsigned int pcr;
        unsigned int srgr;
        /* Attention srgr is updated by hw_params! */
@@ -404,7 +403,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 static int davinci_i2s_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
                                int div_id, int div)
 {
-       struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
 
        if (div_id != DAVINCI_MCBSP_CLKGDV)
                return -ENODEV;
@@ -417,7 +416,7 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *dai)
 {
-       struct davinci_mcbsp_dev *dev = dai->private_data;
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
        struct davinci_pcm_dma_params *dma_params =
                                        &dev->dma_params[substream->stream];
        struct snd_interval *i = NULL;
@@ -427,6 +426,9 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
        snd_pcm_format_t fmt;
        unsigned element_cnt = 1;
 
+       dai->capture_dma_data = dev->dma_params;
+       dai->playback_dma_data = dev->dma_params;
+
        /* general line settings */
        spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
@@ -569,24 +571,18 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
 static int davinci_i2s_prepare(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
-       struct davinci_mcbsp_dev *dev = dai->private_data;
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
        int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
        davinci_mcbsp_stop(dev, playback);
-       if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0) {
-               /* codec is master */
-               davinci_mcbsp_start(dev, substream);
-       }
        return 0;
 }
 
 static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
                               struct snd_soc_dai *dai)
 {
-       struct davinci_mcbsp_dev *dev = dai->private_data;
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
        int ret = 0;
        int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
-       if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0)
-               return 0;       /* return if codec is master */
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -608,7 +604,7 @@ static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
-       struct davinci_mcbsp_dev *dev = dai->private_data;
+       struct davinci_mcbsp_dev *dev = snd_soc_dai_get_drvdata(dai);
        int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
        davinci_mcbsp_stop(dev, playback);
 }
@@ -625,9 +621,7 @@ static struct snd_soc_dai_ops davinci_i2s_dai_ops = {
 
 };
 
-struct snd_soc_dai davinci_i2s_dai = {
-       .name = "davinci-i2s",
-       .id = 0,
+static struct snd_soc_dai_driver davinci_i2s_dai = {
        .playback = {
                .channels_min = 2,
                .channels_max = 2,
@@ -641,7 +635,6 @@ struct snd_soc_dai davinci_i2s_dai = {
        .ops = &davinci_i2s_dai_ops,
 
 };
-EXPORT_SYMBOL_GPL(davinci_i2s_dai);
 
 static int davinci_i2s_probe(struct platform_device *pdev)
 {
@@ -720,10 +713,9 @@ static int davinci_i2s_probe(struct platform_device *pdev)
        dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start;
        dev->dev = &pdev->dev;
 
-       davinci_i2s_dai.private_data = dev;
-       davinci_i2s_dai.capture.dma_data = dev->dma_params;
-       davinci_i2s_dai.playback.dma_data = dev->dma_params;
-       ret = snd_soc_register_dai(&davinci_i2s_dai);
+       dev_set_drvdata(&pdev->dev, dev);
+
+       ret = snd_soc_register_dai(&pdev->dev, &davinci_i2s_dai);
        if (ret != 0)
                goto err_free_mem;
 
@@ -739,10 +731,10 @@ err_release_region:
 
 static int davinci_i2s_remove(struct platform_device *pdev)
 {
-       struct davinci_mcbsp_dev *dev = davinci_i2s_dai.private_data;
+       struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev);
        struct resource *mem;
 
-       snd_soc_unregister_dai(&davinci_i2s_dai);
+       snd_soc_unregister_dai(&pdev->dev);
        clk_disable(dev->clk);
        clk_put(dev->clk);
        dev->clk = NULL;
@@ -757,7 +749,7 @@ static struct platform_driver davinci_mcbsp_driver = {
        .probe          = davinci_i2s_probe,
        .remove         = davinci_i2s_remove,
        .driver         = {
-               .name   = "davinci-asp",
+               .name   = "davinci-i2s",
                .owner  = THIS_MODULE,
        },
 };
index 0b1e77b8c27992294ccf364c1038164485cc87ab..48dac3e2521a90a992aae255c4336eafc220ba9a 100644 (file)
@@ -17,6 +17,4 @@ enum davinci_mcbsp_div {
        DAVINCI_MCBSP_CLKGDV,              /* Sample rate generator divider */
 };
 
-extern struct snd_soc_dai davinci_i2s_dai;
-
 #endif
index b24720894af64a183a68aec1925a77419b5d0ad5..86918ee12419e7fd3ff626bdb2ccd18a1bd09021 100644 (file)
@@ -422,7 +422,7 @@ static void davinci_mcasp_stop(struct davinci_audio_dev *dev, int stream)
 static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                                         unsigned int fmt)
 {
-       struct davinci_audio_dev *dev = cpu_dai->private_data;
+       struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
        void __iomem *base = dev->base;
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -709,12 +709,15 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                                        struct snd_pcm_hw_params *params,
                                        struct snd_soc_dai *cpu_dai)
 {
-       struct davinci_audio_dev *dev = cpu_dai->private_data;
+       struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
        struct davinci_pcm_dma_params *dma_params =
                                        &dev->dma_params[substream->stream];
        int word_length;
        u8 fifo_level;
 
+       cpu_dai->capture_dma_data = dev->dma_params;
+       cpu_dai->playback_dma_data = dev->dma_params;
+
        davinci_hw_common_param(dev, substream->stream);
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                fifo_level = dev->txnumevt;
@@ -761,8 +764,7 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
 static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
                                     int cmd, struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct davinci_audio_dev *dev = rtd->dai->cpu_dai->private_data;
+       struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
        int ret = 0;
 
        switch (cmd) {
@@ -804,10 +806,9 @@ static struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
 
 };
 
-struct snd_soc_dai davinci_mcasp_dai[] = {
+static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
        {
-               .name           = "davinci-i2s",
-               .id             = 0,
+               .name           = "davinci-mcasp.0",
                .playback       = {
                        .channels_min   = 2,
                        .channels_max   = 2,
@@ -828,8 +829,7 @@ struct snd_soc_dai davinci_mcasp_dai[] = {
 
        },
        {
-               .name           = "davinci-dit",
-               .id             = 1,
+               "davinci-mcasp.1",
                .playback       = {
                        .channels_min   = 1,
                        .channels_max   = 384,
@@ -840,7 +840,6 @@ struct snd_soc_dai davinci_mcasp_dai[] = {
        },
 
 };
-EXPORT_SYMBOL_GPL(davinci_mcasp_dai);
 
 static int davinci_mcasp_probe(struct platform_device *pdev)
 {
@@ -899,6 +898,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
        if (!res) {
                dev_err(&pdev->dev, "no DMA resource\n");
+               ret = -ENODEV;
                goto err_release_region;
        }
 
@@ -913,15 +913,13 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
        if (!res) {
                dev_err(&pdev->dev, "no DMA resource\n");
+               ret = -ENODEV;
                goto err_release_region;
        }
 
        dma_data->channel = res->start;
-       davinci_mcasp_dai[pdata->op_mode].private_data = dev;
-       davinci_mcasp_dai[pdata->op_mode].capture.dma_data = dev->dma_params;
-       davinci_mcasp_dai[pdata->op_mode].playback.dma_data = dev->dma_params;
-       davinci_mcasp_dai[pdata->op_mode].dev = &pdev->dev;
-       ret = snd_soc_register_dai(&davinci_mcasp_dai[pdata->op_mode]);
+       dev_set_drvdata(&pdev->dev, dev);
+       ret = snd_soc_register_dai(&pdev->dev, &davinci_mcasp_dai[pdata->op_mode]);
 
        if (ret != 0)
                goto err_release_region;
@@ -937,12 +935,10 @@ err_release_data:
 
 static int davinci_mcasp_remove(struct platform_device *pdev)
 {
-       struct snd_platform_data *pdata = pdev->dev.platform_data;
-       struct davinci_audio_dev *dev;
+       struct davinci_audio_dev *dev = dev_get_drvdata(&pdev->dev);
        struct resource *mem;
 
-       snd_soc_unregister_dai(&davinci_mcasp_dai[pdata->op_mode]);
-       dev = davinci_mcasp_dai[pdata->op_mode].private_data;
+       snd_soc_unregister_dai(&pdev->dev);
        clk_disable(dev->clk);
        clk_put(dev->clk);
        dev->clk = NULL;
index e755b5121ec728be29aed547b662c02994b2dc50..4681acc636061300efe053f56e214fc0eff1b98b 100644 (file)
@@ -22,8 +22,6 @@
 #include <mach/asp.h>
 #include "davinci-pcm.h"
 
-extern struct snd_soc_dai davinci_mcasp_dai[];
-
 #define DAVINCI_MCASP_RATES    SNDRV_PCM_RATE_8000_96000
 #define DAVINCI_MCASP_I2S_DAI  0
 #define DAVINCI_MCASP_DIT_DAI  1
index a7124116d2e01aea6832f158db798a8e16c93bfd..9d35b8c1a624338afcfa27a4282482515d2cb32a 100644 (file)
@@ -653,7 +653,7 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream)
        struct davinci_pcm_dma_params *pa;
        struct davinci_pcm_dma_params *params;
 
-       pa = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+       pa = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
        if (!pa)
                return -ENODEV;
        params = &pa[substream->stream];
@@ -821,7 +821,7 @@ static int davinci_pcm_new(struct snd_card *card,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = 0xffffffff;
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = davinci_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK,
                        pcm_hardware_playback.buffer_bytes_max);
@@ -829,7 +829,7 @@ static int davinci_pcm_new(struct snd_card *card,
                        return ret;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = davinci_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE,
                        pcm_hardware_capture.buffer_bytes_max);
@@ -840,25 +840,44 @@ static int davinci_pcm_new(struct snd_card *card,
        return 0;
 }
 
-struct snd_soc_platform davinci_soc_platform = {
-       .name =         "davinci-audio",
-       .pcm_ops =      &davinci_pcm_ops,
+static struct snd_soc_platform_driver davinci_soc_platform = {
+       .ops =          &davinci_pcm_ops,
        .pcm_new =      davinci_pcm_new,
        .pcm_free =     davinci_pcm_free,
 };
-EXPORT_SYMBOL_GPL(davinci_soc_platform);
 
-static int __init davinci_soc_platform_init(void)
+static int __devinit davinci_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&davinci_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &davinci_soc_platform);
 }
-module_init(davinci_soc_platform_init);
 
-static void __exit davinci_soc_platform_exit(void)
+static int __devexit davinci_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&davinci_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver davinci_pcm_driver = {
+       .driver = {
+                       .name = "davinci-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = davinci_soc_platform_probe,
+       .remove = __devexit_p(davinci_soc_platform_remove),
+};
+
+static int __init snd_davinci_pcm_init(void)
+{
+       return platform_driver_register(&davinci_pcm_driver);
+}
+module_init(snd_davinci_pcm_init);
+
+static void __exit snd_davinci_pcm_exit(void)
+{
+       platform_driver_unregister(&davinci_pcm_driver);
 }
-module_exit(davinci_soc_platform_exit);
+module_exit(snd_davinci_pcm_exit);
 
 MODULE_AUTHOR("Vladimir Barinov");
 MODULE_DESCRIPTION("TI DAVINCI PCM DMA module");
index b799a02333d83b10a896d639ce1c73679ab06bec..c0d6c9be4b4d605b12bdf6145a8fde5319cd2bf6 100644 (file)
@@ -28,7 +28,4 @@ struct davinci_pcm_dma_params {
        unsigned int fifo_level;
 };
 
-
-extern struct snd_soc_platform davinci_soc_platform;
-
 #endif
index 40eccfe9e358c2f2bc05574d3cdeb87f6fa7bffc..009b6521a1bf9f3731e9d597f09ff3644126b967 100644 (file)
@@ -29,7 +29,6 @@
 #include <asm/plat-sffsdr/sffsdr-fpga.h>
 #endif
 
-#include <mach/mcbsp.h>
 #include <mach/edma.h>
 
 #include "../codecs/pcm3008.h"
@@ -48,7 +47,7 @@ static int sffsdr_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int fs;
        int ret = 0;
 
@@ -85,15 +84,16 @@ static struct snd_soc_ops sffsdr_ops = {
 static struct snd_soc_dai_link sffsdr_dai = {
        .name = "PCM3008", /* Codec name */
        .stream_name = "PCM3008 HiFi",
-       .cpu_dai = &davinci_i2s_dai,
-       .codec_dai = &pcm3008_dai,
+       .cpu_dai_name = "davinci-asp.0",
+       .codec_dai_name = "pcm3008-hifi",
+       .codec_name = "pcm3008-codec",
+       .platform_name = "davinci-pcm-audio",
        .ops = &sffsdr_ops,
 };
 
 /* davinci-sffsdr audio machine driver */
 static struct snd_soc_card snd_soc_sffsdr = {
        .name = "DaVinci SFFSDR",
-       .platform = &davinci_soc_platform,
        .dai_link = &sffsdr_dai,
        .num_links = 1,
 };
@@ -106,11 +106,12 @@ static struct pcm3008_setup_data sffsdr_pcm3008_setup = {
        .pdda_pin = GPIO(38),
 };
 
-/* sffsdr audio subsystem */
-static struct snd_soc_device sffsdr_snd_devdata = {
-       .card = &snd_soc_sffsdr,
-       .codec_dev = &soc_codec_dev_pcm3008,
-       .codec_data = &sffsdr_pcm3008_setup,
+struct platform_device pcm3008_codec = {
+               .name = "pcm3008-codec",
+               .id = 0,
+               .dev = {
+                               .platform_data = &sffsdr_pcm3008_setup,
+               },
 };
 
 static struct resource sffsdr_snd_resources[] = {
@@ -135,14 +136,15 @@ static int __init sffsdr_init(void)
        if (!machine_is_sffsdr())
                return -EINVAL;
 
+       platform_device_register(&pcm3008_codec);
+
        sffsdr_snd_device = platform_device_alloc("soc-audio", 0);
        if (!sffsdr_snd_device) {
                printk(KERN_ERR "platform device allocation failed\n");
                return -ENOMEM;
        }
 
-       platform_set_drvdata(sffsdr_snd_device, &sffsdr_snd_devdata);
-       sffsdr_snd_devdata.dev = &sffsdr_snd_device->dev;
+       platform_set_drvdata(sffsdr_snd_device, &snd_soc_sffsdr);
        platform_device_add_data(sffsdr_snd_device, &sffsdr_snd_data,
                                 sizeof(sffsdr_snd_data));
 
@@ -150,7 +152,7 @@ static int __init sffsdr_init(void)
                                            sffsdr_snd_resources,
                                            ARRAY_SIZE(sffsdr_snd_resources));
        if (ret) {
-               printk(KERN_ERR "platform device add ressources failed\n");
+               printk(KERN_ERR "platform device add resources failed\n");
                goto error;
        }
 
@@ -168,6 +170,7 @@ error:
 static void __exit sffsdr_exit(void)
 {
        platform_device_unregister(sffsdr_snd_device);
+       platform_device_unregister(&pcm3008_codec);
 }
 
 module_init(sffsdr_init);
index 48678533da7af1641f56c6b3e2dcfca67d8dbedc..ea232f6a2c21912e408a69ea2d1f8df28e4552dd 100644 (file)
@@ -36,7 +36,6 @@
 
 #include "davinci-pcm.h"
 #include "davinci-i2s.h"
-#include "davinci-vcif.h"
 
 #define MOD_REG_BIT(val, mask, set) do { \
        if (set) { \
@@ -55,7 +54,7 @@ static void davinci_vcif_start(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct davinci_vcif_dev *davinci_vcif_dev =
-                                       rtd->dai->cpu_dai->private_data;
+                       snd_soc_dai_get_drvdata(rtd->cpu_dai);
        struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
        u32 w;
 
@@ -74,7 +73,7 @@ static void davinci_vcif_stop(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct davinci_vcif_dev *davinci_vcif_dev =
-                                       rtd->dai->cpu_dai->private_data;
+                       snd_soc_dai_get_drvdata(rtd->cpu_dai);
        struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
        u32 w;
 
@@ -92,12 +91,15 @@ static int davinci_vcif_hw_params(struct snd_pcm_substream *substream,
                                  struct snd_pcm_hw_params *params,
                                  struct snd_soc_dai *dai)
 {
-       struct davinci_vcif_dev *davinci_vcif_dev = dai->private_data;
+       struct davinci_vcif_dev *davinci_vcif_dev = snd_soc_dai_get_drvdata(dai);
        struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
        struct davinci_pcm_dma_params *dma_params =
                        &davinci_vcif_dev->dma_params[substream->stream];
        u32 w;
 
+       dai->capture_dma_data = davinci_vcif_dev->dma_params;
+       dai->playback_dma_data = davinci_vcif_dev->dma_params;
+
        /* Restart the codec before setup */
        davinci_vcif_stop(substream);
        davinci_vcif_start(substream);
@@ -179,8 +181,7 @@ static struct snd_soc_dai_ops davinci_vcif_dai_ops = {
        .hw_params      = davinci_vcif_hw_params,
 };
 
-struct snd_soc_dai davinci_vcif_dai = {
-       .name = "davinci-vcif",
+static struct snd_soc_dai_driver davinci_vcif_dai = {
        .playback = {
                .channels_min = 1,
                .channels_max = 2,
@@ -194,7 +195,6 @@ struct snd_soc_dai davinci_vcif_dai = {
        .ops = &davinci_vcif_dai_ops,
 
 };
-EXPORT_SYMBOL_GPL(davinci_vcif_dai);
 
 static int davinci_vcif_probe(struct platform_device *pdev)
 {
@@ -222,12 +222,9 @@ static int davinci_vcif_probe(struct platform_device *pdev)
        davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr =
                                        davinci_vc->davinci_vcif.dma_rx_addr;
 
-       davinci_vcif_dai.dev = &pdev->dev;
-       davinci_vcif_dai.capture.dma_data = davinci_vcif_dev->dma_params;
-       davinci_vcif_dai.playback.dma_data = davinci_vcif_dev->dma_params;
-       davinci_vcif_dai.private_data = davinci_vcif_dev;
+       dev_set_drvdata(&pdev->dev, davinci_vcif_dev);
 
-       ret = snd_soc_register_dai(&davinci_vcif_dai);
+       ret = snd_soc_register_dai(&pdev->dev, &davinci_vcif_dai);
        if (ret != 0) {
                dev_err(&pdev->dev, "could not register dai\n");
                goto fail;
@@ -243,7 +240,7 @@ fail:
 
 static int davinci_vcif_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&davinci_vcif_dai);
+       snd_soc_unregister_dai(&pdev->dev);
 
        return 0;
 }
@@ -252,7 +249,7 @@ static struct platform_driver davinci_vcif_driver = {
        .probe          = davinci_vcif_probe,
        .remove         = davinci_vcif_remove,
        .driver         = {
-               .name   = "davinci_vcif",
+               .name   = "davinci-vcif",
                .owner  = THIS_MODULE,
        },
 };
diff --git a/sound/soc/davinci/davinci-vcif.h b/sound/soc/davinci/davinci-vcif.h
deleted file mode 100644 (file)
index 571c994..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * ALSA SoC Voice Codec Interface for TI DAVINCI processor
- *
- * Copyright (C) 2010 Texas Instruments.
- *
- * Author: Miguel Aguilar <miguel.aguilar@ridgerun.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _DAVINCI_VCIF_H
-#define _DAVINCI_VCIF_H
-
-extern struct snd_soc_dai davinci_vcif_dai;
-
-#endif
index f617f560f46b9e56d287ce8232ff70218a1e7ebd..57429041189c134abda26547ab723cef54590e6e 100644 (file)
@@ -3,11 +3,16 @@ config SND_EP93XX_SOC
        depends on ARCH_EP93XX && SND_SOC
        help
          Say Y or M if you want to add support for codecs attached to
-         the EP93xx I2S interface.
+         the EP93xx I2S or AC97 interfaces.
 
 config SND_EP93XX_SOC_I2S
        tristate
 
+config SND_EP93XX_SOC_AC97
+       tristate
+       select AC97_BUS
+       select SND_SOC_AC97_BUS
+
 config SND_EP93XX_SOC_SNAPPERCL15
         tristate "SoC Audio support for Bluewater Systems Snapper CL15 module"
         depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15
@@ -16,3 +21,12 @@ config SND_EP93XX_SOC_SNAPPERCL15
         help
           Say Y or M here if you want to add support for I2S audio on the
           Bluewater Systems Snapper CL15 module.
+
+config SND_EP93XX_SOC_SIMONE
+       tristate "SoC Audio support for Simplemachines Sim.One board"
+       depends on SND_EP93XX_SOC && MACH_SIM_ONE
+       select SND_EP93XX_SOC_AC97
+       select SND_SOC_AC97_CODEC
+       help
+         Say Y or M here if you want to add support for AC97 audio on the
+         Simplemachines Sim.One board.
index 272e60f57b9a5c33b8d9e1a493c32a339b49ec08..8e7977fb6b7d6c407bd94794ce7cbe04d2c96560 100644 (file)
@@ -1,11 +1,15 @@
 # EP93xx Platform Support
 snd-soc-ep93xx-objs                            := ep93xx-pcm.o
 snd-soc-ep93xx-i2s-objs                                := ep93xx-i2s.o
+snd-soc-ep93xx-ac97-objs                       := ep93xx-ac97.o
 
 obj-$(CONFIG_SND_EP93XX_SOC)                   += snd-soc-ep93xx.o
 obj-$(CONFIG_SND_EP93XX_SOC_I2S)               += snd-soc-ep93xx-i2s.o
+obj-$(CONFIG_SND_EP93XX_SOC_AC97)              += snd-soc-ep93xx-ac97.o
 
 # EP93XX Machine Support
 snd-soc-snappercl15-objs                       := snappercl15.o
+snd-soc-simone-objs                            := simone.o
 
 obj-$(CONFIG_SND_EP93XX_SOC_SNAPPERCL15)       += snd-soc-snappercl15.o
+obj-$(CONFIG_SND_EP93XX_SOC_SIMONE)            += snd-soc-simone.o
diff --git a/sound/soc/ep93xx/ep93xx-ac97.c b/sound/soc/ep93xx/ep93xx-ac97.c
new file mode 100644 (file)
index 0000000..68a0bae
--- /dev/null
@@ -0,0 +1,468 @@
+/*
+ * ASoC driver for Cirrus Logic EP93xx AC97 controller.
+ *
+ * Copyright (c) 2010 Mika Westerberg
+ *
+ * Based on s3c-ac97 ASoC driver by Jaswinder Singh.
+ *
+ * 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/io.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/ac97_codec.h>
+#include <sound/soc.h>
+
+#include <mach/dma.h>
+#include "ep93xx-pcm.h"
+
+/*
+ * Per channel (1-4) registers.
+ */
+#define AC97CH(n)              (((n) - 1) * 0x20)
+
+#define AC97DR(n)              (AC97CH(n) + 0x0000)
+
+#define AC97RXCR(n)            (AC97CH(n) + 0x0004)
+#define AC97RXCR_REN           BIT(0)
+#define AC97RXCR_RX3           BIT(3)
+#define AC97RXCR_RX4           BIT(4)
+#define AC97RXCR_CM            BIT(15)
+
+#define AC97TXCR(n)            (AC97CH(n) + 0x0008)
+#define AC97TXCR_TEN           BIT(0)
+#define AC97TXCR_TX3           BIT(3)
+#define AC97TXCR_TX4           BIT(4)
+#define AC97TXCR_CM            BIT(15)
+
+#define AC97SR(n)              (AC97CH(n) + 0x000c)
+#define AC97SR_TXFE            BIT(1)
+#define AC97SR_TXUE            BIT(6)
+
+#define AC97RISR(n)            (AC97CH(n) + 0x0010)
+#define AC97ISR(n)             (AC97CH(n) + 0x0014)
+#define AC97IE(n)              (AC97CH(n) + 0x0018)
+
+/*
+ * Global AC97 controller registers.
+ */
+#define AC97S1DATA             0x0080
+#define AC97S2DATA             0x0084
+#define AC97S12DATA            0x0088
+
+#define AC97RGIS               0x008c
+#define AC97GIS                        0x0090
+#define AC97IM                 0x0094
+/*
+ * Common bits for RGIS, GIS and IM registers.
+ */
+#define AC97_SLOT2RXVALID      BIT(1)
+#define AC97_CODECREADY                BIT(5)
+#define AC97_SLOT2TXCOMPLETE   BIT(6)
+
+#define AC97EOI                        0x0098
+#define AC97EOI_WINT           BIT(0)
+#define AC97EOI_CODECREADY     BIT(1)
+
+#define AC97GCR                        0x009c
+#define AC97GCR_AC97IFE                BIT(0)
+
+#define AC97RESET              0x00a0
+#define AC97RESET_TIMEDRESET   BIT(0)
+
+#define AC97SYNC               0x00a4
+#define AC97SYNC_TIMEDSYNC     BIT(0)
+
+#define AC97_TIMEOUT           msecs_to_jiffies(5)
+
+/**
+ * struct ep93xx_ac97_info - EP93xx AC97 controller info structure
+ * @lock: mutex serializing access to the bus (slot 1 & 2 ops)
+ * @dev: pointer to the platform device dev structure
+ * @mem: physical memory resource for the registers
+ * @regs: mapped AC97 controller registers
+ * @irq: AC97 interrupt number
+ * @done: bus ops wait here for an interrupt
+ */
+struct ep93xx_ac97_info {
+       struct mutex            lock;
+       struct device           *dev;
+       struct resource         *mem;
+       void __iomem            *regs;
+       int                     irq;
+       struct completion       done;
+};
+
+/* currently ALSA only supports a single AC97 device */
+static struct ep93xx_ac97_info *ep93xx_ac97_info;
+
+static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_out = {
+       .name           = "ac97-pcm-out",
+       .dma_port       = EP93XX_DMA_M2P_PORT_AAC1,
+};
+
+static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_in = {
+       .name           = "ac97-pcm-in",
+       .dma_port       = EP93XX_DMA_M2P_PORT_AAC1,
+};
+
+static inline unsigned ep93xx_ac97_read_reg(struct ep93xx_ac97_info *info,
+                                           unsigned reg)
+{
+       return __raw_readl(info->regs + reg);
+}
+
+static inline void ep93xx_ac97_write_reg(struct ep93xx_ac97_info *info,
+                                        unsigned reg, unsigned val)
+{
+       __raw_writel(val, info->regs + reg);
+}
+
+static unsigned short ep93xx_ac97_read(struct snd_ac97 *ac97,
+                                      unsigned short reg)
+{
+       struct ep93xx_ac97_info *info = ep93xx_ac97_info;
+       unsigned short val;
+
+       mutex_lock(&info->lock);
+
+       ep93xx_ac97_write_reg(info, AC97S1DATA, reg);
+       ep93xx_ac97_write_reg(info, AC97IM, AC97_SLOT2RXVALID);
+       if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT)) {
+               dev_warn(info->dev, "timeout reading register %x\n", reg);
+               mutex_unlock(&info->lock);
+               return -ETIMEDOUT;
+       }
+       val = (unsigned short)ep93xx_ac97_read_reg(info, AC97S2DATA);
+
+       mutex_unlock(&info->lock);
+       return val;
+}
+
+static void ep93xx_ac97_write(struct snd_ac97 *ac97,
+                             unsigned short reg,
+                             unsigned short val)
+{
+       struct ep93xx_ac97_info *info = ep93xx_ac97_info;
+
+       mutex_lock(&info->lock);
+
+       /*
+        * Writes to the codec need to be done so that slot 2 is filled in
+        * before slot 1.
+        */
+       ep93xx_ac97_write_reg(info, AC97S2DATA, val);
+       ep93xx_ac97_write_reg(info, AC97S1DATA, reg);
+
+       ep93xx_ac97_write_reg(info, AC97IM, AC97_SLOT2TXCOMPLETE);
+       if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT))
+               dev_warn(info->dev, "timeout writing register %x\n", reg);
+
+       mutex_unlock(&info->lock);
+}
+
+static void ep93xx_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+       struct ep93xx_ac97_info *info = ep93xx_ac97_info;
+
+       mutex_lock(&info->lock);
+
+       /*
+        * We are assuming that before this functions gets called, the codec
+        * BIT_CLK is stopped by forcing the codec into powerdown mode. We can
+        * control the SYNC signal directly via AC97SYNC register. Using
+        * TIMEDSYNC the controller will keep the SYNC high > 1us.
+        */
+       ep93xx_ac97_write_reg(info, AC97SYNC, AC97SYNC_TIMEDSYNC);
+       ep93xx_ac97_write_reg(info, AC97IM, AC97_CODECREADY);
+       if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT))
+               dev_warn(info->dev, "codec warm reset timeout\n");
+
+       mutex_unlock(&info->lock);
+}
+
+static void ep93xx_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+       struct ep93xx_ac97_info *info = ep93xx_ac97_info;
+
+       mutex_lock(&info->lock);
+
+       /*
+        * For doing cold reset, we disable the AC97 controller interface, clear
+        * WINT and CODECREADY bits, and finally enable the interface again.
+        */
+       ep93xx_ac97_write_reg(info, AC97GCR, 0);
+       ep93xx_ac97_write_reg(info, AC97EOI, AC97EOI_CODECREADY | AC97EOI_WINT);
+       ep93xx_ac97_write_reg(info, AC97GCR, AC97GCR_AC97IFE);
+
+       /*
+        * Now, assert the reset and wait for the codec to become ready.
+        */
+       ep93xx_ac97_write_reg(info, AC97RESET, AC97RESET_TIMEDRESET);
+       ep93xx_ac97_write_reg(info, AC97IM, AC97_CODECREADY);
+       if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT))
+               dev_warn(info->dev, "codec cold reset timeout\n");
+
+       /*
+        * Give the codec some time to come fully out from the reset. This way
+        * we ensure that the subsequent reads/writes will work.
+        */
+       usleep_range(15000, 20000);
+
+       mutex_unlock(&info->lock);
+}
+
+static irqreturn_t ep93xx_ac97_interrupt(int irq, void *dev_id)
+{
+       struct ep93xx_ac97_info *info = dev_id;
+       unsigned status, mask;
+
+       /*
+        * Just mask out the interrupt and wake up the waiting thread.
+        * Interrupts are cleared via reading/writing to slot 1 & 2 registers by
+        * the waiting thread.
+        */
+       status = ep93xx_ac97_read_reg(info, AC97GIS);
+       mask = ep93xx_ac97_read_reg(info, AC97IM);
+       mask &= ~status;
+       ep93xx_ac97_write_reg(info, AC97IM, mask);
+
+       complete(&info->done);
+       return IRQ_HANDLED;
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+       .read           = ep93xx_ac97_read,
+       .write          = ep93xx_ac97_write,
+       .reset          = ep93xx_ac97_cold_reset,
+       .warm_reset     = ep93xx_ac97_warm_reset,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
+                              int cmd, struct snd_soc_dai *dai)
+{
+       struct ep93xx_ac97_info *info = snd_soc_dai_get_drvdata(dai);
+       unsigned v = 0;
+
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       /*
+                        * Enable compact mode, TX slots 3 & 4, and the TX FIFO
+                        * itself.
+                        */
+                       v |= AC97TXCR_CM;
+                       v |= AC97TXCR_TX3 | AC97TXCR_TX4;
+                       v |= AC97TXCR_TEN;
+                       ep93xx_ac97_write_reg(info, AC97TXCR(1), v);
+               } else {
+                       /*
+                        * Enable compact mode, RX slots 3 & 4, and the RX FIFO
+                        * itself.
+                        */
+                       v |= AC97RXCR_CM;
+                       v |= AC97RXCR_RX3 | AC97RXCR_RX4;
+                       v |= AC97RXCR_REN;
+                       ep93xx_ac97_write_reg(info, AC97RXCR(1), v);
+               }
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       /*
+                        * As per Cirrus EP93xx errata described below:
+                        *
+                        * http://www.cirrus.com/en/pubs/errata/ER667E2B.pdf
+                        *
+                        * we will wait for the TX FIFO to be empty before
+                        * clearing the TEN bit.
+                        */
+                       unsigned long timeout = jiffies + AC97_TIMEOUT;
+
+                       do {
+                               v = ep93xx_ac97_read_reg(info, AC97SR(1));
+                               if (time_after(jiffies, timeout)) {
+                                       dev_warn(info->dev, "TX timeout\n");
+                                       break;
+                               }
+                       } while (!(v & (AC97SR_TXFE | AC97SR_TXUE)));
+
+                       /* disable the TX FIFO */
+                       ep93xx_ac97_write_reg(info, AC97TXCR(1), 0);
+               } else {
+                       /* disable the RX FIFO */
+                       ep93xx_ac97_write_reg(info, AC97RXCR(1), 0);
+               }
+               break;
+
+       default:
+               dev_warn(info->dev, "unknown command %d\n", cmd);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ep93xx_ac97_startup(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct ep93xx_pcm_dma_params *dma_data;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dma_data = &ep93xx_ac97_pcm_out;
+       else
+               dma_data = &ep93xx_ac97_pcm_in;
+
+       snd_soc_dai_set_dma_data(dai, substream, dma_data);
+       return 0;
+}
+
+static struct snd_soc_dai_ops ep93xx_ac97_dai_ops = {
+       .startup        = ep93xx_ac97_startup,
+       .trigger        = ep93xx_ac97_trigger,
+};
+
+struct snd_soc_dai_driver ep93xx_ac97_dai = {
+       .name           = "ep93xx-ac97",
+       .id             = 0,
+       .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                    = &ep93xx_ac97_dai_ops,
+};
+
+static int __devinit ep93xx_ac97_probe(struct platform_device *pdev)
+{
+       struct ep93xx_ac97_info *info;
+       int ret;
+
+       info = kzalloc(sizeof(struct ep93xx_ac97_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       dev_set_drvdata(&pdev->dev, info);
+
+       mutex_init(&info->lock);
+       init_completion(&info->done);
+       info->dev = &pdev->dev;
+
+       info->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!info->mem) {
+               ret = -ENXIO;
+               goto fail_free_info;
+       }
+
+       info->irq = platform_get_irq(pdev, 0);
+       if (!info->irq) {
+               ret = -ENXIO;
+               goto fail_free_info;
+       }
+
+       if (!request_mem_region(info->mem->start, resource_size(info->mem),
+                               pdev->name)) {
+               ret = -EBUSY;
+               goto fail_free_info;
+       }
+
+       info->regs = ioremap(info->mem->start, resource_size(info->mem));
+       if (!info->regs) {
+               ret = -ENOMEM;
+               goto fail_release_mem;
+       }
+
+       ret = request_irq(info->irq, ep93xx_ac97_interrupt, IRQF_TRIGGER_HIGH,
+                         pdev->name, info);
+       if (ret)
+               goto fail_unmap_mem;
+
+       ep93xx_ac97_info = info;
+       platform_set_drvdata(pdev, info);
+
+       ret = snd_soc_register_dai(&pdev->dev, &ep93xx_ac97_dai);
+       if (ret)
+               goto fail_free_irq;
+
+       return 0;
+
+fail_free_irq:
+       platform_set_drvdata(pdev, NULL);
+       free_irq(info->irq, info);
+fail_unmap_mem:
+       iounmap(info->regs);
+fail_release_mem:
+       release_mem_region(info->mem->start, resource_size(info->mem));
+fail_free_info:
+       kfree(info);
+
+       return ret;
+}
+
+static int __devexit ep93xx_ac97_remove(struct platform_device *pdev)
+{
+       struct ep93xx_ac97_info *info = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_dai(&pdev->dev);
+
+       /* disable the AC97 controller */
+       ep93xx_ac97_write_reg(info, AC97GCR, 0);
+
+       free_irq(info->irq, info);
+       iounmap(info->regs);
+       release_mem_region(info->mem->start, resource_size(info->mem));
+       platform_set_drvdata(pdev, NULL);
+       kfree(info);
+
+       return 0;
+}
+
+static struct platform_driver ep93xx_ac97_driver = {
+       .probe  = ep93xx_ac97_probe,
+       .remove = __devexit_p(ep93xx_ac97_remove),
+       .driver = {
+               .name = "ep93xx-ac97",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init ep93xx_ac97_init(void)
+{
+       return platform_driver_register(&ep93xx_ac97_driver);
+}
+module_init(ep93xx_ac97_init);
+
+static void __exit ep93xx_ac97_exit(void)
+{
+       platform_driver_unregister(&ep93xx_ac97_driver);
+}
+module_exit(ep93xx_ac97_exit);
+
+MODULE_DESCRIPTION("EP93xx AC97 ASoC Driver");
+MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ep93xx-ac97");
index 00b946632184a359cd5157ab8fceca38d1e40f43..4f48733596134c2e0fe68825b494ce798cbb6767 100644 (file)
@@ -31,7 +31,6 @@
 #include <mach/dma.h>
 
 #include "ep93xx-pcm.h"
-#include "ep93xx-i2s.h"
 
 #define EP93XX_I2S_TXCLKCFG            0x00
 #define EP93XX_I2S_RXCLKCFG            0x04
@@ -145,8 +144,8 @@ static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
                              struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data;
+       struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
        snd_soc_dai_set_dma_data(cpu_dai, substream,
                                 &info->dma_params[substream->stream]);
@@ -156,8 +155,7 @@ static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
 static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
                                struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data;
+       struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
 
        ep93xx_i2s_disable(info, substream->stream);
 }
@@ -165,7 +163,7 @@ static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
 static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                                  unsigned int fmt)
 {
-       struct ep93xx_i2s_info *info = cpu_dai->private_data;
+       struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(cpu_dai);
        unsigned int clk_cfg, lin_ctrl;
 
        clk_cfg  = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXCLKCFG);
@@ -242,9 +240,7 @@ static int ep93xx_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 snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct ep93xx_i2s_info *info = cpu_dai->private_data;
+       struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
        unsigned word_len, div, sdiv, lrdiv;
        int found = 0, err;
 
@@ -302,7 +298,7 @@ out:
 static int ep93xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
                                 unsigned int freq, int dir)
 {
-       struct ep93xx_i2s_info *info = cpu_dai->private_data;
+       struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(cpu_dai);
 
        if (dir == SND_SOC_CLOCK_IN || clk_id != 0)
                return -EINVAL;
@@ -313,7 +309,7 @@ static int ep93xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
 #ifdef CONFIG_PM
 static int ep93xx_i2s_suspend(struct snd_soc_dai *dai)
 {
-       struct ep93xx_i2s_info *info = dai->private_data;
+       struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
 
        if (!dai->active)
                return;
@@ -324,7 +320,7 @@ static int ep93xx_i2s_suspend(struct snd_soc_dai *dai)
 
 static int ep93xx_i2s_resume(struct snd_soc_dai *dai)
 {
-       struct ep93xx_i2s_info *info = dai->private_data;
+       struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
 
        if (!dai->active)
                return;
@@ -349,9 +345,7 @@ static struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
                            SNDRV_PCM_FMTBIT_S24_LE | \
                            SNDRV_PCM_FMTBIT_S32_LE)
 
-struct snd_soc_dai ep93xx_i2s_dai = {
-       .name           = "ep93xx-i2s",
-       .id             = 0,
+static struct snd_soc_dai_driver ep93xx_i2s_dai = {
        .symmetric_rates= 1,
        .suspend        = ep93xx_i2s_suspend,
        .resume         = ep93xx_i2s_resume,
@@ -369,7 +363,6 @@ struct snd_soc_dai ep93xx_i2s_dai = {
        },
        .ops            = &ep93xx_i2s_dai_ops,
 };
-EXPORT_SYMBOL_GPL(ep93xx_i2s_dai);
 
 static int ep93xx_i2s_probe(struct platform_device *pdev)
 {
@@ -383,8 +376,7 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
                goto fail;
        }
 
-       ep93xx_i2s_dai.dev = &pdev->dev;
-       ep93xx_i2s_dai.private_data = info;
+       dev_set_drvdata(&pdev->dev, info);
        info->dma_params = ep93xx_i2s_dma_params;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -424,7 +416,7 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
                goto fail_put_sclk;
        }
 
-       err = snd_soc_register_dai(&ep93xx_i2s_dai);
+       err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai);
        if (err)
                goto fail_put_lrclk;
 
@@ -447,9 +439,9 @@ fail:
 
 static int __devexit ep93xx_i2s_remove(struct platform_device *pdev)
 {
-       struct ep93xx_i2s_info *info = ep93xx_i2s_dai.private_data;
+       struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dai(&ep93xx_i2s_dai);
+       snd_soc_unregister_dai(&pdev->dev);
        clk_put(info->lrclk);
        clk_put(info->sclk);
        clk_put(info->mclk);
diff --git a/sound/soc/ep93xx/ep93xx-i2s.h b/sound/soc/ep93xx/ep93xx-i2s.h
deleted file mode 100644 (file)
index 3bd4ebf..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * linux/sound/soc/ep93xx-i2s.h
- * EP93xx I2S driver
- *
- * Copyright (C) 2010 Ryan Mallon <ryan@bluewatersys.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 _EP93XX_SND_SOC_I2S_H
-#define _EP93XX_SND_SOC_I2S_H
-
-extern struct snd_soc_dai ep93xx_i2s_dai;
-
-#endif /* _EP93XX_SND_SOC_I2S_H */
index 4ba9384007916c454081a821cd1fcacab27d76f9..2f121ddbe4bb50d04ced8fb32db30bf54437b864 100644 (file)
@@ -95,7 +95,7 @@ static void ep93xx_pcm_buffer_finished(void *cookie,
 static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *soc_rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = soc_rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = soc_rtd->cpu_dai;
        struct ep93xx_pcm_dma_params *dma_params;
        struct ep93xx_runtime_data *rtd;    
        int ret;
@@ -276,14 +276,14 @@ static int ep93xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = 0xffffffff;
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
                                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        return ret;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
                                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -293,22 +293,41 @@ static int ep93xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
        return 0;
 }
 
-struct snd_soc_platform ep93xx_soc_platform = {
-       .name           = "ep93xx-audio",
-       .pcm_ops        = &ep93xx_pcm_ops,
+static struct snd_soc_platform_driver ep93xx_soc_platform = {
+       .ops            = &ep93xx_pcm_ops,
        .pcm_new        = &ep93xx_pcm_new,
        .pcm_free       = &ep93xx_pcm_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(ep93xx_soc_platform);
+
+static int __devinit ep93xx_soc_platform_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_platform(&pdev->dev, &ep93xx_soc_platform);
+}
+
+static int __devexit ep93xx_soc_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver ep93xx_pcm_driver = {
+       .driver = {
+                       .name = "ep93xx-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = ep93xx_soc_platform_probe,
+       .remove = __devexit_p(ep93xx_soc_platform_remove),
+};
 
 static int __init ep93xx_soc_platform_init(void)
 {
-       return snd_soc_register_platform(&ep93xx_soc_platform);
+       return platform_driver_register(&ep93xx_pcm_driver);
 }
 
 static void __exit ep93xx_soc_platform_exit(void)
 {
-       snd_soc_unregister_platform(&ep93xx_soc_platform);
+       platform_driver_unregister(&ep93xx_pcm_driver);
 }
 
 module_init(ep93xx_soc_platform_init);
index 4ffdd3f62fe9fbc02a40a8078209e0befca3be0a..111e1121ecb83119576c6b9ad3cdf552a426be1e 100644 (file)
@@ -17,6 +17,4 @@ struct ep93xx_pcm_dma_params {
        int     dma_port;
 };
 
-extern struct snd_soc_platform ep93xx_soc_platform;
-
 #endif /* _EP93XX_SND_SOC_PCM_H */
diff --git a/sound/soc/ep93xx/simone.c b/sound/soc/ep93xx/simone.c
new file mode 100644 (file)
index 0000000..4b0d199
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * simone.c -- ASoC audio for Simplemachines Sim.One board
+ *
+ * Copyright (c) 2010 Mika Westerberg
+ *
+ * Based on snappercl15 machine driver by Ryan Mallon.
+ *
+ * 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/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+
+#include "ep93xx-pcm.h"
+
+static struct snd_soc_dai_link simone_dai = {
+       .name           = "AC97",
+       .stream_name    = "AC97 HiFi",
+       .cpu_dai_name   = "ep93xx-ac97",
+       .codec_dai_name = "ac97-hifi",
+       .codec_name     = "ac97-codec",
+       .platform_name  = "ep93xx-pcm-audio",
+};
+
+static struct snd_soc_card snd_soc_simone = {
+       .name           = "Sim.One",
+       .dai_link       = &simone_dai,
+       .num_links      = 1,
+};
+
+static struct platform_device *simone_snd_ac97_device;
+static struct platform_device *simone_snd_device;
+
+static int __init simone_init(void)
+{
+       int ret;
+
+       if (!machine_is_sim_one())
+               return -ENODEV;
+
+       simone_snd_ac97_device = platform_device_alloc("ac97-codec", -1);
+       if (!simone_snd_ac97_device)
+               return -ENOMEM;
+
+       ret = platform_device_add(simone_snd_ac97_device);
+       if (ret)
+               goto fail;
+
+       simone_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!simone_snd_device) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       platform_set_drvdata(simone_snd_device, &snd_soc_simone);
+       ret = platform_device_add(simone_snd_device);
+       if (ret) {
+               platform_device_put(simone_snd_device);
+               goto fail;
+       }
+
+       return ret;
+
+fail:
+       platform_device_put(simone_snd_ac97_device);
+       return ret;
+}
+module_init(simone_init);
+
+static void __exit simone_exit(void)
+{
+       platform_device_unregister(simone_snd_device);
+       platform_device_unregister(simone_snd_ac97_device);
+}
+module_exit(simone_exit);
+
+MODULE_DESCRIPTION("ALSA SoC Simplemachines Sim.One");
+MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
+MODULE_LICENSE("GPL");
index 64955340ff75c9a66f830888cc847cd55c42818a..28ab5ff772acda6a82e7a17794aa988fd20aabfa 100644 (file)
@@ -22,7 +22,6 @@
 
 #include "../codecs/tlv320aic23.h"
 #include "ep93xx-pcm.h"
-#include "ep93xx-i2s.h"
 
 #define CODEC_CLOCK 5644800
 
@@ -30,8 +29,8 @@ static int snappercl15_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int err;
 
        err = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
@@ -77,8 +76,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"MICIN", NULL, "Mic Jack"},
 };
 
-static int snappercl15_tlv320aic23_init(struct snd_soc_codec *codec)
+static int snappercl15_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
                                  ARRAY_SIZE(tlv320aic23_dapm_widgets));
 
@@ -89,24 +90,20 @@ static int snappercl15_tlv320aic23_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link snappercl15_dai = {
        .name           = "tlv320aic23",
        .stream_name    = "AIC23",
-       .cpu_dai        = &ep93xx_i2s_dai,
-       .codec_dai      = &tlv320aic23_dai,
+       .cpu_dai_name   = "ep93xx-i2s",
+       .codec_dai_name = "tlv320aic23-hifi",
+       .codec_name     = "tlv320aic23-codec.0-001a",
+       .platform_name  =  "ep93xx-pcm-audio",
        .init           = snappercl15_tlv320aic23_init,
        .ops            = &snappercl15_ops,
 };
 
 static struct snd_soc_card snd_soc_snappercl15 = {
        .name           = "Snapper CL15",
-       .platform       = &ep93xx_soc_platform,
        .dai_link       = &snappercl15_dai,
        .num_links      = 1,
 };
 
-static struct snd_soc_device snappercl15_snd_devdata = {
-       .card           = &snd_soc_snappercl15,
-       .codec_dev      = &soc_codec_dev_tlv320aic23,
-};
-
 static struct platform_device *snappercl15_snd_device;
 
 static int __init snappercl15_init(void)
@@ -126,8 +123,7 @@ static int __init snappercl15_init(void)
        if (!snappercl15_snd_device)
                return -ENOMEM;
        
-       platform_set_drvdata(snappercl15_snd_device, &snappercl15_snd_devdata);
-       snappercl15_snd_devdata.dev = &snappercl15_snd_device->dev;
+       platform_set_drvdata(snappercl15_snd_device, &snd_soc_snappercl15);
        ret = platform_device_add(snappercl15_snd_device);
        if (ret)
                platform_device_put(snappercl15_snd_device);
index 8cb65ccad35fb8cfcf96caac60cd2b0e1adb468e..d754d34d68a68a83b95b080ee9bf0baebeaea0ce 100644 (file)
@@ -1,27 +1,36 @@
-config SND_SOC_OF_SIMPLE
-       tristate
-       
 config SND_MPC52xx_DMA
        tristate
 
-# ASoC platform support for the Freescale MPC8610 SOC.  This compiles drivers
-# for the SSI and the Elo DMA controller.  You will still need to select
-# a platform driver and a codec driver.
-config SND_SOC_MPC8610
+# ASoC platform support for the Freescale PowerPC SOCs that have an SSI and
+# an Elo DMA controller, such as the MPC8610 and P1022.  You will still need to
+# select a platform driver and a codec driver.
+config SND_SOC_POWERPC_SSI
        tristate
-       depends on MPC8610
+       depends on FSL_SOC
 
 config SND_SOC_MPC8610_HPCD
        tristate "ALSA SoC support for the Freescale MPC8610 HPCD board"
        # I2C is necessary for the CS4270 driver
        depends on MPC8610_HPCD && I2C
-       select SND_SOC_MPC8610
+       select SND_SOC_POWERPC_SSI
        select SND_SOC_CS4270
        select SND_SOC_CS4270_VD33_ERRATA
        default y if MPC8610_HPCD
        help
          Say Y if you want to enable audio on the Freescale MPC8610 HPCD.
 
+config SND_SOC_P1022_DS
+       tristate "ALSA SoC support for the Freescale P1022 DS board"
+       # I2C is necessary for the WM8776 driver
+       depends on P1022_DS && I2C
+       select SND_SOC_POWERPC_SSI
+       select SND_SOC_WM8776
+       default y if P1022_DS
+       help
+         Say Y if you want to enable audio on the Freescale P1022 DS board.
+         This will also include the Wolfson Microelectronics WM8776 codec
+         driver.
+
 config SND_SOC_MPC5200_I2S
        tristate "Freescale MPC5200 PSC in I2S mode driver"
        depends on PPC_MPC52xx && PPC_BESTCOMM
index a83a73967ec666a14409bb8f64c3b540c8b0f401..b4a38c0ac58c35445e8efb91b66cf4f8c7a92cde 100644 (file)
@@ -1,14 +1,15 @@
-# Simple machine driver that extracts configuration from the OF device tree
-obj-$(CONFIG_SND_SOC_OF_SIMPLE) += soc-of-simple.o
-
 # MPC8610 HPCD Machine Support
 snd-soc-mpc8610-hpcd-objs := mpc8610_hpcd.o
 obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += snd-soc-mpc8610-hpcd.o
 
-# MPC8610 Platform Support
+# P1022 DS Machine Support
+snd-soc-p1022-ds-objs := p1022_ds.o
+obj-$(CONFIG_SND_SOC_P1022_DS) += snd-soc-p1022-ds.o
+
+# Freescale PowerPC SSI/DMA Platform Support
 snd-soc-fsl-ssi-objs := fsl_ssi.o
 snd-soc-fsl-dma-objs := fsl_dma.o
-obj-$(CONFIG_SND_SOC_MPC8610) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
+obj-$(CONFIG_SND_SOC_POWERPC_SSI) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
 
 # MPC5200 Platform Support
 obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
index 1a5b8e0d6a34d986fcfb62c5ac0c7cdc6ad9f2b7..53251e6b5bd509303dc17500e8f4d64feeea7021 100644 (file)
@@ -24,7 +24,6 @@
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
-#include <sound/soc-of-simple.h>
 
 #include "mpc5200_dma.h"
 #include "mpc5200_psc_ac97.h"
 
 #define DRV_NAME "efika-audio-fabric"
 
-static struct snd_soc_device device;
 static struct snd_soc_card card;
 
 static struct snd_soc_dai_link efika_fabric_dai[] = {
 {
        .name = "AC97",
        .stream_name = "AC97 Analog",
-       .codec_dai = &stac9766_dai[STAC9766_DAI_AC97_ANALOG],
-       .cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL],
+       .codec_dai_name = "stac9766-hifi-analog",
+       .cpu_dai_name = "mpc5200-psc-ac97.0",
+       .platform_name = "mpc5200-pcm-audio",
+       .codec_name = "stac9766-codec",
 },
 {
        .name = "AC97",
        .stream_name = "AC97 IEC958",
-       .codec_dai = &stac9766_dai[STAC9766_DAI_AC97_DIGITAL],
-       .cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF],
+       .codec_dai_name = "stac9766-hifi-IEC958",
+       .cpu_dai_name = "mpc5200-psc-ac97.1",
+       .platform_name = "mpc5200-pcm-audio",
+       .codec_name = "stac9766-codec",
 },
 };
 
@@ -58,13 +60,10 @@ static __init int efika_fabric_init(void)
        if (!of_machine_is_compatible("bplan,efika"))
                return -ENODEV;
 
-       card.platform = &mpc5200_audio_dma_platform;
        card.name = "Efika";
        card.dai_link = efika_fabric_dai;
        card.num_links = ARRAY_SIZE(efika_fabric_dai);
 
-       device.card = &card;
-       device.codec_dev = &soc_codec_dev_stac9766;
 
        pdev = platform_device_alloc("soc-audio", 1);
        if (!pdev) {
@@ -72,8 +71,7 @@ static __init int efika_fabric_init(void)
                return -ENODEV;
        }
 
-       platform_set_drvdata(pdev, &device);
-       device.dev = &pdev->dev;
+       platform_set_drvdata(pdev, &card);
 
        rc = platform_device_add(pdev);
        if (rc) {
index 410c7496a18dd295cec46770176ba960ca46686b..4cf98c03af223cda837a25a6f0c98c8eb0071025 100644 (file)
@@ -3,10 +3,11 @@
  *
  * Author: Timur Tabi <timur@freescale.com>
  *
- * Copyright 2007-2008 Freescale Semiconductor, Inc.  This file is licensed
- * under the terms of the GNU General Public License version 2.  This
- * program is licensed "as is" without any warranty of any kind, whether
- * express or implied.
+ * Copyright 2007-2010 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
  *
  * This driver implements ASoC support for the Elo DMA controller, which is
  * the DMA controller on Freescale 83xx, 85xx, and 86xx SOCs. In ALSA terms,
@@ -20,6 +21,9 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/gfp.h>
+#include <linux/of_platform.h>
+#include <linux/list.h>
+#include <linux/slab.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -29,6 +33,7 @@
 #include <asm/io.h>
 
 #include "fsl_dma.h"
+#include "fsl_ssi.h"   /* For the offset of stx0 and srx0 */
 
 /*
  * The formats that the DMA controller supports, which is anything
 #define FSLDMA_PCM_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \
                          SNDRV_PCM_RATE_CONTINUOUS)
 
-/* DMA global data.  This structure is used by fsl_dma_open() to determine
- * which DMA channels to assign to a substream.  Unfortunately, ASoC V1 does
- * not allow the machine driver to provide this information to the PCM
- * driver in advance, and there's no way to differentiate between the two
- * DMA controllers.  So for now, this driver only supports one SSI device
- * using two DMA channels.  We cannot support multiple DMA devices.
- *
- * ssi_stx_phys: bus address of SSI STX register
- * ssi_srx_phys: bus address of SSI SRX register
- * dma_channel: pointer to the DMA channel's registers
- * irq: IRQ for this DMA channel
- * assigned: set to 1 if that DMA channel is assigned to a substream
- */
-static struct {
+struct dma_object {
+       struct snd_soc_platform_driver dai;
        dma_addr_t ssi_stx_phys;
        dma_addr_t ssi_srx_phys;
-       struct ccsr_dma_channel __iomem *dma_channel[2];
-       unsigned int irq[2];
-       unsigned int assigned[2];
-} dma_global_data;
+       unsigned int ssi_fifo_depth;
+       struct ccsr_dma_channel __iomem *channel;
+       unsigned int irq;
+       bool assigned;
+       char path[1];
+};
 
 /*
  * The number of DMA links to use.  Two is the bare minimum, but if you
@@ -88,8 +83,6 @@ static struct {
  * structure.
  *
  * @link[]: array of link descriptors
- * @controller_id: which DMA controller (0, 1, ...)
- * @channel_id: which DMA channel on the controller (0, 1, 2, ...)
  * @dma_channel: pointer to the DMA channel's registers
  * @irq: IRQ for this DMA channel
  * @substream: pointer to the substream object, needed by the ISR
@@ -104,12 +97,11 @@ static struct {
  */
 struct fsl_dma_private {
        struct fsl_dma_link_descriptor link[NUM_DMA_LINKS];
-       unsigned int controller_id;
-       unsigned int channel_id;
        struct ccsr_dma_channel __iomem *dma_channel;
        unsigned int irq;
        struct snd_pcm_substream *substream;
        dma_addr_t ssi_sxx_phys;
+       unsigned int ssi_fifo_depth;
        dma_addr_t ld_buf_phys;
        unsigned int current_link;
        dma_addr_t dma_buf_phys;
@@ -185,13 +177,23 @@ static void fsl_dma_update_pointers(struct fsl_dma_private *dma_private)
        struct fsl_dma_link_descriptor *link =
                &dma_private->link[dma_private->current_link];
 
-       /* Update our link descriptors to point to the next period */
-       if (dma_private->substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               link->source_addr =
-                       cpu_to_be32(dma_private->dma_buf_next);
-       else
-               link->dest_addr =
-                       cpu_to_be32(dma_private->dma_buf_next);
+       /* Update our link descriptors to point to the next period. On a 36-bit
+        * system, we also need to update the ESAD bits.  We also set (keep) the
+        * snoop bits.  See the comments in fsl_dma_hw_params() about snooping.
+        */
+       if (dma_private->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               link->source_addr = cpu_to_be32(dma_private->dma_buf_next);
+#ifdef CONFIG_PHYS_64BIT
+               link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP |
+                       upper_32_bits(dma_private->dma_buf_next));
+#endif
+       } else {
+               link->dest_addr = cpu_to_be32(dma_private->dma_buf_next);
+#ifdef CONFIG_PHYS_64BIT
+               link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP |
+                       upper_32_bits(dma_private->dma_buf_next));
+#endif
+       }
 
        /* Update our variables for next time */
        dma_private->dma_buf_next += dma_private->period_size;
@@ -212,6 +214,9 @@ static void fsl_dma_update_pointers(struct fsl_dma_private *dma_private)
 static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
 {
        struct fsl_dma_private *dma_private = dev_id;
+       struct snd_pcm_substream *substream = dma_private->substream;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct device *dev = rtd->platform->dev;
        struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
        irqreturn_t ret = IRQ_NONE;
        u32 sr, sr2 = 0;
@@ -222,11 +227,8 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
        sr = in_be32(&dma_channel->sr);
 
        if (sr & CCSR_DMA_SR_TE) {
-               dev_err(dma_private->substream->pcm->card->dev,
-                       "DMA transmit error (controller=%u channel=%u irq=%u\n",
-                       dma_private->controller_id,
-                       dma_private->channel_id, irq);
-               fsl_dma_abort_stream(dma_private->substream);
+               dev_err(dev, "dma transmit error\n");
+               fsl_dma_abort_stream(substream);
                sr2 |= CCSR_DMA_SR_TE;
                ret = IRQ_HANDLED;
        }
@@ -235,11 +237,8 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
                ret = IRQ_HANDLED;
 
        if (sr & CCSR_DMA_SR_PE) {
-               dev_err(dma_private->substream->pcm->card->dev,
-                       "DMA%u programming error (channel=%u irq=%u)\n",
-                       dma_private->controller_id,
-                       dma_private->channel_id, irq);
-               fsl_dma_abort_stream(dma_private->substream);
+               dev_err(dev, "dma programming error\n");
+               fsl_dma_abort_stream(substream);
                sr2 |= CCSR_DMA_SR_PE;
                ret = IRQ_HANDLED;
        }
@@ -253,8 +252,6 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
                ret = IRQ_HANDLED;
 
        if (sr & CCSR_DMA_SR_EOSI) {
-               struct snd_pcm_substream *substream = dma_private->substream;
-
                /* Tell ALSA we completed a period. */
                snd_pcm_period_elapsed(substream);
 
@@ -288,11 +285,19 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id)
  * This function is called when the codec driver calls snd_soc_new_pcms(),
  * once for each .dai_link in the machine driver's snd_soc_card
  * structure.
+ *
+ * snd_dma_alloc_pages() is just a front-end to dma_alloc_coherent(), which
+ * (currently) always allocates the DMA buffer in lowmem, even if GFP_HIGHMEM
+ * is specified. Therefore, any DMA buffers we allocate will always be in low
+ * memory, but we support for 36-bit physical addresses anyway.
+ *
+ * Regardless of where the memory is actually allocated, since the device can
+ * technically DMA to any 36-bit address, we do need to set the DMA mask to 36.
  */
 static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
        struct snd_pcm *pcm)
 {
-       static u64 fsl_dma_dmamask = DMA_BIT_MASK(32);
+       static u64 fsl_dma_dmamask = DMA_BIT_MASK(36);
        int ret;
 
        if (!card->dev->dma_mask)
@@ -301,25 +306,29 @@ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = fsl_dma_dmamask;
 
-       ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
-               fsl_dma_hardware.buffer_bytes_max,
-               &pcm->streams[0].substream->dma_buffer);
-       if (ret) {
-               dev_err(card->dev,
-                       "Can't allocate playback DMA buffer (size=%u)\n",
-                       fsl_dma_hardware.buffer_bytes_max);
-               return -ENOMEM;
+       /* Some codecs have separate DAIs for playback and capture, so we
+        * should allocate a DMA buffer only for the streams that are valid.
+        */
+
+       if (dai->driver->playback.channels_min) {
+               ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
+                       fsl_dma_hardware.buffer_bytes_max,
+                       &pcm->streams[0].substream->dma_buffer);
+               if (ret) {
+                       dev_err(card->dev, "can't alloc playback dma buffer\n");
+                       return ret;
+               }
        }
 
-       ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
-               fsl_dma_hardware.buffer_bytes_max,
-               &pcm->streams[1].substream->dma_buffer);
-       if (ret) {
-               snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
-               dev_err(card->dev,
-                       "Can't allocate capture DMA buffer (size=%u)\n",
-                       fsl_dma_hardware.buffer_bytes_max);
-               return -ENOMEM;
+       if (dai->driver->capture.channels_min) {
+               ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
+                       fsl_dma_hardware.buffer_bytes_max,
+                       &pcm->streams[1].substream->dma_buffer);
+               if (ret) {
+                       snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
+                       dev_err(card->dev, "can't alloc capture dma buffer\n");
+                       return ret;
+               }
        }
 
        return 0;
@@ -390,6 +399,10 @@ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
 static int fsl_dma_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct device *dev = rtd->platform->dev;
+       struct dma_object *dma =
+               container_of(rtd->platform->driver, struct dma_object, dai);
        struct fsl_dma_private *dma_private;
        struct ccsr_dma_channel __iomem *dma_channel;
        dma_addr_t ld_buf_phys;
@@ -407,52 +420,45 @@ static int fsl_dma_open(struct snd_pcm_substream *substream)
        ret = snd_pcm_hw_constraint_integer(runtime,
                SNDRV_PCM_HW_PARAM_PERIODS);
        if (ret < 0) {
-               dev_err(substream->pcm->card->dev, "invalid buffer size\n");
+               dev_err(dev, "invalid buffer size\n");
                return ret;
        }
 
        channel = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
 
-       if (dma_global_data.assigned[channel]) {
-               dev_err(substream->pcm->card->dev,
-                       "DMA channel already assigned\n");
+       if (dma->assigned) {
+               dev_err(dev, "dma channel already assigned\n");
                return -EBUSY;
        }
 
-       dma_private = dma_alloc_coherent(substream->pcm->card->dev,
-               sizeof(struct fsl_dma_private), &ld_buf_phys, GFP_KERNEL);
+       dma_private = dma_alloc_coherent(dev, sizeof(struct fsl_dma_private),
+                                        &ld_buf_phys, GFP_KERNEL);
        if (!dma_private) {
-               dev_err(substream->pcm->card->dev,
-                       "can't allocate DMA private data\n");
+               dev_err(dev, "can't allocate dma private data\n");
                return -ENOMEM;
        }
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               dma_private->ssi_sxx_phys = dma_global_data.ssi_stx_phys;
+               dma_private->ssi_sxx_phys = dma->ssi_stx_phys;
        else
-               dma_private->ssi_sxx_phys = dma_global_data.ssi_srx_phys;
+               dma_private->ssi_sxx_phys = dma->ssi_srx_phys;
 
-       dma_private->dma_channel = dma_global_data.dma_channel[channel];
-       dma_private->irq = dma_global_data.irq[channel];
+       dma_private->ssi_fifo_depth = dma->ssi_fifo_depth;
+       dma_private->dma_channel = dma->channel;
+       dma_private->irq = dma->irq;
        dma_private->substream = substream;
        dma_private->ld_buf_phys = ld_buf_phys;
        dma_private->dma_buf_phys = substream->dma_buffer.addr;
 
-       /* We only support one DMA controller for now */
-       dma_private->controller_id = 0;
-       dma_private->channel_id = channel;
-
        ret = request_irq(dma_private->irq, fsl_dma_isr, 0, "DMA", dma_private);
        if (ret) {
-               dev_err(substream->pcm->card->dev,
-                       "can't register ISR for IRQ %u (ret=%i)\n",
+               dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
                        dma_private->irq, ret);
-               dma_free_coherent(substream->pcm->card->dev,
-                       sizeof(struct fsl_dma_private),
+               dma_free_coherent(dev, sizeof(struct fsl_dma_private),
                        dma_private, dma_private->ld_buf_phys);
                return ret;
        }
 
-       dma_global_data.assigned[channel] = 1;
+       dma->assigned = 1;
 
        snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
        snd_soc_set_runtime_hwparams(substream, &fsl_dma_hardware);
@@ -546,13 +552,15 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct fsl_dma_private *dma_private = runtime->private_data;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct device *dev = rtd->platform->dev;
 
        /* Number of bits per sample */
-       unsigned int sample_size =
+       unsigned int sample_bits =
                snd_pcm_format_physical_width(params_format(hw_params));
 
        /* Number of bytes per frame */
-       unsigned int frame_size = 2 * (sample_size / 8);
+       unsigned int sample_bytes = sample_bits / 8;
 
        /* Bus address of SSI STX register */
        dma_addr_t ssi_sxx_phys = dma_private->ssi_sxx_phys;
@@ -592,7 +600,7 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
         * that offset here.  While we're at it, also tell the DMA controller
         * how much data to transfer per sample.
         */
-       switch (sample_size) {
+       switch (sample_bits) {
        case 8:
                mr |= CCSR_DMA_MR_DAHTS_1 | CCSR_DMA_MR_SAHTS_1;
                ssi_sxx_phys += 3;
@@ -606,23 +614,42 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
                break;
        default:
                /* We should never get here */
-               dev_err(substream->pcm->card->dev,
-                       "unsupported sample size %u\n", sample_size);
+               dev_err(dev, "unsupported sample size %u\n", sample_bits);
                return -EINVAL;
        }
 
        /*
-        * BWC should always be a multiple of the frame size.  BWC determines
-        * how many bytes are sent/received before the DMA controller checks the
-        * SSI to see if it needs to stop.  For playback, the transmit FIFO can
-        * hold three frames, so we want to send two frames at a time. For
-        * capture, the receive FIFO is triggered when it contains one frame, so
-        * we want to receive one frame at a time.
+        * BWC determines how many bytes are sent/received before the DMA
+        * controller checks the SSI to see if it needs to stop. BWC should
+        * always be a multiple of the frame size, so that we always transmit
+        * whole frames.  Each frame occupies two slots in the FIFO.  The
+        * parameter for CCSR_DMA_MR_BWC() is rounded down the next power of two
+        * (MR[BWC] can only represent even powers of two).
+        *
+        * To simplify the process, we set BWC to the largest value that is
+        * less than or equal to the FIFO watermark.  For playback, this ensures
+        * that we transfer the maximum amount without overrunning the FIFO.
+        * For capture, this ensures that we transfer the maximum amount without
+        * underrunning the FIFO.
+        *
+        * f = SSI FIFO depth
+        * w = SSI watermark value (which equals f - 2)
+        * b = DMA bandwidth count (in bytes)
+        * s = sample size (in bytes, which equals frame_size * 2)
+        *
+        * For playback, we never transmit more than the transmit FIFO
+        * watermark, otherwise we might write more data than the FIFO can hold.
+        * The watermark is equal to the FIFO depth minus two.
+        *
+        * For capture, two equations must hold:
+        *      w > f - (b / s)
+        *      w >= b / s
+        *
+        * So, b > 2 * s, but b must also be <= s * w.  To simplify, we set
+        * b = s * w, which is equal to
+        *      (dma_private->ssi_fifo_depth - 2) * sample_bytes.
         */
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               mr |= CCSR_DMA_MR_BWC(2 * frame_size);
-       else
-               mr |= CCSR_DMA_MR_BWC(frame_size);
+       mr |= CCSR_DMA_MR_BWC((dma_private->ssi_fifo_depth - 2) * sample_bytes);
 
        out_be32(&dma_channel->mr, mr);
 
@@ -631,12 +658,7 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
 
                link->count = cpu_to_be32(period_size);
 
-               /* Even though the DMA controller supports 36-bit addressing,
-                * for simplicity we allow only 32-bit addresses for the audio
-                * buffer itself.  This was enforced in fsl_dma_new() with the
-                * DMA mask.
-                *
-                * The snoop bit tells the DMA controller whether it should tell
+               /* The snoop bit tells the DMA controller whether it should tell
                 * the ECM to snoop during a read or write to an address. For
                 * audio, we use DMA to transfer data between memory and an I/O
                 * device (the SSI's STX0 or SRX0 register). Snooping is only
@@ -651,20 +673,24 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
                 * flush out the data for the previous period.  So if you
                 * increased period_bytes_min to a large enough size, you might
                 * get more performance by not snooping, and you'll still be
-                * okay.
+                * okay.  You'll need to update fsl_dma_update_pointers() also.
                 */
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                        link->source_addr = cpu_to_be32(temp_addr);
-                       link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
+                       link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP |
+                               upper_32_bits(temp_addr));
 
                        link->dest_addr = cpu_to_be32(ssi_sxx_phys);
-                       link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP);
+                       link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP |
+                               upper_32_bits(ssi_sxx_phys));
                } else {
                        link->source_addr = cpu_to_be32(ssi_sxx_phys);
-                       link->source_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP);
+                       link->source_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP |
+                               upper_32_bits(ssi_sxx_phys));
 
                        link->dest_addr = cpu_to_be32(temp_addr);
-                       link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
+                       link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP |
+                               upper_32_bits(temp_addr));
                }
 
                temp_addr += period_size;
@@ -689,14 +715,29 @@ static snd_pcm_uframes_t fsl_dma_pointer(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct fsl_dma_private *dma_private = runtime->private_data;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct device *dev = rtd->platform->dev;
        struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
        dma_addr_t position;
        snd_pcm_uframes_t frames;
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+       /* Obtain the current DMA pointer, but don't read the ESAD bits if we
+        * only have 32-bit DMA addresses.  This function is typically called
+        * in interrupt context, so we need to optimize it.
+        */
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                position = in_be32(&dma_channel->sar);
-       else
+#ifdef CONFIG_PHYS_64BIT
+               position |= (u64)(in_be32(&dma_channel->satr) &
+                                 CCSR_DMA_ATR_ESAD_MASK) << 32;
+#endif
+       } else {
                position = in_be32(&dma_channel->dar);
+#ifdef CONFIG_PHYS_64BIT
+               position |= (u64)(in_be32(&dma_channel->datr) &
+                                 CCSR_DMA_ATR_ESAD_MASK) << 32;
+#endif
+       }
 
        /*
         * When capture is started, the SSI immediately starts to fill its FIFO.
@@ -710,8 +751,7 @@ static snd_pcm_uframes_t fsl_dma_pointer(struct snd_pcm_substream *substream)
 
        if ((position < dma_private->dma_buf_phys) ||
            (position > dma_private->dma_buf_end)) {
-               dev_err(substream->pcm->card->dev,
-                       "dma pointer is out of range, halting stream\n");
+               dev_err(dev, "dma pointer is out of range, halting stream\n");
                return SNDRV_PCM_POS_XRUN;
        }
 
@@ -772,26 +812,28 @@ static int fsl_dma_close(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct fsl_dma_private *dma_private = runtime->private_data;
-       int dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct device *dev = rtd->platform->dev;
+       struct dma_object *dma =
+               container_of(rtd->platform->driver, struct dma_object, dai);
 
        if (dma_private) {
                if (dma_private->irq)
                        free_irq(dma_private->irq, dma_private);
 
                if (dma_private->ld_buf_phys) {
-                       dma_unmap_single(substream->pcm->card->dev,
-                               dma_private->ld_buf_phys,
-                               sizeof(dma_private->link), DMA_TO_DEVICE);
+                       dma_unmap_single(dev, dma_private->ld_buf_phys,
+                                        sizeof(dma_private->link),
+                                        DMA_TO_DEVICE);
                }
 
                /* Deallocate the fsl_dma_private structure */
-               dma_free_coherent(substream->pcm->card->dev,
-                       sizeof(struct fsl_dma_private),
-                       dma_private, dma_private->ld_buf_phys);
+               dma_free_coherent(dev, sizeof(struct fsl_dma_private),
+                                 dma_private, dma_private->ld_buf_phys);
                substream->runtime->private_data = NULL;
        }
 
-       dma_global_data.assigned[dir] = 0;
+       dma->assigned = 0;
 
        return 0;
 }
@@ -814,6 +856,37 @@ static void fsl_dma_free_dma_buffers(struct snd_pcm *pcm)
        }
 }
 
+/**
+ * find_ssi_node -- returns the SSI node that points to his DMA channel node
+ *
+ * Although this DMA driver attempts to operate independently of the other
+ * devices, it still needs to determine some information about the SSI device
+ * that it's working with.  Unfortunately, the device tree does not contain
+ * a pointer from the DMA channel node to the SSI node -- the pointer goes the
+ * other way.  So we need to scan the device tree for SSI nodes until we find
+ * the one that points to the given DMA channel node.  It's ugly, but at least
+ * it's contained in this one function.
+ */
+static struct device_node *find_ssi_node(struct device_node *dma_channel_np)
+{
+       struct device_node *ssi_np, *np;
+
+       for_each_compatible_node(ssi_np, NULL, "fsl,mpc8610-ssi") {
+               /* Check each DMA phandle to see if it points to us.  We
+                * assume that device_node pointers are a valid comparison.
+                */
+               np = of_parse_phandle(ssi_np, "fsl,playback-dma", 0);
+               if (np == dma_channel_np)
+                       return ssi_np;
+
+               np = of_parse_phandle(ssi_np, "fsl,capture-dma", 0);
+               if (np == dma_channel_np)
+                       return ssi_np;
+       }
+
+       return NULL;
+}
+
 static struct snd_pcm_ops fsl_dma_ops = {
        .open           = fsl_dma_open,
        .close          = fsl_dma_close,
@@ -823,59 +896,114 @@ static struct snd_pcm_ops fsl_dma_ops = {
        .pointer        = fsl_dma_pointer,
 };
 
-struct snd_soc_platform fsl_soc_platform = {
-       .name           = "fsl-dma",
-       .pcm_ops        = &fsl_dma_ops,
-       .pcm_new        = fsl_dma_new,
-       .pcm_free       = fsl_dma_free_dma_buffers,
-};
-EXPORT_SYMBOL_GPL(fsl_soc_platform);
+static int __devinit fsl_soc_dma_probe(struct platform_device *pdev,
+                                      const struct of_device_id *match)
+ {
+       struct dma_object *dma;
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *ssi_np;
+       struct resource res;
+       const uint32_t *iprop;
+       int ret;
 
-/**
- * fsl_dma_configure: store the DMA parameters from the fabric driver.
- *
- * This function is called by the ASoC fabric driver to give us the DMA and
- * SSI channel information.
- *
- * Unfortunately, ASoC V1 does make it possible to determine the DMA/SSI
- * data when a substream is created, so for now we need to store this data
- * into a global variable.  This means that we can only support one DMA
- * controller, and hence only one SSI.
- */
-int fsl_dma_configure(struct fsl_dma_info *dma_info)
+       /* Find the SSI node that points to us. */
+       ssi_np = find_ssi_node(np);
+       if (!ssi_np) {
+               dev_err(&pdev->dev, "cannot find parent SSI node\n");
+               return -ENODEV;
+       }
+
+       ret = of_address_to_resource(ssi_np, 0, &res);
+       if (ret) {
+               dev_err(&pdev->dev, "could not determine resources for %s\n",
+                       ssi_np->full_name);
+               of_node_put(ssi_np);
+               return ret;
+       }
+
+       dma = kzalloc(sizeof(*dma) + strlen(np->full_name), GFP_KERNEL);
+       if (!dma) {
+               dev_err(&pdev->dev, "could not allocate dma object\n");
+               of_node_put(ssi_np);
+               return -ENOMEM;
+       }
+
+       strcpy(dma->path, np->full_name);
+       dma->dai.ops = &fsl_dma_ops;
+       dma->dai.pcm_new = fsl_dma_new;
+       dma->dai.pcm_free = fsl_dma_free_dma_buffers;
+
+       /* Store the SSI-specific information that we need */
+       dma->ssi_stx_phys = res.start + offsetof(struct ccsr_ssi, stx0);
+       dma->ssi_srx_phys = res.start + offsetof(struct ccsr_ssi, srx0);
+
+       iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL);
+       if (iprop)
+               dma->ssi_fifo_depth = *iprop;
+       else
+                /* Older 8610 DTs didn't have the fifo-depth property */
+               dma->ssi_fifo_depth = 8;
+
+       of_node_put(ssi_np);
+
+       ret = snd_soc_register_platform(&pdev->dev, &dma->dai);
+       if (ret) {
+               dev_err(&pdev->dev, "could not register platform\n");
+               kfree(dma);
+               return ret;
+       }
+
+       dma->channel = of_iomap(np, 0);
+       dma->irq = irq_of_parse_and_map(np, 0);
+
+       dev_set_drvdata(&pdev->dev, dma);
+
+       return 0;
+}
+
+static int __devexit fsl_soc_dma_remove(struct platform_device *pdev)
 {
-       static int initialized;
+       struct dma_object *dma = dev_get_drvdata(&pdev->dev);
 
-       /* We only support one DMA controller for now */
-       if (initialized)
-               return 0;
+       snd_soc_unregister_platform(&pdev->dev);
+       iounmap(dma->channel);
+       irq_dispose_mapping(dma->irq);
+       kfree(dma);
 
-       dma_global_data.ssi_stx_phys = dma_info->ssi_stx_phys;
-       dma_global_data.ssi_srx_phys = dma_info->ssi_srx_phys;
-       dma_global_data.dma_channel[0] = dma_info->dma_channel[0];
-       dma_global_data.dma_channel[1] = dma_info->dma_channel[1];
-       dma_global_data.irq[0] = dma_info->dma_irq[0];
-       dma_global_data.irq[1] = dma_info->dma_irq[1];
-       dma_global_data.assigned[0] = 0;
-       dma_global_data.assigned[1] = 0;
-
-       initialized = 1;
-       return 1;
+       return 0;
 }
-EXPORT_SYMBOL_GPL(fsl_dma_configure);
 
-static int __init fsl_soc_platform_init(void)
+static const struct of_device_id fsl_soc_dma_ids[] = {
+       { .compatible = "fsl,ssi-dma-channel", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, fsl_soc_dma_ids);
+
+static struct of_platform_driver fsl_soc_dma_driver = {
+       .driver = {
+               .name = "fsl-pcm-audio",
+               .owner = THIS_MODULE,
+               .of_match_table = fsl_soc_dma_ids,
+       },
+       .probe = fsl_soc_dma_probe,
+       .remove = __devexit_p(fsl_soc_dma_remove),
+};
+
+static int __init fsl_soc_dma_init(void)
 {
-       return snd_soc_register_platform(&fsl_soc_platform);
+       pr_info("Freescale Elo DMA ASoC PCM Driver\n");
+
+       return of_register_platform_driver(&fsl_soc_dma_driver);
 }
-module_init(fsl_soc_platform_init);
 
-static void __exit fsl_soc_platform_exit(void)
+static void __exit fsl_soc_dma_exit(void)
 {
-       snd_soc_unregister_platform(&fsl_soc_platform);
+       of_unregister_platform_driver(&fsl_soc_dma_driver);
 }
-module_exit(fsl_soc_platform_exit);
+
+module_init(fsl_soc_dma_init);
+module_exit(fsl_soc_dma_exit);
 
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
-MODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM module");
-MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM Driver");
+MODULE_LICENSE("GPL v2");
index 385d4a42603cf3b681ab12c6f050ccd3e11f7bb0..78fee97e80362eab8035b5eee0bc5df44ce8499b 100644 (file)
@@ -126,24 +126,4 @@ struct fsl_dma_link_descriptor {
        u8 res[4];      /* Reserved */
 } __attribute__ ((aligned(32), packed));
 
-/* DMA information needed to create a snd_soc_dai object
- *
- * ssi_stx_phys: bus address of SSI STX register to use
- * ssi_srx_phys: bus address of SSI SRX register to use
- * dma[0]: points to the DMA channel to use for playback
- * dma[1]: points to the DMA channel to use for capture
- * dma_irq[0]: IRQ of the DMA channel to use for playback
- * dma_irq[1]: IRQ of the DMA channel to use for capture
- */
-struct fsl_dma_info {
-       dma_addr_t ssi_stx_phys;
-       dma_addr_t ssi_srx_phys;
-       struct ccsr_dma_channel __iomem *dma_channel[2];
-       unsigned int dma_irq[2];
-};
-
-extern struct snd_soc_platform fsl_soc_platform;
-
-int fsl_dma_configure(struct fsl_dma_info *dma_info);
-
 #endif
index 762c1b8e8e4e078e48efede6dfc52b5a81eb4fc4..4cc167a7aeb82d411306f23634891aeb3ca6da79 100644 (file)
@@ -3,10 +3,11 @@
  *
  * Author: Timur Tabi <timur@freescale.com>
  *
- * Copyright 2007-2008 Freescale Semiconductor, Inc.  This file is licensed
- * under the terms of the GNU General Public License version 2.  This
- * program is licensed "as is" without any warranty of any kind, whether
- * express or implied.
+ * Copyright 2007-2010 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
  */
 
 #include <linux/init.h>
@@ -15,6 +16,7 @@
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/of_platform.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -22,8 +24,6 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 
-#include <asm/immap_86xx.h>
-
 #include "fsl_ssi.h"
 
 /**
 /**
  * fsl_ssi_private: per-SSI private data
  *
- * @name: short name for this device ("SSI0", "SSI1", etc)
  * @ssi: pointer to the SSI's registers
  * @ssi_phys: physical address of the SSI registers
  * @irq: IRQ of this SSI
  * @first_stream: pointer to the stream that was opened first
  * @second_stream: pointer to second stream
- * @dev: struct device pointer
  * @playback: the number of playback streams opened
  * @capture: the number of capture streams opened
  * @asynchronous: 0=synchronous mode, 1=asynchronous mode
  * @cpu_dai: the CPU DAI for this device
  * @dev_attr: the sysfs device attribute structure
  * @stats: SSI statistics
+ * @name: name for this device
  */
 struct fsl_ssi_private {
-       char name[8];
        struct ccsr_ssi __iomem *ssi;
        dma_addr_t ssi_phys;
        unsigned int irq;
        struct snd_pcm_substream *first_stream;
        struct snd_pcm_substream *second_stream;
-       struct device *dev;
        unsigned int playback;
        unsigned int capture;
        int asynchronous;
-       struct snd_soc_dai cpu_dai;
+       unsigned int fifo_depth;
+       struct snd_soc_dai_driver cpu_dai_drv;
        struct device_attribute dev_attr;
+       struct platform_device *pdev;
 
        struct {
                unsigned int rfrc;
@@ -122,6 +121,8 @@ struct fsl_ssi_private {
                unsigned int tfe1;
                unsigned int tfe0;
        } stats;
+
+       char name[1];
 };
 
 /**
@@ -280,7 +281,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
+       struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
 
        /*
         * If this is the first stream opened, then request the IRQ
@@ -290,6 +291,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
                struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
                int ret;
 
+               /* The 'name' should not have any slashes in it. */
                ret = request_irq(ssi_private->irq, fsl_ssi_isr, 0,
                                  ssi_private->name, ssi_private);
                if (ret < 0) {
@@ -336,11 +338,20 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
 
                /*
                 * Set the watermark for transmit FIFI 0 and receive FIFO 0. We
-                * don't use FIFO 1.  Since the SSI only supports stereo, the
-                * watermark should never be an odd number.
+                * don't use FIFO 1.  We program the transmit water to signal a
+                * DMA transfer if there are only two (or fewer) elements left
+                * in the FIFO.  Two elements equals one frame (left channel,
+                * right channel).  This value, however, depends on the depth of
+                * the transmit buffer.
+                *
+                * We program the receive FIFO to notify us if at least two
+                * elements (one frame) have been written to the FIFO.  We could
+                * make this value larger (and maybe we should), but this way
+                * data will be written to memory as soon as it's available.
                 */
                out_be32(&ssi->sfcsr,
-                        CCSR_SSI_SFCSR_TFWM0(6) | CCSR_SSI_SFCSR_RFWM0(2));
+                       CCSR_SSI_SFCSR_TFWM0(ssi_private->fifo_depth - 2) |
+                       CCSR_SSI_SFCSR_RFWM0(ssi_private->fifo_depth - 2));
 
                /*
                 * We keep the SSI disabled because if we enable it, then the
@@ -422,7 +433,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
 static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai)
 {
-       struct fsl_ssi_private *ssi_private = cpu_dai->private_data;
+       struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
 
        if (substream == ssi_private->first_stream) {
                struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
@@ -458,7 +469,7 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
                           struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
+       struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
 
        switch (cmd) {
@@ -497,7 +508,7 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
+       struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                ssi_private->playback--;
@@ -523,56 +534,15 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
        }
 }
 
-/**
- * fsl_ssi_set_sysclk: set the clock frequency and direction
- *
- * This function is called by the machine driver to tell us what the clock
- * frequency and direction are.
- *
- * Currently, we only support operating as a clock slave (SND_SOC_CLOCK_IN),
- * and we don't care about the frequency.  Return an error if the direction
- * is not SND_SOC_CLOCK_IN.
- *
- * @clk_id: reserved, should be zero
- * @freq: the frequency of the given clock ID, currently ignored
- * @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master)
- */
-static int fsl_ssi_set_sysclk(struct snd_soc_dai *cpu_dai,
-                             int clk_id, unsigned int freq, int dir)
-{
-
-       return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
-}
-
-/**
- * fsl_ssi_set_fmt: set the serial format.
- *
- * This function is called by the machine driver to tell us what serial
- * format to use.
- *
- * Currently, we only support I2S mode.  Return an error if the format is
- * not SND_SOC_DAIFMT_I2S.
- *
- * @format: one of SND_SOC_DAIFMT_xxx
- */
-static int fsl_ssi_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
-{
-       return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
-}
-
-/**
- * fsl_ssi_dai_template: template CPU DAI for the SSI
- */
 static struct snd_soc_dai_ops fsl_ssi_dai_ops = {
        .startup        = fsl_ssi_startup,
        .hw_params      = fsl_ssi_hw_params,
        .shutdown       = fsl_ssi_shutdown,
        .trigger        = fsl_ssi_trigger,
-       .set_sysclk     = fsl_ssi_set_sysclk,
-       .set_fmt        = fsl_ssi_set_fmt,
 };
 
-static struct snd_soc_dai fsl_ssi_dai_template = {
+/* Template for the CPU dai driver structure */
+static struct snd_soc_dai_driver fsl_ssi_dai_template = {
        .playback = {
                /* The SSI does not support monaural audio. */
                .channels_min = 2,
@@ -640,95 +610,195 @@ static ssize_t fsl_sysfs_ssi_show(struct device *dev,
 }
 
 /**
- * fsl_ssi_create_dai: create a snd_soc_dai structure
- *
- * This function is called by the machine driver to create a snd_soc_dai
- * structure.  The function creates an ssi_private object, which contains
- * the snd_soc_dai.  It also creates the sysfs statistics device.
+ * Make every character in a string lower-case
  */
-struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info)
+static void make_lowercase(char *s)
+{
+       char *p = s;
+       char c;
+
+       while ((c = *p)) {
+               if ((c >= 'A') && (c <= 'Z'))
+                       *p = c + ('a' - 'A');
+               p++;
+       }
+}
+
+static int __devinit fsl_ssi_probe(struct platform_device *pdev,
+                                  const struct of_device_id *match)
 {
-       struct snd_soc_dai *fsl_ssi_dai;
        struct fsl_ssi_private *ssi_private;
        int ret = 0;
-       struct device_attribute *dev_attr;
+       struct device_attribute *dev_attr = NULL;
+       struct device_node *np = pdev->dev.of_node;
+       const char *p, *sprop;
+       const uint32_t *iprop;
+       struct resource res;
+       char name[64];
+
+       /* SSIs that are not connected on the board should have a
+        *      status = "disabled"
+        * property in their device tree nodes.
+        */
+       if (!of_device_is_available(np))
+               return -ENODEV;
+
+       /* Check for a codec-handle property. */
+       if (!of_get_property(np, "codec-handle", NULL)) {
+               dev_err(&pdev->dev, "missing codec-handle property\n");
+               return -ENODEV;
+       }
 
-       ssi_private = kzalloc(sizeof(struct fsl_ssi_private), GFP_KERNEL);
+       /* We only support the SSI in "I2S Slave" mode */
+       sprop = of_get_property(np, "fsl,mode", NULL);
+       if (!sprop || strcmp(sprop, "i2s-slave")) {
+               dev_notice(&pdev->dev, "mode %s is unsupported\n", sprop);
+               return -ENODEV;
+       }
+
+       /* The DAI name is the last part of the full name of the node. */
+       p = strrchr(np->full_name, '/') + 1;
+       ssi_private = kzalloc(sizeof(struct fsl_ssi_private) + strlen(p),
+                             GFP_KERNEL);
        if (!ssi_private) {
-               dev_err(ssi_info->dev, "could not allocate DAI object\n");
-               return NULL;
+               dev_err(&pdev->dev, "could not allocate DAI object\n");
+               return -ENOMEM;
        }
-       memcpy(&ssi_private->cpu_dai, &fsl_ssi_dai_template,
-              sizeof(struct snd_soc_dai));
 
-       fsl_ssi_dai = &ssi_private->cpu_dai;
-       dev_attr = &ssi_private->dev_attr;
+       strcpy(ssi_private->name, p);
 
-       sprintf(ssi_private->name, "ssi%u", (u8) ssi_info->id);
-       ssi_private->ssi = ssi_info->ssi;
-       ssi_private->ssi_phys = ssi_info->ssi_phys;
-       ssi_private->irq = ssi_info->irq;
-       ssi_private->dev = ssi_info->dev;
-       ssi_private->asynchronous = ssi_info->asynchronous;
+       /* Initialize this copy of the CPU DAI driver structure */
+       memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template,
+              sizeof(fsl_ssi_dai_template));
+       ssi_private->cpu_dai_drv.name = ssi_private->name;
 
-       dev_set_drvdata(ssi_private->dev, fsl_ssi_dai);
+       /* Get the addresses and IRQ */
+       ret = of_address_to_resource(np, 0, &res);
+       if (ret) {
+               dev_err(&pdev->dev, "could not determine device resources\n");
+               kfree(ssi_private);
+               return ret;
+       }
+       ssi_private->ssi = ioremap(res.start, 1 + res.end - res.start);
+       ssi_private->ssi_phys = res.start;
+       ssi_private->irq = irq_of_parse_and_map(np, 0);
+
+       /* Are the RX and the TX clocks locked? */
+       if (of_find_property(np, "fsl,ssi-asynchronous", NULL))
+               ssi_private->asynchronous = 1;
+       else
+               ssi_private->cpu_dai_drv.symmetric_rates = 1;
+
+       /* Determine the FIFO depth. */
+       iprop = of_get_property(np, "fsl,fifo-depth", NULL);
+       if (iprop)
+               ssi_private->fifo_depth = *iprop;
+       else
+                /* Older 8610 DTs didn't have the fifo-depth property */
+               ssi_private->fifo_depth = 8;
 
        /* Initialize the the device_attribute structure */
-       dev_attr->attr.name = "ssi-stats";
+       dev_attr = &ssi_private->dev_attr;
+       dev_attr->attr.name = "statistics";
        dev_attr->attr.mode = S_IRUGO;
        dev_attr->show = fsl_sysfs_ssi_show;
 
-       ret = device_create_file(ssi_private->dev, dev_attr);
+       ret = device_create_file(&pdev->dev, dev_attr);
        if (ret) {
-               dev_err(ssi_info->dev, "could not create sysfs %s file\n",
+               dev_err(&pdev->dev, "could not create sysfs %s file\n",
                        ssi_private->dev_attr.attr.name);
-               kfree(fsl_ssi_dai);
-               return NULL;
+               goto error;
        }
 
-       fsl_ssi_dai->private_data = ssi_private;
-       fsl_ssi_dai->name = ssi_private->name;
-       fsl_ssi_dai->id = ssi_info->id;
-       fsl_ssi_dai->dev = ssi_info->dev;
-       fsl_ssi_dai->symmetric_rates = 1;
+       /* Register with ASoC */
+       dev_set_drvdata(&pdev->dev, ssi_private);
+
+       ret = snd_soc_register_dai(&pdev->dev, &ssi_private->cpu_dai_drv);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
+               goto error;
+       }
 
-       ret = snd_soc_register_dai(fsl_ssi_dai);
-       if (ret != 0) {
-               dev_err(ssi_info->dev, "failed to register DAI: %d\n", ret);
-               kfree(fsl_ssi_dai);
-               return NULL;
+       /* Trigger the machine driver's probe function.  The platform driver
+        * name of the machine driver is taken from the /model property of the
+        * device tree.  We also pass the address of the CPU DAI driver
+        * structure.
+        */
+       sprop = of_get_property(of_find_node_by_path("/"), "model", NULL);
+       /* Sometimes the model name has a "fsl," prefix, so we strip that. */
+       p = strrchr(sprop, ',');
+       if (p)
+               sprop = p + 1;
+       snprintf(name, sizeof(name), "snd-soc-%s", sprop);
+       make_lowercase(name);
+
+       ssi_private->pdev =
+               platform_device_register_data(&pdev->dev, name, 0, NULL, 0);
+       if (IS_ERR(ssi_private->pdev)) {
+               ret = PTR_ERR(ssi_private->pdev);
+               dev_err(&pdev->dev, "failed to register platform: %d\n", ret);
+               goto error;
        }
 
-       return fsl_ssi_dai;
+       return 0;
+
+error:
+       snd_soc_unregister_dai(&pdev->dev);
+       dev_set_drvdata(&pdev->dev, NULL);
+       if (dev_attr)
+               device_remove_file(&pdev->dev, dev_attr);
+       irq_dispose_mapping(ssi_private->irq);
+       iounmap(ssi_private->ssi);
+       kfree(ssi_private);
+
+       return ret;
 }
-EXPORT_SYMBOL_GPL(fsl_ssi_create_dai);
 
-/**
- * fsl_ssi_destroy_dai: destroy the snd_soc_dai object
- *
- * This function undoes the operations of fsl_ssi_create_dai()
- */
-void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai)
+static int fsl_ssi_remove(struct platform_device *pdev)
 {
-       struct fsl_ssi_private *ssi_private =
-       container_of(fsl_ssi_dai, struct fsl_ssi_private, cpu_dai);
-
-       device_remove_file(ssi_private->dev, &ssi_private->dev_attr);
+       struct fsl_ssi_private *ssi_private = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dai(&ssi_private->cpu_dai);
+       platform_device_unregister(ssi_private->pdev);
+       snd_soc_unregister_dai(&pdev->dev);
+       device_remove_file(&pdev->dev, &ssi_private->dev_attr);
 
        kfree(ssi_private);
+       dev_set_drvdata(&pdev->dev, NULL);
+
+       return 0;
 }
-EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai);
+
+static const struct of_device_id fsl_ssi_ids[] = {
+       { .compatible = "fsl,mpc8610-ssi", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, fsl_ssi_ids);
+
+static struct of_platform_driver fsl_ssi_driver = {
+       .driver = {
+               .name = "fsl-ssi-dai",
+               .owner = THIS_MODULE,
+               .of_match_table = fsl_ssi_ids,
+       },
+       .probe = fsl_ssi_probe,
+       .remove = fsl_ssi_remove,
+};
 
 static int __init fsl_ssi_init(void)
 {
        printk(KERN_INFO "Freescale Synchronous Serial Interface (SSI) ASoC Driver\n");
 
-       return 0;
+       return of_register_platform_driver(&fsl_ssi_driver);
 }
+
+static void __exit fsl_ssi_exit(void)
+{
+       of_unregister_platform_driver(&fsl_ssi_driver);
+}
+
 module_init(fsl_ssi_init);
+module_exit(fsl_ssi_exit);
 
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
 MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
index eade01feaab69f0d69ea82c13466307d52158a14..217300029b5ba44463ccf4423c09093a602bac1d 100644 (file)
@@ -196,31 +196,5 @@ struct ccsr_ssi {
 #define CCSR_SSI_SOR_WAIT(x) (((x) & 3) << CCSR_SSI_SOR_WAIT_SHIFT)
 #define CCSR_SSI_SOR_SYNRST            0x00000001
 
-/* Instantiation data for an SSI interface
- *
- * This structure contains all the information that the the SSI driver needs
- * to instantiate an SSI interface with ALSA.  The machine driver should
- * create this structure, fill it in, call fsl_ssi_create_dai(), and then
- * delete the structure.
- *
- * id: which SSI this is (0, 1, etc. )
- * ssi: pointer to the SSI's registers
- * ssi_phys: physical address of the SSI registers
- * irq: IRQ of this SSI
- * dev: struct device, used to create the sysfs statistics file
- * asynchronous: 0=synchronous mode, 1=asynchronous mode
-*/
-struct fsl_ssi_info {
-       unsigned int id;
-       struct ccsr_ssi __iomem *ssi;
-       dma_addr_t ssi_phys;
-       unsigned int irq;
-       struct device *dev;
-       int asynchronous;
-};
-
-struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info);
-void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai);
-
 #endif
 
index 3dcd1469f2831939447b60f8410da6c6a0f2e11e..dce6b551cd7816be84c5dbd77db74be4c88e8315 100644 (file)
@@ -9,6 +9,8 @@
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
 
 #include <sound/soc.h>
 
@@ -107,7 +109,7 @@ static int psc_dma_hw_free(struct snd_pcm_substream *substream)
 static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
        struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
@@ -212,7 +214,7 @@ static int psc_dma_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        struct psc_dma_stream *s;
        int rc;
 
@@ -239,7 +241,7 @@ static int psc_dma_open(struct snd_pcm_substream *substream)
 static int psc_dma_close(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        struct psc_dma_stream *s;
 
        dev_dbg(psc_dma->dev, "psc_dma_close(substream=%p)\n", substream);
@@ -264,7 +266,7 @@ static snd_pcm_uframes_t
 psc_dma_pointer(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        struct psc_dma_stream *s;
        dma_addr_t count;
 
@@ -302,11 +304,11 @@ static int psc_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
                           struct snd_pcm *pcm)
 {
        struct snd_soc_pcm_runtime *rtd = pcm->private_data;
-       struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        size_t size = psc_dma_hardware.buffer_bytes_max;
        int rc = 0;
 
-       dev_dbg(rtd->socdev->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n",
+       dev_dbg(rtd->platform->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n",
                card, dai, pcm);
 
        if (!card->dev->dma_mask)
@@ -328,8 +330,8 @@ static int psc_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
                        goto capture_alloc_err;
        }
 
-       if (rtd->socdev->card->codec->ac97)
-               rtd->socdev->card->codec->ac97->private_data = psc_dma;
+       if (rtd->codec->ac97)
+               rtd->codec->ac97->private_data = psc_dma;
 
        return 0;
 
@@ -349,7 +351,7 @@ static void psc_dma_free(struct snd_pcm *pcm)
        struct snd_pcm_substream *substream;
        int stream;
 
-       dev_dbg(rtd->socdev->dev, "psc_dma_free(pcm=%p)\n", pcm);
+       dev_dbg(rtd->platform->dev, "psc_dma_free(pcm=%p)\n", pcm);
 
        for (stream = 0; stream < 2; stream++) {
                substream = pcm->streams[stream].substream;
@@ -361,15 +363,14 @@ static void psc_dma_free(struct snd_pcm *pcm)
        }
 }
 
-struct snd_soc_platform mpc5200_audio_dma_platform = {
-       .name           = "mpc5200-psc-audio",
-       .pcm_ops        = &psc_dma_ops,
+static struct snd_soc_platform_driver mpc5200_audio_dma_platform = {
+       .ops            = &psc_dma_ops,
        .pcm_new        = &psc_dma_new,
        .pcm_free       = &psc_dma_free,
 };
-EXPORT_SYMBOL_GPL(mpc5200_audio_dma_platform);
 
-int mpc5200_audio_dma_create(struct platform_device *op)
+static int mpc5200_hpcd_probe(struct of_device *op,
+               const struct of_device_id *match)
 {
        phys_addr_t fifo;
        struct psc_dma *psc_dma;
@@ -475,7 +476,7 @@ int mpc5200_audio_dma_create(struct platform_device *op)
        dev_set_drvdata(&op->dev, psc_dma);
 
        /* Tell the ASoC OF helpers about it */
-       return snd_soc_register_platform(&mpc5200_audio_dma_platform);
+       return snd_soc_register_platform(&op->dev, &mpc5200_audio_dma_platform);
 out_irq:
        free_irq(psc_dma->irq, psc_dma);
        free_irq(psc_dma->capture.irq, &psc_dma->capture);
@@ -486,15 +487,14 @@ out_unmap:
        iounmap(regs);
        return ret;
 }
-EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create);
 
-int mpc5200_audio_dma_destroy(struct platform_device *op)
+static int mpc5200_hpcd_remove(struct of_device *op)
 {
        struct psc_dma *psc_dma = dev_get_drvdata(&op->dev);
 
        dev_dbg(&op->dev, "mpc5200_audio_dma_destroy()\n");
 
-       snd_soc_unregister_platform(&mpc5200_audio_dma_platform);
+       snd_soc_unregister_platform(&op->dev);
 
        bcom_gen_bd_rx_release(psc_dma->capture.bcom_task);
        bcom_gen_bd_tx_release(psc_dma->playback.bcom_task);
@@ -510,7 +510,35 @@ int mpc5200_audio_dma_destroy(struct platform_device *op)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(mpc5200_audio_dma_destroy);
+
+static struct of_device_id mpc5200_hpcd_match[] = {
+       {
+               .compatible = "fsl,mpc5200-pcm",
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(of, mpc5200_hpcd_match);
+
+static struct of_platform_driver mpc5200_hpcd_of_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "mpc5200-pcm-audio",
+       .match_table    = mpc5200_hpcd_match,
+       .probe          = mpc5200_hpcd_probe,
+       .remove         = mpc5200_hpcd_remove,
+};
+
+static int __init mpc5200_hpcd_init(void)
+{
+       return of_register_platform_driver(&mpc5200_hpcd_of_driver);
+}
+
+static void __exit mpc5200_hpcd_exit(void)
+{
+       of_unregister_platform_driver(&mpc5200_hpcd_of_driver);
+}
+
+module_init(mpc5200_hpcd_init);
+module_exit(mpc5200_hpcd_exit);
 
 MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
 MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver");
index ca99586f2ad993ecc286a0fe4e11a083aa9ee11e..a3c0cd5382fbbfdb74a52b93ceaef444e87f011f 100644 (file)
@@ -81,9 +81,4 @@ to_psc_dma_stream(struct snd_pcm_substream *substream, struct psc_dma *psc_dma)
        return &psc_dma->playback;
 }
 
-int mpc5200_audio_dma_create(struct platform_device *op);
-int mpc5200_audio_dma_destroy(struct platform_device *op);
-
-extern struct snd_soc_platform mpc5200_audio_dma_platform;
-
 #endif /* __SOUND_SOC_FSL_MPC5200_DMA_H__ */
index a9560235daeee3d4260d6066f9951bc89aa5ab4f..40acc8e2b1cac1a36ba8a94d11dccd9d10129e55 100644 (file)
@@ -143,7 +143,7 @@ static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *cpu_dai)
 {
-       struct psc_dma *psc_dma = cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
        struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
 
        dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
@@ -166,7 +166,7 @@ static int psc_ac97_hw_digital_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *cpu_dai)
 {
-       struct psc_dma *psc_dma = cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
 
        dev_dbg(psc_dma->dev, "%s(substream=%p)\n", __func__, substream);
 
@@ -181,8 +181,7 @@ static int psc_ac97_hw_digital_params(struct snd_pcm_substream *substream,
 static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
                                                        struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(dai);
        struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
 
        switch (cmd) {
@@ -207,10 +206,9 @@ static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
        return 0;
 }
 
-static int psc_ac97_probe(struct platform_device *pdev,
-                                       struct snd_soc_dai *cpu_dai)
+static int psc_ac97_probe(struct snd_soc_dai *cpu_dai)
 {
-       struct psc_dma *psc_dma = cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
        struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
 
        /* Go */
@@ -237,9 +235,8 @@ static struct snd_soc_dai_ops psc_ac97_digital_ops = {
        .hw_params      = psc_ac97_hw_digital_params,
 };
 
-struct snd_soc_dai psc_ac97_dai[] = {
+static struct snd_soc_dai_driver psc_ac97_dai[] = {
 {
-       .name   = "AC97",
        .ac97_control = 1,
        .probe  = psc_ac97_probe,
        .playback = {
@@ -257,7 +254,6 @@ struct snd_soc_dai psc_ac97_dai[] = {
        .ops = &psc_ac97_analog_ops,
 },
 {
-       .name   = "SPDIF",
        .ac97_control = 1,
        .playback = {
                .channels_min   = 1,
@@ -268,7 +264,6 @@ struct snd_soc_dai psc_ac97_dai[] = {
        },
        .ops = &psc_ac97_digital_ops,
 } };
-EXPORT_SYMBOL_GPL(psc_ac97_dai);
 
 
 
@@ -280,18 +275,11 @@ EXPORT_SYMBOL_GPL(psc_ac97_dai);
 static int __devinit psc_ac97_of_probe(struct platform_device *op,
                                      const struct of_device_id *match)
 {
-       int rc, i;
+       int rc;
        struct snd_ac97 ac97;
        struct mpc52xx_psc __iomem *regs;
 
-       rc = mpc5200_audio_dma_create(op);
-       if (rc != 0)
-               return rc;
-
-       for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
-               psc_ac97_dai[i].dev = &op->dev;
-
-       rc = snd_soc_register_dais(psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
+       rc = snd_soc_register_dais(&op->dev, psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
        if (rc != 0) {
                dev_err(&op->dev, "Failed to register DAI\n");
                return rc;
@@ -301,9 +289,6 @@ static int __devinit psc_ac97_of_probe(struct platform_device *op,
        regs = psc_dma->psc_regs;
        ac97.private_data = psc_dma;
 
-       for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
-               psc_ac97_dai[i].private_data = psc_dma;
-
        psc_dma->imr = 0;
        out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
 
@@ -319,7 +304,8 @@ static int __devinit psc_ac97_of_probe(struct platform_device *op,
 
 static int __devexit psc_ac97_of_remove(struct platform_device *op)
 {
-       return mpc5200_audio_dma_destroy(op);
+       snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_ac97_dai));
+       return 0;
 }
 
 /* Match table for of_platform binding */
index 4bc18c35c369f41fb5f7b582ed94432a8e241fbd..e881e784b27041ffe1ead098aa581e43ac18b8cd 100644 (file)
@@ -7,8 +7,6 @@
 #ifndef __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
 #define __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
 
-extern struct snd_soc_dai psc_ac97_dai[];
-
 #define MPC5200_AC97_NORMAL 0
 #define MPC5200_AC97_SPDIF 1
 
index 534f04cb15d7d1df602b4d8a3e65c962d93ad845..74ffed41340ff00c5d9ba97dc927059731b80673 100644 (file)
@@ -40,7 +40,7 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        u32 mode;
 
        dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
@@ -88,7 +88,7 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
 static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
                              int clk_id, unsigned int freq, int dir)
 {
-       struct psc_dma *psc_dma = cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
        dev_dbg(psc_dma->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n",
                                cpu_dai, dir);
        return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
@@ -107,7 +107,7 @@ static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
  */
 static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
 {
-       struct psc_dma *psc_dma = cpu_dai->private_data;
+       struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
        dev_dbg(psc_dma->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n",
                                cpu_dai, format);
        return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
@@ -129,8 +129,7 @@ static struct snd_soc_dai_ops psc_i2s_dai_ops = {
        .set_fmt        = psc_i2s_set_fmt,
 };
 
-struct snd_soc_dai psc_i2s_dai[] = {{
-       .name   = "I2S",
+static struct snd_soc_dai_driver psc_i2s_dai[] = {{
        .playback = {
                .channels_min = 2,
                .channels_max = 2,
@@ -145,7 +144,6 @@ struct snd_soc_dai psc_i2s_dai[] = {{
        },
        .ops = &psc_i2s_dai_ops,
 } };
-EXPORT_SYMBOL_GPL(psc_i2s_dai);
 
 /* ---------------------------------------------------------------------
  * OF platform bus binding code:
@@ -159,11 +157,7 @@ static int __devinit psc_i2s_of_probe(struct platform_device *op,
        struct psc_dma *psc_dma;
        struct mpc52xx_psc __iomem *regs;
 
-       rc = mpc5200_audio_dma_create(op);
-       if (rc != 0)
-               return rc;
-
-       rc = snd_soc_register_dais(psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
+       rc = snd_soc_register_dais(&op->dev, psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
        if (rc != 0) {
                pr_err("Failed to register DAI\n");
                return 0;
@@ -207,7 +201,8 @@ static int __devinit psc_i2s_of_probe(struct platform_device *op,
 
 static int __devexit psc_i2s_of_remove(struct platform_device *op)
 {
-       return mpc5200_audio_dma_destroy(op);
+       snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_i2s_dai));
+       return 0;
 }
 
 /* Match table for of_platform binding */
index 3b13b8d65262722d0bfbcc7e8e5d205a47485073..0d7dcf1e4863592c439a626b7fe449b56669f45d 100644 (file)
@@ -1,85 +1,97 @@
 /**
- * Freescale MPC8610HPCD ALSA SoC Fabric driver
+ * Freescale MPC8610HPCD ALSA SoC Machine driver
  *
  * Author: Timur Tabi <timur@freescale.com>
  *
- * Copyright 2007-2008 Freescale Semiconductor, Inc.  This file is licensed
- * under the terms of the GNU General Public License version 2.  This
- * program is licensed "as is" without any warranty of any kind, whether
- * express or implied.
+ * Copyright 2007-2010 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
  */
 
-#include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/of_device.h>
-#include <linux/of_platform.h>
+#include <linux/slab.h>
 #include <sound/soc.h>
-#include <asm/immap_86xx.h>
+#include <asm/fsl_guts.h>
 
-#include "../codecs/cs4270.h"
 #include "fsl_dma.h"
 #include "fsl_ssi.h"
 
+/* There's only one global utilities register */
+static phys_addr_t guts_phys;
+
+#define DAI_NAME_SIZE  32
+
 /**
- * mpc8610_hpcd_data: fabric-specific ASoC device data
+ * mpc8610_hpcd_data: machine-specific ASoC device data
  *
  * This structure contains data for a single sound platform device on an
  * MPC8610 HPCD.  Some of the data is taken from the device tree.
  */
 struct mpc8610_hpcd_data {
-       struct snd_soc_device sound_devdata;
-       struct snd_soc_dai_link dai;
-       struct snd_soc_card machine;
+       struct snd_soc_dai_link dai[2];
+       struct snd_soc_card card;
        unsigned int dai_format;
        unsigned int codec_clk_direction;
        unsigned int cpu_clk_direction;
        unsigned int clk_frequency;
-       struct ccsr_guts __iomem *guts;
-       struct ccsr_ssi __iomem *ssi;
-       unsigned int ssi_id;            /* 0 = SSI1, 1 = SSI2, etc */
-       unsigned int ssi_irq;
-       unsigned int dma_id;            /* 0 = DMA1, 1 = DMA2, etc */
-       unsigned int dma_irq[2];
-       struct ccsr_dma_channel __iomem *dma[2];
+       unsigned int ssi_id;            /* 0 = SSI1, 1 = SSI2, etc */
+       unsigned int dma_id[2];         /* 0 = DMA1, 1 = DMA2, etc */
        unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/
+       char codec_dai_name[DAI_NAME_SIZE];
+       char codec_name[DAI_NAME_SIZE];
+       char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
 };
 
 /**
  * mpc8610_hpcd_machine_probe: initialize the board
  *
- * This function is called when platform_device_add() is called.  It is used
- * to initialize the board-specific hardware.
+ * This function is used to initialize the board-specific hardware.
  *
  * Here we program the DMACR and PMUXCR registers.
  */
 static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device)
 {
+       struct snd_soc_card *card = platform_get_drvdata(sound_device);
        struct mpc8610_hpcd_data *machine_data =
-               sound_device->dev.platform_data;
+               container_of(card, struct mpc8610_hpcd_data, card);
+       struct ccsr_guts_86xx __iomem *guts;
 
-       /* Program the signal routing between the SSI and the DMA */
-       guts_set_dmacr(machine_data->guts, machine_data->dma_id,
-               machine_data->dma_channel_id[0], CCSR_GUTS_DMACR_DEV_SSI);
-       guts_set_dmacr(machine_data->guts, machine_data->dma_id,
-               machine_data->dma_channel_id[1], CCSR_GUTS_DMACR_DEV_SSI);
+       guts = ioremap(guts_phys, sizeof(struct ccsr_guts_86xx));
+       if (!guts) {
+               dev_err(card->dev, "could not map global utilities\n");
+               return -ENOMEM;
+       }
 
-       guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id,
-               machine_data->dma_channel_id[0], 0);
-       guts_set_pmuxcr_dma(machine_data->guts, machine_data->dma_id,
-               machine_data->dma_channel_id[1], 0);
+       /* Program the signal routing between the SSI and the DMA */
+       guts_set_dmacr(guts, machine_data->dma_id[0],
+                      machine_data->dma_channel_id[0],
+                      CCSR_GUTS_DMACR_DEV_SSI);
+       guts_set_dmacr(guts, machine_data->dma_id[1],
+                      machine_data->dma_channel_id[1],
+                      CCSR_GUTS_DMACR_DEV_SSI);
+
+       guts_set_pmuxcr_dma(guts, machine_data->dma_id[0],
+                           machine_data->dma_channel_id[0], 0);
+       guts_set_pmuxcr_dma(guts, machine_data->dma_id[1],
+                           machine_data->dma_channel_id[1], 0);
 
        switch (machine_data->ssi_id) {
        case 0:
-               clrsetbits_be32(&machine_data->guts->pmuxcr,
+               clrsetbits_be32(&guts->pmuxcr,
                        CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_SSI);
                break;
        case 1:
-               clrsetbits_be32(&machine_data->guts->pmuxcr,
+               clrsetbits_be32(&guts->pmuxcr,
                        CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_SSI);
                break;
        }
 
+       iounmap(guts);
+
        return 0;
 }
 
@@ -93,38 +105,15 @@ static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device)
 static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream)
 {
        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 mpc8610_hpcd_data *machine_data =
-               rtd->socdev->dev->platform_data;
+               container_of(rtd->card, struct mpc8610_hpcd_data, card);
+       struct device *dev = rtd->card->dev;
        int ret = 0;
 
-       /* Tell the CPU driver what the serial protocol is. */
-       ret = snd_soc_dai_set_fmt(cpu_dai, machine_data->dai_format);
-       if (ret < 0) {
-               dev_err(substream->pcm->card->dev,
-                       "could not set CPU driver audio format\n");
-               return ret;
-       }
-
        /* Tell the codec driver what the serial protocol is. */
-       ret = snd_soc_dai_set_fmt(codec_dai, machine_data->dai_format);
+       ret = snd_soc_dai_set_fmt(rtd->codec_dai, machine_data->dai_format);
        if (ret < 0) {
-               dev_err(substream->pcm->card->dev,
-                       "could not set codec driver audio format\n");
-               return ret;
-       }
-
-       /*
-        * Tell the CPU driver what the clock frequency is, and whether it's a
-        * slave or master.
-        */
-       ret = snd_soc_dai_set_sysclk(cpu_dai, 0,
-                                       machine_data->clk_frequency,
-                                       machine_data->cpu_clk_direction);
-       if (ret < 0) {
-               dev_err(substream->pcm->card->dev,
-                       "could not set CPU driver clock parameters\n");
+               dev_err(dev, "could not set codec driver audio format\n");
                return ret;
        }
 
@@ -132,12 +121,11 @@ static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream)
         * Tell the codec driver what the MCLK frequency is, and whether it's
         * a slave or master.
         */
-       ret = snd_soc_dai_set_sysclk(codec_dai, 0,
-                                       machine_data->clk_frequency,
-                                       machine_data->codec_clk_direction);
+       ret = snd_soc_dai_set_sysclk(rtd->codec_dai, 0,
+                                    machine_data->clk_frequency,
+                                    machine_data->codec_clk_direction);
        if (ret < 0) {
-               dev_err(substream->pcm->card->dev,
-                       "could not set codec driver clock params\n");
+               dev_err(dev, "could not set codec driver clock params\n");
                return ret;
        }
 
@@ -150,116 +138,255 @@ static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream)
  * This function is called to remove the sound device for one SSI.  We
  * de-program the DMACR and PMUXCR register.
  */
-int mpc8610_hpcd_machine_remove(struct platform_device *sound_device)
+static int mpc8610_hpcd_machine_remove(struct platform_device *sound_device)
 {
+       struct snd_soc_card *card = platform_get_drvdata(sound_device);
        struct mpc8610_hpcd_data *machine_data =
-               sound_device->dev.platform_data;
+               container_of(card, struct mpc8610_hpcd_data, card);
+       struct ccsr_guts_86xx __iomem *guts;
+
+       guts = ioremap(guts_phys, sizeof(struct ccsr_guts_86xx));
+       if (!guts) {
+               dev_err(card->dev, "could not map global utilities\n");
+               return -ENOMEM;
+       }
 
        /* Restore the signal routing */
 
-       guts_set_dmacr(machine_data->guts, machine_data->dma_id,
-               machine_data->dma_channel_id[0], 0);
-       guts_set_dmacr(machine_data->guts, machine_data->dma_id,
-               machine_data->dma_channel_id[1], 0);
+       guts_set_dmacr(guts, machine_data->dma_id[0],
+                      machine_data->dma_channel_id[0], 0);
+       guts_set_dmacr(guts, machine_data->dma_id[1],
+                      machine_data->dma_channel_id[1], 0);
 
        switch (machine_data->ssi_id) {
        case 0:
-               clrsetbits_be32(&machine_data->guts->pmuxcr,
+               clrsetbits_be32(&guts->pmuxcr,
                        CCSR_GUTS_PMUXCR_SSI1_MASK, CCSR_GUTS_PMUXCR_SSI1_LA);
                break;
        case 1:
-               clrsetbits_be32(&machine_data->guts->pmuxcr,
+               clrsetbits_be32(&guts->pmuxcr,
                        CCSR_GUTS_PMUXCR_SSI2_MASK, CCSR_GUTS_PMUXCR_SSI2_LA);
                break;
        }
 
+       iounmap(guts);
+
        return 0;
 }
 
 /**
- * mpc8610_hpcd_ops: ASoC fabric driver operations
+ * mpc8610_hpcd_ops: ASoC machine driver operations
  */
 static struct snd_soc_ops mpc8610_hpcd_ops = {
        .startup = mpc8610_hpcd_startup,
 };
 
 /**
- * mpc8610_hpcd_probe: OF probe function for the fabric driver
+ * get_node_by_phandle_name - get a node by its phandle name
  *
- * This function gets called when an SSI node is found in the device tree.
+ * This function takes a node, the name of a property in that node, and a
+ * compatible string.  Assuming the property is a phandle to another node,
+ * it returns that node, (optionally) if that node is compatible.
  *
- * Although this is a fabric driver, the SSI node is the "master" node with
- * respect to audio hardware connections.  Therefore, we create a new ASoC
- * device for each new SSI node that has a codec attached.
+ * If the property is not a phandle, or the node it points to is not compatible
+ * with the specific string, then NULL is returned.
+ */
+static struct device_node *get_node_by_phandle_name(struct device_node *np,
+                                              const char *name,
+                                              const char *compatible)
+{
+       const phandle *ph;
+       int len;
+
+       ph = of_get_property(np, name, &len);
+       if (!ph || (len != sizeof(phandle)))
+               return NULL;
+
+       np = of_find_node_by_phandle(*ph);
+       if (!np)
+               return NULL;
+
+       if (compatible && !of_device_is_compatible(np, compatible)) {
+               of_node_put(np);
+               return NULL;
+       }
+
+       return np;
+}
+
+/**
+ * get_parent_cell_index -- return the cell-index of the parent of a node
+ *
+ * Return the value of the cell-index property of the parent of the given
+ * node.  This is used for DMA channel nodes that need to know the DMA ID
+ * of the controller they are on.
+ */
+static int get_parent_cell_index(struct device_node *np)
+{
+       struct device_node *parent = of_get_parent(np);
+       const u32 *iprop;
+
+       if (!parent)
+               return -1;
+
+       iprop = of_get_property(parent, "cell-index", NULL);
+       of_node_put(parent);
+
+       if (!iprop)
+               return -1;
+
+       return *iprop;
+}
+
+/**
+ * codec_node_dev_name - determine the dev_name for a codec node
  *
- * FIXME: Currently, we only support one DMA controller, so if there are
- * multiple SSI nodes with codecs, only the first will be supported.
+ * This function determines the dev_name for an I2C node.  This is the name
+ * that would be returned by dev_name() if this device_node were part of a
+ * 'struct device'  It's ugly and hackish, but it works.
  *
- * FIXME: Even if we did support multiple DMA controllers, we have no
- * mechanism for assigning DMA controllers and channels to the individual
- * SSI devices.  We also probably aren't compatible with the generic Elo DMA
- * device driver.
+ * The dev_name for such devices include the bus number and I2C address. For
+ * example, "cs4270-codec.0-004f".
  */
-static int mpc8610_hpcd_probe(struct platform_device *ofdev,
-       const struct of_device_id *match)
+static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
 {
-       struct device_node *np = ofdev->dev.of_node;
-       struct device_node *codec_np = NULL;
-       struct device_node *guts_np = NULL;
-       struct device_node *dma_np = NULL;
-       struct device_node *dma_channel_np = NULL;
-       const phandle *codec_ph;
-       const char *sprop;
        const u32 *iprop;
+       int bus, addr;
+       char temp[DAI_NAME_SIZE];
+
+       of_modalias_node(np, temp, DAI_NAME_SIZE);
+
+       iprop = of_get_property(np, "reg", NULL);
+       if (!iprop)
+               return -EINVAL;
+
+       addr = *iprop;
+
+       bus = get_parent_cell_index(np);
+       if (bus < 0)
+               return bus;
+
+       snprintf(buf, len, "%s-codec.%u-%04x", temp, bus, addr);
+
+       return 0;
+}
+
+static int get_dma_channel(struct device_node *ssi_np,
+                          const char *compatible,
+                          struct snd_soc_dai_link *dai,
+                          unsigned int *dma_channel_id,
+                          unsigned int *dma_id)
+{
        struct resource res;
+       struct device_node *dma_channel_np;
+       const u32 *iprop;
+       int ret;
+
+       dma_channel_np = get_node_by_phandle_name(ssi_np, compatible,
+                                                 "fsl,ssi-dma-channel");
+       if (!dma_channel_np)
+               return -EINVAL;
+
+       /* Determine the dev_name for the device_node.  This code mimics the
+        * behavior of of_device_make_bus_id(). We need this because ASoC uses
+        * the dev_name() of the device to match the platform (DMA) device with
+        * the CPU (SSI) device.  It's all ugly and hackish, but it works (for
+        * now).
+        *
+        * dai->platform name should already point to an allocated buffer.
+        */
+       ret = of_address_to_resource(dma_channel_np, 0, &res);
+       if (ret)
+               return ret;
+       snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
+                (unsigned long long) res.start, dma_channel_np->name);
+
+       iprop = of_get_property(dma_channel_np, "cell-index", NULL);
+       if (!iprop) {
+               of_node_put(dma_channel_np);
+               return -EINVAL;
+       }
+
+       *dma_channel_id = *iprop;
+       *dma_id = get_parent_cell_index(dma_channel_np);
+       of_node_put(dma_channel_np);
+
+       return 0;
+}
+
+/**
+ * mpc8610_hpcd_probe: platform probe function for the machine driver
+ *
+ * Although this is a machine driver, the SSI node is the "master" node with
+ * respect to audio hardware connections.  Therefore, we create a new ASoC
+ * device for each new SSI node that has a codec attached.
+ */
+static int mpc8610_hpcd_probe(struct platform_device *pdev)
+{
+       struct device *dev = pdev->dev.parent;
+       /* ssi_pdev is the platform device for the SSI node that probed us */
+       struct platform_device *ssi_pdev =
+               container_of(dev, struct platform_device, dev);
+       struct device_node *np = ssi_pdev->dev.of_node;
+       struct device_node *codec_np = NULL;
        struct platform_device *sound_device = NULL;
        struct mpc8610_hpcd_data *machine_data;
-       struct fsl_ssi_info ssi_info;
-       struct fsl_dma_info dma_info;
        int ret = -ENODEV;
-       unsigned int playback_dma_channel;
-       unsigned int capture_dma_channel;
+       const char *sprop;
+       const u32 *iprop;
+
+       /* We are only interested in SSIs with a codec phandle in them,
+        * so let's make sure this SSI has one. The MPC8610 HPCD only
+        * knows about the CS4270 codec, so reject anything else.
+        */
+       codec_np = get_node_by_phandle_name(np, "codec-handle",
+                                           "cirrus,cs4270");
+       if (!codec_np) {
+               dev_err(dev, "invalid codec node\n");
+               return -EINVAL;
+       }
 
        machine_data = kzalloc(sizeof(struct mpc8610_hpcd_data), GFP_KERNEL);
        if (!machine_data)
                return -ENOMEM;
 
-       memset(&ssi_info, 0, sizeof(ssi_info));
-       memset(&dma_info, 0, sizeof(dma_info));
+       machine_data->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev);
+       machine_data->dai[0].ops = &mpc8610_hpcd_ops;
 
-       ssi_info.dev = &ofdev->dev;
-
-       /*
-        * We are only interested in SSIs with a codec phandle in them, so let's
-        * make sure this SSI has one.
-        */
-       codec_ph = of_get_property(np, "codec-handle", NULL);
-       if (!codec_ph)
+       /* Determine the codec name, it will be used as the codec DAI name */
+       ret = codec_node_dev_name(codec_np, machine_data->codec_name,
+                                 DAI_NAME_SIZE);
+       if (ret) {
+               dev_err(&pdev->dev, "invalid codec node %s\n",
+                       codec_np->full_name);
+               ret = -EINVAL;
                goto error;
+       }
+       machine_data->dai[0].codec_name = machine_data->codec_name;
 
-       codec_np = of_find_node_by_phandle(*codec_ph);
-       if (!codec_np)
-               goto error;
+       /* The DAI name from the codec (snd_soc_dai_driver.name) */
+       machine_data->dai[0].codec_dai_name = "cs4270-hifi";
 
-       /* The MPC8610 HPCD only knows about the CS4270 codec, so reject
-          anything else. */
-       if (!of_device_is_compatible(codec_np, "cirrus,cs4270"))
-               goto error;
+       /* We register two DAIs per SSI, one for playback and the other for
+        * capture.  Currently, we only support codecs that have one DAI for
+        * both playback and capture.
+        */
+       memcpy(&machine_data->dai[1], &machine_data->dai[0],
+              sizeof(struct snd_soc_dai_link));
 
        /* Get the device ID */
        iprop = of_get_property(np, "cell-index", NULL);
        if (!iprop) {
-               dev_err(&ofdev->dev, "cell-index property not found\n");
+               dev_err(&pdev->dev, "cell-index property not found\n");
                ret = -EINVAL;
                goto error;
        }
        machine_data->ssi_id = *iprop;
-       ssi_info.id = *iprop;
 
        /* Get the serial format and clock direction. */
        sprop = of_get_property(np, "fsl,mode", NULL);
        if (!sprop) {
-               dev_err(&ofdev->dev, "fsl,mode property not found\n");
+               dev_err(&pdev->dev, "fsl,mode property not found\n");
                ret = -EINVAL;
                goto error;
        }
@@ -269,15 +396,14 @@ static int mpc8610_hpcd_probe(struct platform_device *ofdev,
                machine_data->codec_clk_direction = SND_SOC_CLOCK_OUT;
                machine_data->cpu_clk_direction = SND_SOC_CLOCK_IN;
 
-               /*
-                * In i2s-slave mode, the codec has its own clock source, so we
+               /* In i2s-slave mode, the codec has its own clock source, so we
                 * need to get the frequency from the device tree and pass it to
                 * the codec driver.
                 */
                iprop = of_get_property(codec_np, "clock-frequency", NULL);
                if (!iprop || !*iprop) {
-                       dev_err(&ofdev->dev, "codec bus-frequency property "
-                               "is missing or invalid\n");
+                       dev_err(&pdev->dev, "codec bus-frequency "
+                               "property is missing or invalid\n");
                        ret = -EINVAL;
                        goto error;
                }
@@ -311,317 +437,153 @@ static int mpc8610_hpcd_probe(struct platform_device *ofdev,
                machine_data->codec_clk_direction = SND_SOC_CLOCK_IN;
                machine_data->cpu_clk_direction = SND_SOC_CLOCK_OUT;
        } else {
-               dev_err(&ofdev->dev,
-                       "unrecognized fsl,mode property \"%s\"\n", sprop);
+               dev_err(&pdev->dev,
+                       "unrecognized fsl,mode property '%s'\n", sprop);
                ret = -EINVAL;
                goto error;
        }
 
        if (!machine_data->clk_frequency) {
-               dev_err(&ofdev->dev, "unknown clock frequency\n");
+               dev_err(&pdev->dev, "unknown clock frequency\n");
                ret = -EINVAL;
                goto error;
        }
 
-       /* Read the SSI information from the device tree */
-       ret = of_address_to_resource(np, 0, &res);
+       /* Find the playback DMA channel to use. */
+       machine_data->dai[0].platform_name = machine_data->platform_name[0];
+       ret = get_dma_channel(np, "fsl,playback-dma", &machine_data->dai[0],
+                             &machine_data->dma_channel_id[0],
+                             &machine_data->dma_id[0]);
        if (ret) {
-               dev_err(&ofdev->dev, "could not obtain SSI address\n");
-               goto error;
-       }
-       if (!res.start) {
-               dev_err(&ofdev->dev, "invalid SSI address\n");
-               goto error;
-       }
-       ssi_info.ssi_phys = res.start;
-
-       machine_data->ssi = ioremap(ssi_info.ssi_phys, sizeof(struct ccsr_ssi));
-       if (!machine_data->ssi) {
-               dev_err(&ofdev->dev, "could not map SSI address %x\n",
-                       ssi_info.ssi_phys);
-               ret = -EINVAL;
-               goto error;
-       }
-       ssi_info.ssi = machine_data->ssi;
-
-
-       /* Get the IRQ of the SSI */
-       machine_data->ssi_irq = irq_of_parse_and_map(np, 0);
-       if (!machine_data->ssi_irq) {
-               dev_err(&ofdev->dev, "could not get SSI IRQ\n");
-               ret = -EINVAL;
-               goto error;
-       }
-       ssi_info.irq = machine_data->ssi_irq;
-
-       /* Do we want to use asynchronous mode? */
-       ssi_info.asynchronous =
-               of_find_property(np, "fsl,ssi-asynchronous", NULL) ? 1 : 0;
-       if (ssi_info.asynchronous)
-               dev_info(&ofdev->dev, "using asynchronous mode\n");
-
-       /* Map the global utilities registers. */
-       guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
-       if (!guts_np) {
-               dev_err(&ofdev->dev, "could not obtain address of GUTS\n");
-               ret = -EINVAL;
-               goto error;
-       }
-       machine_data->guts = of_iomap(guts_np, 0);
-       of_node_put(guts_np);
-       if (!machine_data->guts) {
-               dev_err(&ofdev->dev, "could not map GUTS\n");
-               ret = -EINVAL;
-               goto error;
-       }
-
-       /* Find the DMA channels to use.  Both SSIs need to use the same DMA
-        * controller, so let's use DMA#1.
-        */
-       for_each_compatible_node(dma_np, NULL, "fsl,mpc8610-dma") {
-               iprop = of_get_property(dma_np, "cell-index", NULL);
-               if (iprop && (*iprop == 0)) {
-                       of_node_put(dma_np);
-                       break;
-               }
-       }
-       if (!dma_np) {
-               dev_err(&ofdev->dev, "could not find DMA node\n");
-               ret = -EINVAL;
-               goto error;
-       }
-       machine_data->dma_id = *iprop;
-
-       /* SSI1 needs to use DMA Channels 0 and 1, and SSI2 needs to use DMA
-        * channels 2 and 3.  This is just how the MPC8610 is wired
-        * internally.
-        */
-       playback_dma_channel = (machine_data->ssi_id == 0) ? 0 : 2;
-       capture_dma_channel = (machine_data->ssi_id == 0) ? 1 : 3;
-
-       /*
-        * Find the DMA channels to use.
-        */
-       while ((dma_channel_np = of_get_next_child(dma_np, dma_channel_np))) {
-               iprop = of_get_property(dma_channel_np, "cell-index", NULL);
-               if (iprop && (*iprop == playback_dma_channel)) {
-                       /* dma_channel[0] and dma_irq[0] are for playback */
-                       dma_info.dma_channel[0] = of_iomap(dma_channel_np, 0);
-                       dma_info.dma_irq[0] =
-                               irq_of_parse_and_map(dma_channel_np, 0);
-                       machine_data->dma_channel_id[0] = *iprop;
-                       continue;
-               }
-               if (iprop && (*iprop == capture_dma_channel)) {
-                       /* dma_channel[1] and dma_irq[1] are for capture */
-                       dma_info.dma_channel[1] = of_iomap(dma_channel_np, 0);
-                       dma_info.dma_irq[1] =
-                               irq_of_parse_and_map(dma_channel_np, 0);
-                       machine_data->dma_channel_id[1] = *iprop;
-                       continue;
-               }
-       }
-       if (!dma_info.dma_channel[0] || !dma_info.dma_channel[1] ||
-           !dma_info.dma_irq[0] || !dma_info.dma_irq[1]) {
-               dev_err(&ofdev->dev, "could not find DMA channels\n");
-               ret = -EINVAL;
+               dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n");
                goto error;
        }
 
-       dma_info.ssi_stx_phys = ssi_info.ssi_phys +
-               offsetof(struct ccsr_ssi, stx0);
-       dma_info.ssi_srx_phys = ssi_info.ssi_phys +
-               offsetof(struct ccsr_ssi, srx0);
-
-       /* We have the DMA information, so tell the DMA driver what it is */
-       if (!fsl_dma_configure(&dma_info)) {
-               dev_err(&ofdev->dev, "could not instantiate DMA device\n");
-               ret = -EBUSY;
+       /* Find the capture DMA channel to use. */
+       machine_data->dai[1].platform_name = machine_data->platform_name[1];
+       ret = get_dma_channel(np, "fsl,capture-dma", &machine_data->dai[1],
+                             &machine_data->dma_channel_id[1],
+                             &machine_data->dma_id[1]);
+       if (ret) {
+               dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n");
                goto error;
        }
 
-       /*
-        * Initialize our DAI data structure.  We should probably get this
-        * information from the device tree.
-        */
-       machine_data->dai.name = "CS4270";
-       machine_data->dai.stream_name = "CS4270";
-
-       machine_data->dai.cpu_dai = fsl_ssi_create_dai(&ssi_info);
-       machine_data->dai.codec_dai = &cs4270_dai; /* The codec_dai we want */
-       machine_data->dai.ops = &mpc8610_hpcd_ops;
+       /* Initialize our DAI data structure.  */
+       machine_data->dai[0].stream_name = "playback";
+       machine_data->dai[1].stream_name = "capture";
+       machine_data->dai[0].name = machine_data->dai[0].stream_name;
+       machine_data->dai[1].name = machine_data->dai[1].stream_name;
 
-       machine_data->machine.probe = mpc8610_hpcd_machine_probe;
-       machine_data->machine.remove = mpc8610_hpcd_machine_remove;
-       machine_data->machine.name = "MPC8610 HPCD";
-       machine_data->machine.num_links = 1;
-       machine_data->machine.dai_link = &machine_data->dai;
+       machine_data->card.probe = mpc8610_hpcd_machine_probe;
+       machine_data->card.remove = mpc8610_hpcd_machine_remove;
+       machine_data->card.name = pdev->name; /* The platform driver name */
+       machine_data->card.num_links = 2;
+       machine_data->card.dai_link = machine_data->dai;
 
        /* Allocate a new audio platform device structure */
        sound_device = platform_device_alloc("soc-audio", -1);
        if (!sound_device) {
-               dev_err(&ofdev->dev, "platform device allocation failed\n");
+               dev_err(&pdev->dev, "platform device alloc failed\n");
                ret = -ENOMEM;
                goto error;
        }
 
-       machine_data->sound_devdata.card = &machine_data->machine;
-       machine_data->sound_devdata.codec_dev = &soc_codec_device_cs4270;
-       machine_data->machine.platform = &fsl_soc_platform;
-
-       sound_device->dev.platform_data = machine_data;
-
+       /* Associate the card data with the sound device */
+       platform_set_drvdata(sound_device, &machine_data->card);
 
-       /* Set the platform device and ASoC device to point to each other */
-       platform_set_drvdata(sound_device, &machine_data->sound_devdata);
-
-       machine_data->sound_devdata.dev = &sound_device->dev;
-
-
-       /* Tell ASoC to probe us.  This will call mpc8610_hpcd_machine.probe(),
-          if it exists. */
+       /* Register with ASoC */
        ret = platform_device_add(sound_device);
-
        if (ret) {
-               dev_err(&ofdev->dev, "platform device add failed\n");
+               dev_err(&pdev->dev, "platform device add failed\n");
                goto error;
        }
 
-       dev_set_drvdata(&ofdev->dev, sound_device);
+       of_node_put(codec_np);
 
        return 0;
 
 error:
        of_node_put(codec_np);
-       of_node_put(guts_np);
-       of_node_put(dma_np);
-       of_node_put(dma_channel_np);
 
        if (sound_device)
                platform_device_unregister(sound_device);
 
-       if (machine_data->dai.cpu_dai)
-               fsl_ssi_destroy_dai(machine_data->dai.cpu_dai);
-
-       if (ssi_info.ssi)
-               iounmap(ssi_info.ssi);
-
-       if (ssi_info.irq)
-               irq_dispose_mapping(ssi_info.irq);
-
-       if (dma_info.dma_channel[0])
-               iounmap(dma_info.dma_channel[0]);
-
-       if (dma_info.dma_channel[1])
-               iounmap(dma_info.dma_channel[1]);
-
-       if (dma_info.dma_irq[0])
-               irq_dispose_mapping(dma_info.dma_irq[0]);
-
-       if (dma_info.dma_irq[1])
-               irq_dispose_mapping(dma_info.dma_irq[1]);
-
-       if (machine_data->guts)
-               iounmap(machine_data->guts);
-
        kfree(machine_data);
 
        return ret;
 }
 
 /**
- * mpc8610_hpcd_remove: remove the OF device
+ * mpc8610_hpcd_remove: remove the platform device
  *
- * This function is called when the OF device is removed.
+ * This function is called when the platform device is removed.
  */
-static int mpc8610_hpcd_remove(struct platform_device *ofdev)
+static int __devexit mpc8610_hpcd_remove(struct platform_device *pdev)
 {
-       struct platform_device *sound_device = dev_get_drvdata(&ofdev->dev);
+       struct platform_device *sound_device = dev_get_drvdata(&pdev->dev);
+       struct snd_soc_card *card = platform_get_drvdata(sound_device);
        struct mpc8610_hpcd_data *machine_data =
-               sound_device->dev.platform_data;
+               container_of(card, struct mpc8610_hpcd_data, card);
 
        platform_device_unregister(sound_device);
 
-       if (machine_data->dai.cpu_dai)
-               fsl_ssi_destroy_dai(machine_data->dai.cpu_dai);
-
-       if (machine_data->ssi)
-               iounmap(machine_data->ssi);
-
-       if (machine_data->dma[0])
-               iounmap(machine_data->dma[0]);
-
-       if (machine_data->dma[1])
-               iounmap(machine_data->dma[1]);
-
-       if (machine_data->dma_irq[0])
-               irq_dispose_mapping(machine_data->dma_irq[0]);
-
-       if (machine_data->dma_irq[1])
-               irq_dispose_mapping(machine_data->dma_irq[1]);
-
-       if (machine_data->guts)
-               iounmap(machine_data->guts);
-
        kfree(machine_data);
        sound_device->dev.platform_data = NULL;
 
-       dev_set_drvdata(&ofdev->dev, NULL);
+       dev_set_drvdata(&pdev->dev, NULL);
 
        return 0;
 }
 
-static struct of_device_id mpc8610_hpcd_match[] = {
-       {
-               .compatible = "fsl,mpc8610-ssi",
-       },
-       {}
-};
-MODULE_DEVICE_TABLE(of, mpc8610_hpcd_match);
-
-static struct of_platform_driver mpc8610_hpcd_of_driver = {
+static struct platform_driver mpc8610_hpcd_driver = {
+       .probe = mpc8610_hpcd_probe,
+       .remove = __devexit_p(mpc8610_hpcd_remove),
        .driver = {
-               .name = "mpc8610_hpcd",
+               /* The name must match the 'model' property in the device tree,
+                * in lowercase letters.
+                */
+               .name = "snd-soc-mpc8610hpcd",
                .owner = THIS_MODULE,
-               .of_match_table = mpc8610_hpcd_match,
        },
-       .probe          = mpc8610_hpcd_probe,
-       .remove         = mpc8610_hpcd_remove,
 };
 
 /**
- * mpc8610_hpcd_init: fabric driver initialization.
+ * mpc8610_hpcd_init: machine driver initialization.
  *
  * This function is called when this module is loaded.
  */
 static int __init mpc8610_hpcd_init(void)
 {
-       int ret;
-
-       printk(KERN_INFO "Freescale MPC8610 HPCD ALSA SoC fabric driver\n");
+       struct device_node *guts_np;
+       struct resource res;
 
-       ret = of_register_platform_driver(&mpc8610_hpcd_of_driver);
+       pr_info("Freescale MPC8610 HPCD ALSA SoC machine driver\n");
 
-       if (ret)
-               printk(KERN_ERR
-                       "mpc8610-hpcd: failed to register platform driver\n");
+       /* Get the physical address of the global utilities registers */
+       guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
+       if (of_address_to_resource(guts_np, 0, &res)) {
+               pr_err("mpc8610-hpcd: missing/invalid global utilities node\n");
+               return -EINVAL;
+       }
+       guts_phys = res.start;
 
-       return ret;
+       return platform_driver_register(&mpc8610_hpcd_driver);
 }
 
 /**
- * mpc8610_hpcd_exit: fabric driver exit
+ * mpc8610_hpcd_exit: machine driver exit
  *
  * This function is called when this driver is unloaded.
  */
 static void __exit mpc8610_hpcd_exit(void)
 {
-       of_unregister_platform_driver(&mpc8610_hpcd_of_driver);
+       platform_driver_unregister(&mpc8610_hpcd_driver);
 }
 
 module_init(mpc8610_hpcd_init);
 module_exit(mpc8610_hpcd_exit);
 
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
-MODULE_DESCRIPTION("Freescale MPC8610 HPCD ALSA SoC fabric driver");
-MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Freescale MPC8610 HPCD ALSA SoC machine driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
new file mode 100644 (file)
index 0000000..63b9eaa
--- /dev/null
@@ -0,0 +1,591 @@
+/**
+ * Freescale P1022DS ALSA SoC Machine driver
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <asm/fsl_guts.h>
+
+#include "fsl_dma.h"
+#include "fsl_ssi.h"
+
+/* P1022-specific PMUXCR and DMUXCR bit definitions */
+
+#define CCSR_GUTS_PMUXCR_UART0_I2C1_MASK       0x0001c000
+#define CCSR_GUTS_PMUXCR_UART0_I2C1_UART0_SSI  0x00010000
+#define CCSR_GUTS_PMUXCR_UART0_I2C1_SSI                0x00018000
+
+#define CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK      0x00000c00
+#define CCSR_GUTS_PMUXCR_SSI_DMA_TDM_SSI       0x00000000
+
+#define CCSR_GUTS_DMUXCR_PAD   1       /* DMA controller/channel set to pad */
+#define CCSR_GUTS_DMUXCR_SSI   2       /* DMA controller/channel set to SSI */
+
+/*
+ * Set the DMACR register in the GUTS
+ *
+ * The DMACR register determines the source of initiated transfers for each
+ * channel on each DMA controller.  Rather than have a bunch of repetitive
+ * macros for the bit patterns, we just have a function that calculates
+ * them.
+ *
+ * guts: Pointer to GUTS structure
+ * co: The DMA controller (0 or 1)
+ * ch: The channel on the DMA controller (0, 1, 2, or 3)
+ * device: The device to set as the target (CCSR_GUTS_DMUXCR_xxx)
+ */
+static inline void guts_set_dmuxcr(struct ccsr_guts_85xx __iomem *guts,
+       unsigned int co, unsigned int ch, unsigned int device)
+{
+       unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch));
+
+       clrsetbits_be32(&guts->dmuxcr, 3 << shift, device << shift);
+}
+
+/* There's only one global utilities register */
+static phys_addr_t guts_phys;
+
+#define DAI_NAME_SIZE  32
+
+/**
+ * machine_data: machine-specific ASoC device data
+ *
+ * This structure contains data for a single sound platform device on an
+ * P1022 DS.  Some of the data is taken from the device tree.
+ */
+struct machine_data {
+       struct snd_soc_dai_link dai[2];
+       struct snd_soc_card card;
+       unsigned int dai_format;
+       unsigned int codec_clk_direction;
+       unsigned int cpu_clk_direction;
+       unsigned int clk_frequency;
+       unsigned int ssi_id;            /* 0 = SSI1, 1 = SSI2, etc */
+       unsigned int dma_id[2];         /* 0 = DMA1, 1 = DMA2, etc */
+       unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/
+       char codec_name[DAI_NAME_SIZE];
+       char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
+};
+
+/**
+ * p1022_ds_machine_probe: initialize the board
+ *
+ * This function is used to initialize the board-specific hardware.
+ *
+ * Here we program the DMACR and PMUXCR registers.
+ */
+static int p1022_ds_machine_probe(struct platform_device *sound_device)
+{
+       struct snd_soc_card *card = platform_get_drvdata(sound_device);
+       struct machine_data *mdata =
+               container_of(card, struct machine_data, card);
+       struct ccsr_guts_85xx __iomem *guts;
+
+       guts = ioremap(guts_phys, sizeof(struct ccsr_guts_85xx));
+       if (!guts) {
+               dev_err(card->dev, "could not map global utilities\n");
+               return -ENOMEM;
+       }
+
+       /* Enable SSI Tx signal */
+       clrsetbits_be32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_UART0_I2C1_MASK,
+                       CCSR_GUTS_PMUXCR_UART0_I2C1_UART0_SSI);
+
+       /* Enable SSI Rx signal */
+       clrsetbits_be32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK,
+                       CCSR_GUTS_PMUXCR_SSI_DMA_TDM_SSI);
+
+       /* Enable DMA Channel for SSI */
+       guts_set_dmuxcr(guts, mdata->dma_id[0], mdata->dma_channel_id[0],
+                       CCSR_GUTS_DMUXCR_SSI);
+
+       guts_set_dmuxcr(guts, mdata->dma_id[1], mdata->dma_channel_id[1],
+                       CCSR_GUTS_DMUXCR_SSI);
+
+       iounmap(guts);
+
+       return 0;
+}
+
+/**
+ * p1022_ds_startup: program the board with various hardware parameters
+ *
+ * This function takes board-specific information, like clock frequencies
+ * and serial data formats, and passes that information to the codec and
+ * transport drivers.
+ */
+static int p1022_ds_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct machine_data *mdata =
+               container_of(rtd->card, struct machine_data, card);
+       struct device *dev = rtd->card->dev;
+       int ret = 0;
+
+       /* Tell the codec driver what the serial protocol is. */
+       ret = snd_soc_dai_set_fmt(rtd->codec_dai, mdata->dai_format);
+       if (ret < 0) {
+               dev_err(dev, "could not set codec driver audio format\n");
+               return ret;
+       }
+
+       /*
+        * Tell the codec driver what the MCLK frequency is, and whether it's
+        * a slave or master.
+        */
+       ret = snd_soc_dai_set_sysclk(rtd->codec_dai, 0, mdata->clk_frequency,
+                                    mdata->codec_clk_direction);
+       if (ret < 0) {
+               dev_err(dev, "could not set codec driver clock params\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+/**
+ * p1022_ds_machine_remove: Remove the sound device
+ *
+ * This function is called to remove the sound device for one SSI.  We
+ * de-program the DMACR and PMUXCR register.
+ */
+static int p1022_ds_machine_remove(struct platform_device *sound_device)
+{
+       struct snd_soc_card *card = platform_get_drvdata(sound_device);
+       struct machine_data *mdata =
+               container_of(card, struct machine_data, card);
+       struct ccsr_guts_85xx __iomem *guts;
+
+       guts = ioremap(guts_phys, sizeof(struct ccsr_guts_85xx));
+       if (!guts) {
+               dev_err(card->dev, "could not map global utilities\n");
+               return -ENOMEM;
+       }
+
+       /* Restore the signal routing */
+       clrbits32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_UART0_I2C1_MASK);
+       clrbits32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK);
+       guts_set_dmuxcr(guts, mdata->dma_id[0], mdata->dma_channel_id[0], 0);
+       guts_set_dmuxcr(guts, mdata->dma_id[1], mdata->dma_channel_id[1], 0);
+
+       iounmap(guts);
+
+       return 0;
+}
+
+/**
+ * p1022_ds_ops: ASoC machine driver operations
+ */
+static struct snd_soc_ops p1022_ds_ops = {
+       .startup = p1022_ds_startup,
+};
+
+/**
+ * get_node_by_phandle_name - get a node by its phandle name
+ *
+ * This function takes a node, the name of a property in that node, and a
+ * compatible string.  Assuming the property is a phandle to another node,
+ * it returns that node, (optionally) if that node is compatible.
+ *
+ * If the property is not a phandle, or the node it points to is not compatible
+ * with the specific string, then NULL is returned.
+ */
+static struct device_node *get_node_by_phandle_name(struct device_node *np,
+       const char *name, const char *compatible)
+{
+       np = of_parse_phandle(np, name, 0);
+       if (!np)
+               return NULL;
+
+       if (!of_device_is_compatible(np, compatible)) {
+               of_node_put(np);
+               return NULL;
+       }
+
+       return np;
+}
+
+/**
+ * get_parent_cell_index -- return the cell-index of the parent of a node
+ *
+ * Return the value of the cell-index property of the parent of the given
+ * node.  This is used for DMA channel nodes that need to know the DMA ID
+ * of the controller they are on.
+ */
+static int get_parent_cell_index(struct device_node *np)
+{
+       struct device_node *parent = of_get_parent(np);
+       const u32 *iprop;
+       int ret = -1;
+
+       if (!parent)
+               return -1;
+
+       iprop = of_get_property(parent, "cell-index", NULL);
+       if (iprop)
+               ret = *iprop;
+
+       of_node_put(parent);
+
+       return ret;
+}
+
+/**
+ * codec_node_dev_name - determine the dev_name for a codec node
+ *
+ * This function determines the dev_name for an I2C node.  This is the name
+ * that would be returned by dev_name() if this device_node were part of a
+ * 'struct device'  It's ugly and hackish, but it works.
+ *
+ * The dev_name for such devices include the bus number and I2C address. For
+ * example, "cs4270-codec.0-004f".
+ */
+static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
+{
+       const u32 *iprop;
+       int bus, addr;
+       char temp[DAI_NAME_SIZE];
+
+       of_modalias_node(np, temp, DAI_NAME_SIZE);
+
+       iprop = of_get_property(np, "reg", NULL);
+       if (!iprop)
+               return -EINVAL;
+
+       addr = *iprop;
+
+       bus = get_parent_cell_index(np);
+       if (bus < 0)
+               return bus;
+
+       snprintf(buf, len, "%s-codec.%u-%04x", temp, bus, addr);
+
+       return 0;
+}
+
+static int get_dma_channel(struct device_node *ssi_np,
+                          const char *compatible,
+                          struct snd_soc_dai_link *dai,
+                          unsigned int *dma_channel_id,
+                          unsigned int *dma_id)
+{
+       struct resource res;
+       struct device_node *dma_channel_np;
+       const u32 *iprop;
+       int ret;
+
+       dma_channel_np = get_node_by_phandle_name(ssi_np, compatible,
+                                                 "fsl,ssi-dma-channel");
+       if (!dma_channel_np)
+               return -EINVAL;
+
+       /* Determine the dev_name for the device_node.  This code mimics the
+        * behavior of of_device_make_bus_id(). We need this because ASoC uses
+        * the dev_name() of the device to match the platform (DMA) device with
+        * the CPU (SSI) device.  It's all ugly and hackish, but it works (for
+        * now).
+        *
+        * dai->platform name should already point to an allocated buffer.
+        */
+       ret = of_address_to_resource(dma_channel_np, 0, &res);
+       if (ret)
+               return ret;
+       snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
+                (unsigned long long) res.start, dma_channel_np->name);
+
+       iprop = of_get_property(dma_channel_np, "cell-index", NULL);
+       if (!iprop) {
+               of_node_put(dma_channel_np);
+               return -EINVAL;
+       }
+
+       *dma_channel_id = *iprop;
+       *dma_id = get_parent_cell_index(dma_channel_np);
+       of_node_put(dma_channel_np);
+
+       return 0;
+}
+
+/**
+ * p1022_ds_probe: platform probe function for the machine driver
+ *
+ * Although this is a machine driver, the SSI node is the "master" node with
+ * respect to audio hardware connections.  Therefore, we create a new ASoC
+ * device for each new SSI node that has a codec attached.
+ */
+static int p1022_ds_probe(struct platform_device *pdev)
+{
+       struct device *dev = pdev->dev.parent;
+       /* ssi_pdev is the platform device for the SSI node that probed us */
+       struct platform_device *ssi_pdev =
+               container_of(dev, struct platform_device, dev);
+       struct device_node *np = ssi_pdev->dev.of_node;
+       struct device_node *codec_np = NULL;
+       struct platform_device *sound_device = NULL;
+       struct machine_data *mdata;
+       int ret = -ENODEV;
+       const char *sprop;
+       const u32 *iprop;
+
+       /* Find the codec node for this SSI. */
+       codec_np = of_parse_phandle(np, "codec-handle", 0);
+       if (!codec_np) {
+               dev_err(dev, "could not find codec node\n");
+               return -EINVAL;
+       }
+
+       mdata = kzalloc(sizeof(struct machine_data), GFP_KERNEL);
+       if (!mdata) {
+               ret = -ENOMEM;
+               goto error_put;
+       }
+
+       mdata->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev);
+       mdata->dai[0].ops = &p1022_ds_ops;
+
+       /* Determine the codec name, it will be used as the codec DAI name */
+       ret = codec_node_dev_name(codec_np, mdata->codec_name, DAI_NAME_SIZE);
+       if (ret) {
+               dev_err(&pdev->dev, "invalid codec node %s\n",
+                       codec_np->full_name);
+               ret = -EINVAL;
+               goto error;
+       }
+       mdata->dai[0].codec_name = mdata->codec_name;
+
+       /* We register two DAIs per SSI, one for playback and the other for
+        * capture.  We support codecs that have separate DAIs for both playback
+        * and capture.
+        */
+       memcpy(&mdata->dai[1], &mdata->dai[0], sizeof(struct snd_soc_dai_link));
+
+       /* The DAI names from the codec (snd_soc_dai_driver.name) */
+       mdata->dai[0].codec_dai_name = "wm8776-hifi-playback";
+       mdata->dai[1].codec_dai_name = "wm8776-hifi-capture";
+
+       /* Get the device ID */
+       iprop = of_get_property(np, "cell-index", NULL);
+       if (!iprop) {
+               dev_err(&pdev->dev, "cell-index property not found\n");
+               ret = -EINVAL;
+               goto error;
+       }
+       mdata->ssi_id = *iprop;
+
+       /* Get the serial format and clock direction. */
+       sprop = of_get_property(np, "fsl,mode", NULL);
+       if (!sprop) {
+               dev_err(&pdev->dev, "fsl,mode property not found\n");
+               ret = -EINVAL;
+               goto error;
+       }
+
+       if (strcasecmp(sprop, "i2s-slave") == 0) {
+               mdata->dai_format = SND_SOC_DAIFMT_I2S;
+               mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
+               mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
+
+               /* In i2s-slave mode, the codec has its own clock source, so we
+                * need to get the frequency from the device tree and pass it to
+                * the codec driver.
+                */
+               iprop = of_get_property(codec_np, "clock-frequency", NULL);
+               if (!iprop || !*iprop) {
+                       dev_err(&pdev->dev, "codec bus-frequency "
+                               "property is missing or invalid\n");
+                       ret = -EINVAL;
+                       goto error;
+               }
+               mdata->clk_frequency = *iprop;
+       } else if (strcasecmp(sprop, "i2s-master") == 0) {
+               mdata->dai_format = SND_SOC_DAIFMT_I2S;
+               mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
+               mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
+       } else if (strcasecmp(sprop, "lj-slave") == 0) {
+               mdata->dai_format = SND_SOC_DAIFMT_LEFT_J;
+               mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
+               mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
+       } else if (strcasecmp(sprop, "lj-master") == 0) {
+               mdata->dai_format = SND_SOC_DAIFMT_LEFT_J;
+               mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
+               mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
+       } else if (strcasecmp(sprop, "rj-slave") == 0) {
+               mdata->dai_format = SND_SOC_DAIFMT_RIGHT_J;
+               mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
+               mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
+       } else if (strcasecmp(sprop, "rj-master") == 0) {
+               mdata->dai_format = SND_SOC_DAIFMT_RIGHT_J;
+               mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
+               mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
+       } else if (strcasecmp(sprop, "ac97-slave") == 0) {
+               mdata->dai_format = SND_SOC_DAIFMT_AC97;
+               mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
+               mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
+       } else if (strcasecmp(sprop, "ac97-master") == 0) {
+               mdata->dai_format = SND_SOC_DAIFMT_AC97;
+               mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
+               mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
+       } else {
+               dev_err(&pdev->dev,
+                       "unrecognized fsl,mode property '%s'\n", sprop);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       if (!mdata->clk_frequency) {
+               dev_err(&pdev->dev, "unknown clock frequency\n");
+               ret = -EINVAL;
+               goto error;
+       }
+
+       /* Find the playback DMA channel to use. */
+       mdata->dai[0].platform_name = mdata->platform_name[0];
+       ret = get_dma_channel(np, "fsl,playback-dma", &mdata->dai[0],
+                             &mdata->dma_channel_id[0],
+                             &mdata->dma_id[0]);
+       if (ret) {
+               dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n");
+               goto error;
+       }
+
+       /* Find the capture DMA channel to use. */
+       mdata->dai[1].platform_name = mdata->platform_name[1];
+       ret = get_dma_channel(np, "fsl,capture-dma", &mdata->dai[1],
+                             &mdata->dma_channel_id[1],
+                             &mdata->dma_id[1]);
+       if (ret) {
+               dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n");
+               goto error;
+       }
+
+       /* Initialize our DAI data structure.  */
+       mdata->dai[0].stream_name = "playback";
+       mdata->dai[1].stream_name = "capture";
+       mdata->dai[0].name = mdata->dai[0].stream_name;
+       mdata->dai[1].name = mdata->dai[1].stream_name;
+
+       mdata->card.probe = p1022_ds_machine_probe;
+       mdata->card.remove = p1022_ds_machine_remove;
+       mdata->card.name = pdev->name; /* The platform driver name */
+       mdata->card.num_links = 2;
+       mdata->card.dai_link = mdata->dai;
+
+       /* Allocate a new audio platform device structure */
+       sound_device = platform_device_alloc("soc-audio", -1);
+       if (!sound_device) {
+               dev_err(&pdev->dev, "platform device alloc failed\n");
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       /* Associate the card data with the sound device */
+       platform_set_drvdata(sound_device, &mdata->card);
+
+       /* Register with ASoC */
+       ret = platform_device_add(sound_device);
+       if (ret) {
+               dev_err(&pdev->dev, "platform device add failed\n");
+               goto error;
+       }
+
+       of_node_put(codec_np);
+
+       return 0;
+
+error:
+       if (sound_device)
+               platform_device_unregister(sound_device);
+
+       kfree(mdata);
+error_put:
+       of_node_put(codec_np);
+       return ret;
+}
+
+/**
+ * p1022_ds_remove: remove the platform device
+ *
+ * This function is called when the platform device is removed.
+ */
+static int __devexit p1022_ds_remove(struct platform_device *pdev)
+{
+       struct platform_device *sound_device = dev_get_drvdata(&pdev->dev);
+       struct snd_soc_card *card = platform_get_drvdata(sound_device);
+       struct machine_data *mdata =
+               container_of(card, struct machine_data, card);
+
+       platform_device_unregister(sound_device);
+
+       kfree(mdata);
+       sound_device->dev.platform_data = NULL;
+
+       dev_set_drvdata(&pdev->dev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver p1022_ds_driver = {
+       .probe = p1022_ds_probe,
+       .remove = __devexit_p(p1022_ds_remove),
+       .driver = {
+               /* The name must match the 'model' property in the device tree,
+                * in lowercase letters, but only the part after that last
+                * comma.  This is because some model properties have a "fsl,"
+                * prefix.
+                */
+               .name = "snd-soc-p1022",
+               .owner = THIS_MODULE,
+       },
+};
+
+/**
+ * p1022_ds_init: machine driver initialization.
+ *
+ * This function is called when this module is loaded.
+ */
+static int __init p1022_ds_init(void)
+{
+       struct device_node *guts_np;
+       struct resource res;
+
+       pr_info("Freescale P1022 DS ALSA SoC machine driver\n");
+
+       /* Get the physical address of the global utilities registers */
+       guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
+       if (of_address_to_resource(guts_np, 0, &res)) {
+               pr_err("p1022-ds: missing/invalid global utilities node\n");
+               return -EINVAL;
+       }
+       guts_phys = res.start;
+       of_node_put(guts_np);
+
+       return platform_driver_register(&p1022_ds_driver);
+}
+
+/**
+ * p1022_ds_exit: machine driver exit
+ *
+ * This function is called when this driver is unloaded.
+ */
+static void __exit p1022_ds_exit(void)
+{
+       platform_driver_unregister(&p1022_ds_driver);
+}
+
+module_init(p1022_ds_init);
+module_exit(p1022_ds_exit);
+
+MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
+MODULE_DESCRIPTION("Freescale P1022 DS ALSA SoC machine driver");
+MODULE_LICENSE("GPL v2");
index 6644cba7cbf20e5a16e75ad459df1c2663afcc93..fe15bb26e48474e6f9aacb15961d62b59cea704d 100644 (file)
 
 #define DRV_NAME "pcm030-audio-fabric"
 
-static struct snd_soc_device device;
 static struct snd_soc_card card;
 
 static struct snd_soc_dai_link pcm030_fabric_dai[] = {
 {
        .name = "AC97",
        .stream_name = "AC97 Analog",
-       .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
-       .cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL],
+       .codec_dai_name = "wm9712-hifi",
+       .cpu_dai_name = "mpc5200-psc-ac97.0",
+       .platform_name = "mpc5200-pcm-audio",
+       .codec_name = "wm9712-codec",
 },
 {
        .name = "AC97",
        .stream_name = "AC97 IEC958",
-       .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
-       .cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF],
+       .codec_dai_name = "wm9712-aux",
+       .cpu_dai_name = "mpc5200-psc-ac97.1",
+       .platform_name = "mpc5200-pcm-audio",
+       ..codec_name = "wm9712-codec",
 },
 };
 
@@ -58,22 +61,18 @@ static __init int pcm030_fabric_init(void)
        if (!of_machine_is_compatible("phytec,pcm030"))
                return -ENODEV;
 
-       card.platform = &mpc5200_audio_dma_platform;
+
        card.name = "pcm030";
        card.dai_link = pcm030_fabric_dai;
        card.num_links = ARRAY_SIZE(pcm030_fabric_dai);
 
-       device.card = &card;
-       device.codec_dev = &soc_codec_dev_wm9712;
-
        pdev = platform_device_alloc("soc-audio", 1);
        if (!pdev) {
                pr_err("pcm030_fabric_init: platform_device_alloc() failed\n");
                return -ENODEV;
        }
 
-       platform_set_drvdata(pdev, &device);
-       device.dev = &pdev->dev;
+       platform_set_drvdata(pdev, &card);
 
        rc = platform_device_add(pdev);
        if (rc) {
diff --git a/sound/soc/fsl/soc-of-simple.c b/sound/soc/fsl/soc-of-simple.c
deleted file mode 100644 (file)
index 3bc13fd..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * OF helpers for ALSA SoC Layer
- *
- * Copyright (C) 2008, Secret Lab Technologies Ltd.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
-#include <linux/bitops.h>
-#include <linux/platform_device.h>
-#include <linux/of.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-of-simple.h>
-#include <sound/initval.h>
-
-MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("ALSA SoC OpenFirmware bindings");
-
-static DEFINE_MUTEX(of_snd_soc_mutex);
-static LIST_HEAD(of_snd_soc_device_list);
-static int of_snd_soc_next_index;
-
-struct of_snd_soc_device {
-       int id;
-       struct list_head list;
-       struct snd_soc_device device;
-       struct snd_soc_card card;
-       struct snd_soc_dai_link dai_link;
-       struct platform_device *pdev;
-       struct device_node *platform_node;
-       struct device_node *codec_node;
-};
-
-static struct snd_soc_ops of_snd_soc_ops = {
-};
-
-static struct of_snd_soc_device *
-of_snd_soc_get_device(struct device_node *codec_node)
-{
-       struct of_snd_soc_device *of_soc;
-
-       list_for_each_entry(of_soc, &of_snd_soc_device_list, list) {
-               if (of_soc->codec_node == codec_node)
-                       return of_soc;
-       }
-
-       of_soc = kzalloc(sizeof(struct of_snd_soc_device), GFP_KERNEL);
-       if (!of_soc)
-               return NULL;
-
-       /* Initialize the structure and add it to the global list */
-       of_soc->codec_node = codec_node;
-       of_soc->id = of_snd_soc_next_index++;
-       of_soc->card.dai_link = &of_soc->dai_link;
-       of_soc->card.num_links = 1;
-       of_soc->device.card = &of_soc->card;
-       of_soc->dai_link.ops = &of_snd_soc_ops;
-       list_add(&of_soc->list, &of_snd_soc_device_list);
-
-       return of_soc;
-}
-
-static void of_snd_soc_register_device(struct of_snd_soc_device *of_soc)
-{
-       struct platform_device *pdev;
-       int rc;
-
-       /* Only register the device if both the codec and platform have
-        * been registered */
-       if ((!of_soc->device.codec_data) || (!of_soc->platform_node))
-               return;
-
-       pr_info("platform<-->codec match achieved; registering machine\n");
-
-       pdev = platform_device_alloc("soc-audio", of_soc->id);
-       if (!pdev) {
-               pr_err("of_soc: platform_device_alloc() failed\n");
-               return;
-       }
-
-       pdev->dev.platform_data = of_soc;
-       platform_set_drvdata(pdev, &of_soc->device);
-       of_soc->device.dev = &pdev->dev;
-
-       /* The ASoC device is complete; register it */
-       rc = platform_device_add(pdev);
-       if (rc) {
-               pr_err("of_soc: platform_device_add() failed\n");
-               return;
-       }
-
-}
-
-int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
-                             void *codec_data, struct snd_soc_dai *dai,
-                             struct device_node *node)
-{
-       struct of_snd_soc_device *of_soc;
-       int rc = 0;
-
-       pr_info("registering ASoC codec driver: %s\n", node->full_name);
-
-       mutex_lock(&of_snd_soc_mutex);
-       of_soc = of_snd_soc_get_device(node);
-       if (!of_soc) {
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       /* Store the codec data */
-       of_soc->device.codec_data = codec_data;
-       of_soc->device.codec_dev = codec_dev;
-       of_soc->dai_link.name = (char *)node->name;
-       of_soc->dai_link.stream_name = (char *)node->name;
-       of_soc->dai_link.codec_dai = dai;
-
-       /* Now try to register the SoC device */
-       of_snd_soc_register_device(of_soc);
-
- out:
-       mutex_unlock(&of_snd_soc_mutex);
-       return rc;
-}
-EXPORT_SYMBOL_GPL(of_snd_soc_register_codec);
-
-int of_snd_soc_register_platform(struct snd_soc_platform *platform,
-                                struct device_node *node,
-                                struct snd_soc_dai *cpu_dai)
-{
-       struct of_snd_soc_device *of_soc;
-       struct device_node *codec_node;
-       const phandle *handle;
-       int len, rc = 0;
-
-       pr_info("registering ASoC platform driver: %s\n", node->full_name);
-
-       handle = of_get_property(node, "codec-handle", &len);
-       if (!handle || len < sizeof(handle))
-               return -ENODEV;
-       codec_node = of_find_node_by_phandle(*handle);
-       if (!codec_node)
-               return -ENODEV;
-       pr_info("looking for codec: %s\n", codec_node->full_name);
-
-       mutex_lock(&of_snd_soc_mutex);
-       of_soc = of_snd_soc_get_device(codec_node);
-       if (!of_soc) {
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       of_soc->platform_node = node;
-       of_soc->dai_link.cpu_dai = cpu_dai;
-       of_soc->card.platform = platform;
-       of_soc->card.name = of_soc->dai_link.cpu_dai->name;
-
-       /* Now try to register the SoC device */
-       of_snd_soc_register_device(of_soc);
-
- out:
-       mutex_unlock(&of_snd_soc_mutex);
-       return rc;
-}
-EXPORT_SYMBOL_GPL(of_snd_soc_register_platform);
index 687c76fc08397a39779bfe4eded6f4e67ea2abcb..642270a635ea544957c211cae3d0f69e030876ad 100644 (file)
@@ -8,12 +8,24 @@ menuconfig SND_IMX_SOC
          Say Y or M if you want to add support for codecs attached to
          the i.MX SSI interface.
 
+
 if SND_IMX_SOC
 
+config SND_MXC_SOC_SSI
+       tristate
+
+config SND_MXC_SOC_FIQ
+       tristate
+
+config SND_MXC_SOC_MX2
+       tristate
+
 config SND_MXC_SOC_WM1133_EV1
        tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted"
        depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
        select SND_SOC_WM8350
+       select SND_MXC_SOC_SSI
+       select SND_MXC_SOC_FIQ
        help
          Enable support for audio on the i.MX31ADS with the WM1133-EV1
          PMIC board with WM8835x fitted.
@@ -22,6 +34,8 @@ config SND_SOC_PHYCORE_AC97
        tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
        depends on MACH_PCM043 || MACH_PCA100
        select SND_SOC_WM9712
+       select SND_MXC_SOC_SSI
+       select SND_MXC_SOC_FIQ
        help
          Say Y if you want to add support for SoC audio on Phytec phyCORE
          and phyCARD boards in AC97 mode
@@ -32,6 +46,8 @@ config SND_SOC_EUKREA_TLV320
                || MACH_EUKREA_MBIMXSD25_BASEBOARD \
                || MACH_EUKREA_MBIMXSD35_BASEBOARD
        select SND_SOC_TLV320AIC23
+       select SND_MXC_SOC_SSI
+       select SND_MXC_SOC_FIQ
        help
          Enable I2S based access to the TLV320AIC23B codec attached
          to the SSI interface
index 7bc57baf2b0e9e68aaff7b27564fccc6dbd27113..b67fc02a4eccd781bda485a02e8de2eca26816b7 100644 (file)
@@ -1,11 +1,11 @@
 # i.MX Platform Support
-snd-soc-imx-objs := imx-ssi.o imx-pcm-fiq.o
-
-ifdef CONFIG_MACH_MX27
-snd-soc-imx-objs += imx-pcm-dma-mx2.o
-endif
+snd-soc-imx-objs := imx-ssi.o
+snd-soc-imx-fiq-objs := imx-pcm-fiq.o
+snd-soc-imx-mx2-objs := imx-pcm-dma-mx2.o
 
 obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o
+obj-$(CONFIG_SND_MXC_SOC_FIQ) += snd-soc-imx-fiq.o
+obj-$(CONFIG_SND_MXC_SOC_MX2) += snd-soc-imx-mx2.o
 
 # i.MX Machine Support
 snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
index f15dfbdc47ee5cd838d873d0b8b1add1073eb6a4..b59675257ce55b61b6410f04008f12d6d705e37d 100644 (file)
@@ -79,22 +79,19 @@ static struct snd_soc_ops eukrea_tlv320_snd_ops = {
 static struct snd_soc_dai_link eukrea_tlv320_dai = {
        .name           = "tlv320aic23",
        .stream_name    = "TLV320AIC23",
-       .codec_dai      = &tlv320aic23_dai,
+       .codec_dai      = "tlv320aic23-hifi",
+       .platform_name  = "imx-pcm-audio.0",
+       .codec_name     = "tlv320aic23-codec.0-001a",
+       .cpu_dai = "imx-ssi.0",
        .ops            = &eukrea_tlv320_snd_ops,
 };
 
 static struct snd_soc_card eukrea_tlv320 = {
        .name           = "cpuimx-audio",
-       .platform       = &imx_soc_platform,
        .dai_link       = &eukrea_tlv320_dai,
        .num_links      = 1,
 };
 
-static struct snd_soc_device eukrea_tlv320_snd_devdata = {
-       .card           = &eukrea_tlv320,
-       .codec_dev      = &soc_codec_dev_tlv320aic23,
-};
-
 static struct platform_device *eukrea_tlv320_snd_device;
 
 static int __init eukrea_tlv320_init(void)
@@ -110,10 +107,7 @@ static int __init eukrea_tlv320_init(void)
        if (!eukrea_tlv320_snd_device)
                return -ENOMEM;
 
-       eukrea_tlv320_dai.cpu_dai = &imx_ssi_pcm_dai[0];
-
-       platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320_snd_devdata);
-       eukrea_tlv320_snd_devdata.dev = &eukrea_tlv320_snd_device->dev;
+       platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320);
        ret = platform_device_add(eukrea_tlv320_snd_device);
 
        if (ret) {
index 0a595da4811d343a389709e5656dceb550fbd2dd..fd493ee1428e2a977ac96ba7f7acc3a88d226025 100644 (file)
@@ -103,7 +103,7 @@ static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream)
        struct imx_pcm_runtime_data *iprtd = runtime->private_data;
        int ret;
 
-       dma_params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+       dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        iprtd->dma = imx_dma_request_by_prio(DRV_NAME, DMA_PRIO_HIGH);
        if (iprtd->dma < 0) {
@@ -213,7 +213,7 @@ static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream)
        struct imx_pcm_runtime_data *iprtd = runtime->private_data;
        int err;
 
-       dma_params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+       dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        iprtd->substream = substream;
        iprtd->buf = (unsigned int *)substream->dma_buffer.area;
@@ -318,19 +318,42 @@ static struct snd_pcm_ops imx_pcm_ops = {
        .mmap           = snd_imx_pcm_mmap,
 };
 
-static struct snd_soc_platform imx_soc_platform_dma = {
-       .name           = "imx-audio",
-       .pcm_ops        = &imx_pcm_ops,
+static struct snd_soc_platform_driver imx_soc_platform_mx2 = {
+       .ops            = &imx_pcm_ops,
        .pcm_new        = imx_pcm_new,
        .pcm_free       = imx_pcm_free,
 };
 
-struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev,
-               struct imx_ssi *ssi)
+static int __devinit imx_soc_platform_probe(struct platform_device *pdev)
 {
-       ssi->dma_params_tx.burstsize = DMA_TXFIFO_BURST;
-       ssi->dma_params_rx.burstsize = DMA_RXFIFO_BURST;
+       return snd_soc_register_platform(&pdev->dev, &imx_soc_platform_mx2);
+}
+
+static int __devexit imx_soc_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver imx_pcm_driver = {
+       .driver = {
+                       .name = "imx-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
 
-       return &imx_soc_platform_dma;
+       .probe = imx_soc_platform_probe,
+       .remove = __devexit_p(imx_soc_platform_remove),
+};
+
+static int __init snd_imx_pcm_init(void)
+{
+       return platform_driver_register(&imx_pcm_driver);
+}
+module_init(snd_imx_pcm_init);
+
+static void __exit snd_imx_pcm_exit(void)
+{
+       platform_driver_unregister(&imx_pcm_driver);
 }
+module_exit(snd_imx_pcm_exit);
 
index b2bf27282cd2d10189419236f5463c97c95354b7..413b78da248ff215db592d888e01f68fc40feffb 100644 (file)
@@ -236,6 +236,8 @@ static struct snd_pcm_ops imx_pcm_ops = {
        .mmap           = snd_imx_pcm_mmap,
 };
 
+static int ssi_irq = 0;
+
 static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai,
        struct snd_pcm *pcm)
 {
@@ -245,7 +247,7 @@ static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai,
        if (ret)
                return ret;
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                struct snd_pcm_substream *substream =
                        pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
                struct snd_dma_buffer *buf = &substream->dma_buffer;
@@ -253,7 +255,7 @@ static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai,
                imx_ssi_fiq_tx_buffer = (unsigned long)buf->area;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                struct snd_pcm_substream *substream =
                        pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
                struct snd_dma_buffer *buf = &substream->dma_buffer;
@@ -267,24 +269,32 @@ static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai,
        return 0;
 }
 
-static struct snd_soc_platform imx_soc_platform_fiq = {
-       .pcm_ops        = &imx_pcm_ops,
+static void imx_pcm_fiq_free(struct snd_pcm *pcm)
+{
+       mxc_set_irq_fiq(ssi_irq, 0);
+       release_fiq(&fh);
+       imx_pcm_free(pcm);
+}
+
+static struct snd_soc_platform_driver imx_soc_platform_fiq = {
+       .ops            = &imx_pcm_ops,
        .pcm_new        = imx_pcm_fiq_new,
-       .pcm_free       = imx_pcm_free,
+       .pcm_free       = imx_pcm_fiq_free,
 };
 
-struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev,
-               struct imx_ssi *ssi)
+static int __devinit imx_soc_platform_probe(struct platform_device *pdev)
 {
-       int ret = 0;
+       struct imx_ssi *ssi = platform_get_drvdata(pdev);
+       int ret;
 
        ret = claim_fiq(&fh);
        if (ret) {
                dev_err(&pdev->dev, "failed to claim fiq: %d", ret);
-               return ERR_PTR(ret);
+               return ret;
        }
 
        mxc_set_irq_fiq(ssi->irq, 1);
+       ssi_irq = ssi->irq;
 
        imx_pcm_fiq = ssi->irq;
 
@@ -293,13 +303,43 @@ struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev,
        ssi->dma_params_tx.burstsize = 4;
        ssi->dma_params_rx.burstsize = 6;
 
-       return &imx_soc_platform_fiq;
+       ret = snd_soc_register_platform(&pdev->dev, &imx_soc_platform_fiq);
+       if (ret)
+               goto failed_register;
+
+       return 0;
+
+failed_register:
+       mxc_set_irq_fiq(ssi_irq, 0);
+       release_fiq(&fh);
+
+       return ret;
 }
 
-void imx_ssi_fiq_exit(struct platform_device *pdev,
-               struct imx_ssi *ssi)
+static int __devexit imx_soc_platform_remove(struct platform_device *pdev)
 {
-       mxc_set_irq_fiq(ssi->irq, 0);
-       release_fiq(&fh);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
 }
 
+static struct platform_driver imx_pcm_driver = {
+       .driver = {
+                       .name = "imx-fiq-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = imx_soc_platform_probe,
+       .remove = __devexit_p(imx_soc_platform_remove),
+};
+
+static int __init snd_imx_pcm_init(void)
+{
+       return platform_driver_register(&imx_pcm_driver);
+}
+module_init(snd_imx_pcm_init);
+
+static void __exit snd_imx_pcm_exit(void)
+{
+       platform_driver_unregister(&imx_pcm_driver);
+}
+module_exit(snd_imx_pcm_exit);
index c81da05a4f11ee0ada1ad170dea17aea207eb969..d4bd345b0a8d4ba891222f5752fe6eca56aec7b4 100644 (file)
@@ -61,7 +61,7 @@
 static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
        unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
 {
-       struct imx_ssi *ssi = cpu_dai->private_data;
+       struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
        u32 sccr;
 
        sccr = readl(ssi->base + SSI_STCCR);
@@ -86,7 +86,7 @@ static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
  */
 static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 {
-       struct imx_ssi *ssi = cpu_dai->private_data;
+       struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
        u32 strcr = 0, scr;
 
        scr = readl(ssi->base + SSI_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET);
@@ -164,7 +164,7 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
 static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                                  int clk_id, unsigned int freq, int dir)
 {
-       struct imx_ssi *ssi = cpu_dai->private_data;
+       struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
        u32 scr;
 
        scr = readl(ssi->base + SSI_SCR);
@@ -192,7 +192,7 @@ static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
 static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
                                  int div_id, int div)
 {
-       struct imx_ssi *ssi = cpu_dai->private_data;
+       struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
        u32 stccr, srccr;
 
        stccr = readl(ssi->base + SSI_STCCR);
@@ -241,7 +241,7 @@ static int imx_ssi_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *params,
                             struct snd_soc_dai *cpu_dai)
 {
-       struct imx_ssi *ssi = cpu_dai->private_data;
+       struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
        struct imx_pcm_dma_params *dma_data;
        u32 reg, sccr;
 
@@ -282,9 +282,7 @@ static int imx_ssi_hw_params(struct snd_pcm_substream *substream,
 static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
                struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct imx_ssi *ssi = cpu_dai->private_data;
+       struct imx_ssi *ssi = snd_soc_dai_get_drvdata(dai);
        unsigned int sier_bits, sier;
        unsigned int scr;
 
@@ -353,22 +351,6 @@ static struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
        .trigger        = imx_ssi_trigger,
 };
 
-static struct snd_soc_dai imx_ssi_dai = {
-       .playback = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_96000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .capture = {
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_96000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       },
-       .ops = &imx_ssi_pcm_dai_ops,
-};
-
 int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
                struct vm_area_struct *vma)
 {
@@ -384,6 +366,7 @@ int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
                        runtime->dma_bytes);
        return ret;
 }
+EXPORT_SYMBOL_GPL(snd_imx_pcm_mmap);
 
 static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 {
@@ -415,14 +398,14 @@ int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
                card->dev->dma_mask = &imx_pcm_dmamask;
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = imx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = imx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -432,6 +415,7 @@ int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
 out:
        return ret;
 }
+EXPORT_SYMBOL_GPL(imx_pcm_new);
 
 void imx_pcm_free(struct snd_pcm *pcm)
 {
@@ -453,14 +437,40 @@ void imx_pcm_free(struct snd_pcm *pcm)
                buf->area = NULL;
        }
 }
+EXPORT_SYMBOL_GPL(imx_pcm_free);
 
-struct snd_soc_platform imx_soc_platform = {
-       .name           = "imx-audio",
+static struct snd_soc_dai_driver imx_ssi_dai = {
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .ops = &imx_ssi_pcm_dai_ops,
 };
-EXPORT_SYMBOL_GPL(imx_soc_platform);
 
-static struct snd_soc_dai imx_ac97_dai = {
-       .name = "AC97",
+static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
+{
+       struct imx_ssi *ssi = dev_get_drvdata(dai->dev);
+       uint32_t val;
+
+       snd_soc_dai_set_drvdata(dai, ssi);
+
+       val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
+               SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
+       writel(val, ssi->base + SSI_SFCSR);
+
+       return 0;
+}
+
+static struct snd_soc_dai_driver imx_ac97_dai = {
+       .probe = imx_ssi_dai_probe,
        .ac97_control = 1,
        .playback = {
                .stream_name = "AC97 Playback",
@@ -580,25 +590,18 @@ struct snd_ac97_bus_ops soc_ac97_ops = {
 };
 EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
-struct snd_soc_dai imx_ssi_pcm_dai[2];
-EXPORT_SYMBOL_GPL(imx_ssi_pcm_dai);
-
 static int imx_ssi_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct imx_ssi *ssi;
        struct imx_ssi_platform_data *pdata = pdev->dev.platform_data;
-       struct snd_soc_platform *platform;
        int ret = 0;
-       unsigned int val;
-       struct snd_soc_dai *dai = &imx_ssi_pcm_dai[pdev->id];
-
-       if (dai->id >= ARRAY_SIZE(imx_ssi_pcm_dai))
-               return -EINVAL;
+       struct snd_soc_dai_driver *dai;
 
        ssi = kzalloc(sizeof(*ssi), GFP_KERNEL);
        if (!ssi)
                return -ENOMEM;
+       dev_set_drvdata(&pdev->dev, ssi);
 
        if (pdata) {
                ssi->ac97_reset = pdata->ac97_reset;
@@ -643,9 +646,9 @@ static int imx_ssi_probe(struct platform_device *pdev)
                }
                ac97_ssi = ssi;
                setup_channel_to_ac97(ssi);
-               memcpy(dai, &imx_ac97_dai, sizeof(imx_ac97_dai));
+               dai = &imx_ac97_dai;
        } else
-               memcpy(dai, &imx_ssi_dai, sizeof(imx_ssi_dai));
+               dai = &imx_ssi_dai;
 
        writel(0x0, ssi->base + SSI_SIER);
 
@@ -660,37 +663,36 @@ static int imx_ssi_probe(struct platform_device *pdev)
        if (res)
                ssi->dma_params_rx.dma = res->start;
 
-       dai->id = pdev->id;
-       dai->dev = &pdev->dev;
-       dai->name = kasprintf(GFP_KERNEL, "imx-ssi.%d", pdev->id);
-       dai->private_data = ssi;
-
        if ((cpu_is_mx27() || cpu_is_mx21()) &&
                        !(ssi->flags & IMX_SSI_USE_AC97) &&
                        (ssi->flags & IMX_SSI_DMA)) {
                ssi->flags |= IMX_SSI_DMA;
-               platform = imx_ssi_dma_mx2_init(pdev, ssi);
-       } else
-               platform = imx_ssi_fiq_init(pdev, ssi);
-
-       imx_soc_platform.pcm_ops = platform->pcm_ops;
-       imx_soc_platform.pcm_new = platform->pcm_new;
-       imx_soc_platform.pcm_free = platform->pcm_free;
+       }
 
-       val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
-               SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
-       writel(val, ssi->base + SSI_SFCSR);
+       platform_set_drvdata(pdev, ssi);
 
-       ret = snd_soc_register_dai(dai);
+       ret = snd_soc_register_dai(&pdev->dev, dai);
        if (ret) {
                dev_err(&pdev->dev, "register DAI failed\n");
                goto failed_register;
        }
 
-       platform_set_drvdata(pdev, ssi);
+       ssi->soc_platform_pdev = platform_device_alloc("imx-fiq-pcm-audio", pdev->id);
+       if (!ssi->soc_platform_pdev)
+               goto failed_pdev_alloc;
+       platform_set_drvdata(ssi->soc_platform_pdev, ssi);
+       ret = platform_device_add(ssi->soc_platform_pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to add platform device\n");
+               goto failed_pdev_add;
+       }
 
        return 0;
 
+failed_pdev_add:
+       platform_device_put(ssi->soc_platform_pdev);
+failed_pdev_alloc:
+       snd_soc_unregister_dai(&pdev->dev);
 failed_register:
 failed_ac97:
        iounmap(ssi->base);
@@ -709,16 +711,15 @@ static int __devexit imx_ssi_remove(struct platform_device *pdev)
 {
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        struct imx_ssi *ssi = platform_get_drvdata(pdev);
-       struct snd_soc_dai *dai = &imx_ssi_pcm_dai[pdev->id];
 
-       snd_soc_unregister_dai(dai);
+       platform_device_del(ssi->soc_platform_pdev);
+       platform_device_put(ssi->soc_platform_pdev);
+
+       snd_soc_unregister_dai(&pdev->dev);
 
        if (ssi->flags & IMX_SSI_USE_AC97)
                ac97_ssi = NULL;
 
-       if (!(ssi->flags & IMX_SSI_DMA))
-               imx_ssi_fiq_exit(pdev, ssi);
-
        iounmap(ssi->base);
        release_mem_region(res->start, resource_size(res));
        clk_disable(ssi->clk);
@@ -733,34 +734,19 @@ static struct platform_driver imx_ssi_driver = {
        .remove = __devexit_p(imx_ssi_remove),
 
        .driver = {
-               .name = DRV_NAME,
+               .name = "imx-ssi",
                .owner = THIS_MODULE,
        },
 };
 
 static int __init imx_ssi_init(void)
 {
-       int ret;
-
-       ret = snd_soc_register_platform(&imx_soc_platform);
-       if (ret) {
-               pr_err("failed to register soc platform: %d\n", ret);
-               return ret;
-       }
-
-       ret = platform_driver_register(&imx_ssi_driver);
-       if (ret) {
-               snd_soc_unregister_platform(&imx_soc_platform);
-               return ret;
-       }
-
-       return 0;
+       return platform_driver_register(&imx_ssi_driver);
 }
 
 static void __exit imx_ssi_exit(void)
 {
        platform_driver_unregister(&imx_ssi_driver);
-       snd_soc_unregister_platform(&imx_soc_platform);
 }
 
 module_init(imx_ssi_init);
index 55f26ebcd8c2531fc9267e12a6e590ac50199ad7..53b780d9b2b09375fdc7bf7f60a81af5045ab406 100644 (file)
 #define IMX_SSI_RX_DIV_PSR     4
 #define IMX_SSI_RX_DIV_PM      5
 
-extern struct snd_soc_dai imx_ssi_pcm_dai[2];
-extern struct snd_soc_platform imx_soc_platform;
-
 #define DRV_NAME "imx-ssi"
 
 struct imx_pcm_dma_params {
@@ -197,7 +194,7 @@ struct imx_pcm_dma_params {
 struct imx_ssi {
        struct platform_device *ac97_dev;
 
-       struct snd_soc_device imx_ac97;
+       struct snd_soc_dai *imx_ac97;
        struct clk *clk;
        void __iomem *base;
        int irq;
@@ -213,6 +210,8 @@ struct imx_ssi {
        struct imx_pcm_dma_params       dma_params_tx;
 
        int enabled;
+
+       struct platform_device *soc_platform_pdev;
 };
 
 struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev,
index a8307d55c70eaadc99e03aba65cef24d71668121..6a65dd7055199febc9a63393430461d086e2d4e8 100644 (file)
@@ -32,23 +32,20 @@ static struct snd_soc_dai_link imx_phycore_dai_ac97[] = {
        {
                .name           = "HiFi",
                .stream_name    = "HiFi",
-               .codec_dai      = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+               .codec_dai_name         = "wm9712-hifi",
+               .codec_name     = "wm9712-codec",
+               .cpu_dai_name   = "imx-ssi.0",
+               .platform_name  = "imx-fiq-pcm-audio.0",
                .ops            = &imx_phycore_hifi_ops,
        },
 };
 
 static struct snd_soc_card imx_phycore = {
        .name           = "PhyCORE-audio",
-       .platform       = &imx_soc_platform,
        .dai_link       = imx_phycore_dai_ac97,
        .num_links      = ARRAY_SIZE(imx_phycore_dai_ac97),
 };
 
-static struct snd_soc_device imx_phycore_snd_devdata = {
-       .card           = &imx_phycore,
-       .codec_dev      = &soc_codec_dev_wm9712,
-};
-
 static struct platform_device *imx_phycore_snd_device;
 
 static int __init imx_phycore_init(void)
@@ -63,10 +60,12 @@ static int __init imx_phycore_init(void)
        if (!imx_phycore_snd_device)
                return -ENOMEM;
 
-       imx_phycore_dai_ac97[0].cpu_dai = &imx_ssi_pcm_dai[0];
+       platform_set_drvdata(imx_phycore_snd_device, &imx_phycore);
+       ret = platform_device_add(imx_phycore_snd_device);
 
-       platform_set_drvdata(imx_phycore_snd_device, &imx_phycore_snd_devdata);
-       imx_phycore_snd_devdata.dev = &imx_phycore_snd_device->dev;
+       imx_phycore_snd_device = platform_device_alloc("wm9712-codec", -1);
+       if (!imx_phycore_snd_device)
+               return -ENOMEM;
        ret = platform_device_add(imx_phycore_snd_device);
 
        if (ret) {
index a6e7d94976399ee8c8f01fbd14268ef440e989c9..30fdb15065be314e6f0064b184605ff9f4ef8fb7 100644 (file)
@@ -82,8 +82,8 @@ static int wm1133_ev1_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int i, found = 0;
        snd_pcm_format_t format = params_format(params);
        unsigned int rate = params_rate(params);
@@ -210,9 +210,9 @@ static struct snd_soc_jack_pin mic_jack_pins[] = {
        { .pin = "Mic2 Jack", .mask = SND_JACK_MICROPHONE },
 };
 
-static int wm1133_ev1_init(struct snd_soc_codec *codec)
+static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_card *card = codec->socdev->card;
+       struct snd_soc_codec *codec = rtd->codec;
 
        snd_soc_dapm_new_controls(codec, wm1133_ev1_widgets,
                                  ARRAY_SIZE(wm1133_ev1_widgets));
@@ -221,13 +221,13 @@ static int wm1133_ev1_init(struct snd_soc_codec *codec)
                                ARRAY_SIZE(wm1133_ev1_map));
 
        /* Headphone jack detection */
-       snd_soc_jack_new(card, "Headphone", SND_JACK_HEADPHONE, &hp_jack);
+       snd_soc_jack_new(codec, "Headphone", SND_JACK_HEADPHONE, &hp_jack);
        snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins),
                              hp_jack_pins);
        wm8350_hp_jack_detect(codec, WM8350_JDR, &hp_jack, SND_JACK_HEADPHONE);
 
        /* Microphone jack detection */
-       snd_soc_jack_new(card, "Microphone",
+       snd_soc_jack_new(codec, "Microphone",
                         SND_JACK_MICROPHONE | SND_JACK_BTN_0, &mic_jack);
        snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
                              mic_jack_pins);
@@ -243,8 +243,10 @@ static int wm1133_ev1_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link wm1133_ev1_dai = {
        .name = "WM1133-EV1",
        .stream_name = "Audio",
-       .cpu_dai = &imx_ssi_pcm_dai[0],
-       .codec_dai = &wm8350_dai,
+       .cpu_dai_name = "imx-ssi.0",
+       .codec_dai_name = "wm8350-hifi",
+       .platform_name = "imx-fiq-pcm-audio.0",
+       .codec_name = "wm8350-codec.0-0x1a",
        .init = wm1133_ev1_init,
        .ops = &wm1133_ev1_ops,
        .symmetric_rates = 1,
@@ -252,16 +254,10 @@ static struct snd_soc_dai_link wm1133_ev1_dai = {
 
 static struct snd_soc_card wm1133_ev1 = {
        .name = "WM1133-EV1",
-       .platform = &imx_soc_platform,
        .dai_link = &wm1133_ev1_dai,
        .num_links = 1,
 };
 
-static struct snd_soc_device wm1133_ev1_snd_devdata = {
-       .card = &wm1133_ev1,
-       .codec_dev = &soc_codec_dev_wm8350,
-};
-
 static struct platform_device *wm1133_ev1_snd_device;
 
 static int __init wm1133_ev1_audio_init(void)
@@ -286,8 +282,7 @@ static int __init wm1133_ev1_audio_init(void)
        if (!wm1133_ev1_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(wm1133_ev1_snd_device, &wm1133_ev1_snd_devdata);
-       wm1133_ev1_snd_devdata.dev = &wm1133_ev1_snd_device->dev;
+       platform_set_drvdata(wm1133_ev1_snd_device, &wm1133_ev1);
        ret = platform_device_add(wm1133_ev1_snd_device);
 
        if (ret)
index eb518f0c5e016274c0b00ab11a220e02b754641b..f3cffd18340192b3544e288480a22056b169f560 100644 (file)
@@ -106,15 +106,10 @@ static inline void jz4740_i2s_write(const struct jz4740_i2s *i2s,
        writel(value, i2s->base + reg);
 }
 
-static inline struct jz4740_i2s *jz4740_dai_to_i2s(struct snd_soc_dai *dai)
-{
-       return dai->private_data;
-}
-
 static int jz4740_i2s_startup(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
-       struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        uint32_t conf, ctrl;
 
        if (dai->active)
@@ -136,7 +131,7 @@ static int jz4740_i2s_startup(struct snd_pcm_substream *substream,
 static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
-       struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        uint32_t conf;
 
        if (!dai->active)
@@ -152,7 +147,7 @@ static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream,
 static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
        struct snd_soc_dai *dai)
 {
-       struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 
        uint32_t ctrl;
        uint32_t mask;
@@ -186,7 +181,7 @@ static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 
 static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-       struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 
        uint32_t format = 0;
        uint32_t conf;
@@ -238,7 +233,7 @@ static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
-       struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        enum jz4740_dma_width dma_width;
        struct jz4740_pcm_config *pcm_config;
        unsigned int sample_size;
@@ -288,7 +283,7 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
 static int jz4740_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
        unsigned int freq, int dir)
 {
-       struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        struct clk *parent;
        int ret = 0;
 
@@ -312,7 +307,7 @@ static int jz4740_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 
 static int jz4740_i2s_suspend(struct snd_soc_dai *dai)
 {
-       struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        uint32_t conf;
 
        if (dai->active) {
@@ -330,7 +325,7 @@ static int jz4740_i2s_suspend(struct snd_soc_dai *dai)
 
 static int jz4740_i2s_resume(struct snd_soc_dai *dai)
 {
-       struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        uint32_t conf;
 
        clk_enable(i2s->clk_aic);
@@ -346,11 +341,38 @@ static int jz4740_i2s_resume(struct snd_soc_dai *dai)
        return 0;
 }
 
-static int jz4740_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai)
+static void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s)
 {
-       struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
+       struct jz4740_dma_config *dma_config;
+
+       /* Playback */
+       dma_config = &i2s->pcm_config_playback.dma_config;
+       dma_config->src_width = JZ4740_DMA_WIDTH_32BIT,
+       dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
+       dma_config->request_type = JZ4740_DMA_TYPE_AIC_TRANSMIT;
+       dma_config->flags = JZ4740_DMA_SRC_AUTOINC;
+       dma_config->mode = JZ4740_DMA_MODE_SINGLE;
+       i2s->pcm_config_playback.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
+
+       /* Capture */
+       dma_config = &i2s->pcm_config_capture.dma_config;
+       dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT,
+       dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
+       dma_config->request_type = JZ4740_DMA_TYPE_AIC_RECEIVE;
+       dma_config->flags = JZ4740_DMA_DST_AUTOINC;
+       dma_config->mode = JZ4740_DMA_MODE_SINGLE;
+       i2s->pcm_config_capture.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
+}
+
+static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        uint32_t conf;
 
+       clk_enable(i2s->clk_aic);
+
+       jz4740_i2c_init_pcm_config(i2s);
+
        conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
                (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
                JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
@@ -363,6 +385,14 @@ static int jz4740_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *da
        return 0;
 }
 
+static int jz4740_i2s_dai_remove(struct snd_soc_dai *dai)
+{
+       struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+       clk_disable(i2s->clk_aic);
+       return 0;
+}
+
 static struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
        .startup = jz4740_i2s_startup,
        .shutdown = jz4740_i2s_shutdown,
@@ -375,9 +405,9 @@ static struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
 #define JZ4740_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \
                SNDRV_PCM_FMTBIT_S16_LE)
 
-struct snd_soc_dai jz4740_i2s_dai = {
-       .name = "jz4740-i2s",
-       .probe = jz4740_i2s_probe,
+static struct snd_soc_dai_driver jz4740_i2s_dai = {
+       .probe = jz4740_i2s_dai_probe,
+       .remove = jz4740_i2s_dai_remove,
        .playback = {
                .channels_min = 1,
                .channels_max = 2,
@@ -395,30 +425,6 @@ struct snd_soc_dai jz4740_i2s_dai = {
        .suspend = jz4740_i2s_suspend,
        .resume = jz4740_i2s_resume,
 };
-EXPORT_SYMBOL_GPL(jz4740_i2s_dai);
-
-static void __devinit jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s)
-{
-       struct jz4740_dma_config *dma_config;
-
-       /* Playback */
-       dma_config = &i2s->pcm_config_playback.dma_config;
-       dma_config->src_width = JZ4740_DMA_WIDTH_32BIT,
-       dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
-       dma_config->request_type = JZ4740_DMA_TYPE_AIC_TRANSMIT;
-       dma_config->flags = JZ4740_DMA_SRC_AUTOINC;
-       dma_config->mode = JZ4740_DMA_MODE_SINGLE;
-       i2s->pcm_config_playback.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
-
-       /* Capture */
-       dma_config = &i2s->pcm_config_capture.dma_config;
-       dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT,
-       dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
-       dma_config->request_type = JZ4740_DMA_TYPE_AIC_RECEIVE;
-       dma_config->flags = JZ4740_DMA_DST_AUTOINC;
-       dma_config->mode = JZ4740_DMA_MODE_SINGLE;
-       i2s->pcm_config_capture.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
-}
 
 static int __devinit jz4740_i2s_dev_probe(struct platform_device *pdev)
 {
@@ -463,24 +469,17 @@ static int __devinit jz4740_i2s_dev_probe(struct platform_device *pdev)
                goto err_clk_put_aic;
        }
 
-       clk_enable(i2s->clk_aic);
-
-       jz4740_i2c_init_pcm_config(i2s);
-
-       jz4740_i2s_dai.private_data = i2s;
-       ret = snd_soc_register_dai(&jz4740_i2s_dai);
+       platform_set_drvdata(pdev, i2s);
+       ret = snd_soc_register_dai(&pdev->dev, &jz4740_i2s_dai);
 
        if (ret) {
                dev_err(&pdev->dev, "Failed to register DAI\n");
                goto err_clk_put_i2s;
        }
 
-       platform_set_drvdata(pdev, i2s);
-
        return 0;
 
 err_clk_put_i2s:
-       clk_disable(i2s->clk_aic);
        clk_put(i2s->clk_i2s);
 err_clk_put_aic:
        clk_put(i2s->clk_aic);
@@ -498,9 +497,8 @@ static int __devexit jz4740_i2s_dev_remove(struct platform_device *pdev)
 {
        struct jz4740_i2s *i2s = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&jz4740_i2s_dai);
+       snd_soc_unregister_dai(&pdev->dev);
 
-       clk_disable(i2s->clk_aic);
        clk_put(i2s->clk_i2s);
        clk_put(i2s->clk_aic);
 
index da22ed88a5899ae334670e58ae88767f25287bda..5e49339d8b9340212e7e74f0defc3d2c5cc2ce76 100644 (file)
@@ -13,6 +13,4 @@
 
 #define JZ4740_I2S_BIT_CLK             0
 
-extern struct snd_soc_dai jz4740_i2s_dai;
-
 #endif
index ee68d850c8dd93715564679a8b766655952669c8..fb1483f7c9660b15daeddf0b978f7b969d2ee61a 100644 (file)
@@ -109,7 +109,7 @@ static int jz4740_pcm_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct jz4740_pcm_config *config;
 
-       config = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+       config = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        if (!config)
                return 0;
@@ -310,14 +310,14 @@ int jz4740_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = jz4740_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto err;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = jz4740_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -328,22 +328,20 @@ err:
        return ret;
 }
 
-struct snd_soc_platform jz4740_soc_platform = {
-               .name           = "jz4740-pcm",
-               .pcm_ops        = &jz4740_pcm_ops,
+static struct snd_soc_platform_driver jz4740_soc_platform = {
+               .ops            = &jz4740_pcm_ops,
                .pcm_new        = jz4740_pcm_new,
                .pcm_free       = jz4740_pcm_free,
 };
-EXPORT_SYMBOL_GPL(jz4740_soc_platform);
 
 static int __devinit jz4740_pcm_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&jz4740_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &jz4740_soc_platform);
 }
 
 static int __devexit jz4740_pcm_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&jz4740_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
        return 0;
 }
 
@@ -351,7 +349,7 @@ static struct platform_driver jz4740_pcm_driver = {
        .probe = jz4740_pcm_probe,
        .remove = __devexit_p(jz4740_pcm_remove),
        .driver = {
-               .name = "jz4740-pcm",
+               .name = "jz4740-pcm-audio",
                .owner = THIS_MODULE,
        },
 };
index e3f221e2779c1c8164fc25e97abb17f2709e3e85..1220cbb4382c683966f868f918da55772d9a8288 100644 (file)
@@ -11,8 +11,6 @@
 #include <linux/dma-mapping.h>
 #include <asm/mach-jz4740/dma.h>
 
-/* platform data */
-extern struct snd_soc_platform jz4740_soc_platform;
 
 struct jz4740_pcm_config {
        struct jz4740_dma_config dma_config;
index f15f4918f15f4ef22904589cc3a5bb4992f19011..ef1a99e6a3bdf70994838f0f0d3a14a60680ab4e 100644 (file)
 #include <sound/soc-dapm.h>
 #include <linux/gpio.h>
 
-#include "../codecs/jz4740.h"
-#include "jz4740-pcm.h"
-#include "jz4740-i2s.h"
-
-
 #define QI_LB60_SND_GPIO JZ_GPIO_PORTB(29)
 #define QI_LB60_AMP_GPIO JZ_GPIO_PORTD(4)
 
@@ -60,10 +55,11 @@ static const struct snd_soc_dapm_route qi_lb60_routes[] = {
                        SND_SOC_DAIFMT_NB_NF | \
                        SND_SOC_DAIFMT_CBM_CFM)
 
-static int qi_lb60_codec_init(struct snd_soc_codec *codec)
+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;
        int ret;
-       struct snd_soc_dai *cpu_dai = codec->socdev->card->dai_link->cpu_dai;
 
        snd_soc_dapm_nc_pin(codec, "LIN");
        snd_soc_dapm_nc_pin(codec, "RIN");
@@ -84,8 +80,10 @@ static int qi_lb60_codec_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link qi_lb60_dai = {
        .name = "jz4740",
        .stream_name = "jz4740",
-       .cpu_dai = &jz4740_i2s_dai,
-       .codec_dai = &jz4740_codec_dai,
+       .cpu_dai_name = "jz4740-i2s",
+       .platform_name = "jz4740-pcm-audio",
+       .codec_dai_name = "jz4740-hifi",
+       .codec_name = "jz4740-codec",
        .init = qi_lb60_codec_init,
 };
 
@@ -93,12 +91,6 @@ static struct snd_soc_card qi_lb60 = {
        .name = "QI LB60",
        .dai_link = &qi_lb60_dai,
        .num_links = 1,
-       .platform = &jz4740_soc_platform,
-};
-
-static struct snd_soc_device qi_lb60_snd_devdata = {
-       .card = &qi_lb60,
-       .codec_dev = &soc_codec_dev_jz4740_codec,
 };
 
 static struct platform_device *qi_lb60_snd_device;
@@ -129,8 +121,7 @@ static int __init qi_lb60_init(void)
        gpio_direction_output(QI_LB60_SND_GPIO, 0);
        gpio_direction_output(QI_LB60_AMP_GPIO, 0);
 
-       platform_set_drvdata(qi_lb60_snd_device, &qi_lb60_snd_devdata);
-       qi_lb60_snd_devdata.dev = &qi_lb60_snd_device->dev;
+       platform_set_drvdata(qi_lb60_snd_device, &qi_lb60);
 
        ret = platform_device_add(qi_lb60_snd_device);
        if (ret) {
index a30205be3e2b46b4ee5c315cbe7c227f9eacb8cc..0fd6a630db011eb961406aedb6352f2673fb0f1d 100644 (file)
@@ -2,6 +2,7 @@
  * kirkwood-dma.c
  *
  * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ * (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
@@ -18,7 +19,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/mbus.h>
 #include <sound/soc.h>
-#include "kirkwood-dma.h"
 #include "kirkwood.h"
 
 #define KIRKWOOD_RATES \
@@ -123,9 +123,10 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
        int err;
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-       struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+       struct snd_soc_platform *platform = soc_runtime->platform;
+       struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
        struct kirkwood_dma_data *priv;
-       struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
+       struct kirkwood_dma_priv *prdata = snd_soc_platform_get_drvdata(platform);
        unsigned long addr;
 
        priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
@@ -151,7 +152,7 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
        if (err < 0)
                return err;
 
-       if (soc_runtime->dai->cpu_dai->private_data == NULL) {
+       if (prdata == NULL) {
                prdata = kzalloc(sizeof(struct kirkwood_dma_priv), GFP_KERNEL);
                if (prdata == NULL)
                        return -ENOMEM;
@@ -165,7 +166,7 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
                        return -EBUSY;
                }
 
-               soc_runtime->dai->cpu_dai->private_data = prdata;
+               snd_soc_platform_set_drvdata(platform, prdata);
 
                /*
                 * Enable Error interrupts. We're only ack'ing them but
@@ -191,8 +192,9 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
 static int kirkwood_dma_close(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-       struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
-       struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
+       struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
+       struct snd_soc_platform *platform = soc_runtime->platform;
+       struct kirkwood_dma_priv *prdata = snd_soc_platform_get_drvdata(platform);
        struct kirkwood_dma_data *priv;
 
        priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
@@ -209,7 +211,7 @@ static int kirkwood_dma_close(struct snd_pcm_substream *substream)
                writel(0, priv->io + KIRKWOOD_ERR_MASK);
                free_irq(priv->irq, prdata);
                kfree(prdata);
-               soc_runtime->dai->cpu_dai->private_data = NULL;
+               snd_soc_platform_set_drvdata(platform, NULL);
        }
 
        return 0;
@@ -236,7 +238,7 @@ static int kirkwood_dma_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-       struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
        struct kirkwood_dma_data *priv;
        unsigned long size, count;
 
@@ -265,7 +267,7 @@ static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream
                                                *substream)
 {
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-       struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
        struct kirkwood_dma_data *priv;
        snd_pcm_uframes_t count;
 
@@ -320,14 +322,14 @@ static int kirkwood_dma_new(struct snd_card *card,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = 0xffffffff;
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = kirkwood_dma_preallocate_dma_buffer(pcm,
                                SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        return ret;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = kirkwood_dma_preallocate_dma_buffer(pcm,
                                SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -357,27 +359,46 @@ static void kirkwood_dma_free_dma_buffers(struct snd_pcm *pcm)
        }
 }
 
-struct snd_soc_platform kirkwood_soc_platform = {
-       .name           = "kirkwood-dma",
-       .pcm_ops        = &kirkwood_dma_ops,
+static struct snd_soc_platform_driver kirkwood_soc_platform = {
+       .ops            = &kirkwood_dma_ops,
        .pcm_new        = kirkwood_dma_new,
        .pcm_free       = kirkwood_dma_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(kirkwood_soc_platform);
 
-static int __init kirkwood_soc_platform_init(void)
+static int __devinit kirkwood_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&kirkwood_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &kirkwood_soc_platform);
 }
-module_init(kirkwood_soc_platform_init);
 
-static void __exit kirkwood_soc_platform_exit(void)
+static int __devexit kirkwood_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&kirkwood_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
 }
-module_exit(kirkwood_soc_platform_exit);
 
-MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+static struct platform_driver kirkwood_pcm_driver = {
+       .driver = {
+                       .name = "kirkwood-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = kirkwood_soc_platform_probe,
+       .remove = __devexit_p(kirkwood_soc_platform_remove),
+};
+
+static int __init kirkwood_pcm_init(void)
+{
+       return platform_driver_register(&kirkwood_pcm_driver);
+}
+module_init(kirkwood_pcm_init);
+
+static void __exit kirkwood_pcm_exit(void)
+{
+       platform_driver_unregister(&kirkwood_pcm_driver);
+}
+module_exit(kirkwood_pcm_exit);
+
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
 MODULE_DESCRIPTION("Marvell Kirkwood Audio DMA module");
 MODULE_LICENSE("GPL");
-
+MODULE_ALIAS("platform:kirkwood-pcm-audio");
diff --git a/sound/soc/kirkwood/kirkwood-dma.h b/sound/soc/kirkwood/kirkwood-dma.h
deleted file mode 100644 (file)
index ba4454c..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * kirkwood-dma.h
- *
- * (c) 2010 Arnaud Patard <apatard@mandriva.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.
- */
-
-#ifndef _KIRKWOOD_DMA_H
-#define _KIRKWOOD_DMA_H
-
-extern struct snd_soc_platform kirkwood_soc_platform;
-
-#endif
index 981ffc2a13c8ad5adfdccdcd59cfc177bc1d9101..a33fc51f363be864ad2385e434dce97c409b5991 100644 (file)
@@ -2,6 +2,7 @@
  * kirkwood-i2s.c
  *
  * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ * (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
@@ -20,7 +21,6 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <plat/audio.h>
-#include "kirkwood-i2s.h"
 #include "kirkwood.h"
 
 #define DRV_NAME       "kirkwood-i2s"
         SNDRV_PCM_FMTBIT_S24_LE | \
         SNDRV_PCM_FMTBIT_S32_LE)
 
-
-struct snd_soc_dai kirkwood_i2s_dai;
-static struct kirkwood_dma_data *priv;
-
 static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
                unsigned int fmt)
 {
+       struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(cpu_dai);
        unsigned long mask;
        unsigned long value;
 
@@ -101,10 +98,20 @@ static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
        } while (value == 0);
 }
 
+static int kirkwood_i2s_startup(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *dai)
+{
+       struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
+
+       snd_soc_dai_set_dma_data(dai, substream, priv);
+       return 0;
+}
+
 static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *dai)
 {
+       struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
        unsigned int i2s_reg, reg;
        unsigned long i2s_value, value;
 
@@ -171,6 +178,7 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
 static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
                                int cmd, struct snd_soc_dai *dai)
 {
+       struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
        unsigned long value;
 
        /*
@@ -244,6 +252,7 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
 static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
                                int cmd, struct snd_soc_dai *dai)
 {
+       struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
        unsigned long value;
 
        value = readl(priv->io + KIRKWOOD_RECCTL);
@@ -323,9 +332,9 @@ static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
        return 0;
 }
 
-static int kirkwood_i2s_probe(struct platform_device *pdev,
-                            struct snd_soc_dai *dai)
+static int kirkwood_i2s_probe(struct snd_soc_dai *dai)
 {
+       struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
        unsigned long value;
        unsigned int reg_data;
 
@@ -359,21 +368,20 @@ static int kirkwood_i2s_probe(struct platform_device *pdev,
 
 }
 
-static void kirkwood_i2s_remove(struct platform_device *pdev,
-                               struct snd_soc_dai *dai)
+static int kirkwood_i2s_remove(struct snd_soc_dai *dai)
 {
+       return 0;
 }
 
 static struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
+       .startup        = kirkwood_i2s_startup,
        .trigger        = kirkwood_i2s_trigger,
        .hw_params      = kirkwood_i2s_hw_params,
        .set_fmt        = kirkwood_i2s_set_fmt,
 };
 
 
-struct snd_soc_dai kirkwood_i2s_dai = {
-       .name = DRV_NAME,
-       .id = 0,
+static struct snd_soc_dai_driver kirkwood_i2s_dai = {
        .probe = kirkwood_i2s_probe,
        .remove = kirkwood_i2s_remove,
        .playback = {
@@ -388,13 +396,13 @@ struct snd_soc_dai kirkwood_i2s_dai = {
                .formats = KIRKWOOD_I2S_FORMATS,},
        .ops = &kirkwood_i2s_dai_ops,
 };
-EXPORT_SYMBOL_GPL(kirkwood_i2s_dai);
 
 static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
 {
        struct resource *mem;
        struct kirkwood_asoc_platform_data *data =
                pdev->dev.platform_data;
+       struct kirkwood_dma_data *priv;
        int err;
 
        priv = kzalloc(sizeof(struct kirkwood_dma_data), GFP_KERNEL);
@@ -403,6 +411,7 @@ static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
                err = -ENOMEM;
                goto error;
        }
+       dev_set_drvdata(&pdev->dev, priv);
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!mem) {
@@ -441,10 +450,7 @@ static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
        priv->dram = data->dram;
        priv->burst = data->burst;
 
-       kirkwood_i2s_dai.capture.dma_data = priv;
-       kirkwood_i2s_dai.playback.dma_data = priv;
-
-       return snd_soc_register_dai(&kirkwood_i2s_dai);
+       return snd_soc_register_dai(&pdev->dev, &kirkwood_i2s_dai);
 
 err_ioremap:
        iounmap(priv->io);
@@ -458,12 +464,13 @@ error:
 
 static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev)
 {
-       if (priv) {
-               iounmap(priv->io);
-               release_mem_region(priv->mem->start, SZ_16K);
-               kfree(priv);
-       }
-       snd_soc_unregister_dai(&kirkwood_i2s_dai);
+       struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
+
+       snd_soc_unregister_dai(&pdev->dev);
+       iounmap(priv->io);
+       release_mem_region(priv->mem->start, SZ_16K);
+       kfree(priv);
+
        return 0;
 }
 
@@ -489,7 +496,7 @@ static void __exit kirkwood_i2s_exit(void)
 module_exit(kirkwood_i2s_exit);
 
 /* Module information */
-MODULE_AUTHOR("Arnaud Patard, <apatard@mandriva.com>");
+MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>");
 MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:kirkwood-i2s");
diff --git a/sound/soc/kirkwood/kirkwood-i2s.h b/sound/soc/kirkwood/kirkwood-i2s.h
deleted file mode 100644 (file)
index c5595c6..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * kirkwood-i2s.h
- *
- * (c) 2010 Arnaud Patard <apatard@mandriva.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.
- */
-
-#ifndef _KIRKWOOD_I2S_H
-#define _KIRKWOOD_I2S_H
-
-extern struct snd_soc_dai kirkwood_i2s_dai;
-
-#endif
index 0353d06bc41ac38c94ea67ae10f6afe307485b4d..9d7c81e921f1150ddea58f3c045e7b41dbacb5aa 100644 (file)
@@ -2,6 +2,7 @@
  * kirkwood-openrd.c
  *
  * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ * (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
 #include <mach/kirkwood.h>
 #include <plat/audio.h>
 #include <asm/mach-types.h>
-#include "kirkwood-i2s.h"
-#include "kirkwood-dma.h"
 #include "../codecs/cs42l51.h"
 
 static int openrd_client_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
        unsigned int freq, fmt;
 
@@ -66,8 +65,10 @@ static struct snd_soc_dai_link openrd_client_dai[] = {
 {
        .name = "CS42L51",
        .stream_name = "CS42L51 HiFi",
-       .cpu_dai = &kirkwood_i2s_dai,
-       .codec_dai = &cs42l51_dai,
+       .cpu_dai_name = "kirkwood-i2s",
+       .platform_name = "kirkwood-pcm-audio",
+       .codec_dai_name = "cs42l51-hifi",
+       .codec_name = "cs42l51-codec.0-004a",
        .ops = &openrd_client_ops,
 },
 };
@@ -75,16 +76,10 @@ static struct snd_soc_dai_link openrd_client_dai[] = {
 
 static struct snd_soc_card openrd_client = {
        .name = "OpenRD Client",
-       .platform = &kirkwood_soc_platform,
        .dai_link = openrd_client_dai,
        .num_links = ARRAY_SIZE(openrd_client_dai),
 };
 
-static struct snd_soc_device openrd_client_snd_devdata = {
-       .card = &openrd_client,
-       .codec_dev = &soc_codec_device_cs42l51,
-};
-
 static struct platform_device *openrd_client_snd_device;
 
 static int __init openrd_client_init(void)
@@ -99,8 +94,7 @@ static int __init openrd_client_init(void)
                return -ENOMEM;
 
        platform_set_drvdata(openrd_client_snd_device,
-                       &openrd_client_snd_devdata);
-       openrd_client_snd_devdata.dev = &openrd_client_snd_device->dev;
+                       &openrd_client);
 
        ret = platform_device_add(openrd_client_snd_device);
        if (ret) {
@@ -120,7 +114,7 @@ module_init(openrd_client_init);
 module_exit(openrd_client_exit);
 
 /* Module information */
-MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
 MODULE_DESCRIPTION("ALSA SoC OpenRD Client");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:soc-audio");
index caa7c901bc2e131a24fbfe90e442242ab2e22185..293dc748797c51cf11a63b6b0afa548521ff2898 100644 (file)
@@ -20,7 +20,6 @@
 #include <sound/pcm.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
-#include <linux/device.h>
 #include <linux/clk.h>
 
 #include <mach/mfp.h>
@@ -297,8 +296,7 @@ static struct snd_soc_dai_ops nuc900_ac97_dai_ops = {
        .trigger        = nuc900_ac97_trigger,
 };
 
-struct snd_soc_dai nuc900_ac97_dai = {
-       .name                   = "nuc900-ac97",
+static struct snd_soc_dai_driver nuc900_ac97_dai = {
        .probe                  = nuc900_ac97_probe,
        .remove                 = nuc900_ac97_remove,
        .ac97_control           = 1,
@@ -316,7 +314,6 @@ struct snd_soc_dai nuc900_ac97_dai = {
        },
        .ops = &nuc900_ac97_dai_ops,
 }
-EXPORT_SYMBOL_GPL(nuc900_ac97_dai);
 
 static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev)
 {
@@ -365,9 +362,7 @@ static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev)
 
        nuc900_ac97_data = nuc900_audio;
 
-       nuc900_audio->dev = nuc900_ac97_dai.dev =  &pdev->dev;
-
-       ret = snd_soc_register_dai(&nuc900_ac97_dai);
+       ret = snd_soc_register_dai(&pdev->dev, &nuc900_ac97_dai);
        if (ret)
                goto out3;
 
@@ -390,7 +385,7 @@ out0:
 static int __devexit nuc900_ac97_drvremove(struct platform_device *pdev)
 {
 
-       snd_soc_unregister_dai(&nuc900_ac97_dai);
+       snd_soc_unregister_dai(&pdev->dev);
 
        clk_put(nuc900_ac97_data->clk);
        iounmap(nuc900_ac97_data->mmio);
@@ -404,7 +399,7 @@ static int __devexit nuc900_ac97_drvremove(struct platform_device *pdev)
 
 static struct platform_driver nuc900_ac97_driver = {
        .driver = {
-               .name   = "nuc900-audio",
+               .name   = "nuc900-ac97",
                .owner  = THIS_MODULE,
        },
        .probe          = nuc900_ac97_drvprobe,
index 72e6f518f7b21818a2177dd7739576cb04f2410b..161f5b667d7b5cf641896f462efe3740866f129a 100644 (file)
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 
-#include "../codecs/ac97.h"
 #include "nuc900-audio.h"
 
 static struct snd_soc_dai_link nuc900evb_ac97_dai = {
        .name           = "AC97",
        .stream_name    = "AC97 HiFi",
-       .cpu_dai        = &nuc900_ac97_dai,
-       .codec_dai      = &ac97_dai,
+       .cpu_dai_name   = "nuc900-ac97",
+       .codec_dai_name = "ac97-hifi",
+       .codec_name     = "ac97-codec",
+       .platform_name  = "nuc900-pcm-audio",
 };
 
 static struct snd_soc_card nuc900evb_audio_machine = {
        .name           = "NUC900EVB_AC97",
        .dai_link       = &nuc900evb_ac97_dai,
        .num_links      = 1,
-       .platform       = &nuc900_soc_platform,
-};
-
-static struct snd_soc_device nuc900evb_ac97_devdata = {
-       .card           = &nuc900evb_audio_machine,
-       .codec_dev      = &soc_codec_dev_ac97,
 };
 
 static struct platform_device *nuc900evb_asoc_dev;
@@ -54,9 +49,8 @@ static int __init nuc900evb_audio_init(void)
                goto out;
 
        /* nuc900 board audio device */
-       platform_set_drvdata(nuc900evb_asoc_dev, &nuc900evb_ac97_devdata);
+       platform_set_drvdata(nuc900evb_asoc_dev, &nuc900evb_audio_machine);
 
-       nuc900evb_ac97_devdata.dev = &nuc900evb_asoc_dev->dev;
        ret = platform_device_add(nuc900evb_asoc_dev);
 
        if (ret) {
index 3038f519729f5b9559cb47cceababfb919a93a56..aeed8ead2b2bcc42fcb5e06200a807f68cc6ce63 100644 (file)
@@ -110,8 +110,4 @@ struct nuc900_audio {
 
 };
 
-extern struct nuc900_audio *nuc900_ac97_data;
-extern struct snd_soc_dai nuc900_ac97_dai;
-extern struct snd_soc_platform nuc900_soc_platform;
-
 #endif /*end _NUC900_AUDIO_H */
index e81e803b3a63fd502e4dd857232f1ee9f34f6929..195d1ac94771808c0eda8075255efff787cdfd59 100644 (file)
@@ -328,26 +328,44 @@ static int nuc900_dma_new(struct snd_card *card,
        return 0;
 }
 
-struct snd_soc_platform nuc900_soc_platform = {
-       .name           = "nuc900-dma",
-       .pcm_ops        = &nuc900_dma_ops,
+static struct snd_soc_platform_driver nuc900_soc_platform = {
+       .ops            = &nuc900_dma_ops,
        .pcm_new        = nuc900_dma_new,
        .pcm_free       = nuc900_dma_free_dma_buffers,
 }
-EXPORT_SYMBOL_GPL(nuc900_soc_platform);
 
-static int __init nuc900_soc_platform_init(void)
+static int __devinit nuc900_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&nuc900_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &nuc900_soc_platform);
 }
 
-static void __exit nuc900_soc_platform_exit(void)
+static int __devexit nuc900_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&nuc900_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
 }
 
-module_init(nuc900_soc_platform_init);
-module_exit(nuc900_soc_platform_exit);
+static struct platform_driver nuc900_pcm_driver = {
+       .driver = {
+                       .name = "nuc900-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = nuc900_soc_platform_probe,
+       .remove = __devexit_p(nuc900_soc_platform_remove),
+};
+
+static int __init nuc900_pcm_init(void)
+{
+       return platform_driver_register(&nuc900_pcm_driver);
+}
+module_init(nuc900_pcm_init);
+
+static void __exit nuc900_pcm_exit(void)
+{
+       platform_driver_unregister(&nuc900_pcm_driver);
+}
+module_exit(nuc900_pcm_exit);
 
 MODULE_AUTHOR("Wan ZongShun, <mcuos.com@gmail.com>");
 MODULE_DESCRIPTION("nuc900 Audio DMA module");
index 135901b2ea11b826c629ca93d572ea49ffccb7f8..979dd508305f812bc6ad893893ed6e811a8bdf3a 100644 (file)
@@ -40,8 +40,8 @@ static int am3517evm_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* Set codec DAI configuration */
@@ -111,8 +111,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"MICIN", NULL, "Mic In"},
 };
 
-static int am3517evm_aic23_init(struct snd_soc_codec *codec)
+static int am3517evm_aic23_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        /* Add am3517-evm specific widgets */
        snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
                                  ARRAY_SIZE(tlv320aic23_dapm_widgets));
@@ -134,8 +136,10 @@ static int am3517evm_aic23_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link am3517evm_dai = {
        .name = "TLV320AIC23",
        .stream_name = "AIC23",
-       .cpu_dai = &omap_mcbsp_dai[0],
-       .codec_dai = &tlv320aic23_dai,
+       .cpu_dai_name ="omap-mcbsp-dai.0",
+       .codec_dai_name = "tlv320aic23-hifi",
+       .platform_name = "omap-pcm-audio",
+       .codec_name = "tlv320aic23-codec",
        .init = am3517evm_aic23_init,
        .ops = &am3517evm_ops,
 };
@@ -143,27 +147,18 @@ static struct snd_soc_dai_link am3517evm_dai = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_am3517evm = {
        .name = "am3517evm",
-       .platform = &omap_soc_platform,
        .dai_link = &am3517evm_dai,
        .num_links = 1,
 };
 
-/* Audio subsystem */
-static struct snd_soc_device am3517evm_snd_devdata = {
-       .card = &snd_soc_am3517evm,
-       .codec_dev = &soc_codec_dev_tlv320aic23,
-};
-
 static struct platform_device *am3517evm_snd_device;
 
 static int __init am3517evm_soc_init(void)
 {
        int ret;
 
-       if (!machine_is_omap3517evm()) {
-               pr_err("Not OMAP3517 / AM3517 EVM!\n");
+       if (!machine_is_omap3517evm())
                return -ENODEV;
-       }
        pr_info("OMAP3517 / AM3517 EVM SoC init\n");
 
        am3517evm_snd_device = platform_device_alloc("soc-audio", -1);
@@ -172,9 +167,7 @@ static int __init am3517evm_soc_init(void)
                return -ENOMEM;
        }
 
-       platform_set_drvdata(am3517evm_snd_device, &am3517evm_snd_devdata);
-       am3517evm_snd_devdata.dev = &am3517evm_snd_device->dev;
-       *(unsigned int *)am3517evm_dai.cpu_dai->private_data = 0; /* McBSP1 */
+       platform_set_drvdata(am3517evm_snd_device, &snd_soc_am3517evm);
 
        ret = platform_device_add(am3517evm_snd_device);
        if (ret)
index b0f618e4484068e6c62e7b9515b6af5d6dfa021e..438146addbb88b0fdef55276d9513f772dc5b732 100644 (file)
@@ -99,7 +99,7 @@ static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol,
        int pin, changed = 0;
 
        /* Refuse any mode changes if we are not able to control the codec. */
-       if (!codec->control_data)
+       if (!codec->hw_write)
                return -EUNATCH;
 
        if (ucontrol->value.enumerated.item[0] >= control->max)
@@ -268,10 +268,32 @@ static void cx81801_timeout(unsigned long data)
                ams_delta_latch2_write(AMS_DELTA_LATCH2_MODEM_CODEC, 0);
 }
 
+/*
+ * Used for passing a codec structure pointer
+ * from the board initialization code to the tty line discipline.
+ */
+static struct snd_soc_codec *cx20442_codec;
+
 /* Line discipline .open() */
 static int cx81801_open(struct tty_struct *tty)
 {
-       return v253_ops.open(tty);
+       int ret;
+
+       if (!cx20442_codec)
+               return -ENODEV;
+
+       /*
+        * Pass the codec structure pointer for use by other ldisc callbacks,
+        * both the card and the codec specific parts.
+        */
+       tty->disc_data = cx20442_codec;
+
+       ret = v253_ops.open(tty);
+
+       if (ret < 0)
+               tty->disc_data = NULL;
+
+       return ret;
 }
 
 /* Line discipline .close() */
@@ -281,11 +303,14 @@ static void cx81801_close(struct tty_struct *tty)
 
        del_timer_sync(&cx81801_timer);
 
-       v253_ops.close(tty);
-
        /* Prevent the hook switch from further changing the DAPM pins */
        INIT_LIST_HEAD(&ams_delta_hook_switch.pins);
 
+       if (!codec)
+               return;
+
+       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");
@@ -310,7 +335,10 @@ static void cx81801_receive(struct tty_struct *tty,
        const unsigned char *c;
        int apply, ret;
 
-       if (!codec->control_data) {
+       if (!codec)
+               return;
+
+       if (!codec->hw_write) {
                /* First modem response, complete setup procedure */
 
                /* Initialize timer used for config pulse generation */
@@ -323,7 +351,7 @@ static void cx81801_receive(struct tty_struct *tty,
                                        ARRAY_SIZE(ams_delta_hook_switch_pins),
                                        ams_delta_hook_switch_pins);
                if (ret)
-                       dev_warn(codec->socdev->card->dev,
+                       dev_warn(codec->dev,
                                "Failed to link hook switch to DAPM pins, "
                                "will continue with hook switch unlinked.\n");
 
@@ -383,7 +411,7 @@ static int ams_delta_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
        /* Set cpu DAI configuration */
-       return snd_soc_dai_set_fmt(rtd->dai->cpu_dai,
+       return snd_soc_dai_set_fmt(rtd->cpu_dai,
                                   SND_SOC_DAIFMT_DSP_A |
                                   SND_SOC_DAIFMT_NB_NF |
                                   SND_SOC_DAIFMT_CBM_CFM);
@@ -398,7 +426,7 @@ static struct snd_soc_ops ams_delta_ops = {
 static int ams_delta_set_bias_level(struct snd_soc_card *card,
                                        enum snd_soc_bias_level level)
 {
-       struct snd_soc_codec *codec = card->codec;
+       struct snd_soc_codec *codec = card->rtd->codec;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
@@ -461,18 +489,22 @@ static void ams_delta_shutdown(struct snd_pcm_substream *substream)
  * Card initialization
  */
 
-static int ams_delta_cx20442_init(struct snd_soc_codec *codec)
+static int ams_delta_cx20442_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_dai *codec_dai = codec->dai;
-       struct snd_soc_card *card = codec->socdev->card;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_card *card = rtd->card;
        int ret;
        /* Codec is ready, now add/activate board specific controls */
 
+       /* Store a pointer to the codec structure for tty ldisc use */
+       cx20442_codec = codec;
+
        /* Set up digital mute if not provided by the codec */
-       if (!codec_dai->ops) {
-               codec_dai->ops = &ams_delta_dai_ops;
-       } else if (!codec_dai->ops->digital_mute) {
-               codec_dai->ops->digital_mute = ams_delta_digital_mute;
+       if (!codec_dai->driver->ops) {
+               codec_dai->driver->ops = &ams_delta_dai_ops;
+       } else if (!codec_dai->driver->ops->digital_mute) {
+               codec_dai->driver->ops->digital_mute = ams_delta_digital_mute;
        } else {
                ams_delta_ops.startup = ams_delta_startup;
                ams_delta_ops.shutdown = ams_delta_shutdown;
@@ -483,7 +515,7 @@ static int ams_delta_cx20442_init(struct snd_soc_codec *codec)
 
        /* Add hook switch - can be used to control the codec from userspace
         * even if line discipline fails */
-       ret = snd_soc_jack_new(card, "hook_switch",
+       ret = snd_soc_jack_new(rtd->codec, "hook_switch",
                                SND_JACK_HEADSET, &ams_delta_hook_switch);
        if (ret)
                dev_warn(card->dev,
@@ -551,27 +583,22 @@ static int ams_delta_cx20442_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link ams_delta_dai_link = {
        .name = "CX20442",
        .stream_name = "CX20442",
-       .cpu_dai = &omap_mcbsp_dai[0],
-       .codec_dai = &cx20442_dai,
+       .cpu_dai_name ="omap-mcbsp-dai.0",
+       .codec_dai_name = "cx20442-voice",
        .init = ams_delta_cx20442_init,
+       .platform_name = "omap-pcm-audio",
+       .codec_name = "cx20442-codec",
        .ops = &ams_delta_ops,
 };
 
 /* Audio card driver */
 static struct snd_soc_card ams_delta_audio_card = {
        .name = "AMS_DELTA",
-       .platform = &omap_soc_platform,
        .dai_link = &ams_delta_dai_link,
        .num_links = 1,
        .set_bias_level = ams_delta_set_bias_level,
 };
 
-/* Audio subsystem */
-static struct snd_soc_device ams_delta_snd_soc_device = {
-       .card = &ams_delta_audio_card,
-       .codec_dev = &cx20442_codec_dev,
-};
-
 /* Module init/exit */
 static struct platform_device *ams_delta_audio_platform_device;
 static struct platform_device *cx20442_platform_device;
@@ -589,9 +616,7 @@ static int __init ams_delta_module_init(void)
                return -ENOMEM;
 
        platform_set_drvdata(ams_delta_audio_platform_device,
-                               &ams_delta_snd_soc_device);
-       ams_delta_snd_soc_device.dev = &ams_delta_audio_platform_device->dev;
-       *(unsigned int *)ams_delta_dai_link.cpu_dai->private_data = OMAP_MCBSP1;
+                               &ams_delta_audio_card);
 
        ret = platform_device_add(ams_delta_audio_platform_device);
        if (ret)
@@ -601,8 +626,8 @@ static int __init ams_delta_module_init(void)
         * Codec platform device could be registered from elsewhere (board?),
         * but I do it here as it makes sense only if used with the card.
         */
-       cx20442_platform_device = platform_device_register_simple("cx20442",
-                                                               -1, NULL, 0);
+       cx20442_platform_device =
+               platform_device_register_simple("cx20442-codec", -1, NULL, 0);
        return 0;
 err:
        platform_device_put(ams_delta_audio_platform_device);
@@ -612,19 +637,6 @@ module_init(ams_delta_module_init);
 
 static void __exit ams_delta_module_exit(void)
 {
-       struct snd_soc_codec *codec;
-       struct tty_struct *tty;
-
-       if (ams_delta_audio_card.codec) {
-               codec = ams_delta_audio_card.codec;
-
-               if (codec->control_data) {
-                       tty = codec->control_data;
-
-                       tty_hangup(tty);
-               }
-       }
-
        if (tty_unregister_ldisc(N_V253) != 0)
                dev_warn(&ams_delta_audio_platform_device->dev,
                        "failed to unregister V253 line discipline\n");
index 3583c429f9be38634e95f2c14af34f25cfba7643..fd3a40f309c8e4d3067ea93ecfebc6ad8f0f4a23 100644 (file)
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
-#include "../codecs/twl4030.h"
 
 static int igep2_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* Set codec DAI configuration */
@@ -82,35 +81,28 @@ static struct snd_soc_ops igep2_ops = {
 static struct snd_soc_dai_link igep2_dai = {
        .name = "TWL4030",
        .stream_name = "TWL4030",
-       .cpu_dai = &omap_mcbsp_dai[0],
-       .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+       .cpu_dai_name = "omap-mcbsp-dai.1",
+       .codec_dai_name = "twl4030-hifi",
+       .platform_name = "omap-pcm-audio",
+       .codec_name = "twl4030-codec",
        .ops = &igep2_ops,
 };
 
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_card_igep2 = {
        .name = "igep2",
-       .platform = &omap_soc_platform,
        .dai_link = &igep2_dai,
        .num_links = 1,
 };
 
-/* Audio subsystem */
-static struct snd_soc_device igep2_snd_devdata = {
-       .card = &snd_soc_card_igep2,
-       .codec_dev = &soc_codec_dev_twl4030,
-};
-
 static struct platform_device *igep2_snd_device;
 
 static int __init igep2_soc_init(void)
 {
        int ret;
 
-       if (!machine_is_igep0020()) {
-               pr_debug("Not IGEP v2!\n");
+       if (!machine_is_igep0020())
                return -ENODEV;
-       }
        printk(KERN_INFO "IGEP v2 SoC init\n");
 
        igep2_snd_device = platform_device_alloc("soc-audio", -1);
@@ -119,9 +111,7 @@ static int __init igep2_soc_init(void)
                return -ENOMEM;
        }
 
-       platform_set_drvdata(igep2_snd_device, &igep2_snd_devdata);
-       igep2_snd_devdata.dev = &igep2_snd_device->dev;
-       *(unsigned int *)igep2_dai.cpu_dai->private_data = 1; /* McBSP2 */
+       platform_set_drvdata(igep2_snd_device, &snd_soc_card_igep2);
 
        ret = platform_device_add(igep2_snd_device);
        if (ret)
index 90b8bf71c893be74903209f94b5f1aef17bc0171..928f03707451ecde15f046574ed8f1b4e841ee9a 100644 (file)
@@ -402,7 +402,7 @@ int omap_mcpdm_set_offset(int offset1, int offset2)
        return 0;
 }
 
-static int __devinit omap_mcpdm_probe(struct platform_device *pdev)
+int __devinit omap_mcpdm_probe(struct platform_device *pdev)
 {
        struct resource *res;
        int ret = 0;
@@ -449,7 +449,7 @@ exit:
        return ret;
 }
 
-static int __devexit omap_mcpdm_remove(struct platform_device *pdev)
+int __devexit omap_mcpdm_remove(struct platform_device *pdev)
 {
        struct omap_mcpdm *mcpdm_ptr = platform_get_drvdata(pdev);
 
@@ -468,18 +468,3 @@ static int __devexit omap_mcpdm_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct platform_driver omap_mcpdm_driver = {
-       .probe = omap_mcpdm_probe,
-       .remove = __devexit_p(omap_mcpdm_remove),
-       .driver = {
-               .name = "omap-mcpdm",
-       },
-};
-
-static struct platform_device *omap_mcpdm_device;
-
-static int __init omap_mcpdm_init(void)
-{
-       return platform_driver_register(&omap_mcpdm_driver);
-}
-arch_initcall(omap_mcpdm_init);
index 7bb326ef08866d7e032424c538d8069408d7d1a9..df3e16fb51f31ca2c6e1f25c9881ac272f7788c2 100644 (file)
@@ -149,3 +149,5 @@ extern int omap_mcpdm_playback_close(struct omap_mcpdm_link *downlink);
 extern int omap_mcpdm_request(void);
 extern void omap_mcpdm_free(void);
 extern int omap_mcpdm_set_offset(int offset1, int offset2);
+int __devinit omap_mcpdm_probe(struct platform_device *pdev);
+int __devexit omap_mcpdm_remove(struct platform_device *pdev);
index 08e09d72790f68beb75e40b1f55c1f3a4ff6d68f..a3b6d897ad84751b6ffced0757f27f51726d3385 100644 (file)
@@ -97,7 +97,7 @@ static int n810_startup(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        snd_pcm_hw_constraint_minmax(runtime,
                                     SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
@@ -115,8 +115,8 @@ static int n810_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int err;
 
        /* Set codec DAI configuration */
@@ -271,8 +271,9 @@ static const struct snd_kcontrol_new aic33_n810_controls[] = {
                     n810_get_input, n810_set_input),
 };
 
-static int n810_aic33_init(struct snd_soc_codec *codec)
+static int n810_aic33_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        /* Not connected */
@@ -307,8 +308,10 @@ static int n810_aic33_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link n810_dai = {
        .name = "TLV320AIC33",
        .stream_name = "AIC33",
-       .cpu_dai = &omap_mcbsp_dai[0],
-       .codec_dai = &aic3x_dai,
+       .cpu_dai_name = "omap-mcbsp-dai.1",
+       .platform_name = "omap-pcm-audio",
+       .codec_name = "tlv320aic3x-codec.2-0018",
+       .codec_dai_name = "tlv320aic3x-hifi",
        .init = n810_aic33_init,
        .ops = &n810_ops,
 };
@@ -316,33 +319,12 @@ static struct snd_soc_dai_link n810_dai = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_n810 = {
        .name = "N810",
-       .platform = &omap_soc_platform,
        .dai_link = &n810_dai,
        .num_links = 1,
 };
 
-/* Audio private data */
-static struct aic3x_setup_data n810_aic33_setup = {
-       .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
-       .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
-};
-
-/* Audio subsystem */
-static struct snd_soc_device n810_snd_devdata = {
-       .card = &snd_soc_n810,
-       .codec_dev = &soc_codec_dev_aic3x,
-       .codec_data = &n810_aic33_setup,
-};
-
 static struct platform_device *n810_snd_device;
 
-/* temporary i2c device creation until this can be moved into the machine
- * support file.
-*/
-static struct i2c_board_info i2c_device[] = {
-       { I2C_BOARD_INFO("tlv320aic3x", 0x1b), }
-};
-
 static int __init n810_soc_init(void)
 {
        int err;
@@ -351,15 +333,11 @@ static int __init n810_soc_init(void)
        if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax()))
                return -ENODEV;
 
-       i2c_register_board_info(1, i2c_device, ARRAY_SIZE(i2c_device));
-
        n810_snd_device = platform_device_alloc("soc-audio", -1);
        if (!n810_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(n810_snd_device, &n810_snd_devdata);
-       n810_snd_devdata.dev = &n810_snd_device->dev;
-       *(unsigned int *)n810_dai.cpu_dai->private_data = 1; /* McBSP2 */
+       platform_set_drvdata(n810_snd_device, &snd_soc_n810);
        err = platform_device_add(n810_snd_device);
        if (err)
                goto err1;
index 86f213905e2c0108e261de0f5d73b734cea27e57..99696187b55a8c0023171d383c102147599ab4c6 100644 (file)
@@ -62,8 +62,6 @@ struct omap_mcbsp_data {
        int                             wlen;
 };
 
-#define to_mcbsp(priv) container_of((priv), struct omap_mcbsp_data, bus_id)
-
 static struct omap_mcbsp_data mcbsp_data[NUM_LINKS];
 
 /*
@@ -153,13 +151,13 @@ static const unsigned long omap34xx_mcbsp_port[][2] = {};
 static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
        struct omap_pcm_dma_data *dma_data;
        int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id);
        int words;
 
-       dma_data = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
        if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
@@ -203,11 +201,9 @@ static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
 }
 
 static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
-                                 struct snd_soc_dai *dai)
+                                 struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
        int bus_id = mcbsp_data->bus_id;
        int err = 0;
 
@@ -249,11 +245,9 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
 }
 
 static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
-                                   struct snd_soc_dai *dai)
+                                   struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
 
        if (!cpu_dai->active) {
                omap_mcbsp_free(mcbsp_data->bus_id);
@@ -262,11 +256,9 @@ static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
 }
 
 static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd,
-                                 struct snd_soc_dai *dai)
+                                 struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
        int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 
        switch (cmd) {
@@ -295,8 +287,8 @@ static snd_pcm_sframes_t omap_mcbsp_dai_delay(
                        struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
        u16 fifo_use;
        snd_pcm_sframes_t delay;
 
@@ -317,11 +309,9 @@ static snd_pcm_sframes_t omap_mcbsp_dai_delay(
 
 static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
                                    struct snd_pcm_hw_params *params,
-                                   struct snd_soc_dai *dai)
+                                   struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
        struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
        struct omap_pcm_dma_data *dma_data;
        int dma, bus_id = mcbsp_data->bus_id;
@@ -496,7 +486,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
 static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                                      unsigned int fmt)
 {
-       struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
        struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
        unsigned int temp_fmt = fmt;
 
@@ -596,7 +586,7 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
                                     int div_id, int div)
 {
-       struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
        struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
 
        if (div_id != OMAP_MCBSP_CLKGDV)
@@ -699,7 +689,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                                         int clk_id, unsigned int freq,
                                         int dir)
 {
-       struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
        struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
        int err = 0;
 
@@ -733,7 +723,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        return err;
 }
 
-static struct snd_soc_dai_ops omap_mcbsp_dai_ops = {
+static struct snd_soc_dai_ops mcbsp_dai_ops = {
        .startup        = omap_mcbsp_dai_startup,
        .shutdown       = omap_mcbsp_dai_shutdown,
        .trigger        = omap_mcbsp_dai_trigger,
@@ -744,43 +734,32 @@ static struct snd_soc_dai_ops omap_mcbsp_dai_ops = {
        .set_sysclk     = omap_mcbsp_dai_set_dai_sysclk,
 };
 
-#define OMAP_MCBSP_DAI_BUILDER(link_id)                                \
-{                                                              \
-       .name = "omap-mcbsp-dai-"#link_id,                      \
-       .id = (link_id),                                        \
-       .playback = {                                           \
-               .channels_min = 1,                              \
-               .channels_max = 16,                             \
-               .rates = OMAP_MCBSP_RATES,                      \
-               .formats = SNDRV_PCM_FMTBIT_S16_LE |            \
-                          SNDRV_PCM_FMTBIT_S32_LE,             \
-       },                                                      \
-       .capture = {                                            \
-               .channels_min = 1,                              \
-               .channels_max = 16,                             \
-               .rates = OMAP_MCBSP_RATES,                      \
-               .formats = SNDRV_PCM_FMTBIT_S16_LE |            \
-                          SNDRV_PCM_FMTBIT_S32_LE,             \
-       },                                                      \
-       .ops = &omap_mcbsp_dai_ops,                             \
-       .private_data = &mcbsp_data[(link_id)].bus_id,          \
+static int mcbsp_dai_probe(struct snd_soc_dai *dai)
+{
+       mcbsp_data[dai->id].bus_id = dai->id;
+       snd_soc_dai_set_drvdata(dai, &mcbsp_data[dai->id].bus_id);
+       return 0;
 }
 
-struct snd_soc_dai omap_mcbsp_dai[] = {
-       OMAP_MCBSP_DAI_BUILDER(0),
-       OMAP_MCBSP_DAI_BUILDER(1),
-#if NUM_LINKS >= 3
-       OMAP_MCBSP_DAI_BUILDER(2),
-#endif
-#if NUM_LINKS == 5
-       OMAP_MCBSP_DAI_BUILDER(3),
-       OMAP_MCBSP_DAI_BUILDER(4),
-#endif
+static struct snd_soc_dai_driver omap_mcbsp_dai =
+{
+       .probe = mcbsp_dai_probe,
+       .playback = {
+               .channels_min = 1,
+               .channels_max = 16,
+               .rates = OMAP_MCBSP_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+       },
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 16,
+               .rates = OMAP_MCBSP_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+       },
+       .ops = &mcbsp_dai_ops,
 };
 
-EXPORT_SYMBOL_GPL(omap_mcbsp_dai);
-
-int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
+static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
                        struct snd_ctl_elem_info *uinfo)
 {
        struct soc_mixer_control *mc =
@@ -910,16 +889,36 @@ int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id)
 }
 EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);
 
+static __devinit int asoc_mcbsp_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai);
+}
+
+static int __devexit asoc_mcbsp_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver asoc_mcbsp_driver = {
+       .driver = {
+                       .name = "omap-mcbsp-dai",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = asoc_mcbsp_probe,
+       .remove = __devexit_p(asoc_mcbsp_remove),
+};
+
 static int __init snd_omap_mcbsp_init(void)
 {
-       return snd_soc_register_dais(omap_mcbsp_dai,
-                                    ARRAY_SIZE(omap_mcbsp_dai));
+       return platform_driver_register(&asoc_mcbsp_driver);
 }
 module_init(snd_omap_mcbsp_init);
 
 static void __exit snd_omap_mcbsp_exit(void)
 {
-       snd_soc_unregister_dais(omap_mcbsp_dai, ARRAY_SIZE(omap_mcbsp_dai));
+       platform_driver_unregister(&asoc_mcbsp_driver);
 }
 module_exit(snd_omap_mcbsp_exit);
 
index 6c363e5f43876aa1f4d71906f7c09b2b40b8cd59..ffdcc5abb7b9619b99199ca4b7e079242ad16306 100644 (file)
@@ -55,8 +55,6 @@ enum omap_mcbsp_div {
 #define NUM_LINKS      5
 #endif
 
-extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS];
-
 int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id);
 
 #endif
index b7f4f7e015f3f4ef4c0dc91f46e1e4573ce39259..f161c2f5ed36b1e5f20206924d7fe9a0285c6d17 100644 (file)
@@ -36,7 +36,6 @@
 #include <plat/dma.h>
 #include <plat/mcbsp.h>
 #include "mcpdm.h"
-#include "omap-mcpdm.h"
 #include "omap-pcm.h"
 
 struct omap_mcpdm_data {
@@ -89,11 +88,9 @@ static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
 static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
                                  struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        int err = 0;
 
-       if (!cpu_dai->active)
+       if (!dai->active)
                err = omap_mcpdm_request();
 
        return err;
@@ -102,19 +99,14 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
 static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
                                    struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-
-       if (!cpu_dai->active)
+       if (!dai->active)
                omap_mcpdm_free();
 }
 
 static int omap_mcpdm_dai_trigger(struct snd_pcm_substream *substream, int cmd,
                                  struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
+       struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
        int stream = substream->stream;
        int err = 0;
 
@@ -143,14 +135,12 @@ static int omap_mcpdm_dai_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->dai->cpu_dai;
-       struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
+       struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
        struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
        int stream = substream->stream;
        int channels, err, link_mask = 0;
 
-       snd_soc_dai_set_dma_data(cpu_dai, substream,
+       snd_soc_dai_set_dma_data(dai, substream,
                                 &omap_mcpdm_dai_dma_params[stream]);
 
        channels = params_channels(params);
@@ -189,9 +179,7 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
 static int omap_mcpdm_dai_hw_free(struct snd_pcm_substream *substream,
                                  struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct omap_mcpdm_data *mcpdm_priv = cpu_dai->private_data;
+       struct omap_mcpdm_data *mcpdm_priv = snd_soc_dai_get_drvdata(dai);
        struct omap_mcpdm_link *mcpdm_links = mcpdm_priv->links;
        int stream = substream->stream;
        int err;
@@ -215,9 +203,14 @@ static struct snd_soc_dai_ops omap_mcpdm_dai_ops = {
 #define OMAP_MCPDM_RATES       (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 #define OMAP_MCPDM_FORMATS     (SNDRV_PCM_FMTBIT_S32_LE)
 
-struct snd_soc_dai omap_mcpdm_dai = {
-       .name = "omap-mcpdm",
-       .id = -1,
+static int omap_mcpdm_dai_probe(struct snd_soc_dai *dai)
+{
+       snd_soc_dai_set_drvdata(dai, &mcpdm_data);
+       return 0;
+}
+
+static struct snd_soc_dai_driver omap_mcpdm_dai = {
+       .probe = omap_mcpdm_dai_probe,
        .playback = {
                .channels_min = 1,
                .channels_max = 4,
@@ -231,19 +224,47 @@ struct snd_soc_dai omap_mcpdm_dai = {
                .formats = OMAP_MCPDM_FORMATS,
        },
        .ops = &omap_mcpdm_dai_ops,
-       .private_data = &mcpdm_data,
 };
-EXPORT_SYMBOL_GPL(omap_mcpdm_dai);
+
+static __devinit int asoc_mcpdm_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       ret = omap_mcpdm_probe(pdev);
+       if (ret < 0)
+               return ret;
+       ret = snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
+       if (ret < 0)
+               omap_mcpdm_remove(pdev);
+       return ret;
+}
+
+static int __devexit asoc_mcpdm_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&pdev->dev);
+       omap_mcpdm_remove(pdev);
+       return 0;
+}
+
+static struct platform_driver asoc_mcpdm_driver = {
+       .driver = {
+                       .name = "omap-mcpdm-dai",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = asoc_mcpdm_probe,
+       .remove = __devexit_p(asoc_mcpdm_remove),
+};
 
 static int __init snd_omap_mcpdm_init(void)
 {
-       return snd_soc_register_dai(&omap_mcpdm_dai);
+       return platform_driver_register(&asoc_mcpdm_driver);
 }
 module_init(snd_omap_mcpdm_init);
 
 static void __exit snd_omap_mcpdm_exit(void)
 {
-       snd_soc_unregister_dai(&omap_mcpdm_dai);
+       platform_driver_unregister(&asoc_mcpdm_driver);
 }
 module_exit(snd_omap_mcpdm_exit);
 
diff --git a/sound/soc/omap/omap-mcpdm.h b/sound/soc/omap/omap-mcpdm.h
deleted file mode 100644 (file)
index 73b80d5..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * omap-mcpdm.h
- *
- * Copyright (C) 2009 Texas Instruments
- *
- * Contact: Misael Lopez Cruz <x0052729@ti.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.
- *
- * 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
- *
- */
-
-#ifndef __OMAP_MCPDM_H__
-#define __OMAP_MCPDM_H__
-
-extern struct snd_soc_dai omap_mcpdm_dai;
-
-#endif /* End of __OMAP_MCPDM_H__ */
index 1e521904ea64efabd199c1d334adb2c5a247c799..8caeb8d305c3b0308f0592c7fa8d3461d6fce87f 100644 (file)
@@ -101,9 +101,10 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct omap_runtime_data *prtd = runtime->private_data;
        struct omap_pcm_dma_data *dma_data;
+
        int err = 0;
 
-       dma_data = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        /* return if this is a bufferless transfer e.g.
         * codec <--> BT codec or GSM modem -- lg FIXME */
@@ -374,14 +375,14 @@ static int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(64);
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = omap_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = omap_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -392,25 +393,45 @@ out:
        return ret;
 }
 
-struct snd_soc_platform omap_soc_platform = {
-       .name           = "omap-pcm-audio",
-       .pcm_ops        = &omap_pcm_ops,
+static struct snd_soc_platform_driver omap_soc_platform = {
+       .ops            = &omap_pcm_ops,
        .pcm_new        = omap_pcm_new,
        .pcm_free       = omap_pcm_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(omap_soc_platform);
 
-static int __init omap_soc_platform_init(void)
+static __devinit int omap_pcm_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_platform(&pdev->dev,
+                       &omap_soc_platform);
+}
+
+static int __devexit omap_pcm_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver omap_pcm_driver = {
+       .driver = {
+                       .name = "omap-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = omap_pcm_probe,
+       .remove = __devexit_p(omap_pcm_remove),
+};
+
+static int __init snd_omap_pcm_init(void)
 {
-       return snd_soc_register_platform(&omap_soc_platform);
+       return platform_driver_register(&omap_pcm_driver);
 }
-module_init(omap_soc_platform_init);
+module_init(snd_omap_pcm_init);
 
-static void __exit omap_soc_platform_exit(void)
+static void __exit snd_omap_pcm_exit(void)
 {
-       snd_soc_unregister_platform(&omap_soc_platform);
+       platform_driver_unregister(&omap_pcm_driver);
 }
-module_exit(omap_soc_platform_exit);
+module_exit(snd_omap_pcm_exit);
 
 MODULE_AUTHOR("Jarkko Nikula <jhnikula@gmail.com>");
 MODULE_DESCRIPTION("OMAP PCM DMA module");
index b19975d269076bcf3b9bc46241846e29e5f26aae..fea0515331fb6721f1f91b95ee565f150d5f3e37 100644 (file)
@@ -35,6 +35,4 @@ struct omap_pcm_dma_data {
        int             packet_size;    /* packet size only in PACKET mode */
 };
 
-extern struct snd_soc_platform omap_soc_platform;
-
 #endif
index c7adea38274cb25f101d7dda9e6296eb4ff4e3f3..cf3fc8a675b5fc504169f35aaf418095d7da71d0 100644 (file)
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
-#include "../codecs/twl4030.h"
 
 static int omap2evm_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params,
-       struct snd_soc_dai *dai)
+       struct snd_pcm_hw_params *params)
 {
        struct snd_soc_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* Set codec DAI configuration */
@@ -85,35 +83,28 @@ static struct snd_soc_ops omap2evm_ops = {
 static struct snd_soc_dai_link omap2evm_dai = {
        .name = "TWL4030",
        .stream_name = "TWL4030",
-       .cpu_dai = &omap_mcbsp_dai[0],
-       .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+       .cpu_dai_name = "omap-mcbsp-dai.1",
+       .codec_dai_name = "twl4030-hifi",
+       .platform_name = "omap-pcm-audio",
+       .codec_name = "twl4030-codec",
        .ops = &omap2evm_ops,
 };
 
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_omap2evm = {
        .name = "omap2evm",
-       .platform = &omap_soc_platform,
        .dai_link = &omap2evm_dai,
        .num_links = 1,
 };
 
-/* Audio subsystem */
-static struct snd_soc_device omap2evm_snd_devdata = {
-       .card = &snd_soc_omap2evm,
-       .codec_dev = &soc_codec_dev_twl4030,
-};
-
 static struct platform_device *omap2evm_snd_device;
 
 static int __init omap2evm_soc_init(void)
 {
        int ret;
 
-       if (!machine_is_omap2evm()) {
-               pr_debug("Not omap2evm!\n");
+       if (!machine_is_omap2evm())
                return -ENODEV;
-       }
        printk(KERN_INFO "omap2evm SoC init\n");
 
        omap2evm_snd_device = platform_device_alloc("soc-audio", -1);
@@ -122,9 +113,7 @@ static int __init omap2evm_soc_init(void)
                return -ENOMEM;
        }
 
-       platform_set_drvdata(omap2evm_snd_device, &omap2evm_snd_devdata);
-       omap2evm_snd_devdata.dev = &omap2evm_snd_device->dev;
-       *(unsigned int *)omap2evm_dai.cpu_dai->private_data = 1; /* McBSP2 */
+       platform_set_drvdata(omap2evm_snd_device, &snd_soc_omap2evm);
 
        ret = platform_device_add(omap2evm_snd_device);
        if (ret)
index 240e0975dd6a716e47546a54deb83cecffb9b960..e56832b0c444083def074b75f3c788d9c89d07d3 100644 (file)
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
-#include "../codecs/twl4030.h"
 
 static int omap3beagle_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int fmt;
        int ret;
 
@@ -92,35 +91,29 @@ static struct snd_soc_ops omap3beagle_ops = {
 static struct snd_soc_dai_link omap3beagle_dai = {
        .name = "TWL4030",
        .stream_name = "TWL4030",
-       .cpu_dai = &omap_mcbsp_dai[0],
-       .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+       .cpu_dai_name = "omap-mcbsp-dai.1",
+       .platform_name = "omap-pcm-audio",
+       .codec_dai_name = "twl4030-hifi",
+       .codec_name = "twl4030-codec",
        .ops = &omap3beagle_ops,
 };
 
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_omap3beagle = {
        .name = "omap3beagle",
-       .platform = &omap_soc_platform,
+       .owner = THIS_MODULE,
        .dai_link = &omap3beagle_dai,
        .num_links = 1,
 };
 
-/* Audio subsystem */
-static struct snd_soc_device omap3beagle_snd_devdata = {
-       .card = &snd_soc_omap3beagle,
-       .codec_dev = &soc_codec_dev_twl4030,
-};
-
 static struct platform_device *omap3beagle_snd_device;
 
 static int __init omap3beagle_soc_init(void)
 {
        int ret;
 
-       if (!(machine_is_omap3_beagle() || machine_is_devkit8000())) {
-               pr_debug("Not OMAP3 Beagle or Devkit8000!\n");
+       if (!(machine_is_omap3_beagle() || machine_is_devkit8000()))
                return -ENODEV;
-       }
        pr_info("OMAP3 Beagle/Devkit8000 SoC init\n");
 
        omap3beagle_snd_device = platform_device_alloc("soc-audio", -1);
@@ -129,9 +122,7 @@ static int __init omap3beagle_soc_init(void)
                return -ENOMEM;
        }
 
-       platform_set_drvdata(omap3beagle_snd_device, &omap3beagle_snd_devdata);
-       omap3beagle_snd_devdata.dev = &omap3beagle_snd_device->dev;
-       *(unsigned int *)omap3beagle_dai.cpu_dai->private_data = 1; /* McBSP2 */
+       platform_set_drvdata(omap3beagle_snd_device, &snd_soc_omap3beagle);
 
        ret = platform_device_add(omap3beagle_snd_device);
        if (ret)
index dfcb344092e41c0506e4f243af3c70920a4cc5c0..810f1e36da2127e019570563d8d1d622939a3e48 100644 (file)
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
-#include "../codecs/twl4030.h"
 
 static int omap3evm_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* Set codec DAI configuration */
@@ -80,42 +79,28 @@ static struct snd_soc_ops omap3evm_ops = {
 static struct snd_soc_dai_link omap3evm_dai = {
        .name           = "TWL4030",
        .stream_name    = "TWL4030",
-       .cpu_dai        = &omap_mcbsp_dai[0],
-       .codec_dai      = &twl4030_dai[TWL4030_DAI_HIFI],
+       .cpu_dai_name = "omap-mcbsp-dai.1",
+       .codec_dai_name = "twl4030-hifi",
+       .platform_name = "omap-pcm-audio",
+       .codec_name = "twl4030-codec",
        .ops            = &omap3evm_ops,
 };
 
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_omap3evm = {
        .name = "omap3evm",
-       .platform = &omap_soc_platform,
        .dai_link = &omap3evm_dai,
        .num_links = 1,
 };
 
-/* twl4030 setup */
-static struct twl4030_setup_data twl4030_setup = {
-       .ramp_delay_value = 4,
-       .sysclk = 26000,
-};
-
-/* Audio subsystem */
-static struct snd_soc_device omap3evm_snd_devdata = {
-       .card = &snd_soc_omap3evm,
-       .codec_dev = &soc_codec_dev_twl4030,
-       .codec_data = &twl4030_setup,
-};
-
 static struct platform_device *omap3evm_snd_device;
 
 static int __init omap3evm_soc_init(void)
 {
        int ret;
 
-       if (!machine_is_omap3evm()) {
-               pr_err("Not OMAP3 EVM!\n");
+       if (!machine_is_omap3evm())
                return -ENODEV;
-       }
        pr_info("OMAP3 EVM SoC init\n");
 
        omap3evm_snd_device = platform_device_alloc("soc-audio", -1);
@@ -124,10 +109,7 @@ static int __init omap3evm_soc_init(void)
                return -ENOMEM;
        }
 
-       platform_set_drvdata(omap3evm_snd_device, &omap3evm_snd_devdata);
-       omap3evm_snd_devdata.dev = &omap3evm_snd_device->dev;
-       *(unsigned int *)omap3evm_dai.cpu_dai->private_data = 1;
-
+       platform_set_drvdata(omap3evm_snd_device, &snd_soc_omap3evm);
        ret = platform_device_add(omap3evm_snd_device);
        if (ret)
                goto err1;
index 9eecac135bbbca973645d4391f8f3a6bcff36546..dbd9d96b5f9243c3e0cd0aafd3181e08cce84a3a 100644 (file)
 #include <sound/soc-dapm.h>
 
 #include <asm/mach-types.h>
+#include <plat/mcbsp.h>
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
-#include "../codecs/twl4030.h"
 
 #define OMAP3_PANDORA_DAC_POWER_GPIO   118
 #define OMAP3_PANDORA_AMP_POWER_GPIO   14
@@ -47,8 +47,8 @@ static int omap3pandora_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                  SND_SOC_DAIFMT_CBS_CFS;
        int ret;
@@ -167,8 +167,9 @@ static const struct snd_soc_dapm_route omap3pandora_in_map[] = {
        {"Mic Bias 2", NULL, "Mic (external)"},
 };
 
-static int omap3pandora_out_init(struct snd_soc_codec *codec)
+static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int ret;
 
        /* All TWL4030 output pins are floating */
@@ -194,8 +195,9 @@ static int omap3pandora_out_init(struct snd_soc_codec *codec)
        return snd_soc_dapm_sync(codec);
 }
 
-static int omap3pandora_in_init(struct snd_soc_codec *codec)
+static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int ret;
 
        /* Not comnnected */
@@ -224,15 +226,19 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
        {
                .name = "PCM1773",
                .stream_name = "HiFi Out",
-               .cpu_dai = &omap_mcbsp_dai[0],
-               .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+               .cpu_dai_name = "omap-mcbsp-dai.1",
+               .codec_dai_name = "twl4030-hifi",
+               .platform_name = "omap-pcm-audio",
+               .codec_name = "twl4030-codec",
                .ops = &omap3pandora_ops,
                .init = omap3pandora_out_init,
        }, {
                .name = "TWL4030",
                .stream_name = "Line/Mic In",
-               .cpu_dai = &omap_mcbsp_dai[1],
-               .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+               .cpu_dai_name = "omap-mcbsp-dai.3",
+               .codec_dai_name = "twl4030-hifi",
+               .platform_name = "omap-pcm-audio",
+               .codec_name = "twl4030-codec",
                .ops = &omap3pandora_ops,
                .init = omap3pandora_in_init,
        }
@@ -241,17 +247,10 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
 /* SoC card */
 static struct snd_soc_card snd_soc_card_omap3pandora = {
        .name = "omap3pandora",
-       .platform = &omap_soc_platform,
        .dai_link = omap3pandora_dai,
        .num_links = ARRAY_SIZE(omap3pandora_dai),
 };
 
-/* Audio subsystem */
-static struct snd_soc_device omap3pandora_snd_data = {
-       .card = &snd_soc_card_omap3pandora,
-       .codec_dev = &soc_codec_dev_twl4030,
-};
-
 static struct platform_device *omap3pandora_snd_device;
 
 static int __init omap3pandora_soc_init(void)
@@ -294,10 +293,7 @@ static int __init omap3pandora_soc_init(void)
                goto fail1;
        }
 
-       platform_set_drvdata(omap3pandora_snd_device, &omap3pandora_snd_data);
-       omap3pandora_snd_data.dev = &omap3pandora_snd_device->dev;
-       *(unsigned int *)omap_mcbsp_dai[0].private_data = 1; /* McBSP2 */
-       *(unsigned int *)omap_mcbsp_dai[1].private_data = 3; /* McBSP4 */
+       platform_set_drvdata(omap3pandora_snd_device, &snd_soc_card_omap3pandora);
 
        ret = platform_device_add(omap3pandora_snd_device);
        if (ret) {
index 498ca2e035197af484f0696bee925115fd959558..f0e6625564287df0b33643395af20c1849b8a596 100644 (file)
@@ -55,8 +55,8 @@ static int osk_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int err;
 
        /* Set codec DAI configuration */
@@ -113,8 +113,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"MICIN", NULL, "Mic Jack"},
 };
 
-static int osk_tlv320aic23_init(struct snd_soc_codec *codec)
+static int osk_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* Add osk5912 specific widgets */
        snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
@@ -136,8 +137,10 @@ static int osk_tlv320aic23_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link osk_dai = {
        .name = "TLV320AIC23",
        .stream_name = "AIC23",
-       .cpu_dai = &omap_mcbsp_dai[0],
-       .codec_dai = &tlv320aic23_dai,
+       .cpu_dai_name = "omap-mcbsp-dai.0",
+       .codec_dai_name = "tlv320aic23-hifi",
+       .platform_name = "omap-pcm-audio",
+       .codec_name = "tlv320aic23-codec",
        .init = osk_tlv320aic23_init,
        .ops = &osk_ops,
 };
@@ -145,17 +148,10 @@ static struct snd_soc_dai_link osk_dai = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_card_osk = {
        .name = "OSK5912",
-       .platform = &omap_soc_platform,
        .dai_link = &osk_dai,
        .num_links = 1,
 };
 
-/* Audio subsystem */
-static struct snd_soc_device osk_snd_devdata = {
-       .card = &snd_soc_card_osk,
-       .codec_dev = &soc_codec_dev_tlv320aic23,
-};
-
 static struct platform_device *osk_snd_device;
 
 static int __init osk_soc_init(void)
@@ -171,9 +167,7 @@ static int __init osk_soc_init(void)
        if (!osk_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(osk_snd_device, &osk_snd_devdata);
-       osk_snd_devdata.dev = &osk_snd_device->dev;
-       *(unsigned int *)osk_dai.cpu_dai->private_data = 0;     /* McBSP1 */
+       platform_set_drvdata(osk_snd_device, &snd_soc_card_osk);
        err = platform_device_add(osk_snd_device);
        if (err)
                goto err1;
index c25f5276ad6f0135d1699548da4d3d6ad11b56f5..e95a607937de7a221998766dc0a2214e04b251f9 100644 (file)
 
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
-#include "../codecs/twl4030.h"
 
 static int overo_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* Set codec DAI configuration */
@@ -82,25 +81,20 @@ static struct snd_soc_ops overo_ops = {
 static struct snd_soc_dai_link overo_dai = {
        .name = "TWL4030",
        .stream_name = "TWL4030",
-       .cpu_dai = &omap_mcbsp_dai[0],
-       .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+       .cpu_dai_name = "omap-mcbsp-dai.1",
+       .codec_dai_name = "twl4030-hifi",
+       .platform_name = "omap-pcm-audio",
+       .codec_name = "twl4030-codec",
        .ops = &overo_ops,
 };
 
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_card_overo = {
        .name = "overo",
-       .platform = &omap_soc_platform,
        .dai_link = &overo_dai,
        .num_links = 1,
 };
 
-/* Audio subsystem */
-static struct snd_soc_device overo_snd_devdata = {
-       .card = &snd_soc_card_overo,
-       .codec_dev = &soc_codec_dev_twl4030,
-};
-
 static struct platform_device *overo_snd_device;
 
 static int __init overo_soc_init(void)
@@ -119,9 +113,7 @@ static int __init overo_soc_init(void)
                return -ENOMEM;
        }
 
-       platform_set_drvdata(overo_snd_device, &overo_snd_devdata);
-       overo_snd_devdata.dev = &overo_snd_device->dev;
-       *(unsigned int *)overo_dai.cpu_dai->private_data = 1; /* McBSP2 */
+       platform_set_drvdata(overo_snd_device, &snd_soc_card_overo);
 
        ret = platform_device_add(overo_snd_device);
        if (ret)
index 88052d29617f9da25aac0eb687301d9e6cd207ce..04b5723bf89b5b4f289a6339e97f661fbd9dbccf 100644 (file)
@@ -31,6 +31,7 @@
 #include <sound/pcm.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
+#include <plat/mcbsp.h>
 
 #include <asm/mach-types.h>
 
@@ -76,7 +77,7 @@ static int rx51_startup(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        snd_pcm_hw_constraint_minmax(runtime,
                                     SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
@@ -89,8 +90,8 @@ static int rx51_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int err;
 
        /* Set codec DAI configuration */
@@ -145,9 +146,9 @@ static int rx51_spk_event(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *k, int event)
 {
        if (SND_SOC_DAPM_EVENT_ON(event))
-               gpio_set_value(RX51_SPEAKER_AMP_TWL_GPIO, 1);
+               gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 1);
        else
-               gpio_set_value(RX51_SPEAKER_AMP_TWL_GPIO, 0);
+               gpio_set_value_cansleep(RX51_SPEAKER_AMP_TWL_GPIO, 0);
 
        return 0;
 }
@@ -240,9 +241,9 @@ static const struct snd_kcontrol_new aic34_rx51_controls[] = {
                     rx51_get_jack, rx51_set_jack),
 };
 
-static int rx51_aic34_init(struct snd_soc_codec *codec)
+static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_card *card = codec->socdev->card;
+       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        /* Set up NC codec pins */
@@ -266,7 +267,7 @@ static int rx51_aic34_init(struct snd_soc_codec *codec)
        snd_soc_dapm_sync(codec);
 
        /* AV jack detection */
-       err = snd_soc_jack_new(card, "AV Jack",
+       err = snd_soc_jack_new(codec, "AV Jack",
                               SND_JACK_VIDEOOUT, &rx51_av_jack);
        if (err)
                return err;
@@ -282,32 +283,20 @@ static struct snd_soc_dai_link rx51_dai[] = {
        {
                .name = "TLV320AIC34",
                .stream_name = "AIC34",
-               .cpu_dai = &omap_mcbsp_dai[0],
-               .codec_dai = &aic3x_dai,
+               .cpu_dai_name = "omap-mcbsp-dai.1",
+               .codec_dai_name = "tlv320aic3x-hifi",
+               .platform_name = "omap-pcm-audio",
+               .codec_name = "tlv320aic3x-codec.2-0018",
                .init = rx51_aic34_init,
                .ops = &rx51_ops,
        },
 };
 
-/* Audio private data */
-static struct aic3x_setup_data rx51_aic34_setup = {
-       .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
-       .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
-};
-
 /* Audio card */
 static struct snd_soc_card rx51_sound_card = {
        .name = "RX-51",
        .dai_link = rx51_dai,
        .num_links = ARRAY_SIZE(rx51_dai),
-       .platform = &omap_soc_platform,
-};
-
-/* Audio subsystem */
-static struct snd_soc_device rx51_snd_devdata = {
-       .card = &rx51_sound_card,
-       .codec_dev = &soc_codec_dev_aic3x,
-       .codec_data = &rx51_aic34_setup,
 };
 
 static struct platform_device *rx51_snd_device;
@@ -330,9 +319,7 @@ static int __init rx51_soc_init(void)
                goto err1;
        }
 
-       platform_set_drvdata(rx51_snd_device, &rx51_snd_devdata);
-       rx51_snd_devdata.dev = &rx51_snd_device->dev;
-       *(unsigned int *)rx51_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
+       platform_set_drvdata(rx51_snd_device, &rx51_sound_card);
 
        err = platform_device_add(rx51_snd_device);
        if (err)
index 3c85c0f92823b82a87affec967b663966c279f4d..07fbcf7d2411ea6d0a80f5c390ba629f89a5e2ca 100644 (file)
 #include <mach/gpio.h>
 #include <plat/mcbsp.h>
 
+/* Register descriptions for twl4030 codec part */
+#include <linux/mfd/twl4030-codec.h>
+
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
-#include "../codecs/twl4030.h"
 
 /* TWL4030 PMBR1 Register */
 #define TWL4030_INTBR_PMBR1            0x0D
@@ -51,8 +53,8 @@ static int sdp3430_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* Set codec DAI configuration */
@@ -94,8 +96,8 @@ static int sdp3430_hw_voice_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* Set codec DAI configuration */
@@ -186,8 +188,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Headset Stereophone", NULL, "HSOR"},
 };
 
-static int sdp3430_twl4030_init(struct snd_soc_codec *codec)
+static int sdp3430_twl4030_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int ret;
 
        /* Add SDP3430 specific widgets */
@@ -225,7 +228,7 @@ static int sdp3430_twl4030_init(struct snd_soc_codec *codec)
                return ret;
 
        /* Headset jack detection */
-       ret = snd_soc_jack_new(&snd_soc_sdp3430, "Headset Jack",
+       ret = snd_soc_jack_new(codec, "Headset Jack",
                                SND_JACK_HEADSET, &hs_jack);
        if (ret)
                return ret;
@@ -241,14 +244,15 @@ static int sdp3430_twl4030_init(struct snd_soc_codec *codec)
        return ret;
 }
 
-static int sdp3430_twl4030_voice_init(struct snd_soc_codec *codec)
+static int sdp3430_twl4030_voice_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        unsigned short reg;
 
        /* Enable voice interface */
-       reg = codec->read(codec, TWL4030_REG_VOICE_IF);
+       reg = codec->driver->read(codec, TWL4030_REG_VOICE_IF);
        reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN;
-       codec->write(codec, TWL4030_REG_VOICE_IF, reg);
+       codec->driver->write(codec, TWL4030_REG_VOICE_IF, reg);
 
        return 0;
 }
@@ -259,16 +263,20 @@ static struct snd_soc_dai_link sdp3430_dai[] = {
        {
                .name = "TWL4030 I2S",
                .stream_name = "TWL4030 Audio",
-               .cpu_dai = &omap_mcbsp_dai[0],
-               .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+               .cpu_dai_name = "omap-mcbsp-dai.1",
+               .codec_dai_name = "twl4030-hifi",
+               .platform_name = "omap-pcm-audio",
+               .codec_name = "twl4030-codec",
                .init = sdp3430_twl4030_init,
                .ops = &sdp3430_ops,
        },
        {
                .name = "TWL4030 PCM",
                .stream_name = "TWL4030 Voice",
-               .cpu_dai = &omap_mcbsp_dai[1],
-               .codec_dai = &twl4030_dai[TWL4030_DAI_VOICE],
+               .cpu_dai_name = "omap-mcbsp-dai.2",
+               .codec_dai_name = "twl4030-voice",
+               .platform_name = "omap-pcm-audio",
+               .codec_name = "twl4030-codec",
                .init = sdp3430_twl4030_voice_init,
                .ops = &sdp3430_voice_ops,
        },
@@ -277,25 +285,10 @@ static struct snd_soc_dai_link sdp3430_dai[] = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_sdp3430 = {
        .name = "SDP3430",
-       .platform = &omap_soc_platform,
        .dai_link = sdp3430_dai,
        .num_links = ARRAY_SIZE(sdp3430_dai),
 };
 
-/* twl4030 setup */
-static struct twl4030_setup_data twl4030_setup = {
-       .ramp_delay_value = 3,
-       .sysclk = 26000,
-       .hs_extmute = 1,
-};
-
-/* Audio subsystem */
-static struct snd_soc_device sdp3430_snd_devdata = {
-       .card = &snd_soc_sdp3430,
-       .codec_dev = &soc_codec_dev_twl4030,
-       .codec_data = &twl4030_setup,
-};
-
 static struct platform_device *sdp3430_snd_device;
 
 static int __init sdp3430_soc_init(void)
@@ -303,10 +296,8 @@ static int __init sdp3430_soc_init(void)
        int ret;
        u8 pin_mux;
 
-       if (!machine_is_omap_3430sdp()) {
-               pr_debug("Not SDP3430!\n");
+       if (!machine_is_omap_3430sdp())
                return -ENODEV;
-       }
        printk(KERN_INFO "SDP3430 SoC init\n");
 
        sdp3430_snd_device = platform_device_alloc("soc-audio", -1);
@@ -315,10 +306,7 @@ static int __init sdp3430_soc_init(void)
                return -ENOMEM;
        }
 
-       platform_set_drvdata(sdp3430_snd_device, &sdp3430_snd_devdata);
-       sdp3430_snd_devdata.dev = &sdp3430_snd_device->dev;
-       *(unsigned int *)sdp3430_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
-       *(unsigned int *)sdp3430_dai[1].cpu_dai->private_data = 2; /* McBSP3 */
+       platform_set_drvdata(sdp3430_snd_device, &snd_soc_sdp3430);
 
        /* Set TWL4030 GPIO6 as EXTMUTE signal */
        twl_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux,
index 4ebbde6b565f4fbfe6beafc0ab7fadf799171777..4b4463db6ba0330a0c29b401083e13cbc671bfd0 100644 (file)
@@ -31,7 +31,6 @@
 #include <plat/mux.h>
 
 #include "mcpdm.h"
-#include "omap-mcpdm.h"
 #include "omap-pcm.h"
 #include "../codecs/twl6040.h"
 
@@ -41,7 +40,7 @@ static int sdp4430_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 *codec_dai = rtd->codec_dai;
        int clk_id, freq;
        int ret;
 
@@ -60,6 +59,7 @@ static int sdp4430_hw_params(struct snd_pcm_substream *substream,
                printk(KERN_ERR "can't set codec system clock\n");
                return ret;
        }
+       return ret;
 }
 
 static struct snd_soc_ops sdp4430_ops = {
@@ -126,8 +126,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Earphone Spk", NULL, "EP"},
 };
 
-static int sdp4430_twl6040_init(struct snd_soc_codec *codec)
+static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int ret;
 
        /* Add SDP4430 specific controls */
@@ -164,8 +165,10 @@ static int sdp4430_twl6040_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link sdp4430_dai = {
        .name = "TWL6040",
        .stream_name = "TWL6040",
-       .cpu_dai = &omap_mcpdm_dai,
-       .codec_dai = &twl6040_dai,
+       .cpu_dai_name ="omap-mcpdm-dai",
+       .codec_dai_name = "twl6040-hifi",
+       .platform_name = "omap-pcm-audio",
+       .codec_name = "twl6040-codec",
        .init = sdp4430_twl6040_init,
        .ops = &sdp4430_ops,
 };
@@ -173,27 +176,18 @@ static struct snd_soc_dai_link sdp4430_dai = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_sdp4430 = {
        .name = "SDP4430",
-       .platform = &omap_soc_platform,
        .dai_link = &sdp4430_dai,
        .num_links = 1,
 };
 
-/* Audio subsystem */
-static struct snd_soc_device sdp4430_snd_devdata = {
-       .card = &snd_soc_sdp4430,
-       .codec_dev = &soc_codec_dev_twl6040,
-};
-
 static struct platform_device *sdp4430_snd_device;
 
 static int __init sdp4430_soc_init(void)
 {
        int ret;
 
-       if (!machine_is_omap_4430sdp()) {
-               pr_debug("Not SDP4430!\n");
+       if (!machine_is_omap_4430sdp())
                return -ENODEV;
-       }
        printk(KERN_INFO "SDP4430 SoC init\n");
 
        sdp4430_snd_device = platform_device_alloc("soc-audio", -1);
@@ -202,8 +196,7 @@ static int __init sdp4430_soc_init(void)
                return -ENOMEM;
        }
 
-       platform_set_drvdata(sdp4430_snd_device, &sdp4430_snd_devdata);
-       sdp4430_snd_devdata.dev = &sdp4430_snd_device->dev;
+       platform_set_drvdata(sdp4430_snd_device, &snd_soc_sdp4430);
 
        ret = platform_device_add(sdp4430_snd_device);
        if (ret)
index 50a94ee76ecc2cf598e24068e7daa46e58e60d92..718031eeac34805bc16909fd29cb9a87da494a59 100644 (file)
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <mach/gpio.h>
+#include <mach/board-zoom.h>
 #include <plat/mcbsp.h>
 
+/* Register descriptions for twl4030 codec part */
+#include <linux/mfd/twl4030-codec.h>
+
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
-#include "../codecs/twl4030.h"
 
 #define ZOOM2_HEADSET_MUX_GPIO         (OMAP_MAX_GPIO_LINES + 15)
-#define ZOOM2_HEADSET_EXTMUTE_GPIO     153
 
 static int zoom2_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* Set codec DAI configuration */
@@ -85,8 +87,8 @@ static int zoom2_hw_voice_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
        /* Set codec DAI configuration */
@@ -157,8 +159,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Aux In", NULL, "AUXR"},
 };
 
-static int zoom2_twl4030_init(struct snd_soc_codec *codec)
+static int zoom2_twl4030_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int ret;
 
        /* Add Zoom2 specific widgets */
@@ -192,14 +195,15 @@ static int zoom2_twl4030_init(struct snd_soc_codec *codec)
        return ret;
 }
 
-static int zoom2_twl4030_voice_init(struct snd_soc_codec *codec)
+static int zoom2_twl4030_voice_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        unsigned short reg;
 
        /* Enable voice interface */
-       reg = codec->read(codec, TWL4030_REG_VOICE_IF);
+       reg = codec->driver->read(codec, TWL4030_REG_VOICE_IF);
        reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN;
-       codec->write(codec, TWL4030_REG_VOICE_IF, reg);
+       codec->driver->write(codec, TWL4030_REG_VOICE_IF, reg);
 
        return 0;
 }
@@ -209,16 +213,20 @@ static struct snd_soc_dai_link zoom2_dai[] = {
        {
                .name = "TWL4030 I2S",
                .stream_name = "TWL4030 Audio",
-               .cpu_dai = &omap_mcbsp_dai[0],
-               .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
+               .cpu_dai_name = "omap-mcbsp-dai.1",
+               .codec_dai_name = "twl4030-hifi",
+               .platform_name = "omap-pcm-audio",
+               .codec_name = "twl4030-codec",
                .init = zoom2_twl4030_init,
                .ops = &zoom2_ops,
        },
        {
                .name = "TWL4030 PCM",
                .stream_name = "TWL4030 Voice",
-               .cpu_dai = &omap_mcbsp_dai[1],
-               .codec_dai = &twl4030_dai[TWL4030_DAI_VOICE],
+               .cpu_dai_name = "omap-mcbsp-dai.2",
+               .codec_dai_name = "twl4030-voice",
+               .platform_name = "omap-pcm-audio",
+               .codec_name = "twl4030-codec",
                .init = zoom2_twl4030_voice_init,
                .ops = &zoom2_voice_ops,
        },
@@ -227,42 +235,18 @@ static struct snd_soc_dai_link zoom2_dai[] = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_zoom2 = {
        .name = "Zoom2",
-       .platform = &omap_soc_platform,
        .dai_link = zoom2_dai,
        .num_links = ARRAY_SIZE(zoom2_dai),
 };
 
-/* EXTMUTE callback function */
-void zoom2_set_hs_extmute(int mute)
-{
-       gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute);
-}
-
-/* twl4030 setup */
-static struct twl4030_setup_data twl4030_setup = {
-       .ramp_delay_value = 3,  /* 161 ms */
-       .sysclk = 26000,
-       .hs_extmute = 1,
-       .set_hs_extmute = zoom2_set_hs_extmute,
-};
-
-/* Audio subsystem */
-static struct snd_soc_device zoom2_snd_devdata = {
-       .card = &snd_soc_zoom2,
-       .codec_dev = &soc_codec_dev_twl4030,
-       .codec_data = &twl4030_setup,
-};
-
 static struct platform_device *zoom2_snd_device;
 
 static int __init zoom2_soc_init(void)
 {
        int ret;
 
-       if (!machine_is_omap_zoom2()) {
-               pr_debug("Not Zoom2!\n");
+       if (!machine_is_omap_zoom2())
                return -ENODEV;
-       }
        printk(KERN_INFO "Zoom2 SoC init\n");
 
        zoom2_snd_device = platform_device_alloc("soc-audio", -1);
@@ -271,11 +255,7 @@ static int __init zoom2_soc_init(void)
                return -ENOMEM;
        }
 
-       platform_set_drvdata(zoom2_snd_device, &zoom2_snd_devdata);
-       zoom2_snd_devdata.dev = &zoom2_snd_device->dev;
-       *(unsigned int *)zoom2_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
-       *(unsigned int *)zoom2_dai[1].cpu_dai->private_data = 2; /* McBSP3 */
-
+       platform_set_drvdata(zoom2_snd_device, &snd_soc_zoom2);
        ret = platform_device_add(zoom2_snd_device);
        if (ret)
                goto err1;
index e30c8325f35e5fbccece8ff06f1fa8cc62951a3e..37f191bbfdd91edd64bb4abd7636600f4d694d0c 100644 (file)
@@ -117,6 +117,24 @@ config SND_PXA2XX_SOC_PALM27X
          Say Y if you want to add support for SoC audio on
          Palm T|X, T5, E2 or LifeDrive handheld computer.
 
+config SND_SOC_SAARB
+       tristate "SoC Audio support for Marvell Saarb"
+       depends on SND_PXA2XX_SOC && MACH_SAARB
+       select SND_PXA_SOC_SSP
+       select SND_SOC_88PM860X
+       help
+         Say Y if you want to add support for SoC audio on the
+         Marvell Saarb reference platform.
+
+config SND_SOC_TAVOREVB3
+       tristate "SoC Audio support for Marvell Tavor EVB3"
+       depends on SND_PXA2XX_SOC && MACH_TAVOREVB3
+       select SND_PXA_SOC_SSP
+       select SND_SOC_88PM860X
+       help
+         Say Y if you want to add support for SoC audio on the
+         Marvell Saarb reference platform.
+
 config SND_SOC_ZYLONITE
        tristate "SoC Audio support for Marvell Zylonite"
        depends on SND_PXA2XX_SOC && MACH_ZYLONITE
index caa03d8f47896cf2aa1a8060812da54e79eac7c0..07660165ec8d70cff80726004f9cec56843b2e66 100644 (file)
@@ -19,6 +19,8 @@ snd-soc-e800-objs := e800_wm9712.o
 snd-soc-spitz-objs := spitz.o
 snd-soc-em-x270-objs := em-x270.o
 snd-soc-palm27x-objs := palm27x.o
+snd-soc-saarb-objs := saarb.o
+snd-soc-tavorevb3-objs := tavorevb3.o
 snd-soc-zylonite-objs := zylonite.o
 snd-soc-magician-objs := magician.o
 snd-soc-mioa701-objs := mioa701_wm9713.o
@@ -38,6 +40,8 @@ obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o
 obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o
 obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
 obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o
+obj-$(CONFIG_SND_SOC_SAARB) += snd-soc-saarb.o
+obj-$(CONFIG_SND_SOC_TAVOREVB3) += snd-soc-tavorevb3.o
 obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
 obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o
 obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o
index fefe1a57f31adb329493bc482668a053afb65ea8..97e9423615c9c84d859a2b5b5b31695d73f4ab2f 100644 (file)
@@ -30,7 +30,6 @@
 #include <mach/audio.h>
 
 #include "../codecs/wm8731.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-i2s.h"
 
 #define CORGI_HP        0
@@ -99,7 +98,7 @@ static void corgi_ext_control(struct snd_soc_codec *codec)
 static int corgi_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* check the jack status at stream startup */
        corgi_ext_control(codec);
@@ -118,8 +117,8 @@ static int corgi_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int clk = 0;
        int ret = 0;
 
@@ -150,7 +149,7 @@ static int corgi_hw_params(struct snd_pcm_substream *substream,
                return ret;
 
        /* set the codec system clock for DAC and ADC */
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk,
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk,
                SND_SOC_CLOCK_IN);
        if (ret < 0)
                return ret;
@@ -272,8 +271,9 @@ static const struct snd_kcontrol_new wm8731_corgi_controls[] = {
 /*
  * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device
  */
-static int corgi_wm8731_init(struct snd_soc_codec *codec)
+static int corgi_wm8731_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        snd_soc_dapm_nc_pin(codec, "LLINEIN");
@@ -300,8 +300,10 @@ static int corgi_wm8731_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link corgi_dai = {
        .name = "WM8731",
        .stream_name = "WM8731",
-       .cpu_dai = &pxa_i2s_dai,
-       .codec_dai = &wm8731_dai,
+       .cpu_dai_name = "pxa-is2-dai",
+       .codec_dai_name = "wm8731-hifi",
+       .platform_name = "pxa-pcm-audio",
+       .codec_name = "wm8731-codec-0.001a",
        .init = corgi_wm8731_init,
        .ops = &corgi_ops,
 };
@@ -309,17 +311,10 @@ static struct snd_soc_dai_link corgi_dai = {
 /* corgi audio machine driver */
 static struct snd_soc_card snd_soc_corgi = {
        .name = "Corgi",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = &corgi_dai,
        .num_links = 1,
 };
 
-/* corgi audio subsystem */
-static struct snd_soc_device corgi_snd_devdata = {
-       .card = &snd_soc_corgi,
-       .codec_dev = &soc_codec_dev_wm8731,
-};
-
 static struct platform_device *corgi_snd_device;
 
 static int __init corgi_init(void)
@@ -334,8 +329,7 @@ static int __init corgi_init(void)
        if (!corgi_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(corgi_snd_device, &corgi_snd_devdata);
-       corgi_snd_devdata.dev = &corgi_snd_device->dev;
+       platform_set_drvdata(corgi_snd_device, &snd_soc_corgi);
        ret = platform_device_add(corgi_snd_device);
 
        if (ret)
index 7cd2f89d7b1021d9641a010a80901882b26ef495..c82cedb602fdaba519482639ea86dd670ccd9f12 100644 (file)
@@ -24,7 +24,6 @@
 #include <asm/mach-types.h>
 
 #include "../codecs/wm9705.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 
 
@@ -90,8 +89,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Mic Amp", NULL, "Mic (Internal)"},
 };
 
-static int e740_ac97_init(struct snd_soc_codec *codec)
+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");
@@ -116,30 +117,28 @@ static struct snd_soc_dai_link e740_dai[] = {
        {
                .name = "AC97",
                .stream_name = "AC97 HiFi",
-               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
-               .codec_dai = &wm9705_dai[WM9705_DAI_AC97_HIFI],
+               .cpu_dai_name = "pxa-ac97.0",
+               .codec_dai_name = "wm9705-hifi",
+               .platform_name = "pxa-pcm-audio",
+               .codec_name = "wm9705-codec",
                .init = e740_ac97_init,
        },
        {
                .name = "AC97 Aux",
                .stream_name = "AC97 Aux",
-               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
-               .codec_dai = &wm9705_dai[WM9705_DAI_AC97_AUX],
+               .cpu_dai_name = "pxa-ac97.1",
+               .codec_dai_name = "wm9705-aux",
+               .platform_name = "pxa-pcm-audio",
+               .codec_name = "wm9705-codec",
        },
 };
 
 static struct snd_soc_card e740 = {
        .name = "Toshiba e740",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = e740_dai,
        .num_links = ARRAY_SIZE(e740_dai),
 };
 
-static struct snd_soc_device e740_snd_devdata = {
-       .card = &e740,
-       .codec_dev = &soc_codec_dev_wm9705,
-};
-
 static struct platform_device *e740_snd_device;
 
 static int __init e740_init(void)
@@ -178,8 +177,7 @@ static int __init e740_init(void)
                goto free_apwr_gpio;
        }
 
-       platform_set_drvdata(e740_snd_device, &e740_snd_devdata);
-       e740_snd_devdata.dev = &e740_snd_device->dev;
+       platform_set_drvdata(e740_snd_device, &e740);
        ret = platform_device_add(e740_snd_device);
 
        if (!ret)
@@ -200,6 +198,9 @@ free_mic_amp_gpio:
 static void __exit e740_exit(void)
 {
        platform_device_unregister(e740_snd_device);
+       gpio_free(GPIO_E740_WM9705_nAVDD2);
+       gpio_free(GPIO_E740_AMP_ON);
+       gpio_free(GPIO_E740_MIC_ON);
 }
 
 module_init(e740_init);
index 8dceccc5e059fbb31a818f7fc76c892d4b3ba32e..4c143803a75e971de78e68d01d74f87df551b867 100644 (file)
@@ -24,7 +24,6 @@
 #include <asm/mach-types.h>
 
 #include "../codecs/wm9705.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 
 static int e750_spk_amp_event(struct snd_soc_dapm_widget *w,
@@ -72,8 +71,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"MIC1", NULL, "Mic (Internal)"},
 };
 
-static int e750_ac97_init(struct snd_soc_codec *codec)
+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");
@@ -98,31 +99,29 @@ static struct snd_soc_dai_link e750_dai[] = {
        {
                .name = "AC97",
                .stream_name = "AC97 HiFi",
-               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
-               .codec_dai = &wm9705_dai[WM9705_DAI_AC97_HIFI],
+               .cpu_dai_name = "pxa-ac97.0",
+               .codec_dai_name = "wm9705-hifi",
+               .platform_name = "pxa-pcm-audio",
+               .codec_name = "wm9705-codec",
                .init = e750_ac97_init,
                /* use ops to check startup state */
        },
        {
                .name = "AC97 Aux",
                .stream_name = "AC97 Aux",
-               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
-               .codec_dai = &wm9705_dai[WM9705_DAI_AC97_AUX],
+               .cpu_dai_name = "pxa-ac97.1",
+               .codec_dai_name ="wm9705-aux",
+               .platform_name = "pxa-pcm-audio",
+               .codec_name = "wm9705-codec",
        },
 };
 
 static struct snd_soc_card e750 = {
        .name = "Toshiba e750",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = e750_dai,
        .num_links = ARRAY_SIZE(e750_dai),
 };
 
-static struct snd_soc_device e750_snd_devdata = {
-       .card = &e750,
-       .codec_dev = &soc_codec_dev_wm9705,
-};
-
 static struct platform_device *e750_snd_device;
 
 static int __init e750_init(void)
@@ -154,8 +153,7 @@ static int __init e750_init(void)
                goto free_spk_amp_gpio;
        }
 
-       platform_set_drvdata(e750_snd_device, &e750_snd_devdata);
-       e750_snd_devdata.dev = &e750_snd_device->dev;
+       platform_set_drvdata(e750_snd_device, &e750);
        ret = platform_device_add(e750_snd_device);
 
        if (!ret)
index bc019cdce42922c787f62dfd8bc30cd7a0582d25..d42e5fe832c5d5909176feaa5b3513e95e4b6f85 100644 (file)
@@ -23,7 +23,6 @@
 #include <mach/eseries-gpio.h>
 
 #include "../codecs/wm9712.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 
 static int e800_spk_amp_event(struct snd_soc_dapm_widget *w,
@@ -73,8 +72,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"MIC2", NULL, "Mic (Internal2)"},
 };
 
-static int e800_ac97_init(struct snd_soc_codec *codec)
+static int e800_ac97_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        snd_soc_dapm_new_controls(codec, e800_dapm_widgets,
                                        ARRAY_SIZE(e800_dapm_widgets));
 
@@ -88,30 +89,28 @@ static struct snd_soc_dai_link e800_dai[] = {
        {
                .name = "AC97",
                .stream_name = "AC97 HiFi",
-               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
-               .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+               .cpu_dai_name = "pxa-ac97.0",
+               .codec_dai_name = "wm9712-hifi",
+               .platform_name = "pxa-pcm-audio",
+               .codec_name = "wm9712-codec",
                .init = e800_ac97_init,
        },
        {
                .name = "AC97 Aux",
                .stream_name = "AC97 Aux",
-               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
-               .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+               .cpu_dai_name = "pxa-ac97.1",
+               .codec_dai_name ="wm9712-aux",
+               .platform_name = "pxa-pcm-audio",
+               .codec_name = "wm9712-codec",
        },
 };
 
 static struct snd_soc_card e800 = {
        .name = "Toshiba e800",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = e800_dai,
        .num_links = ARRAY_SIZE(e800_dai),
 };
 
-static struct snd_soc_device e800_snd_devdata = {
-       .card = &e800,
-       .codec_dev = &soc_codec_dev_wm9712,
-};
-
 static struct platform_device *e800_snd_device;
 
 static int __init e800_init(void)
@@ -141,8 +140,7 @@ static int __init e800_init(void)
        if (!e800_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(e800_snd_device, &e800_snd_devdata);
-       e800_snd_devdata.dev = &e800_snd_device->dev;
+       platform_set_drvdata(e800_snd_device, &e800);
        ret = platform_device_add(e800_snd_device);
 
        if (!ret)
index f4756e4025fd1dd0c06080d0e26a8c121dc52c2e..eadf9d351a04d996978881b46a9503b8723f03c7 100644 (file)
 #include <mach/audio.h>
 
 #include "../codecs/wm9712.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 
 static struct snd_soc_dai_link em_x270_dai[] = {
        {
                .name = "AC97",
                .stream_name = "AC97 HiFi",
-               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
-               .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+               .cpu_dai_name = "pxa-ac97.0",
+               .codec_dai_name = "wm9712-hifi",
+               .platform_name = "pxa-pcm-audio",
+               .codec_name = "wm9712-codec",
        },
        {
                .name = "AC97 Aux",
                .stream_name = "AC97 Aux",
-               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
-               .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+               .cpu_dai_name = "pxa-ac97.1",
+               .codec_dai_name ="wm9712-aux",
+               .platform_name = "pxa-pcm-audio",
+               .codec_name = "wm9712-codec",
        },
 };
 
 static struct snd_soc_card em_x270 = {
        .name = "EM-X270",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = em_x270_dai,
        .num_links = ARRAY_SIZE(em_x270_dai),
 };
 
-static struct snd_soc_device em_x270_snd_devdata = {
-       .card = &em_x270,
-       .codec_dev = &soc_codec_dev_wm9712,
-};
-
 static struct platform_device *em_x270_snd_device;
 
 static int __init em_x270_init(void)
@@ -76,8 +73,7 @@ static int __init em_x270_init(void)
        if (!em_x270_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(em_x270_snd_device, &em_x270_snd_devdata);
-       em_x270_snd_devdata.dev = &em_x270_snd_device->dev;
+       platform_set_drvdata(em_x270_snd_device, &em_x270);
        ret = platform_device_add(em_x270_snd_device);
 
        if (ret)
index 405587a011600ab2c1f81400240529201bdbc5c4..154fc6f234389e74d4354770b6057074377f6be2 100644 (file)
@@ -6,14 +6,13 @@
 
 #include "../codecs/wm8940.h"
 #include "pxa2xx-i2s.h"
-#include "pxa2xx-pcm.h"
 
 static int imote2_asoc_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int clk = 0;
        int ret;
 
@@ -64,23 +63,19 @@ static struct snd_soc_ops imote2_asoc_ops = {
 static struct snd_soc_dai_link imote2_dai = {
        .name = "WM8940",
        .stream_name = "WM8940",
-       .cpu_dai = &pxa_i2s_dai,
-       .codec_dai = &wm8940_dai,
+       .cpu_dai_name = "pxa2xx-i2s",
+       .codec_dai_name = "wm8940-hifi",
+       .platform_name = "pxa-pcm-audio",
+       .codec_name = "wm8940-codec.0-0034",
        .ops = &imote2_asoc_ops,
 };
 
 static struct snd_soc_card snd_soc_imote2 = {
        .name = "Imote2",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = &imote2_dai,
        .num_links = 1,
 };
 
-static struct snd_soc_device imote2_snd_devdata = {
-       .card = &snd_soc_imote2,
-       .codec_dev = &soc_codec_dev_wm8940,
-};
-
 static struct platform_device *imote2_snd_device;
 
 static int __init imote2_asoc_init(void)
@@ -93,8 +88,7 @@ static int __init imote2_asoc_init(void)
        if (!imote2_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(imote2_snd_device, &imote2_snd_devdata);
-       imote2_snd_devdata.dev = &imote2_snd_device->dev;
+       platform_set_drvdata(imote2_snd_device, &snd_soc_imote2);
        ret = platform_device_add(imote2_snd_device);
        if (ret)
                platform_device_put(imote2_snd_device);
index 4c8d99a8d38667804ccb80b62a78268f8f55f439..b8207ced40729b0b375f28566b09de404313f28a 100644 (file)
@@ -32,7 +32,6 @@
 #include <mach/magician.h>
 #include <asm/mach-types.h>
 #include "../codecs/uda1380.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-i2s.h"
 #include "pxa-ssp.h"
 
@@ -71,7 +70,7 @@ static void magician_ext_control(struct snd_soc_codec *codec)
 static int magician_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* check the jack status at stream startup */
        magician_ext_control(codec);
@@ -86,8 +85,8 @@ static int magician_playback_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int acps, acds, width, rate;
        unsigned int div4 = PXA_SSP_CLK_SCDB_4;
        int ret = 0;
@@ -227,8 +226,8 @@ static int magician_capture_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret = 0;
 
        /* set codec DAI configuration */
@@ -393,8 +392,9 @@ static const struct snd_kcontrol_new uda1380_magician_controls[] = {
 /*
  * Logic for a uda1380 as connected on a HTC Magician
  */
-static int magician_uda1380_init(struct snd_soc_codec *codec)
+static int magician_uda1380_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        /* NC codec pins */
@@ -427,16 +427,20 @@ static struct snd_soc_dai_link magician_dai[] = {
 {
        .name = "uda1380",
        .stream_name = "UDA1380 Playback",
-       .cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP1],
-       .codec_dai = &uda1380_dai[UDA1380_DAI_PLAYBACK],
+       .cpu_dai_name = "pxa-ssp-dai.0",
+       .codec_dai_name = "uda1380-hifi-playback",
+       .platform_name = "pxa-pcm-audio",
+       .codec_name = "uda1380-codec.0-0018",
        .init = magician_uda1380_init,
        .ops = &magician_playback_ops,
 },
 {
        .name = "uda1380",
        .stream_name = "UDA1380 Capture",
-       .cpu_dai = &pxa_i2s_dai,
-       .codec_dai = &uda1380_dai[UDA1380_DAI_CAPTURE],
+       .cpu_dai_name = "pxa2xx-i2s",
+       .codec_dai_name = "uda1380-hifi-capture",
+       .platform_name = "pxa-pcm-audio",
+       .codec_name = "uda1380-codec.0-0018",
        .ops = &magician_capture_ops,
 }
 };
@@ -446,13 +450,7 @@ static struct snd_soc_card snd_soc_card_magician = {
        .name = "Magician",
        .dai_link = magician_dai,
        .num_links = ARRAY_SIZE(magician_dai),
-       .platform = &pxa2xx_soc_platform,
-};
 
-/* magician audio subsystem */
-static struct snd_soc_device magician_snd_devdata = {
-       .card = &snd_soc_card_magician,
-       .codec_dev = &soc_codec_dev_uda1380,
 };
 
 static struct platform_device *magician_snd_device;
@@ -514,8 +512,7 @@ static int __init magician_init(void)
                goto err_pdev;
        }
 
-       platform_set_drvdata(magician_snd_device, &magician_snd_devdata);
-       magician_snd_devdata.dev = &magician_snd_device->dev;
+       platform_set_drvdata(magician_snd_device, &snd_soc_card_magician);
        ret = platform_device_add(magician_snd_device);
        if (ret) {
                platform_device_put(magician_snd_device);
index 19eda8bbfdafc8264de13284639ad610bcaf60cd..f284cc54bc80e8fcfe100c56ccfd009dcb03168c 100644 (file)
@@ -54,7 +54,6 @@
 #include <sound/initval.h>
 #include <sound/ac97_codec.h>
 
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 #include "../codecs/wm9713.h"
 
@@ -128,8 +127,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Rear Speaker", NULL, "SPKR"},
 };
 
-static int mioa701_wm9713_init(struct snd_soc_codec *codec)
+static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        unsigned short reg;
 
        /* Add mioa701 specific widgets */
@@ -139,12 +139,12 @@ static int mioa701_wm9713_init(struct snd_soc_codec *codec)
        snd_soc_dapm_add_routes(codec, ARRAY_AND_SIZE(audio_map));
 
        /* Prepare GPIO8 for rear speaker amplifier */
-       reg = codec->read(codec, AC97_GPIO_CFG);
-       codec->write(codec, AC97_GPIO_CFG, reg | 0x0100);
+       reg = codec->driver->read(codec, AC97_GPIO_CFG);
+       codec->driver->write(codec, AC97_GPIO_CFG, reg | 0x0100);
 
        /* Prepare MIC input */
-       reg = codec->read(codec, AC97_3D_CONTROL);
-       codec->write(codec, AC97_3D_CONTROL, reg | 0xc000);
+       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");
@@ -162,32 +162,30 @@ static struct snd_soc_dai_link mioa701_dai[] = {
        {
                .name = "AC97",
                .stream_name = "AC97 HiFi",
-               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
-               .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
+               .cpu_dai_name = "pxa-ac97.0",
+               .codec_dai_name = "wm9713-hifi",
+               .codec_name = "wm9713-codec",
                .init = mioa701_wm9713_init,
+               .platform_name = "pxa-pcm-audio",
                .ops = &mioa701_ops,
        },
        {
                .name = "AC97 Aux",
                .stream_name = "AC97 Aux",
-               .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
-               .codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX],
+               .cpu_dai_name = "pxa-ac97.1",
+               .codec_dai_name ="wm9713-aux",
+               .codec_name = "wm9713-codec",
+               .platform_name = "pxa-pcm-audio",
                .ops = &mioa701_ops,
        },
 };
 
 static struct snd_soc_card mioa701 = {
        .name = "MioA701",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = mioa701_dai,
        .num_links = ARRAY_SIZE(mioa701_dai),
 };
 
-static struct snd_soc_device mioa701_snd_devdata = {
-       .card = &mioa701,
-       .codec_dev = &soc_codec_dev_wm9713,
-};
-
 static struct platform_device *mioa701_snd_device;
 
 static int mioa701_wm9713_probe(struct platform_device *pdev)
@@ -205,8 +203,7 @@ static int mioa701_wm9713_probe(struct platform_device *pdev)
        if (!mioa701_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(mioa701_snd_device, &mioa701_snd_devdata);
-       mioa701_snd_devdata.dev = &mioa701_snd_device->dev;
+       platform_set_drvdata(mioa701_snd_device, &mioa701);
 
        ret = platform_device_add(mioa701_snd_device);
        if (!ret)
index 1f96e3227be51920fbc011e2f9adaeba3e0fad31..13f6d485d57168affb88010669513af04c1881cb 100644 (file)
@@ -29,7 +29,6 @@
 #include <mach/palmasoc.h>
 
 #include "../codecs/wm9712.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 
 static struct snd_soc_jack hs_jack;
@@ -75,8 +74,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
 
 static struct snd_soc_card palm27x_asoc;
 
-static int palm27x_ac97_init(struct snd_soc_codec *codec)
+static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        /* add palm27x specific widgets */
@@ -112,7 +112,7 @@ static int palm27x_ac97_init(struct snd_soc_codec *codec)
                return err;
 
        /* Jack detection API stuff */
-       err = snd_soc_jack_new(&palm27x_asoc, "Headphone Jack",
+       err = snd_soc_jack_new(codec, "Headphone Jack",
                                SND_JACK_HEADPHONE, &hs_jack);
        if (err)
                return err;
@@ -132,30 +132,28 @@ static struct snd_soc_dai_link palm27x_dai[] = {
 {
        .name = "AC97 HiFi",
        .stream_name = "AC97 HiFi",
-       .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
-       .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+       .cpu_dai_name = "pxa-ac97.0",
+       .codec_dai_name =  "wm9712-hifi",
+       .codec_name = "wm9712-codec",
+       .platform_name = "pxa-pcm-audio",
        .init = palm27x_ac97_init,
 },
 {
        .name = "AC97 Aux",
        .stream_name = "AC97 Aux",
-       .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
-       .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+       .cpu_dai_name = "pxa-ac97.1",
+       .codec_dai_name = "wm9712-aux",
+       .codec_name = "wm9712-codec",
+       .platform_name = "pxa-pcm-audio",
 },
 };
 
 static struct snd_soc_card palm27x_asoc = {
        .name = "Palm/PXA27x",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = palm27x_dai,
        .num_links = ARRAY_SIZE(palm27x_dai),
 };
 
-static struct snd_soc_device palm27x_snd_devdata = {
-       .card = &palm27x_asoc,
-       .codec_dev = &soc_codec_dev_wm9712,
-};
-
 static struct platform_device *palm27x_snd_device;
 
 static int palm27x_asoc_probe(struct platform_device *pdev)
@@ -178,8 +176,7 @@ static int palm27x_asoc_probe(struct platform_device *pdev)
        if (!palm27x_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(palm27x_snd_device, &palm27x_snd_devdata);
-       palm27x_snd_devdata.dev = &palm27x_snd_device->dev;
+       platform_set_drvdata(palm27x_snd_device, &palm27x_asoc);
        ret = platform_device_add(palm27x_snd_device);
 
        if (ret != 0)
index c5f36e0eab58db4a188e36316f7239fab3272599..af84ee9c5e11edde0c8a253e3a5072e5f3ac0e36 100644 (file)
@@ -31,7 +31,6 @@
 #include <mach/audio.h>
 
 #include "../codecs/wm8731.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-i2s.h"
 
 #define POODLE_HP        1
@@ -76,7 +75,7 @@ static void poodle_ext_control(struct snd_soc_codec *codec)
 static int poodle_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* check the jack status at stream startup */
        poodle_ext_control(codec);
@@ -97,8 +96,8 @@ static int poodle_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int clk = 0;
        int ret = 0;
 
@@ -129,7 +128,7 @@ static int poodle_hw_params(struct snd_pcm_substream *substream,
                return ret;
 
        /* set the codec system clock for DAC and ADC */
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk,
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk,
                SND_SOC_CLOCK_IN);
        if (ret < 0)
                return ret;
@@ -237,8 +236,9 @@ static const struct snd_kcontrol_new wm8731_poodle_controls[] = {
 /*
  * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device
  */
-static int poodle_wm8731_init(struct snd_soc_codec *codec)
+static int poodle_wm8731_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        snd_soc_dapm_nc_pin(codec, "LLINEIN");
@@ -266,8 +266,10 @@ static int poodle_wm8731_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link poodle_dai = {
        .name = "WM8731",
        .stream_name = "WM8731",
-       .cpu_dai = &pxa_i2s_dai,
-       .codec_dai = &wm8731_dai,
+       .cpu_dai_name = "pxa2xx-i2s",
+       .codec_dai_name = "wm8731-hifi",
+       .platform_name = "pxa-pcm-audio",
+       .codec_name = "wm8731-codec.0-001a",
        .init = poodle_wm8731_init,
        .ops = &poodle_ops,
 };
@@ -275,15 +277,9 @@ static struct snd_soc_dai_link poodle_dai = {
 /* poodle audio machine driver */
 static struct snd_soc_card snd_soc_poodle = {
        .name = "Poodle",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = &poodle_dai,
        .num_links = 1,
-};
-
-/* poodle audio subsystem */
-static struct snd_soc_device poodle_snd_devdata = {
-       .card = &snd_soc_poodle,
-       .codec_dev = &soc_codec_dev_wm8731,
+       .owner = THIS_MODULE,
 };
 
 static struct platform_device *poodle_snd_device;
@@ -307,8 +303,7 @@ static int __init poodle_init(void)
        if (!poodle_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(poodle_snd_device, &poodle_snd_devdata);
-       poodle_snd_devdata.dev = &poodle_snd_device->dev;
+       platform_set_drvdata(poodle_snd_device, &snd_soc_poodle);
        ret = platform_device_add(poodle_snd_device);
 
        if (ret)
index a1fd23e0e3d00d5aa5fb93a53c2c106a74731cb0..b439eee462cb720ec622628fa78b955e846980ae 100644 (file)
@@ -35,7 +35,7 @@
 #include <mach/audio.h>
 #include <plat/ssp.h>
 
-#include "pxa2xx-pcm.h"
+#include "../../arm/pxa2xx-pcm.h"
 #include "pxa-ssp.h"
 
 /*
@@ -108,11 +108,9 @@ pxa_ssp_get_dma_params(struct ssp_device *ssp, int width4, int out)
 }
 
 static int pxa_ssp_startup(struct snd_pcm_substream *substream,
-                          struct snd_soc_dai *dai)
+                          struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        int ret = 0;
 
@@ -128,11 +126,9 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,
 }
 
 static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,
-                            struct snd_soc_dai *dai)
+                            struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
 
        if (!cpu_dai->active) {
@@ -148,7 +144,7 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,
 
 static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai)
 {
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
 
        if (!cpu_dai->active)
@@ -166,7 +162,7 @@ static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai)
 
 static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai)
 {
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        uint32_t sssr = SSSR_ROR | SSSR_TUR | SSSR_BCE;
 
@@ -230,7 +226,7 @@ static u32 pxa_ssp_get_scr(struct ssp_device *ssp)
 static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        int clk_id, unsigned int freq, int dir)
 {
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        int val;
 
@@ -287,7 +283,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
 static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
        int div_id, int div)
 {
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        int val;
 
@@ -338,7 +334,7 @@ static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
 static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
        int source, unsigned int freq_in, unsigned int freq_out)
 {
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        u32 ssacd = pxa_ssp_read_reg(ssp, SSACD) & ~0x70;
 
@@ -407,7 +403,7 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
 static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
        unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
 {
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        u32 sscr0;
 
@@ -442,7 +438,7 @@ static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
 static int pxa_ssp_set_dai_tristate(struct snd_soc_dai *cpu_dai,
        int tristate)
 {
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        u32 sscr1;
 
@@ -464,11 +460,9 @@ static int pxa_ssp_set_dai_tristate(struct snd_soc_dai *cpu_dai,
 static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                unsigned int fmt)
 {
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
-       u32 sscr0;
-       u32 sscr1;
-       u32 sspsp;
+       u32 sscr0, sscr1, sspsp, scfr;
 
        /* check if we need to change anything at all */
        if (priv->dai_fmt == fmt)
@@ -483,16 +477,16 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 
        /* reset port settings */
        sscr0 = pxa_ssp_read_reg(ssp, SSCR0) &
-               (SSCR0_ECS |  SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
+               ~(SSCR0_ECS |  SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
        sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7);
        sspsp = 0;
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM:
-               sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR;
+               sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR | SSCR1_SCFR;
                break;
        case SND_SOC_DAIFMT_CBM_CFS:
-               sscr1 |= SSCR1_SCLKDIR;
+               sscr1 |= SSCR1_SCLKDIR | SSCR1_SCFR;
                break;
        case SND_SOC_DAIFMT_CBS_CFS:
                break;
@@ -538,6 +532,17 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        pxa_ssp_write_reg(ssp, SSCR1, sscr1);
        pxa_ssp_write_reg(ssp, SSPSP, sspsp);
 
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_CBM_CFS:
+               scfr = pxa_ssp_read_reg(ssp, SSCR1) | SSCR1_SCFR;
+               pxa_ssp_write_reg(ssp, SSCR1, scfr);
+
+               while (pxa_ssp_read_reg(ssp, SSSR) & SSSR_BSY)
+                       cpu_relax();
+               break;
+       }
+
        dump_registers(ssp);
 
        /* Since we are configuring the timings for the format by hand
@@ -555,11 +560,9 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
  */
 static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
-                               struct snd_soc_dai *dai)
+                               struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        int chn = params_channels(params);
        u32 sscr0;
@@ -568,7 +571,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
        int ttsa = pxa_ssp_read_reg(ssp, SSTSA) & 0xf;
        struct pxa2xx_pcm_dma_params *dma_data;
 
-       dma_data = snd_soc_dai_get_dma_data(dai, substream);
+       dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
 
        /* generate correct DMA params */
        kfree(dma_data);
@@ -581,7 +584,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
                        ((chn == 2) && (ttsa != 1)) || (width == 32),
                        substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 
-       snd_soc_dai_set_dma_data(dai, substream, dma_data);
+       snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
 
        /* we can only change the settings if the port is not in use */
        if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE)
@@ -589,10 +592,8 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
 
        /* clear selected SSP bits */
        sscr0 = pxa_ssp_read_reg(ssp, SSCR0) & ~(SSCR0_DSS | SSCR0_EDSS);
-       pxa_ssp_write_reg(ssp, SSCR0, sscr0);
 
        /* bit size */
-       sscr0 = pxa_ssp_read_reg(ssp, SSCR0);
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
 #ifdef CONFIG_PXA3xx
@@ -668,12 +669,10 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
 }
 
 static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
-                          struct snd_soc_dai *dai)
+                          struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        int ret = 0;
-       struct ssp_priv *priv = cpu_dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
        int val;
 
@@ -729,8 +728,7 @@ static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
        return ret;
 }
 
-static int pxa_ssp_probe(struct platform_device *pdev,
-                           struct snd_soc_dai *dai)
+static int pxa_ssp_probe(struct snd_soc_dai *dai)
 {
        struct ssp_priv *priv;
        int ret;
@@ -746,7 +744,7 @@ static int pxa_ssp_probe(struct platform_device *pdev,
        }
 
        priv->dai_fmt = (unsigned int) -1;
-       dai->private_data = priv;
+       snd_soc_dai_set_drvdata(dai, priv);
 
        return 0;
 
@@ -755,11 +753,13 @@ err_priv:
        return ret;
 }
 
-static void pxa_ssp_remove(struct platform_device *pdev,
-                             struct snd_soc_dai *dai)
+static int pxa_ssp_remove(struct snd_soc_dai *dai)
 {
-       struct ssp_priv *priv = dai->private_data;
+       struct ssp_priv *priv = snd_soc_dai_get_drvdata(dai);
+
        pxa_ssp_free(priv->ssp);
+       kfree(priv);
+       return 0;
 }
 
 #define PXA_SSP_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
@@ -784,10 +784,7 @@ static struct snd_soc_dai_ops pxa_ssp_dai_ops = {
        .set_tristate   = pxa_ssp_set_dai_tristate,
 };
 
-struct snd_soc_dai pxa_ssp_dai[] = {
-       {
-               .name = "pxa2xx-ssp1",
-               .id = 0,
+static struct snd_soc_dai_driver pxa_ssp_dai = {
                .probe = pxa_ssp_probe,
                .remove = pxa_ssp_remove,
                .suspend = pxa_ssp_suspend,
@@ -805,81 +802,38 @@ struct snd_soc_dai pxa_ssp_dai[] = {
                        .formats = PXA_SSP_FORMATS,
                 },
                .ops = &pxa_ssp_dai_ops,
+};
+
+static __devinit int asoc_ssp_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_dai(&pdev->dev, &pxa_ssp_dai);
+}
+
+static int __devexit asoc_ssp_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver asoc_ssp_driver = {
+       .driver = {
+                       .name = "pxa-ssp-dai",
+                       .owner = THIS_MODULE,
        },
-       {       .name = "pxa2xx-ssp2",
-               .id = 1,
-               .probe = pxa_ssp_probe,
-               .remove = pxa_ssp_remove,
-               .suspend = pxa_ssp_suspend,
-               .resume = pxa_ssp_resume,
-               .playback = {
-                       .channels_min = 1,
-                       .channels_max = 8,
-                       .rates = PXA_SSP_RATES,
-                       .formats = PXA_SSP_FORMATS,
-               },
-               .capture = {
-                       .channels_min = 1,
-                       .channels_max = 8,
-                       .rates = PXA_SSP_RATES,
-                       .formats = PXA_SSP_FORMATS,
-                },
-               .ops = &pxa_ssp_dai_ops,
-       },
-       {
-               .name = "pxa2xx-ssp3",
-               .id = 2,
-               .probe = pxa_ssp_probe,
-               .remove = pxa_ssp_remove,
-               .suspend = pxa_ssp_suspend,
-               .resume = pxa_ssp_resume,
-               .playback = {
-                       .channels_min = 1,
-                       .channels_max = 8,
-                       .rates = PXA_SSP_RATES,
-                       .formats = PXA_SSP_FORMATS,
-               },
-               .capture = {
-                       .channels_min = 1,
-                       .channels_max = 8,
-                       .rates = PXA_SSP_RATES,
-                       .formats = PXA_SSP_FORMATS,
-                },
-               .ops = &pxa_ssp_dai_ops,
-       },
-       {
-               .name = "pxa2xx-ssp4",
-               .id = 3,
-               .probe = pxa_ssp_probe,
-               .remove = pxa_ssp_remove,
-               .suspend = pxa_ssp_suspend,
-               .resume = pxa_ssp_resume,
-               .playback = {
-                       .channels_min = 1,
-                       .channels_max = 8,
-                       .rates = PXA_SSP_RATES,
-                       .formats = PXA_SSP_FORMATS,
-               },
-               .capture = {
-                       .channels_min = 1,
-                       .channels_max = 8,
-                       .rates = PXA_SSP_RATES,
-                       .formats = PXA_SSP_FORMATS,
-                },
-               .ops = &pxa_ssp_dai_ops,
-       },
+
+       .probe = asoc_ssp_probe,
+       .remove = __devexit_p(asoc_ssp_remove),
 };
-EXPORT_SYMBOL_GPL(pxa_ssp_dai);
 
 static int __init pxa_ssp_init(void)
 {
-       return snd_soc_register_dais(pxa_ssp_dai, ARRAY_SIZE(pxa_ssp_dai));
+       return platform_driver_register(&asoc_ssp_driver);
 }
 module_init(pxa_ssp_init);
 
 static void __exit pxa_ssp_exit(void)
 {
-       snd_soc_unregister_dais(pxa_ssp_dai, ARRAY_SIZE(pxa_ssp_dai));
+       platform_driver_unregister(&asoc_ssp_driver);
 }
 module_exit(pxa_ssp_exit);
 
index 91deadd55675a23aea5d7d89400747c6bd66cdf8..bc79da221c0df018942b80c613be5d8d11ef6bf9 100644 (file)
@@ -42,6 +42,4 @@
 
 #define PXA_SSP_PLL_OUT  0
 
-extern struct snd_soc_dai pxa_ssp_dai[4];
-
 #endif
index d314115e3dd726750afbb8706b72cc51fbb3104b..ac51c6d25c4291998bd7ffc6b4d51a0c0148923a 100644 (file)
@@ -24,7 +24,6 @@
 #include <mach/dma.h>
 #include <mach/audio.h>
 
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 
 static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97)
@@ -104,24 +103,21 @@ static int pxa2xx_ac97_resume(struct snd_soc_dai *dai)
 #define pxa2xx_ac97_resume     NULL
 #endif
 
-static int pxa2xx_ac97_probe(struct platform_device *pdev,
-                            struct snd_soc_dai *dai)
+static int pxa2xx_ac97_probe(struct snd_soc_dai *dai)
 {
        return pxa2xx_ac97_hw_probe(to_platform_device(dai->dev));
 }
 
-static void pxa2xx_ac97_remove(struct platform_device *pdev,
-                              struct snd_soc_dai *dai)
+static int pxa2xx_ac97_remove(struct snd_soc_dai *dai)
 {
        pxa2xx_ac97_hw_remove(to_platform_device(dai->dev));
+       return 0;
 }
 
 static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
-                                struct snd_soc_dai *dai)
+                                struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        struct pxa2xx_pcm_dma_params *dma_data;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -136,10 +132,8 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
 
 static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream,
                                     struct snd_pcm_hw_params *params,
-                                    struct snd_soc_dai *dai)
+                                    struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        struct pxa2xx_pcm_dma_params *dma_data;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -154,11 +148,8 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream,
 
 static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream,
                                     struct snd_pcm_hw_params *params,
-                                    struct snd_soc_dai *dai)
+                                    struct snd_soc_dai *cpu_dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                return -ENODEV;
        else
@@ -188,10 +179,9 @@ static struct snd_soc_dai_ops pxa_ac97_mic_dai_ops = {
  * There is only 1 physical AC97 interface for pxa2xx, but it
  * has extra fifo's that can be used for aux DACs and ADCs.
  */
-struct snd_soc_dai pxa_ac97_dai[] = {
+static struct snd_soc_dai_driver pxa_ac97_dai[] = {
 {
        .name = "pxa2xx-ac97",
-       .id = 0,
        .ac97_control = 1,
        .probe = pxa2xx_ac97_probe,
        .remove = pxa2xx_ac97_remove,
@@ -213,7 +203,6 @@ struct snd_soc_dai pxa_ac97_dai[] = {
 },
 {
        .name = "pxa2xx-ac97-aux",
-       .id = 1,
        .ac97_control = 1,
        .playback = {
                .stream_name = "AC97 Aux Playback",
@@ -231,7 +220,6 @@ struct snd_soc_dai pxa_ac97_dai[] = {
 },
 {
        .name = "pxa2xx-ac97-mic",
-       .id = 2,
        .ac97_control = 1,
        .capture = {
                .stream_name = "AC97 Mic Capture",
@@ -243,36 +231,26 @@ struct snd_soc_dai pxa_ac97_dai[] = {
 },
 };
 
-EXPORT_SYMBOL_GPL(pxa_ac97_dai);
 EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
-static int __devinit pxa2xx_ac97_dev_probe(struct platform_device *pdev)
+static __devinit int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
 {
-       int i;
-       pxa2xx_audio_ops_t *pdata = pdev->dev.platform_data;
-
-       if (pdev->id >= 0) {
+       if (pdev->id != -1) {
                dev_err(&pdev->dev, "PXA2xx has only one AC97 port.\n");
                return -ENXIO;
        }
 
-       for (i = 0; i < ARRAY_SIZE(pxa_ac97_dai); i++) {
-               pxa_ac97_dai[i].dev = &pdev->dev;
-               if (pdata && pdata->codec_pdata[0])
-                       pxa_ac97_dai[i].ac97_pdata = pdata->codec_pdata[0];
-       }
-
        /* Punt most of the init to the SoC probe; we may need the machine
         * driver to do interesting things with the clocking to get us up
         * and running.
         */
-       return snd_soc_register_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai));
+       return snd_soc_register_dais(&pdev->dev, pxa_ac97_dai,
+                       ARRAY_SIZE(pxa_ac97_dai));
 }
 
 static int __devexit pxa2xx_ac97_dev_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai));
-
+       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(pxa_ac97_dai));
        return 0;
 }
 
index e390de8edcd48724558f63c4338a9e83b19d1762..eda891e6f31bab8ff1395a193bbc3949d2fecc8c 100644 (file)
@@ -14,8 +14,6 @@
 #define PXA2XX_DAI_AC97_AUX            1
 #define PXA2XX_DAI_AC97_MIC            2
 
-extern struct snd_soc_dai pxa_ac97_dai[3];
-
 /* platform data */
 extern struct snd_ac97_bus_ops pxa2xx_ac97_ops;
 
index c1a5275721e4f0eb2812842d31555c84b16f206c..11be5952a5066fa30163a3b51143b9dfb41b05e7 100644 (file)
@@ -27,7 +27,6 @@
 #include <mach/dma.h>
 #include <mach/audio.h>
 
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-i2s.h"
 
 /*
@@ -80,6 +79,7 @@ struct pxa_i2s_port {
 };
 static struct pxa_i2s_port pxa_i2s;
 static struct clk *clk_i2s;
+static int clk_ena = 0;
 
 static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = {
        .name                   = "I2S PCM Stereo out",
@@ -101,7 +101,7 @@ static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream,
                              struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
        if (IS_ERR(clk_i2s))
                return PTR_ERR(clk_i2s);
@@ -162,13 +162,11 @@ static int pxa2xx_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 snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
        struct pxa2xx_pcm_dma_params *dma_data;
 
        BUG_ON(IS_ERR(clk_i2s));
        clk_enable(clk_i2s);
-       dai->private_data = dai;
+       clk_ena = 1;
        pxa_i2s_wait();
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -176,7 +174,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
        else
                dma_data = &pxa2xx_i2s_pcm_stereo_in;
 
-       snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
+       snd_soc_dai_set_dma_data(dai, substream, dma_data);
 
        /* is port used by another stream */
        if (!(SACR0 & SACR0_ENB)) {
@@ -259,9 +257,9 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream,
        if ((SACR1 & (SACR1_DREC | SACR1_DRPL)) == (SACR1_DREC | SACR1_DRPL)) {
                SACR0 &= ~SACR0_ENB;
                pxa_i2s_wait();
-               if (dai->private_data != NULL) {
+               if (clk_ena) {
                        clk_disable(clk_i2s);
-                       dai->private_data = NULL;
+                       clk_ena = 0;
                }
        }
 }
@@ -300,6 +298,35 @@ static int pxa2xx_i2s_resume(struct snd_soc_dai *dai)
 #define pxa2xx_i2s_resume      NULL
 #endif
 
+static int pxa2xx_i2s_probe(struct snd_soc_dai *dai)
+{
+       clk_i2s = clk_get(dai->dev, "I2SCLK");
+       if (IS_ERR(clk_i2s))
+               return PTR_ERR(clk_i2s);
+
+       /*
+        * PXA Developer's Manual:
+        * If SACR0[ENB] is toggled in the middle of a normal operation,
+        * the SACR0[RST] bit must also be set and cleared to reset all
+        * I2S controller registers.
+        */
+       SACR0 = SACR0_RST;
+       SACR0 = 0;
+       /* Make sure RPL and REC are disabled */
+       SACR1 = SACR1_DRPL | SACR1_DREC;
+       /* Along with FIFO servicing */
+       SAIMR &= ~(SAIMR_RFS | SAIMR_TFS);
+
+       return 0;
+}
+
+static int  pxa2xx_i2s_remove(struct snd_soc_dai *dai)
+{
+       clk_put(clk_i2s);
+       clk_i2s = ERR_PTR(-ENOENT);
+       return 0;
+}
+
 #define PXA2XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
                SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
@@ -313,9 +340,9 @@ static struct snd_soc_dai_ops pxa_i2s_dai_ops = {
        .set_sysclk     = pxa2xx_i2s_set_dai_sysclk,
 };
 
-struct snd_soc_dai pxa_i2s_dai = {
-       .name = "pxa2xx-i2s",
-       .id = 0,
+static struct snd_soc_dai_driver pxa_i2s_dai = {
+       .probe = pxa2xx_i2s_probe,
+       .remove = pxa2xx_i2s_remove,
        .suspend = pxa2xx_i2s_suspend,
        .resume = pxa2xx_i2s_resume,
        .playback = {
@@ -332,49 +359,20 @@ struct snd_soc_dai pxa_i2s_dai = {
        .symmetric_rates = 1,
 };
 
-EXPORT_SYMBOL_GPL(pxa_i2s_dai);
-
-static int pxa2xx_i2s_probe(struct platform_device *dev)
+static int pxa2xx_i2s_drv_probe(struct platform_device *pdev)
 {
-       int ret;
-
-       clk_i2s = clk_get(&dev->dev, "I2SCLK");
-       if (IS_ERR(clk_i2s))
-               return PTR_ERR(clk_i2s);
-
-       pxa_i2s_dai.dev = &dev->dev;
-       pxa_i2s_dai.private_data = NULL;
-       ret = snd_soc_register_dai(&pxa_i2s_dai);
-       if (ret != 0)
-               clk_put(clk_i2s);
-
-       /*
-        * PXA Developer's Manual:
-        * If SACR0[ENB] is toggled in the middle of a normal operation,
-        * the SACR0[RST] bit must also be set and cleared to reset all
-        * I2S controller registers.
-        */
-       SACR0 = SACR0_RST;
-       SACR0 = 0;
-       /* Make sure RPL and REC are disabled */
-       SACR1 = SACR1_DRPL | SACR1_DREC;
-       /* Along with FIFO servicing */
-       SAIMR &= ~(SAIMR_RFS | SAIMR_TFS);
-
-       return ret;
+       return snd_soc_register_dai(&pdev->dev, &pxa_i2s_dai);
 }
 
-static int __devexit pxa2xx_i2s_remove(struct platform_device *dev)
+static int __devexit pxa2xx_i2s_drv_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&pxa_i2s_dai);
-       clk_put(clk_i2s);
-       clk_i2s = ERR_PTR(-ENOENT);
+       snd_soc_unregister_dai(&pdev->dev);
        return 0;
 }
 
 static struct platform_driver pxa2xx_i2s_driver = {
-       .probe = pxa2xx_i2s_probe,
-       .remove = __devexit_p(pxa2xx_i2s_remove),
+       .probe = pxa2xx_i2s_drv_probe,
+       .remove = __devexit_p(pxa2xx_i2s_drv_remove),
 
        .driver = {
                .name = "pxa2xx-i2s",
@@ -400,3 +398,4 @@ module_exit(pxa2xx_i2s_exit);
 MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
 MODULE_DESCRIPTION("pxa2xx I2S SoC Interface");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-i2s");
index e2def441153eee706ab6789a00385c6e13f49284..070f3c6059fed6e880f8cce055731506b43c71e8 100644 (file)
@@ -15,6 +15,4 @@
 /* I2S clock */
 #define PXA2XX_I2S_SYSCLK              0
 
-extern struct snd_soc_dai pxa_i2s_dai;
-
 #endif
index adc7e6f15f9367b5acbf16c02f633af3583a16da..02fb66416ddc894c7abdfd2fa52cddc3eb717225 100644 (file)
@@ -16,7 +16,6 @@
 #include <sound/soc.h>
 #include <sound/pxa2xx-lib.h>
 
-#include "pxa2xx-pcm.h"
 #include "../../arm/pxa2xx-pcm.h"
 
 static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
@@ -28,7 +27,7 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
        struct pxa2xx_pcm_dma_params *dma;
        int ret;
 
-       dma = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+       dma = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        /* return if this is a bufferless transfer e.g.
         * codec <--> BT codec or GSM modem -- lg FIXME */
@@ -95,14 +94,14 @@ static int pxa2xx_soc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -112,25 +111,44 @@ static int pxa2xx_soc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
        return ret;
 }
 
-struct snd_soc_platform pxa2xx_soc_platform = {
-       .name           = "pxa2xx-audio",
-       .pcm_ops        = &pxa2xx_pcm_ops,
+static struct snd_soc_platform_driver pxa2xx_soc_platform = {
+       .ops    = &pxa2xx_pcm_ops,
        .pcm_new        = pxa2xx_soc_pcm_new,
        .pcm_free       = pxa2xx_pcm_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(pxa2xx_soc_platform);
 
-static int __init pxa2xx_soc_platform_init(void)
+static int __devinit pxa2xx_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&pxa2xx_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &pxa2xx_soc_platform);
 }
-module_init(pxa2xx_soc_platform_init);
 
-static void __exit pxa2xx_soc_platform_exit(void)
+static int __devexit pxa2xx_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&pxa2xx_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver pxa_pcm_driver = {
+       .driver = {
+                       .name = "pxa-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = pxa2xx_soc_platform_probe,
+       .remove = __devexit_p(pxa2xx_soc_platform_remove),
+};
+
+static int __init snd_pxa_pcm_init(void)
+{
+       return platform_driver_register(&pxa_pcm_driver);
+}
+module_init(snd_pxa_pcm_init);
+
+static void __exit snd_pxa_pcm_exit(void)
+{
+       platform_driver_unregister(&pxa_pcm_driver);
 }
-module_exit(pxa2xx_soc_platform_exit);
+module_exit(snd_pxa_pcm_exit);
 
 MODULE_AUTHOR("Nicolas Pitre");
 MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module");
diff --git a/sound/soc/pxa/pxa2xx-pcm.h b/sound/soc/pxa/pxa2xx-pcm.h
deleted file mode 100644 (file)
index 60c3b20..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * linux/sound/arm/pxa2xx-pcm.h -- ALSA PCM interface for the Intel PXA2xx chip
- *
- * Author:     Nicolas Pitre
- * Created:    Nov 30, 2004
- * Copyright:  MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _PXA2XX_PCM_H
-#define _PXA2XX_PCM_H
-
-/* platform data */
-extern struct snd_soc_platform pxa2xx_soc_platform;
-
-#endif
index 7e3f41696c41f53e6479a4678982f0bc7e28842d..2cda82bc5d2e4362e2a3941428ad1eaf9802934e 100644 (file)
@@ -26,9 +26,6 @@
 
 #include <asm/mach-types.h>
 
-#include "../codecs/cs4270.h"
-#include "../codecs/ak4104.h"
-#include "pxa2xx-pcm.h"
 #include "pxa-ssp.h"
 
 #define GPIO_SPDIF_RESET       (38)
@@ -71,7 +68,7 @@ static void raumfeld_enable_audio(bool en)
 static int raumfeld_cs4270_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
        /* set freq to 0 to enable all possible codec sample rates */
        return snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
@@ -80,7 +77,7 @@ static int raumfeld_cs4270_startup(struct snd_pcm_substream *substream)
 static void raumfeld_cs4270_shutdown(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
        /* set freq to 0 to enable all possible codec sample rates */
        snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
@@ -90,8 +87,8 @@ static int raumfeld_cs4270_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int fmt, clk = 0;
        int ret = 0;
 
@@ -167,32 +164,14 @@ static int raumfeld_line_resume(struct platform_device *pdev)
        return 0;
 }
 
-static struct snd_soc_dai_link raumfeld_line_dai = {
-       .name           = "CS4270",
-       .stream_name    = "CS4270",
-       .cpu_dai        = &pxa_ssp_dai[PXA_DAI_SSP1],
-       .codec_dai      = &cs4270_dai,
-       .ops            = &raumfeld_cs4270_ops,
-};
-
-static struct snd_soc_card snd_soc_line_raumfeld = {
-       .name           = "Raumfeld analog",
-       .platform       = &pxa2xx_soc_platform,
-       .dai_link       = &raumfeld_line_dai,
-       .suspend_post   = raumfeld_line_suspend,
-       .resume_pre     = raumfeld_line_resume,
-       .num_links      = 1,
-};
-
-
 /* AK4104 */
 
 static int raumfeld_ak4104_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int fmt, ret = 0, clk = 0;
 
        switch (params_rate(params)) {
@@ -247,34 +226,35 @@ static struct snd_soc_ops raumfeld_ak4104_ops = {
        .hw_params = raumfeld_ak4104_hw_params,
 };
 
-static struct snd_soc_dai_link raumfeld_spdif_dai = {
+static struct snd_soc_dai_link raumfeld_dai[] = {
+{
        .name           = "ak4104",
        .stream_name    = "Playback",
-       .cpu_dai        = &pxa_ssp_dai[PXA_DAI_SSP2],
-       .codec_dai      = &ak4104_dai,
+       .cpu_dai_name = "pxa-ssp-dai.1",
+       .codec_dai_name = "ak4104-hifi",
+       .platform_name = "pxa-pcm-audio",
        .ops            = &raumfeld_ak4104_ops,
-};
-
-static struct snd_soc_card snd_soc_spdif_raumfeld = {
-       .name           = "Raumfeld S/PDIF",
-       .platform       = &pxa2xx_soc_platform,
-       .dai_link       = &raumfeld_spdif_dai,
-       .num_links      = 1
-};
-
-/* raumfeld_audio audio subsystem */
-static struct snd_soc_device raumfeld_line_devdata = {
-       .card = &snd_soc_line_raumfeld,
-       .codec_dev = &soc_codec_device_cs4270,
-};
+       .codec_name = "ak4104-codec.0",
+},
+{
+       .name           = "CS4270",
+       .stream_name    = "CS4270",
+       .cpu_dai_name = "pxa-ssp-dai.0",
+       .platform_name = "pxa-pcm-audio",
+       .codec_dai_name = "cs4270-hifi",
+       .codec_name = "cs4270-codec.0-0048",
+       .ops            = &raumfeld_cs4270_ops,
+},};
 
-static struct snd_soc_device raumfeld_spdif_devdata = {
-       .card = &snd_soc_spdif_raumfeld,
-       .codec_dev = &soc_codec_device_ak4104,
+static struct snd_soc_card snd_soc_raumfeld = {
+       .name           = "Raumfeld",
+       .dai_link       = raumfeld_dai,
+       .suspend_post   = raumfeld_line_suspend,
+       .resume_pre     = raumfeld_line_resume,
+       .num_links      = ARRAY_SIZE(raumfeld_dai),
 };
 
-static struct platform_device *raumfeld_audio_line_device;
-static struct platform_device *raumfeld_audio_spdif_device;
+static struct platform_device *raumfeld_audio_device;
 
 static int __init raumfeld_audio_init(void)
 {
@@ -292,38 +272,19 @@ static int __init raumfeld_audio_init(void)
 
        set_max9485_clk(MAX9485_MCLK_FREQ_122880);
 
-       /* LINE */
-       raumfeld_audio_line_device = platform_device_alloc("soc-audio", 0);
-       if (!raumfeld_audio_line_device)
+       /* Register LINE and SPDIF */
+       raumfeld_audio_device = platform_device_alloc("soc-audio", 0);
+       if (!raumfeld_audio_device)
                return -ENOMEM;
 
-       platform_set_drvdata(raumfeld_audio_line_device,
-                            &raumfeld_line_devdata);
-       raumfeld_line_devdata.dev = &raumfeld_audio_line_device->dev;
-       ret = platform_device_add(raumfeld_audio_line_device);
-       if (ret)
-               platform_device_put(raumfeld_audio_line_device);
+       platform_set_drvdata(raumfeld_audio_device,
+                            &snd_soc_raumfeld);
+       ret = platform_device_add(raumfeld_audio_device);
 
        /* no S/PDIF on Speakers */
        if (machine_is_raumfeld_speaker())
                return ret;
 
-       /* S/PDIF */
-       raumfeld_audio_spdif_device = platform_device_alloc("soc-audio", 1);
-       if (!raumfeld_audio_spdif_device) {
-               platform_device_put(raumfeld_audio_line_device);
-               return -ENOMEM;
-       }
-
-       platform_set_drvdata(raumfeld_audio_spdif_device,
-                            &raumfeld_spdif_devdata);
-       raumfeld_spdif_devdata.dev = &raumfeld_audio_spdif_device->dev;
-       ret = platform_device_add(raumfeld_audio_spdif_device);
-       if (ret) {
-               platform_device_put(raumfeld_audio_line_device);
-               platform_device_put(raumfeld_audio_spdif_device);
-       }
-
        raumfeld_enable_audio(true);
 
        return ret;
@@ -333,10 +294,7 @@ static void __exit raumfeld_audio_exit(void)
 {
        raumfeld_enable_audio(false);
 
-       platform_device_unregister(raumfeld_audio_line_device);
-
-       if (machine_is_raumfeld_connector())
-               platform_device_unregister(raumfeld_audio_spdif_device);
+       platform_device_unregister(raumfeld_audio_device);
 
        i2c_unregister_device(max9486_client);
 
diff --git a/sound/soc/pxa/saarb.c b/sound/soc/pxa/saarb.c
new file mode 100644 (file)
index 0000000..d63cb47
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * saarb.c -- SoC audio for saarb
+ *
+ * Copyright (C) 2010 Marvell International Ltd.
+ *     Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/88pm860x-codec.h"
+#include "pxa-ssp.h"
+
+static int saarb_pm860x_init(struct snd_soc_pcm_runtime *rtd);
+
+static struct platform_device *saarb_snd_device;
+
+static struct snd_soc_jack hs_jack, mic_jack;
+
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+       { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE, },
+};
+
+static struct snd_soc_jack_pin mic_jack_pins[] = {
+       { .pin = "Headset Mic 2",       .mask = SND_JACK_MICROPHONE, },
+};
+
+/* saarb machine dapm widgets */
+static const struct snd_soc_dapm_widget saarb_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Stereophone", NULL),
+       SND_SOC_DAPM_LINE("Lineout Out 1", NULL),
+       SND_SOC_DAPM_LINE("Lineout Out 2", NULL),
+       SND_SOC_DAPM_SPK("Ext Speaker", NULL),
+       SND_SOC_DAPM_MIC("Ext Mic 1", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Ext Mic 3", NULL),
+};
+
+/* saarb machine audio map */
+static const struct snd_soc_dapm_route audio_map[] = {
+       {"Headset Stereophone", NULL, "HS1"},
+       {"Headset Stereophone", NULL, "HS2"},
+
+       {"Ext Speaker", NULL, "LSP"},
+       {"Ext Speaker", NULL, "LSN"},
+
+       {"Lineout Out 1", NULL, "LINEOUT1"},
+       {"Lineout Out 2", NULL, "LINEOUT2"},
+
+       {"MIC1P", NULL, "Mic1 Bias"},
+       {"MIC1N", NULL, "Mic1 Bias"},
+       {"Mic1 Bias", NULL, "Ext Mic 1"},
+
+       {"MIC2P", NULL, "Mic1 Bias"},
+       {"MIC2N", NULL, "Mic1 Bias"},
+       {"Mic1 Bias", NULL, "Headset Mic 2"},
+
+       {"MIC3P", NULL, "Mic3 Bias"},
+       {"MIC3N", NULL, "Mic3 Bias"},
+       {"Mic3 Bias", NULL, "Ext Mic 3"},
+};
+
+static int saarb_i2s_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       int width = snd_pcm_format_physical_width(params_format(params));
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_NET_PLL, 0,
+                                    PM860X_CLK_DIR_OUT);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, PM860X_CLK_DIR_OUT);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_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_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_tdm_slot(cpu_dai, 3, 3, 2, width);
+
+       return ret;
+}
+
+static struct snd_soc_ops saarb_i2s_ops = {
+       .hw_params      = saarb_i2s_hw_params,
+};
+
+static struct snd_soc_dai_link saarb_dai[] = {
+       {
+               .name           = "88PM860x I2S",
+               .stream_name    = "I2S Audio",
+               .cpu_dai_name   = "pxa-ssp-dai.1",
+               .codec_dai_name = "88pm860x-i2s",
+               .platform_name  = "pxa-pcm-audio",
+               .codec_name     = "88pm860x-codec",
+               .init           = saarb_pm860x_init,
+               .ops            = &saarb_i2s_ops,
+       },
+};
+
+static struct snd_soc_card snd_soc_card_saarb = {
+       .name = "Saarb",
+       .dai_link = saarb_dai,
+       .num_links = ARRAY_SIZE(saarb_dai),
+};
+
+static int saarb_pm860x_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       int ret;
+
+       snd_soc_dapm_new_controls(codec, saarb_dapm_widgets,
+                                 ARRAY_SIZE(saarb_dapm_widgets));
+       snd_soc_dapm_add_routes(codec, 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");
+
+       ret = snd_soc_dapm_sync(codec);
+       if (ret)
+               return ret;
+
+       /* Headset jack detection */
+       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
+                       | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
+                       &hs_jack);
+       snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
+                             hs_jack_pins);
+       snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE,
+                        &mic_jack);
+       snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
+                             mic_jack_pins);
+
+       /* headphone, microphone detection & headset short detection */
+       pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE,
+                             SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2);
+       pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE);
+       return 0;
+}
+
+static int __init saarb_init(void)
+{
+       int ret;
+
+       if (!machine_is_saarb())
+               return -ENODEV;
+       saarb_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!saarb_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(saarb_snd_device, &snd_soc_card_saarb);
+
+       ret = platform_device_add(saarb_snd_device);
+       if (ret)
+               platform_device_put(saarb_snd_device);
+
+       return ret;
+}
+
+static void __exit saarb_exit(void)
+{
+       platform_device_unregister(saarb_snd_device);
+}
+
+module_init(saarb_init);
+module_exit(saarb_exit);
+
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_DESCRIPTION("ALSA SoC 88PM860x Saarb");
+MODULE_LICENSE("GPL");
index d256f5f313b5a0e10ac5158dc422741f08ec6cd3..f470f360f4dda9a3193b5f5011a7b9688cfb3b32 100644 (file)
@@ -28,7 +28,6 @@
 #include <asm/mach-types.h>
 #include <mach/spitz.h>
 #include "../codecs/wm8750.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-i2s.h"
 
 #define SPITZ_HP        0
@@ -107,7 +106,7 @@ static void spitz_ext_control(struct snd_soc_codec *codec)
 static int spitz_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* check the jack status at stream startup */
        spitz_ext_control(codec);
@@ -118,8 +117,8 @@ static int spitz_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int clk = 0;
        int ret = 0;
 
@@ -274,8 +273,9 @@ static const struct snd_kcontrol_new wm8750_spitz_controls[] = {
 /*
  * Logic for a wm8750 as connected on a Sharp SL-Cxx00 Device
  */
-static int spitz_wm8750_init(struct snd_soc_codec *codec)
+static int spitz_wm8750_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        /* NC codec pins */
@@ -308,8 +308,10 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link spitz_dai = {
        .name = "wm8750",
        .stream_name = "WM8750",
-       .cpu_dai = &pxa_i2s_dai,
-       .codec_dai = &wm8750_dai,
+       .cpu_dai_name = "pxa-is2",
+       .codec_dai_name = "wm8750-hifi",
+       .platform_name = "pxa-pcm-audio",
+       .codec_name = "wm8750-codec.0-001a",
        .init = spitz_wm8750_init,
        .ops = &spitz_ops,
 };
@@ -317,17 +319,10 @@ static struct snd_soc_dai_link spitz_dai = {
 /* spitz audio machine driver */
 static struct snd_soc_card snd_soc_spitz = {
        .name = "Spitz",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = &spitz_dai,
        .num_links = 1,
 };
 
-/* spitz audio subsystem */
-static struct snd_soc_device spitz_snd_devdata = {
-       .card = &snd_soc_spitz,
-       .codec_dev = &soc_codec_dev_wm8750,
-};
-
 static struct platform_device *spitz_snd_device;
 
 static int __init spitz_init(void)
@@ -341,8 +336,7 @@ static int __init spitz_init(void)
        if (!spitz_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(spitz_snd_device, &spitz_snd_devdata);
-       spitz_snd_devdata.dev = &spitz_snd_device->dev;
+       platform_set_drvdata(spitz_snd_device, &snd_soc_spitz);
        ret = platform_device_add(spitz_snd_device);
 
        if (ret)
diff --git a/sound/soc/pxa/tavorevb3.c b/sound/soc/pxa/tavorevb3.c
new file mode 100644 (file)
index 0000000..248c283
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * tavorevb3.c -- SoC audio for Tavor EVB3
+ *
+ * Copyright (C) 2010 Marvell International Ltd.
+ *     Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/88pm860x-codec.h"
+#include "pxa-ssp.h"
+
+static int evb3_pm860x_init(struct snd_soc_pcm_runtime *rtd);
+
+static struct platform_device *evb3_snd_device;
+
+static struct snd_soc_jack hs_jack, mic_jack;
+
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+       { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE, },
+};
+
+static struct snd_soc_jack_pin mic_jack_pins[] = {
+       { .pin = "Headset Mic 2",       .mask = SND_JACK_MICROPHONE, },
+};
+
+/* tavorevb3 machine dapm widgets */
+static const struct snd_soc_dapm_widget evb3_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+       SND_SOC_DAPM_LINE("Lineout Out 1", NULL),
+       SND_SOC_DAPM_LINE("Lineout Out 2", NULL),
+       SND_SOC_DAPM_SPK("Ext Speaker", NULL),
+       SND_SOC_DAPM_MIC("Ext Mic 1", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic 2", NULL),
+       SND_SOC_DAPM_MIC("Ext Mic 3", NULL),
+};
+
+/* tavorevb3 machine audio map */
+static const struct snd_soc_dapm_route audio_map[] = {
+       {"Headset Stereophone", NULL, "HS1"},
+       {"Headset Stereophone", NULL, "HS2"},
+
+       {"Ext Speaker", NULL, "LSP"},
+       {"Ext Speaker", NULL, "LSN"},
+
+       {"Lineout Out 1", NULL, "LINEOUT1"},
+       {"Lineout Out 2", NULL, "LINEOUT2"},
+
+       {"MIC1P", NULL, "Mic1 Bias"},
+       {"MIC1N", NULL, "Mic1 Bias"},
+       {"Mic1 Bias", NULL, "Ext Mic 1"},
+
+       {"MIC2P", NULL, "Mic1 Bias"},
+       {"MIC2N", NULL, "Mic1 Bias"},
+       {"Mic1 Bias", NULL, "Headset Mic 2"},
+
+       {"MIC3P", NULL, "Mic3 Bias"},
+       {"MIC3N", NULL, "Mic3 Bias"},
+       {"Mic3 Bias", NULL, "Ext Mic 3"},
+};
+
+static int evb3_i2s_hw_params(struct snd_pcm_substream *substream,
+                             struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       int width = snd_pcm_format_physical_width(params_format(params));
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_NET_PLL, 0,
+                                    PM860X_CLK_DIR_OUT);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, PM860X_CLK_DIR_OUT);
+       if (ret < 0)
+               return ret;
+
+       ret = snd_soc_dai_set_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_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_tdm_slot(cpu_dai, 3, 3, 2, width);
+       return ret;
+}
+
+static struct snd_soc_ops evb3_i2s_ops = {
+       .hw_params      = evb3_i2s_hw_params,
+};
+
+static struct snd_soc_dai_link evb3_dai[] = {
+       {
+               .name           = "88PM860x I2S",
+               .stream_name    = "I2S Audio",
+               .cpu_dai_name   = "pxa-ssp-dai.1",
+               .codec_dai_name = "88pm860x-i2s",
+               .platform_name  = "pxa-pcm-audio",
+               .codec_name     = "88pm860x-codec",
+               .init           = evb3_pm860x_init,
+               .ops            = &evb3_i2s_ops,
+       },
+};
+
+static struct snd_soc_card snd_soc_card_evb3 = {
+       .name = "Tavor EVB3",
+       .dai_link = evb3_dai,
+       .num_links = ARRAY_SIZE(evb3_dai),
+};
+
+static int evb3_pm860x_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       int ret;
+
+       snd_soc_dapm_new_controls(codec, evb3_dapm_widgets,
+                                 ARRAY_SIZE(evb3_dapm_widgets));
+       snd_soc_dapm_add_routes(codec, 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");
+
+       ret = snd_soc_dapm_sync(codec);
+       if (ret)
+               return ret;
+
+       /* Headset jack detection */
+       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
+                       | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
+                       &hs_jack);
+       snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
+                             hs_jack_pins);
+       snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE,
+                        &mic_jack);
+       snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
+                             mic_jack_pins);
+
+       /* headphone, microphone detection & headset short detection */
+       pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE,
+                             SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2);
+       pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE);
+       return 0;
+}
+
+static int __init tavorevb3_init(void)
+{
+       int ret;
+
+       if (!machine_is_tavorevb3())
+               return -ENODEV;
+       evb3_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!evb3_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(evb3_snd_device, &snd_soc_card_evb3);
+
+       ret = platform_device_add(evb3_snd_device);
+       if (ret)
+               platform_device_put(evb3_snd_device);
+
+       return ret;
+}
+
+static void __exit tavorevb3_exit(void)
+{
+       platform_device_unregister(evb3_snd_device);
+}
+
+module_init(tavorevb3_init);
+module_exit(tavorevb3_exit);
+
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_DESCRIPTION("ALSA SoC 88PM860x Tavor EVB3");
+MODULE_LICENSE("GPL");
index dbbd3e9d1637f0b9d14d8790973d5d9035e9d3e1..a3bfb2e8b70fb6946739837126dc49fed237f658 100644 (file)
@@ -33,7 +33,6 @@
 #include <mach/audio.h>
 
 #include "../codecs/wm9712.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 
 static struct snd_soc_card tosa;
@@ -80,7 +79,7 @@ static void tosa_ext_control(struct snd_soc_codec *codec)
 static int tosa_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->socdev->card->codec;
+       struct snd_soc_codec *codec = rtd->card->codec;
 
        /* check the jack status at stream startup */
        tosa_ext_control(codec);
@@ -184,8 +183,9 @@ static const struct snd_kcontrol_new tosa_controls[] = {
                tosa_set_spk),
 };
 
-static int tosa_ac97_init(struct snd_soc_codec *codec)
+static int tosa_ac97_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int err;
 
        snd_soc_dapm_nc_pin(codec, "OUT3");
@@ -212,16 +212,20 @@ static struct snd_soc_dai_link tosa_dai[] = {
 {
        .name = "AC97",
        .stream_name = "AC97 HiFi",
-       .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
-       .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+       .cpu_dai_name = "pxa-ac97.0",
+       .codec_dai_name = "wm9712-hifi",
+       .platform_name = "pxa-pcm-audio",
+       .codec_name = "wm9712-codec",
        .init = tosa_ac97_init,
        .ops = &tosa_ops,
 },
 {
        .name = "AC97 Aux",
        .stream_name = "AC97 Aux",
-       .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
-       .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+       .cpu_dai_name = "pxa-ac97.1",
+       .codec_dai_name = "wm9712-aux",
+       .platform_name = "pxa-pcm-audio",
+       .codec_name = "wm9712-codec",
        .ops = &tosa_ops,
 },
 };
@@ -248,18 +252,12 @@ static int tosa_remove(struct platform_device *dev)
 
 static struct snd_soc_card tosa = {
        .name = "Tosa",
-       .platform = &pxa2xx_soc_platform,
        .dai_link = tosa_dai,
        .num_links = ARRAY_SIZE(tosa_dai),
        .probe = tosa_probe,
        .remove = tosa_remove,
 };
 
-static struct snd_soc_device tosa_snd_devdata = {
-       .card = &tosa,
-       .codec_dev = &soc_codec_dev_wm9712,
-};
-
 static struct platform_device *tosa_snd_device;
 
 static int __init tosa_init(void)
@@ -275,8 +273,7 @@ static int __init tosa_init(void)
                goto err_alloc;
        }
 
-       platform_set_drvdata(tosa_snd_device, &tosa_snd_devdata);
-       tosa_snd_devdata.dev = &tosa_snd_device->dev;
+       platform_set_drvdata(tosa_snd_device, &tosa);
        ret = platform_device_add(tosa_snd_device);
 
        if (!ret)
index 4e4d2fa8ddc5f056de46271aa0f97116350597b1..4cc841b441829bf6f04a2a00f683e4093619a372 100644 (file)
@@ -30,7 +30,6 @@
 #include <mach/z2.h>
 
 #include "../codecs/wm8750.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-i2s.h"
 
 static struct snd_soc_card snd_soc_z2;
@@ -39,8 +38,8 @@ static int z2_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int clk = 0;
        int ret = 0;
 
@@ -138,8 +137,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
 /*
  * Logic for a wm8750 as connected on a Z2 Device
  */
-static int z2_wm8750_init(struct snd_soc_codec *codec)
+static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        int ret;
 
        /* NC codec pins */
@@ -160,7 +160,7 @@ static int z2_wm8750_init(struct snd_soc_codec *codec)
                goto err;
 
        /* Jack detection API stuff */
-       ret = snd_soc_jack_new(&snd_soc_z2, "Headset Jack", SND_JACK_HEADSET,
+       ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET,
                                &hs_jack);
        if (ret)
                goto err;
@@ -189,8 +189,10 @@ static struct snd_soc_ops z2_ops = {
 static struct snd_soc_dai_link z2_dai = {
        .name           = "wm8750",
        .stream_name    = "WM8750",
-       .cpu_dai        = &pxa_i2s_dai,
-       .codec_dai      = &wm8750_dai,
+       .cpu_dai_name   = "pxa2xx-i2s",
+       .codec_dai_name = "wm8750-hifi",
+       .platform_name = "pxa-pcm-audio",
+       .codec_name     = "wm8750-codec.0-001a",
        .init           = z2_wm8750_init,
        .ops            = &z2_ops,
 };
@@ -198,17 +200,10 @@ static struct snd_soc_dai_link z2_dai = {
 /* z2 audio machine driver */
 static struct snd_soc_card snd_soc_z2 = {
        .name           = "Z2",
-       .platform       = &pxa2xx_soc_platform,
        .dai_link       = &z2_dai,
        .num_links      = 1,
 };
 
-/* z2 audio subsystem */
-static struct snd_soc_device z2_snd_devdata = {
-       .card           = &snd_soc_z2,
-       .codec_dev      = &soc_codec_dev_wm8750,
-};
-
 static struct platform_device *z2_snd_device;
 
 static int __init z2_init(void)
@@ -222,8 +217,7 @@ static int __init z2_init(void)
        if (!z2_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(z2_snd_device, &z2_snd_devdata);
-       z2_snd_devdata.dev = &z2_snd_device->dev;
+       platform_set_drvdata(z2_snd_device, &snd_soc_z2);
        ret = platform_device_add(z2_snd_device);
 
        if (ret)
index dd678ae24398bb7f336257a362b43e54eeb25a5f..d27e05af77594093e20b645ef203887683f8b8d5 100644 (file)
@@ -23,7 +23,6 @@
 #include <sound/soc-dapm.h>
 
 #include "../codecs/wm9713.h"
-#include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
 #include "pxa-ssp.h"
 
@@ -71,10 +70,12 @@ static const struct snd_soc_dapm_route audio_map[] = {
        { "Multiactor", NULL, "SPKR" },
 };
 
-static int zylonite_wm9713_init(struct snd_soc_codec *codec)
+static int zylonite_wm9713_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        if (clk_pout)
-               snd_soc_dai_set_pll(&codec->dai[0], 0, 0,
+               snd_soc_dai_set_pll(rtd->codec_dai, 0, 0,
                                    clk_get_rate(pout), 0);
 
        snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets,
@@ -94,8 +95,8 @@ static int zylonite_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->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int pll_out = 0;
        unsigned int wm9713_div = 0;
        int ret = 0;
@@ -163,21 +164,27 @@ static struct snd_soc_dai_link zylonite_dai[] = {
 {
        .name = "AC97",
        .stream_name = "AC97 HiFi",
-       .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
-       .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
+       .codec_name = "wm9713-codec",
+       .platform_name = "pxa-pcm-audio",
+       .cpu_dai_name = "pxa-ac97.0",
+       .codec_name = "wm9713-hifi",
        .init = zylonite_wm9713_init,
 },
 {
        .name = "AC97 Aux",
        .stream_name = "AC97 Aux",
-       .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
-       .codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX],
+       .codec_name = "wm9713-codec",
+       .platform_name = "pxa-pcm-audio",
+       .cpu_dai_name = "pxa-ac97.1",
+       .codec_name = "wm9713-aux",
 },
 {
        .name = "WM9713 Voice",
        .stream_name = "WM9713 Voice",
-       .cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP3],
-       .codec_dai = &wm9713_dai[WM9713_DAI_PCM_VOICE],
+       .codec_name = "wm9713-codec",
+       .platform_name = "pxa-pcm-audio",
+       .cpu_dai_name = "pxa-ssp-dai.2",
+       .codec_name = "wm9713-voice",
        .ops = &zylonite_voice_ops,
 },
 };
@@ -248,14 +255,9 @@ static struct snd_soc_card zylonite = {
        .remove = &zylonite_remove,
        .suspend_post = &zylonite_suspend_post,
        .resume_pre = &zylonite_resume_pre,
-       .platform = &pxa2xx_soc_platform,
        .dai_link = zylonite_dai,
        .num_links = ARRAY_SIZE(zylonite_dai),
-};
-
-static struct snd_soc_device zylonite_snd_ac97_devdata = {
-       .card = &zylonite,
-       .codec_dev = &soc_codec_dev_wm9713,
+       .owner = THIS_MODULE,
 };
 
 static struct platform_device *zylonite_snd_ac97_device;
@@ -268,9 +270,7 @@ static int __init zylonite_init(void)
        if (!zylonite_snd_ac97_device)
                return -ENOMEM;
 
-       platform_set_drvdata(zylonite_snd_ac97_device,
-                            &zylonite_snd_ac97_devdata);
-       zylonite_snd_ac97_devdata.dev = &zylonite_snd_ac97_device->dev;
+       platform_set_drvdata(zylonite_snd_ac97_device, &zylonite);
 
        ret = platform_device_add(zylonite_snd_ac97_device);
        if (ret != 0)
index 213963ac3c28ba4aaa236c399f5211356f469625..8a6b53ccd203e0a8dfe14dd7579325284e736591 100644 (file)
@@ -36,6 +36,10 @@ 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
@@ -118,6 +122,14 @@ config SND_S3C24XX_SOC_SIMTEC_HERMES
        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)
@@ -131,3 +143,28 @@ config SND_S3C64XX_SOC_SMARTQ
        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.
index 50172c385d90b89e7fc327a596efc235f95cca55..ee8f41d6df994e9eb7c3f5507a3a7d6c7023e293 100644 (file)
@@ -7,6 +7,7 @@ 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
@@ -16,6 +17,7 @@ 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
@@ -27,9 +29,13 @@ 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
@@ -40,6 +46,10 @@ 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
new file mode 100644 (file)
index 0000000..235d197
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..694f702
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * 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");
index 8c108b121c10de97f4fbc2f786b54e40c23f9b8f..49605cd83947efc04f7cc6f7cbd4b4bc88614e0d 100644 (file)
@@ -49,8 +49,8 @@ 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->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       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;
@@ -108,8 +108,9 @@ static struct snd_soc_ops jive_ops = {
        .hw_params      = jive_hw_params,
 };
 
-static int jive_wm8750_init(struct snd_soc_codec *codec)
+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. */
@@ -138,8 +139,10 @@ static int jive_wm8750_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link jive_dai = {
        .name           = "wm8750",
        .stream_name    = "WM8750",
-       .cpu_dai        = &s3c2412_i2s_dai,
-       .codec_dai      = &wm8750_dai,
+       .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,
 };
@@ -147,17 +150,10 @@ static struct snd_soc_dai_link jive_dai = {
 /* jive audio machine driver */
 static struct snd_soc_card snd_soc_machine_jive = {
        .name           = "Jive",
-       .platform       = &s3c24xx_soc_platform,
        .dai_link       = &jive_dai,
        .num_links      = 1,
 };
 
-/* jive audio subsystem */
-static struct snd_soc_device jive_snd_devdata = {
-       .card           = &snd_soc_machine_jive,
-       .codec_dev      = &soc_codec_dev_wm8750,
-};
-
 static struct platform_device *jive_snd_device;
 
 static int __init jive_init(void)
@@ -173,8 +169,7 @@ static int __init jive_init(void)
        if (!jive_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(jive_snd_device, &jive_snd_devdata);
-       jive_snd_devdata.dev = &jive_snd_device->dev;
+       platform_set_drvdata(jive_snd_device, &snd_soc_machine_jive);
        ret = platform_device_add(jive_snd_device);
 
        if (ret)
index ffa954fe6931bea522fb02360b8f4877524884bb..abe64abe8c8423ad5f403532a9d40d8234d5b15b 100644 (file)
@@ -23,7 +23,6 @@
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 
-#include "../codecs/ac97.h"
 #include "s3c-dma.h"
 #include "s3c-ac97.h"
 
@@ -33,23 +32,19 @@ static struct snd_soc_dai_link ln2440sbc_dai[] = {
 {
        .name = "AC97",
        .stream_name = "AC97 HiFi",
-       .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
-       .codec_dai = &ac97_dai,
+       .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",
-       .platform = &s3c24xx_soc_platform,
        .dai_link = ln2440sbc_dai,
        .num_links = ARRAY_SIZE(ln2440sbc_dai),
 };
 
-static struct snd_soc_device ln2440sbc_snd_ac97_devdata = {
-       .card = &ln2440sbc,
-       .codec_dev = &soc_codec_dev_ac97,
-};
-
 static struct platform_device *ln2440sbc_snd_ac97_device;
 
 static int __init ln2440sbc_init(void)
@@ -60,9 +55,7 @@ static int __init ln2440sbc_init(void)
        if (!ln2440sbc_snd_ac97_device)
                return -ENOMEM;
 
-       platform_set_drvdata(ln2440sbc_snd_ac97_device,
-                               &ln2440sbc_snd_ac97_devdata);
-       ln2440sbc_snd_ac97_devdata.dev = &ln2440sbc_snd_ac97_device->dev;
+       platform_set_drvdata(ln2440sbc_snd_ac97_device, &ln2440sbc);
        ret = platform_device_add(ln2440sbc_snd_ac97_device);
 
        if (ret)
index 4719558289d402e20a410154ccbef239632c7ac9..e97bdf150a03042e34d231ddc507c5c33e79f95d 100644 (file)
@@ -41,8 +41,8 @@ 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->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       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;
@@ -130,7 +130,7 @@ static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream,
 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->dai->codec_dai;
+       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);
@@ -149,7 +149,7 @@ static int neo1973_gta02_voice_hw_params(
        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 *codec_dai = rtd->codec_dai;
        unsigned int pcmdiv = 0;
        int ret = 0;
        unsigned long iis_clkrate;
@@ -194,7 +194,7 @@ static int neo1973_gta02_voice_hw_params(
 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->dai->codec_dai;
+       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);
@@ -262,7 +262,7 @@ 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(value));
+       gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event));
 
        return 0;
 }
@@ -330,8 +330,9 @@ static const struct snd_kcontrol_new wm8753_neo1973_gta02_controls[] = {
  * This is an example machine initialisation for a wm8753 connected to a
  * neo1973 GTA02.
  */
-static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec)
+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 */
@@ -378,9 +379,8 @@ static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec)
 /*
  * BT Codec DAI
  */
-static struct snd_soc_dai bt_dai = {
-       .name = "Bluetooth",
-       .id = 0,
+static struct snd_soc_dai_driver bt_dai = {
+       .name = "bluetooth-dai",
        .playback = {
                .channels_min = 1,
                .channels_max = 1,
@@ -397,32 +397,30 @@ 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 = &s3c24xx_i2s_dai,
-       .codec_dai = &wm8753_dai[WM8753_DAI_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 = &bt_dai,
-       .codec_dai = &wm8753_dai[WM8753_DAI_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",
-       .platform = &s3c24xx_soc_platform,
        .dai_link = neo1973_gta02_dai,
        .num_links = ARRAY_SIZE(neo1973_gta02_dai),
 };
 
-static struct snd_soc_device neo1973_gta02_snd_devdata = {
-       .card = &neo1973_gta02,
-       .codec_dev = &soc_codec_dev_wm8753,
-};
-
 static struct platform_device *neo1973_gta02_snd_device;
 
 static int __init neo1973_gta02_init(void)
@@ -435,18 +433,18 @@ static int __init neo1973_gta02_init(void)
                return -ENODEV;
        }
 
-       /* register bluetooth DAI here */
-       ret = snd_soc_register_dai(&bt_dai);
-       if (ret)
-               return ret;
-
        neo1973_gta02_snd_device = platform_device_alloc("soc-audio", -1);
        if (!neo1973_gta02_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(neo1973_gta02_snd_device,
-                       &neo1973_gta02_snd_devdata);
-       neo1973_gta02_snd_devdata.dev = &neo1973_gta02_snd_device->dev;
+       /* 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) {
@@ -461,7 +459,7 @@ static int __init neo1973_gta02_init(void)
                goto err_unregister_device;
        }
 
-       ret = gpio_direction_output(GTA02_GPIO_AMP_HP_IN, 1);
+       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;
@@ -493,7 +491,7 @@ module_init(neo1973_gta02_init);
 
 static void __exit neo1973_gta02_exit(void)
 {
-       snd_soc_unregister_dai(&bt_dai);
+       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);
index 4ac620988e7c1d0894de39f7c39e6ba29e4dd0e2..f4f2ee731f0140123955c53c308ebf5071b39eea 100644 (file)
@@ -57,8 +57,8 @@ 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->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       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;
@@ -147,7 +147,7 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
 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->dai->codec_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
        pr_debug("Entered %s\n", __func__);
 
@@ -167,7 +167,7 @@ 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->dai->codec_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        unsigned int pcmdiv = 0;
        int ret = 0;
        unsigned long iis_clkrate;
@@ -213,7 +213,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
 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->dai->codec_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
        pr_debug("Entered %s\n", __func__);
 
@@ -499,8 +499,9 @@ static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
  * 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_codec *codec)
+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__);
@@ -538,8 +539,7 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec)
  * BT Codec DAI
  */
 static struct snd_soc_dai bt_dai = {
-       .name = "Bluetooth",
-       .id = 0,
+       .name = "bluetooth-dai",
        .playback = {
                .channels_min = 1,
                .channels_max = 1,
@@ -556,32 +556,30 @@ static struct snd_soc_dai_link neo1973_dai[] = {
 { /* Hifi Playback - for similatious use with voice below */
        .name = "WM8753",
        .stream_name = "WM8753 HiFi",
-       .cpu_dai = &s3c24xx_i2s_dai,
-       .codec_dai = &wm8753_dai[WM8753_DAI_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",
-       .cpu_dai = &bt_dai,
-       .codec_dai = &wm8753_dai[WM8753_DAI_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",
-       .platform = &s3c24xx_soc_platform,
        .dai_link = neo1973_dai,
        .num_links = ARRAY_SIZE(neo1973_dai),
 };
 
-static struct snd_soc_device neo1973_snd_devdata = {
-       .card = &neo1973,
-       .codec_dev = &soc_codec_dev_wm8753,
-};
-
 static int lm4857_i2c_probe(struct i2c_client *client,
                            const struct i2c_device_id *id)
 {
@@ -673,8 +671,7 @@ static int __init neo1973_init(void)
        if (!neo1973_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(neo1973_snd_device, &neo1973_snd_devdata);
-       neo1973_snd_devdata.dev = &neo1973_snd_device->dev;
+       platform_set_drvdata(neo1973_snd_device, &neo1973);
        ret = platform_device_add(neo1973_snd_device);
 
        if (ret) {
diff --git a/sound/soc/s3c24xx/rx1950_uda1380.c b/sound/soc/s3c24xx/rx1950_uda1380.c
new file mode 100644 (file)
index 0000000..ffd5cf2
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * 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,
+       88200,
+};
+
+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 struct clk *xtal;
+
+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_256FS;
+               div = clk_get_rate(xtal) / (256 * rate);
+               if (clk_get_rate(xtal) % (256 * rate) > (128 * rate))
+                       div++;
+               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,
+               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 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;
+       }
+
+       xtal = clk_get(&s3c24xx_snd_device->dev, "xtal");
+
+       if (IS_ERR(xtal)) {
+               ret = PTR_ERR(xtal);
+               platform_device_unregister(s3c24xx_snd_device);
+               goto err_clk;
+       }
+
+       return 0;
+
+err_clk:
+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);
+       clk_put(xtal);
+       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");
index 31f6d45b6384f2f0e0e4e5a351acc79a6f47520b..f891eb79b5754b19fd0dd443a09481cd2eb743b1 100644 (file)
@@ -89,7 +89,7 @@ static void s3c_ac97_activate(struct snd_ac97 *ac97)
        writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
 
        if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
-               printk(KERN_ERR "AC97: Unable to activate!");
+               pr_err("AC97: Unable to activate!");
 }
 
 static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
@@ -115,14 +115,15 @@ static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
        writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
 
        if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
-               printk(KERN_ERR "AC97: Unable to read!");
+               pr_err("AC97: Unable to read!");
 
        stat = readl(s3c_ac97.regs + S3C_AC97_STAT);
        addr = (stat >> 16) & 0x7f;
        data = (stat & 0xffff);
 
        if (addr != reg)
-               printk(KERN_ERR "s3c-ac97: req addr = %02x, rep addr = %02x\n", reg, addr);
+               pr_err("s3c-ac97: req addr = %02x, rep addr = %02x\n",
+                       reg, addr);
 
        mutex_unlock(&s3c_ac97.lock);
 
@@ -151,7 +152,7 @@ static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
        writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
 
        if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
-               printk(KERN_ERR "AC97: Unable to write!");
+               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;
@@ -162,6 +163,7 @@ static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 
 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);
@@ -178,6 +180,8 @@ static void s3c_ac97_warm_reset(struct snd_ac97 *ac97)
        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);
 
@@ -222,7 +226,7 @@ static int s3c_ac97_hw_params(struct snd_pcm_substream *substream,
                                  struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct s3c_dma_params *dma_data;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -241,7 +245,7 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
        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->dai->cpu_dai, substream);
+               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)
@@ -277,7 +281,7 @@ static int s3c_ac97_hw_mic_params(struct snd_pcm_substream *substream,
                                      struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                return -ENODEV;
@@ -293,7 +297,7 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
        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->dai->cpu_dai, substream);
+               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;
@@ -328,10 +332,9 @@ static struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = {
        .trigger        = s3c_ac97_mic_trigger,
 };
 
-struct snd_soc_dai s3c_ac97_dai[] = {
+static struct snd_soc_dai_driver s3c_ac97_dai[] = {
        [S3C_AC97_DAI_PCM] = {
                .name = "s3c-ac97",
-               .id = S3C_AC97_DAI_PCM,
                .ac97_control = 1,
                .playback = {
                        .stream_name = "AC97 Playback",
@@ -349,7 +352,6 @@ struct snd_soc_dai s3c_ac97_dai[] = {
        },
        [S3C_AC97_DAI_MIC] = {
                .name = "s3c-ac97-mic",
-               .id = S3C_AC97_DAI_MIC,
                .ac97_control = 1,
                .capture = {
                        .stream_name = "AC97 Mic Capture",
@@ -360,7 +362,6 @@ struct snd_soc_dai s3c_ac97_dai[] = {
                .ops = &s3c_ac97_mic_dai_ops,
        },
 };
-EXPORT_SYMBOL_GPL(s3c_ac97_dai);
 
 static __devinit int s3c_ac97_probe(struct platform_device *pdev)
 {
@@ -445,14 +446,12 @@ static __devinit int s3c_ac97_probe(struct platform_device *pdev)
        ret = request_irq(irq_res->start, s3c_ac97_irq,
                                        IRQF_DISABLED, "AC97", NULL);
        if (ret < 0) {
-               printk(KERN_ERR "s3c-ac97: interrupt request failed.\n");
+               dev_err(&pdev->dev, "s3c-ac97: interrupt request failed.\n");
                goto err4;
        }
 
-       s3c_ac97_dai[S3C_AC97_DAI_PCM].dev = &pdev->dev;
-       s3c_ac97_dai[S3C_AC97_DAI_MIC].dev = &pdev->dev;
-
-       ret = snd_soc_register_dais(s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
+       ret = snd_soc_register_dais(&pdev->dev, s3c_ac97_dai,
+                       ARRAY_SIZE(s3c_ac97_dai));
        if (ret)
                goto err5;
 
@@ -476,7 +475,7 @@ static __devexit int s3c_ac97_remove(struct platform_device *pdev)
 {
        struct resource *mem_res, *irq_res;
 
-       snd_soc_unregister_dais(s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
+       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai));
 
        irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (irq_res)
@@ -518,3 +517,4 @@ 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");
index 278198379defa343fcaf905b99e03d897a8b3272..5dcedd07fdbbfdbfaab687e4fa4bea4dce6f9d04 100644 (file)
@@ -18,6 +18,4 @@
 #define S3C_AC97_DAI_PCM 0
 #define S3C_AC97_DAI_MIC 1
 
-extern struct snd_soc_dai s3c_ac97_dai[];
-
 #endif /* __S3C_AC97_H_ */
index f1b1bc4bacfb7134d588469cbcd0b5032747f0ae..243f79bf43bb127fabffa4474db175f4d297ea29 100644 (file)
@@ -146,7 +146,7 @@ static int s3c_dma_hw_params(struct snd_pcm_substream *substream,
        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->dai->cpu_dai, substream);
+               snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
        int ret = 0;
 
 
@@ -440,14 +440,14 @@ static int s3c_dma_new(struct snd_card *card,
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = 0xffffffff;
 
-       if (dai->playback.channels_min) {
+       if (dai->driver->playback.channels_min) {
                ret = s3c_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
 
-       if (dai->capture.channels_min) {
+       if (dai->driver->capture.channels_min) {
                ret = s3c_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
@@ -457,26 +457,46 @@ static int s3c_dma_new(struct snd_card *card,
        return ret;
 }
 
-struct snd_soc_platform s3c24xx_soc_platform = {
-       .name           = "s3c24xx-audio",
-       .pcm_ops        = &s3c_dma_ops,
+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,
 };
-EXPORT_SYMBOL_GPL(s3c24xx_soc_platform);
 
-static int __init s3c24xx_soc_platform_init(void)
+static int __devinit s3c24xx_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&s3c24xx_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &s3c24xx_soc_platform);
 }
-module_init(s3c24xx_soc_platform_init);
 
-static void __exit s3c24xx_soc_platform_exit(void)
+static int __devexit s3c24xx_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&s3c24xx_soc_platform);
+       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(s3c24xx_soc_platform_exit);
+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");
index 69bb6bf6fc1c2a99a475313375a56969310b6f35..748c07d7c07578206cee11fff74be10be476814c 100644 (file)
@@ -25,7 +25,6 @@ struct s3c_dma_params {
 #define S3C24XX_DAI_I2S                        0
 
 /* platform data */
-extern struct snd_soc_platform s3c24xx_soc_platform;
 extern struct snd_ac97_bus_ops s3c24xx_ac97_ops;
 
 #endif
index 64376b2aac73ce8854daa3226368aee7e59ae223..b3866d5b19e95abb379df36b25692a4615af3dc4 100644 (file)
@@ -49,7 +49,7 @@
 
 static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
 {
-       return cpu_dai->private_data;
+       return snd_soc_dai_get_drvdata(cpu_dai);
 }
 
 #define bit_set(v, b) (((v) & (b)) ? 1 : 0)
@@ -307,11 +307,9 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
 
 static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
-                                struct snd_soc_dai *socdai)
+                                struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai_link *dai = rtd->dai;
-       struct s3c_i2sv2_info *i2s = to_info(dai->cpu_dai);
+       struct s3c_i2sv2_info *i2s = to_info(dai);
        struct s3c_dma_params *dma_data;
        u32 iismod;
 
@@ -322,7 +320,7 @@ static int s3c_i2sv2_hw_params(struct snd_pcm_substream *substream,
        else
                dma_data = i2s->dma_capture;
 
-       snd_soc_dai_set_dma_data(dai->cpu_dai, substream, dma_data);
+       snd_soc_dai_set_dma_data(dai, substream, dma_data);
 
        /* Working copies of register */
        iismod = readl(i2s->regs + S3C2412_IISMOD);
@@ -396,12 +394,12 @@ 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->dai->cpu_dai);
+       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->dai->cpu_dai, substream);
+               snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        pr_debug("Entered %s\n", __func__);
 
@@ -640,36 +638,17 @@ int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
 }
 EXPORT_SYMBOL_GPL(s3c_i2sv2_iis_calc_rate);
 
-int s3c_i2sv2_probe(struct platform_device *pdev,
-                   struct snd_soc_dai *dai,
+int s3c_i2sv2_probe(struct snd_soc_dai *dai,
                    struct s3c_i2sv2_info *i2s,
                    unsigned long base)
 {
-       struct device *dev = &pdev->dev;
+       struct device *dev = dai->dev;
        unsigned int iismod;
 
        i2s->dev = dev;
 
        /* record our i2s structure for later use in the callbacks */
-       dai->private_data = i2s;
-
-       if (!base) {
-               struct resource *res = platform_get_resource(pdev,
-                                                            IORESOURCE_MEM,
-                                                            0);
-               if (!res) {
-                       dev_err(dev, "Unable to get register resource\n");
-                       return -ENXIO;
-               }
-
-               if (!request_mem_region(res->start, resource_size(res),
-                                       "s3c64xx-i2s-v4")) {
-                       dev_err(dev, "Unable to request register region\n");
-                       return -EBUSY;
-               }
-
-               base = res->start;
-       }
+       snd_soc_dai_set_drvdata(dai, i2s);
 
        i2s->regs = ioremap(base, 0x100);
        if (i2s->regs == NULL) {
@@ -752,9 +731,10 @@ static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
 #define s3c2412_i2s_resume  NULL
 #endif
 
-int s3c_i2sv2_register_dai(struct snd_soc_dai *dai)
+int s3c_i2sv2_register_dai(struct device *dev, int id,
+               struct snd_soc_dai_driver *drv)
 {
-       struct snd_soc_dai_ops *ops = dai->ops;
+       struct snd_soc_dai_ops *ops = drv->ops;
 
        ops->trigger = s3c2412_i2s_trigger;
        if (!ops->hw_params)
@@ -767,10 +747,10 @@ int s3c_i2sv2_register_dai(struct snd_soc_dai *dai)
        if (!ops->delay)
                ops->delay = s3c2412_i2s_delay;
 
-       dai->suspend = s3c2412_i2s_suspend;
-       dai->resume = s3c2412_i2s_resume;
+       drv->suspend = s3c2412_i2s_suspend;
+       drv->resume = s3c2412_i2s_resume;
 
-       return snd_soc_register_dai(dai);
+       return snd_soc_register_dai(dev, drv);
 }
 EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai);
 
index 766f43a13d8be29fe769b860fc71e2b120b93aa7..d45830151484a62610baa69a9c32e3580f2cfeef 100644 (file)
@@ -66,6 +66,8 @@ struct s3c_i2sv2_info {
        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);
@@ -81,23 +83,24 @@ extern int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
 
 /**
  * s3c_i2sv2_probe - probe for i2s device helper
- * @pdev: The platform device supplied to the original probe.
  * @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 platform_device *pdev,
-                          struct snd_soc_dai *dai,
+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
- * @dai: The snd_soc_dai structure to register
+ * @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 snd_soc_dai *dai);
+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 */
index 326f0a9e7e3076ebbce6af2500c86cb56fce5f60..2e020e1b4eab027640a0e92b4f0506305c0297f9 100644 (file)
@@ -64,11 +64,6 @@ static struct s3c_dma_params s3c_pcm_stereo_in[] = {
 
 static struct s3c_pcm_info s3c_pcm[2];
 
-static inline struct s3c_pcm_info *to_info(struct snd_soc_dai *cpu_dai)
-{
-       return cpu_dai->private_data;
-}
-
 static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on)
 {
        void __iomem *regs = pcm->regs;
@@ -83,7 +78,7 @@ static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on)
                ctl |= S3C_PCM_CTL_TXDMA_EN;
                ctl |= S3C_PCM_CTL_TXFIFO_EN;
                ctl |= S3C_PCM_CTL_ENABLE;
-               ctl |= (0x20<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
+               ctl |= (0x4<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
                clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
        } else {
                ctl &= ~S3C_PCM_CTL_TXDMA_EN;
@@ -107,11 +102,14 @@ static void s3c_pcm_snd_rxctrl(struct s3c_pcm_info *pcm, int on)
 
        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;
@@ -132,7 +130,7 @@ 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 = to_info(rtd->dai->cpu_dai);
+       struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        unsigned long flags;
 
        dev_dbg(pcm->dev, "Entered %s\n", __func__);
@@ -176,8 +174,7 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *socdai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai_link *dai = rtd->dai;
-       struct s3c_pcm_info *pcm = to_info(dai->cpu_dai);
+       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;
@@ -192,7 +189,7 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
        else
                dma_data = pcm->dma_capture;
 
-       snd_soc_dai_set_dma_data(dai->cpu_dai, substream, dma_data);
+       snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
 
        /* Strictly check for sample size */
        switch (params_format(params)) {
@@ -242,7 +239,7 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
 static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai,
                               unsigned int fmt)
 {
-       struct s3c_pcm_info *pcm = to_info(cpu_dai);
+       struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
        void __iomem *regs = pcm->regs;
        unsigned long flags;
        int ret = 0;
@@ -313,7 +310,7 @@ exit:
 static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai,
                                                int div_id, int div)
 {
-       struct s3c_pcm_info *pcm = to_info(cpu_dai);
+       struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
 
        switch (div_id) {
        case S3C_PCM_SCLK_PER_FS:
@@ -330,7 +327,7 @@ static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai,
 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 = to_info(cpu_dai);
+       struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(cpu_dai);
        void __iomem *regs = pcm->regs;
        u32 clkctl = readl(regs + S3C_PCM_CLKCTL);
 
@@ -366,10 +363,7 @@ static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
 
 #define S3C_PCM_RATES  SNDRV_PCM_RATE_8000_96000
 
-#define S3C_PCM_DECLARE(n)                     \
-{                                                              \
-       .name            = "samsung-pcm",                       \
-       .id              = (n),                         \
+#define S3C_PCM_DAI_DECLARE                    \
        .symmetric_rates = 1,                                   \
        .ops = &s3c_pcm_dai_ops,                                \
        .playback = {                                           \
@@ -383,19 +377,23 @@ static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
                .channels_max   = 2,                            \
                .rates          = S3C_PCM_RATES,                \
                .formats        = SNDRV_PCM_FMTBIT_S16_LE,      \
-       },                                                      \
-}
+       }
 
-struct snd_soc_dai s3c_pcm_dai[] = {
-       S3C_PCM_DECLARE(0),
-       S3C_PCM_DECLARE(1),
+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 snd_soc_dai *dai;
        struct resource *mem_res, *dmatx_res, *dmarx_res;
        struct s3c_audio_pdata *pcm_pdata;
        int ret;
@@ -437,9 +435,6 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
 
        spin_lock_init(&pcm->lock);
 
-       dai = &s3c_pcm_dai[pdev->id];
-       dai->dev = &pdev->dev;
-
        /* Default is 128fs */
        pcm->sclk_per_fs = 128;
 
@@ -452,7 +447,7 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
        clk_enable(pcm->cclk);
 
        /* record our pcm structure for later use in the callbacks */
-       dai->private_data = pcm;
+       dev_set_drvdata(&pdev->dev, pcm);
 
        if (!request_mem_region(mem_res->start,
                                resource_size(mem_res), "samsung-pcm")) {
@@ -476,7 +471,7 @@ static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
        }
        clk_enable(pcm->pclk);
 
-       ret = snd_soc_register_dai(dai);
+       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;
@@ -514,6 +509,8 @@ 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);
@@ -552,3 +549,4 @@ module_exit(s3c_pcm_exit);
 MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
 MODULE_DESCRIPTION("S3C PCM Controller Driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-pcm");
index 69ff9971692f8cfa4a5831f8b8f8b5e98e5da58d..f60baa19387d914551b1bb38daf75fb782e2faff 100644 (file)
@@ -22,7 +22,8 @@
 /* PCM_CTL Bit-Fields */
 #define S3C_PCM_CTL_TXDIPSTICK_MASK            (0x3f)
 #define S3C_PCM_CTL_TXDIPSTICK_SHIFT   (13)
-#define S3C_PCM_CTL_RXDIPSTICK_MSK             (0x3f<<7)
+#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)
index 709adef9d0435554a78cfa082fd31d4475d145a3..4a861cfa52c5643852d2612028d3c1d71ffe7d5d 100644 (file)
@@ -65,26 +65,20 @@ static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = {
 
 static struct s3c_i2sv2_info s3c2412_i2s;
 
-static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
-{
-       return cpu_dai->private_data;
-}
-
-static int s3c2412_i2s_probe(struct platform_device *pdev,
-                            struct snd_soc_dai *dai)
+static int s3c2412_i2s_probe(struct snd_soc_dai *dai)
 {
        int ret;
 
        pr_debug("Entered %s\n", __func__);
 
-       ret = s3c_i2sv2_probe(pdev, dai, &s3c2412_i2s, S3C2410_PA_IIS);
+       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(&pdev->dev, "i2sclk");
+       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);
@@ -108,11 +102,20 @@ static int s3c2412_i2s_probe(struct platform_device *pdev,
        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 = to_info(cpu_dai);
+       struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(cpu_dai);
        struct s3c_dma_params *dma_data;
        u32 iismod;
 
@@ -152,10 +155,9 @@ static struct snd_soc_dai_ops s3c2412_i2s_dai_ops = {
        .hw_params      = s3c2412_i2s_hw_params,
 };
 
-struct snd_soc_dai s3c2412_i2s_dai = {
-       .name           = "s3c2412-i2s",
-       .id             = 0,
+static struct snd_soc_dai_driver s3c2412_i2s_dai = {
        .probe          = s3c2412_i2s_probe,
+       .remove = s3c2412_i2s_remove,
        .playback = {
                .channels_min   = 2,
                .channels_max   = 2,
@@ -170,17 +172,36 @@ struct snd_soc_dai s3c2412_i2s_dai = {
        },
        .ops = &s3c2412_i2s_dai_ops,
 };
-EXPORT_SYMBOL_GPL(s3c2412_i2s_dai);
+
+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  s3c_i2sv2_register_dai(&s3c2412_i2s_dai);
+       return platform_driver_register(&s3c2412_iis_driver);
 }
 module_init(s3c2412_i2s_init);
 
 static void __exit s3c2412_i2s_exit(void)
 {
-       snd_soc_unregister_dai(&s3c2412_i2s_dai);
+       platform_driver_unregister(&s3c2412_iis_driver);
 }
 module_exit(s3c2412_i2s_exit);
 
@@ -188,3 +209,4 @@ module_exit(s3c2412_i2s_exit);
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("S3C2412 I2S SoC Interface");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c2412-iis");
index 0b5686b4d5c36fb4c307132b6c654017dd583657..01a0471ac65c88ac79622ec96f653f4fe24aa67a 100644 (file)
@@ -24,6 +24,4 @@
 #define S3C2412_CLKSRC_PCLK    S3C_I2SV2_CLKSRC_PCLK
 #define S3C2412_CLKSRC_I2SCLK  S3C_I2SV2_CLKSRC_AUDIOBUS
 
-extern struct snd_soc_dai s3c2412_i2s_dai;
-
 #endif /* __SND_SOC_S3C24XX_S3C2412_I2S_H */
index c3ac890a3986184f86ed00a1dc300fdb10d7d258..e060daaa458f80bf63ecacfb25731fbb93c497e3 100644 (file)
@@ -252,7 +252,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
        else
                dma_data = &s3c24xx_i2s_pcm_stereo_in;
 
-       snd_soc_dai_set_dma_data(rtd->dai->cpu_dai, substream, dma_data);
+       snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
 
        /* Working copies of register */
        iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
@@ -280,9 +280,8 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
                               struct snd_soc_dai *dai)
 {
        int ret = 0;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct s3c_dma_params *dma_data =
-               snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+               snd_soc_dai_get_dma_data(dai, substream);
 
        pr_debug("Entered %s\n", __func__);
 
@@ -387,8 +386,7 @@ u32 s3c24xx_i2s_get_clockrate(void)
 }
 EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
 
-static int s3c24xx_i2s_probe(struct platform_device *pdev,
-                            struct snd_soc_dai *dai)
+static int s3c24xx_i2s_probe(struct snd_soc_dai *dai)
 {
        pr_debug("Entered %s\n", __func__);
 
@@ -396,7 +394,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev,
        if (s3c24xx_i2s.regs == NULL)
                return -ENXIO;
 
-       s3c24xx_i2s.iis_clk = clk_get(&pdev->dev, "iis");
+       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);
@@ -465,9 +463,7 @@ static struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = {
        .set_sysclk     = s3c24xx_i2s_set_sysclk,
 };
 
-struct snd_soc_dai s3c24xx_i2s_dai = {
-       .name = "s3c24xx-i2s",
-       .id = 0,
+static struct snd_soc_dai_driver s3c24xx_i2s_dai = {
        .probe = s3c24xx_i2s_probe,
        .suspend = s3c24xx_i2s_suspend,
        .resume = s3c24xx_i2s_resume,
@@ -483,17 +479,36 @@ struct snd_soc_dai s3c24xx_i2s_dai = {
                .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
        .ops = &s3c24xx_i2s_dai_ops,
 };
-EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai);
+
+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 snd_soc_register_dai(&s3c24xx_i2s_dai);
+       return platform_driver_register(&s3c24xx_iis_driver);
 }
 module_init(s3c24xx_i2s_init);
 
 static void __exit s3c24xx_i2s_exit(void)
 {
-       snd_soc_unregister_dai(&s3c24xx_i2s_dai);
+       platform_driver_unregister(&s3c24xx_iis_driver);
 }
 module_exit(s3c24xx_i2s_exit);
 
@@ -501,3 +516,4 @@ module_exit(s3c24xx_i2s_exit);
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("s3c24xx I2S SoC Interface");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c24xx-iis");
index 726d91cf4e1cfcbf624facdf7c0a697962bab190..f9ca04edacb7a4283a17bb2105b4d750478644ce 100644 (file)
@@ -32,6 +32,4 @@
 
 u32 s3c24xx_i2s_get_clockrate(void);
 
-extern struct snd_soc_dai s3c24xx_i2s_dai;
-
 #endif /*S3C24XXI2S_H_*/
index 4984754f3298dac412f9ee22dfbce4de5f5804f8..c4c1114420109944bdbf73cdeda17083a054e5e7 100644 (file)
@@ -139,8 +139,10 @@ static const struct snd_kcontrol_new amp_unmute_controls[] = {
                       speaker_unmute_get, speaker_unmute_put),
 };
 
-void simtec_audio_init(struct snd_soc_codec *codec)
+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__);
 
@@ -170,8 +172,8 @@ 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->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       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 */
@@ -319,12 +321,12 @@ EXPORT_SYMBOL_GPL(simtec_audio_pmops);
 #endif
 
 int __devinit simtec_audio_core_probe(struct platform_device *pdev,
-                                     struct snd_soc_device *socdev)
+                                     struct snd_soc_card *card)
 {
        struct platform_device *snd_dev;
        int ret;
 
-       socdev->card->dai_link->ops = &simtec_snd_ops;
+       card->dai_link->ops = &simtec_snd_ops;
 
        pdata = pdev->dev.platform_data;
        if (!pdata) {
@@ -353,8 +355,7 @@ int __devinit simtec_audio_core_probe(struct platform_device *pdev,
                goto err_gpio;
        }
 
-       platform_set_drvdata(snd_dev, socdev);
-       socdev->dev = &snd_dev->dev;
+       platform_set_drvdata(snd_dev, card);
 
        ret = platform_device_add(snd_dev);
        if (ret) {
index e18faee30cce0a388b2d06d2ba9a676200117d16..e63d5ff9c41fe4a42c64a6ea3b3960bf3046e14d 100644 (file)
@@ -7,10 +7,10 @@
  * published by the Free Software Foundation.
 */
 
-extern void simtec_audio_init(struct snd_soc_codec *codec);
+extern void simtec_audio_init(struct snd_soc_pcm_runtime *rtd);
 
 extern int simtec_audio_core_probe(struct platform_device *pdev,
-                                  struct snd_soc_device *socdev);
+                                  struct snd_soc_card *card);
 
 extern int simtec_audio_remove(struct platform_device *pdev);
 
index bdf8951af8e38fac1a7e88ff8be274ce4e7e1815..f88453735ae26e47c98f1c407c789df24227d638 100644 (file)
@@ -73,8 +73,10 @@ static const struct snd_soc_dapm_route base_map[] = {
  * Attach our controls and configure the necessary codec
  * mappings for our sound card instance.
 */
-static int simtec_hermes_init(struct snd_soc_codec *codec)
+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));
 
@@ -85,42 +87,33 @@ static int simtec_hermes_init(struct snd_soc_codec *codec)
        snd_soc_dapm_enable_pin(codec, "Line Out");
        snd_soc_dapm_enable_pin(codec, "Mic Jack");
 
-       simtec_audio_init(codec);
+       simtec_audio_init(rtd);
        snd_soc_dapm_sync(codec);
 
        return 0;
 }
 
-static struct aic3x_setup_data codec_setup = {
-};
-
 static struct snd_soc_dai_link simtec_dai_aic33 = {
        .name           = "tlv320aic33",
        .stream_name    = "TLV320AIC33",
-       .cpu_dai        = &s3c24xx_i2s_dai,
-       .codec_dai      = &aic3x_dai,
+       .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",
-       .platform       = &s3c24xx_soc_platform,
        .dai_link       = &simtec_dai_aic33,
        .num_links      = 1,
 };
 
-/* simtec audio subsystem */
-static struct snd_soc_device simtec_snd_devdata_aic33 = {
-       .card           = &snd_soc_machine_simtec_aic33,
-       .codec_dev      = &soc_codec_dev_aic3x,
-       .codec_data     = &codec_setup,
-};
-
 static int __devinit simtec_audio_hermes_probe(struct platform_device *pd)
 {
        dev_info(&pd->dev, "probing....\n");
-       return simtec_audio_core_probe(pd, &simtec_snd_devdata_aic33);
+       return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic33);
 }
 
 static struct platform_driver simtec_audio_hermes_platdrv = {
index 185c0acb5ce6b8f7fff39c3fd008477ad4c6d11e..c0967593510d1f294d63ae23581d1e4cb1bf54fb 100644 (file)
@@ -62,8 +62,10 @@ static const struct snd_soc_dapm_route base_map[] = {
  * Attach our controls and configure the necessary codec
  * mappings for our sound card instance.
 */
-static int simtec_tlv320aic23_init(struct snd_soc_codec *codec)
+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));
 
@@ -74,7 +76,7 @@ static int simtec_tlv320aic23_init(struct snd_soc_codec *codec)
        snd_soc_dapm_enable_pin(codec, "Line Out");
        snd_soc_dapm_enable_pin(codec, "Mic Jack");
 
-       simtec_audio_init(codec);
+       simtec_audio_init(rtd);
        snd_soc_dapm_sync(codec);
 
        return 0;
@@ -83,28 +85,23 @@ static int simtec_tlv320aic23_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link simtec_dai_aic23 = {
        .name           = "tlv320aic23",
        .stream_name    = "TLV320AIC23",
-       .cpu_dai        = &s3c24xx_i2s_dai,
-       .codec_dai      = &tlv320aic23_dai,
+       .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",
-       .platform       = &s3c24xx_soc_platform,
        .dai_link       = &simtec_dai_aic23,
        .num_links      = 1,
 };
 
-/* simtec audio subsystem */
-static struct snd_soc_device simtec_snd_devdata_aic23 = {
-       .card           = &snd_soc_machine_simtec_aic23,
-       .codec_dev      = &soc_codec_dev_tlv320aic23,
-};
-
 static int __devinit simtec_audio_tlv320aic23_probe(struct platform_device *pd)
 {
-       return simtec_audio_core_probe(pd, &simtec_snd_devdata_aic23);
+       return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic23);
 }
 
 static struct platform_driver simtec_audio_tlv320aic23_platdrv = {
index 052d59659c296f2916261970ae9f4ff675b7a5cf..bd48ffbde8801701b2c5c18deb20b2e28457c697 100644 (file)
@@ -133,8 +133,8 @@ 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->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       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;
@@ -227,14 +227,15 @@ static struct snd_soc_ops s3c24xx_uda134x_ops = {
 static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
        .name = "UDA134X",
        .stream_name = "UDA134X",
-       .codec_dai = &uda134x_dai,
-       .cpu_dai = &s3c24xx_i2s_dai,
+       .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",
-       .platform = &s3c24xx_soc_platform,
        .dai_link = &s3c24xx_uda134x_dai_link,
        .num_links = 1,
 };
@@ -256,6 +257,7 @@ 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,
@@ -270,12 +272,6 @@ static struct uda134x_platform_data s3c24xx_uda134x = {
        },
 };
 
-static struct snd_soc_device s3c24xx_uda134x_snd_devdata = {
-       .card = &snd_soc_s3c24xx_uda134x,
-       .codec_dev = &soc_codec_dev_uda134x,
-       .codec_data = &s3c24xx_uda134x,
-};
-
 static int s3c24xx_uda134x_setup_pin(int pin, char *fun)
 {
        if (gpio_request(pin, "s3c24xx_uda134x") < 0) {
@@ -325,8 +321,7 @@ static int s3c24xx_uda134x_probe(struct platform_device *pdev)
        }
 
        platform_set_drvdata(s3c24xx_uda134x_snd_device,
-                            &s3c24xx_uda134x_snd_devdata);
-       s3c24xx_uda134x_snd_devdata.dev = &s3c24xx_uda134x_snd_device->dev;
+                            &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");
index 06db130030a13f8ce7326a6411f3b77e6209bc31..a9628472ebfe7ff4cff26991b1bcdf13d51d4742 100644 (file)
@@ -16,9 +16,7 @@
 #include <sound/soc.h>
 #include <sound/pcm_params.h>
 
-#include <mach/gpio-bank-c.h>
-#include <mach/gpio-bank-h.h>
-#include <plat/gpio-cfg.h>
+#include <plat/audio.h>
 
 #include <mach/map.h>
 #include <mach/dma.h>
@@ -39,34 +37,23 @@ 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;
 
-struct snd_soc_dai s3c64xx_i2s_v4_dai;
-EXPORT_SYMBOL_GPL(s3c64xx_i2s_v4_dai);
-
-static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
+static int s3c64xx_i2sv4_probe(struct snd_soc_dai *dai)
 {
-       return cpu_dai->private_data;
-}
+       struct s3c_i2sv2_info *i2s = &s3c64xx_i2sv4;
+       int ret = 0;
 
-static int s3c64xx_i2sv4_probe(struct platform_device *pdev,
-                            struct snd_soc_dai *dai)
-{
-       /* configure GPIO for i2s port */
-       s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C64XX_GPC4_I2S_V40_DO0);
-       s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C64XX_GPC5_I2S_V40_DO1);
-       s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C64XX_GPC7_I2S_V40_DO2);
-       s3c_gpio_cfgpin(S3C64XX_GPH(6), S3C64XX_GPH6_I2S_V40_BCLK);
-       s3c_gpio_cfgpin(S3C64XX_GPH(7), S3C64XX_GPH7_I2S_V40_CDCLK);
-       s3c_gpio_cfgpin(S3C64XX_GPH(8), S3C64XX_GPH8_I2S_V40_LRCLK);
-       s3c_gpio_cfgpin(S3C64XX_GPH(9), S3C64XX_GPH9_I2S_V40_DI);
+       snd_soc_dai_set_drvdata(dai, i2s);
 
-       return 0;
+       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 = to_info(cpu_dai);
+       struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(cpu_dai);
        struct s3c_dma_params *dma_data;
        u32 iismod;
 
@@ -104,51 +91,79 @@ 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 snd_soc_dai *dai;
+       struct resource *res;
        int ret;
 
        i2s = &s3c64xx_i2sv4;
-       dai = &s3c64xx_i2s_v4_dai;
-
-       if (dai->dev) {
-               dev_dbg(dai->dev, "%s: \
-                       I2Sv4 instance already registered!\n", __func__);
-               return -EBUSY;
-       }
-
-       dai->dev = &pdev->dev;
-       dai->name = "s3c64xx-i2s-v4";
-       dai->id = 0;
-       dai->symmetric_rates = 1;
-       dai->playback.channels_min = 2;
-       dai->playback.channels_max = 2;
-       dai->playback.rates = S3C64XX_I2S_RATES;
-       dai->playback.formats = S3C64XX_I2S_FMTS;
-       dai->capture.channels_min = 2;
-       dai->capture.channels_max = 2;
-       dai->capture.rates = S3C64XX_I2S_RATES;
-       dai->capture.formats = S3C64XX_I2S_FMTS;
-       dai->probe = s3c64xx_i2sv4_probe;
-       dai->ops = &s3c64xx_i2sv4_dai_ops;
 
        i2s->feature |= S3C_FEATURE_CDCLKCON;
 
        i2s->dma_capture = &s3c64xx_i2sv4_pcm_stereo_in;
        i2s->dma_playback = &s3c64xx_i2sv4_pcm_stereo_out;
 
-       i2s->dma_capture->channel = DMACH_HSI_I2SV40_RX;
-       i2s->dma_capture->dma_addr = S3C64XX_PA_IISV4 + S3C2412_IISRXD;
-       i2s->dma_playback->channel = DMACH_HSI_I2SV40_TX;
-       i2s->dma_playback->dma_addr = S3C64XX_PA_IISV4 + S3C2412_IISTXD;
+       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");
@@ -158,19 +173,13 @@ static __devinit int s3c64xx_i2sv4_dev_probe(struct platform_device *pdev)
 
        clk_enable(i2s->iis_cclk);
 
-       ret = s3c_i2sv2_probe(pdev, dai, i2s, 0);
-       if (ret)
-               goto err_clk;
-
-       ret = s3c_i2sv2_register_dai(dai);
+       ret = s3c_i2sv2_register_dai(&pdev->dev, pdev->id, &s3c64xx_i2s_v4_dai);
        if (ret != 0)
                goto err_i2sv2;
 
        return 0;
 
 err_i2sv2:
-       /* Not implemented for I2Sv2 core yet */
-err_clk:
        clk_put(i2s->iis_cclk);
 err:
        return ret;
@@ -178,7 +187,18 @@ err:
 
 static __devexit int s3c64xx_i2sv4_dev_remove(struct platform_device *pdev)
 {
-       dev_err(&pdev->dev, "Device removal not yet supported\n");
+       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;
 }
 
@@ -207,3 +227,4 @@ module_exit(s3c64xx_i2sv4_exit);
 MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
 MODULE_DESCRIPTION("S3C64XX I2Sv4 SoC Interface");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c64xx-iis-v4");
index 1d85cb85a7d2f1cd1a6f58a52dd8e9717f147fe9..ae7acb6c4f1d5fe6cb6b6808eb8ab177f80b9de9 100644 (file)
  * 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 <mach/gpio-bank-d.h>
-#include <mach/gpio-bank-e.h>
-#include <plat/gpio-cfg.h>
+#include <plat/audio.h>
 
 #include <mach/map.h>
 #include <mach/dma.h>
@@ -46,45 +46,107 @@ 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 snd_soc_dai s3c64xx_i2s_dai[MAX_I2SV3];
-EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai);
-
-static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
+struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai)
 {
-       return cpu_dai->private_data;
+       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 platform_device *pdev,
-                            struct snd_soc_dai *dai)
+static int s3c64xx_i2s_probe(struct snd_soc_dai *dai)
 {
-       /* configure GPIO for i2s port */
-       switch (dai->id) {
-       case 0:
-               s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_I2S0_CLK);
-               s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_I2S0_CDCLK);
-               s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_I2S0_LRCLK);
-               s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_I2S0_DI);
-               s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_I2S0_D0);
-               break;
-       case 1:
-               s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_I2S1_CLK);
-               s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_I2S1_CDCLK);
-               s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_I2S1_LRCLK);
-               s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI);
-               s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0);
+       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 snd_soc_dai *dai;
-       int ret;
+       struct resource *res;
+       int i, ret;
 
        if (pdev->id >= MAX_I2SV3) {
                dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
@@ -92,74 +154,63 @@ static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev)
        }
 
        i2s = &s3c64xx_i2s[pdev->id];
-       dai = &s3c64xx_i2s_dai[pdev->id];
-       dai->dev = &pdev->dev;
-       dai->name = "s3c64xx-i2s";
-       dai->id = pdev->id;
-       dai->symmetric_rates = 1;
-       dai->playback.channels_min = 2;
-       dai->playback.channels_max = 2;
-       dai->playback.rates = S3C64XX_I2S_RATES;
-       dai->playback.formats = S3C64XX_I2S_FMTS;
-       dai->capture.channels_min = 2;
-       dai->capture.channels_max = 2;
-       dai->capture.rates = S3C64XX_I2S_RATES;
-       dai->capture.formats = S3C64XX_I2S_FMTS;
-       dai->probe = s3c64xx_i2s_probe;
-       dai->ops = &s3c64xx_i2s_dai_ops;
-
-       i2s->feature |= S3C_FEATURE_CDCLKCON;
 
        i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id];
        i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id];
 
-       if (pdev->id == 0) {
-               i2s->dma_capture->channel = DMACH_I2S0_IN;
-               i2s->dma_capture->dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISRXD;
-               i2s->dma_playback->channel = DMACH_I2S0_OUT;
-               i2s->dma_playback->dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISTXD;
-       } else {
-               i2s->dma_capture->channel = DMACH_I2S1_IN;
-               i2s->dma_capture->dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISRXD;
-               i2s->dma_playback->channel = DMACH_I2S1_OUT;
-               i2s->dma_playback->dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISTXD;
+       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;
 
-       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;
+       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;
        }
 
-       clk_enable(i2s->iis_cclk);
-
-       ret = s3c_i2sv2_probe(pdev, dai, i2s, 0);
-       if (ret)
-               goto err_clk;
-
-       ret = s3c_i2sv2_register_dai(dai);
-       if (ret != 0)
-               goto err_i2sv2;
-
        return 0;
-
-err_i2sv2:
-       /* Not implemented for I2Sv2 core yet */
-err_clk:
-       clk_put(i2s->iis_cclk);
-err:
-       return ret;
 }
 
 static __devexit int s3c64xx_iis_dev_remove(struct platform_device *pdev)
 {
-       dev_err(&pdev->dev, "Device removal not yet supported\n");
+       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c64xx_i2s_dai));
        return 0;
 }
 
@@ -188,3 +239,4 @@ module_exit(s3c64xx_i2s_exit);
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("S3C64XX I2S SoC Interface");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c64xx-iis");
index 7a40f43d1d5144a6afc6faa95176928cd56096fa..de4075d26f0cb48c48bc1e37161bc689c0de5607 100644 (file)
@@ -36,7 +36,6 @@ struct clk;
        (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
         SNDRV_PCM_FMTBIT_S24_LE)
 
-extern struct snd_soc_dai s3c64xx_i2s_dai[];
-extern struct snd_soc_dai s3c64xx_i2s_v4_dai;
+struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai);
 
 #endif /* __SND_SOC_S3C24XX_S3C64XX_I2S_H */
index b480348140b02db3bc001e84c851629e07b8e288..dd20ca7f46814e3458860931910d18a39bc4508f 100644 (file)
@@ -211,8 +211,10 @@ static struct snd_soc_dai_link smartq_dai[] = {
        {
                .name           = "wm8987",
                .stream_name    = "SmartQ Hi-Fi",
-               .cpu_dai        = &s3c64xx_i2s_dai[0],
-               .codec_dai      = &wm8750_dai,
+               .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,
        },
@@ -220,16 +222,10 @@ static struct snd_soc_dai_link smartq_dai[] = {
 
 static struct snd_soc_card snd_soc_smartq = {
        .name = "SmartQ",
-       .platform = &s3c24xx_soc_platform,
        .dai_link = smartq_dai,
        .num_links = ARRAY_SIZE(smartq_dai),
 };
 
-static struct snd_soc_device smartq_snd_devdata = {
-       .card = &snd_soc_smartq,
-       .codec_dev = &soc_codec_dev_wm8750,
-};
-
 static struct platform_device *smartq_snd_device;
 
 static int __init smartq_init(void)
@@ -245,8 +241,7 @@ static int __init smartq_init(void)
        if (!smartq_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(smartq_snd_device, &smartq_snd_devdata);
-       smartq_snd_devdata.dev = &smartq_snd_device->dev;
+       platform_set_drvdata(smartq_snd_device, &snd_soc_smartq);
 
        ret = platform_device_add(smartq_snd_device);
        if (ret) {
index 362258835e8d9aec20c71c53e8df9a9acf7b6036..4613288c2772a3f5474b54ff35818bf86468ca03 100644 (file)
@@ -19,7 +19,6 @@
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 
-#include "../codecs/ac97.h"
 #include "s3c-dma.h"
 #include "s3c-ac97.h"
 
@@ -29,23 +28,19 @@ static struct snd_soc_dai_link smdk2443_dai[] = {
 {
        .name = "AC97",
        .stream_name = "AC97 HiFi",
-       .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
-       .codec_dai = &ac97_dai,
+       .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",
-       .platform = &s3c24xx_soc_platform,
        .dai_link = smdk2443_dai,
        .num_links = ARRAY_SIZE(smdk2443_dai),
 };
 
-static struct snd_soc_device smdk2443_snd_ac97_devdata = {
-       .card = &smdk2443,
-       .codec_dev = &soc_codec_dev_ac97,
-};
-
 static struct platform_device *smdk2443_snd_ac97_device;
 
 static int __init smdk2443_init(void)
@@ -56,9 +51,7 @@ static int __init smdk2443_init(void)
        if (!smdk2443_snd_ac97_device)
                return -ENOMEM;
 
-       platform_set_drvdata(smdk2443_snd_ac97_device,
-                               &smdk2443_snd_ac97_devdata);
-       smdk2443_snd_ac97_devdata.dev = &smdk2443_snd_ac97_device->dev;
+       platform_set_drvdata(smdk2443_snd_ac97_device, &smdk2443);
        ret = platform_device_add(smdk2443_snd_ac97_device);
 
        if (ret)
index 07e8e51d10d60e925e05062cd331a58a36ba64c4..052e499b68d161c614133bc596bc62b9afa31b2b 100644 (file)
 #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
 
@@ -29,8 +35,8 @@ 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->dai->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       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;
 
@@ -107,14 +113,13 @@ static int smdk64xx_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       /* Explicitly set WM8580-DAC to source from MCLK */
-       ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_DAC_CLKSEL,
-                                       WM8580_CLKSRC_MCLK);
+       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_pll(codec_dai, WM8580_PLLA, 0,
-                                       SMDK64XX_WM8580_FREQ, pll_out);
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA,
+                                    pll_out, SND_SOC_CLOCK_IN);
        if (ret < 0)
                return ret;
 
@@ -138,9 +143,9 @@ static struct snd_soc_ops smdk64xx_ops = {
 
 /* SMDK64xx Playback widgets */
 static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = {
-       SND_SOC_DAPM_HP("Front-L/R", NULL),
-       SND_SOC_DAPM_HP("Center/Sub", NULL),
-       SND_SOC_DAPM_HP("Rear-L/R", NULL),
+       SND_SOC_DAPM_HP("Front", NULL),
+       SND_SOC_DAPM_HP("Center+Sub", NULL),
+       SND_SOC_DAPM_HP("Rear", NULL),
 };
 
 /* SMDK64xx Capture widgets */
@@ -162,20 +167,22 @@ static const struct snd_soc_dapm_route audio_map_tx[] = {
 /* SMDK-PAIFRX connections */
 static const struct snd_soc_dapm_route audio_map_rx[] = {
        /* Front Left/Right are fed VOUT1L/R */
-       {"Front-L/R", NULL, "VOUT1L"},
-       {"Front-L/R", NULL, "VOUT1R"},
+       {"Front", NULL, "VOUT1L"},
+       {"Front", NULL, "VOUT1R"},
 
        /* Center/Sub are fed VOUT2L/R */
-       {"Center/Sub", NULL, "VOUT2L"},
-       {"Center/Sub", NULL, "VOUT2R"},
+       {"Center+Sub", NULL, "VOUT2L"},
+       {"Center+Sub", NULL, "VOUT2R"},
 
        /* Rear Left/Right are fed VOUT3L/R */
-       {"Rear-L/R", NULL, "VOUT3L"},
-       {"Rear-L/R", NULL, "VOUT3R"},
+       {"Rear", NULL, "VOUT3L"},
+       {"Rear", NULL, "VOUT3R"},
 };
 
-static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec)
+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));
@@ -194,8 +201,10 @@ static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec)
        return 0;
 }
 
-static int smdk64xx_wm8580_init_paifrx(struct snd_soc_codec *codec)
+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));
@@ -213,33 +222,31 @@ static struct snd_soc_dai_link smdk64xx_dai[] = {
 { /* Primary Playback i/f */
        .name = "WM8580 PAIF RX",
        .stream_name = "Playback",
-       .cpu_dai = &s3c64xx_i2s_v4_dai,
-       .codec_dai = &wm8580_dai[WM8580_DAI_PAIFRX],
+       .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 = &s3c64xx_i2s_v4_dai,
-       .codec_dai = &wm8580_dai[WM8580_DAI_PAIFTX],
+       .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",
-       .platform = &s3c24xx_soc_platform,
+       .name = "SMDK64xx 5.1",
        .dai_link = smdk64xx_dai,
        .num_links = ARRAY_SIZE(smdk64xx_dai),
 };
 
-static struct snd_soc_device smdk64xx_snd_devdata = {
-       .card = &smdk64xx,
-       .codec_dev = &soc_codec_dev_wm8580,
-};
-
 static struct platform_device *smdk64xx_snd_device;
 
 static int __init smdk64xx_audio_init(void)
@@ -250,8 +257,7 @@ static int __init smdk64xx_audio_init(void)
        if (!smdk64xx_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(smdk64xx_snd_device, &smdk64xx_snd_devdata);
-       smdk64xx_snd_devdata.dev = &smdk64xx_snd_device->dev;
+       platform_set_drvdata(smdk64xx_snd_device, &smdk64xx);
        ret = platform_device_add(smdk64xx_snd_device);
 
        if (ret)
diff --git a/sound/soc/s3c24xx/smdk_spdif.c b/sound/soc/s3c24xx/smdk_spdif.c
new file mode 100644 (file)
index 0000000..f31d22a
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * 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(fout_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(fout_epll)) {
+               printk(KERN_WARNING "%s: Cannot find sclk_spdif.\n",
+                               __func__);
+               ret = -EINVAL;
+               goto out3;
+       }
+
+       /* Set audio clock heirachy 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 heirachy.
+ */
+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 heirachy 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");
index 5527b9e88c98ee9f7772a002db499e6e0e274717..33ba8fdbcf07c2a0845caca16f39bba5d3bbc6bb 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/device.h>
 #include <sound/soc.h>
 
-#include "../codecs/wm9713.h"
 #include "s3c-dma.h"
 #include "s3c-ac97.h"
 
@@ -46,46 +45,57 @@ static struct snd_soc_card smdk;
 static struct snd_soc_dai_link smdk_dai = {
        .name = "AC97",
        .stream_name = "AC97 PCM",
-       .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
-       .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
+       .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",
-       .platform = &s3c24xx_soc_platform,
+       .name = "SMDK WM9713",
        .dai_link = &smdk_dai,
        .num_links = 1,
 };
 
-static struct snd_soc_device smdk_snd_ac97_devdata = {
-       .card = &smdk,
-       .codec_dev = &soc_codec_dev_wm9713,
-};
-
+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_ac97_device = platform_device_alloc("soc-audio", -1);
-       if (!smdk_snd_ac97_device)
+       smdk_snd_wm9713_device = platform_device_alloc("wm9713-codec", -1);
+       if (!smdk_snd_wm9713_device)
                return -ENOMEM;
 
-       platform_set_drvdata(smdk_snd_ac97_device,
-                            &smdk_snd_ac97_devdata);
-       smdk_snd_ac97_devdata.dev = &smdk_snd_ac97_device->dev;
+       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)
+       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);
diff --git a/sound/soc/s3c24xx/spdif.c b/sound/soc/s3c24xx/spdif.c
new file mode 100644 (file)
index 0000000..ce554e9
--- /dev/null
@@ -0,0 +1,501 @@
+/* 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
new file mode 100644 (file)
index 0000000..3ed5559
--- /dev/null
@@ -0,0 +1,19 @@
+/* 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 59e3fa7bcb05a7e912d709e7c1c2958097b1f7a0..8778faa174a6cb66da33e1e81430c6aae2c59973 100644 (file)
@@ -140,7 +140,7 @@ static void s6000_i2s_stop_channel(struct s6000_i2s_dev *dev, int channel)
 static void s6000_i2s_start(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct s6000_i2s_dev *dev = rtd->dai->cpu_dai->private_data;
+       struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        int channel;
 
        channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
@@ -152,7 +152,7 @@ static void s6000_i2s_start(struct snd_pcm_substream *substream)
 static void s6000_i2s_stop(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct s6000_i2s_dev *dev = rtd->dai->cpu_dai->private_data;
+       struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        int channel;
 
        channel = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
@@ -194,7 +194,7 @@ static unsigned int s6000_i2s_int_sources(struct s6000_i2s_dev *dev)
 
 static unsigned int s6000_i2s_check_xrun(struct snd_soc_dai *cpu_dai)
 {
-       struct s6000_i2s_dev *dev = cpu_dai->private_data;
+       struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
        unsigned int errors;
        unsigned int ret;
 
@@ -232,7 +232,7 @@ static void s6000_i2s_wait_disabled(struct s6000_i2s_dev *dev)
 static int s6000_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                                   unsigned int fmt)
 {
-       struct s6000_i2s_dev *dev = cpu_dai->private_data;
+       struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
        u32 w;
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -273,7 +273,7 @@ static int s6000_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 
 static int s6000_i2s_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
 {
-       struct s6000_i2s_dev *dev = dai->private_data;
+       struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
 
        if (!div || (div & 1) || div > (S6_I2S_DIV_MASK + 1) * 2)
                return -EINVAL;
@@ -287,7 +287,7 @@ static int s6000_i2s_hw_params(struct snd_pcm_substream *substream,
                               struct snd_pcm_hw_params *params,
                               struct snd_soc_dai *dai)
 {
-       struct s6000_i2s_dev *dev = dai->private_data;
+       struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
        int interf;
        u32 w = 0;
 
@@ -326,15 +326,17 @@ static int s6000_i2s_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int s6000_i2s_dai_probe(struct platform_device *pdev,
-                              struct snd_soc_dai *dai)
+static int s6000_i2s_dai_probe(struct snd_soc_dai *dai)
 {
-       struct s6000_i2s_dev *dev = dai->private_data;
-       struct s6000_snd_platform_data *pdata = pdev->dev.platform_data;
+       struct s6000_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+       struct s6000_snd_platform_data *pdata = dai->dev->platform_data;
 
        if (!pdata)
                return -EINVAL;
 
+       dai->capture_dma_data = &dev->dma_params;
+       dai->playback_dma_data = &dev->dma_params;
+
        dev->wide = pdata->wide;
        dev->channel_in = pdata->channel_in;
        dev->channel_out = pdata->channel_out;
@@ -352,10 +354,10 @@ static int s6000_i2s_dai_probe(struct platform_device *pdev,
 
                dev->channel_in = 0;
                dev->channel_out = 1;
-               dai->capture.channels_min = 2 * dev->lines_in;
-               dai->capture.channels_max = dai->capture.channels_min;
-               dai->playback.channels_min = 2 * dev->lines_out;
-               dai->playback.channels_max = dai->playback.channels_min;
+               dai->driver->capture.channels_min = 2 * dev->lines_in;
+               dai->driver->capture.channels_max = dai->driver->capture.channels_min;
+               dai->driver->playback.channels_min = 2 * dev->lines_out;
+               dai->driver->playback.channels_max = dai->driver->playback.channels_min;
 
                for (i = 0; i < dev->lines_out; i++)
                        s6_i2s_write_reg(dev, S6_I2S_DATA_CFG(i), S6_I2S_OUT);
@@ -372,10 +374,10 @@ static int s6000_i2s_dai_probe(struct platform_device *pdev,
                if (dev->lines_in > 1 || dev->lines_out > 1)
                        return -EINVAL;
 
-               dai->capture.channels_min = 2 * dev->lines_in;
-               dai->capture.channels_max = 8 * dev->lines_in;
-               dai->playback.channels_min = 2 * dev->lines_out;
-               dai->playback.channels_max = 8 * dev->lines_out;
+               dai->driver->capture.channels_min = 2 * dev->lines_in;
+               dai->driver->capture.channels_max = 8 * dev->lines_in;
+               dai->driver->playback.channels_min = 2 * dev->lines_out;
+               dai->driver->playback.channels_max = 8 * dev->lines_out;
 
                if (dev->lines_in)
                        cfg[dev->channel_in] = S6_I2S_IN;
@@ -413,9 +415,7 @@ static struct snd_soc_dai_ops s6000_i2s_dai_ops = {
        .hw_params = s6000_i2s_hw_params,
 };
 
-struct snd_soc_dai s6000_i2s_dai = {
-       .name = "s6000-i2s",
-       .id = 0,
+static struct snd_soc_dai_driver s6000_i2s_dai = {
        .probe = s6000_i2s_dai_probe,
        .playback = {
                .channels_min = 2,
@@ -435,7 +435,6 @@ struct snd_soc_dai s6000_i2s_dai = {
        },
        .ops = &s6000_i2s_dai_ops,
 }
-EXPORT_SYMBOL_GPL(s6000_i2s_dai);
 
 static int __devinit s6000_i2s_probe(struct platform_device *pdev)
 {
@@ -513,11 +512,7 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev)
                ret = -ENOMEM;
                goto err_release_dma2;
        }
-
-       s6000_i2s_dai.dev = &pdev->dev;
-       s6000_i2s_dai.private_data = dev;
-       s6000_i2s_dai.capture.dma_data = &dev->dma_params;
-       s6000_i2s_dai.playback.dma_data = &dev->dma_params;
+       dev_set_drvdata(&pdev->dev, dev);
 
        dev->sifbase = sifmem->start;
        dev->scbbase = mmio;
@@ -548,7 +543,7 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev)
                         S6_I2S_INT_UNDERRUN |
                         S6_I2S_INT_OVERRUN);
 
-       ret = snd_soc_register_dai(&s6000_i2s_dai);
+       ret = snd_soc_register_dai(&pdev->dev, &s6000_i2s_dai);
        if (ret)
                goto err_release_dev;
 
@@ -573,17 +568,16 @@ err_release_none:
 
 static void __devexit s6000_i2s_remove(struct platform_device *pdev)
 {
-       struct s6000_i2s_dev *dev = s6000_i2s_dai.private_data;
+       struct s6000_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
        struct resource *region;
        void __iomem *mmio = dev->scbbase;
 
-       snd_soc_unregister_dai(&s6000_i2s_dai);
+       snd_soc_unregister_dai(&pdev->dev);
 
        s6000_i2s_stop_channel(dev, 0);
        s6000_i2s_stop_channel(dev, 1);
 
        s6_i2s_write_reg(dev, S6_I2S_INTERRUPT_ENABLE, 0);
-       s6000_i2s_dai.private_data = 0;
        kfree(dev);
 
        region = platform_get_resource(pdev, IORESOURCE_DMA, 0);
index 2375fdfe6dba7dcf996e81dda673417d80b05d64..86aa1921c89e3b06b83b0e75ff78a40c5674a9ef 100644 (file)
@@ -12,8 +12,6 @@
 #ifndef _S6000_I2S_H
 #define _S6000_I2S_H
 
-extern struct snd_soc_dai s6000_i2s_dai;
-
 struct s6000_snd_platform_data {
        int lines_in;
        int lines_out;
index 9c7f7f00cebb45706aa6c8f7302b4a371d469ceb..271fd222bf1997f92cac08b6c8b27f8f604b5147 100644 (file)
@@ -65,7 +65,7 @@ static void s6000_pcm_enqueue_dma(struct snd_pcm_substream *substream)
        dma_addr_t dma_pos;
        dma_addr_t src, dst;
 
-       par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+       par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
 
        period_size = snd_pcm_lib_period_bytes(substream);
        dma_offset = prtd->period * period_size;
@@ -103,23 +103,25 @@ static irqreturn_t s6000_pcm_irq(int irq, void *data)
 {
        struct snd_pcm *pcm = data;
        struct snd_soc_pcm_runtime *runtime = pcm->private_data;
-       struct s6000_pcm_dma_params *params =
-               snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
        struct s6000_runtime_data *prtd;
        unsigned int has_xrun;
        int i, ret = IRQ_NONE;
-       u32 channel[2] = {
-               [SNDRV_PCM_STREAM_PLAYBACK] = params->dma_out,
-               [SNDRV_PCM_STREAM_CAPTURE] = params->dma_in
-       };
-
-       has_xrun = params->check_xrun(runtime->dai->cpu_dai);
 
-       for (i = 0; i < ARRAY_SIZE(channel); ++i) {
+       for (i = 0; i < 2; ++i) {
                struct snd_pcm_substream *substream = pcm->streams[i].substream;
+               struct s6000_pcm_dma_params *params =
+                                       snd_soc_dai_get_dma_data(runtime->cpu_dai, substream);
+               u32 channel;
                unsigned int pending;
 
-               if (!channel[i])
+               if (substream == SNDRV_PCM_STREAM_PLAYBACK)
+                       channel = params->dma_out;
+               else
+                       channel = params->dma_in;
+
+               has_xrun = params->check_xrun(runtime->cpu_dai);
+
+               if (!channel)
                        continue;
 
                if (unlikely(has_xrun & (1 << i)) &&
@@ -130,8 +132,8 @@ static irqreturn_t s6000_pcm_irq(int irq, void *data)
                        ret = IRQ_HANDLED;
                }
 
-               pending = s6dmac_int_sources(DMA_MASK_DMAC(channel[i]),
-                                            DMA_INDEX_CHNL(channel[i]));
+               pending = s6dmac_int_sources(DMA_MASK_DMAC(channel),
+                                            DMA_INDEX_CHNL(channel));
 
                if (pending & 1) {
                        ret = IRQ_HANDLED;
@@ -139,10 +141,10 @@ static irqreturn_t s6000_pcm_irq(int irq, void *data)
                                   snd_pcm_running(substream))) {
                                snd_pcm_period_elapsed(substream);
                                dev_dbg(pcm->dev, "period elapsed %x %x\n",
-                                      s6dmac_cur_src(DMA_MASK_DMAC(channel[i]),
-                                                  DMA_INDEX_CHNL(channel[i])),
-                                      s6dmac_cur_dst(DMA_MASK_DMAC(channel[i]),
-                                                  DMA_INDEX_CHNL(channel[i])));
+                                      s6dmac_cur_src(DMA_MASK_DMAC(channel),
+                                                  DMA_INDEX_CHNL(channel)),
+                                      s6dmac_cur_dst(DMA_MASK_DMAC(channel),
+                                                  DMA_INDEX_CHNL(channel)));
                                prtd = substream->runtime->private_data;
                                spin_lock(&prtd->lock);
                                s6000_pcm_enqueue_dma(substream);
@@ -154,16 +156,16 @@ static irqreturn_t s6000_pcm_irq(int irq, void *data)
                        if (pending & (1 << 3))
                                printk(KERN_WARNING
                                       "s6000-pcm: DMA %x Underflow\n",
-                                      channel[i]);
+                                      channel);
                        if (pending & (1 << 4))
                                printk(KERN_WARNING
                                       "s6000-pcm: DMA %x Overflow\n",
-                                      channel[i]);
+                                      channel);
                        if (pending & 0x1e0)
                                printk(KERN_WARNING
                                       "s6000-pcm: DMA %x Master Error "
                                       "(mask %x)\n",
-                                      channel[i], pending >> 5);
+                                      channel, pending >> 5);
 
                }
        }
@@ -180,7 +182,7 @@ static int s6000_pcm_start(struct snd_pcm_substream *substream)
        int srcinc;
        u32 dma;
 
-       par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+       par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
 
        spin_lock_irqsave(&prtd->lock, flags);
 
@@ -221,7 +223,7 @@ static int s6000_pcm_stop(struct snd_pcm_substream *substream)
        unsigned long flags;
        u32 channel;
 
-       par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+       par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                channel = par->dma_out;
@@ -246,7 +248,7 @@ static int s6000_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        struct s6000_pcm_dma_params *par;
        int ret;
 
-       par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+       par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
 
        ret = par->trigger(substream, cmd, 0);
        if (ret < 0)
@@ -291,7 +293,7 @@ static snd_pcm_uframes_t s6000_pcm_pointer(struct snd_pcm_substream *substream)
        unsigned int offset;
        dma_addr_t count;
 
-       par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+       par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
 
        spin_lock_irqsave(&prtd->lock, flags);
 
@@ -321,7 +323,7 @@ static int s6000_pcm_open(struct snd_pcm_substream *substream)
        struct s6000_runtime_data *prtd;
        int ret;
 
-       par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+       par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
        snd_soc_set_runtime_hwparams(substream, &s6000_pcm_hardware);
 
        ret = snd_pcm_hw_constraint_step(runtime, 0,
@@ -385,7 +387,7 @@ static int s6000_pcm_hw_params(struct snd_pcm_substream *substream,
                return ret;
        }
 
-       par = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+       par = snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
 
        if (par->same_rate) {
                spin_lock(&par->lock);
@@ -407,7 +409,7 @@ static int s6000_pcm_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
        struct s6000_pcm_dma_params *par =
-               snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+               snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
 
        spin_lock(&par->lock);
        par->in_use &= ~(1 << substream->stream);
@@ -433,7 +435,7 @@ static void s6000_pcm_free(struct snd_pcm *pcm)
 {
        struct snd_soc_pcm_runtime *runtime = pcm->private_data;
        struct s6000_pcm_dma_params *params =
-               snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+               snd_soc_dai_get_dma_data(runtime->cpu_dai, pcm->streams[0].substream);
 
        free_irq(params->irq, pcm);
        snd_pcm_lib_preallocate_free_for_all(pcm);
@@ -448,7 +450,8 @@ static int s6000_pcm_new(struct snd_card *card,
        struct s6000_pcm_dma_params *params;
        int res;
 
-       params = snd_soc_dai_get_dma_data(soc_runtime->dai->cpu_dai, substream);
+       params = snd_soc_dai_get_dma_data(runtime->cpu_dai,
+                       pcm->streams[0].substream);
 
        if (!card->dev->dma_mask)
                card->dev->dma_mask = &s6000_pcm_dmamask;
@@ -490,25 +493,44 @@ static int s6000_pcm_new(struct snd_card *card,
        return 0;
 }
 
-struct snd_soc_platform s6000_soc_platform = {
-       .name =         "s6000-audio",
-       .pcm_ops =      &s6000_pcm_ops,
+static struct snd_soc_platform_driver s6000_soc_platform = {
+       .ops =          &s6000_pcm_ops,
        .pcm_new =      s6000_pcm_new,
        .pcm_free =     s6000_pcm_free,
 };
-EXPORT_SYMBOL_GPL(s6000_soc_platform);
 
-static int __init s6000_pcm_init(void)
+static int __devinit s6000_soc_platform_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_platform(&pdev->dev, &s6000_soc_platform);
+}
+
+static int __devexit s6000_soc_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver s6000_pcm_driver = {
+       .driver = {
+                       .name = "s6000-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = s6000_soc_platform_probe,
+       .remove = __devexit_p(s6000_soc_platform_remove),
+};
+
+static int __init snd_s6000_pcm_init(void)
 {
-       return snd_soc_register_platform(&s6000_soc_platform);
+       return platform_driver_register(&s6000_pcm_driver);
 }
-module_init(s6000_pcm_init);
+module_init(snd_s6000_pcm_init);
 
-static void __exit s6000_pcm_exit(void)
+static void __exit snd_s6000_pcm_exit(void)
 {
-       snd_soc_unregister_platform(&s6000_soc_platform);
+       platform_driver_unregister(&s6000_pcm_driver);
 }
-module_exit(s6000_pcm_exit);
+module_exit(snd_s6000_pcm_exit);
 
 MODULE_AUTHOR("Daniel Gloeckner");
 MODULE_DESCRIPTION("Stretch s6000 family PCM DMA module");
index 96f23f6f52bf6b6ece9493e1a6d66b95a54fe5c0..09d9b883e58b08b550927ea65a30f70764aad43d 100644 (file)
@@ -30,6 +30,4 @@ struct s6000_pcm_dma_params {
        int rate;
 };
 
-extern struct snd_soc_platform s6000_soc_platform;
-
 #endif
index c1b40ac22c052b22a986dac52435291529ad2bfd..96c05e1375386ebf6f11fd8d6ebcaa7dd118ac07 100644 (file)
@@ -32,8 +32,8 @@ static int s6105_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 snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret = 0;
 
        /* set codec DAI configuration */
@@ -134,8 +134,10 @@ static const struct snd_kcontrol_new audio_out_mux = {
 };
 
 /* Logic for a aic3x as connected on the s6105 ip camera ref design */
-static int s6105_aic3x_init(struct snd_soc_codec *codec)
+static int s6105_aic3x_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        /* Add s6105 specific widgets */
        snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
                                  ARRAY_SIZE(aic3x_dapm_widgets));
@@ -165,7 +167,7 @@ static int s6105_aic3x_init(struct snd_soc_codec *codec)
 
        snd_soc_dapm_sync(codec);
 
-       snd_ctl_add(codec->card, snd_ctl_new1(&audio_out_mux, codec));
+       snd_ctl_add(codec->snd_card, snd_ctl_new1(&audio_out_mux, codec));
 
        return 0;
 }
@@ -174,8 +176,10 @@ static int s6105_aic3x_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link s6105_dai = {
        .name = "TLV320AIC31",
        .stream_name = "AIC31",
-       .cpu_dai = &s6000_i2s_dai,
-       .codec_dai = &aic3x_dai,
+       .cpu_dai_name = "s6000-i2s",
+       .codec_dai_name = "tlv320aic3x-hifi",
+       .platform_name = "s6000-pcm-audio",
+       .codec_name = "tlv320aic3x-codec.0-001a",
        .init = s6105_aic3x_init,
        .ops = &s6105_ops,
 };
@@ -183,22 +187,10 @@ static struct snd_soc_dai_link s6105_dai = {
 /* s6105 audio machine driver */
 static struct snd_soc_card snd_soc_card_s6105 = {
        .name = "Stretch IP Camera",
-       .platform = &s6000_soc_platform,
        .dai_link = &s6105_dai,
        .num_links = 1,
 };
 
-/* s6105 audio private data */
-static struct aic3x_setup_data s6105_aic3x_setup = {
-};
-
-/* s6105 audio subsystem */
-static struct snd_soc_device s6105_snd_devdata = {
-       .card = &snd_soc_card_s6105,
-       .codec_dev = &soc_codec_dev_aic3x,
-       .codec_data = &s6105_aic3x_setup,
-};
-
 static struct s6000_snd_platform_data __initdata s6105_snd_data = {
        .wide           = 0,
        .channel_in     = 0,
@@ -227,8 +219,7 @@ static int __init s6105_init(void)
        if (!s6105_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(s6105_snd_device, &s6105_snd_devdata);
-       s6105_snd_devdata.dev = &s6105_snd_device->dev;
+       platform_set_drvdata(s6105_snd_device, &snd_soc_card_s6105);
        platform_device_add_data(s6105_snd_device, &s6105_snd_data,
                                 sizeof(s6105_snd_data));
 
index 52d7e8ed9c1faa1e9e38015dfe0c04cb5a9a5fbf..7f0a496e07cee6d7e2ab52d64a02f4bfc4b146ba 100644 (file)
@@ -47,7 +47,7 @@ config SND_SH7760_AC97
          AC97 unit of the SH7760.
 
 config SND_FSI_AK4642
-       bool "FSI-AK4642 sound support"
+       tristate "FSI-AK4642 sound support"
        depends on SND_SOC_SH4_FSI && I2C_SH_MOBILE
        select SND_SOC_AK4642
        help
@@ -55,13 +55,20 @@ config SND_FSI_AK4642
          FSI - AK4642 unit
 
 config SND_FSI_DA7210
-       bool "FSI-DA7210 sound support"
+       tristate "FSI-DA7210 sound support"
        depends on SND_SOC_SH4_FSI && I2C_SH_MOBILE
        select SND_SOC_DA7210
        help
          This option enables generic sound support for the
          FSI - DA7210 unit
 
+config SND_FSI_HDMI
+       tristate "FSI-HDMI sound support"
+       depends on SND_SOC_SH4_FSI && FB_SH_MOBILE_HDMI
+       help
+         This option enables generic sound support for the
+         FSI - HDMI unit
+
 config SND_SIU_MIGOR
        tristate "SIU sound support on Migo-R"
        depends on SH_MIGOR
index 8a5a19293bda17b7d0ef11fc2a80f385aa23f273..94476d4c0fd58f01b9ae46691f9b6621b66cac95 100644 (file)
@@ -16,9 +16,11 @@ obj-$(CONFIG_SND_SOC_SH4_SIU)        += snd-soc-siu.o
 snd-soc-sh7760-ac97-objs       := sh7760-ac97.o
 snd-soc-fsi-ak4642-objs                := fsi-ak4642.o
 snd-soc-fsi-da7210-objs                := fsi-da7210.o
+snd-soc-fsi-hdmi-objs          := fsi-hdmi.o
 snd-soc-migor-objs             := migor.o
 
 obj-$(CONFIG_SND_SH7760_AC97)  += snd-soc-sh7760-ac97.o
 obj-$(CONFIG_SND_FSI_AK4642)   += snd-soc-fsi-ak4642.o
 obj-$(CONFIG_SND_FSI_DA7210)   += snd-soc-fsi-da7210.o
+obj-$(CONFIG_SND_FSI_HDMI)     += snd-soc-fsi-hdmi.o
 obj-$(CONFIG_SND_SIU_MIGOR)    += snd-soc-migor.o
index 0d8bdf07729c559daaf7bc861f379c7b3bbddf0d..c326d29992fe3c90184b7b97cef36ea42f54f3d9 100644 (file)
@@ -137,7 +137,7 @@ static void camelot_rxdma(void *data)
 static int camelot_pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
        int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
        int ret, dmairq;
 
@@ -150,7 +150,7 @@ static int camelot_pcm_open(struct snd_pcm_substream *substream)
                ret = dmabrg_request_irq(dmairq, camelot_rxdma, cam);
                if (unlikely(ret)) {
                        pr_debug("audio unit %d irqs already taken!\n",
-                            rtd->dai->cpu_dai->id);
+                            rtd->cpu_dai->id);
                        return -EBUSY;
                }
                (void)dmabrg_request_irq(dmairq + 1,camelot_rxdma, cam);
@@ -159,7 +159,7 @@ static int camelot_pcm_open(struct snd_pcm_substream *substream)
                ret = dmabrg_request_irq(dmairq, camelot_txdma, cam);
                if (unlikely(ret)) {
                        pr_debug("audio unit %d irqs already taken!\n",
-                            rtd->dai->cpu_dai->id);
+                            rtd->cpu_dai->id);
                        return -EBUSY;
                }
                (void)dmabrg_request_irq(dmairq + 1, camelot_txdma, cam);
@@ -170,7 +170,7 @@ static int camelot_pcm_open(struct snd_pcm_substream *substream)
 static int camelot_pcm_close(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
        int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
        int dmairq;
 
@@ -191,7 +191,7 @@ static int camelot_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *hw_params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
        int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
        int ret;
 
@@ -219,7 +219,7 @@ static int camelot_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
 
        pr_debug("PCM data: addr 0x%08ulx len %d\n",
                 (u32)runtime->dma_addr, runtime->dma_bytes);
@@ -266,7 +266,7 @@ static inline void dmabrg_rec_dma_stop(struct camelot_pcm *cam)
 static int camelot_trigger(struct snd_pcm_substream *substream, int cmd)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
        int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
 
        switch (cmd) {
@@ -293,7 +293,7 @@ static snd_pcm_uframes_t camelot_pos(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->cpu_dai->id];
        int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
        unsigned long pos;
 
@@ -342,25 +342,44 @@ static int camelot_pcm_new(struct snd_card *card,
        return 0;
 }
 
-struct snd_soc_platform sh7760_soc_platform = {
-       .name           = "sh7760-pcm",
+static struct snd_soc_platform sh7760_soc_platform = {
        .pcm_ops        = &camelot_pcm_ops,
        .pcm_new        = camelot_pcm_new,
        .pcm_free       = camelot_pcm_free,
 };
-EXPORT_SYMBOL_GPL(sh7760_soc_platform);
 
-static int __init sh7760_soc_platform_init(void)
+static int __devinit sh7760_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&sh7760_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &sh7760_soc_platform);
 }
-module_init(sh7760_soc_platform_init);
 
-static void __exit sh7760_soc_platform_exit(void)
+static int __devexit sh7760_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&sh7760_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver sh7760_pcm_driver = {
+       .driver = {
+                       .name = "sh7760-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = sh7760_soc_platform_probe,
+       .remove = __devexit_p(sh7760_soc_platform_remove),
+};
+
+static int __init snd_sh7760_pcm_init(void)
+{
+       return platform_driver_register(&sh7760_pcm_driver);
+}
+module_init(snd_sh7760_pcm_init);
+
+static void __exit snd_sh7760_pcm_exit(void)
+{
+       platform_driver_unregister(&sh7760_pcm_driver);
 }
-module_exit(sh7760_soc_platform_exit);
+module_exit(snd_sh7760_pcm_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver");
index dad575a2262228fc1ffa6511bc036d74beade9dc..d96602de71de3fd351eb4c1a2b1ccbb0d21c819a 100644 (file)
 
 #include <linux/platform_device.h>
 #include <sound/sh_fsi.h>
-#include <../sound/soc/codecs/ak4642.h>
 
-static int fsi_ak4642_dai_init(struct snd_soc_codec *codec)
+static int fsi_ak4642_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_dai *dai = rtd->codec_dai;
        int ret;
 
-       ret = snd_soc_dai_set_fmt(&ak4642_dai, SND_SOC_DAIFMT_CBM_CFM);
+       ret = snd_soc_dai_set_fmt(dai, SND_SOC_DAIFMT_CBM_CFM);
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_sysclk(&ak4642_dai, 0, 11289600, 0);
+       ret = snd_soc_dai_set_sysclk(dai, 0, 11289600, 0);
 
        return ret;
 }
@@ -29,24 +29,25 @@ static int fsi_ak4642_dai_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link fsi_dai_link = {
        .name           = "AK4642",
        .stream_name    = "AK4642",
-       .cpu_dai        = &fsi_soc_dai[FSI_PORT_A],
-       .codec_dai      = &ak4642_dai,
+       .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",
-       .platform       = &fsi_soc_platform,
+       .name           = "FSI (AK4642)",
        .dai_link       = &fsi_dai_link,
        .num_links      = 1,
 };
 
-static struct snd_soc_device fsi_snd_devdata = {
-       .card           = &fsi_soc_card,
-       .codec_dev      = &soc_codec_dev_ak4642,
-};
-
 static struct platform_device *fsi_snd_device;
 
 static int __init fsi_ak4642_init(void)
@@ -57,9 +58,7 @@ static int __init fsi_ak4642_init(void)
        if (!fsi_snd_device)
                goto out;
 
-       platform_set_drvdata(fsi_snd_device,
-                            &fsi_snd_devdata);
-       fsi_snd_devdata.dev = &fsi_snd_device->dev;
+       platform_set_drvdata(fsi_snd_device, &fsi_soc_card);
        ret = platform_device_add(fsi_snd_device);
 
        if (ret)
index 121bbb07bb03b7677280dcf7f8e9316c686de332..a6adb6e432507bd921cc7cc948c0380868a3bd4f 100644 (file)
 
 #include <linux/platform_device.h>
 #include <sound/sh_fsi.h>
-#include "../codecs/da7210.h"
 
-static int fsi_da7210_init(struct snd_soc_codec *codec)
+static int fsi_da7210_init(struct snd_soc_pcm_runtime *rtd)
 {
-       return snd_soc_dai_set_fmt(&da7210_dai,
+       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_CBM_CFM);
 }
@@ -24,23 +25,19 @@ static int fsi_da7210_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link fsi_da7210_dai = {
        .name           = "DA7210",
        .stream_name    = "DA7210",
-       .cpu_dai        = &fsi_soc_dai[FSI_PORT_B],
-       .codec_dai      = &da7210_dai,
+       .cpu_dai_name   = "fsib-dai", /* FSI B */
+       .codec_dai_name = "da7210-hifi",
+       .platform_name  = "sh_fsi.0",
+       .codec_name     = "da7210-codec.0-001a",
        .init           = fsi_da7210_init,
 };
 
 static struct snd_soc_card fsi_soc_card = {
-       .name           = "FSI",
-       .platform       = &fsi_soc_platform,
+       .name           = "FSI (DA7210)",
        .dai_link       = &fsi_da7210_dai,
        .num_links      = 1,
 };
 
-static struct snd_soc_device fsi_da7210_snd_devdata = {
-       .card           = &fsi_soc_card,
-       .codec_dev      = &soc_codec_dev_da7210,
-};
-
 static struct platform_device *fsi_da7210_snd_device;
 
 static int __init fsi_da7210_sound_init(void)
@@ -51,8 +48,7 @@ static int __init fsi_da7210_sound_init(void)
        if (!fsi_da7210_snd_device)
                return -ENOMEM;
 
-       platform_set_drvdata(fsi_da7210_snd_device, &fsi_da7210_snd_devdata);
-       fsi_da7210_snd_devdata.dev = &fsi_da7210_snd_device->dev;
+       platform_set_drvdata(fsi_da7210_snd_device, &fsi_soc_card);
        ret = platform_device_add(fsi_da7210_snd_device);
        if (ret)
                platform_device_put(fsi_da7210_snd_device);
diff --git a/sound/soc/sh/fsi-hdmi.c b/sound/soc/sh/fsi-hdmi.c
new file mode 100644 (file)
index 0000000..a52dd8e
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * FSI - HDMI sound support
+ *
+ * Copyright (C) 2010 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/platform_device.h>
+#include <sound/sh_fsi.h>
+
+static struct snd_soc_dai_link fsi_dai_link = {
+       .name           = "HDMI",
+       .stream_name    = "HDMI",
+       .cpu_dai_name   = "fsib-dai", /* fsi B */
+       .codec_dai_name = "sh_mobile_hdmi-hifi",
+       .platform_name  = "sh_fsi2",
+       .codec_name     = "sh-mobile-hdmi",
+};
+
+static struct snd_soc_card fsi_soc_card  = {
+       .name           = "FSI (SH MOBILE HDMI)",
+       .dai_link       = &fsi_dai_link,
+       .num_links      = 1,
+};
+
+static struct platform_device *fsi_snd_device;
+
+static int __init fsi_hdmi_init(void)
+{
+       int ret = -ENOMEM;
+
+       fsi_snd_device = platform_device_alloc("soc-audio", FSI_PORT_B);
+       if (!fsi_snd_device)
+               goto out;
+
+       platform_set_drvdata(fsi_snd_device, &fsi_soc_card);
+       ret = platform_device_add(fsi_snd_device);
+
+       if (ret)
+               platform_device_put(fsi_snd_device);
+
+out:
+       return ret;
+}
+
+static void __exit fsi_hdmi_exit(void)
+{
+       platform_device_unregister(fsi_snd_device);
+}
+
+module_init(fsi_hdmi_init);
+module_exit(fsi_hdmi_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic SH4 FSI-HDMI sound card");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
index 58c6bec642decf3093746f577fd387c0688ad459..507e709f2807c52995bed6c8dfaad09981ce471d 100644 (file)
 #define B_CLK          0x00000010
 #define A_CLK          0x00000001
 
-/* INT_ST */
-#define INT_B_IN       (1 << 12)
-#define INT_B_OUT      (1 << 8)
-#define INT_A_IN       (1 << 4)
-#define INT_A_OUT      (1 << 0)
+/* IO SHIFT / MACRO */
+#define BI_SHIFT       12
+#define BO_SHIFT       8
+#define AI_SHIFT       4
+#define AO_SHIFT       0
+#define AB_IO(param, shift)    (param << shift)
 
 /* SOFT_RST */
 #define PBSR           (1 << 12) /* Port B Software Reset */
 #define FSISR          (1 <<  0) /* Software Reset */
 
 /* FIFO_SZ */
-#define OUT_SZ_MASK    0x7
-#define BO_SZ_SHIFT    8
-#define AO_SZ_SHIFT    0
+#define FIFO_SZ_MASK   0x7
 
 #define FSI_RATES SNDRV_PCM_RATE_8000_96000
 
 #define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
 
-/************************************************************************
+/*
+ * FSI driver use below type name for variable
+ *
+ * xxx_len     : data length
+ * xxx_width   : data width
+ * xxx_offset  : data offset
+ * xxx_num     : number of data
+ */
+
+/*
+ *             struct
+ */
 
+struct fsi_stream {
+       struct snd_pcm_substream *substream;
 
-               struct
+       int fifo_max_num;
+       int chan_num;
 
+       int buff_offset;
+       int buff_len;
+       int period_len;
+       int period_num;
+};
 
-************************************************************************/
 struct fsi_priv {
        void __iomem *base;
-       struct snd_pcm_substream *substream;
        struct fsi_master *master;
 
-       int fifo_max;
-       int chan;
-
-       int byte_offset;
-       int period_len;
-       int buffer_len;
-       int periods;
+       struct fsi_stream playback;
+       struct fsi_stream capture;
 
        u32 mst_ctrl;
 };
@@ -142,13 +153,10 @@ struct fsi_master {
        spinlock_t lock;
 };
 
-/************************************************************************
-
-
-               basic read write function
-
+/*
+ *             basic read write function
+ */
 
-************************************************************************/
 static void __fsi_reg_write(u32 reg, u32 data)
 {
        /* valid data area is 24bit */
@@ -251,13 +259,10 @@ static void fsi_master_mask_set(struct fsi_master *master,
        spin_unlock_irqrestore(&master->lock, flags);
 }
 
-/************************************************************************
-
-
-               basic function
-
+/*
+ *             basic function
+ */
 
-************************************************************************/
 static struct fsi_master *fsi_get_master(struct fsi_priv *fsi)
 {
        return fsi->master;
@@ -271,16 +276,19 @@ static int fsi_is_port_a(struct fsi_priv *fsi)
 static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai_link *machine = rtd->dai;
 
-       return  machine->cpu_dai;
+       return  rtd->cpu_dai;
 }
 
 static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream)
 {
        struct snd_soc_dai *dai = fsi_get_dai(substream);
+       struct fsi_master *master = snd_soc_dai_get_drvdata(dai);
 
-       return dai->private_data;
+       if (dai->id == 0)
+               return &master->fsia;
+       else
+               return &master->fsib;
 }
 
 static u32 fsi_get_info_flags(struct fsi_priv *fsi)
@@ -292,6 +300,22 @@ static u32 fsi_get_info_flags(struct fsi_priv *fsi)
                master->info->portb_flags;
 }
 
+static inline int fsi_stream_is_play(int stream)
+{
+       return stream == SNDRV_PCM_STREAM_PLAYBACK;
+}
+
+static inline int fsi_is_play(struct snd_pcm_substream *substream)
+{
+       return fsi_stream_is_play(substream->stream);
+}
+
+static inline struct fsi_stream *fsi_get_stream(struct fsi_priv *fsi,
+                                               int is_play)
+{
+       return is_play ? &fsi->playback : &fsi->capture;
+}
+
 static int fsi_is_master_mode(struct fsi_priv *fsi, int is_play)
 {
        u32 mode;
@@ -307,63 +331,144 @@ static int fsi_is_master_mode(struct fsi_priv *fsi, int is_play)
        return (mode & flags) != mode;
 }
 
-static u32 fsi_port_ab_io_bit(struct fsi_priv *fsi, int is_play)
+static u32 fsi_get_port_shift(struct fsi_priv *fsi, int is_play)
 {
        int is_porta = fsi_is_port_a(fsi);
-       u32 data;
+       u32 shift;
 
        if (is_porta)
-               data = is_play ? (1 << 0) : (1 << 4);
+               shift = is_play ? AO_SHIFT : AI_SHIFT;
        else
-               data = is_play ? (1 << 8) : (1 << 12);
+               shift = is_play ? BO_SHIFT : BI_SHIFT;
 
-       return data;
+       return shift;
 }
 
 static void fsi_stream_push(struct fsi_priv *fsi,
+                           int is_play,
                            struct snd_pcm_substream *substream,
                            u32 buffer_len,
                            u32 period_len)
 {
-       fsi->substream          = substream;
-       fsi->buffer_len         = buffer_len;
-       fsi->period_len         = period_len;
-       fsi->byte_offset        = 0;
-       fsi->periods            = 0;
+       struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+
+       io->substream   = substream;
+       io->buff_len    = buffer_len;
+       io->buff_offset = 0;
+       io->period_len  = period_len;
+       io->period_num  = 0;
 }
 
-static void fsi_stream_pop(struct fsi_priv *fsi)
+static void fsi_stream_pop(struct fsi_priv *fsi, int is_play)
 {
-       fsi->substream          = NULL;
-       fsi->buffer_len         = 0;
-       fsi->period_len         = 0;
-       fsi->byte_offset        = 0;
-       fsi->periods            = 0;
+       struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+
+       io->substream   = NULL;
+       io->buff_len    = 0;
+       io->buff_offset = 0;
+       io->period_len  = 0;
+       io->period_num  = 0;
 }
 
-static int fsi_get_fifo_residue(struct fsi_priv *fsi, int is_play)
+static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play)
 {
        u32 status;
        u32 reg = is_play ? DOFF_ST : DIFF_ST;
-       int residue;
+       struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+       int data_num;
 
        status = fsi_reg_read(fsi, reg);
-       residue = 0x1ff & (status >> 8);
-       residue *= fsi->chan;
+       data_num = 0x1ff & (status >> 8);
+       data_num *= io->chan_num;
+
+       return data_num;
+}
+
+static int fsi_len2num(int len, int width)
+{
+       return len / width;
+}
+
+#define fsi_num2offset(a, b) fsi_num2len(a, b)
+static int fsi_num2len(int num, int width)
+{
+       return num * width;
+}
+
+static int fsi_get_frame_width(struct fsi_priv *fsi, int is_play)
+{
+       struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+       struct snd_pcm_substream *substream = io->substream;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       return frames_to_bytes(runtime, 1) / io->chan_num;
+}
+
+/*
+ *             dma function
+ */
+
+static u8 *fsi_dma_get_area(struct fsi_priv *fsi, int stream)
+{
+       int is_play = fsi_stream_is_play(stream);
+       struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+
+       return io->substream->runtime->dma_area + io->buff_offset;
+}
+
+static void fsi_dma_soft_push16(struct fsi_priv *fsi, int num)
+{
+       u16 *start;
+       int i;
+
+       start  = (u16 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_PLAYBACK);
+
+       for (i = 0; i < num; i++)
+               fsi_reg_write(fsi, DODT, ((u32)*(start + i) << 8));
+}
+
+static void fsi_dma_soft_pop16(struct fsi_priv *fsi, int num)
+{
+       u16 *start;
+       int i;
 
-       return residue;
+       start  = (u16 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_CAPTURE);
+
+
+       for (i = 0; i < num; i++)
+               *(start + i) = (u16)(fsi_reg_read(fsi, DIDT) >> 8);
 }
 
-/************************************************************************
+static void fsi_dma_soft_push32(struct fsi_priv *fsi, int num)
+{
+       u32 *start;
+       int i;
+
+       start  = (u32 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_PLAYBACK);
+
+
+       for (i = 0; i < num; i++)
+               fsi_reg_write(fsi, DODT, *(start + i));
+}
 
+static void fsi_dma_soft_pop32(struct fsi_priv *fsi, int num)
+{
+       u32 *start;
+       int i;
 
-               irq function
+       start  = (u32 *)fsi_dma_get_area(fsi, SNDRV_PCM_STREAM_CAPTURE);
 
+       for (i = 0; i < num; i++)
+               *(start + i) = fsi_reg_read(fsi, DIDT);
+}
+
+/*
+ *             irq function
+ */
 
-************************************************************************/
 static void fsi_irq_enable(struct fsi_priv *fsi, int is_play)
 {
-       u32 data = fsi_port_ab_io_bit(fsi, 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);
@@ -372,7 +477,7 @@ static void fsi_irq_enable(struct fsi_priv *fsi, int is_play)
 
 static void fsi_irq_disable(struct fsi_priv *fsi, int is_play)
 {
-       u32 data = fsi_port_ab_io_bit(fsi, 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);
@@ -394,20 +499,18 @@ static void fsi_irq_clear_status(struct fsi_priv *fsi)
        u32 data = 0;
        struct fsi_master *master = fsi_get_master(fsi);
 
-       data |= fsi_port_ab_io_bit(fsi, 0);
-       data |= fsi_port_ab_io_bit(fsi, 1);
+       data |= AB_IO(1, fsi_get_port_shift(fsi, 0));
+       data |= AB_IO(1, fsi_get_port_shift(fsi, 1));
 
        /* clear interrupt factor */
        fsi_master_mask_set(master, master->core->int_st, data, 0);
 }
 
-/************************************************************************
-
-
-               SPDIF master clock function
-
-These functions are used later FSI2
-************************************************************************/
+/*
+ *             SPDIF master clock function
+ *
+ * These functions are used later FSI2
+ */
 static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
 {
        struct fsi_master *master = fsi_get_master(fsi);
@@ -424,13 +527,10 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
                fsi_master_mask_set(master, fsi->mst_ctrl, val, 0);
 }
 
-/************************************************************************
-
-
-               ctrl function
-
+/*
+ *             ctrl function
+ */
 
-************************************************************************/
 static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable)
 {
        u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4);
@@ -447,14 +547,15 @@ static void fsi_fifo_init(struct fsi_priv *fsi,
                          struct snd_soc_dai *dai)
 {
        struct fsi_master *master = fsi_get_master(fsi);
+       struct fsi_stream *io = fsi_get_stream(fsi, is_play);
        u32 ctrl, shift, i;
 
        /* get on-chip RAM capacity */
        shift = fsi_master_read(master, FIFO_SZ);
-       shift >>= fsi_is_port_a(fsi) ? AO_SZ_SHIFT : BO_SZ_SHIFT;
-       shift &= OUT_SZ_MASK;
-       fsi->fifo_max = 256 << shift;
-       dev_dbg(dai->dev, "fifo = %d words\n", fsi->fifo_max);
+       shift >>= fsi_get_port_shift(fsi, is_play);
+       shift &= FIFO_SZ_MASK;
+       io->fifo_max_num = 256 << shift;
+       dev_dbg(dai->dev, "fifo = %d words\n", io->fifo_max_num);
 
        /*
         * The maximum number of sample data varies depending
@@ -475,9 +576,10 @@ static void fsi_fifo_init(struct fsi_priv *fsi,
         * 7 channels:  32 ( 32 x 7 = 224)
         * 8 channels:  32 ( 32 x 8 = 256)
         */
-       for (i = 1; i < fsi->chan; i <<= 1)
-               fsi->fifo_max >>= 1;
-       dev_dbg(dai->dev, "%d channel %d store\n", fsi->chan, fsi->fifo_max);
+       for (i = 1; i < io->chan_num; i <<= 1)
+               io->fifo_max_num >>= 1;
+       dev_dbg(dai->dev, "%d channel %d store\n",
+               io->chan_num, io->fifo_max_num);
 
        ctrl = is_play ? DOFF_CTL : DIFF_CTL;
 
@@ -500,84 +602,114 @@ static void fsi_soft_all_reset(struct fsi_master *master)
        mdelay(10);
 }
 
-/* playback interrupt */
-static int fsi_data_push(struct fsi_priv *fsi, int startup)
+static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int startup, int stream)
 {
        struct snd_pcm_runtime *runtime;
        struct snd_pcm_substream *substream = NULL;
-       u32 status;
-       int send;
-       int fifo_free;
-       int width;
-       u8 *start;
-       int i, over_period;
+       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;
+       int ch_width;
+       int over_period;
+       void (*fn)(struct fsi_priv *fsi, int size);
 
        if (!fsi                        ||
-           !fsi->substream             ||
-           !fsi->substream->runtime)
+           !io->substream              ||
+           !io->substream->runtime)
                return -EINVAL;
 
        over_period     = 0;
-       substream       = fsi->substream;
+       substream       = io->substream;
        runtime         = substream->runtime;
 
        /* FSI FIFO has limit.
         * So, this driver can not send periods data at a time
         */
-       if (fsi->byte_offset >=
-           fsi->period_len * (fsi->periods + 1)) {
+       if (io->buff_offset >=
+           fsi_num2offset(io->period_num + 1, io->period_len)) {
 
                over_period = 1;
-               fsi->periods = (fsi->periods + 1) % runtime->periods;
+               io->period_num = (io->period_num + 1) % runtime->periods;
 
-               if (0 == fsi->periods)
-                       fsi->byte_offset = 0;
+               if (0 == io->period_num)
+                       io->buff_offset = 0;
        }
 
        /* get 1 channel data width */
-       width = frames_to_bytes(runtime, 1) / fsi->chan;
-
-       /* get send size for alsa */
-       send = (fsi->buffer_len - fsi->byte_offset) / width;
-
-       /*  get FIFO free size */
-       fifo_free = (fsi->fifo_max * fsi->chan) - fsi_get_fifo_residue(fsi, 1);
-
-       /* size check */
-       if (fifo_free < send)
-               send = fifo_free;
+       ch_width = fsi_get_frame_width(fsi, is_play);
+
+       /* get residue data number of alsa */
+       data_residue_num = fsi_len2num(io->buff_len - io->buff_offset,
+                                      ch_width);
+
+       if (is_play) {
+               /*
+                * for play-back
+                *
+                * data_num_max : number of FSI fifo free space
+                * data_num     : number of ALSA residue data
+                */
+               data_num_max  = io->fifo_max_num * io->chan_num;
+               data_num_max -= fsi_get_fifo_data_num(fsi, is_play);
+
+               data_num = data_residue_num;
+
+               switch (ch_width) {
+               case 2:
+                       fn = fsi_dma_soft_push16;
+                       break;
+               case 4:
+                       fn = fsi_dma_soft_push32;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       } else {
+               /*
+                * for capture
+                *
+                * data_num_max : number of ALSA free space
+                * data_num     : number of data in FSI fifo
+                */
+               data_num_max = data_residue_num;
+               data_num     = fsi_get_fifo_data_num(fsi, is_play);
+
+               switch (ch_width) {
+               case 2:
+                       fn = fsi_dma_soft_pop16;
+                       break;
+               case 4:
+                       fn = fsi_dma_soft_pop32;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
 
-       start = runtime->dma_area;
-       start += fsi->byte_offset;
+       data_num = min(data_num, data_num_max);
 
-       switch (width) {
-       case 2:
-               for (i = 0; i < send; i++)
-                       fsi_reg_write(fsi, DODT,
-                                     ((u32)*((u16 *)start + i) << 8));
-               break;
-       case 4:
-               for (i = 0; i < send; i++)
-                       fsi_reg_write(fsi, DODT, *((u32 *)start + i));
-               break;
-       default:
-               return -EINVAL;
-       }
+       fn(fsi, data_num);
 
-       fsi->byte_offset += send * width;
+       /* update buff_offset */
+       io->buff_offset += fsi_num2offset(data_num, ch_width);
 
-       status = fsi_reg_read(fsi, DOFF_ST);
+       /* 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, DOFF_ST, 0);
+       fsi_reg_write(fsi, status_reg, 0);
 
-       fsi_irq_enable(fsi, 1);
+       /* re-enable irq */
+       fsi_irq_enable(fsi, is_play);
 
        if (over_period)
                snd_pcm_period_elapsed(substream);
@@ -587,85 +719,12 @@ static int fsi_data_push(struct fsi_priv *fsi, int startup)
 
 static int fsi_data_pop(struct fsi_priv *fsi, int startup)
 {
-       struct snd_pcm_runtime *runtime;
-       struct snd_pcm_substream *substream = NULL;
-       u32 status;
-       int free;
-       int fifo_fill;
-       int width;
-       u8 *start;
-       int i, over_period;
-
-       if (!fsi                        ||
-           !fsi->substream             ||
-           !fsi->substream->runtime)
-               return -EINVAL;
-
-       over_period     = 0;
-       substream       = fsi->substream;
-       runtime         = substream->runtime;
-
-       /* FSI FIFO has limit.
-        * So, this driver can not send periods data at a time
-        */
-       if (fsi->byte_offset >=
-           fsi->period_len * (fsi->periods + 1)) {
-
-               over_period = 1;
-               fsi->periods = (fsi->periods + 1) % runtime->periods;
-
-               if (0 == fsi->periods)
-                       fsi->byte_offset = 0;
-       }
-
-       /* get 1 channel data width */
-       width = frames_to_bytes(runtime, 1) / fsi->chan;
-
-       /* get free space for alsa */
-       free = (fsi->buffer_len - fsi->byte_offset) / width;
-
-       /* get recv size */
-       fifo_fill = fsi_get_fifo_residue(fsi, 0);
-
-       if (free < fifo_fill)
-               fifo_fill = free;
-
-       start = runtime->dma_area;
-       start += fsi->byte_offset;
-
-       switch (width) {
-       case 2:
-               for (i = 0; i < fifo_fill; i++)
-                       *((u16 *)start + i) =
-                               (u16)(fsi_reg_read(fsi, DIDT) >> 8);
-               break;
-       case 4:
-               for (i = 0; i < fifo_fill; i++)
-                       *((u32 *)start + i) = fsi_reg_read(fsi, DIDT);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       fsi->byte_offset += fifo_fill * width;
-
-       status = fsi_reg_read(fsi, DIFF_ST);
-       if (!startup) {
-               struct snd_soc_dai *dai = fsi_get_dai(substream);
-
-               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, DIFF_ST, 0);
-
-       fsi_irq_enable(fsi, 0);
-
-       if (over_period)
-               snd_pcm_period_elapsed(substream);
+       return fsi_fifo_data_ctrl(fsi, startup, SNDRV_PCM_STREAM_CAPTURE);
+}
 
-       return 0;
+static int fsi_data_push(struct fsi_priv *fsi, int startup)
+{
+       return fsi_fifo_data_ctrl(fsi, startup, SNDRV_PCM_STREAM_PLAYBACK);
 }
 
 static irqreturn_t fsi_interrupt(int irq, void *data)
@@ -677,13 +736,13 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
        fsi_master_mask_set(master, SOFT_RST, IR, 0);
        fsi_master_mask_set(master, SOFT_RST, IR, IR);
 
-       if (int_st & INT_A_OUT)
+       if (int_st & AB_IO(1, AO_SHIFT))
                fsi_data_push(&master->fsia, 0);
-       if (int_st & INT_B_OUT)
+       if (int_st & AB_IO(1, BO_SHIFT))
                fsi_data_push(&master->fsib, 0);
-       if (int_st & INT_A_IN)
+       if (int_st & AB_IO(1, AI_SHIFT))
                fsi_data_pop(&master->fsia, 0);
-       if (int_st & INT_B_IN)
+       if (int_st & AB_IO(1, BI_SHIFT))
                fsi_data_pop(&master->fsib, 0);
 
        fsi_irq_clear_all_status(master);
@@ -691,25 +750,24 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-/************************************************************************
-
-
-               dai ops
-
+/*
+ *             dai ops
+ */
 
-************************************************************************/
 static int fsi_dai_startup(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
        struct fsi_priv *fsi = fsi_get_priv(substream);
-       u32 flags = fsi_get_info_flags(fsi);
        struct fsi_master *master = fsi_get_master(fsi);
+       struct fsi_stream *io;
+       u32 flags = fsi_get_info_flags(fsi);
        u32 fmt;
        u32 reg;
        u32 data;
-       int is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+       int is_play = fsi_is_play(substream);
        int is_master;
-       int ret = 0;
+
+       io = fsi_get_stream(fsi, is_play);
 
        pm_runtime_get_sync(dai->dev);
 
@@ -741,29 +799,29 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
        switch (fmt) {
        case SH_FSI_FMT_MONO:
                data = CR_MONO;
-               fsi->chan = 1;
+               io->chan_num = 1;
                break;
        case SH_FSI_FMT_MONO_DELAY:
                data = CR_MONO_D;
-               fsi->chan = 1;
+               io->chan_num = 1;
                break;
        case SH_FSI_FMT_PCM:
                data = CR_PCM;
-               fsi->chan = 2;
+               io->chan_num = 2;
                break;
        case SH_FSI_FMT_I2S:
                data = CR_I2S;
-               fsi->chan = 2;
+               io->chan_num = 2;
                break;
        case SH_FSI_FMT_TDM:
-               fsi->chan = is_play ?
+               io->chan_num = is_play ?
                        SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
-               data = CR_TDM | (fsi->chan - 1);
+               data = CR_TDM | (io->chan_num - 1);
                break;
        case SH_FSI_FMT_TDM_DELAY:
-               fsi->chan = is_play ?
+               io->chan_num = is_play ?
                        SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
-               data = CR_TDM_D | (fsi->chan - 1);
+               data = CR_TDM_D | (io->chan_num - 1);
                break;
        case SH_FSI_FMT_SPDIF:
                if (master->core->ver < 2) {
@@ -771,7 +829,7 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
                        return -EINVAL;
                }
                data = CR_SPDIF;
-               fsi->chan = 2;
+               io->chan_num = 2;
                fsi_spdif_clk_ctrl(fsi, 1);
                fsi_reg_mask_set(fsi, OUT_SEL, 0x0010, 0x0010);
                break;
@@ -788,14 +846,14 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
        /* fifo init */
        fsi_fifo_init(fsi, is_play, dai);
 
-       return ret;
+       return 0;
 }
 
 static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
        struct fsi_priv *fsi = fsi_get_priv(substream);
-       int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       int is_play = fsi_is_play(substream);
 
        fsi_irq_disable(fsi, is_play);
        fsi_clk_ctrl(fsi, 0);
@@ -808,19 +866,19 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 {
        struct fsi_priv *fsi = fsi_get_priv(substream);
        struct snd_pcm_runtime *runtime = substream->runtime;
-       int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       int is_play = fsi_is_play(substream);
        int ret = 0;
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               fsi_stream_push(fsi, substream,
+               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);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
                fsi_irq_disable(fsi, is_play);
-               fsi_stream_pop(fsi);
+               fsi_stream_pop(fsi, is_play);
                break;
        }
 
@@ -835,7 +893,7 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
        struct fsi_master *master = fsi_get_master(fsi);
        int (*set_rate)(int is_porta, int rate) = master->info->set_rate;
        int fsi_ver = master->core->ver;
-       int is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+       int is_play = fsi_is_play(substream);
        int ret;
 
        /* if slave mode, set_rate is not needed */
@@ -916,13 +974,10 @@ static struct snd_soc_dai_ops fsi_dai_ops = {
        .hw_params      = fsi_dai_hw_params,
 };
 
-/************************************************************************
-
-
-               pcm ops
-
+/*
+ *             pcm ops
+ */
 
-************************************************************************/
 static struct snd_pcm_hardware fsi_pcm_hardware = {
        .info =         SNDRV_PCM_INFO_INTERLEAVED      |
                        SNDRV_PCM_INFO_MMAP             |
@@ -971,9 +1026,10 @@ static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct fsi_priv *fsi = fsi_get_priv(substream);
+       struct fsi_stream *io = fsi_get_stream(fsi, fsi_is_play(substream));
        long location;
 
-       location = (fsi->byte_offset - 1);
+       location = (io->buff_offset - 1);
        if (location < 0)
                location = 0;
 
@@ -988,13 +1044,10 @@ static struct snd_pcm_ops fsi_pcm_ops = {
        .pointer        = fsi_pointer,
 };
 
-/************************************************************************
-
-
-               snd_soc_platform
-
+/*
+ *             snd_soc_platform
+ */
 
-************************************************************************/
 #define PREALLOC_BUFFER                (32 * 1024)
 #define PREALLOC_BUFFER_MAX    (32 * 1024)
 
@@ -1018,17 +1071,13 @@ static int fsi_pcm_new(struct snd_card *card,
                PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
 }
 
-/************************************************************************
-
-
-               alsa struct
-
+/*
+ *             alsa struct
+ */
 
-************************************************************************/
-struct snd_soc_dai fsi_soc_dai[] = {
+static struct snd_soc_dai_driver fsi_soc_dai[] = {
        {
-               .name                   = "FSIA",
-               .id                     = 0,
+               .name                   = "fsia-dai",
                .playback = {
                        .rates          = FSI_RATES,
                        .formats        = FSI_FMTS,
@@ -1044,8 +1093,7 @@ struct snd_soc_dai fsi_soc_dai[] = {
                .ops = &fsi_dai_ops,
        },
        {
-               .name                   = "FSIB",
-               .id                     = 1,
+               .name                   = "fsib-dai",
                .playback = {
                        .rates          = FSI_RATES,
                        .formats        = FSI_FMTS,
@@ -1061,23 +1109,17 @@ struct snd_soc_dai fsi_soc_dai[] = {
                .ops = &fsi_dai_ops,
        },
 };
-EXPORT_SYMBOL_GPL(fsi_soc_dai);
 
-struct snd_soc_platform fsi_soc_platform = {
-       .name           = "fsi-pcm",
-       .pcm_ops        = &fsi_pcm_ops,
+static struct snd_soc_platform_driver fsi_soc_platform = {
+       .ops            = &fsi_pcm_ops,
        .pcm_new        = fsi_pcm_new,
        .pcm_free       = fsi_pcm_free,
 };
-EXPORT_SYMBOL_GPL(fsi_soc_platform);
-
-/************************************************************************
-
-
-               platform function
 
+/*
+ *             platform function
+ */
 
-************************************************************************/
 static int fsi_probe(struct platform_device *pdev)
 {
        struct fsi_master *master;
@@ -1132,11 +1174,7 @@ static int fsi_probe(struct platform_device *pdev)
 
        pm_runtime_enable(&pdev->dev);
        pm_runtime_resume(&pdev->dev);
-
-       fsi_soc_dai[0].dev              = &pdev->dev;
-       fsi_soc_dai[0].private_data     = &master->fsia;
-       fsi_soc_dai[1].dev              = &pdev->dev;
-       fsi_soc_dai[1].private_data     = &master->fsib;
+       dev_set_drvdata(&pdev->dev, master);
 
        fsi_soft_all_reset(master);
 
@@ -1147,13 +1185,13 @@ static int fsi_probe(struct platform_device *pdev)
                goto exit_iounmap;
        }
 
-       ret = snd_soc_register_platform(&fsi_soc_platform);
+       ret = snd_soc_register_platform(&pdev->dev, &fsi_soc_platform);
        if (ret < 0) {
                dev_err(&pdev->dev, "cannot snd soc register\n");
                goto exit_free_irq;
        }
 
-       return snd_soc_register_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
+       return snd_soc_register_dais(&pdev->dev, fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
 
 exit_free_irq:
        free_irq(irq, master);
@@ -1171,10 +1209,10 @@ static int fsi_remove(struct platform_device *pdev)
 {
        struct fsi_master *master;
 
-       master = fsi_get_master(fsi_soc_dai[0].private_data);
+       master = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
-       snd_soc_unregister_platform(&fsi_soc_platform);
+       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai));
+       snd_soc_unregister_platform(&pdev->dev);
 
        pm_runtime_disable(&pdev->dev);
 
@@ -1183,11 +1221,6 @@ static int fsi_remove(struct platform_device *pdev)
        iounmap(master->base);
        kfree(master);
 
-       fsi_soc_dai[0].dev              = NULL;
-       fsi_soc_dai[0].private_data     = NULL;
-       fsi_soc_dai[1].dev              = NULL;
-       fsi_soc_dai[1].private_data     = NULL;
-
        return 0;
 }
 
@@ -1229,11 +1262,13 @@ static struct fsi_core fsi2_core = {
 static struct platform_device_id fsi_id_table[] = {
        { "sh_fsi",     (kernel_ulong_t)&fsi1_core },
        { "sh_fsi2",    (kernel_ulong_t)&fsi2_core },
+       {},
 };
+MODULE_DEVICE_TABLE(platform, fsi_id_table);
 
 static struct platform_driver fsi_driver = {
        .driver         = {
-               .name   = "sh_fsi",
+               .name   = "fsi-pcm-audio",
                .pm     = &fsi_pm_ops,
        },
        .probe          = fsi_probe,
@@ -1250,6 +1285,7 @@ static void __exit fsi_mobile_exit(void)
 {
        platform_driver_unregister(&fsi_driver);
 }
+
 module_init(fsi_mobile_init);
 module_exit(fsi_mobile_exit);
 
index 41db75af3c69d3b64f2420e07acfb2ca3473fa45..c87e3ff28a0a02957bbd37c2de21d96b661e569e 100644 (file)
@@ -239,8 +239,7 @@ static int hac_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 hac_priv *hac = &hac_cpu_data[rtd->dai->cpu_dai->id];
+       struct hac_priv *hac = &hac_cpu_data[dai->id];
        int d = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
 
        switch (params->msbits) {
@@ -271,10 +270,9 @@ static struct snd_soc_dai_ops hac_dai_ops = {
        .hw_params      = hac_hw_params,
 };
 
-struct snd_soc_dai sh4_hac_dai[] = {
+static struct snd_soc_dai_driver sh4_hac_dai[] = {
 {
-       .name                   = "HAC0",
-       .id                     = 0,
+       .name                   = "hac-dai.0",
        .ac97_control           = 1,
        .playback = {
                .rates          = AC97_RATES,
@@ -292,8 +290,7 @@ struct snd_soc_dai sh4_hac_dai[] = {
 },
 #ifdef CONFIG_CPU_SUBTYPE_SH7760
 {
-       .name                   = "HAC1",
-       .ac97_control           = 1,
+       .name                   = "hac-dai.1",
        .id                     = 1,
        .playback = {
                .rates          = AC97_RATES,
@@ -312,19 +309,40 @@ struct snd_soc_dai sh4_hac_dai[] = {
 },
 #endif
 };
-EXPORT_SYMBOL_GPL(sh4_hac_dai);
 
-static int __init sh4_hac_init(void)
+static int __devinit hac_soc_platform_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_dais(&pdev->dev, sh4_hac_dai,
+                       ARRAY_SIZE(sh4_hac_dai));
+}
+
+static int __devexit hac_soc_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sh4_hac_dai));
+       return 0;
+}
+
+static struct platform_driver hac_pcm_driver = {
+       .driver = {
+                       .name = "hac-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = hac_soc_platform_probe,
+       .remove = __devexit_p(hac_soc_platform_remove),
+};
+
+static int __init sh4_hac_pcm_init(void)
 {
-       return snd_soc_register_dais(sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
+       return platform_driver_register(&hac_pcm_driver);
 }
-module_init(sh4_hac_init);
+module_init(sh4_hac_pcm_init);
 
-static void __exit sh4_hac_exit(void)
+static void __exit sh4_hac_pcm_exit(void)
 {
-       snd_soc_unregister_dais(sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
+       platform_driver_unregister(&hac_pcm_driver);
 }
-module_exit(sh4_hac_exit);
+module_exit(sh4_hac_pcm_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver");
index 87e2b7fcbf176d9f429506b285dcc2f6ac05d7bc..ac6c49ce6fdf5eb199ebad36b64c9fc159f10d40 100644 (file)
@@ -51,7 +51,7 @@ static int migor_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 *codec_dai = rtd->codec_dai;
        int ret;
        unsigned int rate = params_rate(params);
 
@@ -69,7 +69,7 @@ static int migor_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_fmt(rtd->dai->cpu_dai, SND_SOC_DAIFMT_NB_IF |
+       ret = snd_soc_dai_set_fmt(rtd->cpu_dai, SND_SOC_DAIFMT_NB_IF |
                                  SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS);
        if (ret < 0)
                return ret;
@@ -82,7 +82,7 @@ static int migor_hw_params(struct snd_pcm_substream *substream,
        clk_set_rate(&siumckb_clk, codec_freq);
        dev_dbg(codec_dai->dev, "%s: configure %luHz\n", __func__, codec_freq);
 
-       ret = snd_soc_dai_set_sysclk(rtd->dai->cpu_dai, SIU_CLKB_EXT,
+       ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, SIU_CLKB_EXT,
                                     codec_freq / 2, SND_SOC_CLOCK_IN);
 
        if (!ret)
@@ -94,7 +94,7 @@ static int migor_hw_params(struct snd_pcm_substream *substream,
 static int migor_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
        if (use_count) {
                use_count--;
@@ -137,8 +137,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
        { "Mic Bias", NULL, "External Microphone" },
 };
 
-static int migor_dai_init(struct snd_soc_codec *codec)
+static int migor_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_soc_codec *codec = rtd->codec;
+
        snd_soc_dapm_new_controls(codec, migor_dapm_widgets,
                                  ARRAY_SIZE(migor_dapm_widgets));
 
@@ -151,8 +153,10 @@ static int migor_dai_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link migor_dai = {
        .name = "wm8978",
        .stream_name = "WM8978",
-       .cpu_dai = &siu_i2s_dai,
-       .codec_dai = &wm8978_dai,
+       .cpu_dai_name = "siu-i2s-dai",
+       .codec_dai_name = "wm8978-hifi",
+       .platform_name = "siu-pcm-audio",
+       .codec_name = "wm8978.0-001a",
        .ops = &migor_dai_ops,
        .init = migor_dai_init,
 };
@@ -160,17 +164,10 @@ static struct snd_soc_dai_link migor_dai = {
 /* migor audio machine driver */
 static struct snd_soc_card snd_soc_migor = {
        .name = "Migo-R",
-       .platform = &siu_platform,
        .dai_link = &migor_dai,
        .num_links = 1,
 };
 
-/* migor audio subsystem */
-static struct snd_soc_device migor_snd_devdata = {
-       .card = &snd_soc_migor,
-       .codec_dev = &soc_codec_dev_wm8978,
-};
-
 static struct platform_device *migor_snd_device;
 
 static int __init migor_init(void)
@@ -195,9 +192,7 @@ static int __init migor_init(void)
                goto epdevalloc;
        }
 
-       platform_set_drvdata(migor_snd_device, &migor_snd_devdata);
-
-       migor_snd_devdata.dev = &migor_snd_device->dev;
+       platform_set_drvdata(migor_snd_device, &snd_soc_migor);
 
        ret = platform_device_add(migor_snd_device);
        if (ret)
index ce7f95b59de32aa3efe58bd46389ecb1d0b98c5e..b897f7b96d8990bbd0bee2c199bdf4531b9c6840 100644 (file)
 #include <sound/soc-dapm.h>
 #include <asm/io.h>
 
-#include "../codecs/ac97.h"
-
 #define IPSEL 0xFE400034
 
 /* platform specific structs can be declared here */
-extern struct snd_soc_dai sh4_hac_dai[2];
-extern struct snd_soc_platform sh7760_soc_platform;
+extern struct snd_soc_dai_driver sh4_hac_dai[2];
+extern struct snd_soc_platform_driver sh7760_soc_platform;
 
-static int machine_init(struct snd_soc_codec *codec)
+static int machine_init(struct snd_soc_pcm_runtime *rtd)
 {
-       snd_soc_dapm_sync(codec);
+       snd_soc_dapm_sync(rtd->codec);
        return 0;
 }
 
 static struct snd_soc_dai_link sh7760_ac97_dai = {
        .name = "AC97",
        .stream_name = "AC97 HiFi",
-       .cpu_dai = &sh4_hac_dai[0],     /* HAC0 */
-       .codec_dai = &ac97_dai,
+       .cpu_dai_name = "hac-dai.0",    /* HAC0 */
+       .codec_dai_name = "ac97-hifi",
+       .platform_name = "sh7760-pcm-audio",
+       .codec_name = "ac97-codec",
        .init = machine_init,
        .ops = NULL,
 };
 
 static struct snd_soc_card sh7760_ac97_soc_machine  = {
        .name = "SH7760 AC97",
-       .platform = &sh7760_soc_platform,
        .dai_link = &sh7760_ac97_dai,
        .num_links = 1,
 };
 
-static struct snd_soc_device sh7760_ac97_snd_devdata = {
-       .card = &sh7760_ac97_soc_machine,
-       .codec_dev = &soc_codec_dev_ac97,
-};
-
 static struct platform_device *sh7760_ac97_snd_device;
 
 static int __init sh7760_ac97_init(void)
@@ -67,8 +61,7 @@ static int __init sh7760_ac97_init(void)
                goto out;
 
        platform_set_drvdata(sh7760_ac97_snd_device,
-                            &sh7760_ac97_snd_devdata);
-       sh7760_ac97_snd_devdata.dev = &sh7760_ac97_snd_device->dev;
+                            &sh7760_ac97_soc_machine);
        ret = platform_device_add(sh7760_ac97_snd_device);
 
        if (ret)
index 492b1cae24ccb3dcd3b36681866aca923e78752b..9f4dcb921ff027563bab83e0eb720dd96b32b8cd 100644 (file)
@@ -98,7 +98,9 @@ enum {
        SIU_CLKB_EXT
 };
 
+struct device;
 struct siu_info {
+       struct device           *dev;
        int                     port_id;
        u32 __iomem             *pram;
        u32 __iomem             *xram;
@@ -181,8 +183,8 @@ static inline u32 siu_read32(u32 __iomem *addr)
 #define SIU_BRGBSEL    (0x108 / sizeof(u32))
 #define SIU_BRRB       (0x10c / sizeof(u32))
 
-extern struct snd_soc_platform siu_platform;
-extern struct snd_soc_dai siu_i2s_dai;
+extern struct snd_soc_platform_driver siu_platform;
+extern struct siu_info *siu_i2s_data;
 
 int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card);
 void siu_free_port(struct siu_port *port_info);
index eeed5edd722b2df38e4449f8b8e78d815c4fbcfd..af53b64d8af2ca8b6bda4894b6f091bfbefe5f65 100644 (file)
@@ -71,6 +71,8 @@ struct port_flag {
        struct format_flag      capture;
 };
 
+struct siu_info *siu_i2s_data;
+
 static struct port_flag siu_flags[SIU_PORT_NUM] = {
        [SIU_PORT_A] = {
                .playback = {
@@ -104,13 +106,13 @@ static struct port_flag siu_flags[SIU_PORT_NUM] = {
 
 static void siu_dai_start(struct siu_port *port_info)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
 
        dev_dbg(port_info->pcm->card->dev, "%s\n", __func__);
 
        /* Turn on SIU clock */
-       pm_runtime_get_sync(siu_i2s_dai.dev);
+       pm_runtime_get_sync(info->dev);
 
        /* Issue software reset to siu */
        siu_write32(base + SIU_SRCTL, 0);
@@ -148,21 +150,21 @@ static void siu_dai_start(struct siu_port *port_info)
        siu_write32(base + SIU_SBDVCB, port_info->capture.volume);
 }
 
-static void siu_dai_stop(void)
+static void siu_dai_stop(struct siu_port *port_info)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
 
        /* SIU software reset */
        siu_write32(base + SIU_SRCTL, 0);
 
        /* Turn off SIU clock */
-       pm_runtime_put_sync(siu_i2s_dai.dev);
+       pm_runtime_put_sync(info->dev);
 }
 
 static void siu_dai_spbAselect(struct siu_port *port_info)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct siu_firmware *fw = &info->fw;
        u32 *ydef = fw->yram0;
        u32 idx;
@@ -187,7 +189,7 @@ static void siu_dai_spbAselect(struct siu_port *port_info)
 
 static void siu_dai_spbBselect(struct siu_port *port_info)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct siu_firmware *fw = &info->fw;
        u32 *ydef = fw->yram0;
        u32 idx;
@@ -207,7 +209,7 @@ static void siu_dai_spbBselect(struct siu_port *port_info)
 
 static void siu_dai_open(struct siu_stream *siu_stream)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        u32 srctl, ifctl;
 
@@ -238,7 +240,7 @@ static void siu_dai_open(struct siu_stream *siu_stream)
  */
 static void siu_dai_pcmdatapack(struct siu_stream *siu_stream)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        u32 dpak;
 
@@ -258,7 +260,7 @@ static void siu_dai_pcmdatapack(struct siu_stream *siu_stream)
 
 static int siu_dai_spbstart(struct siu_port *port_info)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        struct siu_firmware *fw = &info->fw;
        u32 *ydef = fw->yram0;
@@ -323,7 +325,7 @@ static int siu_dai_spbstart(struct siu_port *port_info)
 
 static void siu_dai_spbstop(struct siu_port *port_info)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
 
        siu_write32(base + SIU_SBACTIV, 0);
@@ -402,7 +404,7 @@ static int siu_dai_put_volume(struct snd_kcontrol *kctrl,
 {
        struct siu_port *port_info = snd_kcontrol_chip(kctrl);
        struct device *dev = port_info->pcm->card->dev;
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        u32 new_vol;
        u32 cur_vol;
@@ -510,7 +512,7 @@ void siu_free_port(struct siu_port *port_info)
 static int siu_dai_startup(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = snd_soc_dai_get_drvdata(dai);
        struct snd_pcm_runtime *rt = substream->runtime;
        struct siu_port *port_info = siu_port_info(substream);
        int ret;
@@ -532,7 +534,7 @@ static int siu_dai_startup(struct snd_pcm_substream *substream,
 static void siu_dai_shutdown(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = snd_soc_dai_get_drvdata(dai);
        struct siu_port *port_info = siu_port_info(substream);
 
        dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__,
@@ -548,7 +550,7 @@ static void siu_dai_shutdown(struct snd_pcm_substream *substream,
                /* during stmread or stmwrite ? */
                BUG_ON(port_info->playback.rw_flg || port_info->capture.rw_flg);
                siu_dai_spbstop(port_info);
-               siu_dai_stop();
+               siu_dai_stop(port_info);
        }
 }
 
@@ -556,7 +558,7 @@ static void siu_dai_shutdown(struct snd_pcm_substream *substream,
 static int siu_dai_prepare(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *dai)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = snd_soc_dai_get_drvdata(dai);
        struct snd_pcm_runtime *rt = substream->runtime;
        struct siu_port *port_info = siu_port_info(substream);
        struct siu_stream *siu_stream;
@@ -605,7 +607,7 @@ fail:
 static int siu_dai_set_fmt(struct snd_soc_dai *dai,
                           unsigned int fmt)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = snd_soc_dai_get_drvdata(dai);
        u32 __iomem *base = info->reg;
        u32 ifctl;
 
@@ -671,21 +673,37 @@ static int siu_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
                return -EINVAL;
        }
 
-       siu_clk = clk_get(siu_i2s_dai.dev, siu_name);
-       if (IS_ERR(siu_clk))
+       siu_clk = clk_get(dai->dev, siu_name);
+       if (IS_ERR(siu_clk)) {
+               dev_err(dai->dev, "%s: cannot get a SIU clock: %ld\n", __func__,
+                       PTR_ERR(siu_clk));
                return PTR_ERR(siu_clk);
+       }
+
+       parent_clk = clk_get(dai->dev, parent_name);
+       if (IS_ERR(parent_clk)) {
+               ret = PTR_ERR(parent_clk);
+               dev_err(dai->dev, "cannot get a SIU clock parent: %d\n", ret);
+               goto epclkget;
+       }
 
-       parent_clk = clk_get(siu_i2s_dai.dev, parent_name);
-       if (!IS_ERR(parent_clk)) {
-               ret = clk_set_parent(siu_clk, parent_clk);
-               if (!ret)
-                       clk_set_rate(siu_clk, freq);
-               clk_put(parent_clk);
+       ret = clk_set_parent(siu_clk, parent_clk);
+       if (ret < 0) {
+               dev_err(dai->dev, "cannot reparent the SIU clock: %d\n", ret);
+               goto eclksetp;
        }
 
+       ret = clk_set_rate(siu_clk, freq);
+       if (ret < 0)
+               dev_err(dai->dev, "cannot set SIU clock rate: %d\n", ret);
+
+       /* TODO: when clkdev gets reference counting we'll move these to siu_dai_shutdown() */
+eclksetp:
+       clk_put(parent_clk);
+epclkget:
        clk_put(siu_clk);
 
-       return 0;
+       return ret;
 }
 
 static struct snd_soc_dai_ops siu_dai_ops = {
@@ -696,9 +714,8 @@ static struct snd_soc_dai_ops siu_dai_ops = {
        .set_fmt        = siu_dai_set_fmt,
 };
 
-struct snd_soc_dai siu_i2s_dai = {
-       .name = "sh-siu",
-       .id = 0,
+static struct snd_soc_dai_driver siu_i2s_dai = {
+       .name   = "siu-i2s-dai",
        .playback = {
                .channels_min = 2,
                .channels_max = 2,
@@ -713,7 +730,6 @@ struct snd_soc_dai siu_i2s_dai = {
         },
        .ops = &siu_dai_ops,
 };
-EXPORT_SYMBOL_GPL(siu_i2s_dai);
 
 static int __devinit siu_probe(struct platform_device *pdev)
 {
@@ -725,6 +741,8 @@ static int __devinit siu_probe(struct platform_device *pdev)
        info = kmalloc(sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
+       siu_i2s_data = info;
+       info->dev = &pdev->dev;
 
        ret = request_firmware(&fw_entry, "siu_spb.bin", &pdev->dev);
        if (ret)
@@ -767,14 +785,14 @@ static int __devinit siu_probe(struct platform_device *pdev)
        if (!info->reg)
                goto emapreg;
 
-       siu_i2s_dai.dev = &pdev->dev;
-       siu_i2s_dai.private_data = info;
+       dev_set_drvdata(&pdev->dev, info);
 
-       ret = snd_soc_register_dais(&siu_i2s_dai, 1);
+       /* register using ARRAY version so we can keep dai name */
+       ret = snd_soc_register_dais(&pdev->dev, &siu_i2s_dai, 1);
        if (ret < 0)
                goto edaiinit;
 
-       ret = snd_soc_register_platform(&siu_platform);
+       ret = snd_soc_register_platform(&pdev->dev, &siu_platform);
        if (ret < 0)
                goto esocregp;
 
@@ -783,7 +801,7 @@ static int __devinit siu_probe(struct platform_device *pdev)
        return ret;
 
 esocregp:
-       snd_soc_unregister_dais(&siu_i2s_dai, 1);
+       snd_soc_unregister_dai(&pdev->dev);
 edaiinit:
        iounmap(info->reg);
 emapreg:
@@ -804,13 +822,13 @@ ereqfw:
 
 static int __devexit siu_remove(struct platform_device *pdev)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = dev_get_drvdata(&pdev->dev);
        struct resource *res;
 
        pm_runtime_disable(&pdev->dev);
 
-       snd_soc_unregister_platform(&siu_platform);
-       snd_soc_unregister_dais(&siu_i2s_dai, 1);
+       snd_soc_unregister_platform(&pdev->dev);
+       snd_soc_unregister_dai(&pdev->dev);
 
        iounmap(info->reg);
        iounmap(info->yram);
@@ -826,7 +844,8 @@ static int __devexit siu_remove(struct platform_device *pdev)
 
 static struct platform_driver siu_driver = {
        .driver         = {
-               .name   = "sh_siu",
+               .owner  = THIS_MODULE,
+               .name   = "siu-pcm-audio",
        },
        .probe          = siu_probe,
        .remove         = __devexit_p(siu_remove),
index b0ccd0b862fc3722512a9d559f107d1a655e67de..ed29c9e1ed4efe764ad7a06d448e58386201efcb 100644 (file)
@@ -48,7 +48,7 @@ struct siu_port *siu_ports[SIU_PORT_NUM];
 /* transfersize is number of u32 dma transfers per period */
 static int siu_pcm_stmwrite_stop(struct siu_port *port_info)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        struct siu_stream *siu_stream = &port_info->playback;
        u32 stfifo;
@@ -114,7 +114,7 @@ static void siu_dma_tx_complete(void *arg)
 static int siu_pcm_wr_set(struct siu_port *port_info,
                          dma_addr_t buff, u32 size)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        struct siu_stream *siu_stream = &port_info->playback;
        struct snd_pcm_substream *substream = siu_stream->substream;
@@ -162,7 +162,7 @@ static int siu_pcm_wr_set(struct siu_port *port_info,
 static int siu_pcm_rd_set(struct siu_port *port_info,
                          dma_addr_t buff, size_t size)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        struct siu_stream *siu_stream = &port_info->capture;
        struct snd_pcm_substream *substream = siu_stream->substream;
@@ -272,7 +272,7 @@ static int siu_pcm_stmread_start(struct siu_port *port_info)
 
 static int siu_pcm_stmread_stop(struct siu_port *port_info)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        struct siu_stream *siu_stream = &port_info->capture;
        struct device *dev = siu_stream->substream->pcm->card->dev;
@@ -296,7 +296,7 @@ static int siu_pcm_stmread_stop(struct siu_port *port_info)
 static int siu_pcm_hw_params(struct snd_pcm_substream *ss,
                             struct snd_pcm_hw_params *hw_params)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct device *dev = ss->pcm->card->dev;
        int ret;
 
@@ -311,7 +311,7 @@ static int siu_pcm_hw_params(struct snd_pcm_substream *ss,
 
 static int siu_pcm_hw_free(struct snd_pcm_substream *ss)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct siu_port *port_info = siu_port_info(ss);
        struct device *dev = ss->pcm->card->dev;
        struct siu_stream *siu_stream;
@@ -342,11 +342,12 @@ static bool filter(struct dma_chan *chan, void *slave)
 static int siu_pcm_open(struct snd_pcm_substream *ss)
 {
        /* Playback / Capture */
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct snd_soc_pcm_runtime *rtd = ss->private_data;
+       struct siu_platform *pdata = rtd->platform->dev->platform_data;
+       struct siu_info *info = siu_i2s_data;
        struct siu_port *port_info = siu_port_info(ss);
        struct siu_stream *siu_stream;
        u32 port = info->port_id;
-       struct siu_platform *pdata = siu_i2s_dai.dev->platform_data;
        struct device *dev = ss->pcm->card->dev;
        dma_cap_mask_t mask;
        struct sh_dmae_slave *param;
@@ -383,7 +384,7 @@ static int siu_pcm_open(struct snd_pcm_substream *ss)
 
 static int siu_pcm_close(struct snd_pcm_substream *ss)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct device *dev = ss->pcm->card->dev;
        struct siu_port *port_info = siu_port_info(ss);
        struct siu_stream *siu_stream;
@@ -405,7 +406,7 @@ static int siu_pcm_close(struct snd_pcm_substream *ss)
 
 static int siu_pcm_prepare(struct snd_pcm_substream *ss)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct siu_port *port_info = siu_port_info(ss);
        struct device *dev = ss->pcm->card->dev;
        struct snd_pcm_runtime  *rt = ss->runtime;
@@ -451,7 +452,7 @@ static int siu_pcm_prepare(struct snd_pcm_substream *ss)
 
 static int siu_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
 {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct device *dev = ss->pcm->card->dev;
        struct siu_port *port_info = siu_port_info(ss);
        int ret;
@@ -494,7 +495,7 @@ static int siu_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
 static snd_pcm_uframes_t siu_pcm_pointer_dma(struct snd_pcm_substream *ss)
 {
        struct device *dev = ss->pcm->card->dev;
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        struct siu_port *port_info = siu_port_info(ss);
        struct snd_pcm_runtime *rt = ss->runtime;
@@ -530,7 +531,7 @@ static int siu_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
                       struct snd_pcm *pcm)
 {
        /* card->dev == socdev->dev, see snd_soc_new_pcms() */
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct platform_device *pdev = to_platform_device(card->dev);
        int ret;
        int i;
@@ -607,9 +608,8 @@ static struct snd_pcm_ops siu_pcm_ops = {
        .pointer        = siu_pcm_pointer_dma,
 };
 
-struct snd_soc_platform siu_platform = {
-       .name           = "siu-audio",
-       .pcm_ops        = &siu_pcm_ops,
+struct snd_soc_platform_driver siu_platform = {
+       .ops                    = &siu_pcm_ops,
        .pcm_new        = siu_pcm_new,
        .pcm_free       = siu_pcm_free,
 };
index b378096cadb1566e4e6dad55ae94cf7c0f6e9e25..40bbdf1591dca351631f8bdbbcc5f514e9c99139 100644 (file)
@@ -92,8 +92,7 @@ struct ssi_priv {
 static int ssi_startup(struct snd_pcm_substream *substream,
                       struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
        if (ssi->inuse) {
                pr_debug("ssi: already in use!\n");
                return -EBUSY;
@@ -105,8 +104,7 @@ static int ssi_startup(struct snd_pcm_substream *substream,
 static void ssi_shutdown(struct snd_pcm_substream *substream,
                         struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
 
        ssi->inuse = 0;
 }
@@ -114,8 +112,7 @@ static void ssi_shutdown(struct snd_pcm_substream *substream,
 static int ssi_trigger(struct snd_pcm_substream *substream, int cmd,
                       struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -135,8 +132,7 @@ static int ssi_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 ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
        unsigned long ssicr = SSIREG(SSICR);
        unsigned int bits, channels, swl, recv, i;
 
@@ -346,10 +342,9 @@ static struct snd_soc_dai_ops ssi_dai_ops = {
        .set_fmt        = ssi_set_fmt,
 };
 
-struct snd_soc_dai sh4_ssi_dai[] = {
+struct snd_soc_dai_driver sh4_ssi_dai[] = {
 {
-       .name                   = "SSI0",
-       .id                     = 0,
+       .name                   = "ssi-dai.0",
        .playback = {
                .rates          = SSI_RATES,
                .formats        = SSI_FMTS,
@@ -366,8 +361,7 @@ struct snd_soc_dai sh4_ssi_dai[] = {
 },
 #ifdef CONFIG_CPU_SUBTYPE_SH7760
 {
-       .name                   = "SSI1",
-       .id                     = 1,
+       .name                   = "ssi-dai.1",
        .playback = {
                .rates          = SSI_RATES,
                .formats        = SSI_FMTS,
@@ -384,19 +378,40 @@ struct snd_soc_dai sh4_ssi_dai[] = {
 },
 #endif
 };
-EXPORT_SYMBOL_GPL(sh4_ssi_dai);
 
-static int __init sh4_ssi_init(void)
+static int __devinit sh4_soc_dai_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_dais(&pdev->dev, sh4_ssi_dai,
+                       ARRAY_SIZE(sh4_ssi_dai));
+}
+
+static int __devexit sh4_soc_dai_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_dai(&pdev->dev, ARRAY_SIZE(sh4_ssi_dai));
+       return 0;
+}
+
+static struct platform_driver sh4_ssi_driver = {
+       .driver = {
+                       .name = "sh4-ssi-dai",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = sh4_soc_dai_probe,
+       .remove = __devexit_p(sh4_soc_dai_remove),
+};
+
+static int __init snd_sh4_ssi_init(void)
 {
-       return snd_soc_register_dais(sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai));
+       return platform_driver_register(&sh4_ssi_driver);
 }
-module_init(sh4_ssi_init);
+module_init(snd_sh4_ssi_init);
 
-static void __exit sh4_ssi_exit(void)
+static void __exit snd_sh4_ssi_exit(void)
 {
-       snd_soc_unregister_dais(sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai));
+       platform_driver_unregister(&sh4_ssi_driver);
 }
-module_exit(sh4_ssi_exit);
+module_exit(snd_sh4_ssi_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver");
index f6b0d2829ea96d438d1e84550272c6a7bda80b4c..d214f02cbb65a46314a121948525cb2b005734e1 100644 (file)
@@ -19,8 +19,15 @@ static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
                                     unsigned int reg)
 {
        u16 *cache = codec->reg_cache;
-       if (reg >= codec->reg_cache_size)
-               return -1;
+
+       if (reg >= codec->driver->reg_cache_size ||
+               snd_soc_codec_volatile_register(codec, reg)) {
+                       if (codec->cache_only)
+                               return -1;
+
+                       return codec->hw_read(codec, reg);
+       }
+
        return cache[reg];
 }
 
@@ -31,13 +38,12 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
        u8 data[2];
        int ret;
 
-       BUG_ON(codec->volatile_register);
-
        data[0] = (reg << 4) | ((value >> 8) & 0x000f);
        data[1] = value & 0x00ff;
 
-       if (reg < codec->reg_cache_size)
-               cache[reg] = value;
+       if (!snd_soc_codec_volatile_register(codec, reg) &&
+               reg < codec->driver->reg_cache_size)
+                       cache[reg] = value;
 
        if (codec->cache_only) {
                codec->cache_sync = 1;
@@ -89,8 +95,15 @@ static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
                                     unsigned int reg)
 {
        u16 *cache = codec->reg_cache;
-       if (reg >= codec->reg_cache_size)
-               return -1;
+
+       if (reg >= codec->driver->reg_cache_size ||
+               snd_soc_codec_volatile_register(codec, reg)) {
+                       if (codec->cache_only)
+                               return -1;
+
+                       return codec->hw_read(codec, reg);
+       }
+
        return cache[reg];
 }
 
@@ -101,13 +114,12 @@ static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
        u8 data[2];
        int ret;
 
-       BUG_ON(codec->volatile_register);
-
        data[0] = (reg << 1) | ((value >> 8) & 0x0001);
        data[1] = value & 0x00ff;
 
-       if (reg < codec->reg_cache_size)
-               cache[reg] = value;
+       if (!snd_soc_codec_volatile_register(codec, reg) &&
+               reg < codec->driver->reg_cache_size)
+                       cache[reg] = value;
 
        if (codec->cache_only) {
                codec->cache_sync = 1;
@@ -161,14 +173,13 @@ static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
        u8 *cache = codec->reg_cache;
        u8 data[2];
 
-       BUG_ON(codec->volatile_register);
-
        reg &= 0xff;
        data[0] = reg;
        data[1] = value & 0xff;
 
-       if (reg < codec->reg_cache_size)
-               cache[reg] = value;
+       if (!snd_soc_codec_volatile_register(codec, reg) &&
+               reg < codec->driver->reg_cache_size)
+                       cache[reg] = value;
 
        if (codec->cache_only) {
                codec->cache_sync = 1;
@@ -187,12 +198,49 @@ static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
                                     unsigned int reg)
 {
        u8 *cache = codec->reg_cache;
+
        reg &= 0xff;
-       if (reg >= codec->reg_cache_size)
-               return -1;
+       if (reg >= codec->driver->reg_cache_size ||
+               snd_soc_codec_volatile_register(codec, reg)) {
+                       if (codec->cache_only)
+                               return -1;
+
+                       return codec->hw_read(codec, reg);
+       }
+
        return cache[reg];
 }
 
+#if defined(CONFIG_SPI_MASTER)
+static int snd_soc_8_8_spi_write(void *control_data, const char *data,
+                                int len)
+{
+       struct spi_device *spi = control_data;
+       struct spi_transfer t;
+       struct spi_message m;
+       u8 msg[2];
+
+       if (len <= 0)
+               return 0;
+
+       msg[0] = data[0];
+       msg[1] = data[1];
+
+       spi_message_init(&m);
+       memset(&t, 0, (sizeof t));
+
+       t.tx_buf = &msg[0];
+       t.len = len;
+
+       spi_message_add_tail(&t, &m);
+       spi_sync(spi, &m);
+
+       return len;
+}
+#else
+#define snd_soc_8_8_spi_write NULL
+#endif
+
 static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
                              unsigned int value)
 {
@@ -203,9 +251,9 @@ static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
        data[1] = (value >> 8) & 0xff;
        data[2] = value & 0xff;
 
-       if (!snd_soc_codec_volatile_register(codec, reg)
-               && reg < codec->reg_cache_size)
-                       reg_cache[reg] = value;
+       if (!snd_soc_codec_volatile_register(codec, reg) &&
+           reg < codec->driver->reg_cache_size)
+               reg_cache[reg] = value;
 
        if (codec->cache_only) {
                codec->cache_sync = 1;
@@ -225,10 +273,10 @@ static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
 {
        u16 *cache = codec->reg_cache;
 
-       if (reg >= codec->reg_cache_size ||
+       if (reg >= codec->driver->reg_cache_size ||
            snd_soc_codec_volatile_register(codec, reg)) {
                if (codec->cache_only)
-                       return -EINVAL;
+                       return -1;
 
                return codec->hw_read(codec, reg);
        } else {
@@ -236,6 +284,37 @@ static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
        }
 }
 
+#if defined(CONFIG_SPI_MASTER)
+static int snd_soc_8_16_spi_write(void *control_data, const char *data,
+                                int len)
+{
+       struct spi_device *spi = control_data;
+       struct spi_transfer t;
+       struct spi_message m;
+       u8 msg[3];
+
+       if (len <= 0)
+               return 0;
+
+       msg[0] = data[0];
+       msg[1] = data[1];
+       msg[2] = data[2];
+
+       spi_message_init(&m);
+       memset(&t, 0, (sizeof t));
+
+       t.tx_buf = &msg[0];
+       t.len = len;
+
+       spi_message_add_tail(&t, &m);
+       spi_sync(spi, &m);
+
+       return len;
+}
+#else
+#define snd_soc_8_16_spi_write NULL
+#endif
+
 #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
 static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
                                          unsigned int r)
@@ -344,8 +423,14 @@ static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
        u8 *cache = codec->reg_cache;
 
        reg &= 0xff;
-       if (reg >= codec->reg_cache_size)
-               return -1;
+       if (reg >= codec->driver->reg_cache_size ||
+               snd_soc_codec_volatile_register(codec, reg)) {
+                       if (codec->cache_only)
+                               return -1;
+
+                       return codec->hw_read(codec, reg);
+       }
+
        return cache[reg];
 }
 
@@ -356,15 +441,14 @@ static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
        u8 data[3];
        int ret;
 
-       BUG_ON(codec->volatile_register);
-
        data[0] = (reg >> 8) & 0xff;
        data[1] = reg & 0xff;
        data[2] = value;
 
        reg &= 0xff;
-       if (reg < codec->reg_cache_size)
-               cache[reg] = value;
+       if (!snd_soc_codec_volatile_register(codec, reg) &&
+               reg < codec->driver->reg_cache_size)
+                       cache[reg] = value;
 
        if (codec->cache_only) {
                codec->cache_sync = 1;
@@ -452,10 +536,10 @@ static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
 {
        u16 *cache = codec->reg_cache;
 
-       if (reg >= codec->reg_cache_size ||
+       if (reg >= codec->driver->reg_cache_size ||
            snd_soc_codec_volatile_register(codec, reg)) {
                if (codec->cache_only)
-                       return -EINVAL;
+                       return -1;
 
                return codec->hw_read(codec, reg);
        }
@@ -475,8 +559,9 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
        data[2] = (value >> 8) & 0xff;
        data[3] = value & 0xff;
 
-       if (reg < codec->reg_cache_size)
-               cache[reg] = value;
+       if (!snd_soc_codec_volatile_register(codec, reg) &&
+               reg < codec->driver->reg_cache_size)
+                       cache[reg] = value;
 
        if (codec->cache_only) {
                codec->cache_sync = 1;
@@ -494,6 +579,38 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
                return -EIO;
 }
 
+#if defined(CONFIG_SPI_MASTER)
+static int snd_soc_16_16_spi_write(void *control_data, const char *data,
+                                int len)
+{
+       struct spi_device *spi = control_data;
+       struct spi_transfer t;
+       struct spi_message m;
+       u8 msg[4];
+
+       if (len <= 0)
+               return 0;
+
+       msg[0] = data[0];
+       msg[1] = data[1];
+       msg[2] = data[2];
+       msg[3] = data[3];
+
+       spi_message_init(&m);
+       memset(&t, 0, (sizeof t));
+
+       t.tx_buf = &msg[0];
+       t.len = len;
+
+       spi_message_add_tail(&t, &m);
+       spi_sync(spi, &m);
+
+       return len;
+}
+#else
+#define snd_soc_16_16_spi_write NULL
+#endif
+
 static struct {
        int addr_bits;
        int data_bits;
@@ -516,11 +633,13 @@ static struct {
                .addr_bits = 8, .data_bits = 8,
                .write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
                .i2c_read = snd_soc_8_8_read_i2c,
+               .spi_write = snd_soc_8_8_spi_write,
        },
        {
                .addr_bits = 8, .data_bits = 16,
                .write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
                .i2c_read = snd_soc_8_16_read_i2c,
+               .spi_write = snd_soc_8_16_spi_write,
        },
        {
                .addr_bits = 16, .data_bits = 8,
@@ -532,6 +651,7 @@ static struct {
                .addr_bits = 16, .data_bits = 16,
                .write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
                .i2c_read = snd_soc_16_16_read_i2c,
+               .spi_write = snd_soc_16_16_spi_write,
        },
 };
 
@@ -572,8 +692,8 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
                return -EINVAL;
        }
 
-       codec->write = io_types[i].write;
-       codec->read = io_types[i].read;
+       codec->driver->write = io_types[i].write;
+       codec->driver->read = io_types[i].read;
 
        switch (control) {
        case SND_SOC_CUSTOM:
@@ -585,11 +705,19 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
 #endif
                if (io_types[i].i2c_read)
                        codec->hw_read = io_types[i].i2c_read;
+
+               codec->control_data = container_of(codec->dev,
+                                                  struct i2c_client,
+                                                  dev);
                break;
 
        case SND_SOC_SPI:
                if (io_types[i].spi_write)
                        codec->hw_write = io_types[i].spi_write;
+
+               codec->control_data = container_of(codec->dev,
+                                                  struct spi_device,
+                                                  dev);
                break;
        }
 
index 4057d35343bbbbd434e6a2f99bf0398aeac2a75e..1c8f3f507f54e7d1fc469ff03a2fdbf787640e3a 100644 (file)
@@ -3,6 +3,8 @@
  *
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Copyright 2005 Openedhand Ltd.
+ * Copyright (C) 2010 Slimlogic Ltd.
+ * Copyright (C) 2010 Texas Instruments Inc.
  *
  * Author: Liam Girdwood <lrg@slimlogic.co.uk>
  *         with code, comments and ideas from :-
@@ -37,6 +39,8 @@
 #include <sound/soc-dapm.h>
 #include <sound/initval.h>
 
+#define NAME_SIZE      32
+
 static DEFINE_MUTEX(pcm_mutex);
 static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq);
 
@@ -52,6 +56,7 @@ static LIST_HEAD(codec_list);
 
 static int snd_soc_register_card(struct snd_soc_card *card);
 static int snd_soc_unregister_card(struct snd_soc_card *card);
+static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
 
 /*
  * This is a timeout to do a DAPM powerdown after a stream is closed().
@@ -86,30 +91,30 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
 {
        int ret, i, step = 1, count = 0;
 
-       if (!codec->reg_cache_size)
+       if (!codec->driver->reg_cache_size)
                return 0;
 
-       if (codec->reg_cache_step)
-               step = codec->reg_cache_step;
+       if (codec->driver->reg_cache_step)
+               step = codec->driver->reg_cache_step;
 
        count += sprintf(buf, "%s registers\n", codec->name);
-       for (i = 0; i < codec->reg_cache_size; i += step) {
-               if (codec->readable_register && !codec->readable_register(i))
+       for (i = 0; i < codec->driver->reg_cache_size; i += step) {
+               if (codec->driver->readable_register && !codec->driver->readable_register(i))
                        continue;
 
                count += sprintf(buf + count, "%2x: ", i);
                if (count >= PAGE_SIZE - 1)
                        break;
 
-               if (codec->display_register) {
-                       count += codec->display_register(codec, buf + count,
+               if (codec->driver->display_register) {
+                       count += codec->driver->display_register(codec, buf + count,
                                                         PAGE_SIZE - count, i);
                } else {
                        /* If the read fails it's almost certainly due to
                         * the register being volatile and the device being
                         * powered off.
                         */
-                       ret = codec->read(codec, i);
+                       ret = codec->driver->read(codec, i);
                        if (ret >= 0)
                                count += snprintf(buf + count,
                                                  PAGE_SIZE - count,
@@ -137,8 +142,10 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
 static ssize_t codec_reg_show(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
-       struct snd_soc_device *devdata = dev_get_drvdata(dev);
-       return soc_codec_reg_show(devdata->card->codec, buf);
+       struct snd_soc_pcm_runtime *rtd =
+                       container_of(dev, struct snd_soc_pcm_runtime, dev);
+
+       return soc_codec_reg_show(rtd->codec, buf);
 }
 
 static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
@@ -146,20 +153,20 @@ static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
 static ssize_t pmdown_time_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       struct snd_soc_device *socdev = dev_get_drvdata(dev);
-       struct snd_soc_card *card = socdev->card;
+       struct snd_soc_pcm_runtime *rtd =
+                       container_of(dev, struct snd_soc_pcm_runtime, dev);
 
-       return sprintf(buf, "%ld\n", card->pmdown_time);
+       return sprintf(buf, "%ld\n", rtd->pmdown_time);
 }
 
 static ssize_t pmdown_time_set(struct device *dev,
                               struct device_attribute *attr,
                               const char *buf, size_t count)
 {
-       struct snd_soc_device *socdev = dev_get_drvdata(dev);
-       struct snd_soc_card *card = socdev->card;
+       struct snd_soc_pcm_runtime *rtd =
+                       container_of(dev, struct snd_soc_pcm_runtime, dev);
 
-       strict_strtol(buf, 10, &card->pmdown_time);
+       strict_strtol(buf, 10, &rtd->pmdown_time);
 
        return count;
 }
@@ -203,19 +210,19 @@ static ssize_t codec_reg_write_file(struct file *file,
                return -EFAULT;
        buf[buf_size] = 0;
 
-       if (codec->reg_cache_step)
-               step = codec->reg_cache_step;
+       if (codec->driver->reg_cache_step)
+               step = codec->driver->reg_cache_step;
 
        while (*start == ' ')
                start++;
        reg = simple_strtoul(start, &start, 16);
-       if ((reg >= codec->reg_cache_size) || (reg % step))
+       if ((reg >= codec->driver->reg_cache_size) || (reg % step))
                return -EINVAL;
        while (*start == ' ')
                start++;
        if (strict_strtoul(start, 16, &value))
                return -EINVAL;
-       codec->write(codec, reg, value);
+       codec->driver->write(codec, reg, value);
        return buf_size;
 }
 
@@ -228,16 +235,7 @@ static const struct file_operations codec_reg_fops = {
 
 static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
 {
-       char codec_root[128];
-
-       if (codec->dev)
-               snprintf(codec_root, sizeof(codec_root),
-                       "%s.%s", codec->name, dev_name(codec->dev));
-       else
-               snprintf(codec_root, sizeof(codec_root),
-                       "%s", codec->name);
-
-       codec->debugfs_codec_root = debugfs_create_dir(codec_root,
+       codec->debugfs_codec_root = debugfs_create_dir(codec->name ,
                                                       debugfs_root);
        if (!codec->debugfs_codec_root) {
                printk(KERN_WARNING
@@ -273,6 +271,106 @@ static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec)
        debugfs_remove_recursive(codec->debugfs_codec_root);
 }
 
+static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
+                                   size_t count, loff_t *ppos)
+{
+       char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       ssize_t len, ret = 0;
+       struct snd_soc_codec *codec;
+
+       if (!buf)
+               return -ENOMEM;
+
+       list_for_each_entry(codec, &codec_list, list) {
+               len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
+                              codec->name);
+               if (len >= 0)
+                       ret += len;
+               if (ret > PAGE_SIZE) {
+                       ret = PAGE_SIZE;
+                       break;
+               }
+       }
+
+       if (ret >= 0)
+               ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+       kfree(buf);
+
+       return ret;
+}
+
+static const struct file_operations codec_list_fops = {
+       .read = codec_list_read_file,
+       .llseek = default_llseek,/* read accesses f_pos */
+};
+
+static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
+                                 size_t count, loff_t *ppos)
+{
+       char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       ssize_t len, ret = 0;
+       struct snd_soc_dai *dai;
+
+       if (!buf)
+               return -ENOMEM;
+
+       list_for_each_entry(dai, &dai_list, list) {
+               len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", dai->name);
+               if (len >= 0)
+                       ret += len;
+               if (ret > PAGE_SIZE) {
+                       ret = PAGE_SIZE;
+                       break;
+               }
+       }
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+       kfree(buf);
+
+       return ret;
+}
+
+static const struct file_operations dai_list_fops = {
+       .read = dai_list_read_file,
+       .llseek = default_llseek,/* read accesses f_pos */
+};
+
+static ssize_t platform_list_read_file(struct file *file,
+                                      char __user *user_buf,
+                                      size_t count, loff_t *ppos)
+{
+       char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       ssize_t len, ret = 0;
+       struct snd_soc_platform *platform;
+
+       if (!buf)
+               return -ENOMEM;
+
+       list_for_each_entry(platform, &platform_list, list) {
+               len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
+                              platform->name);
+               if (len >= 0)
+                       ret += len;
+               if (ret > PAGE_SIZE) {
+                       ret = PAGE_SIZE;
+                       break;
+               }
+       }
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+
+       kfree(buf);
+
+       return ret;
+}
+
+static const struct file_operations platform_list_fops = {
+       .read = platform_list_read_file,
+       .llseek = default_llseek,/* read accesses f_pos */
+};
+
 #else
 
 static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec)
@@ -306,7 +404,7 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec)
        codec->ac97->dev.release = soc_ac97_device_release;
 
        dev_set_name(&codec->ac97->dev, "%d-%d:%s",
-                    codec->card->number, 0, codec->name);
+                    codec->card->snd_card->number, 0, codec->name);
        err = device_register(&codec->ac97->dev);
        if (err < 0) {
                snd_printk(KERN_ERR "Can't register ac97 bus\n");
@@ -320,24 +418,21 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec)
 static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_dai_link *machine = rtd->dai;
-       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_dai *codec_dai = machine->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int ret;
 
-       if (codec_dai->symmetric_rates || cpu_dai->symmetric_rates ||
-           machine->symmetric_rates) {
-               dev_dbg(card->dev, "Symmetry forces %dHz rate\n",
-                       machine->rate);
+       if (codec_dai->driver->symmetric_rates || cpu_dai->driver->symmetric_rates ||
+                       rtd->dai_link->symmetric_rates) {
+               dev_dbg(&rtd->dev, "Symmetry forces %dHz rate\n",
+                               rtd->rate);
 
                ret = snd_pcm_hw_constraint_minmax(substream->runtime,
                                                   SNDRV_PCM_HW_PARAM_RATE,
-                                                  machine->rate,
-                                                  machine->rate);
+                                                  rtd->rate,
+                                                  rtd->rate);
                if (ret < 0) {
-                       dev_err(card->dev,
+                       dev_err(&rtd->dev,
                                "Unable to apply rate symmetry constraint: %d\n", ret);
                        return ret;
                }
@@ -354,20 +449,19 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream)
 static int soc_pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_card *card = socdev->card;
        struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_soc_dai_link *machine = rtd->dai;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_dai *codec_dai = machine->codec_dai;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
+       struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver;
        int ret = 0;
 
        mutex_lock(&pcm_mutex);
 
        /* startup the audio subsystem */
-       if (cpu_dai->ops->startup) {
-               ret = cpu_dai->ops->startup(substream, cpu_dai);
+       if (cpu_dai->driver->ops->startup) {
+               ret = cpu_dai->driver->ops->startup(substream, cpu_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: can't open interface %s\n",
                                cpu_dai->name);
@@ -375,16 +469,16 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                }
        }
 
-       if (platform->pcm_ops->open) {
-               ret = platform->pcm_ops->open(substream);
+       if (platform->driver->ops->open) {
+               ret = platform->driver->ops->open(substream);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: can't open platform %s\n", platform->name);
                        goto platform_err;
                }
        }
 
-       if (codec_dai->ops->startup) {
-               ret = codec_dai->ops->startup(substream, codec_dai);
+       if (codec_dai->driver->ops->startup) {
+               ret = codec_dai->driver->ops->startup(substream, codec_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: can't open codec %s\n",
                                codec_dai->name);
@@ -392,10 +486,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                }
        }
 
-       if (machine->ops && machine->ops->startup) {
-               ret = machine->ops->startup(substream);
+       if (rtd->dai_link->ops && rtd->dai_link->ops->startup) {
+               ret = rtd->dai_link->ops->startup(substream);
                if (ret < 0) {
-                       printk(KERN_ERR "asoc: %s startup failed\n", machine->name);
+                       printk(KERN_ERR "asoc: %s startup failed\n", rtd->dai_link->name);
                        goto machine_err;
                }
        }
@@ -403,50 +497,50 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
        /* Check that the codec and cpu DAI's are compatible */
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                runtime->hw.rate_min =
-                       max(codec_dai->playback.rate_min,
-                           cpu_dai->playback.rate_min);
+                       max(codec_dai_drv->playback.rate_min,
+                           cpu_dai_drv->playback.rate_min);
                runtime->hw.rate_max =
-                       min(codec_dai->playback.rate_max,
-                           cpu_dai->playback.rate_max);
+                       min(codec_dai_drv->playback.rate_max,
+                           cpu_dai_drv->playback.rate_max);
                runtime->hw.channels_min =
-                       max(codec_dai->playback.channels_min,
-                               cpu_dai->playback.channels_min);
+                       max(codec_dai_drv->playback.channels_min,
+                               cpu_dai_drv->playback.channels_min);
                runtime->hw.channels_max =
-                       min(codec_dai->playback.channels_max,
-                               cpu_dai->playback.channels_max);
+                       min(codec_dai_drv->playback.channels_max,
+                               cpu_dai_drv->playback.channels_max);
                runtime->hw.formats =
-                       codec_dai->playback.formats & cpu_dai->playback.formats;
+                       codec_dai_drv->playback.formats & cpu_dai_drv->playback.formats;
                runtime->hw.rates =
-                       codec_dai->playback.rates & cpu_dai->playback.rates;
-               if (codec_dai->playback.rates
+                       codec_dai_drv->playback.rates & cpu_dai_drv->playback.rates;
+               if (codec_dai_drv->playback.rates
                           & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
-                       runtime->hw.rates |= cpu_dai->playback.rates;
-               if (cpu_dai->playback.rates
+                       runtime->hw.rates |= cpu_dai_drv->playback.rates;
+               if (cpu_dai_drv->playback.rates
                           & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
-                       runtime->hw.rates |= codec_dai->playback.rates;
+                       runtime->hw.rates |= codec_dai_drv->playback.rates;
        } else {
                runtime->hw.rate_min =
-                       max(codec_dai->capture.rate_min,
-                           cpu_dai->capture.rate_min);
+                       max(codec_dai_drv->capture.rate_min,
+                           cpu_dai_drv->capture.rate_min);
                runtime->hw.rate_max =
-                       min(codec_dai->capture.rate_max,
-                           cpu_dai->capture.rate_max);
+                       min(codec_dai_drv->capture.rate_max,
+                           cpu_dai_drv->capture.rate_max);
                runtime->hw.channels_min =
-                       max(codec_dai->capture.channels_min,
-                               cpu_dai->capture.channels_min);
+                       max(codec_dai_drv->capture.channels_min,
+                               cpu_dai_drv->capture.channels_min);
                runtime->hw.channels_max =
-                       min(codec_dai->capture.channels_max,
-                               cpu_dai->capture.channels_max);
+                       min(codec_dai_drv->capture.channels_max,
+                               cpu_dai_drv->capture.channels_max);
                runtime->hw.formats =
-                       codec_dai->capture.formats & cpu_dai->capture.formats;
+                       codec_dai_drv->capture.formats & cpu_dai_drv->capture.formats;
                runtime->hw.rates =
-                       codec_dai->capture.rates & cpu_dai->capture.rates;
-               if (codec_dai->capture.rates
+                       codec_dai_drv->capture.rates & cpu_dai_drv->capture.rates;
+               if (codec_dai_drv->capture.rates
                           & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
-                       runtime->hw.rates |= cpu_dai->capture.rates;
-               if (cpu_dai->capture.rates
+                       runtime->hw.rates |= cpu_dai_drv->capture.rates;
+               if (cpu_dai_drv->capture.rates
                           & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
-                       runtime->hw.rates |= codec_dai->capture.rates;
+                       runtime->hw.rates |= codec_dai_drv->capture.rates;
        }
 
        snd_pcm_limit_hw_rates(runtime);
@@ -462,7 +556,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
        }
        if (!runtime->hw.channels_min || !runtime->hw.channels_max) {
                printk(KERN_ERR "asoc: %s <-> %s No matching channels\n",
-                       codec_dai->name, cpu_dai->name);
+                               codec_dai->name, cpu_dai->name);
                goto config_err;
        }
 
@@ -473,7 +567,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                        goto config_err;
        }
 
-       pr_debug("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name);
+       pr_debug("asoc: %s <-> %s info:\n",
+                       codec_dai->name, cpu_dai->name);
        pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates);
        pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min,
                 runtime->hw.channels_max);
@@ -481,33 +576,33 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                 runtime->hw.rate_max);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               cpu_dai->playback.active++;
-               codec_dai->playback.active++;
+               cpu_dai->playback_active++;
+               codec_dai->playback_active++;
        } else {
-               cpu_dai->capture.active++;
-               codec_dai->capture.active++;
+               cpu_dai->capture_active++;
+               codec_dai->capture_active++;
        }
        cpu_dai->active++;
        codec_dai->active++;
-       card->codec->active++;
+       rtd->codec->active++;
        mutex_unlock(&pcm_mutex);
        return 0;
 
 config_err:
-       if (machine->ops && machine->ops->shutdown)
-               machine->ops->shutdown(substream);
+       if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
+               rtd->dai_link->ops->shutdown(substream);
 
 machine_err:
-       if (codec_dai->ops->shutdown)
-               codec_dai->ops->shutdown(substream, codec_dai);
+       if (codec_dai->driver->ops->shutdown)
+               codec_dai->driver->ops->shutdown(substream, codec_dai);
 
 codec_dai_err:
-       if (platform->pcm_ops->close)
-               platform->pcm_ops->close(substream);
+       if (platform->driver->ops->close)
+               platform->driver->ops->close(substream);
 
 platform_err:
-       if (cpu_dai->ops->shutdown)
-               cpu_dai->ops->shutdown(substream, cpu_dai);
+       if (cpu_dai->driver->ops->shutdown)
+               cpu_dai->driver->ops->shutdown(substream, cpu_dai);
 out:
        mutex_unlock(&pcm_mutex);
        return ret;
@@ -520,29 +615,25 @@ out:
  */
 static void close_delayed_work(struct work_struct *work)
 {
-       struct snd_soc_card *card = container_of(work, struct snd_soc_card,
-                                                delayed_work.work);
-       struct snd_soc_codec *codec = card->codec;
-       struct snd_soc_dai *codec_dai;
-       int i;
+       struct snd_soc_pcm_runtime *rtd =
+                       container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
 
        mutex_lock(&pcm_mutex);
-       for (i = 0; i < codec->num_dai; i++) {
-               codec_dai = &codec->dai[i];
-
-               pr_debug("pop wq checking: %s status: %s waiting: %s\n",
-                        codec_dai->playback.stream_name,
-                        codec_dai->playback.active ? "active" : "inactive",
-                        codec_dai->pop_wait ? "yes" : "no");
-
-               /* are we waiting on this codec DAI stream */
-               if (codec_dai->pop_wait == 1) {
-                       codec_dai->pop_wait = 0;
-                       snd_soc_dapm_stream_event(codec,
-                               codec_dai->playback.stream_name,
-                               SND_SOC_DAPM_STREAM_STOP);
-               }
+
+       pr_debug("pop wq checking: %s status: %s waiting: %s\n",
+                codec_dai->driver->playback.stream_name,
+                codec_dai->playback_active ? "active" : "inactive",
+                codec_dai->pop_wait ? "yes" : "no");
+
+       /* are we waiting on this codec DAI stream */
+       if (codec_dai->pop_wait == 1) {
+               codec_dai->pop_wait = 0;
+               snd_soc_dapm_stream_event(rtd,
+                       codec_dai->driver->playback.stream_name,
+                       SND_SOC_DAPM_STREAM_STOP);
        }
+
        mutex_unlock(&pcm_mutex);
 }
 
@@ -554,22 +645,19 @@ static void close_delayed_work(struct work_struct *work)
 static int soc_codec_close(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_dai_link *machine = rtd->dai;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_dai *codec_dai = machine->codec_dai;
-       struct snd_soc_codec *codec = card->codec;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = rtd->codec;
 
        mutex_lock(&pcm_mutex);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               cpu_dai->playback.active--;
-               codec_dai->playback.active--;
+               cpu_dai->playback_active--;
+               codec_dai->playback_active--;
        } else {
-               cpu_dai->capture.active--;
-               codec_dai->capture.active--;
+               cpu_dai->capture_active--;
+               codec_dai->capture_active--;
        }
 
        cpu_dai->active--;
@@ -582,27 +670,28 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                snd_soc_dai_digital_mute(codec_dai, 1);
 
-       if (cpu_dai->ops->shutdown)
-               cpu_dai->ops->shutdown(substream, cpu_dai);
+       if (cpu_dai->driver->ops->shutdown)
+               cpu_dai->driver->ops->shutdown(substream, cpu_dai);
 
-       if (codec_dai->ops->shutdown)
-               codec_dai->ops->shutdown(substream, codec_dai);
+       if (codec_dai->driver->ops->shutdown)
+               codec_dai->driver->ops->shutdown(substream, codec_dai);
 
-       if (machine->ops && machine->ops->shutdown)
-               machine->ops->shutdown(substream);
+       if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
+               rtd->dai_link->ops->shutdown(substream);
 
-       if (platform->pcm_ops->close)
-               platform->pcm_ops->close(substream);
+       if (platform->driver->ops->close)
+               platform->driver->ops->close(substream);
+       cpu_dai->runtime = NULL;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                /* start delayed pop wq here for playback streams */
                codec_dai->pop_wait = 1;
-               schedule_delayed_work(&card->delayed_work,
-                       msecs_to_jiffies(card->pmdown_time));
+               schedule_delayed_work(&rtd->delayed_work,
+                       msecs_to_jiffies(rtd->pmdown_time));
        } else {
                /* capture streams can be powered down now */
-               snd_soc_dapm_stream_event(codec,
-                       codec_dai->capture.stream_name,
+               snd_soc_dapm_stream_event(rtd,
+                       codec_dai->driver->capture.stream_name,
                        SND_SOC_DAPM_STREAM_STOP);
        }
 
@@ -618,43 +707,39 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
 static int soc_pcm_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_dai_link *machine = rtd->dai;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_dai *codec_dai = machine->codec_dai;
-       struct snd_soc_codec *codec = card->codec;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int ret = 0;
 
        mutex_lock(&pcm_mutex);
 
-       if (machine->ops && machine->ops->prepare) {
-               ret = machine->ops->prepare(substream);
+       if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) {
+               ret = rtd->dai_link->ops->prepare(substream);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: machine prepare error\n");
                        goto out;
                }
        }
 
-       if (platform->pcm_ops->prepare) {
-               ret = platform->pcm_ops->prepare(substream);
+       if (platform->driver->ops->prepare) {
+               ret = platform->driver->ops->prepare(substream);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: platform prepare error\n");
                        goto out;
                }
        }
 
-       if (codec_dai->ops->prepare) {
-               ret = codec_dai->ops->prepare(substream, codec_dai);
+       if (codec_dai->driver->ops->prepare) {
+               ret = codec_dai->driver->ops->prepare(substream, codec_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: codec DAI prepare error\n");
                        goto out;
                }
        }
 
-       if (cpu_dai->ops->prepare) {
-               ret = cpu_dai->ops->prepare(substream, cpu_dai);
+       if (cpu_dai->driver->ops->prepare) {
+               ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: cpu DAI prepare error\n");
                        goto out;
@@ -665,16 +750,16 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
            codec_dai->pop_wait) {
                codec_dai->pop_wait = 0;
-               cancel_delayed_work(&card->delayed_work);
+               cancel_delayed_work(&rtd->delayed_work);
        }
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               snd_soc_dapm_stream_event(codec,
-                                         codec_dai->playback.stream_name,
+               snd_soc_dapm_stream_event(rtd,
+                                         codec_dai->driver->playback.stream_name,
                                          SND_SOC_DAPM_STREAM_START);
        else
-               snd_soc_dapm_stream_event(codec,
-                                         codec_dai->capture.stream_name,
+               snd_soc_dapm_stream_event(rtd,
+                                         codec_dai->driver->capture.stream_name,
                                          SND_SOC_DAPM_STREAM_START);
 
        snd_soc_dai_digital_mute(codec_dai, 0);
@@ -693,26 +778,23 @@ static int soc_pcm_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_device *socdev = rtd->socdev;
-       struct snd_soc_dai_link *machine = rtd->dai;
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_dai *codec_dai = machine->codec_dai;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int ret = 0;
 
        mutex_lock(&pcm_mutex);
 
-       if (machine->ops && machine->ops->hw_params) {
-               ret = machine->ops->hw_params(substream, params);
+       if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
+               ret = rtd->dai_link->ops->hw_params(substream, params);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: machine hw_params failed\n");
                        goto out;
                }
        }
 
-       if (codec_dai->ops->hw_params) {
-               ret = codec_dai->ops->hw_params(substream, params, codec_dai);
+       if (codec_dai->driver->ops->hw_params) {
+               ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: can't set codec %s hw params\n",
                                codec_dai->name);
@@ -720,8 +802,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
                }
        }
 
-       if (cpu_dai->ops->hw_params) {
-               ret = cpu_dai->ops->hw_params(substream, params, cpu_dai);
+       if (cpu_dai->driver->ops->hw_params) {
+               ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: interface %s hw params failed\n",
                                cpu_dai->name);
@@ -729,8 +811,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
                }
        }
 
-       if (platform->pcm_ops->hw_params) {
-               ret = platform->pcm_ops->hw_params(substream, params);
+       if (platform->driver->ops->hw_params) {
+               ret = platform->driver->ops->hw_params(substream, params);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: platform %s hw params failed\n",
                                platform->name);
@@ -738,23 +820,23 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
                }
        }
 
-       machine->rate = params_rate(params);
+       rtd->rate = params_rate(params);
 
 out:
        mutex_unlock(&pcm_mutex);
        return ret;
 
 platform_err:
-       if (cpu_dai->ops->hw_free)
-               cpu_dai->ops->hw_free(substream, cpu_dai);
+       if (cpu_dai->driver->ops->hw_free)
+               cpu_dai->driver->ops->hw_free(substream, cpu_dai);
 
 interface_err:
-       if (codec_dai->ops->hw_free)
-               codec_dai->ops->hw_free(substream, codec_dai);
+       if (codec_dai->driver->ops->hw_free)
+               codec_dai->driver->ops->hw_free(substream, codec_dai);
 
 codec_err:
-       if (machine->ops && machine->ops->hw_free)
-               machine->ops->hw_free(substream);
+       if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
+               rtd->dai_link->ops->hw_free(substream);
 
        mutex_unlock(&pcm_mutex);
        return ret;
@@ -766,13 +848,10 @@ codec_err:
 static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_dai_link *machine = rtd->dai;
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_dai *codec_dai = machine->codec_dai;
-       struct snd_soc_codec *codec = card->codec;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = rtd->codec;
 
        mutex_lock(&pcm_mutex);
 
@@ -781,19 +860,19 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
                snd_soc_dai_digital_mute(codec_dai, 1);
 
        /* free any machine hw params */
-       if (machine->ops && machine->ops->hw_free)
-               machine->ops->hw_free(substream);
+       if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
+               rtd->dai_link->ops->hw_free(substream);
 
        /* free any DMA resources */
-       if (platform->pcm_ops->hw_free)
-               platform->pcm_ops->hw_free(substream);
+       if (platform->driver->ops->hw_free)
+               platform->driver->ops->hw_free(substream);
 
        /* now free hw params for the DAI's  */
-       if (codec_dai->ops->hw_free)
-               codec_dai->ops->hw_free(substream, codec_dai);
+       if (codec_dai->driver->ops->hw_free)
+               codec_dai->driver->ops->hw_free(substream, codec_dai);
 
-       if (cpu_dai->ops->hw_free)
-               cpu_dai->ops->hw_free(substream, cpu_dai);
+       if (cpu_dai->driver->ops->hw_free)
+               cpu_dai->driver->ops->hw_free(substream, cpu_dai);
 
        mutex_unlock(&pcm_mutex);
        return 0;
@@ -802,28 +881,25 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
 static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_card *card= socdev->card;
-       struct snd_soc_dai_link *machine = rtd->dai;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_dai *codec_dai = machine->codec_dai;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int ret;
 
-       if (codec_dai->ops->trigger) {
-               ret = codec_dai->ops->trigger(substream, cmd, codec_dai);
+       if (codec_dai->driver->ops->trigger) {
+               ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai);
                if (ret < 0)
                        return ret;
        }
 
-       if (platform->pcm_ops->trigger) {
-               ret = platform->pcm_ops->trigger(substream, cmd);
+       if (platform->driver->ops->trigger) {
+               ret = platform->driver->ops->trigger(substream, cmd);
                if (ret < 0)
                        return ret;
        }
 
-       if (cpu_dai->ops->trigger) {
-               ret = cpu_dai->ops->trigger(substream, cmd, cpu_dai);
+       if (cpu_dai->driver->ops->trigger) {
+               ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
                if (ret < 0)
                        return ret;
        }
@@ -838,27 +914,24 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *socdev = rtd->socdev;
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_dai_link *machine = rtd->dai;
-       struct snd_soc_dai *cpu_dai = machine->cpu_dai;
-       struct snd_soc_dai *codec_dai = machine->codec_dai;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_pcm_runtime *runtime = substream->runtime;
        snd_pcm_uframes_t offset = 0;
        snd_pcm_sframes_t delay = 0;
 
-       if (platform->pcm_ops->pointer)
-               offset = platform->pcm_ops->pointer(substream);
+       if (platform->driver->ops->pointer)
+               offset = platform->driver->ops->pointer(substream);
 
-       if (cpu_dai->ops->delay)
-               delay += cpu_dai->ops->delay(substream, cpu_dai);
+       if (cpu_dai->driver->ops->delay)
+               delay += cpu_dai->driver->ops->delay(substream, cpu_dai);
 
-       if (codec_dai->ops->delay)
-               delay += codec_dai->ops->delay(substream, codec_dai);
+       if (codec_dai->driver->ops->delay)
+               delay += codec_dai->driver->ops->delay(substream, codec_dai);
 
-       if (platform->delay)
-               delay += platform->delay(substream, codec_dai);
+       if (platform->driver->delay)
+               delay += platform->driver->delay(substream, codec_dai);
 
        runtime->delay = delay;
 
@@ -881,104 +954,111 @@ static struct snd_pcm_ops soc_pcm_ops = {
 static int soc_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
-       struct snd_soc_codec *codec = card->codec;
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
        int i;
 
        /* If the initialization of this soc device failed, there is no codec
         * associated with it. Just bail out in this case.
         */
-       if (!codec)
+       if (list_empty(&card->codec_dev_list))
                return 0;
 
        /* Due to the resume being scheduled into a workqueue we could
        * suspend before that's finished - wait for it to complete.
         */
-       snd_power_lock(codec->card);
-       snd_power_wait(codec->card, SNDRV_CTL_POWER_D0);
-       snd_power_unlock(codec->card);
+       snd_power_lock(card->snd_card);
+       snd_power_wait(card->snd_card, SNDRV_CTL_POWER_D0);
+       snd_power_unlock(card->snd_card);
 
        /* we're going to block userspace touching us until resume completes */
-       snd_power_change_state(codec->card, SNDRV_CTL_POWER_D3hot);
+       snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot);
 
        /* mute any active DAC's */
-       for (i = 0; i < card->num_links; i++) {
-               struct snd_soc_dai *dai = card->dai_link[i].codec_dai;
+       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;
 
-               if (card->dai_link[i].ignore_suspend)
+               if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
-               if (dai->ops->digital_mute && dai->playback.active)
-                       dai->ops->digital_mute(dai, 1);
+               if (drv->ops->digital_mute && dai->playback_active)
+                       drv->ops->digital_mute(dai, 1);
        }
 
        /* suspend all pcms */
-       for (i = 0; i < card->num_links; i++) {
-               if (card->dai_link[i].ignore_suspend)
+       for (i = 0; i < card->num_rtd; i++) {
+               if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
-               snd_pcm_suspend_all(card->dai_link[i].pcm);
+               snd_pcm_suspend_all(card->rtd[i].pcm);
        }
 
        if (card->suspend_pre)
                card->suspend_pre(pdev, PMSG_SUSPEND);
 
-       for (i = 0; i < card->num_links; i++) {
-               struct snd_soc_dai  *cpu_dai = card->dai_link[i].cpu_dai;
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+               struct snd_soc_platform *platform = card->rtd[i].platform;
 
-               if (card->dai_link[i].ignore_suspend)
+               if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
-               if (cpu_dai->suspend && !cpu_dai->ac97_control)
-                       cpu_dai->suspend(cpu_dai);
-               if (platform->suspend)
-                       platform->suspend(&card->dai_link[i]);
+               if (cpu_dai->driver->suspend && !cpu_dai->driver->ac97_control)
+                       cpu_dai->driver->suspend(cpu_dai);
+               if (platform->driver->suspend && !platform->suspended) {
+                       platform->driver->suspend(cpu_dai);
+                       platform->suspended = 1;
+               }
        }
 
        /* close any waiting streams and save state */
-       run_delayed_work(&card->delayed_work);
-       codec->suspend_bias_level = codec->bias_level;
+       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;
+       }
 
-       for (i = 0; i < codec->num_dai; i++) {
-               char *stream = codec->dai[i].playback.stream_name;
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver;
 
-               if (card->dai_link[i].ignore_suspend)
+               if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
-               if (stream != NULL)
-                       snd_soc_dapm_stream_event(codec, stream,
+               if (driver->playback.stream_name != NULL)
+                       snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name,
                                SND_SOC_DAPM_STREAM_SUSPEND);
-               stream = codec->dai[i].capture.stream_name;
-               if (stream != NULL)
-                       snd_soc_dapm_stream_event(codec, stream,
+
+               if (driver->capture.stream_name != NULL)
+                       snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name,
                                SND_SOC_DAPM_STREAM_SUSPEND);
        }
 
-       /* If there are paths active then the CODEC will be held with
-        * bias _ON and should not be suspended. */
-       if (codec_dev->suspend) {
-               switch (codec->bias_level) {
-               case SND_SOC_BIAS_STANDBY:
-               case SND_SOC_BIAS_OFF:
-                       codec_dev->suspend(pdev, PMSG_SUSPEND);
-                       break;
-               default:
-                       dev_dbg(socdev->dev, "CODEC is on over suspend\n");
-                       break;
+       /* suspend all CODECs */
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_codec *codec = card->rtd[i].codec;
+               /* 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) {
+                       case SND_SOC_BIAS_STANDBY:
+                       case SND_SOC_BIAS_OFF:
+                               codec->driver->suspend(codec, PMSG_SUSPEND);
+                               codec->suspended = 1;
+                               break;
+                       default:
+                               dev_dbg(codec->dev, "CODEC is on over suspend\n");
+                               break;
+                       }
                }
        }
 
-       for (i = 0; i < card->num_links; i++) {
-               struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
 
-               if (card->dai_link[i].ignore_suspend)
+               if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
-               if (cpu_dai->suspend && cpu_dai->ac97_control)
-                       cpu_dai->suspend(cpu_dai);
+               if (cpu_dai->driver->suspend && cpu_dai->driver->ac97_control)
+                       cpu_dai->driver->suspend(cpu_dai);
        }
 
        if (card->suspend_post)
@@ -992,127 +1072,127 @@ static int soc_suspend(struct device *dev)
  */
 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 snd_soc_device *socdev = card->socdev;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
-       struct snd_soc_codec *codec = card->codec;
-       struct platform_device *pdev = to_platform_device(socdev->dev);
+       struct snd_soc_card *card =
+                       container_of(work, struct snd_soc_card, deferred_resume_work);
+       struct platform_device *pdev = to_platform_device(card->dev);
        int i;
 
        /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
         * so userspace apps are blocked from touching us
         */
 
-       dev_dbg(socdev->dev, "starting resume work\n");
+       dev_dbg(card->dev, "starting resume work\n");
 
        /* Bring us up into D2 so that DAPM starts enabling things */
-       snd_power_change_state(codec->card, SNDRV_CTL_POWER_D2);
+       snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D2);
 
        if (card->resume_pre)
                card->resume_pre(pdev);
 
-       for (i = 0; i < card->num_links; i++) {
-               struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
+       /* resume AC97 DAIs */
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
 
-               if (card->dai_link[i].ignore_suspend)
+               if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
-               if (cpu_dai->resume && cpu_dai->ac97_control)
-                       cpu_dai->resume(cpu_dai);
-       }
-
-       /* 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_dev->resume) {
-               switch (codec->bias_level) {
-               case SND_SOC_BIAS_STANDBY:
-               case SND_SOC_BIAS_OFF:
-                       codec_dev->resume(pdev);
-                       break;
-               default:
-                       dev_dbg(socdev->dev, "CODEC was on over suspend\n");
-                       break;
+               if (cpu_dai->driver->resume && cpu_dai->driver->ac97_control)
+                       cpu_dai->driver->resume(cpu_dai);
+       }
+
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_codec *codec = card->rtd[i].codec;
+               /* 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) {
+                       case SND_SOC_BIAS_STANDBY:
+                       case SND_SOC_BIAS_OFF:
+                               codec->driver->resume(codec);
+                               codec->suspended = 0;
+                               break;
+                       default:
+                               dev_dbg(codec->dev, "CODEC was on over suspend\n");
+                               break;
+                       }
                }
        }
 
-       for (i = 0; i < codec->num_dai; i++) {
-               char *stream = codec->dai[i].playback.stream_name;
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver;
 
-               if (card->dai_link[i].ignore_suspend)
+               if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
-               if (stream != NULL)
-                       snd_soc_dapm_stream_event(codec, stream,
+               if (driver->playback.stream_name != NULL)
+                       snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name,
                                SND_SOC_DAPM_STREAM_RESUME);
-               stream = codec->dai[i].capture.stream_name;
-               if (stream != NULL)
-                       snd_soc_dapm_stream_event(codec, stream,
+
+               if (driver->capture.stream_name != NULL)
+                       snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name,
                                SND_SOC_DAPM_STREAM_RESUME);
        }
 
        /* unmute any active DACs */
-       for (i = 0; i < card->num_links; i++) {
-               struct snd_soc_dai *dai = card->dai_link[i].codec_dai;
+       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;
 
-               if (card->dai_link[i].ignore_suspend)
+               if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
-               if (dai->ops->digital_mute && dai->playback.active)
-                       dai->ops->digital_mute(dai, 0);
+               if (drv->ops->digital_mute && dai->playback_active)
+                       drv->ops->digital_mute(dai, 0);
        }
 
-       for (i = 0; i < card->num_links; i++) {
-               struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+               struct snd_soc_platform *platform = card->rtd[i].platform;
 
-               if (card->dai_link[i].ignore_suspend)
+               if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
 
-               if (cpu_dai->resume && !cpu_dai->ac97_control)
-                       cpu_dai->resume(cpu_dai);
-               if (platform->resume)
-                       platform->resume(&card->dai_link[i]);
+               if (cpu_dai->driver->resume && !cpu_dai->driver->ac97_control)
+                       cpu_dai->driver->resume(cpu_dai);
+               if (platform->driver->resume && platform->suspended) {
+                       platform->driver->resume(cpu_dai);
+                       platform->suspended = 0;
+               }
        }
 
        if (card->resume_post)
                card->resume_post(pdev);
 
-       dev_dbg(socdev->dev, "resume work completed\n");
+       dev_dbg(card->dev, "resume work completed\n");
 
        /* userspace can access us now we are back as we were before */
-       snd_power_change_state(codec->card, SNDRV_CTL_POWER_D0);
+       snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0);
 }
 
 /* powers up audio subsystem after a suspend */
 static int soc_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_dai *cpu_dai = card->dai_link[0].cpu_dai;
-
-       /* If the initialization of this soc device failed, there is no codec
-        * associated with it. Just bail out in this case.
-        */
-       if (!card->codec)
-               return 0;
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       int i;
 
        /* AC97 devices might have other drivers hanging off them so
         * need to resume immediately.  Other drivers don't have that
         * problem and may take a substantial amount of time to resume
         * due to I/O costs and anti-pop so handle them out of line.
         */
-       if (cpu_dai->ac97_control) {
-               dev_dbg(socdev->dev, "Resuming AC97 immediately\n");
-               soc_resume_deferred(&card->deferred_resume_work);
-       } else {
-               dev_dbg(socdev->dev, "Scheduling resume work\n");
-               if (!schedule_work(&card->deferred_resume_work))
-                       dev_err(socdev->dev, "resume work item may be lost\n");
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+               if (cpu_dai->driver->ac97_control) {
+                       dev_dbg(dev, "Resuming AC97 immediately\n");
+                       soc_resume_deferred(&card->deferred_resume_work);
+               } else {
+                       dev_dbg(dev, "Scheduling resume work\n");
+                       if (!schedule_work(&card->deferred_resume_work))
+                               dev_err(dev, "resume work item may be lost\n");
+               }
        }
 
        return 0;
@@ -1125,198 +1205,440 @@ static int soc_resume(struct device *dev)
 static struct snd_soc_dai_ops null_dai_ops = {
 };
 
-static void snd_soc_instantiate_card(struct snd_soc_card *card)
+static int soc_bind_dai_link(struct snd_soc_card *card, int num)
 {
-       struct platform_device *pdev = container_of(card->dev,
-                                                   struct platform_device,
-                                                   dev);
-       struct snd_soc_codec_device *codec_dev = card->socdev->codec_dev;
+       struct snd_soc_dai_link *dai_link = &card->dai_link[num];
+       struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
        struct snd_soc_codec *codec;
        struct snd_soc_platform *platform;
-       struct snd_soc_dai *dai;
-       int i, found, ret, ac97;
+       struct snd_soc_dai *codec_dai, *cpu_dai;
 
-       if (card->instantiated)
-               return;
+       if (rtd->complete)
+               return 1;
+       dev_dbg(card->dev, "binding %s at idx %d\n", dai_link->name, num);
 
-       found = 0;
-       list_for_each_entry(platform, &platform_list, list)
-               if (card->platform == platform) {
-                       found = 1;
-                       break;
+       /* do we already have the CPU DAI for this link ? */
+       if (rtd->cpu_dai) {
+               goto find_codec;
+       }
+       /* no, then find CPU DAI from registered DAIs*/
+       list_for_each_entry(cpu_dai, &dai_list, list) {
+               if (!strcmp(cpu_dai->name, dai_link->cpu_dai_name)) {
+
+                       if (!try_module_get(cpu_dai->dev->driver->owner))
+                               return -ENODEV;
+
+                       rtd->cpu_dai = cpu_dai;
+                       goto find_codec;
                }
-       if (!found) {
-               dev_dbg(card->dev, "Platform %s not registered\n",
-                       card->platform->name);
-               return;
        }
+       dev_dbg(card->dev, "CPU DAI %s not registered\n",
+                       dai_link->cpu_dai_name);
 
-       ac97 = 0;
-       for (i = 0; i < card->num_links; i++) {
-               found = 0;
-               list_for_each_entry(dai, &dai_list, list)
-                       if (card->dai_link[i].cpu_dai == dai) {
-                               found = 1;
-                               break;
+find_codec:
+       /* do we already have the CODEC for this link ? */
+       if (rtd->codec) {
+               goto find_platform;
+       }
+
+       /* no, then find CODEC from registered CODECs*/
+       list_for_each_entry(codec, &codec_list, list) {
+               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 &&
+                                               !strcmp(codec_dai->name, dai_link->codec_dai_name)) {
+                                       rtd->codec_dai = codec_dai;
+                                       goto find_platform;
+                               }
                        }
-               if (!found) {
-                       dev_dbg(card->dev, "DAI %s not registered\n",
-                               card->dai_link[i].cpu_dai->name);
-                       return;
+                       dev_dbg(card->dev, "CODEC DAI %s not registered\n",
+                                       dai_link->codec_dai_name);
+
+                       goto find_platform;
                }
+       }
+       dev_dbg(card->dev, "CODEC %s not registered\n",
+                       dai_link->codec_name);
 
-               if (card->dai_link[i].cpu_dai->ac97_control)
-                       ac97 = 1;
+find_platform:
+       /* do we already have the CODEC DAI for this link ? */
+       if (rtd->platform) {
+               goto out;
        }
+       /* no, then find CPU DAI from registered DAIs*/
+       list_for_each_entry(platform, &platform_list, list) {
+               if (!strcmp(platform->name, dai_link->platform_name)) {
 
-       for (i = 0; i < card->num_links; i++) {
-               if (!card->dai_link[i].codec_dai->ops)
-                       card->dai_link[i].codec_dai->ops = &null_dai_ops;
+                       if (!try_module_get(platform->dev->driver->owner))
+                               return -ENODEV;
+
+                       rtd->platform = platform;
+                       goto out;
+               }
        }
 
-       /* If we have AC97 in the system then don't wait for the
-        * codec.  This will need revisiting if we have to handle
-        * systems with mixed AC97 and non-AC97 parts.  Only check for
-        * DAIs currently; we can't do this per link since some AC97
-        * codecs have non-AC97 DAIs.
-        */
-       if (!ac97)
-               for (i = 0; i < card->num_links; i++) {
-                       found = 0;
-                       list_for_each_entry(dai, &dai_list, list)
-                               if (card->dai_link[i].codec_dai == dai) {
-                                       found = 1;
-                                       break;
-                               }
-                       if (!found) {
-                               dev_dbg(card->dev, "DAI %s not registered\n",
-                                       card->dai_link[i].codec_dai->name);
-                               return;
-                       }
+       dev_dbg(card->dev, "platform %s not registered\n",
+                       dai_link->platform_name);
+       return 0;
+
+out:
+       /* mark rtd as complete if we found all 4 of our client devices */
+       if (rtd->codec && rtd->codec_dai && rtd->platform && rtd->cpu_dai) {
+               rtd->complete = 1;
+               card->num_rtd++;
+       }
+       return 1;
+}
+
+static void soc_remove_dai_link(struct snd_soc_card *card, int num)
+{
+       struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
+       int err;
+
+       /* unregister the rtd device */
+       if (rtd->dev_registered) {
+               device_remove_file(&rtd->dev, &dev_attr_pmdown_time);
+               device_unregister(&rtd->dev);
+               rtd->dev_registered = 0;
+       }
+
+       /* remove the CODEC DAI */
+       if (codec_dai && codec_dai->probed) {
+               if (codec_dai->driver->remove) {
+                       err = codec_dai->driver->remove(codec_dai);
+                       if (err < 0)
+                               printk(KERN_ERR "asoc: failed to remove %s\n", codec_dai->name);
                }
+               codec_dai->probed = 0;
+               list_del(&codec_dai->card_list);
+       }
 
-       /* Note that we do not current check for codec components */
+       /* remove the platform */
+       if (platform && platform->probed) {
+               if (platform->driver->remove) {
+                       err = platform->driver->remove(platform);
+                       if (err < 0)
+                               printk(KERN_ERR "asoc: failed to remove %s\n", platform->name);
+               }
+               platform->probed = 0;
+               list_del(&platform->card_list);
+               module_put(platform->dev->driver->owner);
+       }
 
-       dev_dbg(card->dev, "All components present, instantiating\n");
+       /* 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);
+               }
 
-       /* Found everything, bring it up */
-       card->pmdown_time = pmdown_time;
+               /* Make sure all DAPM widgets are freed */
+               snd_soc_dapm_free(codec);
 
-       if (card->probe) {
-               ret = card->probe(pdev);
-               if (ret < 0)
-                       return;
+               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);
        }
 
-       for (i = 0; i < card->num_links; i++) {
-               struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
-               if (cpu_dai->probe) {
-                       ret = cpu_dai->probe(pdev, cpu_dai);
-                       if (ret < 0)
-                               goto cpu_dai_err;
+       /* remove the cpu_dai */
+       if (cpu_dai && cpu_dai->probed) {
+               if (cpu_dai->driver->remove) {
+                       err = cpu_dai->driver->remove(cpu_dai);
+                       if (err < 0)
+                               printk(KERN_ERR "asoc: failed to remove %s\n", cpu_dai->name);
                }
+               cpu_dai->probed = 0;
+               list_del(&cpu_dai->card_list);
+               module_put(cpu_dai->dev->driver->owner);
        }
+}
 
-       if (codec_dev->probe) {
-               ret = codec_dev->probe(pdev);
-               if (ret < 0)
-                       goto cpu_dai_err;
+static void rtd_release(struct device *dev) {}
+
+static int soc_probe_dai_link(struct snd_soc_card *card, int num)
+{
+       struct snd_soc_dai_link *dai_link = &card->dai_link[num];
+       struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
+       int ret;
+
+       dev_dbg(card->dev, "probe %s dai link %d\n", card->name, 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;
+
+       /* set default power off timeout */
+       rtd->pmdown_time = pmdown_time;
+
+       /* probe the cpu_dai */
+       if (!cpu_dai->probed) {
+               if (cpu_dai->driver->probe) {
+                       ret = cpu_dai->driver->probe(cpu_dai);
+                       if (ret < 0) {
+                               printk(KERN_ERR "asoc: failed to probe CPU DAI %s\n",
+                                               cpu_dai->name);
+                               return ret;
+                       }
+               }
+               cpu_dai->probed = 1;
+               /* mark cpu_dai as probed and add to card cpu_dai list */
+               list_add(&cpu_dai->card_list, &card->dai_dev_list);
        }
-       codec = card->codec;
 
-       if (platform->probe) {
-               ret = platform->probe(pdev);
-               if (ret < 0)
-                       goto platform_err;
+       /* 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);
        }
 
-       /* DAPM stream work */
-       INIT_DELAYED_WORK(&card->delayed_work, close_delayed_work);
-#ifdef CONFIG_PM
-       /* deferred resume work */
-       INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
-#endif
+       /* probe the platform */
+       if (!platform->probed) {
+               if (platform->driver->probe) {
+                       ret = platform->driver->probe(platform);
+                       if (ret < 0) {
+                               printk(KERN_ERR "asoc: failed to probe platform %s\n",
+                                               platform->name);
+                               return ret;
+                       }
+               }
+               /* mark platform as probed and add to card platform list */
+               platform->probed = 1;
+               list_add(&platform->card_list, &card->platform_dev_list);
+       }
 
-       for (i = 0; i < card->num_links; i++) {
-               if (card->dai_link[i].init) {
-                       ret = card->dai_link[i].init(codec);
+       /* probe the CODEC DAI */
+       if (!codec_dai->probed) {
+               if (codec_dai->driver->probe) {
+                       ret = codec_dai->driver->probe(codec_dai);
                        if (ret < 0) {
-                               printk(KERN_ERR "asoc: failed to init %s\n",
-                                       card->dai_link[i].stream_name);
-                               continue;
+                               printk(KERN_ERR "asoc: failed to probe CODEC DAI %s\n",
+                                               codec_dai->name);
+                               return ret;
                        }
                }
-               if (card->dai_link[i].codec_dai->ac97_control)
-                       ac97 = 1;
+
+               /* mark cpu_dai as probed and add to card cpu_dai list */
+               codec_dai->probed = 1;
+               list_add(&codec_dai->card_list, &card->dai_dev_list);
        }
 
-       snprintf(codec->card->shortname, sizeof(codec->card->shortname),
-                "%s",  card->name);
-       snprintf(codec->card->longname, sizeof(codec->card->longname),
-                "%s (%s)", card->name, codec->name);
+       /* 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);
 
-       ret = snd_card_register(codec->card);
+       /* 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 soundcard for %s\n",
-                               codec->name);
-               goto card_err;
+               printk(KERN_ERR "asoc: failed to register DAI runtime device %d\n", ret);
+               return ret;
        }
 
-       mutex_lock(&codec->mutex);
+       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) {
+               printk(KERN_ERR "asoc: can't create pcm %s\n", dai_link->stream_name);
+               return ret;
+       }
+
+       /* add platform data for AC97 devices */
+       if (rtd->codec_dai->driver->ac97_control)
+               snd_ac97_dev_add_pdata(codec->ac97, rtd->cpu_dai->ac97_pdata);
+
+       return 0;
+}
+
 #ifdef CONFIG_SND_SOC_AC97_BUS
+static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
+{
+       int ret;
+
        /* Only instantiate AC97 if not already done by the adaptor
         * for the generic AC97 subsystem.
         */
-       if (ac97 && strcmp(codec->name, "AC97") != 0) {
-               ret = soc_ac97_dev_register(codec);
+       if (rtd->codec_dai->driver->ac97_control && !rtd->codec->ac97_registered) {
+               /*
+                * It is possible that the AC97 device is already registered to
+                * the device subsystem. This happens when the device is created
+                * via snd_ac97_mixer(). Currently only SoC codec that does so
+                * is the generic AC97 glue but others migh emerge.
+                *
+                * In those cases we don't try to register the device again.
+                */
+               if (!rtd->codec->ac97_created)
+                       return 0;
+
+               ret = soc_ac97_dev_register(rtd->codec);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: AC97 device register failed\n");
-                       snd_card_free(codec->card);
-                       mutex_unlock(&codec->mutex);
-                       goto card_err;
+                       return ret;
                }
+
+               rtd->codec->ac97_registered = 1;
+       }
+       return 0;
+}
+
+static void soc_unregister_ac97_dai_link(struct snd_soc_codec *codec)
+{
+       if (codec->ac97_registered) {
+               soc_ac97_dev_unregister(codec);
+               codec->ac97_registered = 0;
        }
+}
 #endif
 
-       ret = snd_soc_dapm_sys_add(card->socdev->dev);
-       if (ret < 0)
-               printk(KERN_WARNING "asoc: failed to add dapm sysfs entries\n");
+static void snd_soc_instantiate_card(struct snd_soc_card *card)
+{
+       struct platform_device *pdev = to_platform_device(card->dev);
+       int ret, i;
 
-       ret = device_create_file(card->socdev->dev, &dev_attr_pmdown_time);
-       if (ret < 0)
-               printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs\n");
+       mutex_lock(&card->mutex);
 
-       ret = device_create_file(card->socdev->dev, &dev_attr_codec_reg);
-       if (ret < 0)
-               printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
+       if (card->instantiated) {
+               mutex_unlock(&card->mutex);
+               return;
+       }
 
-       soc_init_codec_debugfs(codec);
-       mutex_unlock(&codec->mutex);
+       /* bind DAIs */
+       for (i = 0; i < card->num_links; i++)
+               soc_bind_dai_link(card, i);
 
-       card->instantiated = 1;
+       /* bind completed ? */
+       if (card->num_rtd != card->num_links) {
+               mutex_unlock(&card->mutex);
+               return;
+       }
 
-       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);
+       if (ret < 0) {
+               printk(KERN_ERR "asoc: can't create sound card for card %s\n",
+                       card->name);
+               mutex_unlock(&card->mutex);
+               return;
+       }
+       card->snd_card->dev = card->dev;
 
-card_err:
-       if (platform->remove)
-               platform->remove(pdev);
+#ifdef CONFIG_PM
+       /* deferred resume work */
+       INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
+#endif
 
-platform_err:
-       if (codec_dev->remove)
-               codec_dev->remove(pdev);
+       /* initialise the sound card only once */
+       if (card->probe) {
+               ret = card->probe(pdev);
+               if (ret < 0)
+                       goto card_probe_error;
+       }
 
-cpu_dai_err:
-       for (i--; i >= 0; i--) {
-               struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
-               if (cpu_dai->remove)
-                       cpu_dai->remove(pdev, cpu_dai);
+       for (i = 0; i < card->num_links; i++) {
+               ret = soc_probe_dai_link(card, i);
+               if (ret < 0) {
+                       pr_err("asoc: failed to instantiate card %s: %d\n",
+                              card->name, ret);
+                       goto probe_dai_err;
+               }
        }
 
+       snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
+                "%s",  card->name);
+       snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
+                "%s", card->name);
+
+       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;
+       }
+
+#ifdef CONFIG_SND_SOC_AC97_BUS
+       /* register any AC97 codecs */
+       for (i = 0; i < card->num_rtd; i++) {
+                       ret = soc_register_ac97_dai_link(&card->rtd[i]);
+                       if (ret < 0) {
+                               printk(KERN_ERR "asoc: failed to register AC97 %s\n", card->name);
+                               goto probe_dai_err;
+                       }
+               }
+#endif
+
+       card->instantiated = 1;
+       mutex_unlock(&card->mutex);
+       return;
+
+probe_dai_err:
+       for (i = 0; i < card->num_links; i++)
+               soc_remove_dai_link(card, i);
+
+card_probe_error:
        if (card->remove)
                card->remove(pdev);
+
+       snd_card_free(card->snd_card);
+
+       mutex_unlock(&card->mutex);
 }
 
 /*
@@ -1333,15 +1655,15 @@ static void snd_soc_instantiate_cards(void)
 /* probes a new socdev */
 static int soc_probe(struct platform_device *pdev)
 {
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
        int ret = 0;
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_card *card = socdev->card;
-
-       /* Bodge while we push things out of socdev */
-       card->socdev = socdev;
 
        /* Bodge while we unpick instantiation */
        card->dev = &pdev->dev;
+       INIT_LIST_HEAD(&card->dai_dev_list);
+       INIT_LIST_HEAD(&card->codec_dev_list);
+       INIT_LIST_HEAD(&card->platform_dev_list);
+
        ret = snd_soc_register_card(card);
        if (ret != 0) {
                dev_err(&pdev->dev, "Failed to register card\n");
@@ -1354,50 +1676,49 @@ static int soc_probe(struct platform_device *pdev)
 /* removes a socdev */
 static int soc_remove(struct platform_device *pdev)
 {
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
        int i;
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
 
-       if (card->instantiated) {
-               run_delayed_work(&card->delayed_work);
-
-               if (platform->remove)
-                       platform->remove(pdev);
+               if (card->instantiated) {
 
-               if (codec_dev->remove)
-                       codec_dev->remove(pdev);
-
-               for (i = 0; i < card->num_links; i++) {
-                       struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
-                       if (cpu_dai->remove)
-                               cpu_dai->remove(pdev, cpu_dai);
+               /* 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);
                }
 
+               /* remove and free each DAI */
+               for (i = 0; i < card->num_rtd; i++)
+                       soc_remove_dai_link(card, i);
+
+               /* remove the card */
                if (card->remove)
                        card->remove(pdev);
-       }
 
+               kfree(card->rtd);
+               snd_card_free(card->snd_card);
+       }
        snd_soc_unregister_card(card);
-
        return 0;
 }
 
 static int soc_poweroff(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_card *card = socdev->card;
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       int i;
 
        if (!card->instantiated)
                return 0;
 
        /* Flush out pmdown_time work - we actually do want to run it
         * now, we're shutting down so no imminent restart. */
-       run_delayed_work(&card->delayed_work);
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+               run_delayed_work(&rtd->delayed_work);
+       }
 
-       snd_soc_dapm_shutdown(socdev);
+       snd_soc_dapm_shutdown(card);
 
        return 0;
 }
@@ -1420,53 +1741,42 @@ static struct platform_driver soc_driver = {
 };
 
 /* create a new pcm */
-static int soc_new_pcm(struct snd_soc_device *socdev,
-       struct snd_soc_dai_link *dai_link, int num)
-{
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_codec *codec = card->codec;
-       struct snd_soc_platform *platform = card->platform;
-       struct snd_soc_dai *codec_dai = dai_link->codec_dai;
-       struct snd_soc_dai *cpu_dai = dai_link->cpu_dai;
-       struct snd_soc_pcm_runtime *rtd;
+static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_pcm *pcm;
        char new_name[64];
        int ret = 0, playback = 0, capture = 0;
 
-       rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL);
-       if (rtd == NULL)
-               return -ENOMEM;
-
-       rtd->dai = dai_link;
-       rtd->socdev = socdev;
-       codec_dai->codec = card->codec;
-
        /* check client and interface hw capabilities */
        snprintf(new_name, sizeof(new_name), "%s %s-%d",
-                dai_link->stream_name, codec_dai->name, num);
+                       rtd->dai_link->stream_name, codec_dai->name, num);
 
-       if (codec_dai->playback.channels_min)
+       if (codec_dai->driver->playback.channels_min)
                playback = 1;
-       if (codec_dai->capture.channels_min)
+       if (codec_dai->driver->capture.channels_min)
                capture = 1;
 
-       ret = snd_pcm_new(codec->card, new_name, codec->pcm_devs++, playback,
-               capture, &pcm);
+       dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num,new_name);
+       ret = snd_pcm_new(rtd->card->snd_card, new_name,
+                       num, playback, capture, &pcm);
        if (ret < 0) {
-               printk(KERN_ERR "asoc: can't create pcm for codec %s\n",
-                       codec->name);
-               kfree(rtd);
+               printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name);
                return ret;
        }
 
-       dai_link->pcm = pcm;
+       rtd->pcm = pcm;
        pcm->private_data = rtd;
-       soc_pcm_ops.mmap = platform->pcm_ops->mmap;
-       soc_pcm_ops.ioctl = platform->pcm_ops->ioctl;
-       soc_pcm_ops.copy = platform->pcm_ops->copy;
-       soc_pcm_ops.silence = platform->pcm_ops->silence;
-       soc_pcm_ops.ack = platform->pcm_ops->ack;
-       soc_pcm_ops.page = platform->pcm_ops->page;
+       soc_pcm_ops.mmap = platform->driver->ops->mmap;
+       soc_pcm_ops.pointer = platform->driver->ops->pointer;
+       soc_pcm_ops.ioctl = platform->driver->ops->ioctl;
+       soc_pcm_ops.copy = platform->driver->ops->copy;
+       soc_pcm_ops.silence = platform->driver->ops->silence;
+       soc_pcm_ops.ack = platform->driver->ops->ack;
+       soc_pcm_ops.page = platform->driver->ops->page;
 
        if (playback)
                snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);
@@ -1474,14 +1784,13 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
        if (capture)
                snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops);
 
-       ret = platform->pcm_new(codec->card, codec_dai, pcm);
+       ret = platform->driver->pcm_new(rtd->card->snd_card, codec_dai, pcm);
        if (ret < 0) {
                printk(KERN_ERR "asoc: platform pcm constructor failed\n");
-               kfree(rtd);
                return ret;
        }
 
-       pcm->private_free = platform->pcm_free;
+       pcm->private_free = platform->driver->pcm_free;
        printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name,
                cpu_dai->name);
        return ret;
@@ -1497,8 +1806,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
  */
 int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg)
 {
-       if (codec->volatile_register)
-               return codec->volatile_register(reg);
+       if (codec->driver->volatile_register)
+               return codec->driver->volatile_register(reg);
        else
                return 0;
 }
@@ -1533,7 +1842,13 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
 
        codec->ac97->bus->ops = ops;
        codec->ac97->num = num;
-       codec->dev = &codec->ac97->dev;
+
+       /*
+        * Mark the AC97 device to be created by us. This way we ensure that the
+        * device will be registered with the device subsystem later on.
+        */
+       codec->ac97_created = 1;
+
        mutex_unlock(&codec->mutex);
        return 0;
 }
@@ -1548,9 +1863,13 @@ EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
 void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)
 {
        mutex_lock(&codec->mutex);
+#ifdef CONFIG_SND_SOC_AC97_BUS
+       soc_unregister_ac97_dai_link(codec);
+#endif
        kfree(codec->ac97->bus);
        kfree(codec->ac97);
        codec->ac97 = NULL;
+       codec->ac97_created = 0;
        mutex_unlock(&codec->mutex);
 }
 EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
@@ -1633,95 +1952,6 @@ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
 }
 EXPORT_SYMBOL_GPL(snd_soc_test_bits);
 
-/**
- * snd_soc_new_pcms - create new sound card and pcms
- * @socdev: the SoC audio device
- * @idx: ALSA card index
- * @xid: card identification
- *
- * Create a new sound card based upon the codec and interface pcms.
- *
- * Returns 0 for success, else error.
- */
-int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid)
-{
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_codec *codec = card->codec;
-       int ret, i;
-
-       mutex_lock(&codec->mutex);
-
-       /* register a sound card */
-       ret = snd_card_create(idx, xid, codec->owner, 0, &codec->card);
-       if (ret < 0) {
-               printk(KERN_ERR "asoc: can't create sound card for codec %s\n",
-                       codec->name);
-               mutex_unlock(&codec->mutex);
-               return ret;
-       }
-
-       codec->socdev = socdev;
-       codec->card->dev = socdev->dev;
-       codec->card->private_data = codec;
-       strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver));
-
-       /* create the pcms */
-       for (i = 0; i < card->num_links; i++) {
-               ret = soc_new_pcm(socdev, &card->dai_link[i], i);
-               if (ret < 0) {
-                       printk(KERN_ERR "asoc: can't create pcm %s\n",
-                               card->dai_link[i].stream_name);
-                       mutex_unlock(&codec->mutex);
-                       return ret;
-               }
-               /* Check for codec->ac97 to handle the ac97.c fun */
-               if (card->dai_link[i].codec_dai->ac97_control && codec->ac97) {
-                       snd_ac97_dev_add_pdata(codec->ac97,
-                               card->dai_link[i].cpu_dai->ac97_pdata);
-               }
-       }
-
-       mutex_unlock(&codec->mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_new_pcms);
-
-/**
- * snd_soc_free_pcms - free sound card and pcms
- * @socdev: the SoC audio device
- *
- * Frees sound card and pcms associated with the socdev.
- * Also unregister the codec if it is an AC97 device.
- */
-void snd_soc_free_pcms(struct snd_soc_device *socdev)
-{
-       struct snd_soc_codec *codec = socdev->card->codec;
-#ifdef CONFIG_SND_SOC_AC97_BUS
-       struct snd_soc_dai *codec_dai;
-       int i;
-#endif
-
-       mutex_lock(&codec->mutex);
-       soc_cleanup_codec_debugfs(codec);
-#ifdef CONFIG_SND_SOC_AC97_BUS
-       for (i = 0; i < codec->num_dai; i++) {
-               codec_dai = &codec->dai[i];
-               if (codec_dai->ac97_control && codec->ac97 &&
-                   strcmp(codec->name, "AC97") != 0) {
-                       soc_ac97_dev_unregister(codec);
-                       goto free_card;
-               }
-       }
-free_card:
-#endif
-
-       if (codec->card)
-               snd_card_free(codec->card);
-       device_remove_file(socdev->dev, &dev_attr_codec_reg);
-       mutex_unlock(&codec->mutex);
-}
-EXPORT_SYMBOL_GPL(snd_soc_free_pcms);
-
 /**
  * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
  * @substream: the pcm substream
@@ -1783,15 +2013,15 @@ EXPORT_SYMBOL_GPL(snd_soc_cnew);
 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;
+       struct snd_card *card = codec->card->snd_card;
        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 (err < 0) {
-                       dev_err(codec->dev, "%s: Failed to add %s\n",
-                               codec->name, control->name);
+                       dev_err(codec->dev, "%s: Failed to add %s: %d\n",
+                               codec->name, control->name, err);
                        return err;
                }
        }
@@ -2338,7 +2568,7 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8);
 int snd_soc_limit_volume(struct snd_soc_codec *codec,
        const char *name, int max)
 {
-       struct snd_card *card = codec->card;
+       struct snd_card *card = codec->card->snd_card;
        struct snd_kcontrol *kctl;
        struct soc_mixer_control *mc;
        int found = 0;
@@ -2470,8 +2700,8 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx);
 int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
        unsigned int freq, int dir)
 {
-       if (dai->ops && dai->ops->set_sysclk)
-               return dai->ops->set_sysclk(dai, clk_id, freq, dir);
+       if (dai->driver && dai->driver->ops->set_sysclk)
+               return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
        else
                return -EINVAL;
 }
@@ -2490,8 +2720,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
 int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
        int div_id, int div)
 {
-       if (dai->ops && dai->ops->set_clkdiv)
-               return dai->ops->set_clkdiv(dai, div_id, div);
+       if (dai->driver && dai->driver->ops->set_clkdiv)
+               return dai->driver->ops->set_clkdiv(dai, div_id, div);
        else
                return -EINVAL;
 }
@@ -2510,8 +2740,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
 int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
        unsigned int freq_in, unsigned int freq_out)
 {
-       if (dai->ops && dai->ops->set_pll)
-               return dai->ops->set_pll(dai, pll_id, source,
+       if (dai->driver && dai->driver->ops->set_pll)
+               return dai->driver->ops->set_pll(dai, pll_id, source,
                                         freq_in, freq_out);
        else
                return -EINVAL;
@@ -2527,8 +2757,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
  */
 int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
-       if (dai->ops && dai->ops->set_fmt)
-               return dai->ops->set_fmt(dai, fmt);
+       if (dai->driver && dai->driver->ops->set_fmt)
+               return dai->driver->ops->set_fmt(dai, fmt);
        else
                return -EINVAL;
 }
@@ -2548,8 +2778,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
 int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
        unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
 {
-       if (dai->ops && dai->ops->set_tdm_slot)
-               return dai->ops->set_tdm_slot(dai, tx_mask, rx_mask,
+       if (dai->driver && dai->driver->ops->set_tdm_slot)
+               return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
                                slots, slot_width);
        else
                return -EINVAL;
@@ -2572,8 +2802,8 @@ int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
        unsigned int tx_num, unsigned int *tx_slot,
        unsigned int rx_num, unsigned int *rx_slot)
 {
-       if (dai->ops && dai->ops->set_channel_map)
-               return dai->ops->set_channel_map(dai, tx_num, tx_slot,
+       if (dai->driver && dai->driver->ops->set_channel_map)
+               return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
                        rx_num, rx_slot);
        else
                return -EINVAL;
@@ -2589,8 +2819,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
  */
 int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
 {
-       if (dai->ops && dai->ops->set_tristate)
-               return dai->ops->set_tristate(dai, tristate);
+       if (dai->driver && dai->driver->ops->set_tristate)
+               return dai->driver->ops->set_tristate(dai, tristate);
        else
                return -EINVAL;
 }
@@ -2605,8 +2835,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
  */
 int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute)
 {
-       if (dai->ops && dai->ops->digital_mute)
-               return dai->ops->digital_mute(dai, mute);
+       if (dai->driver && dai->driver->ops->digital_mute)
+               return dai->driver->ops->digital_mute(dai, mute);
        else
                return -EINVAL;
 }
@@ -2623,11 +2853,22 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
  */
 static int snd_soc_register_card(struct snd_soc_card *card)
 {
+       int i;
+
        if (!card->name || !card->dev)
                return -EINVAL;
 
+       card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) * card->num_links,
+                       GFP_KERNEL);
+       if (card->rtd == NULL)
+               return -ENOMEM;
+
+       for (i = 0; i < card->num_links; i++)
+               card->rtd[i].dai_link = &card->dai_link[i];
+
        INIT_LIST_HEAD(&card->list);
        card->instantiated = 0;
+       mutex_init(&card->mutex);
 
        mutex_lock(&client_mutex);
        list_add(&card->list, &card_list);
@@ -2653,30 +2894,97 @@ static int snd_soc_unregister_card(struct snd_soc_card *card)
        mutex_lock(&client_mutex);
        list_del(&card->list);
        mutex_unlock(&client_mutex);
-
        dev_dbg(card->dev, "Unregistered card '%s'\n", card->name);
 
        return 0;
 }
 
+/*
+ * Simplify DAI link configuration by removing ".-1" from device names
+ * and sanitizing names.
+ */
+static inline char *fmt_single_name(struct device *dev, int *id)
+{
+       char *found, name[NAME_SIZE];
+       int id1, id2;
+
+       if (dev_name(dev) == NULL)
+               return NULL;
+
+       strncpy(name, dev_name(dev), NAME_SIZE);
+
+       /* are we a "%s.%d" name (platform and SPI components) */
+       found = strstr(name, dev->driver->name);
+       if (found) {
+               /* get ID */
+               if (sscanf(&found[strlen(dev->driver->name)], ".%d", id) == 1) {
+
+                       /* discard ID from name if ID == -1 */
+                       if (*id == -1)
+                               found[strlen(dev->driver->name)] = '\0';
+               }
+
+       } else {
+               /* I2C component devices are named "bus-addr"  */
+               if (sscanf(name, "%x-%x", &id1, &id2) == 2) {
+                       char tmp[NAME_SIZE];
+
+                       /* create unique ID number from I2C addr and bus */
+                       *id = ((id1 & 0xffff) << 16) + id2;
+
+                       /* sanitize component name for DAI link creation */
+                       snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, name);
+                       strncpy(name, tmp, NAME_SIZE);
+               } else
+                       *id = 0;
+       }
+
+       return kstrdup(name, GFP_KERNEL);
+}
+
+/*
+ * Simplify DAI link naming for single devices with multiple DAIs by removing
+ * any ".-1" and using the DAI name (instead of device name).
+ */
+static inline char *fmt_multiple_name(struct device *dev,
+               struct snd_soc_dai_driver *dai_drv)
+{
+       if (dai_drv->name == NULL) {
+               printk(KERN_ERR "asoc: error - multiple DAI %s registered with no name\n",
+                               dev_name(dev));
+               return NULL;
+       }
+
+       return kstrdup(dai_drv->name, GFP_KERNEL);
+}
+
 /**
  * snd_soc_register_dai - Register a DAI with the ASoC core
  *
  * @dai: DAI to register
  */
-int snd_soc_register_dai(struct snd_soc_dai *dai)
+int snd_soc_register_dai(struct device *dev,
+               struct snd_soc_dai_driver *dai_drv)
 {
-       if (!dai->name)
-               return -EINVAL;
+       struct snd_soc_dai *dai;
+
+       dev_dbg(dev, "dai register %s\n", dev_name(dev));
 
-       /* The device should become mandatory over time */
-       if (!dai->dev)
-               printk(KERN_WARNING "No device for DAI %s\n", dai->name);
+       dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
+       if (dai == NULL)
+                       return -ENOMEM;
 
-       if (!dai->ops)
-               dai->ops = &null_dai_ops;
+       /* create DAI component name */
+       dai->name = fmt_single_name(dev, &dai->id);
+       if (dai->name == NULL) {
+               kfree(dai);
+               return -ENOMEM;
+       }
 
-       INIT_LIST_HEAD(&dai->list);
+       dai->dev = dev;
+       dai->driver = dai_drv;
+       if (!dai->driver->ops)
+               dai->driver->ops = &null_dai_ops;
 
        mutex_lock(&client_mutex);
        list_add(&dai->list, &dai_list);
@@ -2694,13 +3002,24 @@ EXPORT_SYMBOL_GPL(snd_soc_register_dai);
  *
  * @dai: DAI to unregister
  */
-void snd_soc_unregister_dai(struct snd_soc_dai *dai)
+void snd_soc_unregister_dai(struct device *dev)
 {
+       struct snd_soc_dai *dai;
+
+       list_for_each_entry(dai, &dai_list, list) {
+               if (dev == dai->dev)
+                       goto found;
+       }
+       return;
+
+found:
        mutex_lock(&client_mutex);
        list_del(&dai->list);
        mutex_unlock(&client_mutex);
 
        pr_debug("Unregistered DAI '%s'\n", dai->name);
+       kfree(dai->name);
+       kfree(dai);
 }
 EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
 
@@ -2710,21 +3029,50 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
  * @dai: Array of DAIs to register
  * @count: Number of DAIs
  */
-int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count)
+int snd_soc_register_dais(struct device *dev,
+               struct snd_soc_dai_driver *dai_drv, size_t count)
 {
-       int i, ret;
+       struct snd_soc_dai *dai;
+       int i, ret = 0;
+
+       dev_dbg(dev, "dai register %s #%Zu\n", dev_name(dev), count);
 
        for (i = 0; i < count; i++) {
-               ret = snd_soc_register_dai(&dai[i]);
-               if (ret != 0)
+
+               dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
+               if (dai == NULL)
+                       return -ENOMEM;
+
+               /* create DAI component name */
+               dai->name = fmt_multiple_name(dev, &dai_drv[i]);
+               if (dai->name == NULL) {
+                       kfree(dai);
+                       ret = -EINVAL;
                        goto err;
+               }
+
+               dai->dev = dev;
+               dai->driver = &dai_drv[i];
+               if (dai->driver->id)
+                       dai->id = dai->driver->id;
+               else
+                       dai->id = i;
+               if (!dai->driver->ops)
+                       dai->driver->ops = &null_dai_ops;
+
+               mutex_lock(&client_mutex);
+               list_add(&dai->list, &dai_list);
+               mutex_unlock(&client_mutex);
+
+               pr_debug("Registered DAI '%s'\n", dai->name);
        }
 
+       snd_soc_instantiate_cards();
        return 0;
 
 err:
        for (i--; i >= 0; i--)
-               snd_soc_unregister_dai(&dai[i]);
+               snd_soc_unregister_dai(dev);
 
        return ret;
 }
@@ -2736,12 +3084,12 @@ EXPORT_SYMBOL_GPL(snd_soc_register_dais);
  * @dai: Array of DAIs to unregister
  * @count: Number of DAIs
  */
-void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count)
+void snd_soc_unregister_dais(struct device *dev, size_t count)
 {
        int i;
 
        for (i = 0; i < count; i++)
-               snd_soc_unregister_dai(&dai[i]);
+               snd_soc_unregister_dai(dev);
 }
 EXPORT_SYMBOL_GPL(snd_soc_unregister_dais);
 
@@ -2750,12 +3098,26 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dais);
  *
  * @platform: platform to register
  */
-int snd_soc_register_platform(struct snd_soc_platform *platform)
+int snd_soc_register_platform(struct device *dev,
+               struct snd_soc_platform_driver *platform_drv)
 {
-       if (!platform->name)
-               return -EINVAL;
+       struct snd_soc_platform *platform;
+
+       dev_dbg(dev, "platform register %s\n", dev_name(dev));
 
-       INIT_LIST_HEAD(&platform->list);
+       platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL);
+       if (platform == NULL)
+                       return -ENOMEM;
+
+       /* create platform component name */
+       platform->name = fmt_single_name(dev, &platform->id);
+       if (platform->name == NULL) {
+               kfree(platform);
+               return -ENOMEM;
+       }
+
+       platform->dev = dev;
+       platform->driver = platform_drv;
 
        mutex_lock(&client_mutex);
        list_add(&platform->list, &platform_list);
@@ -2773,13 +3135,24 @@ EXPORT_SYMBOL_GPL(snd_soc_register_platform);
  *
  * @platform: platform to unregister
  */
-void snd_soc_unregister_platform(struct snd_soc_platform *platform)
+void snd_soc_unregister_platform(struct device *dev)
 {
+       struct snd_soc_platform *platform;
+
+       list_for_each_entry(platform, &platform_list, list) {
+               if (dev == platform->dev)
+                       goto found;
+       }
+       return;
+
+found:
        mutex_lock(&client_mutex);
        list_del(&platform->list);
        mutex_unlock(&client_mutex);
 
        pr_debug("Unregistered platform '%s'\n", platform->name);
+       kfree(platform->name);
+       kfree(platform);
 }
 EXPORT_SYMBOL_GPL(snd_soc_unregister_platform);
 
@@ -2821,22 +3194,61 @@ static void fixup_codec_formats(struct snd_soc_pcm_stream *stream)
  *
  * @codec: codec to register
  */
-int snd_soc_register_codec(struct snd_soc_codec *codec)
+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)
 {
-       int i;
+       struct snd_soc_codec *codec;
+       int ret, i;
 
-       if (!codec->name)
-               return -EINVAL;
+       dev_dbg(dev, "codec register %s\n", dev_name(dev));
+
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (codec == NULL)
+               return -ENOMEM;
+
+       /* create CODEC component name */
+       codec->name = fmt_single_name(dev, &codec->id);
+       if (codec->name == NULL) {
+               kfree(codec);
+               return -ENOMEM;
+       }
 
-       /* The device should become mandatory over time */
-       if (!codec->dev)
-               printk(KERN_WARNING "No device for codec %s\n", codec->name);
+       /* allocate CODEC register cache */
+       if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
 
-       INIT_LIST_HEAD(&codec->list);
+               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);
 
-       for (i = 0; i < codec->num_dai; i++) {
-               fixup_codec_formats(&codec->dai[i].playback);
-               fixup_codec_formats(&codec->dai[i].capture);
+               if (codec->reg_cache == NULL) {
+                       kfree(codec->name);
+                       kfree(codec);
+                       return -ENOMEM;
+               }
+       }
+
+       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);
+
+       for (i = 0; i < num_dai; i++) {
+               fixup_codec_formats(&dai_drv[i].playback);
+               fixup_codec_formats(&dai_drv[i].capture);
+       }
+
+       /* register any DAIs */
+       if (num_dai) {
+               ret = snd_soc_register_dais(dev, dai_drv, num_dai);
+               if (ret < 0)
+                       goto error;
        }
 
        mutex_lock(&client_mutex);
@@ -2845,8 +3257,17 @@ int snd_soc_register_codec(struct snd_soc_codec *codec)
        mutex_unlock(&client_mutex);
 
        pr_debug("Registered codec '%s'\n", codec->name);
-
        return 0;
+
+error:
+       for (i--; i >= 0; i--)
+               snd_soc_unregister_dai(dev);
+
+       if (codec->reg_cache)
+               kfree(codec->reg_cache);
+       kfree(codec->name);
+       kfree(codec);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_register_codec);
 
@@ -2855,13 +3276,32 @@ EXPORT_SYMBOL_GPL(snd_soc_register_codec);
  *
  * @codec: codec to unregister
  */
-void snd_soc_unregister_codec(struct snd_soc_codec *codec)
+void snd_soc_unregister_codec(struct device *dev)
 {
+       struct snd_soc_codec *codec;
+       int i;
+
+       list_for_each_entry(codec, &codec_list, list) {
+               if (dev == codec->dev)
+                       goto found;
+       }
+       return;
+
+found:
+       if (codec->num_dai)
+               for (i = 0; i < codec->num_dai; i++)
+                       snd_soc_unregister_dai(dev);
+
        mutex_lock(&client_mutex);
        list_del(&codec->list);
        mutex_unlock(&client_mutex);
 
        pr_debug("Unregistered codec '%s'\n", codec->name);
+
+       if (codec->reg_cache)
+               kfree(codec->reg_cache);
+       kfree(codec->name);
+       kfree(codec);
 }
 EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
 
@@ -2874,10 +3314,23 @@ static int __init snd_soc_init(void)
                       "ASoC: Failed to create debugfs directory\n");
                debugfs_root = NULL;
        }
+
+       if (!debugfs_create_file("codecs", 0444, debugfs_root, NULL,
+                                &codec_list_fops))
+               pr_warn("ASoC: Failed to create CODEC list debugfs file\n");
+
+       if (!debugfs_create_file("dais", 0444, debugfs_root, NULL,
+                                &dai_list_fops))
+               pr_warn("ASoC: Failed to create DAI list debugfs file\n");
+
+       if (!debugfs_create_file("platforms", 0444, debugfs_root, NULL,
+                                &platform_list_fops))
+               pr_warn("ASoC: Failed to create platform list debugfs file\n");
 #endif
 
        return platform_driver_register(&soc_driver);
 }
+module_init(snd_soc_init);
 
 static void __exit snd_soc_exit(void)
 {
@@ -2886,8 +3339,6 @@ static void __exit snd_soc_exit(void)
 #endif
        platform_driver_unregister(&soc_driver);
 }
-
-module_init(snd_soc_init);
 module_exit(snd_soc_exit);
 
 /* Module information */
index 72a53d0a41e934972120efe156902d4d42290533..7d85c6496afa432cbd9791be5f1a9510e7cb78c7 100644 (file)
@@ -112,43 +112,41 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
 
 /**
  * snd_soc_dapm_set_bias_level - set the bias level for the system
- * @socdev: audio device
+ * @card: audio device
  * @level: level to configure
  *
  * Configure the bias (power) levels for the SoC audio device.
  *
  * Returns 0 for success else error.
  */
-static int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
-                                      enum snd_soc_bias_level level)
+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_card *card = socdev->card;
-       struct snd_soc_codec *codec = socdev->card->codec;
        int ret = 0;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               dev_dbg(socdev->dev, "Setting full bias\n");
+               dev_dbg(codec->dev, "Setting full bias\n");
                break;
        case SND_SOC_BIAS_PREPARE:
-               dev_dbg(socdev->dev, "Setting bias prepare\n");
+               dev_dbg(codec->dev, "Setting bias prepare\n");
                break;
        case SND_SOC_BIAS_STANDBY:
-               dev_dbg(socdev->dev, "Setting standby bias\n");
+               dev_dbg(codec->dev, "Setting standby bias\n");
                break;
        case SND_SOC_BIAS_OFF:
-               dev_dbg(socdev->dev, "Setting bias off\n");
+               dev_dbg(codec->dev, "Setting bias off\n");
                break;
        default:
-               dev_err(socdev->dev, "Setting invalid bias %d\n", level);
+               dev_err(codec->dev, "Setting invalid bias %d\n", level);
                return -EINVAL;
        }
 
-       if (card->set_bias_level)
+       if (card && card->set_bias_level)
                ret = card->set_bias_level(card, level);
        if (ret == 0) {
-               if (codec->set_bias_level)
-                       ret = codec->set_bias_level(codec, level);
+               if (codec->driver->set_bias_level)
+                       ret = codec->driver->set_bias_level(codec, level);
                else
                        codec->bias_level = level;
        }
@@ -370,7 +368,7 @@ 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, path->kcontrol);
+                       ret = snd_ctl_add(codec->card->snd_card, path->kcontrol);
                        if (ret < 0) {
                                printk(KERN_ERR "asoc: failed to add dapm kcontrol %s: %d\n",
                                       path->long_name,
@@ -398,7 +396,7 @@ static int dapm_new_mux(struct snd_soc_codec *codec,
        }
 
        kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name);
-       ret = snd_ctl_add(codec->card, kcontrol);
+       ret = snd_ctl_add(codec->card->snd_card, kcontrol);
        if (ret < 0)
                goto err;
 
@@ -437,9 +435,9 @@ static inline void dapm_clear_walk(struct snd_soc_codec *codec)
  */
 static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
 {
-       struct snd_soc_codec *codec = widget->codec;
+       int level = snd_power_get_state(widget->codec->card->snd_card);
 
-       switch (snd_power_get_state(codec->card)) {
+       switch (level) {
        case SNDRV_CTL_POWER_D3hot:
        case SNDRV_CTL_POWER_D3cold:
                if (widget->ignore_suspend)
@@ -893,7 +891,7 @@ static void dapm_seq_run(struct snd_soc_codec *codec, struct list_head *list,
  */
 static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
 {
-       struct snd_soc_device *socdev = codec->socdev;
+       struct snd_soc_card *card = codec->card;
        struct snd_soc_dapm_widget *w;
        LIST_HEAD(up_list);
        LIST_HEAD(down_list);
@@ -966,7 +964,7 @@ 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(socdev,
+               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);
@@ -975,8 +973,7 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
        /* 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(socdev,
-                                                 SND_SOC_BIAS_PREPARE);
+               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);
        }
@@ -989,8 +986,7 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
 
        /* 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(socdev,
-                                                 SND_SOC_BIAS_STANDBY);
+               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);
        }
@@ -998,15 +994,14 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
        /* 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(socdev, SND_SOC_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 (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) {
-               ret = snd_soc_dapm_set_bias_level(socdev,
-                                                 SND_SOC_BIAS_ON);
+               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);
        }
@@ -1189,8 +1184,9 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
 static ssize_t dapm_widget_show(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
-       struct snd_soc_device *devdata = dev_get_drvdata(dev);
-       struct snd_soc_codec *codec = devdata->card->codec;
+       struct snd_soc_pcm_runtime *rtd =
+                       container_of(dev, struct snd_soc_pcm_runtime, dev);
+       struct snd_soc_codec *codec =rtd->codec;
        struct snd_soc_dapm_widget *w;
        int count = 0;
        char *state = "not set";
@@ -1999,9 +1995,10 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
  *
  * Returns 0 for success else error.
  */
-int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
-       char *stream, int event)
+int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
+       const char *stream, int event)
 {
+       struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dapm_widget *w;
 
        if (stream == NULL)
@@ -2169,25 +2166,19 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
 
 /**
  * snd_soc_dapm_free - free dapm resources
- * @socdev: SoC device
+ * @card: SoC device
  *
  * Free all dapm widgets and resources.
  */
-void snd_soc_dapm_free(struct snd_soc_device *socdev)
+void snd_soc_dapm_free(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = socdev->card->codec;
-
-       snd_soc_dapm_sys_remove(socdev->dev);
+       snd_soc_dapm_sys_remove(codec->dev);
        dapm_free_widgets(codec);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
 
-/*
- * snd_soc_dapm_shutdown - callback for system shutdown
- */
-void snd_soc_dapm_shutdown(struct snd_soc_device *socdev)
+static void soc_dapm_shutdown_codec(struct snd_soc_codec *codec)
 {
-       struct snd_soc_codec *codec = socdev->card->codec;
        struct snd_soc_dapm_widget *w;
        LIST_HEAD(down_list);
        int powerdown = 0;
@@ -2204,12 +2195,23 @@ void snd_soc_dapm_shutdown(struct snd_soc_device *socdev)
         * standby.
         */
        if (powerdown) {
-               snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_PREPARE);
+               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(socdev, SND_SOC_BIAS_STANDBY);
+               snd_soc_dapm_set_bias_level(NULL, codec, SND_SOC_BIAS_STANDBY);
        }
+}
+
+/*
+ * snd_soc_dapm_shutdown - callback for system shutdown
+ */
+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(socdev, SND_SOC_BIAS_OFF);
+       snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_OFF);
 }
 
 /* Module information */
index 29159e1781d0edbc681a8120865323171a7a4906..8a0a9205b1e785bf92d6ddd773b0a70cc7cf568d 100644 (file)
  * Returns zero if successful, or a negative error code on failure.
  * On success jack will be initialised.
  */
-int snd_soc_jack_new(struct snd_soc_card *card, const char *id, int type,
+int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
                     struct snd_soc_jack *jack)
 {
-       jack->card = card;
+       jack->codec = codec;
        INIT_LIST_HEAD(&jack->pins);
        BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier);
 
-       return snd_jack_new(card->codec->card, id, type, &jack->jack);
+       return snd_jack_new(codec->card->snd_card, id, type, &jack->jack);
 }
 EXPORT_SYMBOL_GPL(snd_soc_jack_new);
 
@@ -67,7 +67,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
        if (!jack)
                return;
 
-       codec = jack->card->codec;
+       codec = jack->codec;
 
        mutex_lock(&codec->mutex);
 
@@ -188,9 +188,6 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
        int enable;
        int report;
 
-       if (gpio->debounce_time > 0)
-               mdelay(gpio->debounce_time);
-
        enable = gpio_get_value(gpio->gpio);
        if (gpio->invert)
                enable = !enable;
@@ -211,7 +208,8 @@ static irqreturn_t gpio_handler(int irq, void *data)
 {
        struct snd_soc_jack_gpio *gpio = data;
 
-       schedule_work(&gpio->work);
+       schedule_delayed_work(&gpio->work,
+                             msecs_to_jiffies(gpio->debounce_time));
 
        return IRQ_HANDLED;
 }
@@ -221,7 +219,7 @@ static void gpio_work(struct work_struct *work)
 {
        struct snd_soc_jack_gpio *gpio;
 
-       gpio = container_of(work, struct snd_soc_jack_gpio, work);
+       gpio = container_of(work, struct snd_soc_jack_gpio, work.work);
        snd_soc_jack_gpio_detect(gpio);
 }
 
@@ -262,13 +260,13 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
                if (ret)
                        goto err;
 
-               INIT_WORK(&gpios[i].work, gpio_work);
+               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->card->dev->driver->name,
+                               jack->codec->dev->driver->name,
                                &gpios[i]);
                if (ret)
                        goto err;
@@ -312,6 +310,7 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
                gpio_unexport(gpios[i].gpio);
 #endif
                free_irq(gpio_to_irq(gpios[i].gpio), &gpios[i]);
+               cancel_delayed_work_sync(&gpios[i].work);
                gpio_free(gpios[i].gpio);
                gpios[i].jack = NULL;
        }
index 0ec20b68e8cbbe6089c7c8b453fdf9d4d5a41507..743d07b82c062033f5287a85537b175ef72976d5 100644 (file)
 
 static DECLARE_WAIT_QUEUE_HEAD(ac97_waitq);
 
-/* REVISIT: How to find txx9aclc_soc_device from snd_ac97? */
-static struct txx9aclc_soc_device *txx9aclc_soc_dev;
+/* REVISIT: How to find txx9aclc_drvdata from snd_ac97? */
+static struct txx9aclc_plat_drvdata *txx9aclc_drvdata;
 
-static int txx9aclc_regready(struct txx9aclc_soc_device *dev)
+static int txx9aclc_regready(struct txx9aclc_plat_drvdata *drvdata)
 {
-       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
-
        return __raw_readl(drvdata->base + ACINTSTS) & ACINT_REGACCRDY;
 }
 
@@ -50,8 +48,7 @@ static int txx9aclc_regready(struct txx9aclc_soc_device *dev)
 static unsigned short txx9aclc_ac97_read(struct snd_ac97 *ac97,
                                         unsigned short reg)
 {
-       struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
-       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
        void __iomem *base = drvdata->base;
        u32 dat;
 
@@ -61,15 +58,15 @@ static unsigned short txx9aclc_ac97_read(struct snd_ac97 *ac97,
        dat = (reg << ACREGACC_REG_SHIFT) | ACREGACC_READ;
        __raw_writel(dat, base + ACREGACC);
        __raw_writel(ACINT_REGACCRDY, base + ACINTEN);
-       if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(dev), HZ)) {
+       if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(txx9aclc_drvdata), HZ)) {
                __raw_writel(ACINT_REGACCRDY, base + ACINTDIS);
-               dev_err(dev->soc_dev.dev, "ac97 read timeout (reg %#x)\n", reg);
+               printk(KERN_ERR "ac97 read timeout (reg %#x)\n", reg);
                dat = 0xffff;
                goto done;
        }
        dat = __raw_readl(base + ACREGACC);
        if (((dat >> ACREGACC_REG_SHIFT) & 0xff) != reg) {
-               dev_err(dev->soc_dev.dev, "reg mismatch %x with %x\n",
+               printk(KERN_ERR "reg mismatch %x with %x\n",
                        dat, reg);
                dat = 0xffff;
                goto done;
@@ -84,16 +81,15 @@ done:
 static void txx9aclc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
                                unsigned short val)
 {
-       struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
-       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
        void __iomem *base = drvdata->base;
 
        __raw_writel(((reg | (ac97->num << 7)) << ACREGACC_REG_SHIFT) |
                     (val << ACREGACC_DAT_SHIFT),
                     base + ACREGACC);
        __raw_writel(ACINT_REGACCRDY, base + ACINTEN);
-       if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(dev), HZ)) {
-               dev_err(dev->soc_dev.dev,
+       if (!wait_event_timeout(ac97_waitq, txx9aclc_regready(txx9aclc_drvdata), HZ)) {
+               printk(KERN_ERR
                        "ac97 write timeout (reg %#x)\n", reg);
        }
        __raw_writel(ACINT_REGACCRDY, base + ACINTDIS);
@@ -101,8 +97,7 @@ static void txx9aclc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 
 static void txx9aclc_ac97_cold_reset(struct snd_ac97 *ac97)
 {
-       struct txx9aclc_soc_device *dev = txx9aclc_soc_dev;
-       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
        void __iomem *base = drvdata->base;
        u32 ready = ACINT_CODECRDY(ac97->num) | ACINT_REGACCRDY;
 
@@ -141,31 +136,23 @@ static irqreturn_t txx9aclc_ac97_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int txx9aclc_ac97_probe(struct platform_device *pdev,
-                              struct snd_soc_dai *dai)
+static int txx9aclc_ac97_probe(struct snd_soc_dai *dai)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct txx9aclc_soc_device *dev =
-               container_of(socdev, struct txx9aclc_soc_device, soc_dev);
-
-       dev->aclc_pdev = to_platform_device(dai->dev);
-       txx9aclc_soc_dev = dev;
+       txx9aclc_drvdata = snd_soc_dai_get_drvdata(dai);
        return 0;
 }
 
-static void txx9aclc_ac97_remove(struct platform_device *pdev,
-                                struct snd_soc_dai *dai)
+static int txx9aclc_ac97_remove(struct snd_soc_dai *dai)
 {
-       struct platform_device *aclc_pdev = to_platform_device(dai->dev);
-       struct txx9aclc_plat_drvdata *drvdata = platform_get_drvdata(aclc_pdev);
+       struct txx9aclc_plat_drvdata *drvdata = snd_soc_dai_get_drvdata(dai);
 
        /* disable AC-link */
        __raw_writel(ACCTL_ENLINK, drvdata->base + ACCTLDIS);
-       txx9aclc_soc_dev = NULL;
+       txx9aclc_drvdata = NULL;
+       return 0;
 }
 
-struct snd_soc_dai txx9aclc_ac97_dai = {
-       .name                   = "txx9aclc_ac97",
+static struct snd_soc_dai_driver txx9aclc_ac97_dai = {
        .ac97_control           = 1,
        .probe                  = txx9aclc_ac97_probe,
        .remove                 = txx9aclc_ac97_remove,
@@ -182,7 +169,6 @@ struct snd_soc_dai txx9aclc_ac97_dai = {
                .channels_max   = 2,
        },
 };
-EXPORT_SYMBOL_GPL(txx9aclc_ac97_dai);
 
 static int __devinit txx9aclc_ac97_dev_probe(struct platform_device *pdev)
 {
@@ -219,13 +205,12 @@ static int __devinit txx9aclc_ac97_dev_probe(struct platform_device *pdev)
        if (err < 0)
                return err;
 
-       txx9aclc_ac97_dai.dev = &pdev->dev;
-       return snd_soc_register_dai(&txx9aclc_ac97_dai);
+       return snd_soc_register_dai(&pdev->dev, &txx9aclc_ac97_dai);
 }
 
 static int __devexit txx9aclc_ac97_dev_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&txx9aclc_ac97_dai);
+       snd_soc_unregister_dai(&pdev->dev);
        return 0;
 }
 
index 95b17f731aec3a298e2f8c38638201e8eeb63ac2..6770e7166be4b77ae3427cbd3aba16b3b4694489 100644 (file)
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
-#include "../codecs/ac97.h"
 #include "txx9aclc.h"
 
 static struct snd_soc_dai_link txx9aclc_generic_dai = {
        .name = "AC97",
        .stream_name = "AC97 HiFi",
-       .cpu_dai = &txx9aclc_ac97_dai,
-       .codec_dai = &ac97_dai,
+       .cpu_dai_name = "txx9aclc-ac97",
+       .codec_dai_name = "ac97-hifi",
+       .platform_name  = "txx9aclc-pcm-audio",
+       .codec_name     = "ac97-codec",
 };
 
 static struct snd_soc_card txx9aclc_generic_card = {
        .name           = "Generic TXx9 ACLC Audio",
-       .platform       = &txx9aclc_soc_platform,
        .dai_link       = &txx9aclc_generic_dai,
        .num_links      = 1,
 };
 
-static struct txx9aclc_soc_device txx9aclc_generic_soc_device = {
-       .soc_dev = {
-               .card           = &txx9aclc_generic_card,
-               .codec_dev      = &soc_codec_dev_ac97,
-       },
-};
+static struct platform_device *soc_pdev;
 
 static int __init txx9aclc_generic_probe(struct platform_device *pdev)
 {
-       struct txx9aclc_soc_device *dev = &txx9aclc_generic_soc_device;
-       struct platform_device *soc_pdev;
        int ret;
 
        soc_pdev = platform_device_alloc("soc-audio", -1);
        if (!soc_pdev)
                return -ENOMEM;
-       platform_set_drvdata(soc_pdev, &dev->soc_dev);
-       dev->soc_dev.dev = &soc_pdev->dev;
+       platform_set_drvdata(soc_pdev, &txx9aclc_generic_card);
        ret = platform_device_add(soc_pdev);
        if (ret) {
                platform_device_put(soc_pdev);
                return ret;
        }
-       platform_set_drvdata(pdev, soc_pdev);
+
        return 0;
 }
 
 static int __exit txx9aclc_generic_remove(struct platform_device *pdev)
 {
-       struct platform_device *soc_pdev = platform_get_drvdata(pdev);
-
        platform_device_unregister(soc_pdev);
        return 0;
 }
index 0e3452303ea6903d4045d325be31c059d6257b60..f4aa4e03c88884e0b1768314c6d2273b221fb976 100644 (file)
 #include <sound/soc.h>
 #include "txx9aclc.h"
 
+static struct txx9aclc_soc_device {
+       struct txx9aclc_dmadata dmadata[2];
+} txx9aclc_soc_device;
+
+/* REVISIT: How to find txx9aclc_drvdata from snd_ac97? */
+static struct txx9aclc_plat_drvdata *txx9aclc_drvdata;
+
+static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
+                            struct txx9aclc_dmadata *dmadata);
+
 static const struct snd_pcm_hardware txx9aclc_pcm_hardware = {
        /*
         * REVISIT: SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID
@@ -46,7 +56,6 @@ static int txx9aclc_pcm_hw_params(struct snd_pcm_substream *substream,
                                  struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
-       struct snd_soc_device *socdev = rtd->socdev;
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct txx9aclc_dmadata *dmadata = runtime->private_data;
        int ret;
@@ -55,13 +64,13 @@ static int txx9aclc_pcm_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       dev_dbg(socdev->dev,
+       dev_dbg(rtd->platform->dev,
                "runtime->dma_area = %#lx dma_addr = %#lx dma_bytes = %zd "
                "runtime->min_align %ld\n",
                (unsigned long)runtime->dma_area,
                (unsigned long)runtime->dma_addr, runtime->dma_bytes,
                runtime->min_align);
-       dev_dbg(socdev->dev,
+       dev_dbg(rtd->platform->dev,
                "periods %d period_bytes %d stream %d\n",
                params_periods(params), params_period_bytes(params),
                substream->stream);
@@ -152,11 +161,7 @@ static void txx9aclc_dma_tasklet(unsigned long data)
 
        spin_lock_irqsave(&dmadata->dma_lock, flags);
        if (dmadata->frag_count < 0) {
-               struct txx9aclc_soc_device *dev =
-                       container_of(dmadata, struct txx9aclc_soc_device,
-                                    dmadata[substream->stream]);
-               struct txx9aclc_plat_drvdata *drvdata =
-                       txx9aclc_get_plat_drvdata(dev);
+               struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
                void __iomem *base = drvdata->base;
 
                spin_unlock_irqrestore(&dmadata->dma_lock, flags);
@@ -202,10 +207,7 @@ static void txx9aclc_dma_tasklet(unsigned long data)
 static int txx9aclc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
        struct txx9aclc_dmadata *dmadata = substream->runtime->private_data;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct txx9aclc_soc_device *dev =
-               container_of(rtd->socdev, struct txx9aclc_soc_device, soc_dev);
-       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+       struct txx9aclc_plat_drvdata *drvdata =txx9aclc_drvdata;
        void __iomem *base = drvdata->base;
        unsigned long flags;
        int ret = 0;
@@ -244,9 +246,7 @@ txx9aclc_pcm_pointer(struct snd_pcm_substream *substream)
 
 static int txx9aclc_pcm_open(struct snd_pcm_substream *substream)
 {
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct txx9aclc_soc_device *dev =
-               container_of(rtd->socdev, struct txx9aclc_soc_device, soc_dev);
+       struct txx9aclc_soc_device *dev = &txx9aclc_soc_device;
        struct txx9aclc_dmadata *dmadata = &dev->dmadata[substream->stream];
        int ret;
 
@@ -291,8 +291,38 @@ static void txx9aclc_pcm_free_dma_buffers(struct snd_pcm *pcm)
 static int txx9aclc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
                            struct snd_pcm *pcm)
 {
+       struct platform_device *pdev = to_platform_device(dai->platform->dev);
+       struct txx9aclc_soc_device *dev;
+       struct resource *r;
+       int i;
+       int ret;
+
+       /* at this point onwards the AC97 component has probed and this will be valid */
+       dev = snd_soc_dai_get_drvdata(dai);
+
+       dev->dmadata[0].stream = SNDRV_PCM_STREAM_PLAYBACK;
+       dev->dmadata[1].stream = SNDRV_PCM_STREAM_CAPTURE;
+       for (i = 0; i < 2; i++) {
+               r = platform_get_resource(pdev, IORESOURCE_DMA, i);
+               if (!r) {
+                       ret = -EBUSY;
+                       goto exit;
+               }
+               dev->dmadata[i].dma_res = r;
+               ret = txx9aclc_dma_init(dev, &dev->dmadata[i]);
+               if (ret)
+                       goto exit;
+       }
        return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                card->dev, 64 * 1024, 4 * 1024 * 1024);
+
+exit:
+       for (i = 0; i < 2; i++) {
+               if (dev->dmadata[i].dma_chan)
+                       dma_release_channel(dev->dmadata[i].dma_chan);
+               dev->dmadata[i].dma_chan = NULL;
+       }
+       return ret;
 }
 
 static bool filter(struct dma_chan *chan, void *param)
@@ -314,7 +344,7 @@ static bool filter(struct dma_chan *chan, void *param)
 static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
                             struct txx9aclc_dmadata *dmadata)
 {
-       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+       struct txx9aclc_plat_drvdata *drvdata =txx9aclc_drvdata;
        struct txx9dmac_slave *ds = &dmadata->dma_slave;
        dma_cap_mask_t mask;
 
@@ -334,7 +364,7 @@ static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
        dma_cap_set(DMA_SLAVE, mask);
        dmadata->dma_chan = dma_request_channel(mask, filter, dmadata);
        if (!dmadata->dma_chan) {
-               dev_err(dev->soc_dev.dev,
+               printk(KERN_ERR
                        "DMA channel for %s is not available\n",
                        dmadata->stream == SNDRV_PCM_STREAM_PLAYBACK ?
                        "playback" : "capture");
@@ -345,45 +375,16 @@ static int txx9aclc_dma_init(struct txx9aclc_soc_device *dev,
        return 0;
 }
 
-static int txx9aclc_pcm_probe(struct platform_device *pdev)
+static int txx9aclc_pcm_probe(struct snd_soc_platform *platform)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct txx9aclc_soc_device *dev =
-               container_of(socdev, struct txx9aclc_soc_device, soc_dev);
-       struct resource *r;
-       int i;
-       int ret;
-
-       dev->dmadata[0].stream = SNDRV_PCM_STREAM_PLAYBACK;
-       dev->dmadata[1].stream = SNDRV_PCM_STREAM_CAPTURE;
-       for (i = 0; i < 2; i++) {
-               r = platform_get_resource(dev->aclc_pdev, IORESOURCE_DMA, i);
-               if (!r) {
-                       ret = -EBUSY;
-                       goto exit;
-               }
-               dev->dmadata[i].dma_res = r;
-               ret = txx9aclc_dma_init(dev, &dev->dmadata[i]);
-               if (ret)
-                       goto exit;
-       }
+       snd_soc_platform_set_drvdata(platform, &txx9aclc_soc_device);
        return 0;
-
-exit:
-       for (i = 0; i < 2; i++) {
-               if (dev->dmadata[i].dma_chan)
-                       dma_release_channel(dev->dmadata[i].dma_chan);
-               dev->dmadata[i].dma_chan = NULL;
-       }
-       return ret;
 }
 
-static int txx9aclc_pcm_remove(struct platform_device *pdev)
+static int txx9aclc_pcm_remove(struct snd_soc_platform *platform)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct txx9aclc_soc_device *dev =
-               container_of(socdev, struct txx9aclc_soc_device, soc_dev);
-       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_get_plat_drvdata(dev);
+       struct txx9aclc_soc_device *dev = snd_soc_platform_get_drvdata(platform);
+       struct txx9aclc_plat_drvdata *drvdata = txx9aclc_drvdata;
        void __iomem *base = drvdata->base;
        int i;
 
@@ -406,28 +407,46 @@ static int txx9aclc_pcm_remove(struct platform_device *pdev)
        return 0;
 }
 
-struct snd_soc_platform txx9aclc_soc_platform = {
-       .name           = "txx9aclc-audio",
+static struct snd_soc_platform_driver txx9aclc_soc_platform = {
        .probe          = txx9aclc_pcm_probe,
        .remove         = txx9aclc_pcm_remove,
-       .pcm_ops        = &txx9aclc_pcm_ops,
+       .ops            = &txx9aclc_pcm_ops,
        .pcm_new        = txx9aclc_pcm_new,
        .pcm_free       = txx9aclc_pcm_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(txx9aclc_soc_platform);
 
-static int __init txx9aclc_soc_platform_init(void)
+static int __devinit txx9aclc_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_platform(&txx9aclc_soc_platform);
+       return snd_soc_register_platform(&pdev->dev, &txx9aclc_soc_platform);
 }
 
-static void __exit txx9aclc_soc_platform_exit(void)
+static int __devexit txx9aclc_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_platform(&txx9aclc_soc_platform);
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
 }
 
-module_init(txx9aclc_soc_platform_init);
-module_exit(txx9aclc_soc_platform_exit);
+static struct platform_driver txx9aclc_pcm_driver = {
+       .driver = {
+                       .name = "txx9aclc-pcm-audio",
+                       .owner = THIS_MODULE,
+       },
+
+       .probe = txx9aclc_soc_platform_probe,
+       .remove = __devexit_p(txx9aclc_soc_platform_remove),
+};
+
+static int __init snd_txx9aclc_pcm_init(void)
+{
+       return platform_driver_register(&txx9aclc_pcm_driver);
+}
+module_init(snd_txx9aclc_pcm_init);
+
+static void __exit snd_txx9aclc_pcm_exit(void)
+{
+       platform_driver_unregister(&txx9aclc_pcm_driver);
+}
+module_exit(snd_txx9aclc_pcm_exit);
 
 MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
 MODULE_DESCRIPTION("TXx9 ACLC Audio DMA driver");
index 6769aab41b331d60f77b412369cb68823aa3b8c6..9c2de84fec3bbae4bd529f977b4aeab648f38129 100644 (file)
@@ -65,19 +65,10 @@ struct txx9aclc_plat_drvdata {
        u64 physbase;
 };
 
-struct txx9aclc_soc_device {
-       struct snd_soc_device soc_dev;
-       struct platform_device *aclc_pdev;      /* for ioresources, drvdata */
-       struct txx9aclc_dmadata dmadata[2];
-};
-
 static inline struct txx9aclc_plat_drvdata *txx9aclc_get_plat_drvdata(
-       struct txx9aclc_soc_device *sdev)
+       struct snd_soc_dai *dai)
 {
-       return platform_get_drvdata(sdev->aclc_pdev);
+       return dev_get_drvdata(dai->dev);
 }
 
-extern struct snd_soc_platform txx9aclc_soc_platform;
-extern struct snd_soc_dai txx9aclc_ac97_dai;
-
 #endif /* __TXX9ACLC_H */
index ff0b2a8fd25bbe20dd51191935582746f8ba6edf..5ae1eae9f6dbc2491c5b6bb378ca81cc896e22dc 100644 (file)
@@ -128,6 +128,9 @@ snd_emux_init_hwdep(struct snd_emux *emu)
        strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME);
        hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE;
        hw->ops.ioctl = snd_emux_hwdep_ioctl;
+       /* The ioctl parameter types are compatible between 32- and
+        * 64-bit architectures, so use the same function. */
+       hw->ops.ioctl_compat = snd_emux_hwdep_ioctl;
        hw->exclusive = 1;
        hw->private_data = emu;
        if ((err = snd_card_register(emu->card)) < 0)
index 44d6d2ec964f364c07852f9bf88a7d9282a6d059..112984f4080f1d5cbd84aa157d0c60fae2be5cd9 100644 (file)
@@ -65,6 +65,7 @@ config SND_USB_CAIAQ
            * Native Instruments Guitar Rig Session I/O
            * Native Instruments Guitar Rig mobile
            * Native Instruments Traktor Kontrol X1
+           * Native Instruments Traktor Kontrol S4
 
           To compile this driver as a module, choose M here: the module
           will be called snd-usb-caiaq.
@@ -82,6 +83,7 @@ config SND_USB_CAIAQ_INPUT
           * Native Instruments Kore Controller
           * Native Instruments Kore Controller 2
           * Native Instruments Audio Kontrol 1
+          * Native Instruments Traktor Kontrol S4
 
 config SND_USB_US122L
        tristate "Tascam US-122L USB driver"
index 4328cad6c3a24cd7f5887eb6d825d52f0ad6091b..68b97477577b923f8017733d0a6656cbbfa486d3 100644 (file)
@@ -111,7 +111,7 @@ static int stream_start(struct snd_usb_caiaqdev *dev)
        memset(dev->sub_capture, 0, sizeof(dev->sub_capture));
        dev->input_panic = 0;
        dev->output_panic = 0;
-       dev->first_packet = 1;
+       dev->first_packet = 4;
        dev->streaming = 1;
        dev->warned = 0;
 
@@ -169,7 +169,7 @@ static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream)
 }
 
 static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub,
-                                       struct snd_pcm_hw_params *hw_params)
+                                      struct snd_pcm_hw_params *hw_params)
 {
        debug("%s(%p)\n", __func__, sub);
        return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params));
@@ -189,7 +189,7 @@ static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub)
 #endif
 
 static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100,
-                                 48000, 64000, 88200, 96000, 176400, 192000 };
+                               48000, 64000, 88200, 96000, 176400, 192000 };
 
 static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
 {
@@ -201,12 +201,39 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
        debug("%s(%p)\n", __func__, substream);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               dev->period_out_count[index] = BYTES_PER_SAMPLE + 1;
-               dev->audio_out_buf_pos[index] = BYTES_PER_SAMPLE + 1;
+               int out_pos;
+
+               switch (dev->spec.data_alignment) {
+               case 0:
+               case 2:
+                       out_pos = BYTES_PER_SAMPLE + 1;
+                       break;
+               case 3:
+               default:
+                       out_pos = 0;
+                       break;
+               }
+
+               dev->period_out_count[index] = out_pos;
+               dev->audio_out_buf_pos[index] = out_pos;
        } else {
-               int in_pos = (dev->spec.data_alignment == 2) ? 0 : 2;
-               dev->period_in_count[index] = BYTES_PER_SAMPLE + in_pos;
-               dev->audio_in_buf_pos[index] = BYTES_PER_SAMPLE + in_pos;
+               int in_pos;
+
+               switch (dev->spec.data_alignment) {
+               case 0:
+                       in_pos = BYTES_PER_SAMPLE + 2;
+                       break;
+               case 2:
+                       in_pos = BYTES_PER_SAMPLE;
+                       break;
+               case 3:
+               default:
+                       in_pos = 0;
+                       break;
+               }
+
+               dev->period_in_count[index] = in_pos;
+               dev->audio_in_buf_pos[index] = in_pos;
        }
 
        if (dev->streaming)
@@ -221,7 +248,7 @@ static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
        snd_pcm_limit_hw_rates(runtime);
 
        bytes_per_sample = BYTES_PER_SAMPLE;
-       if (dev->spec.data_alignment == 2)
+       if (dev->spec.data_alignment >= 2)
                bytes_per_sample++;
 
        bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE)
@@ -253,6 +280,8 @@ static int snd_usb_caiaq_pcm_trigger(struct snd_pcm_substream *sub, int cmd)
 {
        struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub);
 
+       debug("%s(%p) cmd %d\n", __func__, sub, cmd);
+
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -402,6 +431,61 @@ static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev,
        }
 }
 
+static void read_in_urb_mode3(struct snd_usb_caiaqdev *dev,
+                             const struct urb *urb,
+                             const struct usb_iso_packet_descriptor *iso)
+{
+       unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
+       int stream, i;
+
+       /* paranoia check */
+       if (iso->actual_length % (BYTES_PER_SAMPLE_USB * CHANNELS_PER_STREAM))
+               return;
+
+       for (i = 0; i < iso->actual_length;) {
+               for (stream = 0; stream < dev->n_streams; stream++) {
+                       struct snd_pcm_substream *sub = dev->sub_capture[stream];
+                       char *audio_buf = NULL;
+                       int c, n, sz = 0;
+
+                       if (sub && !dev->input_panic) {
+                               struct snd_pcm_runtime *rt = sub->runtime;
+                               audio_buf = rt->dma_area;
+                               sz = frames_to_bytes(rt, rt->buffer_size);
+                       }
+
+                       for (c = 0; c < CHANNELS_PER_STREAM; c++) {
+                               /* 3 audio data bytes, followed by 1 check byte */
+                               if (audio_buf) {
+                                       for (n = 0; n < BYTES_PER_SAMPLE; n++) {
+                                               audio_buf[dev->audio_in_buf_pos[stream]++] = usb_buf[i+n];
+
+                                               if (dev->audio_in_buf_pos[stream] == sz)
+                                                       dev->audio_in_buf_pos[stream] = 0;
+                                       }
+
+                                       dev->period_in_count[stream] += BYTES_PER_SAMPLE;
+                               }
+
+                               i += BYTES_PER_SAMPLE;
+
+                               if (usb_buf[i] != ((stream << 1) | c) &&
+                                   !dev->first_packet) {
+                                       if (!dev->input_panic)
+                                               printk(" EXPECTED: %02x got %02x, c %d, stream %d, i %d\n",
+                                                       ((stream << 1) | c), usb_buf[i], c, stream, i);
+                                       dev->input_panic = 1;
+                               }
+
+                               i++;
+                       }
+               }
+       }
+
+       if (dev->first_packet > 0)
+               dev->first_packet--;
+}
+
 static void read_in_urb(struct snd_usb_caiaqdev *dev,
                        const struct urb *urb,
                        const struct usb_iso_packet_descriptor *iso)
@@ -419,6 +503,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev,
        case 2:
                read_in_urb_mode2(dev, urb, iso);
                break;
+       case 3:
+               read_in_urb_mode3(dev, urb, iso);
+               break;
        }
 
        if ((dev->input_panic || dev->output_panic) && !dev->warned) {
@@ -429,9 +516,9 @@ static void read_in_urb(struct snd_usb_caiaqdev *dev,
        }
 }
 
-static void fill_out_urb(struct snd_usb_caiaqdev *dev,
-                        struct urb *urb,
-                        const struct usb_iso_packet_descriptor *iso)
+static void fill_out_urb_mode_0(struct snd_usb_caiaqdev *dev,
+                               struct urb *urb,
+                               const struct usb_iso_packet_descriptor *iso)
 {
        unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
        struct snd_pcm_substream *sub;
@@ -457,9 +544,67 @@ static void fill_out_urb(struct snd_usb_caiaqdev *dev,
                /* fill in the check bytes */
                if (dev->spec.data_alignment == 2 &&
                    i % (dev->n_streams * BYTES_PER_SAMPLE_USB) ==
-                       (dev->n_streams * CHANNELS_PER_STREAM))
-                   for (stream = 0; stream < dev->n_streams; stream++, i++)
-                       usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i);
+                       (dev->n_streams * CHANNELS_PER_STREAM))
+                       for (stream = 0; stream < dev->n_streams; stream++, i++)
+                               usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i);
+       }
+}
+
+static void fill_out_urb_mode_3(struct snd_usb_caiaqdev *dev,
+                               struct urb *urb,
+                               const struct usb_iso_packet_descriptor *iso)
+{
+       unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
+       int stream, i;
+
+       for (i = 0; i < iso->length;) {
+               for (stream = 0; stream < dev->n_streams; stream++) {
+                       struct snd_pcm_substream *sub = dev->sub_playback[stream];
+                       char *audio_buf = NULL;
+                       int c, n, sz = 0;
+
+                       if (sub) {
+                               struct snd_pcm_runtime *rt = sub->runtime;
+                               audio_buf = rt->dma_area;
+                               sz = frames_to_bytes(rt, rt->buffer_size);
+                       }
+
+                       for (c = 0; c < CHANNELS_PER_STREAM; c++) {
+                               for (n = 0; n < BYTES_PER_SAMPLE; n++) {
+                                       if (audio_buf) {
+                                               usb_buf[i+n] = audio_buf[dev->audio_out_buf_pos[stream]++];
+
+                                               if (dev->audio_out_buf_pos[stream] == sz)
+                                                       dev->audio_out_buf_pos[stream] = 0;
+                                       } else {
+                                               usb_buf[i+n] = 0;
+                                       }
+                               }
+
+                               if (audio_buf)
+                                       dev->period_out_count[stream] += BYTES_PER_SAMPLE;
+
+                               i += BYTES_PER_SAMPLE;
+
+                               /* fill in the check byte pattern */
+                               usb_buf[i++] = (stream << 1) | c;
+                       }
+               }
+       }
+}
+
+static inline void fill_out_urb(struct snd_usb_caiaqdev *dev,
+                               struct urb *urb,
+                               const struct usb_iso_packet_descriptor *iso)
+{
+       switch (dev->spec.data_alignment) {
+       case 0:
+       case 2:
+               fill_out_urb_mode_0(dev, urb, iso);
+               break;
+       case 3:
+               fill_out_urb_mode_3(dev, urb, iso);
+               break;
        }
 }
 
index 91c804cd278278c639f428ab59d963d6d6804105..00e5d0a469e1b065a6bee10b57d9fc1c41f2d716 100644 (file)
@@ -55,6 +55,10 @@ static int control_info(struct snd_kcontrol *kcontrol,
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
                maxval = 127;
                break;
+
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
+               maxval = 31;
+               break;
        }
 
        if (is_intval) {
@@ -93,6 +97,7 @@ static int control_put(struct snd_kcontrol *kcontrol,
        struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol);
        struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
        int pos = kcontrol->private_value;
+       int v = ucontrol->value.integer.value[0];
        unsigned char cmd = EP1_CMD_WRITE_IO;
 
        if (dev->chip.usb_id ==
@@ -100,12 +105,27 @@ static int control_put(struct snd_kcontrol *kcontrol,
                cmd = EP1_CMD_DIMM_LEDS;
 
        if (pos & CNT_INTVAL) {
-               dev->control_state[pos & ~CNT_INTVAL]
-                       = ucontrol->value.integer.value[0];
-               snd_usb_caiaq_send_command(dev, cmd,
-                               dev->control_state, sizeof(dev->control_state));
+               int i = pos & ~CNT_INTVAL;
+
+               dev->control_state[i] = v;
+
+               if (dev->chip.usb_id ==
+                       USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4)) {
+                       int actual_len;
+
+                       dev->ep8_out_buf[0] = i;
+                       dev->ep8_out_buf[1] = v;
+
+                       usb_bulk_msg(dev->chip.dev,
+                                    usb_sndbulkpipe(dev->chip.dev, 8),
+                                    dev->ep8_out_buf, sizeof(dev->ep8_out_buf),
+                                    &actual_len, 200);
+               } else {
+                       snd_usb_caiaq_send_command(dev, cmd,
+                                       dev->control_state, sizeof(dev->control_state));
+               }
        } else {
-               if (ucontrol->value.integer.value[0])
+               if (v)
                        dev->control_state[pos / 8] |= 1 << (pos % 8);
                else
                        dev->control_state[pos / 8] &= ~(1 << (pos % 8));
@@ -296,6 +316,179 @@ static struct caiaq_controller kontrolx1_controller[] = {
        { "LED Deck B: SYNC",           8  | CNT_INTVAL },
 };
 
+static struct caiaq_controller kontrols4_controller[] = {
+       { "LED: Master: Quant",                 10  | CNT_INTVAL },
+       { "LED: Master: Headphone",             11  | CNT_INTVAL },
+       { "LED: Master: Master",                12  | CNT_INTVAL },
+       { "LED: Master: Snap",                  14  | CNT_INTVAL },
+       { "LED: Master: Warning",               15  | CNT_INTVAL },
+       { "LED: Master: Master button",         112 | CNT_INTVAL },
+       { "LED: Master: Snap button",           113 | CNT_INTVAL },
+       { "LED: Master: Rec",                   118 | CNT_INTVAL },
+       { "LED: Master: Size",                  119 | CNT_INTVAL },
+       { "LED: Master: Quant button",          120 | CNT_INTVAL },
+       { "LED: Master: Browser button",        121 | CNT_INTVAL },
+       { "LED: Master: Play button",           126 | CNT_INTVAL },
+       { "LED: Master: Undo button",           127 | CNT_INTVAL },
+
+       { "LED: Channel A: >",                  4   | CNT_INTVAL },
+       { "LED: Channel A: <",                  5   | CNT_INTVAL },
+       { "LED: Channel A: Meter 1",            97  | CNT_INTVAL },
+       { "LED: Channel A: Meter 2",            98  | CNT_INTVAL },
+       { "LED: Channel A: Meter 3",            99  | CNT_INTVAL },
+       { "LED: Channel A: Meter 4",            100 | CNT_INTVAL },
+       { "LED: Channel A: Meter 5",            101 | CNT_INTVAL },
+       { "LED: Channel A: Meter 6",            102 | CNT_INTVAL },
+       { "LED: Channel A: Meter clip",         103 | CNT_INTVAL },
+       { "LED: Channel A: Active",             114 | CNT_INTVAL },
+       { "LED: Channel A: Cue",                116 | CNT_INTVAL },
+       { "LED: Channel A: FX1",                149 | CNT_INTVAL },
+       { "LED: Channel A: FX2",                148 | CNT_INTVAL },
+
+       { "LED: Channel B: >",                  2   | CNT_INTVAL },
+       { "LED: Channel B: <",                  3   | CNT_INTVAL },
+       { "LED: Channel B: Meter 1",            89  | CNT_INTVAL },
+       { "LED: Channel B: Meter 2",            90  | CNT_INTVAL },
+       { "LED: Channel B: Meter 3",            91  | CNT_INTVAL },
+       { "LED: Channel B: Meter 4",            92  | CNT_INTVAL },
+       { "LED: Channel B: Meter 5",            93  | CNT_INTVAL },
+       { "LED: Channel B: Meter 6",            94  | CNT_INTVAL },
+       { "LED: Channel B: Meter clip",         95  | CNT_INTVAL },
+       { "LED: Channel B: Active",             122 | CNT_INTVAL },
+       { "LED: Channel B: Cue",                125 | CNT_INTVAL },
+       { "LED: Channel B: FX1",                147 | CNT_INTVAL },
+       { "LED: Channel B: FX2",                146 | CNT_INTVAL },
+
+       { "LED: Channel C: >",                  6   | CNT_INTVAL },
+       { "LED: Channel C: <",                  7   | CNT_INTVAL },
+       { "LED: Channel C: Meter 1",            105 | CNT_INTVAL },
+       { "LED: Channel C: Meter 2",            106 | CNT_INTVAL },
+       { "LED: Channel C: Meter 3",            107 | CNT_INTVAL },
+       { "LED: Channel C: Meter 4",            108 | CNT_INTVAL },
+       { "LED: Channel C: Meter 5",            109 | CNT_INTVAL },
+       { "LED: Channel C: Meter 6",            110 | CNT_INTVAL },
+       { "LED: Channel C: Meter clip",         111 | CNT_INTVAL },
+       { "LED: Channel C: Active",             115 | CNT_INTVAL },
+       { "LED: Channel C: Cue",                117 | CNT_INTVAL },
+       { "LED: Channel C: FX1",                151 | CNT_INTVAL },
+       { "LED: Channel C: FX2",                150 | CNT_INTVAL },
+
+       { "LED: Channel D: >",                  0   | CNT_INTVAL },
+       { "LED: Channel D: <",                  1   | CNT_INTVAL },
+       { "LED: Channel D: Meter 1",            81  | CNT_INTVAL },
+       { "LED: Channel D: Meter 2",            82  | CNT_INTVAL },
+       { "LED: Channel D: Meter 3",            83  | CNT_INTVAL },
+       { "LED: Channel D: Meter 4",            84  | CNT_INTVAL },
+       { "LED: Channel D: Meter 5",            85  | CNT_INTVAL },
+       { "LED: Channel D: Meter 6",            86  | CNT_INTVAL },
+       { "LED: Channel D: Meter clip",         87  | CNT_INTVAL },
+       { "LED: Channel D: Active",             123 | CNT_INTVAL },
+       { "LED: Channel D: Cue",                124 | CNT_INTVAL },
+       { "LED: Channel D: FX1",                145 | CNT_INTVAL },
+       { "LED: Channel D: FX2",                144 | CNT_INTVAL },
+
+       { "LED: Deck A: 1 (blue)",              22  | CNT_INTVAL },
+       { "LED: Deck A: 1 (green)",             23  | CNT_INTVAL },
+       { "LED: Deck A: 2 (blue)",              20  | CNT_INTVAL },
+       { "LED: Deck A: 2 (green)",             21  | CNT_INTVAL },
+       { "LED: Deck A: 3 (blue)",              18  | CNT_INTVAL },
+       { "LED: Deck A: 3 (green)",             19  | CNT_INTVAL },
+       { "LED: Deck A: 4 (blue)",              16  | CNT_INTVAL },
+       { "LED: Deck A: 4 (green)",             17  | CNT_INTVAL },
+       { "LED: Deck A: Load",                  44  | CNT_INTVAL },
+       { "LED: Deck A: Deck C button",         45  | CNT_INTVAL },
+       { "LED: Deck A: In",                    47  | CNT_INTVAL },
+       { "LED: Deck A: Out",                   46  | CNT_INTVAL },
+       { "LED: Deck A: Shift",                 24  | CNT_INTVAL },
+       { "LED: Deck A: Sync",                  27  | CNT_INTVAL },
+       { "LED: Deck A: Cue",                   26  | CNT_INTVAL },
+       { "LED: Deck A: Play",                  25  | CNT_INTVAL },
+       { "LED: Deck A: Tempo up",              33  | CNT_INTVAL },
+       { "LED: Deck A: Tempo down",            32  | CNT_INTVAL },
+       { "LED: Deck A: Master",                34  | CNT_INTVAL },
+       { "LED: Deck A: Keylock",               35  | CNT_INTVAL },
+       { "LED: Deck A: Deck A",                37  | CNT_INTVAL },
+       { "LED: Deck A: Deck C",                36  | CNT_INTVAL },
+       { "LED: Deck A: Samples",               38  | CNT_INTVAL },
+       { "LED: Deck A: On Air",                39  | CNT_INTVAL },
+       { "LED: Deck A: Sample 1",              31  | CNT_INTVAL },
+       { "LED: Deck A: Sample 2",              30  | CNT_INTVAL },
+       { "LED: Deck A: Sample 3",              29  | CNT_INTVAL },
+       { "LED: Deck A: Sample 4",              28  | CNT_INTVAL },
+       { "LED: Deck A: Digit 1 - A",           55  | CNT_INTVAL },
+       { "LED: Deck A: Digit 1 - B",           54  | CNT_INTVAL },
+       { "LED: Deck A: Digit 1 - C",           53  | CNT_INTVAL },
+       { "LED: Deck A: Digit 1 - D",           52  | CNT_INTVAL },
+       { "LED: Deck A: Digit 1 - E",           51  | CNT_INTVAL },
+       { "LED: Deck A: Digit 1 - F",           50  | CNT_INTVAL },
+       { "LED: Deck A: Digit 1 - G",           49  | CNT_INTVAL },
+       { "LED: Deck A: Digit 1 - dot",         48  | CNT_INTVAL },
+       { "LED: Deck A: Digit 2 - A",           63  | CNT_INTVAL },
+       { "LED: Deck A: Digit 2 - B",           62  | CNT_INTVAL },
+       { "LED: Deck A: Digit 2 - C",           61  | CNT_INTVAL },
+       { "LED: Deck A: Digit 2 - D",           60  | CNT_INTVAL },
+       { "LED: Deck A: Digit 2 - E",           59  | CNT_INTVAL },
+       { "LED: Deck A: Digit 2 - F",           58  | CNT_INTVAL },
+       { "LED: Deck A: Digit 2 - G",           57  | CNT_INTVAL },
+       { "LED: Deck A: Digit 2 - dot",         56  | CNT_INTVAL },
+
+       { "LED: Deck B: 1 (blue)",              78  | CNT_INTVAL },
+       { "LED: Deck B: 1 (green)",             79  | CNT_INTVAL },
+       { "LED: Deck B: 2 (blue)",              76  | CNT_INTVAL },
+       { "LED: Deck B: 2 (green)",             77  | CNT_INTVAL },
+       { "LED: Deck B: 3 (blue)",              74  | CNT_INTVAL },
+       { "LED: Deck B: 3 (green)",             75  | CNT_INTVAL },
+       { "LED: Deck B: 4 (blue)",              72  | CNT_INTVAL },
+       { "LED: Deck B: 4 (green)",             73  | CNT_INTVAL },
+       { "LED: Deck B: Load",                  180 | CNT_INTVAL },
+       { "LED: Deck B: Deck D button",         181 | CNT_INTVAL },
+       { "LED: Deck B: In",                    183 | CNT_INTVAL },
+       { "LED: Deck B: Out",                   182 | CNT_INTVAL },
+       { "LED: Deck B: Shift",                 64  | CNT_INTVAL },
+       { "LED: Deck B: Sync",                  67  | CNT_INTVAL },
+       { "LED: Deck B: Cue",                   66  | CNT_INTVAL },
+       { "LED: Deck B: Play",                  65  | CNT_INTVAL },
+       { "LED: Deck B: Tempo up",              185 | CNT_INTVAL },
+       { "LED: Deck B: Tempo down",            184 | CNT_INTVAL },
+       { "LED: Deck B: Master",                186 | CNT_INTVAL },
+       { "LED: Deck B: Keylock",               187 | CNT_INTVAL },
+       { "LED: Deck B: Deck B",                189 | CNT_INTVAL },
+       { "LED: Deck B: Deck D",                188 | CNT_INTVAL },
+       { "LED: Deck B: Samples",               190 | CNT_INTVAL },
+       { "LED: Deck B: On Air",                191 | CNT_INTVAL },
+       { "LED: Deck B: Sample 1",              71  | CNT_INTVAL },
+       { "LED: Deck B: Sample 2",              70  | CNT_INTVAL },
+       { "LED: Deck B: Sample 3",              69  | CNT_INTVAL },
+       { "LED: Deck B: Sample 4",              68  | CNT_INTVAL },
+       { "LED: Deck B: Digit 1 - A",           175 | CNT_INTVAL },
+       { "LED: Deck B: Digit 1 - B",           174 | CNT_INTVAL },
+       { "LED: Deck B: Digit 1 - C",           173 | CNT_INTVAL },
+       { "LED: Deck B: Digit 1 - D",           172 | CNT_INTVAL },
+       { "LED: Deck B: Digit 1 - E",           171 | CNT_INTVAL },
+       { "LED: Deck B: Digit 1 - F",           170 | CNT_INTVAL },
+       { "LED: Deck B: Digit 1 - G",           169 | CNT_INTVAL },
+       { "LED: Deck B: Digit 1 - dot",         168 | CNT_INTVAL },
+       { "LED: Deck B: Digit 2 - A",           167 | CNT_INTVAL },
+       { "LED: Deck B: Digit 2 - B",           166 | CNT_INTVAL },
+       { "LED: Deck B: Digit 2 - C",           165 | CNT_INTVAL },
+       { "LED: Deck B: Digit 2 - D",           164 | CNT_INTVAL },
+       { "LED: Deck B: Digit 2 - E",           163 | CNT_INTVAL },
+       { "LED: Deck B: Digit 2 - F",           162 | CNT_INTVAL },
+       { "LED: Deck B: Digit 2 - G",           161 | CNT_INTVAL },
+       { "LED: Deck B: Digit 2 - dot",         160 | CNT_INTVAL },
+
+       { "LED: FX1: dry/wet",                  153 | CNT_INTVAL },
+       { "LED: FX1: 1",                        154 | CNT_INTVAL },
+       { "LED: FX1: 2",                        155 | CNT_INTVAL },
+       { "LED: FX1: 3",                        156 | CNT_INTVAL },
+       { "LED: FX1: Mode",                     157 | CNT_INTVAL },
+       { "LED: FX2: dry/wet",                  129 | CNT_INTVAL },
+       { "LED: FX2: 1",                        130 | CNT_INTVAL },
+       { "LED: FX2: 2",                        131 | CNT_INTVAL },
+       { "LED: FX2: 3",                        132 | CNT_INTVAL },
+       { "LED: FX2: Mode",                     133 | CNT_INTVAL },
+};
+
 static int __devinit add_controls(struct caiaq_controller *c, int num,
                                  struct snd_usb_caiaqdev *dev)
 {
@@ -354,6 +547,11 @@ int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev)
                ret = add_controls(kontrolx1_controller,
                        ARRAY_SIZE(kontrolx1_controller), dev);
                break;
+
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
+               ret = add_controls(kontrols4_controller,
+                       ARRAY_SIZE(kontrols4_controller), dev);
+               break;
        }
 
        return ret;
index cdfb856bddd261c5717fe6845b5a210fa20a7f75..6480c3283c05a0082e21c31788ea54c0e7ccb7b4 100644 (file)
@@ -36,7 +36,7 @@
 #include "input.h"
 
 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
-MODULE_DESCRIPTION("caiaq USB audio, version 1.3.21");
+MODULE_DESCRIPTION("caiaq USB audio");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
                         "{Native Instruments, RigKontrol3},"
@@ -48,7 +48,8 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
                         "{Native Instruments, Audio 8 DJ},"
                         "{Native Instruments, Session I/O},"
                         "{Native Instruments, GuitarRig mobile}"
-                        "{Native Instruments, Traktor Kontrol X1}");
+                        "{Native Instruments, Traktor Kontrol X1}"
+                        "{Native Instruments, Traktor Kontrol S4}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
 static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
@@ -134,6 +135,11 @@ static struct usb_device_id snd_usb_id_table[] = {
                .idVendor =     USB_VID_NATIVEINSTRUMENTS,
                .idProduct =    USB_PID_TRAKTORKONTROLX1
        },
+       {
+               .match_flags =  USB_DEVICE_ID_MATCH_DEVICE,
+               .idVendor =     USB_VID_NATIVEINSTRUMENTS,
+               .idProduct =    USB_PID_TRAKTORKONTROLS4
+       },
        { /* terminator */ }
 };
 
index f1117ecc84fdf9d7b6133ae3fd96ed395f073109..e3d8a3efb35b5350de0f60789f4834bf19494f96 100644 (file)
@@ -16,6 +16,7 @@
 #define USB_PID_SESSIONIO              0x1915
 #define USB_PID_GUITARRIGMOBILE                0x0d8d
 #define USB_PID_TRAKTORKONTROLX1       0x2305
+#define USB_PID_TRAKTORKONTROLS4       0xbaff
 
 #define EP1_BUFSIZE 64
 #define EP4_BUFSIZE 512
@@ -99,13 +100,14 @@ struct snd_usb_caiaqdev {
        struct snd_pcm_substream *sub_capture[MAX_STREAMS];
 
        /* Controls */
-       unsigned char control_state[64];
+       unsigned char control_state[256];
+       unsigned char ep8_out_buf[2];
 
        /* Linux input */
 #ifdef CONFIG_SND_USB_CAIAQ_INPUT
        struct input_dev *input_dev;
        char phys[64];                  /* physical device path */
-       unsigned short keycode[64];
+       unsigned short keycode[128];
        struct urb *ep4_in_urb;
        unsigned char ep4_in_buf[EP4_BUFSIZE];
 #endif
index dcb620796d9ef5c14ba7f52ab3686b1ae0c1969a..4432ef7a70a9ad184066d4d0b63ff594c442acdf 100644 (file)
@@ -67,7 +67,12 @@ static unsigned short keycode_kore[] = {
        KEY_BRL_DOT5
 };
 
-#define KONTROLX1_INPUTS 40
+#define KONTROLX1_INPUTS       (40)
+#define KONTROLS4_BUTTONS      (12 * 8)
+#define KONTROLS4_AXIS         (46)
+
+#define KONTROLS4_BUTTON(X)    ((X) + BTN_MISC)
+#define KONTROLS4_ABS(X)       ((X) + ABS_HAT0X)
 
 #define DEG90          (range / 2)
 #define DEG180         (range)
@@ -139,6 +144,13 @@ static unsigned int decode_erp(unsigned char a, unsigned char b)
 #undef HIGH_PEAK
 #undef LOW_PEAK
 
+static inline void snd_caiaq_input_report_abs(struct snd_usb_caiaqdev *dev,
+                                             int axis, const unsigned char *buf,
+                                             int offset)
+{
+       input_report_abs(dev->input_dev, axis,
+                        (buf[offset * 2] << 8) | buf[offset * 2 + 1]);
+}
 
 static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev,
                                        const unsigned char *buf,
@@ -148,36 +160,30 @@ static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev,
 
        switch (dev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
-               input_report_abs(input_dev, ABS_X, (buf[4] << 8) | buf[5]);
-               input_report_abs(input_dev, ABS_Y, (buf[0] << 8) | buf[1]);
-               input_report_abs(input_dev, ABS_Z, (buf[2] << 8) | buf[3]);
-               input_sync(input_dev);
+               snd_caiaq_input_report_abs(dev, ABS_X, buf, 2);
+               snd_caiaq_input_report_abs(dev, ABS_Y, buf, 0);
+               snd_caiaq_input_report_abs(dev, ABS_Z, buf, 1);
                break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
-               input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]);
-               input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]);
-               input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]);
-               input_sync(input_dev);
-               break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
-               input_report_abs(input_dev, ABS_X, (buf[0] << 8) | buf[1]);
-               input_report_abs(input_dev, ABS_Y, (buf[2] << 8) | buf[3]);
-               input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]);
-               input_sync(input_dev);
+               snd_caiaq_input_report_abs(dev, ABS_X, buf, 0);
+               snd_caiaq_input_report_abs(dev, ABS_Y, buf, 1);
+               snd_caiaq_input_report_abs(dev, ABS_Z, buf, 2);
                break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
-               input_report_abs(input_dev, ABS_HAT0X, (buf[8] << 8)  | buf[9]);
-               input_report_abs(input_dev, ABS_HAT0Y, (buf[4] << 8)  | buf[5]);
-               input_report_abs(input_dev, ABS_HAT1X, (buf[12] << 8) | buf[13]);
-               input_report_abs(input_dev, ABS_HAT1Y, (buf[2] << 8)  | buf[3]);
-               input_report_abs(input_dev, ABS_HAT2X, (buf[14] << 8) | buf[15]);
-               input_report_abs(input_dev, ABS_HAT2Y, (buf[0] << 8)  | buf[1]);
-               input_report_abs(input_dev, ABS_HAT3X, (buf[10] << 8) | buf[11]);
-               input_report_abs(input_dev, ABS_HAT3Y, (buf[6] << 8)  | buf[7]);
-               input_sync(input_dev);
+               snd_caiaq_input_report_abs(dev, ABS_HAT0X, buf, 4);
+               snd_caiaq_input_report_abs(dev, ABS_HAT0Y, buf, 2);
+               snd_caiaq_input_report_abs(dev, ABS_HAT1X, buf, 6);
+               snd_caiaq_input_report_abs(dev, ABS_HAT1Y, buf, 1);
+               snd_caiaq_input_report_abs(dev, ABS_HAT2X, buf, 7);
+               snd_caiaq_input_report_abs(dev, ABS_HAT2Y, buf, 0);
+               snd_caiaq_input_report_abs(dev, ABS_HAT3X, buf, 5);
+               snd_caiaq_input_report_abs(dev, ABS_HAT3Y, buf, 3);
                break;
        }
+
+       input_sync(input_dev);
 }
 
 static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev,
@@ -250,6 +256,150 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev,
        input_sync(input_dev);
 }
 
+#define TKS4_MSGBLOCK_SIZE     16
+
+static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *dev,
+                                       const unsigned char *buf,
+                                       unsigned int len)
+{
+       while (len) {
+               unsigned int i, block_id = (buf[0] << 8) | buf[1];
+
+               switch (block_id) {
+               case 0:
+                       /* buttons */
+                       for (i = 0; i < KONTROLS4_BUTTONS; i++)
+                               input_report_key(dev->input_dev, KONTROLS4_BUTTON(i),
+                                                (buf[4 + (i / 8)] >> (i % 8)) & 1);
+                       break;
+
+               case 1:
+                       /* left wheel */
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(36), buf[9] | ((buf[8] & 0x3) << 8));
+                       /* right wheel */
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(37), buf[13] | ((buf[12] & 0x3) << 8));
+
+                       /* rotary encoders */
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(38), buf[3] & 0xf);
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(39), buf[4] >> 4);
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(40), buf[4] & 0xf);
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(41), buf[5] >> 4);
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(42), buf[5] & 0xf);
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(43), buf[6] >> 4);
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(44), buf[6] & 0xf);
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(45), buf[7] >> 4);
+                       input_report_abs(dev->input_dev, KONTROLS4_ABS(46), buf[7] & 0xf);
+
+                       break;
+               case 2:
+                       /* Volume Fader Channel D */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(0), buf, 1);
+                       /* Volume Fader Channel B */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(1), buf, 2);
+                       /* Volume Fader Channel A */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(2), buf, 3);
+                       /* Volume Fader Channel C */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(3), buf, 4);
+                       /* Loop Volume */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(4), buf, 6);
+                       /* Crossfader */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(7), buf, 7);
+
+                       break;
+
+               case 3:
+                       /* Tempo Fader R */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(6), buf, 3);
+                       /* Tempo Fader L */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(5), buf, 4);
+                       /* Mic Volume */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(8), buf, 6);
+                       /* Cue Mix */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(9), buf, 7);
+
+                       break;
+
+               case 4:
+                       /* Wheel distance sensor L */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(10), buf, 1);
+                       /* Wheel distance sensor R */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(11), buf, 2);
+                       /* Channel D EQ - Filter */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(12), buf, 3);
+                       /* Channel D EQ - Low */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(13), buf, 4);
+                       /* Channel D EQ - Mid */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(14), buf, 5);
+                       /* Channel D EQ - Hi */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(15), buf, 6);
+                       /* FX2 - dry/wet */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(16), buf, 7);
+
+                       break;
+
+               case 5:
+                       /* FX2 - 1 */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(17), buf, 1);
+                       /* FX2 - 2 */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(18), buf, 2);
+                       /* FX2 - 3 */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(19), buf, 3);
+                       /* Channel B EQ - Filter */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(20), buf, 4);
+                       /* Channel B EQ - Low */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(21), buf, 5);
+                       /* Channel B EQ - Mid */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(22), buf, 6);
+                       /* Channel B EQ - Hi */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(23), buf, 7);
+
+                       break;
+
+               case 6:
+                       /* Channel A EQ - Filter */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(24), buf, 1);
+                       /* Channel A EQ - Low */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(25), buf, 2);
+                       /* Channel A EQ - Mid */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(26), buf, 3);
+                       /* Channel A EQ - Hi */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(27), buf, 4);
+                       /* Channel C EQ - Filter */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(28), buf, 5);
+                       /* Channel C EQ - Low */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(29), buf, 6);
+                       /* Channel C EQ - Mid */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(30), buf, 7);
+
+                       break;
+
+               case 7:
+                       /* Channel C EQ - Hi */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(31), buf, 1);
+                       /* FX1 - wet/dry */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(32), buf, 2);
+                       /* FX1 - 1 */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(33), buf, 3);
+                       /* FX1 - 2 */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(34), buf, 4);
+                       /* FX1 - 3 */
+                       snd_caiaq_input_report_abs(dev, KONTROLS4_ABS(35), buf, 5);
+
+                       break;
+
+               default:
+                       debug("%s(): bogus block (id %d)\n",
+                               __func__, block_id);
+                       return;
+               }
+
+               len -= TKS4_MSGBLOCK_SIZE;
+               buf += TKS4_MSGBLOCK_SIZE;
+       }
+
+       input_sync(dev->input_dev);
+}
+
 static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)
 {
        struct snd_usb_caiaqdev *dev = urb->context;
@@ -259,11 +409,11 @@ static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)
        if (urb->status || !dev || urb != dev->ep4_in_urb)
                return;
 
-       if (urb->actual_length < 24)
-               goto requeue;
-
        switch (dev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+               if (urb->actual_length < 24)
+                       goto requeue;
+
                if (buf[0] & 0x3)
                        snd_caiaq_input_read_io(dev, buf + 1, 7);
 
@@ -271,6 +421,10 @@ static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)
                        snd_caiaq_input_read_analog(dev, buf + 8, 16);
 
                break;
+
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
+               snd_usb_caiaq_tks4_dispatch(dev, buf, urb->actual_length);
+               break;
        }
 
 requeue:
@@ -289,6 +443,7 @@ static int snd_usb_caiaq_input_open(struct input_dev *idev)
 
        switch (dev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
                if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0)
                        return -EIO;
                break;
@@ -306,6 +461,7 @@ static void snd_usb_caiaq_input_close(struct input_dev *idev)
 
        switch (dev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
                usb_kill_urb(dev->ep4_in_urb);
                break;
        }
@@ -456,6 +612,46 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
                snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
 
                break;
+
+       case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLS4):
+               input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+               BUILD_BUG_ON(sizeof(dev->keycode) < KONTROLS4_BUTTONS);
+               for (i = 0; i < KONTROLS4_BUTTONS; i++)
+                       dev->keycode[i] = KONTROLS4_BUTTON(i);
+               input->keycodemax = KONTROLS4_BUTTONS;
+
+               for (i = 0; i < KONTROLS4_AXIS; i++) {
+                       int axis = KONTROLS4_ABS(i);
+                       input->absbit[BIT_WORD(axis)] |= BIT_MASK(axis);
+               }
+
+               /* 36 analog potentiometers and faders */
+               for (i = 0; i < 36; i++)
+                       input_set_abs_params(input, KONTROLS4_ABS(i), 0, 0xfff, 0, 10);
+
+               /* 2 encoder wheels */
+               input_set_abs_params(input, KONTROLS4_ABS(36), 0, 0x3ff, 0, 1);
+               input_set_abs_params(input, KONTROLS4_ABS(37), 0, 0x3ff, 0, 1);
+
+               /* 9 rotary encoders */
+               for (i = 0; i < 9; i++)
+                       input_set_abs_params(input, KONTROLS4_ABS(38+i), 0, 0xf, 0, 1);
+
+               dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!dev->ep4_in_urb) {
+                       ret = -ENOMEM;
+                       goto exit_free_idev;
+               }
+
+               usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev,
+                                 usb_rcvbulkpipe(usb_dev, 0x4),
+                                 dev->ep4_in_buf, EP4_BUFSIZE,
+                                 snd_usb_caiaq_ep4_reply_dispatch, dev);
+
+               snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
+
+               break;
+
        default:
                /* no input methods supported on this device */
                goto exit_free_idev;
index 4eabafa5b037db66b250db64cc0ce05aa783f595..800f7cb4f251cd77ae246c5dee2acaed9de587f4 100644 (file)
@@ -300,9 +300,13 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
 
        *rchip = NULL;
 
-       if (snd_usb_get_speed(dev) != USB_SPEED_LOW &&
-           snd_usb_get_speed(dev) != USB_SPEED_FULL &&
-           snd_usb_get_speed(dev) != USB_SPEED_HIGH) {
+       switch (snd_usb_get_speed(dev)) {
+       case USB_SPEED_LOW:
+       case USB_SPEED_FULL:
+       case USB_SPEED_HIGH:
+       case USB_SPEED_SUPER:
+               break;
+       default:
                snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev));
                return -ENXIO;
        }
@@ -378,11 +382,22 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
        if (len < sizeof(card->longname))
                usb_make_path(dev, card->longname + len, sizeof(card->longname) - len);
 
-       strlcat(card->longname,
-               snd_usb_get_speed(dev) == USB_SPEED_LOW ? ", low speed" :
-               snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" :
-               ", high speed",
-               sizeof(card->longname));
+       switch (snd_usb_get_speed(dev)) {
+       case USB_SPEED_LOW:
+               strlcat(card->longname, ", low speed", sizeof(card->longname));
+               break;
+       case USB_SPEED_FULL:
+               strlcat(card->longname, ", full speed", sizeof(card->longname));
+               break;
+       case USB_SPEED_HIGH:
+               strlcat(card->longname, ", high speed", sizeof(card->longname));
+               break;
+       case USB_SPEED_SUPER:
+               strlcat(card->longname, ", super speed", sizeof(card->longname));
+               break;
+       default:
+               break;
+       }
 
        snd_usb_audio_create_proc(chip);
 
index ef0a07e34844ae4d53ffd12e54b16a203da02a19..b0ef9f5018960db6a502170a05e73044864e0c0e 100644 (file)
@@ -405,8 +405,6 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
                        break;
                case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */
                case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
-               case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra 8 */
-               case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */
                        /* doesn't set the sample rate attribute, but supports it */
                        fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE;
                        break;
index d48d6f8f6ac9747343b6c3b7c6e5d3760464c7e4..f280c1903c25bdaa0b20e8456b6753c3dc5edcfb 100644 (file)
@@ -103,11 +103,16 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
 unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip,
                                         struct usb_host_interface *alts)
 {
-       if (snd_usb_get_speed(chip->dev) == USB_SPEED_HIGH &&
-           get_endpoint(alts, 0)->bInterval >= 1 &&
-           get_endpoint(alts, 0)->bInterval <= 4)
-               return get_endpoint(alts, 0)->bInterval - 1;
-       else
-               return 0;
+       switch (snd_usb_get_speed(chip->dev)) {
+       case USB_SPEED_HIGH:
+       case USB_SPEED_SUPER:
+               if (get_endpoint(alts, 0)->bInterval >= 1 &&
+                   get_endpoint(alts, 0)->bInterval <= 4)
+                       return get_endpoint(alts, 0)->bInterval - 1;
+               break;
+       default:
+               break;
+       }
+       return 0;
 }
 
index b9c2bc65f51ae7bd24da9adfaf8b62c241c2846f..25bce7e5b1afd09cf1fdac8ad7d5f77e61c0eca9 100644 (file)
@@ -784,7 +784,7 @@ static struct usb_protocol_ops snd_usbmidi_novation_ops = {
 };
 
 /*
- * "raw" protocol: used by the MOTU FastLane.
+ * "raw" protocol: just move raw MIDI bytes from/to the endpoint
  */
 
 static void snd_usbmidi_raw_input(struct snd_usb_midi_in_endpoint* ep,
@@ -834,7 +834,14 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep,
 
        if (!ep->ports[0].active)
                return;
-       count = snd_usb_get_speed(ep->umidi->dev) == USB_SPEED_HIGH ? 1 : 2;
+       switch (snd_usb_get_speed(ep->umidi->dev)) {
+       case USB_SPEED_HIGH:
+       case USB_SPEED_SUPER:
+               count = 1;
+               break;
+       default:
+               count = 2;
+       }
        count = snd_rawmidi_transmit(ep->ports[0].substream,
                                     urb->transfer_buffer,
                                     count);
@@ -2115,7 +2122,7 @@ int snd_usbmidi_create(struct snd_card *card,
                umidi->usb_protocol_ops = &snd_usbmidi_novation_ops;
                err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
                break;
-       case QUIRK_MIDI_FASTLANE:
+       case QUIRK_MIDI_RAW_BYTES:
                umidi->usb_protocol_ops = &snd_usbmidi_raw_ops;
                /*
                 * Interface 1 contains isochronous endpoints, but with the same
@@ -2126,7 +2133,8 @@ int snd_usbmidi_create(struct snd_card *card,
                 * interface 0, so we have to make sure that the USB core looks
                 * again at interface 0 by calling usb_set_interface() on it.
                 */
-               usb_set_interface(umidi->dev, 0, 0);
+               if (umidi->usb_id == USB_ID(0x07fd, 0x0001)) /* MOTU Fastlane */
+                       usb_set_interface(umidi->dev, 0, 0);
                err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
                break;
        case QUIRK_MIDI_EMAGIC:
index 3ed3901369ce1a9ca58473ecef450623cf95a7b2..f2d74d654b3c3302b6dbe353ae8be95484c16ccf 100644 (file)
@@ -759,8 +759,6 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
  */
 static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
 {
-       struct snd_usb_audio *chip = cval->mixer->chip;
-
        /* for failsafe */
        cval->min = default_min;
        cval->max = cval->min + 1;
@@ -783,7 +781,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
                if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 ||
                    get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) {
                        snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n",
-                                  cval->id, snd_usb_ctrl_intf(chip), cval->control, cval->id);
+                                  cval->id, snd_usb_ctrl_intf(cval->mixer->chip), cval->control, cval->id);
                        return -EINVAL;
                }
                if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) {
@@ -1642,9 +1640,10 @@ static int mixer_ctl_selector_info(struct snd_kcontrol *kcontrol, struct snd_ctl
        uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
        uinfo->count = 1;
        uinfo->value.enumerated.items = cval->max;
-       if ((int)uinfo->value.enumerated.item >= cval->max)
+       if (uinfo->value.enumerated.item >= cval->max)
                uinfo->value.enumerated.item = cval->max - 1;
-       strcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item]);
+       strlcpy(uinfo->value.enumerated.name, itemlist[uinfo->value.enumerated.item],
+               sizeof(uinfo->value.enumerated.name));
        return 0;
 }
 
index e7df1e5e3f2ecd36b60ba07944dfeac1d14ff85f..7dae05d8783e4274266bb5c867e534b342e18614 100644 (file)
@@ -60,6 +60,7 @@ static const struct rc_config {
        { USB_ID(0x041e, 0x3000), 0, 1, 2, 1,  18, 0x0013 }, /* Extigy       */
        { USB_ID(0x041e, 0x3020), 2, 1, 6, 6,  18, 0x0013 }, /* Audigy 2 NX  */
        { USB_ID(0x041e, 0x3040), 2, 2, 6, 6,  2,  0x6e91 }, /* Live! 24-bit */
+       { USB_ID(0x041e, 0x3042), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi */
        { USB_ID(0x041e, 0x3048), 2, 2, 6, 6,  2,  0x6e91 }, /* Toshiba SB0500 */
 };
 
index 3b5135c930628fc092cad54e67ce2a7645c59c02..f49756c1b83709716d8a60a8341dccb7c5f10f4f 100644 (file)
@@ -466,7 +466,7 @@ static int hw_check_valid_format(struct snd_usb_substream *subs,
                return 0;
        }
        /* check whether the period time is >= the data packet interval */
-       if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) {
+       if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) {
                ptime = 125 * (1 << fp->datainterval);
                if (ptime > pt->max || (ptime == pt->max && pt->openmax)) {
                        hwc_debug("   > check: ptime %u > max %u\n", ptime, pt->max);
@@ -734,7 +734,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
        }
 
        param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME;
-       if (snd_usb_get_speed(subs->dev) != USB_SPEED_HIGH)
+       if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
                /* full speed devices have fixed data packet interval */
                ptmin = 1000;
        if (ptmin == 1000)
index f5e3f356b95ff4277e98ad5ad60518f2cac15aa7..3c650ab3c91de8e2edb87e3e0b03ce716b17d894 100644 (file)
@@ -107,7 +107,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s
                        }
                        snd_iprintf(buffer, "\n");
                }
-               if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH)
+               if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL)
                        snd_iprintf(buffer, "    Data packet interval: %d us\n",
                                    125 * (1 << fp->datainterval));
                // snd_iprintf(buffer, "    Max Packet Size = %d\n", fp->maxpacksize);
index 2e8003f98fca9bd141f655aa619abb4009ae9553..ad7079d1676cd1607b7cc161b4c2dfff6651a5eb 100644 (file)
@@ -240,9 +240,21 @@ YAMAHA_DEVICE(0x104f, NULL),
 YAMAHA_DEVICE(0x1050, NULL),
 YAMAHA_DEVICE(0x1051, NULL),
 YAMAHA_DEVICE(0x1052, NULL),
+YAMAHA_INTERFACE(0x1053, 0, NULL),
+YAMAHA_INTERFACE(0x1054, 0, NULL),
+YAMAHA_DEVICE(0x1055, NULL),
+YAMAHA_DEVICE(0x1056, NULL),
+YAMAHA_DEVICE(0x1057, NULL),
+YAMAHA_DEVICE(0x1058, NULL),
+YAMAHA_DEVICE(0x1059, NULL),
+YAMAHA_DEVICE(0x105a, NULL),
+YAMAHA_DEVICE(0x105b, NULL),
+YAMAHA_DEVICE(0x105c, NULL),
+YAMAHA_DEVICE(0x105d, NULL),
 YAMAHA_DEVICE(0x2000, "DGP-7"),
 YAMAHA_DEVICE(0x2001, "DGP-5"),
 YAMAHA_DEVICE(0x2002, NULL),
+YAMAHA_DEVICE(0x2003, NULL),
 YAMAHA_DEVICE(0x5000, "CS1D"),
 YAMAHA_DEVICE(0x5001, "DSP1D"),
 YAMAHA_DEVICE(0x5002, "DME32"),
@@ -1135,12 +1147,35 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                .type = QUIRK_MIDI_STANDARD_INTERFACE
        }
 },
+{
+       /* has ID 0x0066 when not in "Advanced Driver" mode */
+       USB_DEVICE(0x0582, 0x0064),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               /* .vendor_name = "EDIROL", */
+               /* .product_name = "PCR-1", */
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 {
        /* has ID 0x0067 when not in "Advanced Driver" mode */
        USB_DEVICE(0x0582, 0x0065),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-               .vendor_name = "EDIROL",
-               .product_name = "PCR-1",
+               /* .vendor_name = "EDIROL", */
+               /* .product_name = "PCR-1", */
                .ifnum = 0,
                .type = QUIRK_MIDI_FIXED_ENDPOINT,
                .data = & (const struct snd_usb_midi_endpoint_info) {
@@ -1525,6 +1560,50 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+{
+       /* has ID 0x0110 when not in Advanced Driver mode */
+       USB_DEVICE_VENDOR_SPEC(0x0582, 0x010f),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               /* .vendor_name = "Roland", */
+               /* .product_name = "A-PRO", */
+               .ifnum = 1,
+               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+               .data = & (const struct snd_usb_midi_endpoint_info) {
+                       .out_cables = 0x0003,
+                       .in_cables  = 0x0007
+               }
+       }
+},
+{
+       USB_DEVICE(0x0582, 0x0113),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               /* .vendor_name = "BOSS", */
+               /* .product_name = "ME-25", */
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+                               .data = & (const struct snd_usb_midi_endpoint_info) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 
 /* Guillemot devices */
 {
@@ -1830,7 +1909,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        USB_DEVICE(0x0763, 0x2080),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
                /* .vendor_name = "M-Audio", */
-               /* .product_name = "Fast Track Ultra 8", */
+               /* .product_name = "Fast Track Ultra", */
                .ifnum = QUIRK_ANY_INTERFACE,
                .type = QUIRK_COMPOSITE,
                .data = & (const struct snd_usb_audio_quirk[]) {
@@ -1840,11 +1919,51 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                        },
                        {
                                .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = & (const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8,
+                                       .iface = 1,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+                                       .endpoint = 0x01,
+                                       .ep_attr = 0x09,
+                                       .rates = SNDRV_PCM_RATE_44100 |
+                                                SNDRV_PCM_RATE_48000 |
+                                                SNDRV_PCM_RATE_88200 |
+                                                SNDRV_PCM_RATE_96000,
+                                       .rate_min = 44100,
+                                       .rate_max = 96000,
+                                       .nr_rates = 4,
+                                       .rate_table = (unsigned int[]) {
+                                               44100, 48000, 88200, 96000
+                                       }
+                               }
                        },
                        {
                                .ifnum = 2,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = & (const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8,
+                                       .iface = 2,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+                                       .endpoint = 0x81,
+                                       .ep_attr = 0x05,
+                                       .rates = SNDRV_PCM_RATE_44100 |
+                                                SNDRV_PCM_RATE_48000 |
+                                                SNDRV_PCM_RATE_88200 |
+                                                SNDRV_PCM_RATE_96000,
+                                       .rate_min = 44100,
+                                       .rate_max = 96000,
+                                       .nr_rates = 4,
+                                       .rate_table = (unsigned int[]) {
+                                               44100, 48000, 88200, 96000
+                                       }
+                               }
                        },
                        /* interface 3 (MIDI) is standard compliant */
                        {
@@ -1867,11 +1986,51 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                        },
                        {
                                .ifnum = 1,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = & (const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8,
+                                       .iface = 1,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+                                       .endpoint = 0x01,
+                                       .ep_attr = 0x09,
+                                       .rates = SNDRV_PCM_RATE_44100 |
+                                                SNDRV_PCM_RATE_48000 |
+                                                SNDRV_PCM_RATE_88200 |
+                                                SNDRV_PCM_RATE_96000,
+                                       .rate_min = 44100,
+                                       .rate_max = 96000,
+                                       .nr_rates = 4,
+                                       .rate_table = (unsigned int[]) {
+                                                       44100, 48000, 88200, 96000
+                                       }
+                               }
                        },
                        {
                                .ifnum = 2,
-                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = & (const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                       .channels = 8,
+                                       .iface = 2,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+                                       .endpoint = 0x81,
+                                       .ep_attr = 0x05,
+                                       .rates = SNDRV_PCM_RATE_44100 |
+                                                SNDRV_PCM_RATE_48000 |
+                                                SNDRV_PCM_RATE_88200 |
+                                                SNDRV_PCM_RATE_96000,
+                                       .rate_min = 44100,
+                                       .rate_max = 96000,
+                                       .nr_rates = 4,
+                                       .rate_table = (unsigned int[]) {
+                                               44100, 48000, 88200, 96000
+                                       }
+                               }
                        },
                        /* interface 3 (MIDI) is standard compliant */
                        {
@@ -1919,7 +2078,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                .data = & (const struct snd_usb_audio_quirk[]) {
                        {
                                .ifnum = 0,
-                               .type = QUIRK_MIDI_FASTLANE
+                               .type = QUIRK_MIDI_RAW_BYTES
                        },
                        {
                                .ifnum = 1,
@@ -2067,6 +2226,15 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                .type = QUIRK_MIDI_NOVATION
        }
 },
+{
+       USB_DEVICE(0x1235, 0x000e),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               /* .vendor_name = "Novation", */
+               /* .product_name = "Launchpad", */
+               .ifnum = 0,
+               .type = QUIRK_MIDI_RAW_BYTES
+       }
+},
 {
        USB_DEVICE_VENDOR_SPEC(0x1235, 0x4661),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
index 9a9da09586a5581b8fe26eec00d3b5183e3a8469..cf8bf088394bd39431a0cd541720bc6990013c4f 100644 (file)
@@ -287,7 +287,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
                [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk,
                [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk,
                [QUIRK_MIDI_NOVATION] = create_any_midi_quirk,
-               [QUIRK_MIDI_FASTLANE] = create_any_midi_quirk,
+               [QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk,
                [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk,
                [QUIRK_MIDI_CME] = create_any_midi_quirk,
                [QUIRK_MIDI_AKAI] = create_any_midi_quirk,
index de607d4411acf5137edbeeb4e6af45ea0546b67b..8deeaad10f10caa4827288cc41230ce1cc6eb77e 100644 (file)
@@ -244,7 +244,7 @@ int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
        else
                subs->curpacksize = maxsize;
 
-       if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH)
+       if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL)
                packs_per_ms = 8 >> subs->datainterval;
        else
                packs_per_ms = 1;
index 24d3319cc34d0985ace0270be5b7894a3b086c21..db3eb21627eeee5f7c9c062286e5669ed93aff1a 100644 (file)
@@ -70,7 +70,7 @@ enum quirk_type {
        QUIRK_MIDI_YAMAHA,
        QUIRK_MIDI_MIDIMAN,
        QUIRK_MIDI_NOVATION,
-       QUIRK_MIDI_FASTLANE,
+       QUIRK_MIDI_RAW_BYTES,
        QUIRK_MIDI_EMAGIC,
        QUIRK_MIDI_CME,
        QUIRK_MIDI_AKAI,
index 2a528e56afd50db1c7f7cb309e1734c826cef3c2..287ef73b123728dbe4a60c2cf999ac5eeaffea75 100644 (file)
@@ -36,9 +36,9 @@
          plain usx2y alsa mode is able to achieve 64frames, 4periods, but only at the
          cost of easier triggered i.e. aeolus xruns (128 or 256frames,
          2periods works but is useless cause of crackling).
+
  This is a first "proof of concept" implementation.
- Later, funcionalities should migrate to more apropriate places:
+ Later, functionalities should migrate to more apropriate places:
  Userland:
  - The jackd could mmap its float-pcm buffers directly from alsa-lib.
  - alsa-lib could provide power of 2 period sized shaping combined with int/float
@@ -54,7 +54,7 @@
 #include <linux/gfp.h>
 #include "usbusx2yaudio.c"
 
-#if defined(USX2Y_NRPACKS_VARIABLE) || (!defined(USX2Y_NRPACKS_VARIABLE) &&  USX2Y_NRPACKS == 1)
+#if defined(USX2Y_NRPACKS_VARIABLE) || USX2Y_NRPACKS == 1
 
 #include <sound/hwdep.h>