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)
+       &nb