Merge tag 'sound-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 11 Feb 2015 16:51:59 +0000 (08:51 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 11 Feb 2015 16:51:59 +0000 (08:51 -0800)
Pull sound updates from Takashi Iwai:
 "In this batch, you can find lots of cleanups through the whole
  subsystem, as our good New Year's resolution.  Lots of LOCs and
  commits are about LINE6 driver that was promoted finally from staging
  tree, and as usual, there've been widely spread ASoC changes.

  Here some highlights:

  ALSA core changes
   - Embedding struct device into ALSA core structures
   - sequencer core cleanups / fixes
   - PCM msbits constraints cleanups / fixes
   - New SNDRV_PCM_TRIGGER_DRAIN command
   - PCM kerneldoc fixes, header cleanups
   - PCM code cleanups using more standard codes
   - Control notification ID fixes

  Driver cleanups
   - Cleanups of PCI PM callbacks
   - Timer helper usages cleanups
   - Simplification (e.g. argument reduction) of many driver codes

  HD-audio
   - Hotkey and LED support on HP laptops with Realtek codecs
   - Dock station support on HP laptops
   - Toshiba Satellite S50D fixup
   - Enhanced wallclock timestamp handling for HD-audio
   - Componentization to simplify the linkage between i915 and hd-audio
     drivers for Intel HDMI/DP

  USB-audio
   - Akai MPC Element support
   - Enhanced timestamp handling

  ASoC
   - Lots of refactoringin ASoC core, moving drivers to more data driven
     initialization and rationalizing a lot of DAPM usage
   - Much improved handling of CDCLK clocks on Samsung I2S controllers
   - Lots of driver specific cleanups and feature improvements
   - CODEC support for TI PCM514x and TLV320AIC3104 devices
   - Board support for Tegra systems with Realtek RT5677
   - New driver for Maxim max98357a
   - More enhancements / fixes for Intel SST driver

  Others
   - Promotion of LINE6 driver from staging along with lots of rewrites
     and cleanups
   - DT support for old non-ASoC atmel driver
   - oxygen cleanups, XIO2001 init, Studio Evolution SE6x support
   - Emu8000 DRAM size detection fix on ISA(!!) AWE64 boards
   - A few more ak411x fixes for ice1724 boards"

* tag 'sound-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (542 commits)
  ALSA: line6: toneport: Use explicit type for firmware version
  ALSA: line6: Use explicit type for serial number
  ALSA: line6: Return EIO if read/write not successful
  ALSA: line6: Return error if device not responding
  ALSA: line6: Add delay before reading status
  ASoC: Intel: Clean data after SST fw fetch
  ALSA: hda - Add docking station support for another HP machine
  ALSA: control: fix failure to return new numerical ID in 'replace' event data
  ALSA: usb: update trigger timestamp on first non-zero URB submitted
  ALSA: hda: read trigger_timestamp immediately after starting DMA
  ALSA: pcm: allow for trigger_tstamp snapshot in .trigger
  ALSA: pcm: don't override timestamp unconditionally
  ALSA: off by one bug in snd_riptide_joystick_probe()
  ASoC: rt5670: Set use_single_rw flag for regmap
  ASoC: rt286: Add rt288 codec support
  ASoC: max98357a: Fix build in !CONFIG_OF case
  ASoC: Intel: fix platform_no_drv_owner.cocci warnings
  ARM: dts: Switch Odroid X2/U2 to simple-audio-card
  ARM: dts: Exynos4 and Odroid X2/U3 sound device nodes update
  ALSA: control: fix failure to return numerical ID in 'add' event
  ...

499 files changed:
Documentation/devicetree/bindings/sound/cdns,xtfpga-i2s.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/designware-i2s.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/max98357a.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/pcm512x.txt
Documentation/devicetree/bindings/sound/samsung-i2s.txt
Documentation/devicetree/bindings/sound/simple-card.txt
Documentation/devicetree/bindings/sound/st,sta32x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/tlv320aic3x.txt
Documentation/devicetree/bindings/sound/ts3a227e.txt
Documentation/devicetree/bindings/sound/wm8904.txt
MAINTAINERS
arch/arm/boot/dts/exynos4.dtsi
arch/arm/boot/dts/exynos4412-odroid-common.dtsi
arch/arm/boot/dts/exynos4412-odroidu3.dts
arch/arm/boot/dts/exynos4412-odroidx2.dts
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/intel_audio.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_runtime_pm.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/line6/Kconfig [deleted file]
drivers/staging/line6/Makefile [deleted file]
drivers/staging/line6/audio.c [deleted file]
drivers/staging/line6/audio.h [deleted file]
drivers/staging/line6/capture.c [deleted file]
drivers/staging/line6/capture.h [deleted file]
drivers/staging/line6/driver.c [deleted file]
drivers/staging/line6/driver.h [deleted file]
drivers/staging/line6/midi.c [deleted file]
drivers/staging/line6/midi.h [deleted file]
drivers/staging/line6/midibuf.c [deleted file]
drivers/staging/line6/midibuf.h [deleted file]
drivers/staging/line6/pcm.c [deleted file]
drivers/staging/line6/pcm.h [deleted file]
drivers/staging/line6/playback.c [deleted file]
drivers/staging/line6/playback.h [deleted file]
drivers/staging/line6/pod.c [deleted file]
drivers/staging/line6/pod.h [deleted file]
drivers/staging/line6/podhd.c [deleted file]
drivers/staging/line6/podhd.h [deleted file]
drivers/staging/line6/revision.h [deleted file]
drivers/staging/line6/toneport.c [deleted file]
drivers/staging/line6/toneport.h [deleted file]
drivers/staging/line6/usbdefs.h [deleted file]
drivers/staging/line6/variax.c [deleted file]
drivers/staging/line6/variax.h [deleted file]
include/drm/i915_component.h [new file with mode: 0644]
include/drm/i915_powerwell.h [deleted file]
include/dt-bindings/sound/samsung-i2s.h [new file with mode: 0644]
include/sound/ad1816a.h
include/sound/ak4113.h
include/sound/ak4114.h
include/sound/compress_driver.h
include/sound/control.h
include/sound/core.h
include/sound/emu10k1.h
include/sound/es1688.h
include/sound/gus.h
include/sound/hwdep.h
include/sound/pcm.h
include/sound/pcm_params.h
include/sound/rawmidi.h
include/sound/rcar_snd.h
include/sound/rt5677.h
include/sound/sb.h
include/sound/seq_kernel.h
include/sound/simple_card.h
include/sound/soc-dapm.h
include/sound/soc.h
include/sound/sta32x.h
include/sound/wss.h
include/uapi/sound/asound.h
include/uapi/sound/usb_stream.h [new file with mode: 0644]
sound/aoa/soundbus/i2sbus/control.c
sound/aoa/soundbus/i2sbus/core.c
sound/aoa/soundbus/i2sbus/pcm.c
sound/arm/aaci.c
sound/atmel/ac97c.c
sound/core/compress_offload.c
sound/core/control.c
sound/core/hwdep.c
sound/core/init.c
sound/core/memory.c
sound/core/oss/pcm_oss.c
sound/core/pcm.c
sound/core/pcm_lib.c
sound/core/pcm_memory.c
sound/core/pcm_native.c
sound/core/rawmidi.c
sound/core/seq/oss/seq_oss_midi.c
sound/core/seq/seq_clientmgr.c
sound/core/seq/seq_midi.c
sound/core/seq/seq_ports.c
sound/core/seq/seq_ports.h
sound/core/sound.c
sound/core/timer.c
sound/drivers/aloop.c
sound/drivers/dummy.c
sound/drivers/ml403-ac97cr.c
sound/drivers/mpu401/mpu401_uart.c
sound/drivers/mtpav.c
sound/drivers/opl3/opl3_lib.c
sound/drivers/opl3/opl3_midi.c
sound/drivers/opl3/opl3_seq.c
sound/drivers/opl4/opl4_lib.c
sound/drivers/opl4/opl4_synth.c
sound/drivers/pcsp/pcsp.c
sound/drivers/pcsp/pcsp_input.c
sound/drivers/pcsp/pcsp_lib.c
sound/drivers/serial-u16550.c
sound/drivers/vx/vx_core.c
sound/i2c/other/ak4113.c
sound/i2c/other/ak4114.c
sound/i2c/other/ak4117.c
sound/i2c/other/ak4xxx-adda.c
sound/isa/ad1816a/ad1816a.c
sound/isa/ad1816a/ad1816a_lib.c
sound/isa/ad1848/ad1848.c
sound/isa/als100.c
sound/isa/azt2320.c
sound/isa/cmi8328.c
sound/isa/cs423x/cs4231.c
sound/isa/cs423x/cs4236.c
sound/isa/cs423x/cs4236_lib.c
sound/isa/es1688/es1688.c
sound/isa/es1688/es1688_lib.c
sound/isa/es18xx.c
sound/isa/galaxy/galaxy.c
sound/isa/gus/gus_instr.c [deleted file]
sound/isa/gus/gus_pcm.c
sound/isa/gus/gus_uart.c
sound/isa/gus/gusclassic.c
sound/isa/gus/gusextreme.c
sound/isa/gus/gusmax.c
sound/isa/gus/interwave.c
sound/isa/msnd/msnd.c
sound/isa/msnd/msnd.h
sound/isa/msnd/msnd_pinnacle.c
sound/isa/opl3sa2.c
sound/isa/opti9xx/miro.c
sound/isa/opti9xx/opti92x-ad1848.c
sound/isa/sb/emu8000.c
sound/isa/sb/emu8000_patch.c
sound/isa/sb/emu8000_pcm.c
sound/isa/sb/emu8000_synth.c
sound/isa/sb/jazz16.c
sound/isa/sb/sb16.c
sound/isa/sb/sb16_main.c
sound/isa/sb/sb8.c
sound/isa/sb/sb8_main.c
sound/isa/sb/sb8_midi.c
sound/isa/sb/sb_common.c
sound/isa/sb/sb_mixer.c
sound/isa/sc6000.c
sound/isa/sscape.c
sound/isa/wavefront/wavefront.c
sound/isa/wavefront/wavefront_fx.c
sound/isa/wavefront/wavefront_midi.c
sound/isa/wavefront/wavefront_synth.c
sound/isa/wss/wss_lib.c
sound/oss/msnd_pinnacle.c
sound/oss/pss.c
sound/oss/swarm_cs4297a.c
sound/oss/trix.c
sound/parisc/harmony.c
sound/pci/Kconfig
sound/pci/ad1889.c
sound/pci/ali5451/ali5451.c
sound/pci/als300.c
sound/pci/als4000.c
sound/pci/asihpi/asihpi.c
sound/pci/asihpi/hpi6000.c
sound/pci/asihpi/hpioctl.c
sound/pci/atiixp.c
sound/pci/atiixp_modem.c
sound/pci/au88x0/au88x0.h
sound/pci/aw2/aw2-alsa.c
sound/pci/aw2/aw2-saa7146.c
sound/pci/azt3328.c
sound/pci/bt87x.c
sound/pci/ca0106/ca0106_main.c
sound/pci/ca0106/ca0106_mixer.c
sound/pci/ca0106/ca0106_proc.c
sound/pci/cmipci.c
sound/pci/cs4281.c
sound/pci/cs46xx/cs46xx.c
sound/pci/cs46xx/cs46xx.h
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/cs46xx/dsp_spos.c
sound/pci/cs46xx/dsp_spos_scb_lib.c
sound/pci/cs5530.c
sound/pci/cs5535audio/cs5535audio.c
sound/pci/cs5535audio/cs5535audio_pm.c
sound/pci/ctxfi/cthw20k1.c
sound/pci/ctxfi/cthw20k2.c
sound/pci/echoaudio/darla20.c
sound/pci/echoaudio/darla24.c
sound/pci/echoaudio/echo3g.c
sound/pci/echoaudio/echoaudio.c
sound/pci/echoaudio/gina20.c
sound/pci/echoaudio/gina24.c
sound/pci/echoaudio/indigo.c
sound/pci/echoaudio/indigodj.c
sound/pci/echoaudio/indigoio.c
sound/pci/echoaudio/layla20.c
sound/pci/echoaudio/layla24.c
sound/pci/echoaudio/mia.c
sound/pci/echoaudio/midi.c
sound/pci/echoaudio/mona.c
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/emu10k1/emufx.c
sound/pci/emu10k1/emupcm.c
sound/pci/emu10k1/p16v.c
sound/pci/ens1370.c
sound/pci/es1938.c
sound/pci/es1968.c
sound/pci/fm801.c
sound/pci/hda/Kconfig
sound/pci/hda/hda_auto_parser.c
sound/pci/hda/hda_controller.c
sound/pci/hda/hda_hwdep.c
sound/pci/hda/hda_i915.c
sound/pci/hda/hda_i915.h [deleted file]
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_intel.h [new file with mode: 0644]
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/ice1712/ak4xxx.c
sound/pci/ice1712/ice1712.c
sound/pci/ice1712/ice1724.c
sound/pci/ice1712/juli.c
sound/pci/ice1712/wm8766.c
sound/pci/ice1712/wm8766.h
sound/pci/ice1712/wm8776.c
sound/pci/ice1712/wm8776.h
sound/pci/intel8x0.c
sound/pci/intel8x0m.c
sound/pci/korg1212/korg1212.c
sound/pci/lola/lola.c
sound/pci/maestro3.c
sound/pci/mixart/mixart.c
sound/pci/mixart/mixart_core.c
sound/pci/mixart/mixart_hwdep.c
sound/pci/nm256/nm256.c
sound/pci/oxygen/Makefile
sound/pci/oxygen/oxygen.h
sound/pci/oxygen/oxygen_io.c
sound/pci/oxygen/oxygen_lib.c
sound/pci/oxygen/oxygen_mixer.c
sound/pci/oxygen/oxygen_pcm.c
sound/pci/oxygen/se6x.c [new file with mode: 0644]
sound/pci/pcxhr/pcxhr_core.c
sound/pci/pcxhr/pcxhr_hwdep.c
sound/pci/riptide/riptide.c
sound/pci/rme32.c
sound/pci/rme96.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/pci/rme9652/rme9652.c
sound/pci/sis7019.c
sound/pci/sonicvibes.c
sound/pci/trident/trident.c
sound/pci/trident/trident.h
sound/pci/trident/trident_main.c
sound/pci/trident/trident_memory.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/pci/vx222/vx222.c
sound/pci/vx222/vx222_ops.c
sound/pci/ymfpci/ymfpci.c
sound/pci/ymfpci/ymfpci.h
sound/pci/ymfpci/ymfpci_main.c
sound/ppc/awacs.c
sound/ppc/beep.c
sound/ppc/burgundy.c
sound/ppc/pmac.c
sound/ppc/snd_ps3.c
sound/ppc/tumbler.c
sound/sh/aica.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/atmel/Kconfig
sound/soc/atmel/atmel-pcm-dma.c
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/au1x/db1200.c
sound/soc/au1x/dbdma2.c
sound/soc/au1x/dma.c
sound/soc/codecs/88pm860x-codec.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ad193x.c
sound/soc/codecs/ak4671.c
sound/soc/codecs/alc5623.c
sound/soc/codecs/alc5632.c
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/bt-sco.c
sound/soc/codecs/cs35l32.c
sound/soc/codecs/cs42l52.c
sound/soc/codecs/cs42l56.c
sound/soc/codecs/cs42l73.c
sound/soc/codecs/da732x.c
sound/soc/codecs/max98357a.c [new file with mode: 0644]
sound/soc/codecs/mc13783.c
sound/soc/codecs/pcm3008.c
sound/soc/codecs/pcm512x-i2c.c
sound/soc/codecs/pcm512x-spi.c
sound/soc/codecs/pcm512x.c
sound/soc/codecs/pcm512x.h
sound/soc/codecs/rt286.c
sound/soc/codecs/rt286.h
sound/soc/codecs/rt5631.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5645.h
sound/soc/codecs/rt5651.c
sound/soc/codecs/rt5670.c
sound/soc/codecs/rt5670.h
sound/soc/codecs/rt5677.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/sn95031.c
sound/soc/codecs/sta32x.c
sound/soc/codecs/sta32x.h
sound/soc/codecs/tlv320aic31xx.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320dac33.c
sound/soc/codecs/ts3a227e.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/twl6040.c
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm5100.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8770.c
sound/soc/codecs/wm8804.c
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8955.c
sound/soc/codecs/wm8958-dsp2.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8961.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8988.c
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm8991.c
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8995.c
sound/soc/codecs/wm8996.c
sound/soc/codecs/wm8997.c
sound/soc/codecs/wm9081.c
sound/soc/codecs/wm9090.c
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wm_hubs.c
sound/soc/davinci/Kconfig
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/dwc/Kconfig
sound/soc/dwc/designware_i2s.c
sound/soc/fsl/eukrea-tlv320.c
sound/soc/fsl/fsl_asrc.c
sound/soc/fsl/fsl_asrc.h
sound/soc/fsl/fsl_esai.c
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/fsl_spdif.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/fsl_utils.c
sound/soc/fsl/fsl_utils.h
sound/soc/fsl/imx-mc13783.c
sound/soc/fsl/imx-spdif.c
sound/soc/fsl/imx-ssi.c
sound/soc/fsl/mx27vis-aic32x4.c
sound/soc/fsl/wm1133-ev1.c
sound/soc/generic/simple-card.c
sound/soc/intel/Kconfig
sound/soc/intel/Makefile
sound/soc/intel/broadwell.c
sound/soc/intel/byt-rt5640.c
sound/soc/intel/bytcr_dpcm_rt5640.c
sound/soc/intel/cht_bsw_rt5645.c [new file with mode: 0644]
sound/soc/intel/cht_bsw_rt5672.c
sound/soc/intel/sst-baytrail-pcm.c
sound/soc/intel/sst-dsp.c
sound/soc/intel/sst-firmware.c
sound/soc/intel/sst-haswell-dsp.c
sound/soc/intel/sst-haswell-ipc.c
sound/soc/intel/sst-haswell-ipc.h
sound/soc/intel/sst-haswell-pcm.c
sound/soc/intel/sst-mfld-platform-pcm.c
sound/soc/intel/sst/sst.h
sound/soc/intel/sst/sst_acpi.c
sound/soc/intel/sst/sst_loader.c
sound/soc/jz4740/jz4740-i2s.c
sound/soc/mxs/mxs-saif.c
sound/soc/mxs/mxs-saif.h
sound/soc/mxs/mxs-sgtl5000.c
sound/soc/nuc900/nuc900-pcm.c
sound/soc/omap/ams-delta.c
sound/soc/omap/omap-hdmi-audio.c
sound/soc/omap/omap-twl4030.c
sound/soc/omap/rx51.c
sound/soc/pxa/Kconfig
sound/soc/pxa/corgi.c
sound/soc/pxa/e740_wm9705.c
sound/soc/pxa/e750_wm9705.c
sound/soc/pxa/hx4700.c
sound/soc/pxa/magician.c
sound/soc/pxa/mioa701_wm9713.c
sound/soc/pxa/palm27x.c
sound/soc/pxa/raumfeld.c
sound/soc/pxa/spitz.c
sound/soc/pxa/ttc-dkb.c
sound/soc/pxa/zylonite.c
sound/soc/rockchip/rockchip_i2s.c
sound/soc/samsung/Kconfig
sound/soc/samsung/Makefile
sound/soc/samsung/arndale_rt5631.c
sound/soc/samsung/goni_wm8994.c [deleted file]
sound/soc/samsung/h1940_uda1380.c
sound/soc/samsung/i2s.c
sound/soc/samsung/jive_wm8750.c
sound/soc/samsung/neo1973_wm8753.c
sound/soc/samsung/odroidx2_max98090.c
sound/soc/samsung/rx1950_uda1380.c
sound/soc/samsung/s3c24xx_simtec.c
sound/soc/samsung/s3c24xx_uda134x.c
sound/soc/samsung/smartq_wm8987.c
sound/soc/samsung/smdk_wm8580.c
sound/soc/samsung/smdk_wm8580pcm.c
sound/soc/samsung/smdk_wm8994pcm.c
sound/soc/sh/dma-sh7760.c
sound/soc/sh/fsi.c
sound/soc/sh/migor.c
sound/soc/sh/rcar/adg.c
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/dvc.c
sound/soc/sh/rcar/gen.c
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/src.c
sound/soc/sh/rcar/ssi.c
sound/soc/sh/siu_pcm.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-devres.c
sound/soc/soc-generic-dmaengine-pcm.c
sound/soc/soc-pcm.c
sound/soc/tegra/Kconfig
sound/soc/tegra/Makefile
sound/soc/tegra/tegra_rt5677.c [new file with mode: 0644]
sound/soc/txx9/txx9aclc.c
sound/soc/ux500/mop500_ab8500.c
sound/soc/xtensa/Kconfig [new file with mode: 0644]
sound/soc/xtensa/Makefile [new file with mode: 0644]
sound/soc/xtensa/xtfpga-i2s.c [new file with mode: 0644]
sound/sparc/amd7930.c
sound/synth/emux/emux.c
sound/synth/emux/emux_hwdep.c
sound/synth/emux/emux_oss.c
sound/synth/emux/emux_synth.c
sound/synth/emux/soundfont.c
sound/usb/Kconfig
sound/usb/Makefile
sound/usb/card.h
sound/usb/line6/Kconfig [new file with mode: 0644]
sound/usb/line6/Makefile [new file with mode: 0644]
sound/usb/line6/capture.c [new file with mode: 0644]
sound/usb/line6/capture.h [new file with mode: 0644]
sound/usb/line6/driver.c [new file with mode: 0644]
sound/usb/line6/driver.h [new file with mode: 0644]
sound/usb/line6/midi.c [new file with mode: 0644]
sound/usb/line6/midi.h [new file with mode: 0644]
sound/usb/line6/midibuf.c [new file with mode: 0644]
sound/usb/line6/midibuf.h [new file with mode: 0644]
sound/usb/line6/pcm.c [new file with mode: 0644]
sound/usb/line6/pcm.h [new file with mode: 0644]
sound/usb/line6/playback.c [new file with mode: 0644]
sound/usb/line6/playback.h [new file with mode: 0644]
sound/usb/line6/pod.c [new file with mode: 0644]
sound/usb/line6/podhd.c [new file with mode: 0644]
sound/usb/line6/toneport.c [new file with mode: 0644]
sound/usb/line6/variax.c [new file with mode: 0644]
sound/usb/midi.c
sound/usb/pcm.c
sound/usb/quirks-table.h
sound/usb/usx2y/usb_stream.h

diff --git a/Documentation/devicetree/bindings/sound/cdns,xtfpga-i2s.txt b/Documentation/devicetree/bindings/sound/cdns,xtfpga-i2s.txt
new file mode 100644 (file)
index 0000000..befd125
--- /dev/null
@@ -0,0 +1,18 @@
+Bindings for I2S controller built into xtfpga Xtensa bitstreams.
+
+Required properties:
+- compatible: shall be "cdns,xtfpga-i2s".
+- reg: memory region (address and length) with device registers.
+- interrupts: interrupt for the device.
+- clocks: phandle to the clk used as master clock. I2S bus clock
+  is derived from it.
+
+Examples:
+
+       i2s0: xtfpga-i2s@0d080000 {
+               #sound-dai-cells = <0>;
+               compatible = "cdns,xtfpga-i2s";
+               reg = <0x0d080000 0x40>;
+               interrupts = <2 1>;
+               clocks = <&cdce706 4>;
+       };
diff --git a/Documentation/devicetree/bindings/sound/designware-i2s.txt b/Documentation/devicetree/bindings/sound/designware-i2s.txt
new file mode 100644 (file)
index 0000000..7bb5424
--- /dev/null
@@ -0,0 +1,31 @@
+DesignWare I2S controller
+
+Required properties:
+ - compatible : Must be "snps,designware-i2s"
+ - reg : Must contain the I2S core's registers location and length
+ - clocks : Pairs of phandle and specifier referencing the controller's
+   clocks. The controller expects one clock: the clock used as the sampling
+   rate reference clock sample.
+ - clock-names : "i2sclk" for the sample rate reference clock.
+ - dmas: Pairs of phandle and specifier for the DMA channels that are used by
+   the core. The core expects one or two dma channels: one for transmit and
+   one for receive.
+ - dma-names : "tx" for the transmit channel, "rx" for the receive channel.
+
+For more details on the 'dma', 'dma-names', 'clock' and 'clock-names'
+properties please check:
+       * resource-names.txt
+       * clock/clock-bindings.txt
+       * dma/dma.txt
+
+Example:
+
+       soc_i2s: i2s@7ff90000 {
+               compatible = "snps,designware-i2s";
+               reg = <0x0 0x7ff90000 0x0 0x1000>;
+               clocks = <&scpi_i2sclk 0>;
+               clock-names = "i2sclk";
+               #sound-dai-cells = <0>;
+               dmas = <&dma0 5>;
+               dma-names = "tx";
+       };
diff --git a/Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt b/Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt
new file mode 100644 (file)
index 0000000..b414333
--- /dev/null
@@ -0,0 +1,23 @@
+Ingenic JZ4740 I2S controller
+
+Required properties:
+- compatible : "ingenic,jz4740-i2s"
+- reg : I2S registers location and length
+- clocks : AIC and I2S PLL clock specifiers.
+- clock-names: "aic" and "i2s"
+- dmas: DMA controller phandle and DMA request line for I2S Tx and Rx channels
+- dma-names: Must be "tx" and "rx"
+
+Example:
+
+i2s: i2s@10020000 {
+       compatible = "ingenic,jz4740-i2s";
+       reg = <0x10020000 0x94>;
+
+       clocks = <&cgu JZ4740_CLK_AIC>, <&cgu JZ4740_CLK_I2SPLL>;
+       clock-names = "aic", "i2s";
+
+       dmas = <&dma 2>, <&dma 3>;
+       dma-names = "tx", "rx";
+
+};
diff --git a/Documentation/devicetree/bindings/sound/max98357a.txt b/Documentation/devicetree/bindings/sound/max98357a.txt
new file mode 100644 (file)
index 0000000..a7a149a
--- /dev/null
@@ -0,0 +1,14 @@
+Maxim MAX98357A audio DAC
+
+This node models the Maxim MAX98357A DAC.
+
+Required properties:
+- compatible   : "maxim,max98357a"
+- sdmode-gpios : GPIO specifier for the GPIO -> DAC SDMODE pin
+
+Example:
+
+max98357a {
+       compatible = "maxim,max98357a";
+       sdmode-gpios = <&qcom_pinmux 25 0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.txt
new file mode 100644 (file)
index 0000000..a4589cd
--- /dev/null
@@ -0,0 +1,67 @@
+NVIDIA Tegra audio complex, with RT5677 CODEC
+
+Required properties:
+- compatible : "nvidia,tegra-audio-rt5677"
+- clocks : Must contain an entry for each entry in clock-names.
+  See ../clocks/clock-bindings.txt for details.
+- clock-names : Must include the following entries:
+  - pll_a
+  - pll_a_out0
+  - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk)
+- nvidia,model : The user-visible name of this sound complex.
+- nvidia,audio-routing : A list of the connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source. Valid names for sources and
+  sinks are the RT5677's pins (as documented in its binding), and the jacks
+  on the board:
+
+  * Headphone
+  * Speaker
+  * Headset Mic
+  * Internal Mic 1
+  * Internal Mic 2
+
+- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
+  connected to the CODEC.
+- nvidia,audio-codec : The phandle of the RT5677 audio codec. This binding
+  assumes that AIF1 on the CODEC is connected to Tegra.
+
+Optional properties:
+- nvidia,hp-det-gpios : The GPIO that detects headphones are plugged in
+- nvidia,hp-en-gpios : The GPIO that enables headphone amplifier
+- nvidia,mic-present-gpios: The GPIO that mic jack is plugged in
+- nvidia,dmic-clk-en-gpios : The GPIO that gates DMIC clock signal
+
+Example:
+
+sound {
+       compatible = "nvidia,tegra-audio-rt5677-ryu",
+               "nvidia,tegra-audio-rt5677";
+       nvidia,model = "NVIDIA Tegra Ryu";
+
+       nvidia,audio-routing =
+               "Headphone", "LOUT2",
+               "Headphone", "LOUT1",
+               "Headset Mic", "MICBIAS1",
+               "IN1P", "Headset Mic",
+               "IN1N", "Headset Mic",
+               "DMIC L1", "Internal Mic 1",
+               "DMIC R1", "Internal Mic 1",
+               "DMIC L2", "Internal Mic 2",
+               "DMIC R2", "Internal Mic 2",
+               "Speaker", "PDM1L",
+               "Speaker", "PDM1R";
+
+       nvidia,i2s-controller = <&tegra_i2s1>;
+       nvidia,audio-codec = <&rt5677>;
+
+       nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(R, 7) GPIO_ACTIVE_HIGH>;
+       nvidia,mic-present-gpios = <&gpio TEGRA_GPIO(O, 5) GPIO_ACTIVE_LOW>;
+       nvidia,hp-en-gpios = <&rt5677 1 GPIO_ACTIVE_HIGH>;
+       nvidia,dmic-clk-en-gpios = <&rt5677 2 GPIO_ACTIVE_HIGH>;
+
+       clocks = <&tegra_car TEGRA124_CLK_PLL_A>,
+                <&tegra_car TEGRA124_CLK_PLL_A_OUT0>,
+                <&tegra_car TEGRA124_CLK_EXTERN1>;
+       clock-names = "pll_a", "pll_a_out0", "mclk";
+};
index faff75e64573cb559144fdacb94c96476e2ea73e..3aae3b41bd8e8f48ed4af639b312690d7c6f9a33 100644 (file)
@@ -5,7 +5,8 @@ on the board).
 
 Required properties:
 
-  - compatible : One of "ti,pcm5121" or "ti,pcm5122"
+  - compatible : One of "ti,pcm5121", "ti,pcm5122", "ti,pcm5141" or
+                 "ti,pcm5142"
 
   - reg : the I2C address of the device for I2C, the chip select
           number for SPI.
@@ -16,9 +17,16 @@ Required properties:
 Optional properties:
 
   - clocks : A clock specifier for the clock connected as SCLK.  If this
-    is absent the device will be configured to clock from BCLK.
+    is absent the device will be configured to clock from BCLK.  If pll-in
+    and pll-out are specified in addition to a clock, the device is
+    configured to accept clock input on a specified gpio pin.
 
-Example:
+  - pll-in, pll-out : gpio pins used to connect the pll using <1>
+    through <6>.  The device will be configured for clock input on the
+    given pll-in pin and PLL output on the given pll-out pin.  An
+    external connection from the pll-out pin to the SCLK pin is assumed.
+
+Examples:
 
        pcm5122: pcm5122@4c {
                compatible = "ti,pcm5122";
@@ -28,3 +36,17 @@ Example:
                DVDD-supply = <&reg_1v8>;
                CPVDD-supply = <&reg_3v3>;
        };
+
+
+       pcm5142: pcm5142@4c {
+               compatible = "ti,pcm5142";
+               reg = <0x4c>;
+
+               AVDD-supply = <&reg_3v3_analog>;
+               DVDD-supply = <&reg_1v8>;
+               CPVDD-supply = <&reg_3v3>;
+
+               clocks = <&sck>;
+               pll-in = <3>;
+               pll-out = <6>;
+       };
index d188296bb6ec301fd49bec5cd61da0729b1ecd5e..09e0e18591ae26edd867ccd1fd263559f32400c1 100644 (file)
@@ -33,6 +33,25 @@ Required SoC Specific Properties:
   "iis" is the i2s bus clock and i2s_opclk0, i2s_opclk1 are sources of the root
   clk. i2s0 has internal mux to select the source of root clk and i2s1 and i2s2
   doesn't have any such mux.
+- #clock-cells: should be 1, this property must be present if the I2S device
+  is a clock provider in terms of the common clock bindings, described in
+  ../clock/clock-bindings.txt.
+- clock-output-names: from the common clock bindings, names of the CDCLK
+  I2S output clocks, suggested values are "i2s_cdclk0", "i2s_cdclk1",
+  "i2s_cdclk3" for the I2S0, I2S1, I2S2 devices recpectively.
+
+There are following clocks available at the I2S device nodes:
+ CLK_I2S_CDCLK    - the CDCLK (CODECLKO) gate clock,
+ CLK_I2S_RCLK_PSR - the RCLK prescaler divider clock (corresponding to the
+                   IISPSR register),
+ CLK_I2S_RCLK_SRC - the RCLKSRC mux clock (corresponding to RCLKSRC bit in
+                   IISMOD register).
+
+Refer to the SoC datasheet for availability of the above clocks.
+The CLK_I2S_RCLK_PSR and CLK_I2S_RCLK_SRC clocks are usually only available
+in the IIS Multi Audio Interface (I2S0).
+Note: Old DTs may not have the #clock-cells, clock-output-names properties
+and then not use the I2S node as a clock supplier.
 
 Optional SoC Specific Properties:
 
@@ -41,6 +60,7 @@ Optional SoC Specific Properties:
 - pinctrl-0: Should specify pin control groups used for this controller.
 - pinctrl-names: Should contain only one value - "default".
 
+
 Example:
 
 i2s0: i2s@03830000 {
@@ -54,6 +74,8 @@ i2s0: i2s@03830000 {
                <&clock_audss EXYNOS_I2S_BUS>,
                <&clock_audss EXYNOS_SCLK_I2S>;
        clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
+       #clock-cells;
+       clock-output-names = "i2s_cdclk0";
        samsung,idma-addr = <0x03000000>;
        pinctrl-names = "default";
        pinctrl-0 = <&i2s0_bus>;
index c3cba600bf112b70b4667e2001fe6c02ccb8da93..73bf314f7240483514db27980ef6aa63dd0298f2 100644 (file)
@@ -75,6 +75,11 @@ Optional CPU/CODEC subnodes properties:
                                          it can be specified via "clocks" if system has
                                          clock node (= common clock), or "system-clock-frequency"
                                          (if system doens't support common clock)
+                                         If a clock is specified, it is
+                                         enabled with clk_prepare_enable()
+                                         in dai startup() and disabled with
+                                         clk_disable_unprepare() in dai
+                                         shutdown().
 
 Example 1 - single DAI link:
 
diff --git a/Documentation/devicetree/bindings/sound/st,sta32x.txt b/Documentation/devicetree/bindings/sound/st,sta32x.txt
new file mode 100644 (file)
index 0000000..255de3a
--- /dev/null
@@ -0,0 +1,92 @@
+STA32X audio CODEC
+
+The driver for this device only supports I2C.
+
+Required properties:
+
+  - compatible: "st,sta32x"
+  - reg: the I2C address of the device for I2C
+  - reset-gpios: a GPIO spec for the reset pin. If specified, it will be
+                deasserted before communication to the codec starts.
+
+  - power-down-gpios: a GPIO spec for the power down pin. If specified,
+                     it will be deasserted before communication to the codec
+                     starts.
+
+  - Vdda-supply: regulator spec, providing 3.3V
+  - Vdd3-supply: regulator spec, providing 3.3V
+  - Vcc-supply: regulator spec, providing 5V - 26V
+
+Optional properties:
+
+  -  st,output-conf: number, Selects the output configuration:
+       0: 2-channel (full-bridge) power, 2-channel data-out
+       1: 2 (half-bridge). 1 (full-bridge) on-board power
+       2: 2 Channel (Full-Bridge) Power, 1 Channel FFX
+       3: 1 Channel Mono-Parallel
+       If parameter is missing, mode 0 will be enabled.
+       This property has to be specified as '/bits/ 8' value.
+
+  -  st,ch1-output-mapping: Channel 1 output mapping
+  -  st,ch2-output-mapping: Channel 2 output mapping
+  -  st,ch3-output-mapping: Channel 3 output mapping
+       0: Channel 1
+       1: Channel 2
+       2: Channel 3
+       If parameter is missing, channel 1 is chosen.
+       This properties have to be specified as '/bits/ 8' values.
+
+  -  st,thermal-warning-recover:
+       If present, thermal warning recovery is enabled.
+
+  -  st,thermal-warning-adjustment:
+       If present, thermal warning adjustment is enabled.
+
+  -  st,fault-detect-recovery:
+       If present, then fault recovery will be enabled.
+
+  -  st,drop-compensation-ns: number
+       Only required for "st,ffx-power-output-mode" ==
+       "variable-drop-compensation".
+       Specifies the drop compensation in nanoseconds.
+       The value must be in the range of 0..300, and only
+       multiples of 20 are allowed. Default is 140ns.
+
+  -  st,max-power-use-mpcc:
+       If present, then MPCC bits are used for MPC coefficients,
+       otherwise standard MPC coefficients are used.
+
+  -  st,max-power-corr:
+       If present, power bridge correction for THD reduction near maximum
+       power output is enabled.
+
+  -  st,am-reduction-mode:
+       If present, FFX mode runs in AM reduction mode, otherwise normal
+       FFX mode is used.
+
+  -  st,odd-pwm-speed-mode:
+       If present, PWM speed mode run on odd speed mode (341.3 kHz) on all
+       channels. If not present, normal PWM spped mode (384 kHz) will be used.
+
+  -  st,invalid-input-detect-mute:
+       If present, automatic invalid input detect mute is enabled.
+
+Example:
+
+codec: sta32x@38 {
+       compatible = "st,sta32x";
+       reg = <0x1c>;
+       reset-gpios = <&gpio1 19 0>;
+       power-down-gpios = <&gpio1 16 0>;
+       st,output-conf = /bits/ 8  <0x3>;       // set output to 2-channel
+                                               // (full-bridge) power,
+                                               // 2-channel data-out
+       st,ch1-output-mapping = /bits/ 8 <0>;   // set channel 1 output ch 1
+       st,ch2-output-mapping = /bits/ 8 <0>;   // set channel 2 output ch 1
+       st,ch3-output-mapping = /bits/ 8 <0>;   // set channel 3 output ch 1
+       st,max-power-correction;                // enables power bridge
+                                               // correction for THD reduction
+                                               // near maximum power output
+       st,invalid-input-detect-mute;           // mute if no valid digital
+                                               // audio signal is provided.
+};
index 5e6040c2c2e9c34019dceb93e439504e4e5af9ad..47a213c411ce922321e692ecca849390cbcd53e8 100644 (file)
@@ -9,6 +9,7 @@ Required properties:
     "ti,tlv320aic33" - TLV320AIC33
     "ti,tlv320aic3007" - TLV320AIC3007
     "ti,tlv320aic3106" - TLV320AIC3106
+    "ti,tlv320aic3104" - TLV320AIC3104
 
 
 - reg - <int> -  I2C slave address
@@ -18,6 +19,7 @@ Optional properties:
 
 - gpio-reset - gpio pin number used for codec reset
 - ai3x-gpio-func - <array of 2 int> - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality
+                                   - Not supported on tlv320aic3104
 - ai3x-micbias-vg - MicBias Voltage required.
        1 - MICBIAS output is powered to 2.0V,
        2 - MICBIAS output is powered to 2.5V,
@@ -36,7 +38,13 @@ CODEC output pins:
   * HPLCOM
   * HPRCOM
 
-CODEC input pins:
+CODEC input pins for TLV320AIC3104:
+  * MIC2L
+  * MIC2R
+  * LINE1L
+  * LINE1R
+
+CODEC input pins for other compatible codecs:
   * MIC3L
   * MIC3R
   * LINE1L
index e8bf23eb1803f6497224ef4ade437f6eae74111f..a836881d96085895619a122d2f1614aa62c93836 100644 (file)
@@ -13,6 +13,11 @@ Required properties:
  - interrupt-parent:   The parent interrupt controller
  - interrupts:         Interrupt number for /INT pin from the 227e
 
+Optional properies:
+ - ti,micbias:   Intended MICBIAS voltage (datasheet section 9.6.7).
+      Select 0/1/2/3/4/5/6/7 to specify MACBIAS voltage
+      2.1V/2.2V/2.3V/2.4V/2.5V/2.6V/2.7V/2.8V
+      Default value is "1" (2.2V).
 
 Examples:
 
index e99f4097c83c4e343f0ce2829c73217b6df3c5b0..66bf261423b92499d54694e46a4fcfd90b23f753 100644 (file)
@@ -3,7 +3,7 @@ WM8904 audio CODEC
 This device supports I2C only.
 
 Required properties:
-  - compatible: "wlf,wm8904"
+  - compatible: "wlf,wm8904" or "wlf,wm8912"
   - reg: the I2C address of the device.
   - clock-names: "mclk"
   - clocks: reference to
index 8726ac5d7cec669b3d43bfa4b3c68604454655ac..249498844a43b7654c2e57c6e0edde5959f8c349 100644 (file)
@@ -10713,6 +10713,7 @@ M:      Max Filippov <jcmvbkbc@gmail.com>
 L:     linux-xtensa@linux-xtensa.org
 S:     Maintained
 F:     drivers/spi/spi-xtensa-xtfpga.c
+F:     sound/soc/xtensa/xtfpga-i2s.c
 
 YAM DRIVER FOR AX.25
 M:     Jean-Paul Roubelat <jpr@f6fbb.org>
index 24ff27049ce015bf6c1203b73d97bfaa12ff0e37..cb6001085f1a1885c8dec0ae29fe3e7e0b109221 100644 (file)
                reg = <0x03830000 0x100>;
                clocks = <&clock_audss EXYNOS_I2S_BUS>;
                clock-names = "iis";
+               #clock-cells = <1>;
+               clock-output-names = "i2s_cdclk0";
                dmas = <&pdma0 12>, <&pdma0 11>, <&pdma0 10>;
                dma-names = "tx", "rx", "tx-sec";
                samsung,idma-addr = <0x03000000>;
+               #sound-dai-cells = <1>;
                status = "disabled";
        };
 
                reg = <0x13960000 0x100>;
                clocks = <&clock CLK_I2S1>;
                clock-names = "iis";
+               #clock-cells = <1>;
+               clock-output-names = "i2s_cdclk1";
                dmas = <&pdma1 12>, <&pdma1 11>;
                dma-names = "tx", "rx";
+               #sound-dai-cells = <1>;
                status = "disabled";
        };
 
                reg = <0x13970000 0x100>;
                clocks = <&clock CLK_I2S2>;
                clock-names = "iis";
+               #clock-cells = <1>;
+               clock-output-names = "i2s_cdclk2";
                dmas = <&pdma0 14>, <&pdma0 13>;
                dma-names = "tx", "rx";
+               #sound-dai-cells = <1>;
                status = "disabled";
        };
 
index 3fbf588682b94fcf8f6b340ad266794741825f34..abd63366298a812c2df659006c726b6345bfb444 100644 (file)
@@ -7,6 +7,7 @@
  * published by the Free Software Foundation.
 */
 
+#include <dt-bindings/sound/samsung-i2s.h>
 #include <dt-bindings/input/input.h>
 #include "exynos4412.dtsi"
 
                pinctrl-names = "default";
                status = "okay";
                clocks = <&clock_audss EXYNOS_I2S_BUS>,
-                        <&clock_audss EXYNOS_DOUT_AUD_BUS>;
-               clock-names = "iis", "i2s_opclk0";
+                        <&clock_audss EXYNOS_DOUT_AUD_BUS>,
+                        <&clock_audss EXYNOS_SCLK_I2S>;
+               clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
        };
 
        sound: sound {
-               compatible = "samsung,odroidx2-audio";
-               samsung,i2s-controller = <&i2s0>;
-               samsung,audio-codec = <&max98090>;
+               compatible = "simple-audio-card";
                assigned-clocks = <&clock_audss EXYNOS_MOUT_AUDSS>,
                                <&clock_audss EXYNOS_MOUT_I2S>,
                                <&clock_audss EXYNOS_DOUT_SRP>,
                                <0>,
                                <192000000>,
                                <19200000>;
+
+               simple-audio-card,format = "i2s";
+               simple-audio-card,bitclock-master = <&link0_codec>;
+               simple-audio-card,frame-master = <&link0_codec>;
+
+               simple-audio-card,cpu {
+                       sound-dai = <&i2s0 0>;
+                       system-clock-frequency = <19200000>;
+               };
+
+               link0_codec: simple-audio-card,codec {
+                       sound-dai = <&max98090>;
+                       clocks = <&i2s0 CLK_I2S_CDCLK>;
+               };
        };
 
        mmc@12550000 {
                        reg = <0x10>;
                        interrupt-parent = <&gpx0>;
                        interrupts = <0 0>;
+                       clocks = <&i2s0 CLK_I2S_CDCLK>;
+                       clock-names = "mclk";
+                       #sound-dai-cells = <0>;
                };
        };
 
index c8a64be55d071ce863085e838477e983f20ed2a7..44684e57ead1e6a60e86731e67f7f5bc0141adfc 100644 (file)
 };
 
 &sound {
-       compatible = "samsung,odroidu3-audio";
-       samsung,model = "Odroid-U3";
-       samsung,audio-routing =
+       simple-audio-card,name = "Odroid-U3";
+       simple-audio-card,widgets =
+               "Headphone", "Headphone Jack",
+               "Speakers", "Speakers";
+       simple-audio-card,routing =
                "Headphone Jack", "HPL",
                "Headphone Jack", "HPR",
                "Headphone Jack", "MICBIAS",
index 96b43f4497cc0eefb931456bc34be4365a66dcb6..6e33678562aebf5be0cc055831489073ca16270f 100644 (file)
 };
 
 &sound {
-       samsung,model = "Odroid-X2";
-       samsung,audio-routing =
+       simple-audio-card,name = "Odroid-X2";
+       simple-audio-card,widgets =
+               "Headphone", "Headphone Jack",
+               "Microphone", "Mic Jack",
+               "Microphone", "DMIC";
+       simple-audio-card,routing =
                "Headphone Jack", "HPL",
                "Headphone Jack", "HPR",
                "IN1", "Mic Jack",
index ecee3bcc8772907850a536166851624ab4795800..26b3199e0af2f55c2ec8ca9616f6f545aca331ee 100644 (file)
@@ -830,6 +830,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
        intel_runtime_pm_enable(dev_priv);
 
+       i915_audio_component_init(dev_priv);
+
        return 0;
 
 out_power_well:
@@ -870,6 +872,8 @@ int i915_driver_unload(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
+       i915_audio_component_cleanup(dev_priv);
+
        ret = i915_gem_suspend(dev);
        if (ret) {
                DRM_ERROR("failed to idle hardware: %d\n", ret);
index 7643300828c3aef79d32260af5f2c8e4c7ff5b2c..489b220af02b60a8fcafb0a6a188fd8aa0ff8b85 100644 (file)
@@ -934,8 +934,7 @@ static int i915_pm_suspend(struct device *dev)
 
 static int i915_pm_suspend_late(struct device *dev)
 {
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct drm_device *drm_dev = pci_get_drvdata(pdev);
+       struct drm_device *drm_dev = dev_to_i915(dev)->dev;
 
        /*
         * We have a suspedn ordering issue with the snd-hda driver also
@@ -954,8 +953,7 @@ static int i915_pm_suspend_late(struct device *dev)
 
 static int i915_pm_resume_early(struct device *dev)
 {
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct drm_device *drm_dev = pci_get_drvdata(pdev);
+       struct drm_device *drm_dev = dev_to_i915(dev)->dev;
 
        if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
                return 0;
@@ -965,8 +963,7 @@ static int i915_pm_resume_early(struct device *dev)
 
 static int i915_pm_resume(struct device *dev)
 {
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct drm_device *drm_dev = pci_get_drvdata(pdev);
+       struct drm_device *drm_dev = dev_to_i915(dev)->dev;
 
        if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
                return 0;
index 9d7a7155bf02a6f9fb44d504e69e635fefcc9c2e..24cc36a9f3ff8694e8cf4db9eadecbf021ac4e33 100644 (file)
@@ -1698,6 +1698,9 @@ struct drm_i915_private {
        struct drm_property *broadcast_rgb_property;
        struct drm_property *force_audio_property;
 
+       /* hda/i915 audio component */
+       bool audio_component_registered;
+
        uint32_t hw_context_size;
        struct list_head context_list;
 
@@ -1781,6 +1784,11 @@ static inline struct drm_i915_private *to_i915(const struct drm_device *dev)
        return dev->dev_private;
 }
 
+static inline struct drm_i915_private *dev_to_i915(struct device *dev)
+{
+       return to_i915(dev_get_drvdata(dev));
+}
+
 /* Iterate over initialised rings */
 #define for_each_ring(ring__, dev_priv__, i__) \
        for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \
index 2c7ed5cb29c0f4aae70ee6599d1d0e59cb857fb5..ee41b882e71aa4126fc9c37fb56228a686b7ec08 100644 (file)
@@ -22,6 +22,9 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/component.h>
+#include <drm/i915_component.h>
+#include "intel_drv.h"
 
 #include <drm/drmP.h>
 #include <drm/drm_edid.h>
@@ -461,3 +464,110 @@ void intel_init_audio(struct drm_device *dev)
                dev_priv->display.audio_codec_disable = ilk_audio_codec_disable;
        }
 }
+
+static void i915_audio_component_get_power(struct device *dev)
+{
+       intel_display_power_get(dev_to_i915(dev), POWER_DOMAIN_AUDIO);
+}
+
+static void i915_audio_component_put_power(struct device *dev)
+{
+       intel_display_power_put(dev_to_i915(dev), POWER_DOMAIN_AUDIO);
+}
+
+/* Get CDCLK in kHz  */
+static int i915_audio_component_get_cdclk_freq(struct device *dev)
+{
+       struct drm_i915_private *dev_priv = dev_to_i915(dev);
+       int ret;
+
+       if (WARN_ON_ONCE(!HAS_DDI(dev_priv)))
+               return -ENODEV;
+
+       intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
+       ret = intel_ddi_get_cdclk_freq(dev_priv);
+       intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
+
+       return ret;
+}
+
+static const struct i915_audio_component_ops i915_audio_component_ops = {
+       .owner          = THIS_MODULE,
+       .get_power      = i915_audio_component_get_power,
+       .put_power      = i915_audio_component_put_power,
+       .get_cdclk_freq = i915_audio_component_get_cdclk_freq,
+};
+
+static int i915_audio_component_bind(struct device *i915_dev,
+                                    struct device *hda_dev, void *data)
+{
+       struct i915_audio_component *acomp = data;
+
+       if (WARN_ON(acomp->ops || acomp->dev))
+               return -EEXIST;
+
+       acomp->ops = &i915_audio_component_ops;
+       acomp->dev = i915_dev;
+
+       return 0;
+}
+
+static void i915_audio_component_unbind(struct device *i915_dev,
+                                       struct device *hda_dev, void *data)
+{
+       struct i915_audio_component *acomp = data;
+
+       acomp->ops = NULL;
+       acomp->dev = NULL;
+}
+
+static const struct component_ops i915_audio_component_bind_ops = {
+       .bind   = i915_audio_component_bind,
+       .unbind = i915_audio_component_unbind,
+};
+
+/**
+ * i915_audio_component_init - initialize and register the audio component
+ * @dev_priv: i915 device instance
+ *
+ * This will register with the component framework a child component which
+ * will bind dynamically to the snd_hda_intel driver's corresponding master
+ * component when the latter is registered. During binding the child
+ * initializes an instance of struct i915_audio_component which it receives
+ * from the master. The master can then start to use the interface defined by
+ * this struct. Each side can break the binding at any point by deregistering
+ * its own component after which each side's component unbind callback is
+ * called.
+ *
+ * We ignore any error during registration and continue with reduced
+ * functionality (i.e. without HDMI audio).
+ */
+void i915_audio_component_init(struct drm_i915_private *dev_priv)
+{
+       int ret;
+
+       ret = component_add(dev_priv->dev->dev, &i915_audio_component_bind_ops);
+       if (ret < 0) {
+               DRM_ERROR("failed to add audio component (%d)\n", ret);
+               /* continue with reduced functionality */
+               return;
+       }
+
+       dev_priv->audio_component_registered = true;
+}
+
+/**
+ * i915_audio_component_cleanup - deregister the audio component
+ * @dev_priv: i915 device instance
+ *
+ * Deregisters the audio component, breaking any existing binding to the
+ * corresponding snd_hda_intel driver's master component.
+ */
+void i915_audio_component_cleanup(struct drm_i915_private *dev_priv)
+{
+       if (!dev_priv->audio_component_registered)
+               return;
+
+       component_del(dev_priv->dev->dev, &i915_audio_component_bind_ops);
+       dev_priv->audio_component_registered = false;
+}
index 3b40a17b8852fa7d3ff0519a37baef85c09f467b..29ba962d15e38d4a79c4b308dc8d8dec6b7db5a7 100644 (file)
@@ -873,6 +873,8 @@ void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire);
 void intel_init_audio(struct drm_device *dev);
 void intel_audio_codec_enable(struct intel_encoder *encoder);
 void intel_audio_codec_disable(struct intel_encoder *encoder);
+void i915_audio_component_init(struct drm_i915_private *dev_priv);
+void i915_audio_component_cleanup(struct drm_i915_private *dev_priv);
 
 /* intel_display.c */
 const char *intel_output_name(int output);
index ac6da7102fbbdc53c74e584234c51506191da1ee..39ddf40171bf08ca4b6acb677982f87582d998c0 100644 (file)
@@ -31,7 +31,6 @@
 
 #include "i915_drv.h"
 #include "intel_drv.h"
-#include <drm/i915_powerwell.h>
 
 /**
  * DOC: runtime pm
@@ -50,8 +49,6 @@
  * present for a given platform.
  */
 
-static struct i915_power_domains *hsw_pwr;
-
 #define for_each_power_well(i, power_well, domain_mask, power_domains) \
        for (i = 0;                                                     \
             i < (power_domains)->power_well_count &&                   \
@@ -1071,10 +1068,8 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
         */
        if (IS_HASWELL(dev_priv->dev)) {
                set_power_wells(power_domains, hsw_power_wells);
-               hsw_pwr = power_domains;
        } else if (IS_BROADWELL(dev_priv->dev)) {
                set_power_wells(power_domains, bdw_power_wells);
-               hsw_pwr = power_domains;
        } else if (IS_CHERRYVIEW(dev_priv->dev)) {
                set_power_wells(power_domains, chv_power_wells);
        } else if (IS_VALLEYVIEW(dev_priv->dev)) {
@@ -1118,8 +1113,6 @@ void intel_power_domains_fini(struct drm_i915_private *dev_priv)
         * the power well is not enabled, so just enable it in case
         * we're going to unload/reload. */
        intel_display_set_init_power(dev_priv, true);
-
-       hsw_pwr = NULL;
 }
 
 static void intel_power_domains_resume(struct drm_i915_private *dev_priv)
@@ -1328,52 +1321,3 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv)
        pm_runtime_put_autosuspend(device);
 }
 
-/* Display audio driver power well request */
-int i915_request_power_well(void)
-{
-       struct drm_i915_private *dev_priv;
-
-       if (!hsw_pwr)
-               return -ENODEV;
-
-       dev_priv = container_of(hsw_pwr, struct drm_i915_private,
-                               power_domains);
-       intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(i915_request_power_well);
-
-/* Display audio driver power well release */
-int i915_release_power_well(void)
-{
-       struct drm_i915_private *dev_priv;
-
-       if (!hsw_pwr)
-               return -ENODEV;
-
-       dev_priv = container_of(hsw_pwr, struct drm_i915_private,
-                               power_domains);
-       intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(i915_release_power_well);
-
-/*
- * Private interface for the audio driver to get CDCLK in kHz.
- *
- * Caller must request power well using i915_request_power_well() prior to
- * making the call.
- */
-int i915_get_cdclk_freq(void)
-{
-       struct drm_i915_private *dev_priv;
-
-       if (!hsw_pwr)
-               return -ENODEV;
-
-       dev_priv = container_of(hsw_pwr, struct drm_i915_private,
-                               power_domains);
-
-       return intel_ddi_get_cdclk_freq(dev_priv);
-}
-EXPORT_SYMBOL_GPL(i915_get_cdclk_freq);
index 815de379a1309c9acc49366ccd9a2a6ef3cf44b3..9049dd91b5694658345999ce20a422c1e99fedd5 100644 (file)
@@ -46,8 +46,6 @@ source "drivers/staging/rtl8723au/Kconfig"
 
 source "drivers/staging/rts5208/Kconfig"
 
-source "drivers/staging/line6/Kconfig"
-
 source "drivers/staging/octeon/Kconfig"
 
 source "drivers/staging/octeon-usb/Kconfig"
index 33c640b4956649cea2ecd50e6dc5439669004842..fe26ff162b428c7a7e634f94639b13ca6abd47be 100644 (file)
@@ -15,7 +15,6 @@ obj-$(CONFIG_R8712U)          += rtl8712/
 obj-$(CONFIG_R8188EU)          += rtl8188eu/
 obj-$(CONFIG_R8723AU)          += rtl8723au/
 obj-$(CONFIG_RTS5208)          += rts5208/
-obj-$(CONFIG_LINE6_USB)                += line6/
 obj-$(CONFIG_NETLOGIC_XLR_NET) += netlogic/
 obj-$(CONFIG_OCTEON_ETHERNET)  += octeon/
 obj-$(CONFIG_OCTEON_USB)       += octeon-usb/
diff --git a/drivers/staging/line6/Kconfig b/drivers/staging/line6/Kconfig
deleted file mode 100644 (file)
index 4f1219b..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-menuconfig LINE6_USB
-       tristate "Line6 USB support"
-       depends on USB && SND
-       select SND_RAWMIDI
-       select SND_PCM
-       help
-         This is a driver for the guitar amp, cab, and effects modeller
-         PODxt Pro by Line6 (and similar devices), supporting the
-         following features:
-           * Reading/writing individual parameters
-           * Reading/writing complete channel, effects setup, and amp
-             setup data
-           * Channel switching
-           * Virtual MIDI interface
-           * Tuner access
-           * Playback/capture/mixer device for any ALSA-compatible PCM
-             audio application
-           * Signal routing (record clean/processed guitar signal,
-             re-amping)
-
-         Preliminary support for the Variax Workbench and TonePort
-         devices is included.
-
-if LINE6_USB
-
-config LINE6_USB_IMPULSE_RESPONSE
-       bool "measure impulse response"
-       default n
-       help
-         Say Y here to add code to measure the impulse response of a Line6
-         device. This is more accurate than user-space methods since it
-         bypasses any PCM data buffering (e.g., by ALSA or jack). This is
-         useful for assessing the performance of new devices, but is not
-         required for normal operation.
-
-         If unsure, say N.
-
-endif # LINE6_USB
diff --git a/drivers/staging/line6/Makefile b/drivers/staging/line6/Makefile
deleted file mode 100644 (file)
index ae5c374..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-obj-$(CONFIG_LINE6_USB)                += line6usb.o
-
-line6usb-y :=          \
-               audio.o         \
-               capture.o       \
-               driver.o        \
-               midi.o          \
-               midibuf.o       \
-               pcm.o           \
-               playback.o      \
-               pod.o           \
-               toneport.o      \
-               variax.o        \
-               podhd.o
diff --git a/drivers/staging/line6/audio.c b/drivers/staging/line6/audio.c
deleted file mode 100644 (file)
index 171d80c..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *     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, version 2.
- *
- */
-
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <linux/export.h>
-
-#include "driver.h"
-#include "audio.h"
-
-/*
-       Initialize the Line6 USB audio system.
-*/
-int line6_init_audio(struct usb_line6 *line6)
-{
-       struct snd_card *card;
-       int err;
-
-       err = snd_card_new(line6->ifcdev,
-                          SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
-                          THIS_MODULE, 0, &card);
-       if (err < 0)
-               return err;
-
-       line6->card = card;
-
-       strcpy(card->id, line6->properties->id);
-       strcpy(card->driver, DRIVER_NAME);
-       strcpy(card->shortname, line6->properties->name);
-       /* longname is 80 chars - see asound.h */
-       sprintf(card->longname, "Line6 %s at USB %s", line6->properties->name,
-               dev_name(line6->ifcdev));
-       return 0;
-}
-
-/*
-       Register the Line6 USB audio system.
-*/
-int line6_register_audio(struct usb_line6 *line6)
-{
-       int err;
-
-       err = snd_card_register(line6->card);
-       if (err < 0)
-               return err;
-
-       return 0;
-}
-
-/*
-       Cleanup the Line6 USB audio system.
-*/
-void line6_cleanup_audio(struct usb_line6 *line6)
-{
-       struct snd_card *card = line6->card;
-
-       if (card == NULL)
-               return;
-
-       snd_card_disconnect(card);
-       snd_card_free(card);
-       line6->card = NULL;
-}
diff --git a/drivers/staging/line6/audio.h b/drivers/staging/line6/audio.h
deleted file mode 100644 (file)
index 5f8a09a..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *     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, version 2.
- *
- */
-
-#ifndef AUDIO_H
-#define AUDIO_H
-
-#include "driver.h"
-
-extern void line6_cleanup_audio(struct usb_line6 *);
-extern int line6_init_audio(struct usb_line6 *);
-extern int line6_register_audio(struct usb_line6 *);
-
-#endif
diff --git a/drivers/staging/line6/capture.c b/drivers/staging/line6/capture.c
deleted file mode 100644 (file)
index e6ca631..0000000
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *     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, version 2.
- *
- */
-
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-
-#include "audio.h"
-#include "capture.h"
-#include "driver.h"
-#include "pcm.h"
-#include "pod.h"
-
-/*
-       Find a free URB and submit it.
-*/
-static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)
-{
-       int index;
-       unsigned long flags;
-       int i, urb_size;
-       int ret;
-       struct urb *urb_in;
-
-       spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
-       index =
-           find_first_zero_bit(&line6pcm->active_urb_in, LINE6_ISO_BUFFERS);
-
-       if (index < 0 || index >= LINE6_ISO_BUFFERS) {
-               spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
-               dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
-               return -EINVAL;
-       }
-
-       urb_in = line6pcm->urb_audio_in[index];
-       urb_size = 0;
-
-       for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
-               struct usb_iso_packet_descriptor *fin =
-                   &urb_in->iso_frame_desc[i];
-               fin->offset = urb_size;
-               fin->length = line6pcm->max_packet_size;
-               urb_size += line6pcm->max_packet_size;
-       }
-
-       urb_in->transfer_buffer =
-           line6pcm->buffer_in +
-           index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
-       urb_in->transfer_buffer_length = urb_size;
-       urb_in->context = line6pcm;
-
-       ret = usb_submit_urb(urb_in, GFP_ATOMIC);
-
-       if (ret == 0)
-               set_bit(index, &line6pcm->active_urb_in);
-       else
-               dev_err(line6pcm->line6->ifcdev,
-                       "URB in #%d submission failed (%d)\n", index, ret);
-
-       spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
-       return 0;
-}
-
-/*
-       Submit all currently available capture URBs.
-*/
-int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm)
-{
-       int ret, i;
-
-       for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
-               ret = submit_audio_in_urb(line6pcm);
-               if (ret < 0)
-                       return ret;
-       }
-
-       return 0;
-}
-
-/*
-       Unlink all currently active capture URBs.
-*/
-void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm)
-{
-       unsigned int i;
-
-       for (i = LINE6_ISO_BUFFERS; i--;) {
-               if (test_bit(i, &line6pcm->active_urb_in)) {
-                       if (!test_and_set_bit(i, &line6pcm->unlink_urb_in)) {
-                               struct urb *u = line6pcm->urb_audio_in[i];
-
-                               usb_unlink_urb(u);
-                       }
-               }
-       }
-}
-
-/*
-       Wait until unlinking of all currently active capture URBs has been
-       finished.
-*/
-void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
-{
-       int timeout = HZ;
-       unsigned int i;
-       int alive;
-
-       do {
-               alive = 0;
-               for (i = LINE6_ISO_BUFFERS; i--;) {
-                       if (test_bit(i, &line6pcm->active_urb_in))
-                               alive++;
-               }
-               if (!alive)
-                       break;
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(1);
-       } while (--timeout > 0);
-       if (alive)
-               snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
-}
-
-/*
-       Unlink all currently active capture URBs, and wait for finishing.
-*/
-void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
-{
-       line6_unlink_audio_in_urbs(line6pcm);
-       line6_wait_clear_audio_in_urbs(line6pcm);
-}
-
-/*
-       Copy data into ALSA capture buffer.
-*/
-void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize)
-{
-       struct snd_pcm_substream *substream =
-           get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
-       int frames = fsize / bytes_per_frame;
-
-       if (runtime == NULL)
-               return;
-
-       if (line6pcm->pos_in_done + frames > runtime->buffer_size) {
-               /*
-                  The transferred area goes over buffer boundary,
-                  copy two separate chunks.
-                */
-               int len;
-
-               len = runtime->buffer_size - line6pcm->pos_in_done;
-
-               if (len > 0) {
-                       memcpy(runtime->dma_area +
-                              line6pcm->pos_in_done * bytes_per_frame, fbuf,
-                              len * bytes_per_frame);
-                       memcpy(runtime->dma_area, fbuf + len * bytes_per_frame,
-                              (frames - len) * bytes_per_frame);
-               } else {
-                       /* this is somewhat paranoid */
-                       dev_err(line6pcm->line6->ifcdev,
-                               "driver bug: len = %d\n", len);
-               }
-       } else {
-               /* copy single chunk */
-               memcpy(runtime->dma_area +
-                      line6pcm->pos_in_done * bytes_per_frame, fbuf, fsize);
-       }
-
-       line6pcm->pos_in_done += frames;
-       if (line6pcm->pos_in_done >= runtime->buffer_size)
-               line6pcm->pos_in_done -= runtime->buffer_size;
-}
-
-void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length)
-{
-       struct snd_pcm_substream *substream =
-           get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
-
-       line6pcm->bytes_in += length;
-       if (line6pcm->bytes_in >= line6pcm->period_in) {
-               line6pcm->bytes_in %= line6pcm->period_in;
-               snd_pcm_period_elapsed(substream);
-       }
-}
-
-void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm)
-{
-       kfree(line6pcm->buffer_in);
-       line6pcm->buffer_in = NULL;
-}
-
-/*
- * Callback for completed capture URB.
- */
-static void audio_in_callback(struct urb *urb)
-{
-       int i, index, length = 0, shutdown = 0;
-       unsigned long flags;
-
-       struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;
-
-       line6pcm->last_frame_in = urb->start_frame;
-
-       /* find index of URB */
-       for (index = 0; index < LINE6_ISO_BUFFERS; ++index)
-               if (urb == line6pcm->urb_audio_in[index])
-                       break;
-
-       spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
-
-       for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
-               char *fbuf;
-               int fsize;
-               struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i];
-
-               if (fin->status == -EXDEV) {
-                       shutdown = 1;
-                       break;
-               }
-
-               fbuf = urb->transfer_buffer + fin->offset;
-               fsize = fin->actual_length;
-
-               if (fsize > line6pcm->max_packet_size) {
-                       dev_err(line6pcm->line6->ifcdev,
-                               "driver and/or device bug: packet too large (%d > %d)\n",
-                               fsize, line6pcm->max_packet_size);
-               }
-
-               length += fsize;
-
-               /* the following assumes LINE6_ISO_PACKETS == 1: */
-               line6pcm->prev_fbuf = fbuf;
-               line6pcm->prev_fsize = fsize;
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-               if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
-#endif
-                       if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
-                                    &line6pcm->flags) && (fsize > 0))
-                               line6_capture_copy(line6pcm, fbuf, fsize);
-       }
-
-       clear_bit(index, &line6pcm->active_urb_in);
-
-       if (test_and_clear_bit(index, &line6pcm->unlink_urb_in))
-               shutdown = 1;
-
-       spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
-
-       if (!shutdown) {
-               submit_audio_in_urb(line6pcm);
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-               if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
-#endif
-                       if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
-                                    &line6pcm->flags))
-                               line6_capture_check_period(line6pcm, length);
-       }
-}
-
-/* open capture callback */
-static int snd_line6_capture_open(struct snd_pcm_substream *substream)
-{
-       int err;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
-       err = snd_pcm_hw_constraint_ratdens(runtime, 0,
-                                           SNDRV_PCM_HW_PARAM_RATE,
-                                           (&line6pcm->
-                                            properties->snd_line6_rates));
-       if (err < 0)
-               return err;
-
-       runtime->hw = line6pcm->properties->snd_line6_capture_hw;
-       return 0;
-}
-
-/* close capture callback */
-static int snd_line6_capture_close(struct snd_pcm_substream *substream)
-{
-       return 0;
-}
-
-/* hw_params capture callback */
-static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream,
-                                      struct snd_pcm_hw_params *hw_params)
-{
-       int ret;
-       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
-       /* -- Florian Demski [FD] */
-       /* don't ask me why, but this fixes the bug on my machine */
-       if (line6pcm == NULL) {
-               if (substream->pcm == NULL)
-                       return -ENOMEM;
-               if (substream->pcm->private_data == NULL)
-                       return -ENOMEM;
-               substream->private_data = substream->pcm->private_data;
-               line6pcm = snd_pcm_substream_chip(substream);
-       }
-       /* -- [FD] end */
-
-       ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
-
-       if (ret < 0)
-               return ret;
-
-       ret = snd_pcm_lib_malloc_pages(substream,
-                                      params_buffer_bytes(hw_params));
-       if (ret < 0) {
-               line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
-               return ret;
-       }
-
-       line6pcm->period_in = params_period_bytes(hw_params);
-       return 0;
-}
-
-/* hw_free capture callback */
-static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
-       line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
-       return snd_pcm_lib_free_pages(substream);
-}
-
-/* trigger callback */
-int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd)
-{
-       int err;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-#ifdef CONFIG_PM
-       case SNDRV_PCM_TRIGGER_RESUME:
-#endif
-               err = line6_pcm_acquire(line6pcm,
-                                       LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
-
-               if (err < 0)
-                       return err;
-
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-#ifdef CONFIG_PM
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-#endif
-               err = line6_pcm_release(line6pcm,
-                                       LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
-
-               if (err < 0)
-                       return err;
-
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/* capture pointer callback */
-static snd_pcm_uframes_t
-snd_line6_capture_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
-       return line6pcm->pos_in_done;
-}
-
-/* capture operators */
-struct snd_pcm_ops snd_line6_capture_ops = {
-       .open = snd_line6_capture_open,
-       .close = snd_line6_capture_close,
-       .ioctl = snd_pcm_lib_ioctl,
-       .hw_params = snd_line6_capture_hw_params,
-       .hw_free = snd_line6_capture_hw_free,
-       .prepare = snd_line6_prepare,
-       .trigger = snd_line6_trigger,
-       .pointer = snd_line6_capture_pointer,
-};
-
-int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
-{
-       int i;
-
-       /* create audio URBs and fill in constant values: */
-       for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
-               struct urb *urb;
-
-               /* URB for audio in: */
-               urb = line6pcm->urb_audio_in[i] =
-                   usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
-
-               if (urb == NULL) {
-                       dev_err(line6pcm->line6->ifcdev, "Out of memory\n");
-                       return -ENOMEM;
-               }
-
-               urb->dev = line6pcm->line6->usbdev;
-               urb->pipe =
-                   usb_rcvisocpipe(line6pcm->line6->usbdev,
-                                   line6pcm->ep_audio_read &
-                                   USB_ENDPOINT_NUMBER_MASK);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->start_frame = -1;
-               urb->number_of_packets = LINE6_ISO_PACKETS;
-               urb->interval = LINE6_ISO_INTERVAL;
-               urb->error_count = 0;
-               urb->complete = audio_in_callback;
-       }
-
-       return 0;
-}
diff --git a/drivers/staging/line6/capture.h b/drivers/staging/line6/capture.h
deleted file mode 100644 (file)
index 4157bcb..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *     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, version 2.
- *
- */
-
-#ifndef CAPTURE_H
-#define CAPTURE_H
-
-#include <sound/pcm.h>
-
-#include "driver.h"
-#include "pcm.h"
-
-extern struct snd_pcm_ops snd_line6_capture_ops;
-
-extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf,
-                              int fsize);
-extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm,
-                                      int length);
-extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm);
-extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm
-                                                 *line6pcm);
-extern void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm);
-extern int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd);
-
-#endif
diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c
deleted file mode 100644 (file)
index 503b2d7..0000000
+++ /dev/null
@@ -1,1162 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *     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, version 2.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-
-#include "audio.h"
-#include "capture.h"
-#include "driver.h"
-#include "midi.h"
-#include "playback.h"
-#include "pod.h"
-#include "podhd.h"
-#include "revision.h"
-#include "toneport.h"
-#include "usbdefs.h"
-#include "variax.h"
-
-#define DRIVER_AUTHOR  "Markus Grabner <grabner@icg.tugraz.at>"
-#define DRIVER_DESC    "Line6 USB Driver"
-#define DRIVER_VERSION "0.9.1beta" DRIVER_REVISION
-
-/* table of devices that work with this driver */
-static const struct usb_device_id line6_id_table[] = {
-       {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXT)},
-       {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXTLIVE)},
-       {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXTPRO)},
-       {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_GUITARPORT)},
-       {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_POCKETPOD)},
-       {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD300)},
-       {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD400)},
-       {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD500)},
-       {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_GX)},
-       {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_UX1)},
-       {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_UX2)},
-       {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODX3)},
-       {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODX3LIVE)},
-       {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXT)},
-       {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXTLIVE)},
-       {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXTPRO)},
-       {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_GX)},
-       {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_UX1)},
-       {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_UX2)},
-       {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_VARIAX)},
-       {},
-};
-
-MODULE_DEVICE_TABLE(usb, line6_id_table);
-
-#define L6PROP(dev_bit, dev_id, dev_name, dev_cap)\
-       {.device_bit = LINE6_BIT_##dev_bit, .id = dev_id,\
-        .name = dev_name, .capabilities = LINE6_BIT_##dev_cap}
-
-/* *INDENT-OFF* */
-static const struct line6_properties line6_properties_table[] = {
-       L6PROP(BASSPODXT,     "BassPODxt",     "BassPODxt",        CTRL_PCM_HW),
-       L6PROP(BASSPODXTLIVE, "BassPODxtLive", "BassPODxt Live",   CTRL_PCM_HW),
-       L6PROP(BASSPODXTPRO,  "BassPODxtPro",  "BassPODxt Pro",    CTRL_PCM_HW),
-       L6PROP(GUITARPORT,    "GuitarPort",    "GuitarPort",       PCM),
-       L6PROP(POCKETPOD,     "PocketPOD",     "Pocket POD",       CONTROL),
-       L6PROP(PODHD300,      "PODHD300",      "POD HD300",        CTRL_PCM_HW),
-       L6PROP(PODHD400,      "PODHD400",      "POD HD400",        CTRL_PCM_HW),
-       L6PROP(PODHD500,      "PODHD500",      "POD HD500",        CTRL_PCM_HW),
-       L6PROP(PODSTUDIO_GX,  "PODStudioGX",   "POD Studio GX",    PCM),
-       L6PROP(PODSTUDIO_UX1, "PODStudioUX1",  "POD Studio UX1",   PCM),
-       L6PROP(PODSTUDIO_UX2, "PODStudioUX2",  "POD Studio UX2",   PCM),
-       L6PROP(PODX3,         "PODX3",         "POD X3",           PCM),
-       L6PROP(PODX3LIVE,     "PODX3Live",     "POD X3 Live",      PCM),
-       L6PROP(PODXT,         "PODxt",         "PODxt",            CTRL_PCM_HW),
-       L6PROP(PODXTLIVE,     "PODxtLive",     "PODxt Live",       CTRL_PCM_HW),
-       L6PROP(PODXTPRO,      "PODxtPro",      "PODxt Pro",        CTRL_PCM_HW),
-       L6PROP(TONEPORT_GX,   "TonePortGX",    "TonePort GX",      PCM),
-       L6PROP(TONEPORT_UX1,  "TonePortUX1",   "TonePort UX1",     PCM),
-       L6PROP(TONEPORT_UX2,  "TonePortUX2",   "TonePort UX2",     PCM),
-       L6PROP(VARIAX,        "Variax",        "Variax Workbench", CONTROL),
-};
-/* *INDENT-ON* */
-
-/*
-       This is Line6's MIDI manufacturer ID.
-*/
-const unsigned char line6_midi_id[] = {
-       0x00, 0x01, 0x0c
-};
-
-/*
-       Code to request version of POD, Variax interface
-       (and maybe other devices).
-*/
-static const char line6_request_version[] = {
-       0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7
-};
-
-/**
-        Class for asynchronous messages.
-*/
-struct message {
-       struct usb_line6 *line6;
-       const char *buffer;
-       int size;
-       int done;
-};
-
-/*
-       Forward declarations.
-*/
-static void line6_data_received(struct urb *urb);
-static int line6_send_raw_message_async_part(struct message *msg,
-                                            struct urb *urb);
-
-/*
-       Start to listen on endpoint.
-*/
-static int line6_start_listen(struct usb_line6 *line6)
-{
-       int err;
-
-       usb_fill_int_urb(line6->urb_listen, line6->usbdev,
-                        usb_rcvintpipe(line6->usbdev, line6->ep_control_read),
-                        line6->buffer_listen, LINE6_BUFSIZE_LISTEN,
-                        line6_data_received, line6, line6->interval);
-       line6->urb_listen->actual_length = 0;
-       err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC);
-       return err;
-}
-
-/*
-       Stop listening on endpoint.
-*/
-static void line6_stop_listen(struct usb_line6 *line6)
-{
-       usb_kill_urb(line6->urb_listen);
-}
-
-/*
-       Send raw message in pieces of wMaxPacketSize bytes.
-*/
-int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
-                          int size)
-{
-       int i, done = 0;
-
-       for (i = 0; i < size; i += line6->max_packet_size) {
-               int partial;
-               const char *frag_buf = buffer + i;
-               int frag_size = min(line6->max_packet_size, size - i);
-               int retval;
-
-               retval = usb_interrupt_msg(line6->usbdev,
-                                       usb_sndintpipe(line6->usbdev,
-                                               line6->ep_control_write),
-                                       (char *)frag_buf, frag_size,
-                                       &partial, LINE6_TIMEOUT * HZ);
-
-               if (retval) {
-                       dev_err(line6->ifcdev,
-                               "usb_interrupt_msg failed (%d)\n", retval);
-                       break;
-               }
-
-               done += frag_size;
-       }
-
-       return done;
-}
-
-/*
-       Notification of completion of asynchronous request transmission.
-*/
-static void line6_async_request_sent(struct urb *urb)
-{
-       struct message *msg = (struct message *)urb->context;
-
-       if (msg->done >= msg->size) {
-               usb_free_urb(urb);
-               kfree(msg);
-       } else
-               line6_send_raw_message_async_part(msg, urb);
-}
-
-/*
-       Asynchronously send part of a raw message.
-*/
-static int line6_send_raw_message_async_part(struct message *msg,
-                                            struct urb *urb)
-{
-       int retval;
-       struct usb_line6 *line6 = msg->line6;
-       int done = msg->done;
-       int bytes = min(msg->size - done, line6->max_packet_size);
-
-       usb_fill_int_urb(urb, line6->usbdev,
-                        usb_sndintpipe(line6->usbdev, line6->ep_control_write),
-                        (char *)msg->buffer + done, bytes,
-                        line6_async_request_sent, msg, line6->interval);
-
-       msg->done += bytes;
-       retval = usb_submit_urb(urb, GFP_ATOMIC);
-
-       if (retval < 0) {
-               dev_err(line6->ifcdev, "%s: usb_submit_urb failed (%d)\n",
-                       __func__, retval);
-               usb_free_urb(urb);
-               kfree(msg);
-               return retval;
-       }
-
-       return 0;
-}
-
-/*
-       Setup and start timer.
-*/
-void line6_start_timer(struct timer_list *timer, unsigned int msecs,
-                      void (*function)(unsigned long), unsigned long data)
-{
-       setup_timer(timer, function, data);
-       timer->expires = jiffies + msecs * HZ / 1000;
-       add_timer(timer);
-}
-
-/*
-       Asynchronously send raw message.
-*/
-int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer,
-                                int size)
-{
-       struct message *msg;
-       struct urb *urb;
-
-       /* create message: */
-       msg = kmalloc(sizeof(struct message), GFP_ATOMIC);
-       if (msg == NULL)
-               return -ENOMEM;
-
-       /* create URB: */
-       urb = usb_alloc_urb(0, GFP_ATOMIC);
-
-       if (urb == NULL) {
-               kfree(msg);
-               dev_err(line6->ifcdev, "Out of memory\n");
-               return -ENOMEM;
-       }
-
-       /* set message data: */
-       msg->line6 = line6;
-       msg->buffer = buffer;
-       msg->size = size;
-       msg->done = 0;
-
-       /* start sending: */
-       return line6_send_raw_message_async_part(msg, urb);
-}
-
-/*
-       Send asynchronous device version request.
-*/
-int line6_version_request_async(struct usb_line6 *line6)
-{
-       char *buffer;
-       int retval;
-
-       buffer = kmemdup(line6_request_version,
-                       sizeof(line6_request_version), GFP_ATOMIC);
-       if (buffer == NULL) {
-               dev_err(line6->ifcdev, "Out of memory");
-               return -ENOMEM;
-       }
-
-       retval = line6_send_raw_message_async(line6, buffer,
-                                             sizeof(line6_request_version));
-       kfree(buffer);
-       return retval;
-}
-
-/*
-       Send sysex message in pieces of wMaxPacketSize bytes.
-*/
-int line6_send_sysex_message(struct usb_line6 *line6, const char *buffer,
-                            int size)
-{
-       return line6_send_raw_message(line6, buffer,
-                                     size + SYSEX_EXTRA_SIZE) -
-           SYSEX_EXTRA_SIZE;
-}
-
-/*
-       Allocate buffer for sysex message and prepare header.
-       @param code sysex message code
-       @param size number of bytes between code and sysex end
-*/
-char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2,
-                              int size)
-{
-       char *buffer = kmalloc(size + SYSEX_EXTRA_SIZE, GFP_ATOMIC);
-
-       if (!buffer)
-               return NULL;
-
-       buffer[0] = LINE6_SYSEX_BEGIN;
-       memcpy(buffer + 1, line6_midi_id, sizeof(line6_midi_id));
-       buffer[sizeof(line6_midi_id) + 1] = code1;
-       buffer[sizeof(line6_midi_id) + 2] = code2;
-       buffer[sizeof(line6_midi_id) + 3 + size] = LINE6_SYSEX_END;
-       return buffer;
-}
-
-/*
-       Notification of data received from the Line6 device.
-*/
-static void line6_data_received(struct urb *urb)
-{
-       struct usb_line6 *line6 = (struct usb_line6 *)urb->context;
-       struct midi_buffer *mb = &line6->line6midi->midibuf_in;
-       int done;
-
-       if (urb->status == -ESHUTDOWN)
-               return;
-
-       done =
-           line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length);
-
-       if (done < urb->actual_length) {
-               line6_midibuf_ignore(mb, done);
-               dev_dbg(line6->ifcdev, "%d %d buffer overflow - message skipped\n",
-                       done, urb->actual_length);
-       }
-
-       for (;;) {
-               done =
-                   line6_midibuf_read(mb, line6->buffer_message,
-                                      LINE6_MESSAGE_MAXLEN);
-
-               if (done == 0)
-                       break;
-
-               line6->message_length = done;
-               line6_midi_receive(line6, line6->buffer_message, done);
-
-               switch (le16_to_cpu(line6->usbdev->descriptor.idProduct)) {
-               case LINE6_DEVID_BASSPODXT:
-               case LINE6_DEVID_BASSPODXTLIVE:
-               case LINE6_DEVID_BASSPODXTPRO:
-               case LINE6_DEVID_PODXT:
-               case LINE6_DEVID_PODXTPRO:
-               case LINE6_DEVID_POCKETPOD:
-                       line6_pod_process_message((struct usb_line6_pod *)
-                                                 line6);
-                       break;
-
-               case LINE6_DEVID_PODHD300:
-               case LINE6_DEVID_PODHD400:
-               case LINE6_DEVID_PODHD500:
-                       break; /* let userspace handle MIDI */
-
-               case LINE6_DEVID_PODXTLIVE:
-                       switch (line6->interface_number) {
-                       case PODXTLIVE_INTERFACE_POD:
-                               line6_pod_process_message((struct usb_line6_pod
-                                                          *)line6);
-                               break;
-
-                       case PODXTLIVE_INTERFACE_VARIAX:
-                               line6_variax_process_message((struct
-                                                             usb_line6_variax
-                                                             *)line6);
-                               break;
-
-                       default:
-                               dev_err(line6->ifcdev,
-                                       "PODxt Live interface %d not supported\n",
-                                       line6->interface_number);
-                       }
-                       break;
-
-               case LINE6_DEVID_VARIAX:
-                       line6_variax_process_message((struct usb_line6_variax *)
-                                                    line6);
-                       break;
-
-               default:
-                       MISSING_CASE;
-               }
-       }
-
-       line6_start_listen(line6);
-}
-
-/*
-       Send channel number (i.e., switch to a different sound).
-*/
-int line6_send_program(struct usb_line6 *line6, u8 value)
-{
-       int retval;
-       unsigned char *buffer;
-       int partial;
-
-       buffer = kmalloc(2, GFP_KERNEL);
-       if (!buffer)
-               return -ENOMEM;
-
-       buffer[0] = LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST;
-       buffer[1] = value;
-
-       retval = usb_interrupt_msg(line6->usbdev,
-                                  usb_sndintpipe(line6->usbdev,
-                                                 line6->ep_control_write),
-                                  buffer, 2, &partial, LINE6_TIMEOUT * HZ);
-
-       if (retval)
-               dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n",
-                       retval);
-
-       kfree(buffer);
-       return retval;
-}
-
-/*
-       Transmit Line6 control parameter.
-*/
-int line6_transmit_parameter(struct usb_line6 *line6, int param, u8 value)
-{
-       int retval;
-       unsigned char *buffer;
-       int partial;
-
-       buffer = kmalloc(3, GFP_KERNEL);
-       if (!buffer)
-               return -ENOMEM;
-
-       buffer[0] = LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST;
-       buffer[1] = param;
-       buffer[2] = value;
-
-       retval = usb_interrupt_msg(line6->usbdev,
-                                  usb_sndintpipe(line6->usbdev,
-                                                 line6->ep_control_write),
-                                  buffer, 3, &partial, LINE6_TIMEOUT * HZ);
-
-       if (retval)
-               dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n",
-                       retval);
-
-       kfree(buffer);
-       return retval;
-}
-
-/*
-       Read data from device.
-*/
-int line6_read_data(struct usb_line6 *line6, int address, void *data,
-                   size_t datalen)
-{
-       struct usb_device *usbdev = line6->usbdev;
-       int ret;
-       unsigned char len;
-
-       /* query the serial number: */
-       ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
-                             USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
-                             (datalen << 8) | 0x21, address,
-                             NULL, 0, LINE6_TIMEOUT * HZ);
-
-       if (ret < 0) {
-               dev_err(line6->ifcdev, "read request failed (error %d)\n", ret);
-               return ret;
-       }
-
-       /* Wait for data length. We'll get 0xff until length arrives. */
-       do {
-               ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67,
-                                     USB_TYPE_VENDOR | USB_RECIP_DEVICE |
-                                     USB_DIR_IN,
-                                     0x0012, 0x0000, &len, 1,
-                                     LINE6_TIMEOUT * HZ);
-               if (ret < 0) {
-                       dev_err(line6->ifcdev,
-                               "receive length failed (error %d)\n", ret);
-                       return ret;
-               }
-       } while (len == 0xff);
-
-       if (len != datalen) {
-               /* should be equal or something went wrong */
-               dev_err(line6->ifcdev,
-                       "length mismatch (expected %d, got %d)\n",
-                       (int)datalen, (int)len);
-               return -EINVAL;
-       }
-
-       /* receive the result: */
-       ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67,
-                             USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                             0x0013, 0x0000, data, datalen,
-                             LINE6_TIMEOUT * HZ);
-
-       if (ret < 0) {
-               dev_err(line6->ifcdev, "read failed (error %d)\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-/*
-       Write data to device.
-*/
-int line6_write_data(struct usb_line6 *line6, int address, void *data,
-                    size_t datalen)
-{
-       struct usb_device *usbdev = line6->usbdev;
-       int ret;
-       unsigned char status;
-
-       ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
-                             USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
-                             0x0022, address, data, datalen,
-                             LINE6_TIMEOUT * HZ);
-
-       if (ret < 0) {
-               dev_err(line6->ifcdev,
-                       "write request failed (error %d)\n", ret);
-               return ret;
-       }
-
-       do {
-               ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
-                                     0x67,
-                                     USB_TYPE_VENDOR | USB_RECIP_DEVICE |
-                                     USB_DIR_IN,
-                                     0x0012, 0x0000,
-                                     &status, 1, LINE6_TIMEOUT * HZ);
-
-               if (ret < 0) {
-                       dev_err(line6->ifcdev,
-                               "receiving status failed (error %d)\n", ret);
-                       return ret;
-               }
-       } while (status == 0xff);
-
-       if (status != 0) {
-               dev_err(line6->ifcdev, "write failed (error %d)\n", ret);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/*
-       Read Line6 device serial number.
-       (POD, TonePort, GuitarPort)
-*/
-int line6_read_serial_number(struct usb_line6 *line6, int *serial_number)
-{
-       return line6_read_data(line6, 0x80d0, serial_number,
-                              sizeof(*serial_number));
-}
-
-/*
-       No operation (i.e., unsupported).
-*/
-ssize_t line6_nop_read(struct device *dev, struct device_attribute *attr,
-                      char *buf)
-{
-       return 0;
-}
-
-/*
-       Generic destructor.
-*/
-static void line6_destruct(struct usb_interface *interface)
-{
-       struct usb_line6 *line6;
-
-       if (interface == NULL)
-               return;
-       line6 = usb_get_intfdata(interface);
-       if (line6 == NULL)
-               return;
-
-       /* free buffer memory first: */
-       kfree(line6->buffer_message);
-       kfree(line6->buffer_listen);
-
-       /* then free URBs: */
-       usb_free_urb(line6->urb_listen);
-
-       /* make sure the device isn't destructed twice: */
-       usb_set_intfdata(interface, NULL);
-
-       /* free interface data: */
-       kfree(line6);
-}
-
-/*
-       Probe USB device.
-*/
-static int line6_probe(struct usb_interface *interface,
-                      const struct usb_device_id *id)
-{
-       int devtype;
-       struct usb_device *usbdev;
-       struct usb_line6 *line6;
-       const struct line6_properties *properties;
-       int interface_number, alternate = 0;
-       int product;
-       int size = 0;
-       int ep_read = 0, ep_write = 0;
-       int ret;
-
-       if (interface == NULL)
-               return -ENODEV;
-       usbdev = interface_to_usbdev(interface);
-       if (usbdev == NULL)
-               return -ENODEV;
-
-       /* we don't handle multiple configurations */
-       if (usbdev->descriptor.bNumConfigurations != 1) {
-               ret = -ENODEV;
-               goto err_put;
-       }
-
-       /* check vendor and product id */
-       for (devtype = ARRAY_SIZE(line6_id_table) - 1; devtype--;) {
-               u16 idVendor = le16_to_cpu(usbdev->descriptor.idVendor);
-               u16 idProduct = le16_to_cpu(usbdev->descriptor.idProduct);
-
-               if (idVendor == line6_id_table[devtype].idVendor &&
-                   idProduct == line6_id_table[devtype].idProduct)
-                       break;
-       }
-
-       if (devtype < 0) {
-               ret = -ENODEV;
-               goto err_put;
-       }
-
-       /* initialize device info: */
-       properties = &line6_properties_table[devtype];
-       dev_info(&interface->dev, "Line6 %s found\n", properties->name);
-       product = le16_to_cpu(usbdev->descriptor.idProduct);
-
-       /* query interface number */
-       interface_number = interface->cur_altsetting->desc.bInterfaceNumber;
-
-       switch (product) {
-       case LINE6_DEVID_BASSPODXTLIVE:
-       case LINE6_DEVID_PODXTLIVE:
-       case LINE6_DEVID_VARIAX:
-               alternate = 1;
-               break;
-
-       case LINE6_DEVID_POCKETPOD:
-               switch (interface_number) {
-               case 0:
-                       return -ENODEV; /* this interface has no endpoints */
-               case 1:
-                       alternate = 0;
-                       break;
-               default:
-                       MISSING_CASE;
-               }
-               break;
-
-       case LINE6_DEVID_PODHD500:
-       case LINE6_DEVID_PODX3:
-       case LINE6_DEVID_PODX3LIVE:
-               switch (interface_number) {
-               case 0:
-                       alternate = 1;
-                       break;
-               case 1:
-                       alternate = 0;
-                       break;
-               default:
-                       MISSING_CASE;
-               }
-               break;
-
-       case LINE6_DEVID_BASSPODXT:
-       case LINE6_DEVID_BASSPODXTPRO:
-       case LINE6_DEVID_PODXT:
-       case LINE6_DEVID_PODXTPRO:
-       case LINE6_DEVID_PODHD300:
-       case LINE6_DEVID_PODHD400:
-               alternate = 5;
-               break;
-
-       case LINE6_DEVID_GUITARPORT:
-       case LINE6_DEVID_PODSTUDIO_GX:
-       case LINE6_DEVID_PODSTUDIO_UX1:
-       case LINE6_DEVID_TONEPORT_GX:
-       case LINE6_DEVID_TONEPORT_UX1:
-               alternate = 2;  /* 1..4 seem to be ok */
-               break;
-
-       case LINE6_DEVID_TONEPORT_UX2:
-       case LINE6_DEVID_PODSTUDIO_UX2:
-               switch (interface_number) {
-               case 0:
-                       /* defaults to 44.1kHz, 16-bit */
-                       alternate = 2;
-                       break;
-               case 1:
-                       /* don't know yet what this is ...
-                          alternate = 1;
-                          break;
-                        */
-                       return -ENODEV;
-               default:
-                       MISSING_CASE;
-               }
-               break;
-
-       default:
-               MISSING_CASE;
-               ret = -ENODEV;
-               goto err_put;
-       }
-
-       ret = usb_set_interface(usbdev, interface_number, alternate);
-       if (ret < 0) {
-               dev_err(&interface->dev, "set_interface failed\n");
-               goto err_put;
-       }
-
-       /* initialize device data based on product id: */
-       switch (product) {
-       case LINE6_DEVID_BASSPODXT:
-       case LINE6_DEVID_BASSPODXTLIVE:
-       case LINE6_DEVID_BASSPODXTPRO:
-       case LINE6_DEVID_PODXT:
-       case LINE6_DEVID_PODXTPRO:
-               size = sizeof(struct usb_line6_pod);
-               ep_read = 0x84;
-               ep_write = 0x03;
-               break;
-
-       case LINE6_DEVID_PODHD300:
-       case LINE6_DEVID_PODHD400:
-               size = sizeof(struct usb_line6_podhd);
-               ep_read = 0x84;
-               ep_write = 0x03;
-               break;
-
-       case LINE6_DEVID_PODHD500:
-               size = sizeof(struct usb_line6_podhd);
-               ep_read = 0x81;
-               ep_write = 0x01;
-               break;
-
-       case LINE6_DEVID_POCKETPOD:
-               size = sizeof(struct usb_line6_pod);
-               ep_read = 0x82;
-               ep_write = 0x02;
-               break;
-
-       case LINE6_DEVID_PODX3:
-       case LINE6_DEVID_PODX3LIVE:
-               /* currently unused! */
-               size = sizeof(struct usb_line6_pod);
-               ep_read = 0x81;
-               ep_write = 0x01;
-               break;
-
-       case LINE6_DEVID_PODSTUDIO_GX:
-       case LINE6_DEVID_PODSTUDIO_UX1:
-       case LINE6_DEVID_PODSTUDIO_UX2:
-       case LINE6_DEVID_TONEPORT_GX:
-       case LINE6_DEVID_TONEPORT_UX1:
-       case LINE6_DEVID_TONEPORT_UX2:
-       case LINE6_DEVID_GUITARPORT:
-               size = sizeof(struct usb_line6_toneport);
-               /* these don't have a control channel */
-               break;
-
-       case LINE6_DEVID_PODXTLIVE:
-               switch (interface_number) {
-               case PODXTLIVE_INTERFACE_POD:
-                       size = sizeof(struct usb_line6_pod);
-                       ep_read = 0x84;
-                       ep_write = 0x03;
-                       break;
-
-               case PODXTLIVE_INTERFACE_VARIAX:
-                       size = sizeof(struct usb_line6_variax);
-                       ep_read = 0x86;
-                       ep_write = 0x05;
-                       break;
-
-               default:
-                       ret = -ENODEV;
-                       goto err_put;
-               }
-               break;
-
-       case LINE6_DEVID_VARIAX:
-               size = sizeof(struct usb_line6_variax);
-               ep_read = 0x82;
-               ep_write = 0x01;
-               break;
-
-       default:
-               MISSING_CASE;
-               ret = -ENODEV;
-               goto err_put;
-       }
-
-       if (size == 0) {
-               dev_err(&interface->dev,
-                       "driver bug: interface data size not set\n");
-               ret = -ENODEV;
-               goto err_put;
-       }
-
-       line6 = kzalloc(size, GFP_KERNEL);
-       if (line6 == NULL) {
-               ret = -ENODEV;
-               goto err_put;
-       }
-
-       /* store basic data: */
-       line6->interface_number = interface_number;
-       line6->properties = properties;
-       line6->usbdev = usbdev;
-       line6->ifcdev = &interface->dev;
-       line6->ep_control_read = ep_read;
-       line6->ep_control_write = ep_write;
-       line6->product = product;
-
-       /* get data from endpoint descriptor (see usb_maxpacket): */
-       {
-               struct usb_host_endpoint *ep;
-               unsigned epnum =
-                   usb_pipeendpoint(usb_rcvintpipe(usbdev, ep_read));
-               ep = usbdev->ep_in[epnum];
-
-               if (ep != NULL) {
-                       line6->interval = ep->desc.bInterval;
-                       line6->max_packet_size =
-                           le16_to_cpu(ep->desc.wMaxPacketSize);
-               } else {
-                       line6->interval = LINE6_FALLBACK_INTERVAL;
-                       line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE;
-                       dev_err(line6->ifcdev,
-                               "endpoint not available, using fallback values");
-               }
-       }
-
-       usb_set_intfdata(interface, line6);
-
-       if (properties->capabilities & LINE6_BIT_CONTROL) {
-               /* initialize USB buffers: */
-               line6->buffer_listen =
-                   kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL);
-               if (line6->buffer_listen == NULL) {
-                       ret = -ENOMEM;
-                       goto err_destruct;
-               }
-
-               line6->buffer_message =
-                   kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL);
-               if (line6->buffer_message == NULL) {
-                       ret = -ENOMEM;
-                       goto err_destruct;
-               }
-
-               line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL);
-
-               if (line6->urb_listen == NULL) {
-                       dev_err(&interface->dev, "Out of memory\n");
-                       line6_destruct(interface);
-                       ret = -ENOMEM;
-                       goto err_destruct;
-               }
-
-               ret = line6_start_listen(line6);
-               if (ret < 0) {
-                       dev_err(&interface->dev, "%s: usb_submit_urb failed\n",
-                               __func__);
-                       goto err_destruct;
-               }
-       }
-
-       /* initialize device data based on product id: */
-       switch (product) {
-       case LINE6_DEVID_BASSPODXT:
-       case LINE6_DEVID_BASSPODXTLIVE:
-       case LINE6_DEVID_BASSPODXTPRO:
-       case LINE6_DEVID_POCKETPOD:
-       case LINE6_DEVID_PODX3:
-       case LINE6_DEVID_PODX3LIVE:
-       case LINE6_DEVID_PODXT:
-       case LINE6_DEVID_PODXTPRO:
-               ret = line6_pod_init(interface, (struct usb_line6_pod *)line6);
-               break;
-
-       case LINE6_DEVID_PODHD300:
-       case LINE6_DEVID_PODHD400:
-       case LINE6_DEVID_PODHD500:
-               ret = line6_podhd_init(interface,
-                                      (struct usb_line6_podhd *)line6);
-               break;
-
-       case LINE6_DEVID_PODXTLIVE:
-               switch (interface_number) {
-               case PODXTLIVE_INTERFACE_POD:
-                       ret =
-                           line6_pod_init(interface,
-                                          (struct usb_line6_pod *)line6);
-                       break;
-
-               case PODXTLIVE_INTERFACE_VARIAX:
-                       ret =
-                           line6_variax_init(interface,
-                                             (struct usb_line6_variax *)line6);
-                       break;
-
-               default:
-                       dev_err(&interface->dev,
-                               "PODxt Live interface %d not supported\n",
-                               interface_number);
-                       ret = -ENODEV;
-               }
-
-               break;
-
-       case LINE6_DEVID_VARIAX:
-               ret =
-                   line6_variax_init(interface,
-                                     (struct usb_line6_variax *)line6);
-               break;
-
-       case LINE6_DEVID_PODSTUDIO_GX:
-       case LINE6_DEVID_PODSTUDIO_UX1:
-       case LINE6_DEVID_PODSTUDIO_UX2:
-       case LINE6_DEVID_TONEPORT_GX:
-       case LINE6_DEVID_TONEPORT_UX1:
-       case LINE6_DEVID_TONEPORT_UX2:
-       case LINE6_DEVID_GUITARPORT:
-               ret =
-                   line6_toneport_init(interface,
-                                       (struct usb_line6_toneport *)line6);
-               break;
-
-       default:
-               MISSING_CASE;
-               ret = -ENODEV;
-       }
-
-       if (ret < 0)
-               goto err_destruct;
-
-       ret = sysfs_create_link(&interface->dev.kobj, &usbdev->dev.kobj,
-                               "usb_device");
-       if (ret < 0)
-               goto err_destruct;
-
-       /* creation of additional special files should go here */
-
-       dev_info(&interface->dev, "Line6 %s now attached\n",
-                line6->properties->name);
-
-       switch (product) {
-       case LINE6_DEVID_PODX3:
-       case LINE6_DEVID_PODX3LIVE:
-               dev_info(&interface->dev,
-                        "NOTE: the Line6 %s is detected, but not yet supported\n",
-                        line6->properties->name);
-       }
-
-       /* increment reference counters: */
-       usb_get_intf(interface);
-       usb_get_dev(usbdev);
-
-       return 0;
-
-err_destruct:
-       line6_destruct(interface);
-err_put:
-       return ret;
-}
-
-/*
-       Line6 device disconnected.
-*/
-static void line6_disconnect(struct usb_interface *interface)
-{
-       struct usb_line6 *line6;
-       struct usb_device *usbdev;
-       int interface_number;
-
-       if (interface == NULL)
-               return;
-       usbdev = interface_to_usbdev(interface);
-       if (usbdev == NULL)
-               return;
-
-       /* removal of additional special files should go here */
-
-       sysfs_remove_link(&interface->dev.kobj, "usb_device");
-
-       interface_number = interface->cur_altsetting->desc.bInterfaceNumber;
-       line6 = usb_get_intfdata(interface);
-
-       if (line6 != NULL) {
-               if (line6->urb_listen != NULL)
-                       line6_stop_listen(line6);
-
-               if (usbdev != line6->usbdev)
-                       dev_err(line6->ifcdev,
-                               "driver bug: inconsistent usb device\n");
-
-               switch (le16_to_cpu(line6->usbdev->descriptor.idProduct)) {
-               case LINE6_DEVID_BASSPODXT:
-               case LINE6_DEVID_BASSPODXTLIVE:
-               case LINE6_DEVID_BASSPODXTPRO:
-               case LINE6_DEVID_POCKETPOD:
-               case LINE6_DEVID_PODX3:
-               case LINE6_DEVID_PODX3LIVE:
-               case LINE6_DEVID_PODXT:
-               case LINE6_DEVID_PODXTPRO:
-                       line6_pod_disconnect(interface);
-                       break;
-
-               case LINE6_DEVID_PODHD300:
-               case LINE6_DEVID_PODHD400:
-               case LINE6_DEVID_PODHD500:
-                       line6_podhd_disconnect(interface);
-                       break;
-
-               case LINE6_DEVID_PODXTLIVE:
-                       switch (interface_number) {
-                       case PODXTLIVE_INTERFACE_POD:
-                               line6_pod_disconnect(interface);
-                               break;
-
-                       case PODXTLIVE_INTERFACE_VARIAX:
-                               line6_variax_disconnect(interface);
-                               break;
-                       }
-
-                       break;
-
-               case LINE6_DEVID_VARIAX:
-                       line6_variax_disconnect(interface);
-                       break;
-
-               case LINE6_DEVID_PODSTUDIO_GX:
-               case LINE6_DEVID_PODSTUDIO_UX1:
-               case LINE6_DEVID_PODSTUDIO_UX2:
-               case LINE6_DEVID_TONEPORT_GX:
-               case LINE6_DEVID_TONEPORT_UX1:
-               case LINE6_DEVID_TONEPORT_UX2:
-               case LINE6_DEVID_GUITARPORT:
-                       line6_toneport_disconnect(interface);
-                       break;
-
-               default:
-                       MISSING_CASE;
-               }
-
-               dev_info(&interface->dev, "Line6 %s now disconnected\n",
-                        line6->properties->name);
-       }
-
-       line6_destruct(interface);
-
-       /* decrement reference counters: */
-       usb_put_intf(interface);
-       usb_put_dev(usbdev);
-}
-
-#ifdef CONFIG_PM
-
-/*
-       Suspend Line6 device.
-*/
-static int line6_suspend(struct usb_interface *interface, pm_message_t message)
-{
-       struct usb_line6 *line6 = usb_get_intfdata(interface);
-       struct snd_line6_pcm *line6pcm = line6->line6pcm;
-
-       snd_power_change_state(line6->card, SNDRV_CTL_POWER_D3hot);
-
-       if (line6->properties->capabilities & LINE6_BIT_CONTROL)
-               line6_stop_listen(line6);
-
-       if (line6pcm != NULL) {
-               snd_pcm_suspend_all(line6pcm->pcm);
-               line6_pcm_disconnect(line6pcm);
-               line6pcm->flags = 0;
-       }
-
-       return 0;
-}
-
-/*
-       Resume Line6 device.
-*/
-static int line6_resume(struct usb_interface *interface)
-{
-       struct usb_line6 *line6 = usb_get_intfdata(interface);
-
-       if (line6->properties->capabilities & LINE6_BIT_CONTROL)
-               line6_start_listen(line6);
-
-       snd_power_change_state(line6->card, SNDRV_CTL_POWER_D0);
-       return 0;
-}
-
-/*
-       Resume Line6 device after reset.
-*/
-static int line6_reset_resume(struct usb_interface *interface)
-{
-       struct usb_line6 *line6 = usb_get_intfdata(interface);
-
-       switch (le16_to_cpu(line6->usbdev->descriptor.idProduct)) {
-       case LINE6_DEVID_PODSTUDIO_GX:
-       case LINE6_DEVID_PODSTUDIO_UX1:
-       case LINE6_DEVID_PODSTUDIO_UX2:
-       case LINE6_DEVID_TONEPORT_GX:
-       case LINE6_DEVID_TONEPORT_UX1:
-       case LINE6_DEVID_TONEPORT_UX2:
-       case LINE6_DEVID_GUITARPORT:
-               line6_toneport_reset_resume((struct usb_line6_toneport *)line6);
-       }
-
-       return line6_resume(interface);
-}
-
-#endif /* CONFIG_PM */
-
-static struct usb_driver line6_driver = {
-       .name = DRIVER_NAME,
-       .probe = line6_probe,
-       .disconnect = line6_disconnect,
-#ifdef CONFIG_PM
-       .suspend = line6_suspend,
-       .resume = line6_resume,
-       .reset_resume = line6_reset_resume,
-#endif
-       .id_table = line6_id_table,
-};
-
-module_usb_driver(line6_driver);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h
deleted file mode 100644 (file)
index 16e3fc2..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *     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, version 2.
- *
- */
-
-#ifndef DRIVER_H
-#define DRIVER_H
-
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-#include <sound/core.h>
-
-#include "midi.h"
-
-#define DRIVER_NAME "line6usb"
-
-#define LINE6_TIMEOUT 1
-#define LINE6_BUFSIZE_LISTEN 32
-#define LINE6_MESSAGE_MAXLEN 256
-
-/*
-       Line6 MIDI control commands
-*/
-#define LINE6_PARAM_CHANGE   0xb0
-#define LINE6_PROGRAM_CHANGE 0xc0
-#define LINE6_SYSEX_BEGIN    0xf0
-#define LINE6_SYSEX_END      0xf7
-#define LINE6_RESET          0xff
-
-/*
-       MIDI channel for messages initiated by the host
-       (and eventually echoed back by the device)
-*/
-#define LINE6_CHANNEL_HOST   0x00
-
-/*
-       MIDI channel for messages initiated by the device
-*/
-#define LINE6_CHANNEL_DEVICE 0x02
-
-#define LINE6_CHANNEL_UNKNOWN 5        /* don't know yet what this is good for */
-
-#define LINE6_CHANNEL_MASK 0x0f
-
-#define MISSING_CASE   \
-       pr_err("line6usb driver bug: missing case in %s:%d\n", \
-               __FILE__, __LINE__)
-
-#define CHECK_RETURN(x)                \
-do {                           \
-       err = x;                \
-       if (err < 0)            \
-               return err;     \
-} while (0)
-
-#define CHECK_STARTUP_PROGRESS(x, n)   \
-do {                                   \
-       if ((x) >= (n))                 \
-               return;                 \
-       x = (n);                        \
-} while (0)
-
-extern const unsigned char line6_midi_id[3];
-
-static const int SYSEX_DATA_OFS = sizeof(line6_midi_id) + 3;
-static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4;
-
-/**
-        Common properties of Line6 devices.
-*/
-struct line6_properties {
-       /**
-                Bit identifying this device in the line6usb driver.
-       */
-       int device_bit;
-
-       /**
-                Card id string (maximum 16 characters).
-                This can be used to address the device in ALSA programs as
-                "default:CARD=<id>"
-       */
-       const char *id;
-
-       /**
-                Card short name (maximum 32 characters).
-       */
-       const char *name;
-
-       /**
-                Bit vector defining this device's capabilities in the
-                line6usb driver.
-       */
-       int capabilities;
-};
-
-/**
-        Common data shared by all Line6 devices.
-        Corresponds to a pair of USB endpoints.
-*/
-struct usb_line6 {
-       /**
-                USB device.
-       */
-       struct usb_device *usbdev;
-
-       /**
-                Product id.
-       */
-       int product;
-
-       /**
-                Properties.
-       */
-       const struct line6_properties *properties;
-
-       /**
-                Interface number.
-       */
-       int interface_number;
-
-       /**
-                Interval (ms).
-       */
-       int interval;
-
-       /**
-                Maximum size of USB packet.
-       */
-       int max_packet_size;
-
-       /**
-                Device representing the USB interface.
-       */
-       struct device *ifcdev;
-
-       /**
-                Line6 sound card data structure.
-                Each device has at least MIDI or PCM.
-       */
-       struct snd_card *card;
-
-       /**
-                Line6 PCM device data structure.
-       */
-       struct snd_line6_pcm *line6pcm;
-
-       /**
-                Line6 MIDI device data structure.
-       */
-       struct snd_line6_midi *line6midi;
-
-       /**
-                USB endpoint for listening to control commands.
-       */
-       int ep_control_read;
-
-       /**
-                USB endpoint for writing control commands.
-       */
-       int ep_control_write;
-
-       /**
-                URB for listening to PODxt Pro control endpoint.
-       */
-       struct urb *urb_listen;
-
-       /**
-                Buffer for listening to PODxt Pro control endpoint.
-       */
-       unsigned char *buffer_listen;
-
-       /**
-                Buffer for message to be processed.
-       */
-       unsigned char *buffer_message;
-
-       /**
-                Length of message to be processed.
-       */
-       int message_length;
-};
-
-extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1,
-                                     int code2, int size);
-extern ssize_t line6_nop_read(struct device *dev,
-                             struct device_attribute *attr, char *buf);
-extern int line6_read_data(struct usb_line6 *line6, int address, void *data,
-                          size_t datalen);
-extern int line6_read_serial_number(struct usb_line6 *line6,
-                                   int *serial_number);
-extern int line6_send_program(struct usb_line6 *line6, u8 value);
-extern int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
-                                 int size);
-extern int line6_send_raw_message_async(struct usb_line6 *line6,
-                                       const char *buffer, int size);
-extern int line6_send_sysex_message(struct usb_line6 *line6,
-                                   const char *buffer, int size);
-extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr,
-                            const char *buf, size_t count);
-extern void line6_start_timer(struct timer_list *timer, unsigned int msecs,
-                             void (*function)(unsigned long),
-                             unsigned long data);
-extern int line6_transmit_parameter(struct usb_line6 *line6, int param,
-                                   u8 value);
-extern int line6_version_request_async(struct usb_line6 *line6);
-extern int line6_write_data(struct usb_line6 *line6, int address, void *data,
-                           size_t datalen);
-
-#endif
diff --git a/drivers/staging/line6/midi.c b/drivers/staging/line6/midi.c
deleted file mode 100644 (file)
index 1ac343b..0000000
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *     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, version 2.
- *
- */
-
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <sound/core.h>
-#include <sound/rawmidi.h>
-
-#include "audio.h"
-#include "driver.h"
-#include "midi.h"
-#include "pod.h"
-#include "usbdefs.h"
-
-#define line6_rawmidi_substream_midi(substream) \
-       ((struct snd_line6_midi *)((substream)->rmidi->private_data))
-
-static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
-                          int length);
-
-/*
-       Pass data received via USB to MIDI.
-*/
-void line6_midi_receive(struct usb_line6 *line6, unsigned char *data,
-                       int length)
-{
-       if (line6->line6midi->substream_receive)
-               snd_rawmidi_receive(line6->line6midi->substream_receive,
-                                   data, length);
-}
-
-/*
-       Read data from MIDI buffer and transmit them via USB.
-*/
-static void line6_midi_transmit(struct snd_rawmidi_substream *substream)
-{
-       struct usb_line6 *line6 =
-           line6_rawmidi_substream_midi(substream)->line6;
-       struct snd_line6_midi *line6midi = line6->line6midi;
-       struct midi_buffer *mb = &line6midi->midibuf_out;
-       unsigned long flags;
-       unsigned char chunk[LINE6_FALLBACK_MAXPACKETSIZE];
-       int req, done;
-
-       spin_lock_irqsave(&line6->line6midi->midi_transmit_lock, flags);
-
-       for (;;) {
-               req = min(line6_midibuf_bytes_free(mb), line6->max_packet_size);
-               done = snd_rawmidi_transmit_peek(substream, chunk, req);
-
-               if (done == 0)
-                       break;
-
-               line6_midibuf_write(mb, chunk, done);
-               snd_rawmidi_transmit_ack(substream, done);
-       }
-
-       for (;;) {
-               done = line6_midibuf_read(mb, chunk,
-                                         LINE6_FALLBACK_MAXPACKETSIZE);
-
-               if (done == 0)
-                       break;
-
-               send_midi_async(line6, chunk, done);
-       }
-
-       spin_unlock_irqrestore(&line6->line6midi->midi_transmit_lock, flags);
-}
-
-/*
-       Notification of completion of MIDI transmission.
-*/
-static void midi_sent(struct urb *urb)
-{
-       unsigned long flags;
-       int status;
-       int num;
-       struct usb_line6 *line6 = (struct usb_line6 *)urb->context;
-
-       status = urb->status;
-       kfree(urb->transfer_buffer);
-       usb_free_urb(urb);
-
-       if (status == -ESHUTDOWN)
-               return;
-
-       spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags);
-       num = --line6->line6midi->num_active_send_urbs;
-
-       if (num == 0) {
-               line6_midi_transmit(line6->line6midi->substream_transmit);
-               num = line6->line6midi->num_active_send_urbs;
-       }
-
-       if (num == 0)
-               wake_up(&line6->line6midi->send_wait);
-
-       spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags);
-}
-
-/*
-       Send an asynchronous MIDI message.
-       Assumes that line6->line6midi->send_urb_lock is held
-       (i.e., this function is serialized).
-*/
-static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
-                          int length)
-{
-       struct urb *urb;
-       int retval;
-       unsigned char *transfer_buffer;
-
-       urb = usb_alloc_urb(0, GFP_ATOMIC);
-
-       if (urb == NULL) {
-               dev_err(line6->ifcdev, "Out of memory\n");
-               return -ENOMEM;
-       }
-
-       transfer_buffer = kmemdup(data, length, GFP_ATOMIC);
-
-       if (transfer_buffer == NULL) {
-               usb_free_urb(urb);
-               dev_err(line6->ifcdev, "Out of memory\n");
-               return -ENOMEM;
-       }
-
-       usb_fill_int_urb(urb, line6->usbdev,
-                        usb_sndbulkpipe(line6->usbdev,
-                                        line6->ep_control_write),
-                        transfer_buffer, length, midi_sent, line6,
-                        line6->interval);
-       urb->actual_length = 0;
-       retval = usb_submit_urb(urb, GFP_ATOMIC);
-
-       if (retval < 0) {
-               dev_err(line6->ifcdev, "usb_submit_urb failed\n");
-               usb_free_urb(urb);
-               return retval;
-       }
-
-       ++line6->line6midi->num_active_send_urbs;
-       return 0;
-}
-
-static int line6_midi_output_open(struct snd_rawmidi_substream *substream)
-{
-       return 0;
-}
-
-static int line6_midi_output_close(struct snd_rawmidi_substream *substream)
-{
-       return 0;
-}
-
-static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream,
-                                     int up)
-{
-       unsigned long flags;
-       struct usb_line6 *line6 =
-           line6_rawmidi_substream_midi(substream)->line6;
-
-       line6->line6midi->substream_transmit = substream;
-       spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags);
-
-       if (line6->line6midi->num_active_send_urbs == 0)
-               line6_midi_transmit(substream);
-
-       spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags);
-}
-
-static void line6_midi_output_drain(struct snd_rawmidi_substream *substream)
-{
-       struct usb_line6 *line6 =
-           line6_rawmidi_substream_midi(substream)->line6;
-       struct snd_line6_midi *midi = line6->line6midi;
-
-       wait_event_interruptible(midi->send_wait,
-                                midi->num_active_send_urbs == 0);
-}
-
-static int line6_midi_input_open(struct snd_rawmidi_substream *substream)
-{
-       return 0;
-}
-
-static int line6_midi_input_close(struct snd_rawmidi_substream *substream)
-{
-       return 0;
-}
-
-static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream,
-                                    int up)
-{
-       struct usb_line6 *line6 =
-           line6_rawmidi_substream_midi(substream)->line6;
-
-       if (up)
-               line6->line6midi->substream_receive = substream;
-       else
-               line6->line6midi->substream_receive = NULL;
-}
-
-static struct snd_rawmidi_ops line6_midi_output_ops = {
-       .open = line6_midi_output_open,
-       .close = line6_midi_output_close,
-       .trigger = line6_midi_output_trigger,
-       .drain = line6_midi_output_drain,
-};
-
-static struct snd_rawmidi_ops line6_midi_input_ops = {
-       .open = line6_midi_input_open,
-       .close = line6_midi_input_close,
-       .trigger = line6_midi_input_trigger,
-};
-
-/*
-       Cleanup the Line6 MIDI device.
-*/
-static void line6_cleanup_midi(struct snd_rawmidi *rmidi)
-{
-}
-
-/* Create a MIDI device */
-static int snd_line6_new_midi(struct snd_line6_midi *line6midi)
-{
-       struct snd_rawmidi *rmidi;
-       int err;
-
-       err = snd_rawmidi_new(line6midi->line6->card, "Line6 MIDI", 0, 1, 1,
-                             &rmidi);
-       if (err < 0)
-               return err;
-
-       rmidi->private_data = line6midi;
-       rmidi->private_free = line6_cleanup_midi;
-       strcpy(rmidi->id, line6midi->line6->properties->id);
-       strcpy(rmidi->name, line6midi->line6->properties->name);
-
-       rmidi->info_flags =
-           SNDRV_RAWMIDI_INFO_OUTPUT |
-           SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
-
-       snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
-                           &line6_midi_output_ops);
-       snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
-                           &line6_midi_input_ops);
-       return 0;
-}
-
-/* MIDI device destructor */
-static int snd_line6_midi_free(struct snd_device *device)
-{
-       struct snd_line6_midi *line6midi = device->device_data;
-
-       line6_midibuf_destroy(&line6midi->midibuf_in);
-       line6_midibuf_destroy(&line6midi->midibuf_out);
-       return 0;
-}
-
-/*
-       Initialize the Line6 MIDI subsystem.
-*/
-int line6_init_midi(struct usb_line6 *line6)
-{
-       static struct snd_device_ops midi_ops = {
-               .dev_free = snd_line6_midi_free,
-       };
-
-       int err;
-       struct snd_line6_midi *line6midi;
-
-       if (!(line6->properties->capabilities & LINE6_BIT_CONTROL)) {
-               /* skip MIDI initialization and report success */
-               return 0;
-       }
-
-       line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL);
-
-       if (line6midi == NULL)
-               return -ENOMEM;
-
-       err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0);
-       if (err < 0) {
-               kfree(line6midi);
-               return err;
-       }
-
-       err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1);
-       if (err < 0) {
-               kfree(line6midi->midibuf_in.buf);
-               kfree(line6midi);
-               return err;
-       }
-
-       line6midi->line6 = line6;
-       line6->line6midi = line6midi;
-
-       err = snd_device_new(line6->card, SNDRV_DEV_RAWMIDI, line6midi,
-                            &midi_ops);
-       if (err < 0)
-               return err;
-
-       err = snd_line6_new_midi(line6midi);
-       if (err < 0)
-               return err;
-
-       init_waitqueue_head(&line6midi->send_wait);
-       spin_lock_init(&line6midi->send_urb_lock);
-       spin_lock_init(&line6midi->midi_transmit_lock);
-       return 0;
-}
diff --git a/drivers/staging/line6/midi.h b/drivers/staging/line6/midi.h
deleted file mode 100644 (file)
index 78f903f..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *     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, version 2.
- *
- */
-
-#ifndef MIDI_H
-#define MIDI_H
-
-#include <sound/rawmidi.h>
-
-#include "midibuf.h"
-
-#define MIDI_BUFFER_SIZE 1024
-
-struct snd_line6_midi {
-       /**
-                Pointer back to the Line6 driver data structure.
-       */
-       struct usb_line6 *line6;
-
-       /**
-                MIDI substream for receiving (or NULL if not active).
-       */
-       struct snd_rawmidi_substream *substream_receive;
-
-       /**
-                MIDI substream for transmitting (or NULL if not active).
-       */
-       struct snd_rawmidi_substream *substream_transmit;
-
-       /**
-                Number of currently active MIDI send URBs.
-       */
-       int num_active_send_urbs;
-
-       /**
-                Spin lock to protect updates of send_urb.
-       */
-       spinlock_t send_urb_lock;
-
-       /**
-                Spin lock to protect MIDI buffer handling.
-       */
-       spinlock_t midi_transmit_lock;
-
-       /**
-                Wait queue for MIDI transmission.
-       */
-       wait_queue_head_t send_wait;
-
-       /**
-                Buffer for incoming MIDI stream.
-       */
-       struct midi_buffer midibuf_in;
-
-       /**
-                Buffer for outgoing MIDI stream.
-       */
-       struct midi_buffer midibuf_out;
-};
-
-extern int line6_init_midi(struct usb_line6 *line6);
-extern void line6_midi_receive(struct usb_line6 *line6, unsigned char *data,
-                              int length);
-
-#endif
diff --git a/drivers/staging/line6/midibuf.c b/drivers/staging/line6/midibuf.c
deleted file mode 100644 (file)
index 1ff8569..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *     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, version 2.
- *
- */
-
-#include <linux/slab.h>
-
-#include "midibuf.h"
-
-static int midibuf_message_length(unsigned char code)
-{
-       int message_length;
-
-       if (code < 0x80)
-               message_length = -1;
-       else if (code < 0xf0) {
-               static const int length[] = { 3, 3, 3, 3, 2, 2, 3 };
-
-               message_length = length[(code >> 4) - 8];
-       } else {
-               /*
-                  Note that according to the MIDI specification 0xf2 is
-                  the "Song Position Pointer", but this is used by Line6
-                  to send sysex messages to the host.
-                */
-               static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1,
-                       1, 1, 1, -1, 1, 1
-               };
-               message_length = length[code & 0x0f];
-       }
-
-       return message_length;
-}
-
-static int midibuf_is_empty(struct midi_buffer *this)
-{
-       return (this->pos_read == this->pos_write) && !this->full;
-}
-
-static int midibuf_is_full(struct midi_buffer *this)
-{
-       return this->full;
-}
-
-void line6_midibuf_reset(struct midi_buffer *this)
-{
-       this->pos_read = this->pos_write = this->full = 0;
-       this->command_prev = -1;
-}
-
-int line6_midibuf_init(struct midi_buffer *this, int size, int split)
-{
-       this->buf = kmalloc(size, GFP_KERNEL);
-
-       if (this->buf == NULL)
-               return -ENOMEM;
-
-       this->size = size;
-       this->split = split;
-       line6_midibuf_reset(this);
-       return 0;
-}
-
-void line6_midibuf_status(struct midi_buffer *this)
-{
-       pr_debug("midibuf size=%d split=%d pos_read=%d pos_write=%d full=%d command_prev=%02x\n",
-                this->size, this->split, this->pos_read, this->pos_write,
-                this->full, this->command_prev);
-}
-
-int line6_midibuf_bytes_free(struct midi_buffer *this)
-{
-       return
-           midibuf_is_full(this) ?
-           0 :
-           (this->pos_read - this->pos_write + this->size - 1) % this->size +
-           1;
-}
-
-int line6_midibuf_bytes_used(struct midi_buffer *this)
-{
-       return
-           midibuf_is_empty(this) ?
-           0 :
-           (this->pos_write - this->pos_read + this->size - 1) % this->size +
-           1;
-}
-
-int line6_midibuf_write(struct midi_buffer *this, unsigned char *data,
-                       int length)
-{
-       int bytes_free;
-       int length1, length2;
-       int skip_active_sense = 0;
-
-       if (midibuf_is_full(this) || (length <= 0))
-               return 0;
-
-       /* skip trailing active sense */
-       if (data[length - 1] == 0xfe) {
-               --length;
-               skip_active_sense = 1;
-       }
-
-       bytes_free = line6_midibuf_bytes_free(this);
-
-       if (length > bytes_free)
-               length = bytes_free;
-
-       if (length > 0) {
-               length1 = this->size - this->pos_write;
-
-               if (length < length1) {
-                       /* no buffer wraparound */
-                       memcpy(this->buf + this->pos_write, data, length);
-                       this->pos_write += length;
-               } else {
-                       /* buffer wraparound */
-                       length2 = length - length1;
-                       memcpy(this->buf + this->pos_write, data, length1);
-                       memcpy(this->buf, data + length1, length2);
-                       this->pos_write = length2;
-               }
-
-               if (this->pos_write == this->pos_read)
-                       this->full = 1;
-       }
-
-       return length + skip_active_sense;
-}
-
-int line6_midibuf_read(struct midi_buffer *this, unsigned char *data,
-                      int length)
-{
-       int bytes_used;
-       int length1, length2;
-       int command;
-       int midi_length;
-       int repeat = 0;
-       int i;
-
-       /* we need to be able to store at least a 3 byte MIDI message */
-       if (length < 3)
-               return -EINVAL;
-
-       if (midibuf_is_empty(this))
-               return 0;
-
-       bytes_used = line6_midibuf_bytes_used(this);
-
-       if (length > bytes_used)
-               length = bytes_used;
-
-       length1 = this->size - this->pos_read;
-
-       /* check MIDI command length */
-       command = this->buf[this->pos_read];
-
-       if (command & 0x80) {
-               midi_length = midibuf_message_length(command);
-               this->command_prev = command;
-       } else {
-               if (this->command_prev > 0) {
-                       int midi_length_prev =
-                           midibuf_message_length(this->command_prev);
-
-                       if (midi_length_prev > 0) {
-                               midi_length = midi_length_prev - 1;
-                               repeat = 1;
-                       } else
-                               midi_length = -1;
-               } else
-                       midi_length = -1;
-       }
-
-       if (midi_length < 0) {
-               /* search for end of message */
-               if (length < length1) {
-                       /* no buffer wraparound */
-                       for (i = 1; i < length; ++i)
-                               if (this->buf[this->pos_read + i] & 0x80)
-                                       break;
-
-                       midi_length = i;
-               } else {
-                       /* buffer wraparound */
-                       length2 = length - length1;
-
-                       for (i = 1; i < length1; ++i)
-                               if (this->buf[this->pos_read + i] & 0x80)
-                                       break;
-
-                       if (i < length1)
-                               midi_length = i;
-                       else {
-                               for (i = 0; i < length2; ++i)
-                                       if (this->buf[i] & 0x80)
-                                               break;
-
-                               midi_length = length1 + i;
-                       }
-               }
-
-               if (midi_length == length)
-                       midi_length = -1;       /* end of message not found */
-       }
-
-       if (midi_length < 0) {
-               if (!this->split)
-                       return 0;       /* command is not yet complete */
-       } else {
-               if (length < midi_length)
-                       return 0;       /* command is not yet complete */
-
-               length = midi_length;
-       }
-
-       if (length < length1) {
-               /* no buffer wraparound */
-               memcpy(data + repeat, this->buf + this->pos_read, length);
-               this->pos_read += length;
-       } else {
-               /* buffer wraparound */
-               length2 = length - length1;
-               memcpy(data + repeat, this->buf + this->pos_read, length1);
-               memcpy(data + repeat + length1, this->buf, length2);
-               this->pos_read = length2;
-       }
-
-       if (repeat)
-               data[0] = this->command_prev;
-
-       this->full = 0;
-       return length + repeat;
-}
-
-int line6_midibuf_ignore(struct midi_buffer *this, int length)
-{
-       int bytes_used = line6_midibuf_bytes_used(this);
-
-       if (length > bytes_used)
-               length = bytes_used;
-
-       this->pos_read = (this->pos_read + length) % this->size;
-       this->full = 0;
-       return length;
-}
-
-int line6_midibuf_skip_message(struct midi_buffer *this, unsigned short mask)
-{
-       int cmd = this->command_prev;
-
-       if ((cmd >= 0x80) && (cmd < 0xf0))
-               if ((mask & (1 << (cmd & 0x0f))) == 0)
-                       return 1;
-
-       return 0;
-}
-
-void line6_midibuf_destroy(struct midi_buffer *this)
-{
-       kfree(this->buf);
-       this->buf = NULL;
-}
diff --git a/drivers/staging/line6/midibuf.h b/drivers/staging/line6/midibuf.h
deleted file mode 100644 (file)
index 707482b..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *     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, version 2.
- *
- */
-
-#ifndef MIDIBUF_H
-#define MIDIBUF_H
-
-struct midi_buffer {
-       unsigned char *buf;
-       int size;
-       int split;
-       int pos_read, pos_write;
-       int full;
-       int command_prev;
-};
-
-extern int line6_midibuf_bytes_used(struct midi_buffer *mb);
-extern int line6_midibuf_bytes_free(struct midi_buffer *mb);
-extern void line6_midibuf_destroy(struct midi_buffer *mb);
-extern int line6_midibuf_ignore(struct midi_buffer *mb, int length);
-extern int line6_midibuf_init(struct midi_buffer *mb, int size, int split);
-extern int line6_midibuf_read(struct midi_buffer *mb, unsigned char *data,
-                             int length);
-extern void line6_midibuf_reset(struct midi_buffer *mb);
-extern int line6_midibuf_skip_message(struct midi_buffer *mb,
-                                     unsigned short mask);
-extern void line6_midibuf_status(struct midi_buffer *mb);
-extern int line6_midibuf_write(struct midi_buffer *mb, unsigned char *data,
-                              int length);
-
-#endif
diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c
deleted file mode 100644 (file)
index a3136b1..0000000
+++ /dev/null
@@ -1,576 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *     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, version 2.
- *
- */
-
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/control.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-
-#include "audio.h"
-#include "capture.h"
-#include "driver.h"
-#include "playback.h"
-#include "pod.h"
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-
-static struct snd_line6_pcm *dev2pcm(struct device *dev)
-{
-       struct usb_interface *interface = to_usb_interface(dev);
-       struct usb_line6 *line6 = usb_get_intfdata(interface);
-       struct snd_line6_pcm *line6pcm = line6->line6pcm;
-       return line6pcm;
-}
-
-/*
-       "read" request on "impulse_volume" special file.
-*/
-static ssize_t impulse_volume_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
-{
-       return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_volume);
-}
-
-/*
-       "write" request on "impulse_volume" special file.
-*/
-static ssize_t impulse_volume_store(struct device *dev,
-                                   struct device_attribute *attr,
-                                   const char *buf, size_t count)
-{
-       struct snd_line6_pcm *line6pcm = dev2pcm(dev);
-       int value;
-       int ret;
-
-       ret = kstrtoint(buf, 10, &value);
-       if (ret < 0)
-               return ret;
-
-       line6pcm->impulse_volume = value;
-
-       if (value > 0)
-               line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE);
-       else
-               line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE);
-
-       return count;
-}
-static DEVICE_ATTR_RW(impulse_volume);
-
-/*
-       "read" request on "impulse_period" special file.
-*/
-static ssize_t impulse_period_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
-{
-       return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_period);
-}
-
-/*
-       "write" request on "impulse_period" special file.
-*/
-static ssize_t impulse_period_store(struct device *dev,
-                                   struct device_attribute *attr,
-                                   const char *buf, size_t count)
-{
-       int value;
-       int ret;
-
-       ret = kstrtoint(buf, 10, &value);
-       if (ret < 0)
-               return ret;
-
-       dev2pcm(dev)->impulse_period = value;
-       return count;
-}
-static DEVICE_ATTR_RW(impulse_period);
-
-#endif
-
-static bool test_flags(unsigned long flags0, unsigned long flags1,
-                      unsigned long mask)
-{
-       return ((flags0 & mask) == 0) && ((flags1 & mask) != 0);
-}
-
-int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels)
-{
-       unsigned long flags_old, flags_new, flags_final;
-       int err;
-
-       do {
-               flags_old = ACCESS_ONCE(line6pcm->flags);
-               flags_new = flags_old | channels;
-       } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old);
-
-       flags_final = flags_old;
-
-       line6pcm->prev_fbuf = NULL;
-
-       if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) {
-               /* Invoked multiple times in a row so allocate once only */
-               if (!line6pcm->buffer_in) {
-                       line6pcm->buffer_in =
-                               kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
-                                       line6pcm->max_packet_size, GFP_KERNEL);
-                       if (!line6pcm->buffer_in) {
-                               err = -ENOMEM;
-                               goto pcm_acquire_error;
-                       }
-
-                       flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER;
-               }
-       }
-
-       if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) {
-               /*
-                  Waiting for completion of active URBs in the stop handler is
-                  a bug, we therefore report an error if capturing is restarted
-                  too soon.
-                */
-               if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) {
-                       dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
-                       return -EBUSY;
-               }
-
-               line6pcm->count_in = 0;
-               line6pcm->prev_fsize = 0;
-               err = line6_submit_audio_in_all_urbs(line6pcm);
-
-               if (err < 0)
-                       goto pcm_acquire_error;
-
-               flags_final |= channels & LINE6_BITS_CAPTURE_STREAM;
-       }
-
-       if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) {
-               /* Invoked multiple times in a row so allocate once only */
-               if (!line6pcm->buffer_out) {
-                       line6pcm->buffer_out =
-                               kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
-                                       line6pcm->max_packet_size, GFP_KERNEL);
-                       if (!line6pcm->buffer_out) {
-                               err = -ENOMEM;
-                               goto pcm_acquire_error;
-                       }
-
-                       flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER;
-               }
-       }
-
-       if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) {
-               /*
-                 See comment above regarding PCM restart.
-               */
-               if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) {
-                       dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
-                       return -EBUSY;
-               }
-
-               line6pcm->count_out = 0;
-               err = line6_submit_audio_out_all_urbs(line6pcm);
-
-               if (err < 0)
-                       goto pcm_acquire_error;
-
-               flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM;
-       }
-
-       return 0;
-
-pcm_acquire_error:
-       /*
-          If not all requested resources/streams could be obtained, release
-          those which were successfully obtained (if any).
-       */
-       line6_pcm_release(line6pcm, flags_final & channels);
-       return err;
-}
-
-int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels)
-{
-       unsigned long flags_old, flags_new;
-
-       do {
-               flags_old = ACCESS_ONCE(line6pcm->flags);
-               flags_new = flags_old & ~channels;
-       } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old);
-
-       if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM))
-               line6_unlink_audio_in_urbs(line6pcm);
-
-       if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) {
-               line6_wait_clear_audio_in_urbs(line6pcm);
-               line6_free_capture_buffer(line6pcm);
-       }
-
-       if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM))
-               line6_unlink_audio_out_urbs(line6pcm);
-
-       if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) {
-               line6_wait_clear_audio_out_urbs(line6pcm);
-               line6_free_playback_buffer(line6pcm);
-       }
-
-       return 0;
-}
-
-/* trigger callback */
-int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-       struct snd_pcm_substream *s;
-       int err;
-       unsigned long flags;
-
-       spin_lock_irqsave(&line6pcm->lock_trigger, flags);
-       clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags);
-
-       snd_pcm_group_for_each_entry(s, substream) {
-               switch (s->stream) {
-               case SNDRV_PCM_STREAM_PLAYBACK:
-                       err = snd_line6_playback_trigger(line6pcm, cmd);
-
-                       if (err < 0) {
-                               spin_unlock_irqrestore(&line6pcm->lock_trigger,
-                                                      flags);
-                               return err;
-                       }
-
-                       break;
-
-               case SNDRV_PCM_STREAM_CAPTURE:
-                       err = snd_line6_capture_trigger(line6pcm, cmd);
-
-                       if (err < 0) {
-                               spin_unlock_irqrestore(&line6pcm->lock_trigger,
-                                                      flags);
-                               return err;
-                       }
-
-                       break;
-
-               default:
-                       dev_err(line6pcm->line6->ifcdev,
-                               "Unknown stream direction %d\n", s->stream);
-               }
-       }
-
-       spin_unlock_irqrestore(&line6pcm->lock_trigger, flags);
-       return 0;
-}
-
-/* control info callback */
-static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol,
-                                          struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 2;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = 256;
-       return 0;
-}
-
-/* control get callback */
-static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol,
-                                         struct snd_ctl_elem_value *ucontrol)
-{
-       int i;
-       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-
-       for (i = 2; i--;)
-               ucontrol->value.integer.value[i] = line6pcm->volume_playback[i];
-
-       return 0;
-}
-
-/* control put callback */
-static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol,
-                                         struct snd_ctl_elem_value *ucontrol)
-{
-       int i, changed = 0;
-       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-
-       for (i = 2; i--;)
-               if (line6pcm->volume_playback[i] !=
-                   ucontrol->value.integer.value[i]) {
-                       line6pcm->volume_playback[i] =
-                           ucontrol->value.integer.value[i];
-                       changed = 1;
-               }
-
-       return changed;
-}
-
-/* control definition */
-static struct snd_kcontrol_new line6_control_playback = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "PCM Playback Volume",
-       .index = 0,
-       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-       .info = snd_line6_control_playback_info,
-       .get = snd_line6_control_playback_get,
-       .put = snd_line6_control_playback_put
-};
-
-/*
-       Cleanup the PCM device.
-*/
-static void line6_cleanup_pcm(struct snd_pcm *pcm)
-{
-       int i;
-       struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm);
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-       device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_volume);
-       device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_period);
-#endif
-
-       for (i = LINE6_ISO_BUFFERS; i--;) {
-               if (line6pcm->urb_audio_out[i]) {
-                       usb_kill_urb(line6pcm->urb_audio_out[i]);
-                       usb_free_urb(line6pcm->urb_audio_out[i]);
-               }
-               if (line6pcm->urb_audio_in[i]) {
-                       usb_kill_urb(line6pcm->urb_audio_in[i]);
-                       usb_free_urb(line6pcm->urb_audio_in[i]);
-               }
-       }
-}
-
-/* create a PCM device */
-static int snd_line6_new_pcm(struct snd_line6_pcm *line6pcm)
-{
-       struct snd_pcm *pcm;
-       int err;
-
-       err = snd_pcm_new(line6pcm->line6->card,
-                         (char *)line6pcm->line6->properties->name,
-                         0, 1, 1, &pcm);
-       if (err < 0)
-               return err;
-
-       pcm->private_data = line6pcm;
-       pcm->private_free = line6_cleanup_pcm;
-       line6pcm->pcm = pcm;
-       strcpy(pcm->name, line6pcm->line6->properties->name);
-
-       /* set operators */
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-                       &snd_line6_playback_ops);
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops);
-
-       /* pre-allocation of buffers */
-       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
-                                             snd_dma_continuous_data
-                                             (GFP_KERNEL), 64 * 1024,
-                                             128 * 1024);
-
-       return 0;
-}
-
-/* PCM device destructor */
-static int snd_line6_pcm_free(struct snd_device *device)
-{
-       return 0;
-}
-
-/*
-       Stop substream if still running.
-*/
-static void pcm_disconnect_substream(struct snd_pcm_substream *substream)
-{
-       if (substream->runtime && snd_pcm_running(substream)) {
-               snd_pcm_stream_lock_irq(substream);
-               snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
-               snd_pcm_stream_unlock_irq(substream);
-       }
-}
-
-/*
-       Stop PCM stream.
-*/
-void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm)
-{
-       pcm_disconnect_substream(get_substream
-                                (line6pcm, SNDRV_PCM_STREAM_CAPTURE));
-       pcm_disconnect_substream(get_substream
-                                (line6pcm, SNDRV_PCM_STREAM_PLAYBACK));
-       line6_unlink_wait_clear_audio_out_urbs(line6pcm);
-       line6_unlink_wait_clear_audio_in_urbs(line6pcm);
-}
-
-/*
-       Create and register the PCM device and mixer entries.
-       Create URBs for playback and capture.
-*/
-int line6_init_pcm(struct usb_line6 *line6,
-                  struct line6_pcm_properties *properties)
-{
-       static struct snd_device_ops pcm_ops = {
-               .dev_free = snd_line6_pcm_free,
-       };
-
-       int err;
-       int ep_read = 0, ep_write = 0;
-       struct snd_line6_pcm *line6pcm;
-
-       if (!(line6->properties->capabilities & LINE6_BIT_PCM))
-               return 0;       /* skip PCM initialization and report success */
-
-       /* initialize PCM subsystem based on product id: */
-       switch (line6->product) {
-       case LINE6_DEVID_BASSPODXT:
-       case LINE6_DEVID_BASSPODXTLIVE:
-       case LINE6_DEVID_BASSPODXTPRO:
-       case LINE6_DEVID_PODXT:
-       case LINE6_DEVID_PODXTLIVE:
-       case LINE6_DEVID_PODXTPRO:
-       case LINE6_DEVID_PODHD300:
-       case LINE6_DEVID_PODHD400:
-               ep_read = 0x82;
-               ep_write = 0x01;
-               break;
-
-       case LINE6_DEVID_PODHD500:
-       case LINE6_DEVID_PODX3:
-       case LINE6_DEVID_PODX3LIVE:
-               ep_read = 0x86;
-               ep_write = 0x02;
-               break;
-
-       case LINE6_DEVID_POCKETPOD:
-               ep_read = 0x82;
-               ep_write = 0x02;
-               break;
-
-       case LINE6_DEVID_GUITARPORT:
-       case LINE6_DEVID_PODSTUDIO_GX:
-       case LINE6_DEVID_PODSTUDIO_UX1:
-       case LINE6_DEVID_PODSTUDIO_UX2:
-       case LINE6_DEVID_TONEPORT_GX:
-       case LINE6_DEVID_TONEPORT_UX1:
-       case LINE6_DEVID_TONEPORT_UX2:
-               ep_read = 0x82;
-               ep_write = 0x01;
-               break;
-
-       /* this is for interface_number == 1:
-       case LINE6_DEVID_TONEPORT_UX2:
-       case LINE6_DEVID_PODSTUDIO_UX2:
-               ep_read  = 0x87;
-               ep_write = 0x00;
-               break; */
-
-       default:
-               MISSING_CASE;
-       }
-
-       line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL);
-
-       if (line6pcm == NULL)
-               return -ENOMEM;
-
-       line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255;
-       line6pcm->volume_monitor = 255;
-       line6pcm->line6 = line6;
-       line6pcm->ep_audio_read = ep_read;
-       line6pcm->ep_audio_write = ep_write;
-
-       /* Read and write buffers are sized identically, so choose minimum */
-       line6pcm->max_packet_size = min(
-                       usb_maxpacket(line6->usbdev,
-                               usb_rcvisocpipe(line6->usbdev, ep_read), 0),
-                       usb_maxpacket(line6->usbdev,
-                               usb_sndisocpipe(line6->usbdev, ep_write), 1));
-
-       line6pcm->properties = properties;
-       line6->line6pcm = line6pcm;
-
-       /* PCM device: */
-       err = snd_device_new(line6->card, SNDRV_DEV_PCM, line6, &pcm_ops);
-       if (err < 0)
-               return err;
-
-       err = snd_line6_new_pcm(line6pcm);
-       if (err < 0)
-               return err;
-
-       spin_lock_init(&line6pcm->lock_audio_out);
-       spin_lock_init(&line6pcm->lock_audio_in);
-       spin_lock_init(&line6pcm->lock_trigger);
-
-       err = line6_create_audio_out_urbs(line6pcm);
-       if (err < 0)
-               return err;
-
-       err = line6_create_audio_in_urbs(line6pcm);
-       if (err < 0)
-               return err;
-
-       /* mixer: */
-       err =
-           snd_ctl_add(line6->card,
-                       snd_ctl_new1(&line6_control_playback, line6pcm));
-       if (err < 0)
-               return err;
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-       /* impulse response test: */
-       err = device_create_file(line6->ifcdev, &dev_attr_impulse_volume);
-       if (err < 0)
-               return err;
-
-       err = device_create_file(line6->ifcdev, &dev_attr_impulse_period);
-       if (err < 0)
-               return err;
-
-       line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
-#endif
-
-       return 0;
-}
-
-/* prepare pcm callback */
-int snd_line6_prepare(struct snd_pcm_substream *substream)
-{
-       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
-       switch (substream->stream) {
-       case SNDRV_PCM_STREAM_PLAYBACK:
-               if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0)
-                       line6_unlink_wait_clear_audio_out_urbs(line6pcm);
-
-               break;
-
-       case SNDRV_PCM_STREAM_CAPTURE:
-               if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0)
-                       line6_unlink_wait_clear_audio_in_urbs(line6pcm);
-
-               break;
-
-       default:
-               MISSING_CASE;
-       }
-
-       if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) {
-               line6pcm->count_out = 0;
-               line6pcm->pos_out = 0;
-               line6pcm->pos_out_done = 0;
-               line6pcm->bytes_out = 0;
-               line6pcm->count_in = 0;
-               line6pcm->pos_in_done = 0;
-               line6pcm->bytes_in = 0;
-       }
-
-       return 0;
-}
diff --git a/drivers/staging/line6/pcm.h b/drivers/staging/line6/pcm.h
deleted file mode 100644 (file)
index 6aa0d46..0000000
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *     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, version 2.
- *
- */
-
-/*
-       PCM interface to POD series devices.
-*/
-
-#ifndef PCM_H
-#define PCM_H
-
-#include <sound/pcm.h>
-
-#include "driver.h"
-#include "usbdefs.h"
-
-/* number of URBs */
-#define LINE6_ISO_BUFFERS      2
-
-/*
-       number of USB frames per URB
-       The Line6 Windows driver always transmits two frames per packet, but
-       the Linux driver performs significantly better (i.e., lower latency)
-       with only one frame per packet.
-*/
-#define LINE6_ISO_PACKETS      1
-
-/* in a "full speed" device (such as the PODxt Pro) this means 1ms */
-#define LINE6_ISO_INTERVAL     1
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-#define LINE6_IMPULSE_DEFAULT_PERIOD 100
-#endif
-
-/*
-       Get substream from Line6 PCM data structure
-*/
-#define get_substream(line6pcm, stream)        \
-               (line6pcm->pcm->streams[stream].substream)
-
-/*
-       PCM mode bits.
-
-       There are several features of the Line6 USB driver which require PCM
-       data to be exchanged with the device:
-       *) PCM playback and capture via ALSA
-       *) software monitoring (for devices without hardware monitoring)
-       *) optional impulse response measurement
-       However, from the device's point of view, there is just a single
-       capture and playback stream, which must be shared between these
-       subsystems. It is therefore necessary to maintain the state of the
-       subsystems with respect to PCM usage. We define several constants of
-       the form LINE6_BIT_PCM_<subsystem>_<direction>_<resource> with the
-       following meanings:
-       *) <subsystem> is one of
-       -) ALSA: PCM playback and capture via ALSA
-       -) MONITOR: software monitoring
-       -) IMPULSE: optional impulse response measurement
-       *) <direction> is one of
-       -) PLAYBACK: audio output (from host to device)
-       -) CAPTURE: audio input (from device to host)
-       *) <resource> is one of
-       -) BUFFER: buffer required by PCM data stream
-       -) STREAM: actual PCM data stream
-
-       The subsystems call line6_pcm_acquire() to acquire the (shared)
-       resources needed for a particular operation (e.g., allocate the buffer
-       for ALSA playback or start the capture stream for software monitoring).
-       When a resource is no longer needed, it is released by calling
-       line6_pcm_release(). Buffer allocation and stream startup are handled
-       separately to allow the ALSA kernel driver to perform them at
-       appropriate places (since the callback which starts a PCM stream is not
-       allowed to sleep).
-*/
-enum {
-       /* individual bit indices: */
-       LINE6_INDEX_PCM_ALSA_PLAYBACK_BUFFER,
-       LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM,
-       LINE6_INDEX_PCM_ALSA_CAPTURE_BUFFER,
-       LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
-       LINE6_INDEX_PCM_MONITOR_PLAYBACK_BUFFER,
-       LINE6_INDEX_PCM_MONITOR_PLAYBACK_STREAM,
-       LINE6_INDEX_PCM_MONITOR_CAPTURE_BUFFER,
-       LINE6_INDEX_PCM_MONITOR_CAPTURE_STREAM,
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-       LINE6_INDEX_PCM_IMPULSE_PLAYBACK_BUFFER,
-       LINE6_INDEX_PCM_IMPULSE_PLAYBACK_STREAM,
-       LINE6_INDEX_PCM_IMPULSE_CAPTURE_BUFFER,
-       LINE6_INDEX_PCM_IMPULSE_CAPTURE_STREAM,
-#endif
-       LINE6_INDEX_PAUSE_PLAYBACK,
-       LINE6_INDEX_PREPARED,
-
-       /* individual bit masks: */
-       LINE6_BIT(PCM_ALSA_PLAYBACK_BUFFER),
-       LINE6_BIT(PCM_ALSA_PLAYBACK_STREAM),
-       LINE6_BIT(PCM_ALSA_CAPTURE_BUFFER),
-       LINE6_BIT(PCM_ALSA_CAPTURE_STREAM),
-       LINE6_BIT(PCM_MONITOR_PLAYBACK_BUFFER),
-       LINE6_BIT(PCM_MONITOR_PLAYBACK_STREAM),
-       LINE6_BIT(PCM_MONITOR_CAPTURE_BUFFER),
-       LINE6_BIT(PCM_MONITOR_CAPTURE_STREAM),
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-       LINE6_BIT(PCM_IMPULSE_PLAYBACK_BUFFER),
-       LINE6_BIT(PCM_IMPULSE_PLAYBACK_STREAM),
-       LINE6_BIT(PCM_IMPULSE_CAPTURE_BUFFER),
-       LINE6_BIT(PCM_IMPULSE_CAPTURE_STREAM),
-#endif
-       LINE6_BIT(PAUSE_PLAYBACK),
-       LINE6_BIT(PREPARED),
-
-       /* combined bit masks (by operation): */
-       LINE6_BITS_PCM_ALSA_BUFFER =
-           LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER |
-           LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER,
-
-       LINE6_BITS_PCM_ALSA_STREAM =
-           LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM |
-           LINE6_BIT_PCM_ALSA_CAPTURE_STREAM,
-
-       LINE6_BITS_PCM_MONITOR =
-           LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER |
-           LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM |
-           LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER |
-           LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-       LINE6_BITS_PCM_IMPULSE =
-           LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
-           LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM |
-           LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER |
-           LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM,
-#endif
-
-       /* combined bit masks (by direction): */
-       LINE6_BITS_PLAYBACK_BUFFER =
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-           LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
-#endif
-           LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER |
-           LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER ,
-
-       LINE6_BITS_PLAYBACK_STREAM =
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-           LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM |
-#endif
-           LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM |
-           LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM ,
-
-       LINE6_BITS_CAPTURE_BUFFER =
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-           LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER |
-#endif
-           LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER |
-           LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER ,
-
-       LINE6_BITS_CAPTURE_STREAM =
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-           LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM |
-#endif
-           LINE6_BIT_PCM_ALSA_CAPTURE_STREAM |
-           LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,
-
-       LINE6_BITS_STREAM =
-           LINE6_BITS_PLAYBACK_STREAM |
-           LINE6_BITS_CAPTURE_STREAM
-};
-
-struct line6_pcm_properties {
-       struct snd_pcm_hardware snd_line6_playback_hw, snd_line6_capture_hw;
-       struct snd_pcm_hw_constraint_ratdens snd_line6_rates;
-       int bytes_per_frame;
-};
-
-struct snd_line6_pcm {
-       /**
-                Pointer back to the Line6 driver data structure.
-       */
-       struct usb_line6 *line6;
-
-       /**
-                Properties.
-       */
-       struct line6_pcm_properties *properties;
-
-       /**
-                ALSA pcm stream
-       */
-       struct snd_pcm *pcm;
-
-       /**
-                URBs for audio playback.
-       */
-       struct urb *urb_audio_out[LINE6_ISO_BUFFERS];
-
-       /**
-                URBs for audio capture.
-       */
-       struct urb *urb_audio_in[LINE6_ISO_BUFFERS];
-
-       /**
-                Temporary buffer for playback.
-                Since the packet size is not known in advance, this buffer is
-                large enough to store maximum size packets.
-       */
-       unsigned char *buffer_out;
-
-       /**
-                Temporary buffer for capture.
-                Since the packet size is not known in advance, this buffer is
-                large enough to store maximum size packets.
-       */
-       unsigned char *buffer_in;
-
-       /**
-                Previously captured frame (for software monitoring).
-       */
-       unsigned char *prev_fbuf;
-
-       /**
-                Size of previously captured frame (for software monitoring).
-       */
-       int prev_fsize;
-
-       /**
-                Free frame position in the playback buffer.
-       */
-       snd_pcm_uframes_t pos_out;
-
-       /**
-                Count processed bytes for playback.
-                This is modulo period size (to determine when a period is
-                finished).
-       */
-       unsigned bytes_out;
-
-       /**
-                Counter to create desired playback sample rate.
-       */
-       unsigned count_out;
-
-       /**
-                Playback period size in bytes
-       */
-       unsigned period_out;
-
-       /**
-                Processed frame position in the playback buffer.
-                The contents of the output ring buffer have been consumed by
-                the USB subsystem (i.e., sent to the USB device) up to this
-                position.
-       */
-       snd_pcm_uframes_t pos_out_done;
-
-       /**
-                Count processed bytes for capture.
-                This is modulo period size (to determine when a period is
-                finished).
-       */
-       unsigned bytes_in;
-
-       /**
-                Counter to create desired capture sample rate.
-       */
-       unsigned count_in;
-
-       /**
-                Capture period size in bytes
-       */
-       unsigned period_in;
-
-       /**
-                Processed frame position in the capture buffer.
-                The contents of the output ring buffer have been consumed by
-                the USB subsystem (i.e., sent to the USB device) up to this
-                position.
-       */
-       snd_pcm_uframes_t pos_in_done;
-
-       /**
-                Bit mask of active playback URBs.
-       */
-       unsigned long active_urb_out;
-
-       /**
-                Maximum size of USB packet.
-       */
-       int max_packet_size;
-
-       /**
-                USB endpoint for listening to audio data.
-       */
-       int ep_audio_read;
-
-       /**
-                USB endpoint for writing audio data.
-       */
-       int ep_audio_write;
-
-       /**
-                Bit mask of active capture URBs.
-       */
-       unsigned long active_urb_in;
-
-       /**
-                Bit mask of playback URBs currently being unlinked.
-       */
-       unsigned long unlink_urb_out;
-
-       /**
-                Bit mask of capture URBs currently being unlinked.
-       */
-       unsigned long unlink_urb_in;
-
-       /**
-                Spin lock to protect updates of the playback buffer positions (not
-                contents!)
-       */
-       spinlock_t lock_audio_out;
-
-       /**
-                Spin lock to protect updates of the capture buffer positions (not
-                contents!)
-       */
-       spinlock_t lock_audio_in;
-
-       /**
-                Spin lock to protect trigger.
-       */
-       spinlock_t lock_trigger;
-
-       /**
-                PCM playback volume (left and right).
-       */
-       int volume_playback[2];
-
-       /**
-                PCM monitor volume.
-       */
-       int volume_monitor;
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-       /**
-                Volume of impulse response test signal (if zero, test is disabled).
-       */
-       int impulse_volume;
-
-       /**
-                Period of impulse response test signal.
-       */
-       int impulse_period;
-
-       /**
-                Counter for impulse response test signal.
-       */
-       int impulse_count;
-#endif
-
-       /**
-                Several status bits (see LINE6_BIT_*).
-       */
-       unsigned long flags;
-
-       int last_frame_in, last_frame_out;
-};
-
-extern int line6_init_pcm(struct usb_line6 *line6,
-                         struct line6_pcm_properties *properties);
-extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd);
-extern int snd_line6_prepare(struct snd_pcm_substream *substream);
-extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm);
-extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels);
-extern int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels);
-
-#endif
diff --git a/drivers/staging/line6/playback.c b/drivers/staging/line6/playback.c
deleted file mode 100644 (file)
index 2ca8900..0000000
+++ /dev/null
@@ -1,592 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *     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, version 2.
- *
- */
-
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-
-#include "audio.h"
-#include "capture.h"
-#include "driver.h"
-#include "pcm.h"
-#include "pod.h"
-#include "playback.h"
-
-/*
-       Software stereo volume control.
-*/
-static void change_volume(struct urb *urb_out, int volume[],
-                         int bytes_per_frame)
-{
-       int chn = 0;
-
-       if (volume[0] == 256 && volume[1] == 256)
-               return;         /* maximum volume - no change */
-
-       if (bytes_per_frame == 4) {
-               short *p, *buf_end;
-
-               p = (short *)urb_out->transfer_buffer;
-               buf_end = p + urb_out->transfer_buffer_length / sizeof(*p);
-
-               for (; p < buf_end; ++p) {
-                       *p = (*p * volume[chn & 1]) >> 8;
-                       ++chn;
-               }
-       } else if (bytes_per_frame == 6) {
-               unsigned char *p, *buf_end;
-
-               p = (unsigned char *)urb_out->transfer_buffer;
-               buf_end = p + urb_out->transfer_buffer_length;
-
-               for (; p < buf_end; p += 3) {
-                       int val;
-
-                       val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16);
-                       val = (val * volume[chn & 1]) >> 8;
-                       p[0] = val;
-                       p[1] = val >> 8;
-                       p[2] = val >> 16;
-                       ++chn;
-               }
-       }
-}
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-
-/*
-       Create signal for impulse response test.
-*/
-static void create_impulse_test_signal(struct snd_line6_pcm *line6pcm,
-                                      struct urb *urb_out, int bytes_per_frame)
-{
-       int frames = urb_out->transfer_buffer_length / bytes_per_frame;
-
-       if (bytes_per_frame == 4) {
-               int i;
-               short *pi = (short *)line6pcm->prev_fbuf;
-               short *po = (short *)urb_out->transfer_buffer;
-
-               for (i = 0; i < frames; ++i) {
-                       po[0] = pi[0];
-                       po[1] = 0;
-                       pi += 2;
-                       po += 2;
-               }
-       } else if (bytes_per_frame == 6) {
-               int i, j;
-               unsigned char *pi = line6pcm->prev_fbuf;
-               unsigned char *po = urb_out->transfer_buffer;
-
-               for (i = 0; i < frames; ++i) {
-                       for (j = 0; j < bytes_per_frame / 2; ++j)
-                               po[j] = pi[j];
-
-                       for (; j < bytes_per_frame; ++j)
-                               po[j] = 0;
-
-                       pi += bytes_per_frame;
-                       po += bytes_per_frame;
-               }
-       }
-       if (--line6pcm->impulse_count <= 0) {
-               ((unsigned char *)(urb_out->transfer_buffer))[bytes_per_frame -
-                                                             1] =
-                   line6pcm->impulse_volume;
-               line6pcm->impulse_count = line6pcm->impulse_period;
-       }
-}
-
-#endif
-
-/*
-       Add signal to buffer for software monitoring.
-*/
-static void add_monitor_signal(struct urb *urb_out, unsigned char *signal,
-                              int volume, int bytes_per_frame)
-{
-       if (volume == 0)
-               return;         /* zero volume - no change */
-
-       if (bytes_per_frame == 4) {
-               short *pi, *po, *buf_end;
-
-               pi = (short *)signal;
-               po = (short *)urb_out->transfer_buffer;
-               buf_end = po + urb_out->transfer_buffer_length / sizeof(*po);
-
-               for (; po < buf_end; ++pi, ++po)
-                       *po += (*pi * volume) >> 8;
-       }
-
-       /*
-          We don't need to handle devices with 6 bytes per frame here
-          since they all support hardware monitoring.
-        */
-}
-
-/*
-       Find a free URB, prepare audio data, and submit URB.
-*/
-static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
-{
-       int index;
-       unsigned long flags;
-       int i, urb_size, urb_frames;
-       int ret;
-       const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
-       const int frame_increment =
-           line6pcm->properties->snd_line6_rates.rats[0].num_min;
-       const int frame_factor =
-           line6pcm->properties->snd_line6_rates.rats[0].den *
-           (USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL);
-       struct urb *urb_out;
-
-       spin_lock_irqsave(&line6pcm->lock_audio_out, flags);
-       index =
-           find_first_zero_bit(&line6pcm->active_urb_out, LINE6_ISO_BUFFERS);
-
-       if (index < 0 || index >= LINE6_ISO_BUFFERS) {
-               spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
-               dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
-               return -EINVAL;
-       }
-
-       urb_out = line6pcm->urb_audio_out[index];
-       urb_size = 0;
-
-       for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
-               /* compute frame size for given sampling rate */
-               int fsize = 0;
-               struct usb_iso_packet_descriptor *fout =
-                   &urb_out->iso_frame_desc[i];
-
-               if (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM)
-                       fsize = line6pcm->prev_fsize;
-
-               if (fsize == 0) {
-                       int n;
-
-                       line6pcm->count_out += frame_increment;
-                       n = line6pcm->count_out / frame_factor;
-                       line6pcm->count_out -= n * frame_factor;
-                       fsize = n * bytes_per_frame;
-               }
-
-               fout->offset = urb_size;
-               fout->length = fsize;
-               urb_size += fsize;
-       }
-
-       if (urb_size == 0) {
-               /* can't determine URB size */
-               spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
-               dev_err(line6pcm->line6->ifcdev, "driver bug: urb_size = 0\n");
-               return -EINVAL;
-       }
-
-       urb_frames = urb_size / bytes_per_frame;
-       urb_out->transfer_buffer =
-           line6pcm->buffer_out +
-           index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
-       urb_out->transfer_buffer_length = urb_size;
-       urb_out->context = line6pcm;
-
-       if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags) &&
-           !test_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags)) {
-               struct snd_pcm_runtime *runtime =
-                   get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime;
-
-               if (line6pcm->pos_out + urb_frames > runtime->buffer_size) {
-                       /*
-                          The transferred area goes over buffer boundary,
-                          copy the data to the temp buffer.
-                        */
-                       int len;
-
-                       len = runtime->buffer_size - line6pcm->pos_out;
-
-                       if (len > 0) {
-                               memcpy(urb_out->transfer_buffer,
-                                      runtime->dma_area +
-                                      line6pcm->pos_out * bytes_per_frame,
-                                      len * bytes_per_frame);
-                               memcpy(urb_out->transfer_buffer +
-                                      len * bytes_per_frame, runtime->dma_area,
-                                      (urb_frames - len) * bytes_per_frame);
-                       } else
-                               dev_err(line6pcm->line6->ifcdev, "driver bug: len = %d\n",
-                                       len);
-               } else {
-                       memcpy(urb_out->transfer_buffer,
-                              runtime->dma_area +
-                              line6pcm->pos_out * bytes_per_frame,
-                              urb_out->transfer_buffer_length);
-               }
-
-               line6pcm->pos_out += urb_frames;
-               if (line6pcm->pos_out >= runtime->buffer_size)
-                       line6pcm->pos_out -= runtime->buffer_size;
-       } else {
-               memset(urb_out->transfer_buffer, 0,
-                      urb_out->transfer_buffer_length);
-       }
-
-       change_volume(urb_out, line6pcm->volume_playback, bytes_per_frame);
-
-       if (line6pcm->prev_fbuf != NULL) {
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-               if (line6pcm->flags & LINE6_BITS_PCM_IMPULSE) {
-                       create_impulse_test_signal(line6pcm, urb_out,
-                                                  bytes_per_frame);
-                       if (line6pcm->flags &
-                           LINE6_BIT_PCM_ALSA_CAPTURE_STREAM) {
-                               line6_capture_copy(line6pcm,
-                                                  urb_out->transfer_buffer,
-                                                  urb_out->
-                                                  transfer_buffer_length);
-                               line6_capture_check_period(line6pcm,
-                                       urb_out->transfer_buffer_length);
-                       }
-               } else {
-#endif
-                       if (!
-                           (line6pcm->line6->
-                            properties->capabilities & LINE6_BIT_HWMON)
-                           && (line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM)
-                           && (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM))
-                               add_monitor_signal(urb_out, line6pcm->prev_fbuf,
-                                                  line6pcm->volume_monitor,
-                                                  bytes_per_frame);
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-               }
-#endif
-       }
-
-       ret = usb_submit_urb(urb_out, GFP_ATOMIC);
-
-       if (ret == 0)
-               set_bit(index, &line6pcm->active_urb_out);
-       else
-               dev_err(line6pcm->line6->ifcdev,
-                       "URB out #%d submission failed (%d)\n", index, ret);
-
-       spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
-       return 0;
-}
-
-/*
-       Submit all currently available playback URBs.
-*/
-int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm)
-{
-       int ret, i;
-
-       for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
-               ret = submit_audio_out_urb(line6pcm);
-               if (ret < 0)
-                       return ret;
-       }
-
-       return 0;
-}
-
-/*
-       Unlink all currently active playback URBs.
-*/
-void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm)
-{
-       unsigned int i;
-
-       for (i = LINE6_ISO_BUFFERS; i--;) {
-               if (test_bit(i, &line6pcm->active_urb_out)) {
-                       if (!test_and_set_bit(i, &line6pcm->unlink_urb_out)) {
-                               struct urb *u = line6pcm->urb_audio_out[i];
-
-                               usb_unlink_urb(u);
-                       }
-               }
-       }
-}
-
-/*
-       Wait until unlinking of all currently active playback URBs has been
-       finished.
-*/
-void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
-{
-       int timeout = HZ;
-       unsigned int i;
-       int alive;
-
-       do {
-               alive = 0;
-               for (i = LINE6_ISO_BUFFERS; i--;) {
-                       if (test_bit(i, &line6pcm->active_urb_out))
-                               alive++;
-               }
-               if (!alive)
-                       break;
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(1);
-       } while (--timeout > 0);
-       if (alive)
-               snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
-}
-
-/*
-       Unlink all currently active playback URBs, and wait for finishing.
-*/
-void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
-{
-       line6_unlink_audio_out_urbs(line6pcm);
-       line6_wait_clear_audio_out_urbs(line6pcm);
-}
-
-void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm)
-{
-       kfree(line6pcm->buffer_out);
-       line6pcm->buffer_out = NULL;
-}
-
-/*
-       Callback for completed playback URB.
-*/
-static void audio_out_callback(struct urb *urb)
-{
-       int i, index, length = 0, shutdown = 0;
-       unsigned long flags;
-       struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;
-       struct snd_pcm_substream *substream =
-           get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK);
-
-#if USE_CLEAR_BUFFER_WORKAROUND
-       memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
-#endif
-
-       line6pcm->last_frame_out = urb->start_frame;
-
-       /* find index of URB */
-       for (index = LINE6_ISO_BUFFERS; index--;)
-               if (urb == line6pcm->urb_audio_out[index])
-                       break;
-
-       if (index < 0)
-               return;         /* URB has been unlinked asynchronously */
-
-       for (i = LINE6_ISO_PACKETS; i--;)
-               length += urb->iso_frame_desc[i].length;
-
-       spin_lock_irqsave(&line6pcm->lock_audio_out, flags);
-
-       if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags)) {
-               struct snd_pcm_runtime *runtime = substream->runtime;
-
-               line6pcm->pos_out_done +=
-                   length / line6pcm->properties->bytes_per_frame;
-
-               if (line6pcm->pos_out_done >= runtime->buffer_size)
-                       line6pcm->pos_out_done -= runtime->buffer_size;
-       }
-
-       clear_bit(index, &line6pcm->active_urb_out);
-
-       for (i = LINE6_ISO_PACKETS; i--;)
-               if (urb->iso_frame_desc[i].status == -EXDEV) {
-                       shutdown = 1;
-                       break;
-               }
-
-       if (test_and_clear_bit(index, &line6pcm->unlink_urb_out))
-               shutdown = 1;
-
-       spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
-
-       if (!shutdown) {
-               submit_audio_out_urb(line6pcm);
-
-               if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM,
-                            &line6pcm->flags)) {
-                       line6pcm->bytes_out += length;
-                       if (line6pcm->bytes_out >= line6pcm->period_out) {
-                               line6pcm->bytes_out %= line6pcm->period_out;
-                               snd_pcm_period_elapsed(substream);
-                       }
-               }
-       }
-}
-
-/* open playback callback */
-static int snd_line6_playback_open(struct snd_pcm_substream *substream)
-{
-       int err;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
-       err = snd_pcm_hw_constraint_ratdens(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
-                                           (&line6pcm->
-                                            properties->snd_line6_rates));
-       if (err < 0)
-               return err;
-
-       runtime->hw = line6pcm->properties->snd_line6_playback_hw;
-       return 0;
-}
-
-/* close playback callback */
-static int snd_line6_playback_close(struct snd_pcm_substream *substream)
-{
-       return 0;
-}
-
-/* hw_params playback callback */
-static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream,
-                                       struct snd_pcm_hw_params *hw_params)
-{
-       int ret;
-       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
-       /* -- Florian Demski [FD] */
-       /* don't ask me why, but this fixes the bug on my machine */
-       if (line6pcm == NULL) {
-               if (substream->pcm == NULL)
-                       return -ENOMEM;
-               if (substream->pcm->private_data == NULL)
-                       return -ENOMEM;
-               substream->private_data = substream->pcm->private_data;
-               line6pcm = snd_pcm_substream_chip(substream);
-       }
-       /* -- [FD] end */
-
-       ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
-
-       if (ret < 0)
-               return ret;
-
-       ret = snd_pcm_lib_malloc_pages(substream,
-                                      params_buffer_bytes(hw_params));
-       if (ret < 0) {
-               line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
-               return ret;
-       }
-
-       line6pcm->period_out = params_period_bytes(hw_params);
-       return 0;
-}
-
-/* hw_free playback callback */
-static int snd_line6_playback_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
-       line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
-       return snd_pcm_lib_free_pages(substream);
-}
-
-/* trigger playback callback */
-int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd)
-{
-       int err;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-#ifdef CONFIG_PM
-       case SNDRV_PCM_TRIGGER_RESUME:
-#endif
-               err = line6_pcm_acquire(line6pcm,
-                                       LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM);
-
-               if (err < 0)
-                       return err;
-
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-#ifdef CONFIG_PM
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-#endif
-               err = line6_pcm_release(line6pcm,
-                                       LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM);
-
-               if (err < 0)
-                       return err;
-
-               break;
-
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               set_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags);
-               break;
-
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               clear_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags);
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/* playback pointer callback */
-static snd_pcm_uframes_t
-snd_line6_playback_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
-       return line6pcm->pos_out_done;
-}
-
-/* playback operators */
-struct snd_pcm_ops snd_line6_playback_ops = {
-       .open = snd_line6_playback_open,
-       .close = snd_line6_playback_close,
-       .ioctl = snd_pcm_lib_ioctl,
-       .hw_params = snd_line6_playback_hw_params,
-       .hw_free = snd_line6_playback_hw_free,
-       .prepare = snd_line6_prepare,
-       .trigger = snd_line6_trigger,
-       .pointer = snd_line6_playback_pointer,
-};
-
-int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm)
-{
-       int i;
-
-       /* create audio URBs and fill in constant values: */
-       for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
-               struct urb *urb;
-
-               /* URB for audio out: */
-               urb = line6pcm->urb_audio_out[i] =
-                   usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
-
-               if (urb == NULL) {
-                       dev_err(line6pcm->line6->ifcdev, "Out of memory\n");
-                       return -ENOMEM;
-               }
-
-               urb->dev = line6pcm->line6->usbdev;
-               urb->pipe =
-                   usb_sndisocpipe(line6pcm->line6->usbdev,
-                                   line6pcm->ep_audio_write &
-                                   USB_ENDPOINT_NUMBER_MASK);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->start_frame = -1;
-               urb->number_of_packets = LINE6_ISO_PACKETS;
-               urb->interval = LINE6_ISO_INTERVAL;
-               urb->error_count = 0;
-               urb->complete = audio_out_callback;
-       }
-
-       return 0;
-}
diff --git a/drivers/staging/line6/playback.h b/drivers/staging/line6/playback.h
deleted file mode 100644 (file)
index 743bd6f..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *     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, version 2.
- *
- */
-
-#ifndef PLAYBACK_H
-#define PLAYBACK_H
-
-#include <sound/pcm.h>
-
-#include "driver.h"
-
-/*
- * When the TonePort is used with jack in full duplex mode and the outputs are
- * not connected, the software monitor produces an ugly noise since everything
- * written to the output buffer (i.e., the input signal) will be repeated in
- * the next period (sounds like a delay effect). As a workaround, the output
- * buffer is cleared after the data have been read, but there must be a better
- * solution. Until one is found, this workaround can be used to fix the
- * problem.
- */
-#define USE_CLEAR_BUFFER_WORKAROUND 1
-
-extern struct snd_pcm_ops snd_line6_playback_ops;
-
-extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm);
-extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm
-                                                  *line6pcm);
-extern void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm);
-extern int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd);
-
-#endif
diff --git a/drivers/staging/line6/pod.c b/drivers/staging/line6/pod.c
deleted file mode 100644 (file)
index 44f4b2f..0000000
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *     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, version 2.
- *
- */
-
-#include <linux/slab.h>
-#include <linux/wait.h>
-#include <sound/control.h>
-
-#include "audio.h"
-#include "capture.h"
-#include "driver.h"
-#include "playback.h"
-#include "pod.h"
-
-#define POD_SYSEX_CODE 3
-#define POD_BYTES_PER_FRAME 6  /* 24bit audio (stereo) */
-
-/* *INDENT-OFF* */
-
-enum {
-       POD_SYSEX_SAVE      = 0x24,
-       POD_SYSEX_SYSTEM    = 0x56,
-       POD_SYSEX_SYSTEMREQ = 0x57,
-       /* POD_SYSEX_UPDATE    = 0x6c, */  /* software update! */
-       POD_SYSEX_STORE     = 0x71,
-       POD_SYSEX_FINISH    = 0x72,
-       POD_SYSEX_DUMPMEM   = 0x73,
-       POD_SYSEX_DUMP      = 0x74,
-       POD_SYSEX_DUMPREQ   = 0x75
-
-       /* dumps entire internal memory of PODxt Pro */
-       /* POD_SYSEX_DUMPMEM2  = 0x76 */
-};
-
-enum {
-       POD_MONITOR_LEVEL  = 0x04,
-       POD_SYSTEM_INVALID = 0x10000
-};
-
-/* *INDENT-ON* */
-
-enum {
-       POD_DUMP_MEMORY = 2
-};
-
-enum {
-       POD_BUSY_READ,
-       POD_BUSY_WRITE,
-       POD_CHANNEL_DIRTY,
-       POD_SAVE_PRESSED,
-       POD_BUSY_MIDISEND
-};
-
-static struct snd_ratden pod_ratden = {
-       .num_min = 78125,
-       .num_max = 78125,
-       .num_step = 1,
-       .den = 2
-};
-
-static struct line6_pcm_properties pod_pcm_properties = {
-       .snd_line6_playback_hw = {
-                                 .info = (SNDRV_PCM_INFO_MMAP |
-                                          SNDRV_PCM_INFO_INTERLEAVED |
-                                          SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                                          SNDRV_PCM_INFO_MMAP_VALID |
-                                          SNDRV_PCM_INFO_PAUSE |
-#ifdef CONFIG_PM
-                                          SNDRV_PCM_INFO_RESUME |
-#endif
-                                          SNDRV_PCM_INFO_SYNC_START),
-                                 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
-                                 .rates = SNDRV_PCM_RATE_KNOT,
-                                 .rate_min = 39062,
-                                 .rate_max = 39063,
-                                 .channels_min = 2,
-                                 .channels_max = 2,
-                                 .buffer_bytes_max = 60000,
-                                 .period_bytes_min = 64,
-                                 .period_bytes_max = 8192,
-                                 .periods_min = 1,
-                                 .periods_max = 1024},
-       .snd_line6_capture_hw = {
-                                .info = (SNDRV_PCM_INFO_MMAP |
-                                         SNDRV_PCM_INFO_INTERLEAVED |
-                                         SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                                         SNDRV_PCM_INFO_MMAP_VALID |
-#ifdef CONFIG_PM
-                                         SNDRV_PCM_INFO_RESUME |
-#endif
-                                         SNDRV_PCM_INFO_SYNC_START),
-                                .formats = SNDRV_PCM_FMTBIT_S24_3LE,
-                                .rates = SNDRV_PCM_RATE_KNOT,
-                                .rate_min = 39062,
-                                .rate_max = 39063,
-                                .channels_min = 2,
-                                .channels_max = 2,
-                                .buffer_bytes_max = 60000,
-                                .period_bytes_min = 64,
-                                .period_bytes_max = 8192,
-                                .periods_min = 1,
-                                .periods_max = 1024},
-       .snd_line6_rates = {
-                           .nrats = 1,
-                           .rats = &pod_ratden},
-       .bytes_per_frame = POD_BYTES_PER_FRAME
-};
-
-static const char pod_version_header[] = {
-       0xf2, 0x7e, 0x7f, 0x06, 0x02
-};
-
-/* forward declarations: */
-static void pod_startup2(unsigned long data);
-static void pod_startup3(struct usb_line6_pod *pod);
-
-static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code,
-                                   int size)
-{
-       return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code,
-                                       size);
-}
-
-/*
-       Process a completely received message.
-*/
-void line6_pod_process_message(struct usb_line6_pod *pod)
-{
-       const unsigned char *buf = pod->line6.buffer_message;
-
-       if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) {
-               pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15];
-               pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) |
-                                (int) buf[10];
-               pod_startup3(pod);
-               return;
-       }
-
-       /* Only look for sysex messages from this device */
-       if (buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE) &&
-           buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN)) {
-               return;
-       }
-       if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) != 0)
-               return;
-
-       if (buf[5] == POD_SYSEX_SYSTEM && buf[6] == POD_MONITOR_LEVEL) {
-               short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) |
-                             ((int)buf[9] << 4) | (int)buf[10];
-               pod->monitor_level = value;
-       }
-}
-
-/*
-       Transmit PODxt Pro control parameter.
-*/
-void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param,
-                                 u8 value)
-{
-       line6_transmit_parameter(&pod->line6, param, value);
-}
-
-/*
-       Send system parameter (from integer).
-*/
-static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
-                                   int code)
-{
-       char *sysex;
-       static const int size = 5;
-
-       sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
-       if (!sysex)
-               return -ENOMEM;
-       sysex[SYSEX_DATA_OFS] = code;
-       sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f;
-       sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f;
-       sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f;
-       sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f;
-       line6_send_sysex_message(&pod->line6, sysex, size);
-       kfree(sysex);
-       return 0;
-}
-
-/*
-       "read" request on "serial_number" special file.
-*/
-static ssize_t serial_number_show(struct device *dev,
-                                 struct device_attribute *attr, char *buf)
-{
-       struct usb_interface *interface = to_usb_interface(dev);
-       struct usb_line6_pod *pod = usb_get_intfdata(interface);
-
-       return sprintf(buf, "%d\n", pod->serial_number);
-}
-
-/*
-       "read" request on "firmware_version" special file.
-*/
-static ssize_t firmware_version_show(struct device *dev,
-                                    struct device_attribute *attr, char *buf)
-{
-       struct usb_interface *interface = to_usb_interface(dev);
-       struct usb_line6_pod *pod = usb_get_intfdata(interface);
-
-       return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
-                      pod->firmware_version % 100);
-}
-
-/*
-       "read" request on "device_id" special file.
-*/
-static ssize_t device_id_show(struct device *dev,
-                             struct device_attribute *attr, char *buf)
-{
-       struct usb_interface *interface = to_usb_interface(dev);
-       struct usb_line6_pod *pod = usb_get_intfdata(interface);
-
-       return sprintf(buf, "%d\n", pod->device_id);
-}
-
-/*
-       POD startup procedure.
-       This is a sequence of functions with special requirements (e.g., must
-       not run immediately after initialization, must not run in interrupt
-       context). After the last one has finished, the device is ready to use.
-*/
-
-static void pod_startup1(struct usb_line6_pod *pod)
-{
-       CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT);
-
-       /* delay startup procedure: */
-       line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
-                         (unsigned long)pod);
-}
-
-static void pod_startup2(unsigned long data)
-{
-       struct usb_line6_pod *pod = (struct usb_line6_pod *)data;
-       struct usb_line6 *line6 = &pod->line6;
-
-       CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ);
-
-       /* request firmware version: */
-       line6_version_request_async(line6);
-}
-
-static void pod_startup3(struct usb_line6_pod *pod)
-{
-       CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE);
-
-       /* schedule work for global work queue: */
-       schedule_work(&pod->startup_work);
-}
-
-static void pod_startup4(struct work_struct *work)
-{
-       struct usb_line6_pod *pod =
-           container_of(work, struct usb_line6_pod, startup_work);
-       struct usb_line6 *line6 = &pod->line6;
-
-       CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP);
-
-       /* serial number: */
-       line6_read_serial_number(&pod->line6, &pod->serial_number);
-
-       /* ALSA audio interface: */
-       line6_register_audio(line6);
-}
-
-/* POD special files: */
-static DEVICE_ATTR_RO(device_id);
-static DEVICE_ATTR_RO(firmware_version);
-static DEVICE_ATTR_RO(serial_number);
-
-/* control info callback */
-static int snd_pod_control_monitor_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 = 65535;
-       return 0;
-}
-
-/* control get callback */
-static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol,
-                                      struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-       struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
-
-       ucontrol->value.integer.value[0] = pod->monitor_level;
-       return 0;
-}
-
-/* control put callback */
-static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol,
-                                      struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-       struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
-
-       if (ucontrol->value.integer.value[0] == pod->monitor_level)
-               return 0;
-
-       pod->monitor_level = ucontrol->value.integer.value[0];
-       pod_set_system_param_int(pod, ucontrol->value.integer.value[0],
-                                POD_MONITOR_LEVEL);
-       return 1;
-}
-
-/* control definition */
-static struct snd_kcontrol_new pod_control_monitor = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Monitor Playback Volume",
-       .index = 0,
-       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-       .info = snd_pod_control_monitor_info,
-       .get = snd_pod_control_monitor_get,
-       .put = snd_pod_control_monitor_put
-};
-
-/*
-       POD destructor.
-*/
-static void pod_destruct(struct usb_interface *interface)
-{
-       struct usb_line6_pod *pod = usb_get_intfdata(interface);
-
-       if (pod == NULL)
-               return;
-       line6_cleanup_audio(&pod->line6);
-
-       del_timer(&pod->startup_timer);
-       cancel_work_sync(&pod->startup_work);
-}
-
-/*
-       Create sysfs entries.
-*/
-static int pod_create_files2(struct device *dev)
-{
-       int err;
-
-       CHECK_RETURN(device_create_file(dev, &dev_attr_device_id));
-       CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version));
-       CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number));
-       return 0;
-}
-
-/*
-        Try to init POD device.
-*/
-static int pod_try_init(struct usb_interface *interface,
-                       struct usb_line6_pod *pod)
-{
-       int err;
-       struct usb_line6 *line6 = &pod->line6;
-
-       init_timer(&pod->startup_timer);
-       INIT_WORK(&pod->startup_work, pod_startup4);
-
-       if ((interface == NULL) || (pod == NULL))
-               return -ENODEV;
-
-       /* create sysfs entries: */
-       err = pod_create_files2(&interface->dev);
-       if (err < 0)
-               return err;
-
-       /* initialize audio system: */
-       err = line6_init_audio(line6);
-       if (err < 0)
-               return err;
-
-       /* initialize MIDI subsystem: */
-       err = line6_init_midi(line6);
-       if (err < 0)
-               return err;
-
-       /* initialize PCM subsystem: */
-       err = line6_init_pcm(line6, &pod_pcm_properties);
-       if (err < 0)
-               return err;
-
-       /* register monitor control: */
-       err = snd_ctl_add(line6->card,
-                         snd_ctl_new1(&pod_control_monitor, line6->line6pcm));
-       if (err < 0)
-               return err;
-
-       /*
-          When the sound card is registered at this point, the PODxt Live
-          displays "Invalid Code Error 07", so we do it later in the event
-          handler.
-        */
-
-       if (pod->line6.properties->capabilities & LINE6_BIT_CONTROL) {
-               pod->monitor_level = POD_SYSTEM_INVALID;
-
-               /* initiate startup procedure: */
-               pod_startup1(pod);
-       }
-
-       return 0;
-}
-
-/*
-        Init POD device (and clean up in case of failure).
-*/
-int line6_pod_init(struct usb_interface *interface, struct usb_line6_pod *pod)
-{
-       int err = pod_try_init(interface, pod);
-
-       if (err < 0)
-               pod_destruct(interface);
-
-       return err;
-}
-
-/*
-       POD device disconnected.
-*/
-void line6_pod_disconnect(struct usb_interface *interface)
-{
-       struct usb_line6_pod *pod;
-
-       if (interface == NULL)
-               return;
-       pod = usb_get_intfdata(interface);
-
-       if (pod != NULL) {
-               struct snd_line6_pcm *line6pcm = pod->line6.line6pcm;
-               struct device *dev = &interface->dev;
-
-               if (line6pcm != NULL)
-                       line6_pcm_disconnect(line6pcm);
-
-               if (dev != NULL) {
-                       /* remove sysfs entries: */
-                       device_remove_file(dev, &dev_attr_device_id);
-                       device_remove_file(dev, &dev_attr_firmware_version);
-                       device_remove_file(dev, &dev_attr_serial_number);
-               }
-       }
-
-       pod_destruct(interface);
-}
diff --git a/drivers/staging/line6/pod.h b/drivers/staging/line6/pod.h
deleted file mode 100644 (file)
index 3e3f167..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *     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, version 2.
- *
- */
-
-#ifndef POD_H
-#define POD_H
-
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-
-#include <sound/core.h>
-
-#include "driver.h"
-
-/*
-       PODxt Live interfaces
-*/
-#define PODXTLIVE_INTERFACE_POD    0
-#define PODXTLIVE_INTERFACE_VARIAX 1
-
-/*
-       Locate name in binary program dump
-*/
-#define        POD_NAME_OFFSET 0
-#define        POD_NAME_LENGTH 16
-
-/*
-       Other constants
-*/
-#define POD_CONTROL_SIZE 0x80
-#define POD_BUFSIZE_DUMPREQ 7
-#define POD_STARTUP_DELAY 1000
-
-/*
-       Stages of POD startup procedure
-*/
-enum {
-       POD_STARTUP_INIT = 1,
-       POD_STARTUP_VERSIONREQ,
-       POD_STARTUP_WORKQUEUE,
-       POD_STARTUP_SETUP,
-       POD_STARTUP_LAST = POD_STARTUP_SETUP - 1
-};
-
-struct usb_line6_pod {
-       /**
-               Generic Line6 USB data.
-       */
-       struct usb_line6 line6;
-
-       /**
-               Instrument monitor level.
-       */
-       int monitor_level;
-
-       /**
-               Timer for device initializaton.
-       */
-       struct timer_list startup_timer;
-
-       /**
-               Work handler for device initializaton.
-       */
-       struct work_struct startup_work;
-
-       /**
-               Current progress in startup procedure.
-       */
-       int startup_progress;
-
-       /**
-               Serial number of device.
-       */
-       int serial_number;
-
-       /**
-               Firmware version (x 100).
-       */
-       int firmware_version;
-
-       /**
-               Device ID.
-       */
-       int device_id;
-};
-
-extern void line6_pod_disconnect(struct usb_interface *interface);
-extern int line6_pod_init(struct usb_interface *interface,
-                         struct usb_line6_pod *pod);
-extern void line6_pod_process_message(struct usb_line6_pod *pod);
-extern void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param,
-                                        u8 value);
-
-#endif
diff --git a/drivers/staging/line6/podhd.c b/drivers/staging/line6/podhd.c
deleted file mode 100644 (file)
index 7ef4543..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Line6 Pod HD
- *
- * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation, version 2.
- *
- */
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-
-#include "audio.h"
-#include "driver.h"
-#include "pcm.h"
-#include "podhd.h"
-
-#define PODHD_BYTES_PER_FRAME 6        /* 24bit audio (stereo) */
-
-static struct snd_ratden podhd_ratden = {
-       .num_min = 48000,
-       .num_max = 48000,
-       .num_step = 1,
-       .den = 1,
-};
-
-static struct line6_pcm_properties podhd_pcm_properties = {
-       .snd_line6_playback_hw = {
-                                 .info = (SNDRV_PCM_INFO_MMAP |
-                                          SNDRV_PCM_INFO_INTERLEAVED |
-                                          SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                                          SNDRV_PCM_INFO_MMAP_VALID |
-                                          SNDRV_PCM_INFO_PAUSE |
-#ifdef CONFIG_PM
-                                          SNDRV_PCM_INFO_RESUME |
-#endif
-                                          SNDRV_PCM_INFO_SYNC_START),
-                                 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
-                                 .rates = SNDRV_PCM_RATE_48000,
-                                 .rate_min = 48000,
-                                 .rate_max = 48000,
-                                 .channels_min = 2,
-                                 .channels_max = 2,
-                                 .buffer_bytes_max = 60000,
-                                 .period_bytes_min = 64,
-                                 .period_bytes_max = 8192,
-                                 .periods_min = 1,
-                                 .periods_max = 1024},
-       .snd_line6_capture_hw = {
-                                .info = (SNDRV_PCM_INFO_MMAP |
-                                         SNDRV_PCM_INFO_INTERLEAVED |
-                                         SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                                         SNDRV_PCM_INFO_MMAP_VALID |
-#ifdef CONFIG_PM
-                                         SNDRV_PCM_INFO_RESUME |
-#endif
-                                         SNDRV_PCM_INFO_SYNC_START),
-                                .formats = SNDRV_PCM_FMTBIT_S24_3LE,
-                                .rates = SNDRV_PCM_RATE_48000,
-                                .rate_min = 48000,
-                                .rate_max = 48000,
-                                .channels_min = 2,
-                                .channels_max = 2,
-                                .buffer_bytes_max = 60000,
-                                .period_bytes_min = 64,
-                                .period_bytes_max = 8192,
-                                .periods_min = 1,
-                                .periods_max = 1024},
-       .snd_line6_rates = {
-                           .nrats = 1,
-                           .rats = &podhd_ratden},
-       .bytes_per_frame = PODHD_BYTES_PER_FRAME
-};
-
-/*
-       POD HD destructor.
-*/
-static void podhd_destruct(struct usb_interface *interface)
-{
-       struct usb_line6_podhd *podhd = usb_get_intfdata(interface);
-
-       if (podhd == NULL)
-               return;
-       line6_cleanup_audio(&podhd->line6);
-}
-
-/*
-       Try to init POD HD device.
-*/
-static int podhd_try_init(struct usb_interface *interface,
-                         struct usb_line6_podhd *podhd)
-{
-       int err;
-       struct usb_line6 *line6 = &podhd->line6;
-
-       if ((interface == NULL) || (podhd == NULL))
-               return -ENODEV;
-
-       /* initialize audio system: */
-       err = line6_init_audio(line6);
-       if (err < 0)
-               return err;
-
-       /* initialize MIDI subsystem: */
-       err = line6_init_midi(line6);
-       if (err < 0)
-               return err;
-
-       /* initialize PCM subsystem: */
-       err = line6_init_pcm(line6, &podhd_pcm_properties);
-       if (err < 0)
-               return err;
-
-       /* register USB audio system: */
-       err = line6_register_audio(line6);
-       return err;
-}
-
-/*
-       Init POD HD device (and clean up in case of failure).
-*/
-int line6_podhd_init(struct usb_interface *interface,
-                    struct usb_line6_podhd *podhd)
-{
-       int err = podhd_try_init(interface, podhd);
-
-       if (err < 0)
-               podhd_destruct(interface);
-
-       return err;
-}
-
-/*
-       POD HD device disconnected.
-*/
-void line6_podhd_disconnect(struct usb_interface *interface)
-{
-       struct usb_line6_podhd *podhd;
-
-       if (interface == NULL)
-               return;
-       podhd = usb_get_intfdata(interface);
-
-       if (podhd != NULL) {
-               struct snd_line6_pcm *line6pcm = podhd->line6.line6pcm;
-
-               if (line6pcm != NULL)
-                       line6_pcm_disconnect(line6pcm);
-       }
-
-       podhd_destruct(interface);
-}
diff --git a/drivers/staging/line6/podhd.h b/drivers/staging/line6/podhd.h
deleted file mode 100644 (file)
index 652f740..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Line6 Pod HD
- *
- * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation, version 2.
- *
- */
-
-#ifndef PODHD_H
-#define PODHD_H
-
-#include <linux/usb.h>
-
-#include "driver.h"
-
-struct usb_line6_podhd {
-       /**
-               Generic Line6 USB data.
-       */
-       struct usb_line6 line6;
-};
-
-extern void line6_podhd_disconnect(struct usb_interface *interface);
-extern int line6_podhd_init(struct usb_interface *interface,
-                           struct usb_line6_podhd *podhd);
-
-#endif /* PODHD_H */
diff --git a/drivers/staging/line6/revision.h b/drivers/staging/line6/revision.h
deleted file mode 100644 (file)
index b4eee2b..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef DRIVER_REVISION
-/* current subversion revision */
-#define DRIVER_REVISION " (904)"
-#endif
diff --git a/drivers/staging/line6/toneport.c b/drivers/staging/line6/toneport.c
deleted file mode 100644 (file)
index 6943715..0000000
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *                         Emil Myhrman (emil.myhrman@gmail.com)
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation, version 2.
- *
- */
-
-#include <linux/wait.h>
-#include <sound/control.h>
-
-#include "audio.h"
-#include "capture.h"
-#include "driver.h"
-#include "playback.h"
-#include "toneport.h"
-
-static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2);
-
-#define TONEPORT_PCM_DELAY 1
-
-static struct snd_ratden toneport_ratden = {
-       .num_min = 44100,
-       .num_max = 44100,
-       .num_step = 1,
-       .den = 1
-};
-
-static struct line6_pcm_properties toneport_pcm_properties = {
-       .snd_line6_playback_hw = {
-                                 .info = (SNDRV_PCM_INFO_MMAP |
-                                          SNDRV_PCM_INFO_INTERLEAVED |
-                                          SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                                          SNDRV_PCM_INFO_MMAP_VALID |
-                                          SNDRV_PCM_INFO_PAUSE |
-#ifdef CONFIG_PM
-                                          SNDRV_PCM_INFO_RESUME |
-#endif
-                                          SNDRV_PCM_INFO_SYNC_START),
-                                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
-                                 .rates = SNDRV_PCM_RATE_KNOT,
-                                 .rate_min = 44100,
-                                 .rate_max = 44100,
-                                 .channels_min = 2,
-                                 .channels_max = 2,
-                                 .buffer_bytes_max = 60000,
-                                 .period_bytes_min = 64,
-                                 .period_bytes_max = 8192,
-                                 .periods_min = 1,
-                                 .periods_max = 1024},
-       .snd_line6_capture_hw = {
-                                .info = (SNDRV_PCM_INFO_MMAP |
-                                         SNDRV_PCM_INFO_INTERLEAVED |
-                                         SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                                         SNDRV_PCM_INFO_MMAP_VALID |
-#ifdef CONFIG_PM
-                                         SNDRV_PCM_INFO_RESUME |
-#endif
-                                         SNDRV_PCM_INFO_SYNC_START),
-                                .formats = SNDRV_PCM_FMTBIT_S16_LE,
-                                .rates = SNDRV_PCM_RATE_KNOT,
-                                .rate_min = 44100,
-                                .rate_max = 44100,
-                                .channels_min = 2,
-                                .channels_max = 2,
-                                .buffer_bytes_max = 60000,
-                                .period_bytes_min = 64,
-                                .period_bytes_max = 8192,
-                                .periods_min = 1,
-                                .periods_max = 1024},
-       .snd_line6_rates = {
-                           .nrats = 1,
-                           .rats = &toneport_ratden},
-       .bytes_per_frame = 4
-};
-
-/*
-       For the led on Guitarport.
-       Brightness goes from 0x00 to 0x26. Set a value above this to have led
-       blink.
-       (void cmd_0x02(byte red, byte green)
-*/
-static int led_red = 0x00;
-static int led_green = 0x26;
-
-static const struct {
-       const char *name;
-       int code;
-} toneport_source_info[] = {
-       {"Microphone", 0x0a01},
-       {"Line", 0x0801},
-       {"Instrument", 0x0b01},
-       {"Inst & Mic", 0x0901}
-};
-
-static bool toneport_has_led(short product)
-{
-       return
-           (product == LINE6_DEVID_GUITARPORT) ||
-           (product == LINE6_DEVID_TONEPORT_GX);
-       /* add your device here if you are missing support for the LEDs */
-}
-
-static void toneport_update_led(struct device *dev)
-{
-       struct usb_interface *interface = to_usb_interface(dev);
-       struct usb_line6_toneport *tp = usb_get_intfdata(interface);
-       struct usb_line6 *line6;
-
-       if (!tp)
-               return;
-
-       line6 = &tp->line6;
-       if (line6)
-               toneport_send_cmd(line6->usbdev, (led_red << 8) | 0x0002,
-                                 led_green);
-}
-
-static ssize_t toneport_set_led_red(struct device *dev,
-                                   struct device_attribute *attr,
-                                   const char *buf, size_t count)
-{
-       int retval;
-
-       retval = kstrtoint(buf, 10, &led_red);
-       if (retval)
-               return retval;
-
-       toneport_update_led(dev);
-       return count;
-}
-
-static ssize_t toneport_set_led_green(struct device *dev,
-                                     struct device_attribute *attr,
-                                     const char *buf, size_t count)
-{
-       int retval;
-
-       retval = kstrtoint(buf, 10, &led_green);
-       if (retval)
-               return retval;
-
-       toneport_update_led(dev);
-       return count;
-}
-
-static DEVICE_ATTR(led_red, S_IWUSR | S_IRUGO, line6_nop_read,
-                  toneport_set_led_red);
-static DEVICE_ATTR(led_green, S_IWUSR | S_IRUGO, line6_nop_read,
-                  toneport_set_led_green);
-
-static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)
-{
-       int ret;
-
-       ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
-                             USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
-                             cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ);
-
-       if (ret < 0) {
-               dev_err(&usbdev->dev, "send failed (error %d)\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-/* monitor info callback */
-static int snd_toneport_monitor_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 = 256;
-       return 0;
-}
-
-/* monitor get callback */
-static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-
-       ucontrol->value.integer.value[0] = line6pcm->volume_monitor;
-       return 0;
-}
-
-/* monitor put callback */
-static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-
-       if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor)
-               return 0;
-
-       line6pcm->volume_monitor = ucontrol->value.integer.value[0];
-
-       if (line6pcm->volume_monitor > 0)
-               line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_MONITOR);
-       else
-               line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
-
-       return 1;
-}
-
-/* source info callback */
-static int snd_toneport_source_info(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_info *uinfo)
-{
-       const int size = ARRAY_SIZE(toneport_source_info);
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = size;
-
-       if (uinfo->value.enumerated.item >= size)
-               uinfo->value.enumerated.item = size - 1;
-
-       strcpy(uinfo->value.enumerated.name,
-              toneport_source_info[uinfo->value.enumerated.item].name);
-
-       return 0;
-}
-
-/* source get callback */
-static int snd_toneport_source_get(struct snd_kcontrol *kcontrol,
-                                  struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-       struct usb_line6_toneport *toneport =
-           (struct usb_line6_toneport *)line6pcm->line6;
-       ucontrol->value.enumerated.item[0] = toneport->source;
-       return 0;
-}
-
-/* source put callback */
-static int snd_toneport_source_put(struct snd_kcontrol *kcontrol,
-                                  struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-       struct usb_line6_toneport *toneport =
-           (struct usb_line6_toneport *)line6pcm->line6;
-       unsigned int source;
-
-       source = ucontrol->value.enumerated.item[0];
-       if (source >= ARRAY_SIZE(toneport_source_info))
-               return -EINVAL;
-       if (source == toneport->source)
-               return 0;
-
-       toneport->source = source;
-       toneport_send_cmd(toneport->line6.usbdev,
-                         toneport_source_info[source].code, 0x0000);
-       return 1;
-}
-
-static void toneport_start_pcm(unsigned long arg)
-{
-       struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg;
-       struct usb_line6 *line6 = &toneport->line6;
-
-       line6_pcm_acquire(line6->line6pcm, LINE6_BITS_PCM_MONITOR);
-}
-
-/* control definition */
-static struct snd_kcontrol_new toneport_control_monitor = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Monitor Playback Volume",
-       .index = 0,
-       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-       .info = snd_toneport_monitor_info,
-       .get = snd_toneport_monitor_get,
-       .put = snd_toneport_monitor_put
-};
-
-/* source selector definition */
-static struct snd_kcontrol_new toneport_control_source = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "PCM Capture Source",
-       .index = 0,
-       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-       .info = snd_toneport_source_info,
-       .get = snd_toneport_source_get,
-       .put = snd_toneport_source_put
-};
-
-/*
-       Toneport destructor.
-*/
-static void toneport_destruct(struct usb_interface *interface)
-{
-       struct usb_line6_toneport *toneport = usb_get_intfdata(interface);
-
-       if (toneport == NULL)
-               return;
-       line6_cleanup_audio(&toneport->line6);
-}
-
-/*
-       Setup Toneport device.
-*/
-static void toneport_setup(struct usb_line6_toneport *toneport)
-{
-       int ticks;
-       struct usb_line6 *line6 = &toneport->line6;
-       struct usb_device *usbdev = line6->usbdev;
-       u16 idProduct = le16_to_cpu(usbdev->descriptor.idProduct);
-
-       /* sync time on device with host: */
-       ticks = (int)get_seconds();
-       line6_write_data(line6, 0x80c6, &ticks, 4);
-
-       /* enable device: */
-       toneport_send_cmd(usbdev, 0x0301, 0x0000);
-
-       /* initialize source select: */
-       switch (le16_to_cpu(usbdev->descriptor.idProduct)) {
-       case LINE6_DEVID_TONEPORT_UX1:
-       case LINE6_DEVID_TONEPORT_UX2:
-       case LINE6_DEVID_PODSTUDIO_UX1:
-       case LINE6_DEVID_PODSTUDIO_UX2:
-               toneport_send_cmd(usbdev,
-                                 toneport_source_info[toneport->source].code,
-                                 0x0000);
-       }
-
-       if (toneport_has_led(idProduct))
-               toneport_update_led(&usbdev->dev);
-}
-
-/*
-        Try to init Toneport device.
-*/
-static int toneport_try_init(struct usb_interface *interface,
-                            struct usb_line6_toneport *toneport)
-{
-       int err;
-       struct usb_line6 *line6 = &toneport->line6;
-       struct usb_device *usbdev = line6->usbdev;
-       u16 idProduct = le16_to_cpu(usbdev->descriptor.idProduct);
-
-       if ((interface == NULL) || (toneport == NULL))
-               return -ENODEV;
-
-       /* initialize audio system: */
-       err = line6_init_audio(line6);
-       if (err < 0)
-               return err;
-
-       /* initialize PCM subsystem: */
-       err = line6_init_pcm(line6, &toneport_pcm_properties);
-       if (err < 0)
-               return err;
-
-       /* register monitor control: */
-       err = snd_ctl_add(line6->card,
-                         snd_ctl_new1(&toneport_control_monitor,
-                                      line6->line6pcm));
-       if (err < 0)
-               return err;
-
-       /* register source select control: */
-       switch (le16_to_cpu(usbdev->descriptor.idProduct)) {
-       case LINE6_DEVID_TONEPORT_UX1:
-       case LINE6_DEVID_TONEPORT_UX2:
-       case LINE6_DEVID_PODSTUDIO_UX1:
-       case LINE6_DEVID_PODSTUDIO_UX2:
-               err =
-                   snd_ctl_add(line6->card,
-                               snd_ctl_new1(&toneport_control_source,
-                                            line6->line6pcm));
-               if (err < 0)
-                       return err;
-       }
-
-       /* register audio system: */
-       err = line6_register_audio(line6);
-       if (err < 0)
-               return err;
-
-       line6_read_serial_number(line6, &toneport->serial_number);
-       line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1);
-
-       if (toneport_has_led(idProduct)) {
-               CHECK_RETURN(device_create_file
-                            (&interface->dev, &dev_attr_led_red));
-               CHECK_RETURN(device_create_file
-                            (&interface->dev, &dev_attr_led_green));
-       }
-
-       toneport_setup(toneport);
-
-       init_timer(&toneport->timer);
-       toneport->timer.expires = jiffies + TONEPORT_PCM_DELAY * HZ;
-       toneport->timer.function = toneport_start_pcm;
-       toneport->timer.data = (unsigned long)toneport;
-       add_timer(&toneport->timer);
-
-       return 0;
-}
-
-/*
-        Init Toneport device (and clean up in case of failure).
-*/
-int line6_toneport_init(struct usb_interface *interface,
-                       struct usb_line6_toneport *toneport)
-{
-       int err = toneport_try_init(interface, toneport);
-
-       if (err < 0)
-               toneport_destruct(interface);
-
-       return err;
-}
-
-/*
-       Resume Toneport device after reset.
-*/
-void line6_toneport_reset_resume(struct usb_line6_toneport *toneport)
-{
-       toneport_setup(toneport);
-}
-
-/*
-       Toneport device disconnected.
-*/
-void line6_toneport_disconnect(struct usb_interface *interface)
-{
-       struct usb_line6_toneport *toneport;
-       u16 idProduct;
-
-       if (interface == NULL)
-               return;
-
-       toneport = usb_get_intfdata(interface);
-       del_timer_sync(&toneport->timer);
-       idProduct = le16_to_cpu(toneport->line6.usbdev->descriptor.idProduct);
-
-       if (toneport_has_led(idProduct)) {
-               device_remove_file(&interface->dev, &dev_attr_led_red);
-               device_remove_file(&interface->dev, &dev_attr_led_green);
-       }
-
-       if (toneport != NULL) {
-               struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm;
-
-               if (line6pcm != NULL) {
-                       line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
-                       line6_pcm_disconnect(line6pcm);
-               }
-       }
-
-       toneport_destruct(interface);
-}
diff --git a/drivers/staging/line6/toneport.h b/drivers/staging/line6/toneport.h
deleted file mode 100644 (file)
index 8576b72..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *     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, version 2.
- *
- */
-
-#ifndef TONEPORT_H
-#define TONEPORT_H
-
-#include <linux/usb.h>
-#include <sound/core.h>
-
-#include "driver.h"
-
-struct usb_line6_toneport {
-       /**
-               Generic Line6 USB data.
-       */
-       struct usb_line6 line6;
-
-       /**
-               Source selector.
-       */
-       int source;
-
-       /**
-               Serial number of device.
-       */
-       int serial_number;
-
-       /**
-               Firmware version (x 100).
-       */
-       int firmware_version;
-
-       /**
-                Timer for delayed PCM startup.
-       */
-       struct timer_list timer;
-};
-
-extern void line6_toneport_disconnect(struct usb_interface *interface);
-extern int line6_toneport_init(struct usb_interface *interface,
-                              struct usb_line6_toneport *toneport);
-extern void line6_toneport_reset_resume(struct usb_line6_toneport *toneport);
-
-#endif
diff --git a/drivers/staging/line6/usbdefs.h b/drivers/staging/line6/usbdefs.h
deleted file mode 100644 (file)
index 2d1cc47..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2005-2008 Markus Grabner (grabner@icg.tugraz.at)
- *
- *     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, version 2.
- *
- */
-
-#ifndef USBDEFS_H
-#define USBDEFS_H
-
-#define LINE6_VENDOR_ID  0x0e41
-
-#define USB_INTERVALS_PER_SECOND 1000
-
-/*
-       Device ids.
-*/
-#define LINE6_DEVID_BASSPODXT     0x4250
-#define LINE6_DEVID_BASSPODXTLIVE 0x4642
-#define LINE6_DEVID_BASSPODXTPRO  0x4252
-#define LINE6_DEVID_GUITARPORT    0x4750
-#define LINE6_DEVID_POCKETPOD     0x5051
-#define LINE6_DEVID_PODHD300      0x5057
-#define LINE6_DEVID_PODHD400      0x5058
-#define LINE6_DEVID_PODHD500      0x414D
-#define LINE6_DEVID_PODSTUDIO_GX  0x4153
-#define LINE6_DEVID_PODSTUDIO_UX1 0x4150
-#define LINE6_DEVID_PODSTUDIO_UX2 0x4151
-#define LINE6_DEVID_PODX3         0x414a
-#define LINE6_DEVID_PODX3LIVE     0x414b
-#define LINE6_DEVID_PODXT         0x5044
-#define LINE6_DEVID_PODXTLIVE     0x4650
-#define LINE6_DEVID_PODXTPRO      0x5050
-#define LINE6_DEVID_TONEPORT_GX   0x4147
-#define LINE6_DEVID_TONEPORT_UX1  0x4141
-#define LINE6_DEVID_TONEPORT_UX2  0x4142
-#define LINE6_DEVID_VARIAX        0x534d
-
-#define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_INDEX_ ## x
-
-enum {
-       LINE6_INDEX_BASSPODXT,
-       LINE6_INDEX_BASSPODXTLIVE,
-       LINE6_INDEX_BASSPODXTPRO,
-       LINE6_INDEX_GUITARPORT,
-       LINE6_INDEX_POCKETPOD,
-       LINE6_INDEX_PODHD300,
-       LINE6_INDEX_PODHD400,
-       LINE6_INDEX_PODHD500,
-       LINE6_INDEX_PODSTUDIO_GX,
-       LINE6_INDEX_PODSTUDIO_UX1,
-       LINE6_INDEX_PODSTUDIO_UX2,
-       LINE6_INDEX_PODX3,
-       LINE6_INDEX_PODX3LIVE,
-       LINE6_INDEX_PODXT,
-       LINE6_INDEX_PODXTLIVE,
-       LINE6_INDEX_PODXTPRO,
-       LINE6_INDEX_TONEPORT_GX,
-       LINE6_INDEX_TONEPORT_UX1,
-       LINE6_INDEX_TONEPORT_UX2,
-       LINE6_INDEX_VARIAX,
-
-       LINE6_BIT(BASSPODXT),
-       LINE6_BIT(BASSPODXTLIVE),
-       LINE6_BIT(BASSPODXTPRO),
-       LINE6_BIT(GUITARPORT),
-       LINE6_BIT(POCKETPOD),
-       LINE6_BIT(PODHD300),
-       LINE6_BIT(PODHD400),
-       LINE6_BIT(PODHD500),
-       LINE6_BIT(PODSTUDIO_GX),
-       LINE6_BIT(PODSTUDIO_UX1),
-       LINE6_BIT(PODSTUDIO_UX2),
-       LINE6_BIT(PODX3),
-       LINE6_BIT(PODX3LIVE),
-       LINE6_BIT(PODXT),
-       LINE6_BIT(PODXTLIVE),
-       LINE6_BIT(PODXTPRO),
-       LINE6_BIT(TONEPORT_GX),
-       LINE6_BIT(TONEPORT_UX1),
-       LINE6_BIT(TONEPORT_UX2),
-       LINE6_BIT(VARIAX),
-
-       LINE6_BITS_PRO = LINE6_BIT_BASSPODXTPRO | LINE6_BIT_PODXTPRO,
-       LINE6_BITS_LIVE = LINE6_BIT_BASSPODXTLIVE | LINE6_BIT_PODXTLIVE |
-                         LINE6_BIT_PODX3LIVE,
-       LINE6_BITS_PODXTALL = LINE6_BIT_PODXT | LINE6_BIT_PODXTLIVE |
-                             LINE6_BIT_PODXTPRO,
-       LINE6_BITS_PODX3ALL = LINE6_BIT_PODX3 | LINE6_BIT_PODX3LIVE,
-       LINE6_BITS_PODHDALL = LINE6_BIT_PODHD300 |
-                             LINE6_BIT_PODHD400 |
-                             LINE6_BIT_PODHD500,
-       LINE6_BITS_BASSPODXTALL = LINE6_BIT_BASSPODXT |
-                                 LINE6_BIT_BASSPODXTLIVE |
-                                 LINE6_BIT_BASSPODXTPRO
-};
-
-/* device supports settings parameter via USB */
-#define LINE6_BIT_CONTROL (1 << 0)
-/* device supports PCM input/output via USB */
-#define LINE6_BIT_PCM (1 << 1)
-/* device support hardware monitoring */
-#define LINE6_BIT_HWMON (1 << 2)
-
-#define LINE6_BIT_CTRL_PCM_HW  (LINE6_BIT_CONTROL |    \
-                                        LINE6_BIT_PCM |        \
-                                        LINE6_BIT_HWMON)
-
-#define LINE6_FALLBACK_INTERVAL 10
-#define LINE6_FALLBACK_MAXPACKETSIZE 16
-
-#endif
diff --git a/drivers/staging/line6/variax.c b/drivers/staging/line6/variax.c
deleted file mode 100644 (file)
index ae2be99..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *     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, version 2.
- *
- */
-
-#include <linux/slab.h>
-
-#include "audio.h"
-#include "driver.h"
-#include "variax.h"
-
-#define VARIAX_OFFSET_ACTIVATE 7
-
-/*
-       This message is sent by the device during initialization and identifies
-       the connected guitar version.
-*/
-static const char variax_init_version[] = {
-       0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
-       0x07, 0x00, 0x00, 0x00
-};
-
-/*
-       This message is the last one sent by the device during initialization.
-*/
-static const char variax_init_done[] = {
-       0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
-};
-
-static const char variax_activate[] = {
-       0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
-       0xf7
-};
-
-/* forward declarations: */
-static void variax_startup2(unsigned long data);
-static void variax_startup4(unsigned long data);
-static void variax_startup5(unsigned long data);
-
-static void variax_activate_async(struct usb_line6_variax *variax, int a)
-{
-       variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
-       line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
-                                    sizeof(variax_activate));
-}
-
-/*
-       Variax startup procedure.
-       This is a sequence of functions with special requirements (e.g., must
-       not run immediately after initialization, must not run in interrupt
-       context). After the last one has finished, the device is ready to use.
-*/
-
-static void variax_startup1(struct usb_line6_variax *variax)
-{
-       CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);
-
-       /* delay startup procedure: */
-       line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
-                         variax_startup2, (unsigned long)variax);
-}
-
-static void variax_startup2(unsigned long data)
-{
-       struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
-       struct usb_line6 *line6 = &variax->line6;
-
-       /* schedule another startup procedure until startup is complete: */
-       if (variax->startup_progress >= VARIAX_STARTUP_LAST)
-               return;
-
-       variax->startup_progress = VARIAX_STARTUP_VERSIONREQ;
-       line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
-                         variax_startup2, (unsigned long)variax);
-
-       /* request firmware version: */
-       line6_version_request_async(line6);
-}
-
-static void variax_startup3(struct usb_line6_variax *variax)
-{
-       CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);
-
-       /* delay startup procedure: */
-       line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
-                         variax_startup4, (unsigned long)variax);
-}
-
-static void variax_startup4(unsigned long data)
-{
-       struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
-
-       CHECK_STARTUP_PROGRESS(variax->startup_progress,
-                              VARIAX_STARTUP_ACTIVATE);
-
-       /* activate device: */
-       variax_activate_async(variax, 1);
-       line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
-                         variax_startup5, (unsigned long)variax);
-}
-
-static void variax_startup5(unsigned long data)
-{
-       struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
-
-       CHECK_STARTUP_PROGRESS(variax->startup_progress,
-                              VARIAX_STARTUP_WORKQUEUE);
-
-       /* schedule work for global work queue: */
-       schedule_work(&variax->startup_work);
-}
-
-static void variax_startup6(struct work_struct *work)
-{
-       struct usb_line6_variax *variax =
-           container_of(work, struct usb_line6_variax, startup_work);
-
-       CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
-
-       /* ALSA audio interface: */
-       line6_register_audio(&variax->line6);
-}
-
-/*
-       Process a completely received message.
-*/
-void line6_variax_process_message(struct usb_line6_variax *variax)
-{
-       const unsigned char *buf = variax->line6.buffer_message;
-
-       switch (buf[0]) {
-       case LINE6_RESET:
-               dev_info(variax->line6.ifcdev, "VARIAX reset\n");
-               break;
-
-       case LINE6_SYSEX_BEGIN:
-               if (memcmp(buf + 1, variax_init_version + 1,
-                          sizeof(variax_init_version) - 1) == 0) {
-                       variax_startup3(variax);
-               } else if (memcmp(buf + 1, variax_init_done + 1,
-                                 sizeof(variax_init_done) - 1) == 0) {
-                       /* notify of complete initialization: */
-                       variax_startup4((unsigned long)variax);
-               }
-               break;
-       }
-}
-
-/*
-       Variax destructor.
-*/
-static void variax_destruct(struct usb_interface *interface)
-{
-       struct usb_line6_variax *variax = usb_get_intfdata(interface);
-
-       if (variax == NULL)
-               return;
-       line6_cleanup_audio(&variax->line6);
-
-       del_timer(&variax->startup_timer1);
-       del_timer(&variax->startup_timer2);
-       cancel_work_sync(&variax->startup_work);
-
-       kfree(variax->buffer_activate);
-}
-
-/*
-        Try to init workbench device.
-*/
-static int variax_try_init(struct usb_interface *interface,
-                          struct usb_line6_variax *variax)
-{
-       int err;
-
-       init_timer(&variax->startup_timer1);
-       init_timer(&variax->startup_timer2);
-       INIT_WORK(&variax->startup_work, variax_startup6);
-
-       if ((interface == NULL) || (variax == NULL))
-               return -ENODEV;
-
-       /* initialize USB buffers: */
-       variax->buffer_activate = kmemdup(variax_activate,
-                                         sizeof(variax_activate), GFP_KERNEL);
-
-       if (variax->buffer_activate == NULL) {
-               dev_err(&interface->dev, "Out of memory\n");
-               return -ENOMEM;
-       }
-
-       /* initialize audio system: */
-       err = line6_init_audio(&variax->line6);
-       if (err < 0)
-               return err;
-
-       /* initialize MIDI subsystem: */
-       err = line6_init_midi(&variax->line6);
-       if (err < 0)
-               return err;
-
-       /* initiate startup procedure: */
-       variax_startup1(variax);
-       return 0;
-}
-
-/*
-        Init workbench device (and clean up in case of failure).
-*/
-int line6_variax_init(struct usb_interface *interface,
-                     struct usb_line6_variax *variax)
-{
-       int err = variax_try_init(interface, variax);
-
-       if (err < 0)
-               variax_destruct(interface);
-
-       return err;
-}
-
-/*
-       Workbench device disconnected.
-*/
-void line6_variax_disconnect(struct usb_interface *interface)
-{
-       if (interface == NULL)
-               return;
-
-       variax_destruct(interface);
-}
diff --git a/drivers/staging/line6/variax.h b/drivers/staging/line6/variax.h
deleted file mode 100644 (file)
index 24de796..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *     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, version 2.
- *
- */
-
-#ifndef VARIAX_H
-#define VARIAX_H
-
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-#include <linux/wait.h>
-#include <sound/core.h>
-
-#include "driver.h"
-
-#define VARIAX_STARTUP_DELAY1 1000
-#define VARIAX_STARTUP_DELAY3 100
-#define VARIAX_STARTUP_DELAY4 100
-
-/*
-       Stages of Variax startup procedure
-*/
-enum {
-       VARIAX_STARTUP_INIT = 1,
-       VARIAX_STARTUP_VERSIONREQ,
-       VARIAX_STARTUP_WAIT,
-       VARIAX_STARTUP_ACTIVATE,
-       VARIAX_STARTUP_WORKQUEUE,
-       VARIAX_STARTUP_SETUP,
-       VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1
-};
-
-struct usb_line6_variax {
-       /**
-               Generic Line6 USB data.
-       */
-       struct usb_line6 line6;
-
-       /**
-               Buffer for activation code.
-       */
-       unsigned char *buffer_activate;
-
-       /**
-               Handler for device initializaton.
-       */
-       struct work_struct startup_work;
-
-       /**
-               Timers for device initializaton.
-       */
-       struct timer_list startup_timer1;
-       struct timer_list startup_timer2;
-
-       /**
-               Current progress in startup procedure.
-       */
-       int startup_progress;
-};
-
-extern void line6_variax_disconnect(struct usb_interface *interface);
-extern int line6_variax_init(struct usb_interface *interface,
-                            struct usb_line6_variax *variax);
-extern void line6_variax_process_message(struct usb_line6_variax *variax);
-
-#endif
diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h
new file mode 100644 (file)
index 0000000..3e2f22e
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright Â© 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _I915_COMPONENT_H_
+#define _I915_COMPONENT_H_
+
+struct i915_audio_component {
+       struct device *dev;
+
+       const struct i915_audio_component_ops {
+               struct module *owner;
+               void (*get_power)(struct device *);
+               void (*put_power)(struct device *);
+               int (*get_cdclk_freq)(struct device *);
+       } *ops;
+};
+
+#endif /* _I915_COMPONENT_H_ */
diff --git a/include/drm/i915_powerwell.h b/include/drm/i915_powerwell.h
deleted file mode 100644 (file)
index baa6f11..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2013 Intel Inc.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- * USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- *
- **************************************************************************/
-
-#ifndef _I915_POWERWELL_H_
-#define _I915_POWERWELL_H_
-
-/* For use by hda_i915 driver */
-extern int i915_request_power_well(void);
-extern int i915_release_power_well(void);
-extern int i915_get_cdclk_freq(void);
-
-#endif                         /* _I915_POWERWELL_H_ */
diff --git a/include/dt-bindings/sound/samsung-i2s.h b/include/dt-bindings/sound/samsung-i2s.h
new file mode 100644 (file)
index 0000000..0c69818
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _DT_BINDINGS_SAMSUNG_I2S_H
+#define _DT_BINDINGS_SAMSUNG_I2S_H
+
+#define CLK_I2S_CDCLK          0
+#define CLK_I2S_RCLK_SRC       1
+#define CLK_I2S_RCLK_PSR       2
+
+#endif /* _DT_BINDINGS_SAMSUNG_I2S_H */
index abdf609c5918ab0d1baf94ee4158a3c9ada1622b..f2d3a6d0721016589c5e52b0066dbdb3df012366 100644 (file)
@@ -170,10 +170,9 @@ extern int snd_ad1816a_create(struct snd_card *card, unsigned long port,
                              int irq, int dma1, int dma2,
                              struct snd_ad1816a *chip);
 
-extern int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm);
+extern int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device);
 extern int snd_ad1816a_mixer(struct snd_ad1816a *chip);
-extern int snd_ad1816a_timer(struct snd_ad1816a *chip, int device,
-                            struct snd_timer **rtimer);
+extern int snd_ad1816a_timer(struct snd_ad1816a *chip, int device);
 #ifdef CONFIG_PM
 extern void snd_ad1816a_suspend(struct snd_ad1816a *chip);
 extern void snd_ad1816a_resume(struct snd_ad1816a *chip);
index 3a34f6edc2d1ff6bb9280b3bd9b1a203c5393c68..58c145620c3c0c853bce37d0f8bac8903e95e318 100644 (file)
@@ -287,6 +287,7 @@ struct ak4113 {
        ak4113_read_t *read;
        void *private_data;
        atomic_t wq_processing;
+       struct mutex reinit_mutex;
        spinlock_t lock;
        unsigned char regmap[AK4113_WRITABLE_REGS];
        struct snd_kcontrol *kctls[AK4113_CONTROLS];
@@ -317,5 +318,13 @@ int snd_ak4113_build(struct ak4113 *ak4113,
 int snd_ak4113_external_rate(struct ak4113 *ak4113);
 int snd_ak4113_check_rate_and_errors(struct ak4113 *ak4113, unsigned int flags);
 
+#ifdef CONFIG_PM
+void snd_ak4113_suspend(struct ak4113 *chip);
+void snd_ak4113_resume(struct ak4113 *chip);
+#else
+static inline void snd_ak4113_suspend(struct ak4113 *chip) {}
+static inline void snd_ak4113_resume(struct ak4113 *chip) {}
+#endif
+
 #endif /* __SOUND_AK4113_H */
 
index 069299a88915b6f27506c06471b08a7519590e88..b6feb7e225f2624570ace761e22ad3faf73f2c44 100644 (file)
@@ -169,6 +169,7 @@ struct ak4114 {
        ak4114_read_t * read;
        void * private_data;
        atomic_t wq_processing;
+       struct mutex reinit_mutex;
        spinlock_t lock;
        unsigned char regmap[6];
        unsigned char txcsb[5];
@@ -199,5 +200,13 @@ int snd_ak4114_build(struct ak4114 *ak4114,
 int snd_ak4114_external_rate(struct ak4114 *ak4114);
 int snd_ak4114_check_rate_and_errors(struct ak4114 *ak4114, unsigned int flags);
 
+#ifdef CONFIG_PM
+void snd_ak4114_suspend(struct ak4114 *chip);
+void snd_ak4114_resume(struct ak4114 *chip);
+#else
+static inline void snd_ak4114_suspend(struct ak4114 *chip) {}
+static inline void snd_ak4114_resume(struct ak4114 *chip) {}
+#endif
+
 #endif /* __SOUND_AK4114_H */
 
index 396e8f73670a59a2eea321867d36a6b3d0a22b2d..f48089d364c540a0527d6a874ca0e6516e5254b1 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <linux/types.h>
 #include <linux/sched.h>
+#include <sound/core.h>
 #include <sound/compress_offload.h>
 #include <sound/asound.h>
 #include <sound/pcm.h>
@@ -134,7 +135,7 @@ struct snd_compr_ops {
 /**
  * struct snd_compr: Compressed device
  * @name: DSP device name
- * @dev: Device pointer
+ * @dev: associated device instance
  * @ops: pointer to DSP callbacks
  * @private_data: pointer to DSP pvt data
  * @card: sound card pointer
@@ -144,7 +145,7 @@ struct snd_compr_ops {
  */
 struct snd_compr {
        const char *name;
-       struct device *dev;
+       struct device dev;
        struct snd_compr_ops *ops;
        void *private_data;
        struct snd_card *card;
index 042613938a1db4fdf1f5b0b3d5b373d90307887d..75f3054023f71182b6cf4ab89491c65180cb6292 100644 (file)
@@ -93,12 +93,17 @@ struct snd_kctl_event {
 
 struct pid;
 
+enum {
+       SND_CTL_SUBDEV_PCM,
+       SND_CTL_SUBDEV_RAWMIDI,
+       SND_CTL_SUBDEV_ITEMS,
+};
+
 struct snd_ctl_file {
        struct list_head list;          /* list of all control files */
        struct snd_card *card;
        struct pid *pid;
-       int prefer_pcm_subdevice;
-       int prefer_rawmidi_subdevice;
+       int preferred_subdevice[SND_CTL_SUBDEV_ITEMS];
        wait_queue_head_t change_sleep;
        spinlock_t read_lock;
        struct fasync_struct *fasync;
@@ -138,6 +143,8 @@ int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn);
 #define snd_ctl_unregister_ioctl_compat(fcn)
 #endif
 
+int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type);
+
 static inline unsigned int snd_ctl_get_ioffnum(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id)
 {
        return id->numid - kctl->id.numid;
index 1df3f2fe5350f8a886e65d17cb7caebced128b20..da5748289968074f2d89ae1c25e29f3a7298b789 100644 (file)
@@ -109,6 +109,7 @@ struct snd_card {
                                                                private data */
        struct list_head devices;       /* devices */
 
+       struct device ctl_dev;          /* control device */
        unsigned int last_numid;        /* last used numeric ID */
        struct rw_semaphore controls_rwsem;     /* controls list lock */
        rwlock_t ctl_files_rwlock;      /* ctl_files list lock */
@@ -131,6 +132,7 @@ struct snd_card {
        struct completion *release_completion;
        struct device *dev;             /* device assigned to this card */
        struct device card_dev;         /* cardX object for sysfs */
+       const struct attribute_group *dev_groups[4]; /* assigned sysfs attr */
        bool registered;                /* card_dev is registered? */
 
 #ifdef CONFIG_PM
@@ -206,43 +208,13 @@ extern struct class *sound_class;
 
 void snd_request_card(int card);
 
-int snd_register_device_for_dev(int type, struct snd_card *card,
-                               int dev,
-                               const struct file_operations *f_ops,
-                               void *private_data,
-                               const char *name,
-                               struct device *device);
+void snd_device_initialize(struct device *dev, struct snd_card *card);
 
-/**
- * snd_register_device - Register the ALSA device file for the card
- * @type: the device type, SNDRV_DEVICE_TYPE_XXX
- * @card: the card instance
- * @dev: the device index
- * @f_ops: the file operations
- * @private_data: user pointer for f_ops->open()
- * @name: the device file name
- *
- * Registers an ALSA device file for the given card.
- * The operators have to be set in reg parameter.
- *
- * This function uses the card's device pointer to link to the
- * correct &struct device.
- *
- * Return: Zero if successful, or a negative error code on failure.
- */
-static inline int snd_register_device(int type, struct snd_card *card, int dev,
-                                     const struct file_operations *f_ops,
-                                     void *private_data,
-                                     const char *name)
-{
-       return snd_register_device_for_dev(type, card, dev, f_ops,
-                                          private_data, name,
-                                          snd_card_get_device_link(card));
-}
-
-int snd_unregister_device(int type, struct snd_card *card, int dev);
+int snd_register_device(int type, struct snd_card *card, int dev,
+                       const struct file_operations *f_ops,
+                       void *private_data, struct device *device);
+int snd_unregister_device(struct device *dev);
 void *snd_lookup_minor_data(unsigned int minor, int type);
-struct device *snd_get_device(int type, struct snd_card *card, int dev);
 
 #ifdef CONFIG_SND_OSSEMUL
 int snd_register_oss_device(int type, struct snd_card *card, int dev,
@@ -291,6 +263,8 @@ void snd_card_set_id(struct snd_card *card, const char *id);
 int snd_card_register(struct snd_card *card);
 int snd_card_info_init(void);
 int snd_card_info_done(void);
+int snd_card_add_dev_attr(struct snd_card *card,
+                         const struct attribute_group *group);
 int snd_component_add(struct snd_card *card, const char *component);
 int snd_card_file_add(struct snd_card *card, struct file *file);
 int snd_card_file_remove(struct snd_card *card, struct file *file);
index c46908c1bb3f006268222f5c57af257aa3e76ef1..0de95ccb92cf58ed0536cca855d1255b0276b4fb 100644 (file)
@@ -33,8 +33,8 @@
 #include <linux/interrupt.h>
 #include <linux/mutex.h>
 #include <linux/firmware.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <uapi/sound/emu10k1.h>
 
 /* ------------------- DEFINES -------------------- */
@@ -1809,17 +1809,17 @@ int snd_emu10k1_create(struct snd_card *card,
                       uint subsystem,
                       struct snd_emu10k1 ** remu);
 
-int snd_emu10k1_pcm(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
-int snd_emu10k1_pcm_mic(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
-int snd_emu10k1_pcm_efx(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
-int snd_p16v_pcm(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
+int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device);
+int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device);
+int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device);
+int snd_p16v_pcm(struct snd_emu10k1 *emu, int device);
 int snd_p16v_free(struct snd_emu10k1 * emu);
 int snd_p16v_mixer(struct snd_emu10k1 * emu);
-int snd_emu10k1_pcm_multi(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
-int snd_emu10k1_fx8010_pcm(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm);
+int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device);
+int snd_emu10k1_fx8010_pcm(struct snd_emu10k1 *emu, int device);
 int snd_emu10k1_mixer(struct snd_emu10k1 * emu, int pcm_device, int multi_device);
 int snd_emu10k1_timer(struct snd_emu10k1 * emu, int device);
-int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct snd_hwdep ** rhwdep);
+int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device);
 
 irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id);
 
index 1d636a2d8896e30e9c1f801bbe6ee1c435cbc703..b34f23a5bb74a35f8be07b462af23b18eb80544a 100644 (file)
@@ -115,8 +115,7 @@ int snd_es1688_create(struct snd_card *card,
                      int mpu_irq,
                      int dma8,
                      unsigned short hardware);
-int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device,
-                  struct snd_pcm **rpcm);
+int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device);
 int snd_es1688_mixer(struct snd_card *card, struct snd_es1688 *chip);
 int snd_es1688_reset(struct snd_es1688 *chip);
 
index 42905d811da79db488a2b376668698a861016b5e..07c116fe78c85c82de959a2012b85159ed4891d5 100644 (file)
@@ -27,7 +27,7 @@
 #include <sound/timer.h>
 #include <sound/seq_midi_emul.h>
 #include <sound/seq_device.h>
-#include <asm/io.h>
+#include <linux/io.h>
 
 /* IO ports */
 
@@ -591,7 +591,7 @@ int snd_gf1_new_mixer(struct snd_gus_card * gus);
 
 /* gus_pcm.c */
 
-int snd_gf1_pcm_new(struct snd_gus_card * gus, int pcm_dev, int control_index, struct snd_pcm ** rpcm);
+int snd_gf1_pcm_new(struct snd_gus_card *gus, int pcm_dev, int control_index);
 
 #ifdef CONFIG_SND_DEBUG
 extern void snd_gf1_print_voice_registers(struct snd_gus_card * gus);
@@ -620,7 +620,7 @@ void snd_gus_irq_profile_init(struct snd_gus_card *gus);
 
 /* gus_uart.c */
 
-int snd_gf1_rawmidi_new(struct snd_gus_card * gus, int device, struct snd_rawmidi **rrawmidi);
+int snd_gf1_rawmidi_new(struct snd_gus_card *gus, int device);
 
 /* gus_dram.c */
 int snd_gus_dram_write(struct snd_gus_card *gus, char __user *ptr,
index ae04a3ec9c774e6ba41508e595535b92216dce8e..ab9fcb2f97f0abfbb1307138eec19e7f0dbe6a39 100644 (file)
@@ -68,8 +68,7 @@ struct snd_hwdep {
        wait_queue_head_t open_wait;
        void *private_data;
        void (*private_free) (struct snd_hwdep *hwdep);
-       struct device *dev;
-       const struct attribute_group **groups;
+       struct device dev;
 
        struct mutex open_mutex;
        int used;                       /* reference counter */
index b429b73e875ea2725f87d10d21c318adab83e4d5..c0ddb7e69c2863a385b34212b29255df993131e5 100644 (file)
@@ -94,9 +94,6 @@ struct snd_pcm_ops {
 #define SNDRV_PCM_DEVICES      8
 #endif
 
-#define SNDRV_PCM_IOCTL1_FALSE         ((void *)0)
-#define SNDRV_PCM_IOCTL1_TRUE          ((void *)1)
-
 #define SNDRV_PCM_IOCTL1_RESET         0
 #define SNDRV_PCM_IOCTL1_INFO          1
 #define SNDRV_PCM_IOCTL1_CHANNEL_INFO  2
@@ -109,6 +106,7 @@ struct snd_pcm_ops {
 #define SNDRV_PCM_TRIGGER_PAUSE_RELEASE        4
 #define SNDRV_PCM_TRIGGER_SUSPEND      5
 #define SNDRV_PCM_TRIGGER_RESUME       6
+#define SNDRV_PCM_TRIGGER_DRAIN                7
 
 #define SNDRV_PCM_POS_XRUN             ((snd_pcm_uframes_t)-1)
 
@@ -275,12 +273,19 @@ struct snd_pcm_hw_constraint_list {
        unsigned int mask;
 };
 
+struct snd_pcm_hw_constraint_ranges {
+       unsigned int count;
+       const struct snd_interval *ranges;
+       unsigned int mask;
+};
+
 struct snd_pcm_hwptr_log;
 
 struct snd_pcm_runtime {
        /* -- Status -- */
        struct snd_pcm_substream *trigger_master;
        struct timespec trigger_tstamp; /* trigger timestamp */
+       bool trigger_tstamp_latched;     /* trigger timestamp latched in low-level driver/hardware */
        int overrange;
        snd_pcm_uframes_t avail_max;
        snd_pcm_uframes_t hw_ptr_base;  /* Position at buffer restart */
@@ -449,6 +454,7 @@ struct snd_pcm_str {
 #endif
 #endif
        struct snd_kcontrol *chmap_kctl; /* channel-mapping controls */
+       struct device dev;
 };
 
 struct snd_pcm {
@@ -465,7 +471,6 @@ struct snd_pcm {
        wait_queue_head_t open_wait;
        void *private_data;
        void (*private_free) (struct snd_pcm *pcm);
-       struct device *dev; /* actual hw device this belongs to */
        bool internal; /* pcm is for internal use only */
        bool nonatomic; /* whole PCM operations are in non-atomic context */
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
@@ -520,7 +525,6 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream);
 int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, struct file *file,
                             struct snd_pcm_substream **rsubstream);
 void snd_pcm_detach_substream(struct snd_pcm_substream *substream);
-void snd_pcm_vma_notify_data(void *client, void *data);
 int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area);
 
 
@@ -910,6 +914,8 @@ void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
                          const struct snd_interval *b, struct snd_interval *c);
 int snd_interval_list(struct snd_interval *i, unsigned int count,
                      const unsigned int *list, unsigned int mask);
+int snd_interval_ranges(struct snd_interval *i, unsigned int count,
+                       const struct snd_interval *list, unsigned int mask);
 int snd_interval_ratnum(struct snd_interval *i,
                        unsigned int rats_count, struct snd_ratnum *rats,
                        unsigned int *nump, unsigned int *denp);
@@ -934,6 +940,10 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime,
                               unsigned int cond,
                               snd_pcm_hw_param_t var,
                               const struct snd_pcm_hw_constraint_list *l);
+int snd_pcm_hw_constraint_ranges(struct snd_pcm_runtime *runtime,
+                                unsigned int cond,
+                                snd_pcm_hw_param_t var,
+                                const struct snd_pcm_hw_constraint_ranges *r);
 int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, 
                                  unsigned int cond,
                                  snd_pcm_hw_param_t var,
@@ -986,21 +996,15 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format);               /* in bits */
 ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples);
 const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format);
 int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int frames);
-snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsigned, int big_endian);
 
 void snd_pcm_set_ops(struct snd_pcm * pcm, int direction,
                     const struct snd_pcm_ops *ops);
 void snd_pcm_set_sync(struct snd_pcm_substream *substream);
-int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream);
 int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
                      unsigned int cmd, void *arg);                      
 int snd_pcm_update_state(struct snd_pcm_substream *substream,
                         struct snd_pcm_runtime *runtime);
 int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream);
-int snd_pcm_playback_xrun_check(struct snd_pcm_substream *substream);
-int snd_pcm_capture_xrun_check(struct snd_pcm_substream *substream);
-int snd_pcm_playback_xrun_asap(struct snd_pcm_substream *substream);
-int snd_pcm_capture_xrun_asap(struct snd_pcm_substream *substream);
 void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_uframes_t new_hw_ptr);
 void snd_pcm_period_elapsed(struct snd_pcm_substream *substream);
 snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream,
index 6b1c78f05fab49f3617dcef673d98c70a8fd256b..3c45f3924ba7e779a4d32a357665d0359abcbaaf 100644 (file)
@@ -38,31 +38,6 @@ int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
 #define MASK_OFS(i)    ((i) >> 5)
 #define MASK_BIT(i)    (1U << ((i) & 31))
 
-static inline unsigned int ld2(u_int32_t v)
-{
-        unsigned r = 0;
-
-        if (v >= 0x10000) {
-                v >>= 16;
-                r += 16;
-        }
-        if (v >= 0x100) {
-                v >>= 8;
-                r += 8;
-        }
-        if (v >= 0x10) {
-                v >>= 4;
-                r += 4;
-        }
-        if (v >= 4) {
-                v >>= 2;
-                r += 2;
-        }
-        if (v >= 2)
-                r++;
-        return r;
-}
-
 static inline size_t snd_mask_sizeof(void)
 {
        return sizeof(struct snd_mask);
@@ -92,7 +67,7 @@ static inline unsigned int snd_mask_min(const struct snd_mask *mask)
        int i;
        for (i = 0; i < SNDRV_MASK_SIZE; i++) {
                if (mask->bits[i])
-                       return ffs(mask->bits[i]) - 1 + (i << 5);
+                       return __ffs(mask->bits[i]) + (i << 5);
        }
        return 0;
 }
@@ -102,7 +77,7 @@ static inline unsigned int snd_mask_max(const struct snd_mask *mask)
        int i;
        for (i = SNDRV_MASK_SIZE - 1; i >= 0; i--) {
                if (mask->bits[i])
-                       return ld2(mask->bits[i]) + (i << 5);
+                       return __fls(mask->bits[i]) + (i << 5);
        }
        return 0;
 }
@@ -325,43 +300,68 @@ static inline int snd_interval_eq(const struct snd_interval *i1, const struct sn
                i1->max == i2->max && i1->openmax == i2->openmax;
 }
 
-static inline unsigned int add(unsigned int a, unsigned int b)
+/**
+ * params_access - get the access type from the hw params
+ * @p: hw params
+ */
+static inline snd_pcm_access_t params_access(const struct snd_pcm_hw_params *p)
 {
-       if (a >= UINT_MAX - b)
-               return UINT_MAX;
-       return a + b;
+       return (__force snd_pcm_access_t)snd_mask_min(hw_param_mask_c(p,
+               SNDRV_PCM_HW_PARAM_ACCESS));
 }
 
-static inline unsigned int sub(unsigned int a, unsigned int b)
+/**
+ * params_format - get the sample format from the hw params
+ * @p: hw params
+ */
+static inline snd_pcm_format_t params_format(const struct snd_pcm_hw_params *p)
 {
-       if (a > b)
-               return a - b;
-       return 0;
+       return (__force snd_pcm_format_t)snd_mask_min(hw_param_mask_c(p,
+               SNDRV_PCM_HW_PARAM_FORMAT));
 }
 
-#define params_access(p) ((__force snd_pcm_access_t)\
-               snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_ACCESS)))
-#define params_format(p) ((__force snd_pcm_format_t)\
-               snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_FORMAT)))
-#define params_subformat(p) \
-       snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_SUBFORMAT))
+/**
+ * params_subformat - get the sample subformat from the hw params
+ * @p: hw params
+ */
+static inline snd_pcm_subformat_t
+params_subformat(const struct snd_pcm_hw_params *p)
+{
+       return (__force snd_pcm_subformat_t)snd_mask_min(hw_param_mask_c(p,
+               SNDRV_PCM_HW_PARAM_SUBFORMAT));
+}
 
+/**
+ * params_period_bytes - get the period size (in bytes) from the hw params
+ * @p: hw params
+ */
 static inline unsigned int
 params_period_bytes(const struct snd_pcm_hw_params *p)
 {
-       return (params_period_size(p) *
-               snd_pcm_format_physical_width(params_format(p)) *
-               params_channels(p)) / 8;
+       return hw_param_interval_c(p, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)->min;
 }
 
-static inline int
-params_width(const struct snd_pcm_hw_params *p)
+/**
+ * params_width - get the number of bits of the sample format from the hw params
+ * @p: hw params
+ *
+ * This function returns the number of bits per sample that the selected sample
+ * format of the hw params has.
+ */
+static inline int params_width(const struct snd_pcm_hw_params *p)
 {
        return snd_pcm_format_width(params_format(p));
 }
 
-static inline int
-params_physical_width(const struct snd_pcm_hw_params *p)
+/*
+ * params_physical_width - get the storage size of the sample format from the hw params
+ * @p: hw params
+ *
+ * This functions returns the number of bits per sample that the selected sample
+ * format of the hw params takes up in memory. This will be equal or larger than
+ * params_width().
+ */
+static inline int params_physical_width(const struct snd_pcm_hw_params *p)
 {
        return snd_pcm_format_physical_width(params_format(p));
 }
index 311dafe6cc4b508ecc372ba45d8f647d55b44f9c..f6cbef78db620f2ff85c02126f9a9518553cf2c1 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/wait.h>
 #include <linux/mutex.h>
 #include <linux/workqueue.h>
+#include <linux/device.h>
 
 #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
 #include <sound/seq_device.h>
@@ -139,7 +140,8 @@ struct snd_rawmidi {
        struct mutex open_mutex;
        wait_queue_head_t open_wait;
 
-       struct snd_info_entry *dev;
+       struct device dev;
+
        struct snd_info_entry *proc_entry;
 
 #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
index 83284cae464c492bf77cf127958f46469ee4b9c0..4cecd0c175f607c7f3cae2a2fb03660f81131799 100644 (file)
@@ -55,6 +55,7 @@ struct rsnd_ssi_platform_info {
 struct rsnd_src_platform_info {
        u32 convert_rate; /* sampling rate convert */
        int dma_id; /* for Gen2 SCU */
+       int irq;
 };
 
 /*
index d9eb7d861cd0da77722e178b3c3f94ee88ba9b99..a6207043ac3c7f80f1def8b4fb2025f0dd1a05ca 100644 (file)
@@ -37,6 +37,9 @@ struct rt5677_platform_data {
                OFF, GPIO4, GPIO5 and GPIO6 respectively */
        unsigned int jd2_gpio;
        unsigned int jd3_gpio;
+
+       /* Set MICBIAS1 VDD 1v8 or 3v3 */
+       bool micbias1_vdd_3v3;
 };
 
 #endif
index ba39603296462d7dca81253a40ab6a1d4f6a8bd7..bacefaee411a55b28a0110f1d7a8ab1779ce1da9 100644 (file)
@@ -25,7 +25,7 @@
 #include <sound/pcm.h>
 #include <sound/rawmidi.h>
 #include <linux/interrupt.h>
-#include <asm/io.h>
+#include <linux/io.h>
 
 enum sb_hw_type {
        SB_HW_AUTO,
@@ -308,7 +308,7 @@ void snd_sbmixer_resume(struct snd_sb *chip);
 #endif
 
 /* sb8_init.c */
-int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm);
+int snd_sb8dsp_pcm(struct snd_sb *chip, int device);
 /* sb8.c */
 irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip);
 int snd_sb8_playback_open(struct snd_pcm_substream *substream);
@@ -317,10 +317,10 @@ int snd_sb8_playback_close(struct snd_pcm_substream *substream);
 int snd_sb8_capture_close(struct snd_pcm_substream *substream);
 /* midi8.c */
 irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb *chip);
-int snd_sb8dsp_midi(struct snd_sb *chip, int device, struct snd_rawmidi ** rrawmidi);
+int snd_sb8dsp_midi(struct snd_sb *chip, int device);
 
 /* sb16_init.c */
-int snd_sb16dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm);
+int snd_sb16dsp_pcm(struct snd_sb *chip, int device);
 const struct snd_pcm_ops *snd_sb16dsp_get_pcm_ops(int direction);
 int snd_sb16dsp_configure(struct snd_sb *chip);
 /* sb16.c */
index eea5400fe373862e55382f0ac0efadbd50d0cc08..18a2ac58b88f996d5668fef268f3f9c73256d1ce 100644 (file)
 typedef struct snd_seq_real_time snd_seq_real_time_t;
 typedef union snd_seq_timestamp snd_seq_timestamp_t;
 
-/* maximum number of events dequeued per schedule interval */
-#define SNDRV_SEQ_MAX_DEQUEUE          50
-
 /* maximum number of queues */
-#define SNDRV_SEQ_MAX_QUEUES           8
+#define SNDRV_SEQ_MAX_QUEUES           32
 
 /* max number of concurrent clients */
 #define SNDRV_SEQ_MAX_CLIENTS          192
@@ -42,9 +39,6 @@ typedef union snd_seq_timestamp snd_seq_timestamp_t;
 /* max number of events in memory pool */
 #define SNDRV_SEQ_MAX_EVENTS           2000
 
-/* default number of events in memory chunk */
-#define SNDRV_SEQ_DEFAULT_CHUNK_EVENTS 64
-
 /* default number of events in memory pool */
 #define SNDRV_SEQ_DEFAULT_EVENTS       500
 
@@ -70,7 +64,6 @@ struct snd_seq_port_callback {
        int (*unuse)(void *private_data, struct snd_seq_port_subscribe *info);
        int (*event_input)(struct snd_seq_event *ev, int direct, void *private_data, int atomic, int hop);
        void (*private_free)(void *private_data);
-       unsigned int callback_all;      /* call subscribe callbacks at each connection/disconnection */
        /*...*/
 };
 
index 9b0ac77177b6e3aa13156822a2c23f61635e56bd..1255ddb1d3e2c22d05b188a82bc589f62c307b9b 100644 (file)
@@ -20,6 +20,7 @@ struct asoc_simple_dai {
        unsigned int sysclk;
        int slots;
        int slot_width;
+       struct clk *clk;
 };
 
 struct asoc_simple_card_info {
index 89823cfe6f043147b3798b78ac4034831d25c790..8d7416e46861744d990f4c0dbb2d1f72fdd9407b 100644 (file)
@@ -405,7 +405,7 @@ int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
                struct snd_soc_dapm_update *update);
 
 /* dapm sys fs - used by the core */
-int snd_soc_dapm_sys_add(struct device *dev);
+extern struct attribute *soc_dapm_dev_attrs[];
 void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
                                struct dentry *parent);
 
@@ -431,7 +431,6 @@ int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
                                           const char *pin);
 int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
                                const char *pin);
-void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card);
 unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol);
 
 /* Mostly internal - should not normally be used */
@@ -526,7 +525,6 @@ struct snd_soc_dapm_widget {
        enum snd_soc_dapm_type id;
        const char *name;               /* widget name */
        const char *sname;      /* stream name */
-       struct snd_soc_codec *codec;
        struct list_head list;
        struct snd_soc_dapm_context *dapm;
 
index ac8b333acb4dd721596db8ddf9bf7fcbc7ab6c1d..0d1ade19562857c7b65157636ac37b2f0222e202 100644 (file)
@@ -429,6 +429,9 @@ bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd);
 void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream);
 void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream);
 
+int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
+       unsigned int dai_fmt);
+
 /* 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);
index 8d93b0357a14b39a23fa4292a85510b7dc21635a..a894f7d17b1a325e882723ce696c8a921f9508ec 100644 (file)
 #define STA32X_THERMAL_RECOVERY_ENABLE         2
 
 struct sta32x_platform_data {
-       int output_conf;
-       int ch1_output_mapping;
-       int ch2_output_mapping;
-       int ch3_output_mapping;
-       int thermal_conf;
+       u8 output_conf;
+       u8 ch1_output_mapping;
+       u8 ch2_output_mapping;
+       u8 ch3_output_mapping;
        int needs_esd_watchdog;
+       u8 drop_compensation_ns;
+       unsigned int thermal_warning_recovery:1;
+       unsigned int thermal_warning_adjustment:1;
+       unsigned int fault_detect_recovery:1;
+       unsigned int max_power_use_mpcc:1;
+       unsigned int max_power_correction:1;
+       unsigned int am_reduction_mode:1;
+       unsigned int odd_pwm_speed_mode:1;
+       unsigned int invalid_input_detect_mute:1;
 };
 
 #endif /* __LINUX_SND__STA32X_H */
index 0c7f034f1e86cc1cd2966b9ac84ee142ad0faa28..1823e3a964e28776a798d3200c3e1f0fceb12f43 100644 (file)
@@ -154,8 +154,8 @@ int snd_wss_create(struct snd_card *card,
                      unsigned short hardware,
                      unsigned short hwshare,
                      struct snd_wss **rchip);
-int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm);
-int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer);
+int snd_wss_pcm(struct snd_wss *chip, int device);
+int snd_wss_timer(struct snd_wss *chip, int device);
 int snd_wss_mixer(struct snd_wss *chip);
 
 const struct snd_pcm_ops *snd_wss_get_pcm_ops(int direction);
@@ -167,7 +167,7 @@ int snd_cs4236_create(struct snd_card *card,
                      unsigned short hardware,
                      unsigned short hwshare,
                      struct snd_wss **rchip);
-int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm);
+int snd_cs4236_pcm(struct snd_wss *chip, int device);
 int snd_cs4236_mixer(struct snd_wss *chip);
 
 /*
index 1f23cd635957846dd6fbb683c1a525cc51b06179..0e88e7a0f0ebf227894f05ef6ed2225931b9d6d6 100644 (file)
@@ -268,6 +268,7 @@ typedef int __bitwise snd_pcm_subformat_t;
 #define SNDRV_PCM_INFO_SYNC_START      0x00400000      /* pcm support some kind of sync go */
 #define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP        0x00800000      /* period wakeup can be disabled */
 #define SNDRV_PCM_INFO_HAS_WALL_CLOCK   0x01000000      /* has audio wall clock for audio/system time sync */
+#define SNDRV_PCM_INFO_DRAIN_TRIGGER   0x40000000              /* internal kernel flag - trigger in drain */
 #define SNDRV_PCM_INFO_FIFO_IN_FRAMES  0x80000000      /* internal kernel flag - FIFO size is in frames */
 
 typedef int __bitwise snd_pcm_state_t;
diff --git a/include/uapi/sound/usb_stream.h b/include/uapi/sound/usb_stream.h
new file mode 100644 (file)
index 0000000..cfe8fba
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2007, 2008 Karsten Wiese <fzu@wemgehoertderstaat.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _UAPI__SOUND_USB_STREAM_H
+#define _UAPI__SOUND_USB_STREAM_H
+
+#define USB_STREAM_INTERFACE_VERSION 2
+
+#define SNDRV_USB_STREAM_IOCTL_SET_PARAMS \
+       _IOW('H', 0x90, struct usb_stream_config)
+
+struct usb_stream_packet {
+       unsigned offset;
+       unsigned length;
+};
+
+
+struct usb_stream_config {
+       unsigned version;
+       unsigned sample_rate;
+       unsigned period_frames;
+       unsigned frame_size;
+};
+
+struct usb_stream {
+       struct usb_stream_config cfg;
+       unsigned read_size;
+       unsigned write_size;
+
+       int period_size;
+
+       unsigned state;
+
+       int idle_insize;
+       int idle_outsize;
+       int sync_packet;
+       unsigned insize_done;
+       unsigned periods_done;
+       unsigned periods_polled;
+
+       struct usb_stream_packet outpacket[2];
+       unsigned                 inpackets;
+       unsigned                 inpacket_head;
+       unsigned                 inpacket_split;
+       unsigned                 inpacket_split_at;
+       unsigned                 next_inpacket_split;
+       unsigned                 next_inpacket_split_at;
+       struct usb_stream_packet inpacket[0];
+};
+
+enum usb_stream_state {
+       usb_stream_invalid,
+       usb_stream_stopped,
+       usb_stream_sync0,
+       usb_stream_sync1,
+       usb_stream_ready,
+       usb_stream_running,
+       usb_stream_xrun,
+};
+
+#endif /* _UAPI__SOUND_USB_STREAM_H */
index 4dc9b49c02cf78a983e9a38ec02ee24adac399bd..f4495decc6996d1c95d8b727daf33a053ae8398b 100644 (file)
@@ -9,8 +9,8 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/macio.h>
 #include <asm/pmac_feature.h>
index 4e2b4fbf2496817f31a17a1302346225628e86ee..b9737fae656a89ba6121eddf4804312f2843dc7f 100644 (file)
@@ -74,10 +74,9 @@ static void i2sbus_release_dev(struct device *dev)
        int i;
 
        i2sdev = container_of(dev, struct i2sbus_dev, sound.ofdev.dev);
-
-       if (i2sdev->intfregs) iounmap(i2sdev->intfregs);
-       if (i2sdev->out.dbdma) iounmap(i2sdev->out.dbdma);
-       if (i2sdev->in.dbdma) iounmap(i2sdev->in.dbdma);
+       iounmap(i2sdev->intfregs);
+       iounmap(i2sdev->out.dbdma);
+       iounmap(i2sdev->in.dbdma);
        for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++)
                release_and_free_resource(i2sdev->allocated_resource[i]);
        free_dbdma_descriptor_ring(i2sdev, &i2sdev->out.dbdma_ring);
@@ -318,9 +317,9 @@ static int i2sbus_add_dev(struct macio_dev *macio,
                        free_irq(dev->interrupts[i], dev);
        free_dbdma_descriptor_ring(dev, &dev->out.dbdma_ring);
        free_dbdma_descriptor_ring(dev, &dev->in.dbdma_ring);
-       if (dev->intfregs) iounmap(dev->intfregs);
-       if (dev->out.dbdma) iounmap(dev->out.dbdma);
-       if (dev->in.dbdma) iounmap(dev->in.dbdma);
+       iounmap(dev->intfregs);
+       iounmap(dev->out.dbdma);
+       iounmap(dev->in.dbdma);
        for (i=0;i<3;i++)
                release_and_free_resource(dev->allocated_resource[i]);
        mutex_destroy(&dev->lock);
@@ -381,10 +380,8 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state)
 
        list_for_each_entry(i2sdev, &control->list, item) {
                /* Notify Alsa */
-               if (i2sdev->sound.pcm) {
-                       /* Suspend PCM streams */
-                       snd_pcm_suspend_all(i2sdev->sound.pcm);
-               }
+               /* Suspend PCM streams */
+               snd_pcm_suspend_all(i2sdev->sound.pcm);
 
                /* Notify codecs */
                list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
index 7b74a4ba75f8bce451309a9f704ea16e7d42816a..053b09c79053e548c1c7c1d8deef5064e7780d29 100644 (file)
@@ -6,7 +6,7 @@
  * GPL v2, can be found in COPYING.
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -968,7 +968,6 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
                        printk(KERN_DEBUG "i2sbus: failed to create pcm\n");
                        goto out_put_ci_module;
                }
-               dev->pcm->dev = &dev->ofdev.dev;
        }
 
        /* ALSA yet again sucks.
@@ -988,6 +987,8 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
                        goto out_put_ci_module;
                snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK,
                                &i2sbus_playback_ops);
+               dev->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].dev.parent =
+                       &dev->ofdev.dev;
                i2sdev->out.created = 1;
        }
 
@@ -1003,6 +1004,8 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
                        goto out_put_ci_module;
                snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE,
                                &i2sbus_record_ops);
+               dev->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].dev.parent =
+                       &dev->ofdev.dev;
                i2sdev->in.created = 1;
        }
 
index 0e83a73efb16e18dc4a5dc5982e86976dc9e2f2c..4140b1b950544bce0fc0360402d67f7fc5a031d4 100644 (file)
@@ -889,8 +889,8 @@ static int aaci_probe_ac97(struct aaci *aaci)
 static void aaci_free_card(struct snd_card *card)
 {
        struct aaci *aaci = card->private_data;
-       if (aaci->base)
-               iounmap(aaci->base);
+
+       iounmap(aaci->base);
 }
 
 static struct aaci *aaci_init_card(struct amba_device *dev)
index 4f6b14d704f35f734e58d26961a5078c0e1a9b18..cf4cedf2b420f12de4d46cf702fabeab2c136b02 100644 (file)
@@ -22,6 +22,9 @@
 #include <linux/gpio.h>
 #include <linux/types.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
 
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <linux/platform_data/dma-dw.h>
 #include <linux/dma/dw.h>
 
+#ifdef CONFIG_AVR32
 #include <mach/cpu.h>
-
-#ifdef CONFIG_ARCH_AT91
-#include <mach/hardware.h>
+#else
+#define cpu_is_at32ap7000() 0
 #endif
 
 #include "ac97c.h"
@@ -902,6 +905,40 @@ static void atmel_ac97c_reset(struct atmel_ac97c *chip)
        }
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id atmel_ac97c_dt_ids[] = {
+       { .compatible = "atmel,at91sam9263-ac97c", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, atmel_ac97c_dt_ids);
+
+static struct ac97c_platform_data *atmel_ac97c_probe_dt(struct device *dev)
+{
+       struct ac97c_platform_data *pdata;
+       struct device_node *node = dev->of_node;
+       const struct of_device_id *match;
+
+       if (!node) {
+               dev_err(dev, "Device does not have associated DT data\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return ERR_PTR(-ENOMEM);
+
+       pdata->reset_pin = of_get_named_gpio(dev->of_node, "ac97-gpios", 2);
+
+       return pdata;
+}
+#else
+static struct ac97c_platform_data *atmel_ac97c_probe_dt(struct device *dev)
+{
+       dev_err(dev, "no platform data defined\n");
+       return ERR_PTR(-ENXIO);
+}
+#endif
+
 static int atmel_ac97c_probe(struct platform_device *pdev)
 {
        struct snd_card                 *card;
@@ -922,10 +959,11 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        if (!pdata) {
-               dev_dbg(&pdev->dev, "no platform data\n");
-               return -ENXIO;
+               pdata = atmel_ac97c_probe_dt(&pdev->dev);
+               if (IS_ERR(pdata))
+                       return PTR_ERR(pdata);
        }
 
        irq = platform_get_irq(pdev, 0);
@@ -1204,6 +1242,7 @@ static struct platform_driver atmel_ac97c_driver = {
        .driver         = {
                .name   = "atmel_ac97c",
                .pm     = ATMEL_AC97C_PM_OPS,
+               .of_match_table = of_match_ptr(atmel_ac97c_dt_ids),
        },
 };
 module_platform_driver(atmel_ac97c_driver);
index 89028fab64fdd27bd75698e651fdc3b26b424941..b123c42e7dc8995be7fc948952500f74508f5034 100644 (file)
@@ -868,12 +868,12 @@ static int snd_compress_dev_register(struct snd_device *device)
                return -EBADFD;
        compr = device->device_data;
 
-       sprintf(str, "comprC%iD%i", compr->card->number, compr->device);
        pr_debug("reg %s for device %s, direction %d\n", str, compr->name,
                        compr->direction);
        /* register compressed device */
-       ret = snd_register_device(SNDRV_DEVICE_TYPE_COMPRESS, compr->card,
-                       compr->device, &snd_compr_file_ops, compr, str);
+       ret = snd_register_device(SNDRV_DEVICE_TYPE_COMPRESS,
+                                 compr->card, compr->device,
+                                 &snd_compr_file_ops, compr, &compr->dev);
        if (ret < 0) {
                pr_err("snd_register_device failed\n %d", ret);
                return ret;
@@ -887,8 +887,16 @@ static int snd_compress_dev_disconnect(struct snd_device *device)
        struct snd_compr *compr;
 
        compr = device->device_data;
-       snd_unregister_device(SNDRV_DEVICE_TYPE_COMPRESS, compr->card,
-               compr->device);
+       snd_unregister_device(&compr->dev);
+       return 0;
+}
+
+static int snd_compress_dev_free(struct snd_device *device)
+{
+       struct snd_compr *compr;
+
+       compr = device->device_data;
+       put_device(&compr->dev);
        return 0;
 }
 
@@ -903,7 +911,7 @@ int snd_compress_new(struct snd_card *card, int device,
                        int dirn, struct snd_compr *compr)
 {
        static struct snd_device_ops ops = {
-               .dev_free = NULL,
+               .dev_free = snd_compress_dev_free,
                .dev_register = snd_compress_dev_register,
                .dev_disconnect = snd_compress_dev_disconnect,
        };
@@ -911,6 +919,10 @@ int snd_compress_new(struct snd_card *card, int device,
        compr->card = card;
        compr->device = device;
        compr->direction = dirn;
+
+       snd_device_initialize(&compr->dev, card);
+       dev_set_name(&compr->dev, "comprC%iD%i", card->number, device);
+
        return snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops);
 }
 EXPORT_SYMBOL_GPL(snd_compress_new);
@@ -948,7 +960,7 @@ int snd_compress_register(struct snd_compr *device)
 {
        int retval;
 
-       if (device->name == NULL || device->dev == NULL || device->ops == NULL)
+       if (device->name == NULL || device->ops == NULL)
                return -EINVAL;
 
        pr_debug("Registering compressed device %s\n", device->name);
index bb96a467e88d080ff693766f77b36b4dc1a02b01..35324a8e83c867f126256f67b493b5320b9652c7 100644 (file)
@@ -50,7 +50,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
        unsigned long flags;
        struct snd_card *card;
        struct snd_ctl_file *ctl;
-       int err;
+       int i, err;
 
        err = nonseekable_open(inode, file);
        if (err < 0)
@@ -79,8 +79,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
        init_waitqueue_head(&ctl->change_sleep);
        spin_lock_init(&ctl->read_lock);
        ctl->card = card;
-       ctl->prefer_pcm_subdevice = -1;
-       ctl->prefer_rawmidi_subdevice = -1;
+       for (i = 0; i < SND_CTL_SUBDEV_ITEMS; i++)
+               ctl->preferred_subdevice[i] = -1;
        ctl->pid = get_pid(task_pid(current));
        file->private_data = ctl;
        write_lock_irqsave(&card->ctl_files_rwlock, flags);
@@ -373,6 +373,7 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
        card->controls_count += kcontrol->count;
        kcontrol->id.numid = card->last_numid + 1;
        card->last_numid += kcontrol->count;
+       id = kcontrol->id;
        count = kcontrol->count;
        up_write(&card->controls_rwsem);
        for (idx = 0; idx < count; idx++, id.index++, id.numid++)
@@ -439,6 +440,7 @@ add:
        card->controls_count += kcontrol->count;
        kcontrol->id.numid = card->last_numid + 1;
        card->last_numid += kcontrol->count;
+       id = kcontrol->id;
        count = kcontrol->count;
        up_write(&card->controls_rwsem);
        for (idx = 0; idx < count; idx++, id.index++, id.numid++)
@@ -1607,6 +1609,27 @@ static int snd_ctl_fasync(int fd, struct file * file, int on)
        return fasync_helper(fd, file, on, &ctl->fasync);
 }
 
+/* return the preferred subdevice number if already assigned;
+ * otherwise return -1
+ */
+int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type)
+{
+       struct snd_ctl_file *kctl;
+       int subdevice = -1;
+
+       read_lock(&card->ctl_files_rwlock);
+       list_for_each_entry(kctl, &card->ctl_files, list) {
+               if (kctl->pid == task_pid(current)) {
+                       subdevice = kctl->preferred_subdevice[type];
+                       if (subdevice != -1)
+                               break;
+               }
+       }
+       read_unlock(&card->ctl_files_rwlock);
+       return subdevice;
+}
+EXPORT_SYMBOL_GPL(snd_ctl_get_preferred_subdevice);
+
 /*
  * ioctl32 compat
  */
@@ -1639,19 +1662,9 @@ static const struct file_operations snd_ctl_f_ops =
 static int snd_ctl_dev_register(struct snd_device *device)
 {
        struct snd_card *card = device->device_data;
-       int err, cardnum;
-       char name[16];
 
-       if (snd_BUG_ON(!card))
-               return -ENXIO;
-       cardnum = card->number;
-       if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))
-               return -ENXIO;
-       sprintf(name, "controlC%i", cardnum);
-       if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
-                                      &snd_ctl_f_ops, card, name)) < 0)
-               return err;
-       return 0;
+       return snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
+                                  &snd_ctl_f_ops, card, &card->ctl_dev);
 }
 
 /*
@@ -1661,13 +1674,6 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
 {
        struct snd_card *card = device->device_data;
        struct snd_ctl_file *ctl;
-       int err, cardnum;
-
-       if (snd_BUG_ON(!card))
-               return -ENXIO;
-       cardnum = card->number;
-       if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))
-               return -ENXIO;
 
        read_lock(&card->ctl_files_rwlock);
        list_for_each_entry(ctl, &card->ctl_files, list) {
@@ -1676,10 +1682,7 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
        }
        read_unlock(&card->ctl_files_rwlock);
 
-       if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL,
-                                        card, -1)) < 0)
-               return err;
-       return 0;
+       return snd_unregister_device(&card->ctl_dev);
 }
 
 /*
@@ -1696,6 +1699,7 @@ static int snd_ctl_dev_free(struct snd_device *device)
                snd_ctl_remove(card, control);
        }
        up_write(&card->controls_rwsem);
+       put_device(&card->ctl_dev);
        return 0;
 }
 
@@ -1710,10 +1714,20 @@ int snd_ctl_create(struct snd_card *card)
                .dev_register = snd_ctl_dev_register,
                .dev_disconnect = snd_ctl_dev_disconnect,
        };
+       int err;
 
        if (snd_BUG_ON(!card))
                return -ENXIO;
-       return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
+       if (snd_BUG_ON(card->number < 0 || card->number >= SNDRV_CARDS))
+               return -ENXIO;
+
+       snd_device_initialize(&card->ctl_dev, card);
+       dev_set_name(&card->ctl_dev, "controlC%d", card->number);
+
+       err = snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
+       if (err < 0)
+               put_device(&card->ctl_dev);
+       return err;
 }
 
 /*
index 69459e5f712e9e50c51f5d3aedb360616afe5c1b..84244a5143cfe91fb53c5cfc1e2f9f5818d588aa 100644 (file)
@@ -38,7 +38,6 @@ MODULE_LICENSE("GPL");
 static LIST_HEAD(snd_hwdep_devices);
 static DEFINE_MUTEX(register_mutex);
 
-static int snd_hwdep_free(struct snd_hwdep *hwdep);
 static int snd_hwdep_dev_free(struct snd_device *device);
 static int snd_hwdep_dev_register(struct snd_device *device);
 static int snd_hwdep_dev_disconnect(struct snd_device *device);
@@ -345,6 +344,11 @@ static const struct file_operations snd_hwdep_f_ops =
        .mmap =         snd_hwdep_mmap,
 };
 
+static void release_hwdep_device(struct device *dev)
+{
+       kfree(container_of(dev, struct snd_hwdep, dev));
+}
+
 /**
  * snd_hwdep_new - create a new hwdep instance
  * @card: the card instance
@@ -378,48 +382,49 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device,
                dev_err(card->dev, "hwdep: cannot allocate\n");
                return -ENOMEM;
        }
+
+       init_waitqueue_head(&hwdep->open_wait);
+       mutex_init(&hwdep->open_mutex);
        hwdep->card = card;
        hwdep->device = device;
        if (id)
                strlcpy(hwdep->id, id, sizeof(hwdep->id));
+
+       snd_device_initialize(&hwdep->dev, card);
+       hwdep->dev.release = release_hwdep_device;
+       dev_set_name(&hwdep->dev, "hwC%iD%i", card->number, device);
 #ifdef CONFIG_SND_OSSEMUL
        hwdep->oss_type = -1;
 #endif
-       if ((err = snd_device_new(card, SNDRV_DEV_HWDEP, hwdep, &ops)) < 0) {
-               snd_hwdep_free(hwdep);
+
+       err = snd_device_new(card, SNDRV_DEV_HWDEP, hwdep, &ops);
+       if (err < 0) {
+               put_device(&hwdep->dev);
                return err;
        }
-       init_waitqueue_head(&hwdep->open_wait);
-       mutex_init(&hwdep->open_mutex);
+
        if (rhwdep)
                *rhwdep = hwdep;
        return 0;
 }
 EXPORT_SYMBOL(snd_hwdep_new);
 
-static int snd_hwdep_free(struct snd_hwdep *hwdep)
+static int snd_hwdep_dev_free(struct snd_device *device)
 {
+       struct snd_hwdep *hwdep = device->device_data;
        if (!hwdep)
                return 0;
        if (hwdep->private_free)
                hwdep->private_free(hwdep);
-       kfree(hwdep);
+       put_device(&hwdep->dev);
        return 0;
 }
 
-static int snd_hwdep_dev_free(struct snd_device *device)
-{
-       struct snd_hwdep *hwdep = device->device_data;
-       return snd_hwdep_free(hwdep);
-}
-
 static int snd_hwdep_dev_register(struct snd_device *device)
 {
        struct snd_hwdep *hwdep = device->device_data;
        struct snd_card *card = hwdep->card;
-       struct device *dev;
        int err;
-       char name[32];
 
        mutex_lock(&register_mutex);
        if (snd_hwdep_search(card, hwdep->device)) {
@@ -427,53 +432,30 @@ static int snd_hwdep_dev_register(struct snd_device *device)
                return -EBUSY;
        }
        list_add_tail(&hwdep->list, &snd_hwdep_devices);
-       sprintf(name, "hwC%iD%i", hwdep->card->number, hwdep->device);
-       dev = hwdep->dev;
-       if (!dev)
-               dev = snd_card_get_device_link(hwdep->card);
-       err = snd_register_device_for_dev(SNDRV_DEVICE_TYPE_HWDEP,
-                                         hwdep->card, hwdep->device,
-                                         &snd_hwdep_f_ops, hwdep, name, dev);
+       err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP,
+                                 hwdep->card, hwdep->device,
+                                 &snd_hwdep_f_ops, hwdep, &hwdep->dev);
        if (err < 0) {
-               dev_err(dev,
-                       "unable to register hardware dependent device %i:%i\n",
-                       card->number, hwdep->device);
+               dev_err(&hwdep->dev, "unable to register\n");
                list_del(&hwdep->list);
                mutex_unlock(&register_mutex);
                return err;
        }
 
-       if (hwdep->groups) {
-               struct device *d = snd_get_device(SNDRV_DEVICE_TYPE_HWDEP,
-                                                 hwdep->card, hwdep->device);
-               if (d) {
-                       if (hwdep->private_data)
-                               dev_set_drvdata(d, hwdep->private_data);
-                       err = sysfs_create_groups(&d->kobj, hwdep->groups);
-                       if (err < 0)
-                               dev_warn(dev,
-                                        "hwdep %d:%d: cannot create sysfs groups\n",
-                                        card->number, hwdep->device);
-                       put_device(d);
-               }
-       }
-
 #ifdef CONFIG_SND_OSSEMUL
        hwdep->ossreg = 0;
        if (hwdep->oss_type >= 0) {
-               if ((hwdep->oss_type == SNDRV_OSS_DEVICE_TYPE_DMFM) && (hwdep->device != 0)) {
-                       dev_warn(dev,
+               if (hwdep->oss_type == SNDRV_OSS_DEVICE_TYPE_DMFM &&
+                   hwdep->device)
+                       dev_warn(&hwdep->dev,
                                 "only hwdep device 0 can be registered as OSS direct FM device!\n");
-               } else {
-                       if (snd_register_oss_device(hwdep->oss_type,
-                                                   card, hwdep->device,
-                                                   &snd_hwdep_f_ops, hwdep) < 0) {
-                               dev_err(dev,
-                                       "unable to register OSS compatibility device %i:%i\n",
-                                       card->number, hwdep->device);
-                       } else
-                               hwdep->ossreg = 1;
-               }
+               else if (snd_register_oss_device(hwdep->oss_type,
+                                                card, hwdep->device,
+                                                &snd_hwdep_f_ops, hwdep) < 0)
+                       dev_warn(&hwdep->dev,
+                                "unable to register OSS compatibility device\n");
+               else
+                       hwdep->ossreg = 1;
        }
 #endif
        mutex_unlock(&register_mutex);
@@ -497,7 +479,7 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device)
        if (hwdep->ossreg)
                snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device);
 #endif
-       snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device);
+       snd_unregister_device(&hwdep->dev);
        list_del_init(&hwdep->list);
        mutex_unlock(&hwdep->open_mutex);
        mutex_unlock(&register_mutex);
index 074875d68c156745519987f24d22058ca4c398b4..35419054821c3deab7e590b6a586f05d1282d055 100644 (file)
@@ -157,8 +157,31 @@ static int get_slot_from_bitmask(int mask, int (*check)(struct module *, int),
        return mask; /* unchanged */
 }
 
+/* the default release callback set in snd_device_initialize() below;
+ * this is just NOP for now, as almost all jobs are already done in
+ * dev_free callback of snd_device chain instead.
+ */
+static void default_release(struct device *dev)
+{
+}
+
+/**
+ * snd_device_initialize - Initialize struct device for sound devices
+ * @dev: device to initialize
+ * @card: card to assign, optional
+ */
+void snd_device_initialize(struct device *dev, struct snd_card *card)
+{
+       device_initialize(dev);
+       if (card)
+               dev->parent = &card->card_dev;
+       dev->class = sound_class;
+       dev->release = default_release;
+}
+EXPORT_SYMBOL_GPL(snd_device_initialize);
+
 static int snd_card_do_free(struct snd_card *card);
-static const struct attribute_group *card_dev_attr_groups[];
+static const struct attribute_group card_dev_attr_group;
 
 static void release_card_device(struct device *dev)
 {
@@ -246,7 +269,8 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
        card->card_dev.parent = parent;
        card->card_dev.class = sound_class;
        card->card_dev.release = release_card_device;
-       card->card_dev.groups = card_dev_attr_groups;
+       card->card_dev.groups = card->dev_groups;
+       card->dev_groups[0] = &card_dev_attr_group;
        err = kobject_set_name(&card->card_dev.kobj, "card%d", idx);
        if (err < 0)
                goto __error;
@@ -677,14 +701,32 @@ static struct attribute *card_dev_attrs[] = {
        NULL
 };
 
-static struct attribute_group card_dev_attr_group = {
+static const struct attribute_group card_dev_attr_group = {
        .attrs  = card_dev_attrs,
 };
 
-static const struct attribute_group *card_dev_attr_groups[] = {
-       &card_dev_attr_group,
-       NULL
+/**
+ * snd_card_add_dev_attr - Append a new sysfs attribute group to card
+ * @card: card instance
+ * @group: attribute group to append
+ */
+int snd_card_add_dev_attr(struct snd_card *card,
+                         const struct attribute_group *group)
+{
+       int i;
+
+       /* loop for (arraysize-1) here to keep NULL at the last entry */
+       for (i = 0; i < ARRAY_SIZE(card->dev_groups) - 1; i++) {
+               if (!card->dev_groups[i]) {
+                       card->dev_groups[i] = group;
+                       return 0;
+               }
+       }
+
+       dev_err(card->dev, "Too many groups assigned\n");
+       return -ENOSPC;
 };
+EXPORT_SYMBOL_GPL(snd_card_add_dev_attr);
 
 /**
  *  snd_card_register - register the soundcard
index 36c0f1a2e189e7dd6a7aceb325be3abbc6f8688d..4cd664efad770fc4e4284caa1bb053cbc5bd3166 100644 (file)
@@ -21,8 +21,8 @@
  */
 
 #include <linux/export.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
 #include <sound/core.h>
 
 /**
index ada69d7a8d70a077c18abfa2aa7bf26ee8125b27..80423a4ccab621b04d0c0fbdbe3bdeafc67a7e3b 100644 (file)
@@ -719,7 +719,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
 
        oss_buffer_size = snd_pcm_plug_client_size(substream,
                                                   snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size;
-       oss_buffer_size = 1 << ld2(oss_buffer_size);
+       oss_buffer_size = rounddown_pow_of_two(oss_buffer_size);
        if (atomic_read(&substream->mmap_count)) {
                if (oss_buffer_size > runtime->oss.mmap_bytes)
                        oss_buffer_size = runtime->oss.mmap_bytes;
@@ -755,14 +755,14 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
        min_period_size = snd_pcm_plug_client_size(substream,
                                                   snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
        min_period_size *= oss_frame_size;
-       min_period_size = 1 << (ld2(min_period_size - 1) + 1);
+       min_period_size = roundup_pow_of_two(min_period_size);
        if (oss_period_size < min_period_size)
                oss_period_size = min_period_size;
 
        max_period_size = snd_pcm_plug_client_size(substream,
                                                   snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
        max_period_size *= oss_frame_size;
-       max_period_size = 1 << ld2(max_period_size);
+       max_period_size = rounddown_pow_of_two(max_period_size);
        if (oss_period_size > max_period_size)
                oss_period_size = max_period_size;
 
index cfc56c806964ed3a804f744c6297d6ea813b8fb2..0345e53a340ca90d68fa3f4b05b3a7e655ebdb1f 100644 (file)
@@ -161,7 +161,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
                        
                        if (get_user(val, (int __user *)arg))
                                return -EFAULT;
-                       control->prefer_pcm_subdevice = val;
+                       control->preferred_subdevice[SND_CTL_SUBDEV_PCM] = val;
                        return 0;
                }
        }
@@ -673,6 +673,8 @@ static inline int snd_pcm_substream_proc_init(struct snd_pcm_substream *substrea
 static inline int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) { return 0; }
 #endif /* CONFIG_SND_VERBOSE_PROCFS */
 
+static const struct attribute_group *pcm_dev_attr_groups[];
+
 /**
  * snd_pcm_new_stream - create a new PCM stream
  * @pcm: the pcm instance
@@ -698,7 +700,15 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
        pstr->stream = stream;
        pstr->pcm = pcm;
        pstr->substream_count = substream_count;
-       if (substream_count > 0 && !pcm->internal) {
+       if (!substream_count)
+               return 0;
+
+       snd_device_initialize(&pstr->dev, pcm->card);
+       pstr->dev.groups = pcm_dev_attr_groups;
+       dev_set_name(&pstr->dev, "pcmC%iD%i%c", pcm->card->number, pcm->device,
+                    stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c');
+
+       if (!pcm->internal) {
                err = snd_pcm_stream_proc_init(pstr);
                if (err < 0) {
                        pcm_err(pcm, "Error in snd_pcm_stream_proc_init\n");
@@ -868,6 +878,8 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
                kfree(setup);
        }
 #endif
+       if (pstr->substream_count)
+               put_device(&pstr->dev);
 }
 
 static int snd_pcm_free(struct snd_pcm *pcm)
@@ -901,9 +913,8 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
        struct snd_pcm_str * pstr;
        struct snd_pcm_substream *substream;
        struct snd_pcm_runtime *runtime;
-       struct snd_ctl_file *kctl;
        struct snd_card *card;
-       int prefer_subdevice = -1;
+       int prefer_subdevice;
        size_t size;
 
        if (snd_BUG_ON(!pcm || !rsubstream))
@@ -914,15 +925,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
                return -ENODEV;
 
        card = pcm->card;
-       read_lock(&card->ctl_files_rwlock);
-       list_for_each_entry(kctl, &card->ctl_files, list) {
-               if (kctl->pid == task_pid(current)) {
-                       prefer_subdevice = kctl->prefer_pcm_subdevice;
-                       if (prefer_subdevice != -1)
-                               break;
-               }
-       }
-       read_unlock(&card->ctl_files_rwlock);
+       prefer_subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_PCM);
 
        switch (stream) {
        case SNDRV_PCM_STREAM_PLAYBACK:
@@ -1078,9 +1081,7 @@ static int snd_pcm_dev_register(struct snd_device *device)
        int cidx, err;
        struct snd_pcm_substream *substream;
        struct snd_pcm_notify *notify;
-       char str[16];
        struct snd_pcm *pcm;
-       struct device *dev;
 
        if (snd_BUG_ON(!device || !device->device_data))
                return -ENXIO;
@@ -1097,42 +1098,22 @@ static int snd_pcm_dev_register(struct snd_device *device)
                        continue;
                switch (cidx) {
                case SNDRV_PCM_STREAM_PLAYBACK:
-                       sprintf(str, "pcmC%iD%ip", pcm->card->number, pcm->device);
                        devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
                        break;
                case SNDRV_PCM_STREAM_CAPTURE:
-                       sprintf(str, "pcmC%iD%ic", pcm->card->number, pcm->device);
                        devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
                        break;
                }
-               /* device pointer to use, pcm->dev takes precedence if
-                * it is assigned, otherwise fall back to card's device
-                * if possible */
-               dev = pcm->dev;
-               if (!dev)
-                       dev = snd_card_get_device_link(pcm->card);
                /* register pcm */
-               err = snd_register_device_for_dev(devtype, pcm->card,
-                                                 pcm->device,
-                                                 &snd_pcm_f_ops[cidx],
-                                                 pcm, str, dev);
+               err = snd_register_device(devtype, pcm->card, pcm->device,
+                                         &snd_pcm_f_ops[cidx], pcm,
+                                         &pcm->streams[cidx].dev);
                if (err < 0) {
                        list_del(&pcm->list);
                        mutex_unlock(&register_mutex);
                        return err;
                }
 
-               dev = snd_get_device(devtype, pcm->card, pcm->device);
-               if (dev) {
-                       err = sysfs_create_groups(&dev->kobj,
-                                                 pcm_dev_attr_groups);
-                       if (err < 0)
-                               dev_warn(dev,
-                                        "pcm %d:%d: cannot create sysfs groups\n",
-                                        pcm->card->number, pcm->device);
-                       put_device(dev);
-               }
-
                for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
                        snd_pcm_timer_init(substream);
        }
@@ -1149,7 +1130,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
        struct snd_pcm *pcm = device->device_data;
        struct snd_pcm_notify *notify;
        struct snd_pcm_substream *substream;
-       int cidx, devtype;
+       int cidx;
 
        mutex_lock(&register_mutex);
        if (list_empty(&pcm->list))
@@ -1172,16 +1153,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
                notify->n_disconnect(pcm);
        }
        for (cidx = 0; cidx < 2; cidx++) {
-               devtype = -1;
-               switch (cidx) {
-               case SNDRV_PCM_STREAM_PLAYBACK:
-                       devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
-                       break;
-               case SNDRV_PCM_STREAM_CAPTURE:
-                       devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
-                       break;
-               }
-               snd_unregister_device(devtype, pcm->card, pcm->device);
+               snd_unregister_device(&pcm->streams[cidx].dev);
                if (pcm->streams[cidx].chmap_kctl) {
                        snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl);
                        pcm->streams[cidx].chmap_kctl = NULL;
index ec9e7866177feff13db582abc6007fa6f4a40932..ffd656012ab8cf123faef551c9eaaae48c2beb8c 100644 (file)
@@ -1015,6 +1015,60 @@ int snd_interval_list(struct snd_interval *i, unsigned int count,
 
 EXPORT_SYMBOL(snd_interval_list);
 
+/**
+ * snd_interval_ranges - refine the interval value from the list of ranges
+ * @i: the interval value to refine
+ * @count: the number of elements in the list of ranges
+ * @ranges: the ranges list
+ * @mask: the bit-mask to evaluate
+ *
+ * Refines the interval value from the list of ranges.
+ * When mask is non-zero, only the elements corresponding to bit 1 are
+ * evaluated.
+ *
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
+ */
+int snd_interval_ranges(struct snd_interval *i, unsigned int count,
+                       const struct snd_interval *ranges, unsigned int mask)
+{
+       unsigned int k;
+       struct snd_interval range_union;
+       struct snd_interval range;
+
+       if (!count) {
+               snd_interval_none(i);
+               return -EINVAL;
+       }
+       snd_interval_any(&range_union);
+       range_union.min = UINT_MAX;
+       range_union.max = 0;
+       for (k = 0; k < count; k++) {
+               if (mask && !(mask & (1 << k)))
+                       continue;
+               snd_interval_copy(&range, &ranges[k]);
+               if (snd_interval_refine(&range, i) < 0)
+                       continue;
+               if (snd_interval_empty(&range))
+                       continue;
+
+               if (range.min < range_union.min) {
+                       range_union.min = range.min;
+                       range_union.openmin = 1;
+               }
+               if (range.min == range_union.min && !range.openmin)
+                       range_union.openmin = 0;
+               if (range.max > range_union.max) {
+                       range_union.max = range.max;
+                       range_union.openmax = 1;
+               }
+               if (range.max == range_union.max && !range.openmax)
+                       range_union.openmax = 0;
+       }
+       return snd_interval_refine(i, &range_union);
+}
+EXPORT_SYMBOL(snd_interval_ranges);
+
 static int snd_interval_step(struct snd_interval *i, unsigned int step)
 {
        unsigned int n;
@@ -1221,6 +1275,37 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime,
 
 EXPORT_SYMBOL(snd_pcm_hw_constraint_list);
 
+static int snd_pcm_hw_rule_ranges(struct snd_pcm_hw_params *params,
+                                 struct snd_pcm_hw_rule *rule)
+{
+       struct snd_pcm_hw_constraint_ranges *r = rule->private;
+       return snd_interval_ranges(hw_param_interval(params, rule->var),
+                                  r->count, r->ranges, r->mask);
+}
+
+
+/**
+ * snd_pcm_hw_constraint_ranges - apply list of range constraints to a parameter
+ * @runtime: PCM runtime instance
+ * @cond: condition bits
+ * @var: hw_params variable to apply the list of range constraints
+ * @r: ranges
+ *
+ * Apply the list of range constraints to an interval parameter.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
+ */
+int snd_pcm_hw_constraint_ranges(struct snd_pcm_runtime *runtime,
+                                unsigned int cond,
+                                snd_pcm_hw_param_t var,
+                                const struct snd_pcm_hw_constraint_ranges *r)
+{
+       return snd_pcm_hw_rule_add(runtime, cond, var,
+                                  snd_pcm_hw_rule_ranges, (void *)r,
+                                  var, -1);
+}
+EXPORT_SYMBOL(snd_pcm_hw_constraint_ranges);
+
 static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params,
                                   struct snd_pcm_hw_rule *rule)
 {
@@ -1299,8 +1384,14 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,
        int width = l & 0xffff;
        unsigned int msbits = l >> 16;
        struct snd_interval *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
-       if (snd_interval_single(i) && snd_interval_value(i) == width)
-               params->msbits = msbits;
+
+       if (!snd_interval_single(i))
+               return 0;
+
+       if ((snd_interval_value(i) == width) ||
+           (width == 0 && snd_interval_value(i) > msbits))
+               params->msbits = min_not_zero(params->msbits, msbits);
+
        return 0;
 }
 
@@ -1311,6 +1402,11 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,
  * @width: sample bits width
  * @msbits: msbits width
  *
+ * This constraint will set the number of most significant bits (msbits) if a
+ * sample format with the specified width has been select. If width is set to 0
+ * the msbits will be set for any sample format with a width larger than the
+ * specified msbits.
+ *
  * Return: Zero if successful, or a negative error code on failure.
  */
 int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime, 
index 54debc07f5cbb233a2249e4bf957855adbfac25b..b45f6aa322642ed6f132af0535c424a99ac39b6b 100644 (file)
@@ -19,7 +19,7 @@
  *
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/time.h>
 #include <linux/init.h>
 #include <linux/slab.h>
index 095d9572ad2b3a683b3d671845d63c38a2856b30..b03a638b420c18243776c45fda5884b422392c46 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/time.h>
 #include <linux/pm_qos.h>
 #include <linux/aio.h>
+#include <linux/io.h>
 #include <linux/dma-mapping.h>
 #include <sound/core.h>
 #include <sound/control.h>
@@ -34,7 +35,6 @@
 #include <sound/pcm_params.h>
 #include <sound/timer.h>
 #include <sound/minors.h>
-#include <asm/io.h>
 
 /*
  *  Compatibility
@@ -420,7 +420,8 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
 
        hw = &substream->runtime->hw;
        if (!params->info) {
-               params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES;
+               params->info = hw->info & ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES |
+                                           SNDRV_PCM_INFO_DRAIN_TRIGGER);
                if (!hw_support_mmap(substream))
                        params->info &= ~(SNDRV_PCM_INFO_MMAP |
                                          SNDRV_PCM_INFO_MMAP_VALID);
@@ -719,8 +720,11 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
                                runtime->status->audio_tstamp;
                        goto _tstamp_end;
                }
+       } else {
+               /* get tstamp only in fallback mode and only if enabled */
+               if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+                       snd_pcm_gettime(runtime, &status->tstamp);
        }
-       snd_pcm_gettime(runtime, &status->tstamp);
  _tstamp_end:
        status->appl_ptr = runtime->control->appl_ptr;
        status->hw_ptr = runtime->status->hw_ptr;
@@ -806,7 +810,8 @@ static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream)
        if (runtime->trigger_master == NULL)
                return;
        if (runtime->trigger_master == substream) {
-               snd_pcm_gettime(runtime, &runtime->trigger_tstamp);
+               if (!runtime->trigger_tstamp_latched)
+                       snd_pcm_gettime(runtime, &runtime->trigger_tstamp);
        } else {
                snd_pcm_trigger_tstamp(runtime->trigger_master);
                runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp;
@@ -975,6 +980,7 @@ static int snd_pcm_pre_start(struct snd_pcm_substream *substream, int state)
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
            !snd_pcm_playback_data(substream))
                return -EPIPE;
+       runtime->trigger_tstamp_latched = false;
        runtime->trigger_master = substream;
        return 0;
 }
@@ -1566,6 +1572,13 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state)
                        snd_pcm_post_stop(substream, new_state);
                }
        }
+
+       if (runtime->status->state == SNDRV_PCM_STATE_DRAINING &&
+           runtime->trigger_master == substream &&
+           (runtime->hw.info & SNDRV_PCM_INFO_DRAIN_TRIGGER))
+               return substream->ops->trigger(substream,
+                                              SNDRV_PCM_TRIGGER_DRAIN);
+
        return 0;
 }
 
index 6fc71a4c8a5177c63094333093de18a70b3159ac..b5a748596fc40dda977e437b2ed6a6b87c4321b3 100644 (file)
@@ -57,11 +57,11 @@ static LIST_HEAD(snd_rawmidi_devices);
 static DEFINE_MUTEX(register_mutex);
 
 #define rmidi_err(rmidi, fmt, args...) \
-       dev_err((rmidi)->card->dev, fmt, ##args)
+       dev_err(&(rmidi)->dev, fmt, ##args)
 #define rmidi_warn(rmidi, fmt, args...) \
-       dev_warn((rmidi)->card->dev, fmt, ##args)
+       dev_warn(&(rmidi)->dev, fmt, ##args)
 #define rmidi_dbg(rmidi, fmt, args...) \
-       dev_dbg((rmidi)->card->dev, fmt, ##args)
+       dev_dbg(&(rmidi)->dev, fmt, ##args)
 
 static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device)
 {
@@ -369,7 +369,6 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
        struct snd_rawmidi *rmidi;
        struct snd_rawmidi_file *rawmidi_file = NULL;
        wait_queue_t wait;
-       struct snd_ctl_file *kctl;
 
        if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) 
                return -EINVAL;         /* invalid combination */
@@ -413,16 +412,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
        init_waitqueue_entry(&wait, current);
        add_wait_queue(&rmidi->open_wait, &wait);
        while (1) {
-               subdevice = -1;
-               read_lock(&card->ctl_files_rwlock);
-               list_for_each_entry(kctl, &card->ctl_files, list) {
-                       if (kctl->pid == task_pid(current)) {
-                               subdevice = kctl->prefer_rawmidi_subdevice;
-                               if (subdevice != -1)
-                                       break;
-                       }
-               }
-               read_unlock(&card->ctl_files_rwlock);
+               subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_RAWMIDI);
                err = rawmidi_open_priv(rmidi, subdevice, fflags, rawmidi_file);
                if (err >= 0)
                        break;
@@ -862,7 +852,7 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card,
                
                if (get_user(val, (int __user *)argp))
                        return -EFAULT;
-               control->prefer_rawmidi_subdevice = val;
+               control->preferred_subdevice[SND_CTL_SUBDEV_RAWMIDI] = val;
                return 0;
        }
        case SNDRV_CTL_IOCTL_RAWMIDI_INFO:
@@ -1453,6 +1443,11 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi,
        return 0;
 }
 
+static void release_rawmidi_device(struct device *dev)
+{
+       kfree(container_of(dev, struct snd_rawmidi, dev));
+}
+
 /**
  * snd_rawmidi_new - create a rawmidi instance
  * @card: the card instance
@@ -1497,6 +1492,11 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
 
        if (id != NULL)
                strlcpy(rmidi->id, id, sizeof(rmidi->id));
+
+       snd_device_initialize(&rmidi->dev, card);
+       rmidi->dev.release = release_rawmidi_device;
+       dev_set_name(&rmidi->dev, "midiC%iD%i", card->number, device);
+
        if ((err = snd_rawmidi_alloc_substreams(rmidi,
                                                &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT],
                                                SNDRV_RAWMIDI_STREAM_INPUT,
@@ -1548,7 +1548,7 @@ static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
        snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
        if (rmidi->private_free)
                rmidi->private_free(rmidi);
-       kfree(rmidi);
+       put_device(&rmidi->dev);
        return 0;
 }
 
@@ -1581,19 +1581,18 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
                return -EBUSY;
        }
        list_add_tail(&rmidi->list, &snd_rawmidi_devices);
-       sprintf(name, "midiC%iD%i", rmidi->card->number, rmidi->device);
-       if ((err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI,
-                                      rmidi->card, rmidi->device,
-                                      &snd_rawmidi_f_ops, rmidi, name)) < 0) {
-               rmidi_err(rmidi, "unable to register rawmidi device %i:%i\n",
-                         rmidi->card->number, rmidi->device);
+       err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI,
+                                 rmidi->card, rmidi->device,
+                                 &snd_rawmidi_f_ops, rmidi, &rmidi->dev);
+       if (err < 0) {
+               rmidi_err(rmidi, "unable to register\n");
                list_del(&rmidi->list);
                mutex_unlock(&register_mutex);
                return err;
        }
        if (rmidi->ops && rmidi->ops->dev_register &&
            (err = rmidi->ops->dev_register(rmidi)) < 0) {
-               snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
+               snd_unregister_device(&rmidi->dev);
                list_del(&rmidi->list);
                mutex_unlock(&register_mutex);
                return err;
@@ -1681,7 +1680,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
                rmidi->ossreg = 0;
        }
 #endif /* CONFIG_SND_OSSEMUL */
-       snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
+       snd_unregister_device(&rmidi->dev);
        mutex_unlock(&rmidi->open_mutex);
        mutex_unlock(&register_mutex);
        return 0;
index 3a4569669efa4b561b2751d9d1170e69ee2f4b47..e79cc44b1394e68c07d8eab6c00c3868522f8c03 100644 (file)
@@ -237,8 +237,7 @@ snd_seq_oss_midi_check_exit_port(int client, int port)
                spin_unlock_irqrestore(&register_lock, flags);
                snd_use_lock_free(&mdev->use_lock);
                snd_use_lock_sync(&mdev->use_lock);
-               if (mdev->coder)
-                       snd_midi_event_free(mdev->coder);
+               snd_midi_event_free(mdev->coder);
                kfree(mdev);
        }
        spin_lock_irqsave(&register_lock, flags);
@@ -265,8 +264,7 @@ snd_seq_oss_midi_clear_all(void)
        spin_lock_irqsave(&register_lock, flags);
        for (i = 0; i < max_midi_devs; i++) {
                if ((mdev = midi_devs[i]) != NULL) {
-                       if (mdev->coder)
-                               snd_midi_event_free(mdev->coder);
+                       snd_midi_event_free(mdev->coder);
                        kfree(mdev);
                        midi_devs[i] = NULL;
                }
index 225c73152ee9e5896c06a3b7f1fbb16095bb5bd2..48287651ac7795b8ac27e3b5a4eacb1389ec4950 100644 (file)
@@ -1133,7 +1133,7 @@ static int snd_seq_ioctl_system_info(struct snd_seq_client *client, void __user
        /* fill the info fields */
        info.queues = SNDRV_SEQ_MAX_QUEUES;
        info.clients = SNDRV_SEQ_MAX_CLIENTS;
-       info.ports = 256;       /* fixed limit */
+       info.ports = SNDRV_SEQ_MAX_PORTS;
        info.channels = 256;    /* fixed limit */
        info.cur_clients = client_usage.cur;
        info.cur_queues = snd_seq_queue_get_cur_queues();
@@ -1279,7 +1279,6 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client,
                                port->owner = callback->owner;
                        port->private_data = callback->private_data;
                        port->private_free = callback->private_free;
-                       port->callback_all = callback->callback_all;
                        port->event_input = callback->event_input;
                        port->c_src.open = callback->subscribe;
                        port->c_src.close = callback->unsubscribe;
@@ -2571,6 +2570,8 @@ static const struct file_operations snd_seq_f_ops =
        .compat_ioctl = snd_seq_ioctl_compat,
 };
 
+static struct device seq_dev;
+
 /* 
  * register sequencer device 
  */
@@ -2578,12 +2579,17 @@ int __init snd_sequencer_device_init(void)
 {
        int err;
 
+       snd_device_initialize(&seq_dev, NULL);
+       dev_set_name(&seq_dev, "seq");
+
        if (mutex_lock_interruptible(&register_mutex))
                return -ERESTARTSYS;
 
-       if ((err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0,
-                                      &snd_seq_f_ops, NULL, "seq")) < 0) {
+       err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0,
+                                 &snd_seq_f_ops, NULL, &seq_dev);
+       if (err < 0) {
                mutex_unlock(&register_mutex);
+               put_device(&seq_dev);
                return err;
        }
        
@@ -2599,5 +2605,6 @@ int __init snd_sequencer_device_init(void)
  */
 void __exit snd_sequencer_device_done(void)
 {
-       snd_unregister_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0);
+       snd_unregister_device(&seq_dev);
+       put_device(&seq_dev);
 }
index a1fd77af60593e26de9cf4c560e8a3b80412d797..68fec776da2619db52163b143551b6e045ce2ee8 100644 (file)
@@ -268,8 +268,7 @@ static void snd_seq_midisynth_delete(struct seq_midisynth *msynth)
                snd_seq_event_port_detach(msynth->seq_client, msynth->seq_port);
        }
 
-       if (msynth->parser)
-               snd_midi_event_free(msynth->parser);
+       snd_midi_event_free(msynth->parser);
 }
 
 /* register new midi synth port */
index 794a341bf0e560d7d5b69d37dc665fd9e571b294..46ff593f618dc0b75ea66f886e051c035f2aebad 100644 (file)
@@ -134,7 +134,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
        if (snd_BUG_ON(!client))
                return NULL;
 
-       if (client->num_ports >= SNDRV_SEQ_MAX_PORTS - 1) {
+       if (client->num_ports >= SNDRV_SEQ_MAX_PORTS) {
                pr_warn("ALSA: seq: too many ports for client %d\n", client->number);
                return NULL;
        }
@@ -411,9 +411,6 @@ int snd_seq_get_port_info(struct snd_seq_client_port * port,
  * invoked.
  * This feature is useful if these callbacks are associated with
  * initialization or termination of devices (see seq_midi.c).
- *
- * If callback_all option is set, the callback function is invoked
- * at each connection/disconnection. 
  */
 
 static int subscribe_port(struct snd_seq_client *client,
@@ -427,7 +424,7 @@ static int subscribe_port(struct snd_seq_client *client,
        if (!try_module_get(port->owner))
                return -EFAULT;
        grp->count++;
-       if (grp->open && (port->callback_all || grp->count == 1)) {
+       if (grp->open && grp->count == 1) {
                err = grp->open(port->private_data, info);
                if (err < 0) {
                        module_put(port->owner);
@@ -452,7 +449,7 @@ static int unsubscribe_port(struct snd_seq_client *client,
        if (! grp->count)
                return -EINVAL;
        grp->count--;
-       if (grp->close && (port->callback_all || grp->count == 0))
+       if (grp->close && grp->count == 0)
                err = grp->close(port->private_data, info);
        if (send_ack && client->type == USER_CLIENT)
                snd_seq_client_notify_subscription(port->addr.client, port->addr.port,
index 9d7117118ba481a9b25aef7d757730cc48d8139f..26bd71f36c41d1961d3be970d0264e6aef06483d 100644 (file)
@@ -73,7 +73,6 @@ struct snd_seq_client_port {
                           int atomic, int hop);
        void (*private_free)(void *private_data);
        void *private_data;
-       unsigned int callback_all : 1;
        unsigned int closing : 1;
        unsigned int timestamping: 1;
        unsigned int time_real: 1;
index f1333060bf1cc71bb391673017a5bd84a6e8123a..185cec01ee258cceea232209c24b8aa5478b300b 100644 (file)
@@ -242,30 +242,30 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev)
 #endif
 
 /**
- * snd_register_device_for_dev - Register the ALSA device file for the card
+ * snd_register_device - Register the ALSA device file for the card
  * @type: the device type, SNDRV_DEVICE_TYPE_XXX
  * @card: the card instance
  * @dev: the device index
  * @f_ops: the file operations
  * @private_data: user pointer for f_ops->open()
- * @name: the device file name
- * @device: the &struct device to link this new device to
+ * @device: the device to register
  *
  * Registers an ALSA device file for the given card.
  * The operators have to be set in reg parameter.
  *
  * Return: Zero if successful, or a negative error code on failure.
  */
-int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
-                               const struct file_operations *f_ops,
-                               void *private_data,
-                               const char *name, struct device *device)
+int snd_register_device(int type, struct snd_card *card, int dev,
+                       const struct file_operations *f_ops,
+                       void *private_data, struct device *device)
 {
        int minor;
+       int err = 0;
        struct snd_minor *preg;
 
-       if (snd_BUG_ON(!name))
+       if (snd_BUG_ON(!device))
                return -EINVAL;
+
        preg = kmalloc(sizeof *preg, GFP_KERNEL);
        if (preg == NULL)
                return -ENOMEM;
@@ -284,102 +284,56 @@ int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
                minor = -EBUSY;
 #endif
        if (minor < 0) {
-               mutex_unlock(&sound_mutex);
-               kfree(preg);
-               return minor;
-       }
-       snd_minors[minor] = preg;
-       preg->dev = device_create(sound_class, device, MKDEV(major, minor),
-                                 private_data, "%s", name);
-       if (IS_ERR(preg->dev)) {
-               snd_minors[minor] = NULL;
-               mutex_unlock(&sound_mutex);
-               minor = PTR_ERR(preg->dev);
-               kfree(preg);
-               return minor;
+               err = minor;
+               goto error;
        }
 
-       mutex_unlock(&sound_mutex);
-       return 0;
-}
-
-EXPORT_SYMBOL(snd_register_device_for_dev);
-
-/* find the matching minor record
- * return the index of snd_minor, or -1 if not found
- */
-static int find_snd_minor(int type, struct snd_card *card, int dev)
-{
-       int cardnum, minor;
-       struct snd_minor *mptr;
+       preg->dev = device;
+       device->devt = MKDEV(major, minor);
+       err = device_add(device);
+       if (err < 0)
+               goto error;
 
-       cardnum = card ? card->number : -1;
-       for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor)
-               if ((mptr = snd_minors[minor]) != NULL &&
-                   mptr->type == type &&
-                   mptr->card == cardnum &&
-                   mptr->device == dev)
-                       return minor;
-       return -1;
+       snd_minors[minor] = preg;
+ error:
+       mutex_unlock(&sound_mutex);
+       if (err < 0)
+               kfree(preg);
+       return err;
 }
+EXPORT_SYMBOL(snd_register_device);
 
 /**
  * snd_unregister_device - unregister the device on the given card
- * @type: the device type, SNDRV_DEVICE_TYPE_XXX
- * @card: the card instance
- * @dev: the device index
+ * @dev: the device instance
  *
  * Unregisters the device file already registered via
  * snd_register_device().
  *
  * Return: Zero if successful, or a negative error code on failure.
  */
-int snd_unregister_device(int type, struct snd_card *card, int dev)
+int snd_unregister_device(struct device *dev)
 {
        int minor;
+       struct snd_minor *preg;
 
        mutex_lock(&sound_mutex);
-       minor = find_snd_minor(type, card, dev);
-       if (minor < 0) {
-               mutex_unlock(&sound_mutex);
-               return -EINVAL;
+       for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) {
+               preg = snd_minors[minor];
+               if (preg && preg->dev == dev) {
+                       snd_minors[minor] = NULL;
+                       device_del(dev);
+                       kfree(preg);
+                       break;
+               }
        }
-
-       device_destroy(sound_class, MKDEV(major, minor));
-
-       kfree(snd_minors[minor]);
-       snd_minors[minor] = NULL;
        mutex_unlock(&sound_mutex);
+       if (minor >= ARRAY_SIZE(snd_minors))
+               return -ENOENT;
        return 0;
 }
-
 EXPORT_SYMBOL(snd_unregister_device);
 
-/**
- * snd_get_device - get the assigned device to the given type and device number
- * @type: the device type, SNDRV_DEVICE_TYPE_XXX
- * @card:the card instance
- * @dev: the device index
- *
- * The caller needs to release it via put_device() after using it.
- */
-struct device *snd_get_device(int type, struct snd_card *card, int dev)
-{
-       int minor;
-       struct device *d = NULL;
-
-       mutex_lock(&sound_mutex);
-       minor = find_snd_minor(type, card, dev);
-       if (minor >= 0) {
-               d = snd_minors[minor]->dev;
-               if (d)
-                       get_device(d);
-       }
-       mutex_unlock(&sound_mutex);
-       return d;
-}
-EXPORT_SYMBOL(snd_get_device);
-
 #ifdef CONFIG_PROC_FS
 /*
  *  INFO PART
index 777a45e08e539aa3c7320f31c5d1329db1ea0944..490b489d713d4c892af0689d4eafb32cde2131c1 100644 (file)
@@ -1030,9 +1030,7 @@ static int snd_timer_register_system(void)
                snd_timer_free(timer);
                return -ENOMEM;
        }
-       init_timer(&priv->tlist);
-       priv->tlist.function = snd_timer_s_function;
-       priv->tlist.data = (unsigned long) timer;
+       setup_timer(&priv->tlist, snd_timer_s_function, (unsigned long) timer);
        timer->private_data = priv;
        timer->private_free = snd_timer_free_system;
        return snd_timer_global_register(timer);
@@ -1942,6 +1940,17 @@ static const struct file_operations snd_timer_f_ops =
        .fasync =       snd_timer_user_fasync,
 };
 
+/* unregister the system timer */
+static void snd_timer_free_all(void)
+{
+       struct snd_timer *timer, *n;
+
+       list_for_each_entry_safe(timer, n, &snd_timer_list, device_list)
+               snd_timer_free(timer);
+}
+
+static struct device timer_dev;
+
 /*
  *  ENTRY functions
  */
@@ -1950,30 +1959,39 @@ static int __init alsa_timer_init(void)
 {
        int err;
 
+       snd_device_initialize(&timer_dev, NULL);
+       dev_set_name(&timer_dev, "timer");
+
 #ifdef SNDRV_OSS_INFO_DEV_TIMERS
        snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1,
                              "system timer");
 #endif
 
-       if ((err = snd_timer_register_system()) < 0)
+       err = snd_timer_register_system();
+       if (err < 0) {
                pr_err("ALSA: unable to register system timer (%i)\n", err);
-       if ((err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0,
-                                      &snd_timer_f_ops, NULL, "timer")) < 0)
+               put_device(&timer_dev);
+               return err;
+       }
+
+       err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0,
+                                 &snd_timer_f_ops, NULL, &timer_dev);
+       if (err < 0) {
                pr_err("ALSA: unable to register timer device (%i)\n", err);
+               snd_timer_free_all();
+               put_device(&timer_dev);
+               return err;
+       }
+
        snd_timer_proc_init();
        return 0;
 }
 
 static void __exit alsa_timer_exit(void)
 {
-       struct list_head *p, *n;
-
-       snd_unregister_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0);
-       /* unregister the system timer */
-       list_for_each_safe(p, n, &snd_timer_list) {
-               struct snd_timer *timer = list_entry(p, struct snd_timer, device_list);
-               snd_timer_free(timer);
-       }
+       snd_unregister_device(&timer_dev);
+       snd_timer_free_all();
+       put_device(&timer_dev);
        snd_timer_proc_done();
 #ifdef SNDRV_OSS_INFO_DEV_TIMERS
        snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1);
index 7ea53399404dc59f3823dd3e92a2c4c41df10f03..7f9126efc1e51229373316b25e965e92ffbc08a9 100644 (file)
@@ -181,8 +181,7 @@ static void loopback_timer_start(struct loopback_pcm *dpcm)
        }
        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);
+       mod_timer(&dpcm->timer, jiffies + tick);
 }
 
 /* call in cable->lock */
index 5d0dfb787cece4e9cfc4eb95e09ea6ba6ffb38a6..d11baaf0f0b4a43d63b5e805ab970e72755e2605 100644 (file)
@@ -245,9 +245,8 @@ struct dummy_systimer_pcm {
 
 static void dummy_systimer_rearm(struct dummy_systimer_pcm *dpcm)
 {
-       dpcm->timer.expires = jiffies +
-               (dpcm->frac_period_rest + dpcm->rate - 1) / dpcm->rate;
-       add_timer(&dpcm->timer);
+       mod_timer(&dpcm->timer, jiffies +
+               (dpcm->frac_period_rest + dpcm->rate - 1) / dpcm->rate);
 }
 
 static void dummy_systimer_update(struct dummy_systimer_pcm *dpcm)
@@ -340,9 +339,8 @@ static int dummy_systimer_create(struct snd_pcm_substream *substream)
        if (!dpcm)
                return -ENOMEM;
        substream->runtime->private_data = dpcm;
-       init_timer(&dpcm->timer);
-       dpcm->timer.data = (unsigned long) dpcm;
-       dpcm->timer.function = dummy_systimer_callback;
+       setup_timer(&dpcm->timer, dummy_systimer_callback,
+                       (unsigned long) dpcm);
        spin_lock_init(&dpcm->lock);
        dpcm->substream = substream;
        return 0;
index bcca825a1c8dc6fb1fce435ba9744aa0f2c5de4e..bdcb5721393b1b326497e7a9e4fa43c60a2c3ee5 100644 (file)
@@ -1094,8 +1094,7 @@ static int snd_ml403_ac97cr_free(struct snd_ml403_ac97cr *ml403_ac97cr)
        if (ml403_ac97cr->capture_irq >= 0)
                free_irq(ml403_ac97cr->capture_irq, ml403_ac97cr);
        /* give back "port" */
-       if (ml403_ac97cr->port != NULL)
-               iounmap(ml403_ac97cr->port);
+       iounmap(ml403_ac97cr->port);
        kfree(ml403_ac97cr);
        PDEBUG(INIT_INFO, "free(): (done)\n");
        return 0;
@@ -1238,14 +1237,11 @@ snd_ml403_ac97cr_mixer(struct snd_ml403_ac97cr *ml403_ac97cr)
 }
 
 static int
-snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device,
-                    struct snd_pcm **rpcm)
+snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device)
 {
        struct snd_pcm *pcm;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
        err = snd_pcm_new(ml403_ac97cr->card, "ML403AC97CR/1", device, 1, 1,
                          &pcm);
        if (err < 0)
@@ -1263,8 +1259,6 @@ snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device,
                                          snd_dma_continuous_data(GFP_KERNEL),
                                          64 * 1024,
                                          128 * 1024);
-       if (rpcm)
-               *rpcm = pcm;
        return 0;
 }
 
@@ -1298,7 +1292,7 @@ static int snd_ml403_ac97cr_probe(struct platform_device *pfdev)
                return err;
        }
        PDEBUG(INIT_INFO, "probe(): mixer done\n");
-       err = snd_ml403_ac97cr_pcm(ml403_ac97cr, 0, NULL);
+       err = snd_ml403_ac97cr_pcm(ml403_ac97cr, 0);
        if (err < 0) {
                snd_card_free(card);
                return err;
index e3a90d043f03aa7025cbbd2609b44eedab41d298..776596b5ee0570975eb5df3761cf33cc8baf0f9c 100644 (file)
@@ -28,7 +28,7 @@
  *
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -176,8 +176,7 @@ static void snd_mpu401_uart_timer(unsigned long data)
 
        spin_lock_irqsave(&mpu->timer_lock, flags);
        /*mpu->mode |= MPU401_MODE_TIMER;*/
-       mpu->timer.expires = 1 + jiffies;
-       add_timer(&mpu->timer);
+       mod_timer(&mpu->timer,  1 + jiffies);
        spin_unlock_irqrestore(&mpu->timer_lock, flags);
        if (mpu->rmidi)
                _snd_mpu401_uart_interrupt(mpu);
@@ -192,11 +191,9 @@ static void snd_mpu401_uart_add_timer (struct snd_mpu401 *mpu, int input)
 
        spin_lock_irqsave (&mpu->timer_lock, flags);
        if (mpu->timer_invoked == 0) {
-               init_timer(&mpu->timer);
-               mpu->timer.data = (unsigned long)mpu;
-               mpu->timer.function = snd_mpu401_uart_timer;
-               mpu->timer.expires = 1 + jiffies;
-               add_timer(&mpu->timer);
+               setup_timer(&mpu->timer, snd_mpu401_uart_timer,
+                           (unsigned long)mpu);
+               mod_timer(&mpu->timer, 1 + jiffies);
        } 
        mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER :
                MPU401_MODE_OUTPUT_TIMER;
index 15769447688f2d807ed43912085ad00e53ec72af..30e8a1d5bc87116db97e19cd1c1e718a69f19d39 100644 (file)
@@ -414,8 +414,7 @@ static void snd_mtpav_output_timer(unsigned long data)
 
        spin_lock_irqsave(&chip->spinlock, flags);
        /* reprogram timer */
-       chip->timer.expires = 1 + jiffies;
-       add_timer(&chip->timer);
+       mod_timer(&chip->timer, 1 + jiffies);
        /* process each port */
        for (p = 0; p <= chip->num_ports * 2 + MTPAV_PIDX_BROADCAST; p++) {
                struct mtpav_port *portp = &chip->ports[p];
@@ -428,8 +427,7 @@ static void snd_mtpav_output_timer(unsigned long data)
 /* spinlock held! */
 static void snd_mtpav_add_output_timer(struct mtpav *chip)
 {
-       chip->timer.expires = 1 + jiffies;
-       add_timer(&chip->timer);
+       mod_timer(&chip->timer, 1 + jiffies);
 }
 
 /* spinlock held! */
@@ -704,15 +702,13 @@ static int snd_mtpav_probe(struct platform_device *dev)
 
        mtp_card = card->private_data;
        spin_lock_init(&mtp_card->spinlock);
-       init_timer(&mtp_card->timer);
        mtp_card->card = card;
        mtp_card->irq = -1;
        mtp_card->share_irq = 0;
        mtp_card->inmidistate = 0;
        mtp_card->outmidihwport = 0xffffffff;
-       init_timer(&mtp_card->timer);
-       mtp_card->timer.function = snd_mtpav_output_timer;
-       mtp_card->timer.data = (unsigned long) mtp_card;
+       setup_timer(&mtp_card->timer, snd_mtpav_output_timer,
+                   (unsigned long) mtp_card);
 
        card->private_free = snd_mtpav_free;
 
index f66af5884c4066cadcad107378e8ca30b32f0f69..369cef212ea90a8c0798cc204ad8fc9cfe075053 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include <sound/opl3.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/init.h>
index 6c6d09a51f42838dc19d98dc63836f53839b5d2a..f62780ed64adcc85465447838ee3b5d794690937 100644 (file)
@@ -258,12 +258,10 @@ void snd_opl3_timer_func(unsigned long data)
        spin_unlock_irqrestore(&opl3->voice_lock, flags);
 
        spin_lock_irqsave(&opl3->sys_timer_lock, flags);
-       if (again) {
-               opl3->tlist.expires = jiffies + 1;      /* invoke again */
-               add_timer(&opl3->tlist);
-       } else {
+       if (again)
+               mod_timer(&opl3->tlist, jiffies + 1);   /* invoke again */
+       else
                opl3->sys_timer_status = 0;
-       }
        spin_unlock_irqrestore(&opl3->sys_timer_lock, flags);
 }
 
@@ -275,8 +273,7 @@ static void snd_opl3_start_timer(struct snd_opl3 *opl3)
        unsigned long flags;
        spin_lock_irqsave(&opl3->sys_timer_lock, flags);
        if (! opl3->sys_timer_status) {
-               opl3->tlist.expires = jiffies + 1;
-               add_timer(&opl3->tlist);
+               mod_timer(&opl3->tlist, jiffies + 1);
                opl3->sys_timer_status = 1;
        }
        spin_unlock_irqrestore(&opl3->sys_timer_lock, flags);
index 68399538e435ffbbd324175258bde0f3949827a2..a9f618e06a22bc5f8722932d31e02bfe7fec82b2 100644 (file)
@@ -247,9 +247,7 @@ static int snd_opl3_seq_new_device(struct snd_seq_device *dev)
        }
 
        /* setup system timer */
-       init_timer(&opl3->tlist);
-       opl3->tlist.function = snd_opl3_timer_func;
-       opl3->tlist.data = (unsigned long) opl3;
+       setup_timer(&opl3->tlist, snd_opl3_timer_func, (unsigned long) opl3);
        spin_lock_init(&opl3->sys_timer_lock);
        opl3->sys_timer_status = 0;
 
index b953fb4aa298031a294a7b673a38f27037438f92..3b0ee42a534336b83cf8f362184789ac6679538c 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
 
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_DESCRIPTION("OPL4 driver");
index 4b91adc0238ca4bc855065c2a0af32ef23d9cf33..7bc1e58c95aa56bc4fac2efd45f87bfb7f69cca6 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "opl4_local.h"
 #include <linux/delay.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <sound/asoundef.h>
 
 /* GM2 controllers */
index 2adc7548ffca7ce8869d558d5f6c7d3751f0d691..d9647bd84d0f49e9b532fa1cbeb685645dfe33b9 100644 (file)
@@ -13,7 +13,7 @@
 #include <sound/pcm.h>
 #include <linux/input.h>
 #include <linux/delay.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include "pcsp_input.h"
 #include "pcsp.h"
 
index 0ecf8a453e0112cb56a76ec2035ad2c196fec87f..bfc25811985f157c48a5746642fb71e3bc9559fb 100644 (file)
@@ -14,7 +14,7 @@
 
 #include <linux/init.h>
 #include <linux/input.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include "pcsp.h"
 #include "pcsp_input.h"
 
index 29ebaa4ec0fda8ff02bc36daa41f9e26927c1e66..3689f5f6be6498b1aa19dfb72f6446987c591686 100644 (file)
@@ -10,8 +10,8 @@
 #include <linux/gfp.h>
 #include <linux/moduleparam.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
 #include <sound/pcm.h>
-#include <asm/io.h>
 #include "pcsp.h"
 
 static bool nforce_wa;
index 13a34e3c63823d8c604d636157a2044e2626d8e9..1927b89e1d1f6b2e302da1e4fc7337850906f689 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/rawmidi.h>
 #include <sound/initval.h>
@@ -44,8 +45,6 @@
 #include <linux/serial_reg.h>
 #include <linux/jiffies.h>
 
-#include <asm/io.h>
-
 MODULE_DESCRIPTION("MIDI serial u16550");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{ALSA, MIDI serial u16550}}");
@@ -174,9 +173,8 @@ static inline void snd_uart16550_add_timer(struct snd_uart16550 *uart)
 {
        if (!uart->timer_running) {
                /* timer 38600bps * 10bit * 16byte */
-               uart->buffer_timer.expires = jiffies + (HZ+255)/256;
+               mod_timer(&uart->buffer_timer, jiffies + (HZ + 255) / 256);
                uart->timer_running = 1;
-               add_timer(&uart->buffer_timer);
        }
 }
 
@@ -830,9 +828,8 @@ static int snd_uart16550_create(struct snd_card *card,
        uart->prev_in = 0;
        uart->rstatus = 0;
        memset(uart->prev_status, 0x80, sizeof(unsigned char) * SNDRV_SERIAL_MAX_OUTS);
-       init_timer(&uart->buffer_timer);
-       uart->buffer_timer.function = snd_uart16550_buffer_timer;
-       uart->buffer_timer.data = (unsigned long)uart;
+       setup_timer(&uart->buffer_timer, snd_uart16550_buffer_timer,
+                   (unsigned long)uart);
        uart->timer_running = 0;
 
        /* Register device */
index fc05a37fd017db4cc20bdcbfa4786cd0c5f8f741..289f041706cd2526be2743281ef6f1b94be49a5b 100644 (file)
 #include <linux/device.h>
 #include <linux/firmware.h>
 #include <linux/module.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/asoundef.h>
 #include <sound/info.h>
-#include <asm/io.h>
 #include <sound/vx_core.h>
 #include "vx_cmd.h"
 
index c6bba99a90b285a939865eb57bd97de3d7646d31..88844881cbff99179eb68f6aff288598945d07c7 100644 (file)
@@ -89,6 +89,7 @@ int snd_ak4113_create(struct snd_card *card, ak4113_read_t *read,
        chip->private_data = private_data;
        INIT_DELAYED_WORK(&chip->work, ak4113_stats);
        atomic_set(&chip->wq_processing, 0);
+       mutex_init(&chip->reinit_mutex);
 
        for (reg = 0; reg < AK4113_WRITABLE_REGS ; reg++)
                chip->regmap[reg] = pgm[reg];
@@ -141,7 +142,9 @@ void snd_ak4113_reinit(struct ak4113 *chip)
 {
        if (atomic_inc_return(&chip->wq_processing) == 1)
                cancel_delayed_work_sync(&chip->work);
+       mutex_lock(&chip->reinit_mutex);
        ak4113_init_regs(chip);
+       mutex_unlock(&chip->reinit_mutex);
        /* bring up statistics / event queing */
        if (atomic_dec_and_test(&chip->wq_processing))
                schedule_delayed_work(&chip->work, HZ / 10);
@@ -636,3 +639,19 @@ static void ak4113_stats(struct work_struct *work)
        if (atomic_dec_and_test(&chip->wq_processing))
                schedule_delayed_work(&chip->work, HZ / 10);
 }
+
+#ifdef CONFIG_PM
+void snd_ak4113_suspend(struct ak4113 *chip)
+{
+       atomic_inc(&chip->wq_processing); /* don't schedule new work */
+       cancel_delayed_work_sync(&chip->work);
+}
+EXPORT_SYMBOL(snd_ak4113_suspend);
+
+void snd_ak4113_resume(struct ak4113 *chip)
+{
+       atomic_dec(&chip->wq_processing);
+       snd_ak4113_reinit(chip);
+}
+EXPORT_SYMBOL(snd_ak4113_resume);
+#endif
index b70e6eccbd035372e48098188f32aa99e83b4ea5..5a4cf3fab4ae868d3d571fdb70587e22dca8f4fa 100644 (file)
@@ -100,6 +100,7 @@ int snd_ak4114_create(struct snd_card *card,
        chip->private_data = private_data;
        INIT_DELAYED_WORK(&chip->work, ak4114_stats);
        atomic_set(&chip->wq_processing, 0);
+       mutex_init(&chip->reinit_mutex);
 
        for (reg = 0; reg < 6; reg++)
                chip->regmap[reg] = pgm[reg];
@@ -122,6 +123,7 @@ int snd_ak4114_create(struct snd_card *card,
        snd_ak4114_free(chip);
        return err < 0 ? err : -EIO;
 }
+EXPORT_SYMBOL(snd_ak4114_create);
 
 void snd_ak4114_reg_write(struct ak4114 *chip, unsigned char reg, unsigned char mask, unsigned char val)
 {
@@ -131,6 +133,7 @@ void snd_ak4114_reg_write(struct ak4114 *chip, unsigned char reg, unsigned char
                reg_write(chip, reg,
                          (chip->txcsb[reg-AK4114_REG_TXCSB0] & ~mask) | val);
 }
+EXPORT_SYMBOL(snd_ak4114_reg_write);
 
 static void ak4114_init_regs(struct ak4114 *chip)
 {
@@ -154,11 +157,14 @@ void snd_ak4114_reinit(struct ak4114 *chip)
 {
        if (atomic_inc_return(&chip->wq_processing) == 1)
                cancel_delayed_work_sync(&chip->work);
+       mutex_lock(&chip->reinit_mutex);
        ak4114_init_regs(chip);
+       mutex_unlock(&chip->reinit_mutex);
        /* bring up statistics / event queing */
        if (atomic_dec_and_test(&chip->wq_processing))
                schedule_delayed_work(&chip->work, HZ / 10);
 }
+EXPORT_SYMBOL(snd_ak4114_reinit);
 
 static unsigned int external_rate(unsigned char rcs1)
 {
@@ -503,6 +509,7 @@ int snd_ak4114_build(struct ak4114 *ak4114,
        schedule_delayed_work(&ak4114->work, HZ / 10);
        return 0;
 }
+EXPORT_SYMBOL(snd_ak4114_build);
 
 /* notify kcontrols if any parameters are changed */
 static void ak4114_notify(struct ak4114 *ak4114,
@@ -558,6 +565,7 @@ int snd_ak4114_external_rate(struct ak4114 *ak4114)
        rcs1 = reg_read(ak4114, AK4114_REG_RCS1);
        return external_rate(rcs1);
 }
+EXPORT_SYMBOL(snd_ak4114_external_rate);
 
 int snd_ak4114_check_rate_and_errors(struct ak4114 *ak4114, unsigned int flags)
 {
@@ -605,6 +613,7 @@ int snd_ak4114_check_rate_and_errors(struct ak4114 *ak4114, unsigned int flags)
        }
        return res;
 }
+EXPORT_SYMBOL(snd_ak4114_check_rate_and_errors);
 
 static void ak4114_stats(struct work_struct *work)
 {
@@ -616,9 +625,18 @@ static void ak4114_stats(struct work_struct *work)
                schedule_delayed_work(&chip->work, HZ / 10);
 }
 
-EXPORT_SYMBOL(snd_ak4114_create);
-EXPORT_SYMBOL(snd_ak4114_reg_write);
-EXPORT_SYMBOL(snd_ak4114_reinit);
-EXPORT_SYMBOL(snd_ak4114_build);
-EXPORT_SYMBOL(snd_ak4114_external_rate);
-EXPORT_SYMBOL(snd_ak4114_check_rate_and_errors);
+#ifdef CONFIG_PM
+void snd_ak4114_suspend(struct ak4114 *chip)
+{
+       atomic_inc(&chip->wq_processing); /* don't schedule new work */
+       cancel_delayed_work_sync(&chip->work);
+}
+EXPORT_SYMBOL(snd_ak4114_suspend);
+
+void snd_ak4114_resume(struct ak4114 *chip)
+{
+       atomic_dec(&chip->wq_processing);
+       snd_ak4114_reinit(chip);
+}
+EXPORT_SYMBOL(snd_ak4114_resume);
+#endif
index 88452e899bd94124ddffe1ad3485d7b9896aeddf..48848909a5a95f6776e262788755b0501ec59563 100644 (file)
@@ -91,9 +91,7 @@ int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t
        chip->read = read;
        chip->write = write;
        chip->private_data = private_data;
-       init_timer(&chip->timer);
-       chip->timer.data = (unsigned long)chip;
-       chip->timer.function = snd_ak4117_timer;
+       setup_timer(&chip->timer, snd_ak4117_timer, (unsigned long)chip);
 
        for (reg = 0; reg < 5; reg++)
                chip->regmap[reg] = pgm[reg];
@@ -139,8 +137,7 @@ void snd_ak4117_reinit(struct ak4117 *chip)
        /* release powerdown, everything is initialized now */
        reg_write(chip, AK4117_REG_PWRDN, old | AK4117_RST | AK4117_PWN);
        chip->init = 0;
-       chip->timer.expires = 1 + jiffies;
-       add_timer(&chip->timer);
+       mod_timer(&chip->timer, 1 + jiffies);
 }
 
 static unsigned int external_rate(unsigned char rcs1)
@@ -540,8 +537,7 @@ static void snd_ak4117_timer(unsigned long data)
        if (chip->init)
                return;
        snd_ak4117_check_rate_and_errors(chip, 0);
-       chip->timer.expires = 1 + jiffies;
-       add_timer(&chip->timer);
+       mod_timer(&chip->timer, 1 + jiffies);
 }
 
 EXPORT_SYMBOL(snd_ak4117_create);
index 67dbfde837ab852ca7ca9b36ee4b2d0b3594a55b..c65731088aa297ee8a7959126645a5795d335faa 100644 (file)
@@ -21,7 +21,7 @@
  *
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
index f481a41e027eb132a2acfd1632f8351fe4daa8b6..769226515f0d6d43fa3f05f73c2db11c0385ba14 100644 (file)
@@ -142,7 +142,6 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard,
        struct snd_card *card;
        struct snd_ad1816a *chip;
        struct snd_opl3 *opl3;
-       struct snd_timer *timer;
 
        error = snd_card_new(&pcard->card->dev,
                             index[dev], id[dev], THIS_MODULE,
@@ -172,7 +171,7 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard,
        sprintf(card->longname, "%s, SS at 0x%lx, irq %d, dma %d&%d",
                card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
 
-       if ((error = snd_ad1816a_pcm(chip, 0, NULL)) < 0) {
+       if ((error = snd_ad1816a_pcm(chip, 0)) < 0) {
                snd_card_free(card);
                return error;
        }
@@ -182,7 +181,7 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard,
                return error;
        }
 
-       error = snd_ad1816a_timer(chip, 0, &timer);
+       error = snd_ad1816a_timer(chip, 0);
        if (error < 0) {
                snd_card_free(card);
                return error;
index 01a07986f4a3dcffb89aa8b7d00338616f73c864..5c815f5fb044906f5e76cafe0c46e9107b2e0bd2 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/tlv.h>
 #include <sound/ad1816a.h>
 
-#include <asm/io.h>
 #include <asm/dma.h>
 
 static inline int snd_ad1816a_busy_wait(struct snd_ad1816a *chip)
@@ -675,7 +675,7 @@ static struct snd_pcm_ops snd_ad1816a_capture_ops = {
        .pointer =      snd_ad1816a_capture_pointer,
 };
 
-int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm)
+int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device)
 {
        int error;
        struct snd_pcm *pcm;
@@ -697,13 +697,10 @@ int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm)
                                              64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
 
        chip->pcm = pcm;
-       if (rpcm)
-               *rpcm = pcm;
        return 0;
 }
 
-int snd_ad1816a_timer(struct snd_ad1816a *chip, int device,
-                     struct snd_timer **rtimer)
+int snd_ad1816a_timer(struct snd_ad1816a *chip, int device)
 {
        struct snd_timer *timer;
        struct snd_timer_id tid;
@@ -720,8 +717,6 @@ int snd_ad1816a_timer(struct snd_ad1816a *chip, int device,
        timer->private_data = chip;
        chip->timer = timer;
        timer->hw = snd_ad1816a_timer_table;
-       if (rtimer)
-               *rtimer = timer;
        return 0;
 }
 
index 093f22a464d7494e373bf6e64c5842613ea8f971..f159da4ec890b856dbedb0e3d83970a7839b7a78 100644 (file)
@@ -88,7 +88,6 @@ static int snd_ad1848_probe(struct device *dev, unsigned int n)
 {
        struct snd_card *card;
        struct snd_wss *chip;
-       struct snd_pcm *pcm;
        int error;
 
        error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card);
@@ -103,7 +102,7 @@ static int snd_ad1848_probe(struct device *dev, unsigned int n)
 
        card->private_data = chip;
 
-       error = snd_wss_pcm(chip, 0, &pcm);
+       error = snd_wss_pcm(chip, 0);
        if (error < 0)
                goto out;
 
@@ -112,10 +111,10 @@ static int snd_ad1848_probe(struct device *dev, unsigned int n)
                goto out;
 
        strcpy(card->driver, "AD1848");
-       strcpy(card->shortname, pcm->name);
+       strcpy(card->shortname, chip->pcm->name);
 
        sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
-               pcm->name, chip->port, irq[n], dma1[n]);
+               chip->pcm->name, chip->port, irq[n], dma1[n]);
        if (thinkpad[n])
                strcat(card->longname, " [Thinkpad]");
 
index 32d01525211d34432229c1ca2f90bacc9ccf5665..bc9ea306ee02283275fb8f253b7a869cabde6c49 100644 (file)
@@ -233,7 +233,7 @@ static int snd_card_als100_probe(int dev,
                        irq[dev], dma8[dev], dma16[dev]);
        }
 
-       if ((error = snd_sb16dsp_pcm(chip, 0, &chip->pcm)) < 0) {
+       if ((error = snd_sb16dsp_pcm(chip, 0)) < 0) {
                snd_card_free(card);
                return error;
        }
index 0ea75fc620725599b817736482dfef306f5de285..fff186fa621ee94924ca79ad5e91d9104bc27fd6 100644 (file)
@@ -29,7 +29,7 @@
     activation method (full-duplex audio!).
 */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/time.h>
@@ -215,7 +215,7 @@ static int snd_card_azt2320_probe(int dev,
        sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i",
                card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
 
-       error = snd_wss_pcm(chip, 0, NULL);
+       error = snd_wss_pcm(chip, 0);
        if (error < 0) {
                snd_card_free(card);
                return error;
@@ -225,7 +225,7 @@ static int snd_card_azt2320_probe(int dev,
                snd_card_free(card);
                return error;
        }
-       error = snd_wss_timer(chip, 0, NULL);
+       error = snd_wss_timer(chip, 0);
        if (error < 0) {
                snd_card_free(card);
                return error;
index 4778852a1201388645d15c54f4f67cbd2abd3142..2c89d95da674658f780ea475b0f2b3d55f59f0fc 100644 (file)
@@ -307,7 +307,7 @@ static int snd_cmi8328_probe(struct device *pdev, unsigned int ndev)
        if (err < 0)
                goto error;
 
-       err = snd_wss_pcm(cmi->wss, 0, NULL);
+       err = snd_wss_pcm(cmi->wss, 0);
        if (err < 0)
                goto error;
 
@@ -318,7 +318,7 @@ static int snd_cmi8328_probe(struct device *pdev, unsigned int ndev)
        if (err < 0)
                goto error;
 
-       if (snd_wss_timer(cmi->wss, 0, NULL) < 0)
+       if (snd_wss_timer(cmi->wss, 0) < 0)
                snd_printk(KERN_WARNING "error initializing WSS timer\n");
 
        if (mpuport[ndev] == SNDRV_AUTO_PORT) {
index 7dba07a4343aecfbebbb2c97c43e47b87936e768..282cd75d2235659729e58e558e2872bbfbb3f20d 100644 (file)
@@ -92,7 +92,6 @@ static int snd_cs4231_probe(struct device *dev, unsigned int n)
 {
        struct snd_card *card;
        struct snd_wss *chip;
-       struct snd_pcm *pcm;
        int error;
 
        error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card);
@@ -106,15 +105,15 @@ static int snd_cs4231_probe(struct device *dev, unsigned int n)
 
        card->private_data = chip;
 
-       error = snd_wss_pcm(chip, 0, &pcm);
+       error = snd_wss_pcm(chip, 0);
        if (error < 0)
                goto out;
 
        strcpy(card->driver, "CS4231");
-       strcpy(card->shortname, pcm->name);
+       strcpy(card->shortname, chip->pcm->name);
 
        sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
-               pcm->name, chip->port, irq[n], dma1[n]);
+               chip->pcm->name, chip->port, irq[n], dma1[n]);
        if (dma2[n] >= 0)
                sprintf(card->longname + strlen(card->longname), "&%d", dma2[n]);
 
@@ -122,7 +121,7 @@ static int snd_cs4231_probe(struct device *dev, unsigned int n)
        if (error < 0)
                goto out;
 
-       error = snd_wss_timer(chip, 0, NULL);
+       error = snd_wss_timer(chip, 0);
        if (error < 0)
                goto out;
 
index 750f51c904fcb446b0726109516f04c1bd348bac..9d7582c90a95d90a66290c6e386aa4749b8ff056 100644 (file)
@@ -382,7 +382,6 @@ static int snd_cs423x_card_new(struct device *pdev, int dev,
 static int snd_cs423x_probe(struct snd_card *card, int dev)
 {
        struct snd_card_cs4236 *acard;
-       struct snd_pcm *pcm;
        struct snd_wss *chip;
        struct snd_opl3 *opl3;
        int err;
@@ -404,7 +403,7 @@ static int snd_cs423x_probe(struct snd_card *card, int dev)
        acard->chip = chip;
        if (chip->hardware & WSS_HW_CS4236B_MASK) {
 
-               err = snd_cs4236_pcm(chip, 0, &pcm);
+               err = snd_cs4236_pcm(chip, 0);
                if (err < 0)
                        return err;
 
@@ -412,7 +411,7 @@ static int snd_cs423x_probe(struct snd_card *card, int dev)
                if (err < 0)
                        return err;
        } else {
-               err = snd_wss_pcm(chip, 0, &pcm);
+               err = snd_wss_pcm(chip, 0);
                if (err < 0)
                        return err;
 
@@ -420,17 +419,17 @@ static int snd_cs423x_probe(struct snd_card *card, int dev)
                if (err < 0)
                        return err;
        }
-       strcpy(card->driver, pcm->name);
-       strcpy(card->shortname, pcm->name);
+       strcpy(card->driver, chip->pcm->name);
+       strcpy(card->shortname, chip->pcm->name);
        sprintf(card->longname, "%s at 0x%lx, irq %i, dma %i",
-               pcm->name,
+               chip->pcm->name,
                chip->port,
                irq[dev],
                dma1[dev]);
        if (dma2[dev] >= 0)
                sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]);
 
-       err = snd_wss_timer(chip, 0, NULL);
+       err = snd_wss_timer(chip, 0);
        if (err < 0)
                return err;
 
index c5adca300632b16c744e92a09580c02cd932472d..2b7cc596f4c6a89239821d598c0caf2c47409f02 100644 (file)
@@ -79,7 +79,7 @@
  *
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/time.h>
@@ -376,17 +376,14 @@ int snd_cs4236_create(struct snd_card *card,
        return 0;
 }
 
-int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm)
+int snd_cs4236_pcm(struct snd_wss *chip, int device)
 {
-       struct snd_pcm *pcm;
        int err;
        
-       err = snd_wss_pcm(chip, device, &pcm);
+       err = snd_wss_pcm(chip, device);
        if (err < 0)
                return err;
-       pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX;
-       if (rpcm)
-               *rpcm = pcm;
+       chip->pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX;
        return 0;
 }
 
index 76001fe0579da1942620ae97f1c0e8bed4aa67fa..1901c2bb6c3bca0cb0ace9a95617f5137a6fa07a 100644 (file)
@@ -138,10 +138,9 @@ static int snd_es1688_probe(struct snd_card *card, unsigned int n)
 {
        struct snd_es1688 *chip = card->private_data;
        struct snd_opl3 *opl3;
-       struct snd_pcm *pcm;
        int error;
 
-       error = snd_es1688_pcm(card, chip, 0, &pcm);
+       error = snd_es1688_pcm(card, chip, 0);
        if (error < 0)
                return error;
 
@@ -150,9 +149,9 @@ static int snd_es1688_probe(struct snd_card *card, unsigned int n)
                return error;
 
        strlcpy(card->driver, "ES1688", sizeof(card->driver));
-       strlcpy(card->shortname, pcm->name, sizeof(card->shortname));
+       strlcpy(card->shortname, chip->pcm->name, sizeof(card->shortname));
        snprintf(card->longname, sizeof(card->longname),
-               "%s at 0x%lx, irq %i, dma %i", pcm->name, chip->port,
+               "%s at 0x%lx, irq %i, dma %i", chip->pcm->name, chip->port,
                 chip->irq, chip->dma8);
 
        if (fm_port[n] == SNDRV_AUTO_PORT)
index b5450143407b2f43041921c081b16e973899986e..e2cf508841b1ef2890eb2f253ec6acddc5be91b8 100644 (file)
 #include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/es1688.h>
 #include <sound/initval.h>
 
-#include <asm/io.h>
 #include <asm/dma.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
@@ -728,8 +728,7 @@ static struct snd_pcm_ops snd_es1688_capture_ops = {
        .pointer =              snd_es1688_capture_pointer,
 };
 
-int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip,
-                  int device, struct snd_pcm **rpcm)
+int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device)
 {
        struct snd_pcm *pcm;
        int err;
@@ -749,9 +748,6 @@ int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip,
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                              snd_dma_isa_data(),
                                              64*1024, 64*1024);
-
-       if (rpcm)
-               *rpcm = pcm;
        return 0;
 }
 
index b481bb8c31bc7ba0fad5d62f6b57112fd82ca587..5094b62d8f7718c0888306b5fe4eeca60326c1e2 100644 (file)
@@ -84,8 +84,8 @@
 #include <linux/isapnp.h>
 #include <linux/module.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/dma.h>
 #include <sound/core.h>
 #include <sound/control.h>
@@ -1687,16 +1687,13 @@ static struct snd_pcm_ops snd_es18xx_capture_ops = {
        .pointer =      snd_es18xx_capture_pointer,
 };
 
-static int snd_es18xx_pcm(struct snd_card *card, int device,
-                         struct snd_pcm **rpcm)
+static int snd_es18xx_pcm(struct snd_card *card, int device)
 {
        struct snd_es18xx *chip = card->private_data;
         struct snd_pcm *pcm;
        char str[16];
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
        sprintf(str, "ES%x", chip->version);
        if (chip->caps & ES18XX_PCM2)
                err = snd_pcm_new(card, str, device, 2, 1, &pcm);
@@ -1722,9 +1719,6 @@ static int snd_es18xx_pcm(struct snd_card *card, int device,
                                              snd_dma_isa_data(),
                                              64*1024,
                                              chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
-
-        if (rpcm)
-               *rpcm = pcm;
        return 0;
 }
 
@@ -2154,7 +2148,7 @@ static int snd_audiodrive_probe(struct snd_card *card, int dev)
                        chip->port,
                        irq[dev], dma1[dev]);
 
-       err = snd_es18xx_pcm(card, 0, NULL);
+       err = snd_es18xx_pcm(card, 0);
        if (err < 0)
                return err;
 
index 1eb2b1ec0fd93c8a288a521f8e35f184ee7ebd69..32278847884f018a90b20c8312bd203c78a97673 100644 (file)
@@ -569,7 +569,7 @@ static int snd_galaxy_probe(struct device *dev, unsigned int n)
        if (err < 0)
                goto error;
 
-       err = snd_wss_pcm(chip, 0, NULL);
+       err = snd_wss_pcm(chip, 0);
        if (err < 0)
                goto error;
 
@@ -577,7 +577,7 @@ static int snd_galaxy_probe(struct device *dev, unsigned int n)
        if (err < 0)
                goto error;
 
-       err = snd_wss_timer(chip, 0, NULL);
+       err = snd_wss_timer(chip, 0);
        if (err < 0)
                goto error;
 
diff --git a/sound/isa/gus/gus_instr.c b/sound/isa/gus/gus_instr.c
deleted file mode 100644 (file)
index 4dc9caf..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- *  Routines for Gravis UltraSound soundcards - Synthesizer
- *  Copyright (c) by 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/time.h>
-#include <sound/core.h>
-#include <sound/gus.h>
-
-/*
- *
- */
-
-int snd_gus_iwffff_put_sample(void *private_data, struct iwffff_wave *wave,
-                             char __user *data, long len, int atomic)
-{
-       struct snd_gus_card *gus = private_data;
-       struct snd_gf1_mem_block *block;
-       int err;
-
-       if (wave->format & IWFFFF_WAVE_ROM)
-               return 0;       /* it's probably ok - verify the address? */
-       if (wave->format & IWFFFF_WAVE_STEREO)
-               return -EINVAL; /* not supported */
-       block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc,
-                                 SNDRV_GF1_MEM_OWNER_WAVE_IWFFFF,
-                                 NULL, wave->size,
-                                 wave->format & IWFFFF_WAVE_16BIT, 1,
-                                 wave->share_id);
-       if (block == NULL)
-               return -ENOMEM;
-       err = snd_gus_dram_write(gus, data,
-                                block->ptr, wave->size);
-       if (err < 0) {
-               snd_gf1_mem_lock(&gus->gf1.mem_alloc, 0);
-               snd_gf1_mem_xfree(&gus->gf1.mem_alloc, block);
-               snd_gf1_mem_lock(&gus->gf1.mem_alloc, 1);
-               return err;
-       }
-       wave->address.memory = block->ptr;
-       return 0;
-}
-
-int snd_gus_iwffff_get_sample(void *private_data, struct iwffff_wave *wave,
-                             char __user *data, long len, int atomic)
-{
-       struct snd_gus_card *gus = private_data;
-
-       return snd_gus_dram_read(gus, data, wave->address.memory, wave->size,
-                                wave->format & IWFFFF_WAVE_ROM ? 1 : 0);
-}
-
-int snd_gus_iwffff_remove_sample(void *private_data, struct iwffff_wave *wave,
-                                int atomic)
-{
-       struct snd_gus_card *gus = private_data;
-
-       if (wave->format & IWFFFF_WAVE_ROM)
-               return 0;       /* it's probably ok - verify the address? */    
-       return snd_gf1_mem_free(&gus->gf1.mem_alloc, wave->address.memory);
-}
-
-/*
- *
- */
-
-int snd_gus_gf1_put_sample(void *private_data, struct gf1_wave *wave,
-                          char __user *data, long len, int atomic)
-{
-       struct snd_gus_card *gus = private_data;
-       struct snd_gf1_mem_block *block;
-       int err;
-
-       if (wave->format & GF1_WAVE_STEREO)
-               return -EINVAL; /* not supported */
-       block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc,
-                                 SNDRV_GF1_MEM_OWNER_WAVE_GF1,
-                                 NULL, wave->size,
-                                 wave->format & GF1_WAVE_16BIT, 1,
-                                 wave->share_id);
-       if (block == NULL)
-               return -ENOMEM;
-       err = snd_gus_dram_write(gus, data,
-                                block->ptr, wave->size);
-       if (err < 0) {
-               snd_gf1_mem_lock(&gus->gf1.mem_alloc, 0);
-               snd_gf1_mem_xfree(&gus->gf1.mem_alloc, block);
-               snd_gf1_mem_lock(&gus->gf1.mem_alloc, 1);
-               return err;
-       }
-       wave->address.memory = block->ptr;
-       return 0;
-}
-
-int snd_gus_gf1_get_sample(void *private_data, struct gf1_wave *wave,
-                          char __user *data, long len, int atomic)
-{
-       struct snd_gus_card *gus = private_data;
-
-       return snd_gus_dram_read(gus, data, wave->address.memory, wave->size, 0);
-}
-
-int snd_gus_gf1_remove_sample(void *private_data, struct gf1_wave *wave,
-                             int atomic)
-{
-       struct snd_gus_card *gus = private_data;
-
-       return snd_gf1_mem_free(&gus->gf1.mem_alloc, wave->address.memory);
-}
-
-/*
- *
- */
-
-int snd_gus_simple_put_sample(void *private_data, struct simple_instrument *instr,
-                             char __user *data, long len, int atomic)
-{
-       struct snd_gus_card *gus = private_data;
-       struct snd_gf1_mem_block *block;
-       int err;
-
-       if (instr->format & SIMPLE_WAVE_STEREO)
-               return -EINVAL; /* not supported */
-       block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc,
-                                 SNDRV_GF1_MEM_OWNER_WAVE_SIMPLE,
-                                 NULL, instr->size,
-                                 instr->format & SIMPLE_WAVE_16BIT, 1,
-                                 instr->share_id);
-       if (block == NULL)
-               return -ENOMEM;
-       err = snd_gus_dram_write(gus, data, block->ptr, instr->size);
-       if (err < 0) {
-               snd_gf1_mem_lock(&gus->gf1.mem_alloc, 0);
-               snd_gf1_mem_xfree(&gus->gf1.mem_alloc, block);
-               snd_gf1_mem_lock(&gus->gf1.mem_alloc, 1);
-               return err;
-       }
-       instr->address.memory = block->ptr;
-       return 0;
-}
-
-int snd_gus_simple_get_sample(void *private_data, struct simple_instrument *instr,
-                             char __user *data, long len, int atomic)
-{
-       struct snd_gus_card *gus = private_data;
-
-       return snd_gus_dram_read(gus, data, instr->address.memory, instr->size, 0);
-}
-
-int snd_gus_simple_remove_sample(void *private_data, struct simple_instrument *instr,
-                                int atomic)
-{
-       struct snd_gus_card *gus = private_data;
-
-       return snd_gf1_mem_free(&gus->gf1.mem_alloc, instr->address.memory);
-}
index 2dcf45bf7293f1d68a3391226110ce34cc2b721d..25f6788ccef36b3c785843f1a83ceb40716e7333 100644 (file)
@@ -849,7 +849,7 @@ static struct snd_pcm_ops snd_gf1_pcm_capture_ops = {
        .pointer =      snd_gf1_pcm_capture_pointer,
 };
 
-int snd_gf1_pcm_new(struct snd_gus_card * gus, int pcm_dev, int control_index, struct snd_pcm ** rpcm)
+int snd_gf1_pcm_new(struct snd_gus_card *gus, int pcm_dev, int control_index)
 {
        struct snd_card *card;
        struct snd_kcontrol *kctl;
@@ -857,8 +857,6 @@ int snd_gf1_pcm_new(struct snd_gus_card * gus, int pcm_dev, int control_index, s
        struct snd_pcm_substream *substream;
        int capture, err;
 
-       if (rpcm)
-               *rpcm = NULL;
        card = gus->card;
        capture = !gus->interwave && !gus->ess_flag && !gus->ace_flag ? 1 : 0;
        err = snd_pcm_new(card,
@@ -903,8 +901,6 @@ int snd_gf1_pcm_new(struct snd_gus_card * gus, int pcm_dev, int control_index, s
                return err;
        kctl->id.index = control_index;
 
-       if (rpcm)
-               *rpcm = pcm;
        return 0;
 }
 
index 21cc42e4c4be8aa91dc5a910f5013e5cb256da73..3992912743f5d3a33cc0a6aa5e027c262f3be55d 100644 (file)
@@ -241,13 +241,11 @@ static struct snd_rawmidi_ops snd_gf1_uart_input =
        .trigger =      snd_gf1_uart_input_trigger,
 };
 
-int snd_gf1_rawmidi_new(struct snd_gus_card * gus, int device, struct snd_rawmidi ** rrawmidi)
+int snd_gf1_rawmidi_new(struct snd_gus_card *gus, int device)
 {
        struct snd_rawmidi *rmidi;
        int err;
 
-       if (rrawmidi)
-               *rrawmidi = NULL;
        if ((err = snd_rawmidi_new(gus->card, "GF1", device, 1, 1, &rmidi)) < 0)
                return err;
        strcpy(rmidi->name, gus->interwave ? "AMD InterWave" : "GF1");
@@ -256,7 +254,5 @@ int snd_gf1_rawmidi_new(struct snd_gus_card * gus, int device, struct snd_rawmid
        rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
        rmidi->private_data = gus;
        gus->midi_uart = rmidi;
-       if (rrawmidi)
-               *rrawmidi = rmidi;
        return err;
 }
index 7ce29ffa1af9b476ef264cc874591a0d8829415d..f0019715d82ec45cc3fefc58dbecc9d2e06d4352 100644 (file)
@@ -181,12 +181,12 @@ static int snd_gusclassic_probe(struct device *dev, unsigned int n)
        if (error < 0)
                goto out;
 
-       error = snd_gf1_pcm_new(gus, 0, 0, NULL);
+       error = snd_gf1_pcm_new(gus, 0, 0);
        if (error < 0)
                goto out;
 
        if (!gus->ace_flag) {
-               error = snd_gf1_rawmidi_new(gus, 0, NULL);
+               error = snd_gf1_rawmidi_new(gus, 0);
                if (error < 0)
                        goto out;
        }
index 28a16936a397b71207b88504cd6ee1fc0e8ad82a..693d95f4680482a4bd38dbd61c30a268215582bf 100644 (file)
@@ -284,7 +284,7 @@ static int snd_gusextreme_probe(struct device *dev, unsigned int n)
        }
        gus->codec_flag = 1;
 
-       error = snd_es1688_pcm(card, es1688, 0, NULL);
+       error = snd_es1688_pcm(card, es1688, 0);
        if (error < 0)
                goto out;
 
@@ -295,7 +295,7 @@ static int snd_gusextreme_probe(struct device *dev, unsigned int n)
        snd_component_add(card, "ES1688");
 
        if (pcm_channels[n] > 0) {
-               error = snd_gf1_pcm_new(gus, 1, 1, NULL);
+               error = snd_gf1_pcm_new(gus, 1, 1);
                if (error < 0)
                        goto out;
        }
index 39df36ca3acbe7438d2dc3bd6e0644683c1f0f53..8216e8d8f017bfbdc915142e63543abaab936797 100644 (file)
@@ -309,7 +309,7 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev)
        if (err < 0)
                goto _err;
 
-       err = snd_wss_pcm(wss, 0, NULL);
+       err = snd_wss_pcm(wss, 0);
        if (err < 0)
                goto _err;
 
@@ -317,19 +317,19 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev)
        if (err < 0)
                goto _err;
 
-       err = snd_wss_timer(wss, 2, NULL);
+       err = snd_wss_timer(wss, 2);
        if (err < 0)
                goto _err;
 
        if (pcm_channels[dev] > 0) {
-               if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0)
+               if ((err = snd_gf1_pcm_new(gus, 1, 1)) < 0)
                        goto _err;
        }
        err = snd_gusmax_mixer(wss);
        if (err < 0)
                goto _err;
 
-       err = snd_gf1_rawmidi_new(gus, 0, NULL);
+       err = snd_gf1_rawmidi_new(gus, 0);
        if (err < 0)
                goto _err;
 
index ad55e5cb8e941207f6034593ad5afa996f18b2ff..70d0040484c89c7e2bd0d15303a917c71154b729 100644 (file)
@@ -647,7 +647,6 @@ static int snd_interwave_probe(struct snd_card *card, int dev)
 #ifdef SNDRV_STB
        struct snd_i2c_bus *i2c_bus;
 #endif
-       struct snd_pcm *pcm;
        char *str;
        int err;
 
@@ -695,14 +694,15 @@ static int snd_interwave_probe(struct snd_card *card, int dev)
        if (err < 0)
                return err;
 
-       err = snd_wss_pcm(wss, 0, &pcm);
+       err = snd_wss_pcm(wss, 0);
        if (err < 0)
                return err;
 
-       sprintf(pcm->name + strlen(pcm->name), " rev %c", gus->revision + 'A');
-       strcat(pcm->name, " (codec)");
+       sprintf(wss->pcm->name + strlen(wss->pcm->name), " rev %c",
+               gus->revision + 'A');
+       strcat(wss->pcm->name, " (codec)");
 
-       err = snd_wss_timer(wss, 2, NULL);
+       err = snd_wss_timer(wss, 2);
        if (err < 0)
                return err;
 
@@ -711,7 +711,7 @@ static int snd_interwave_probe(struct snd_card *card, int dev)
                return err;
 
        if (pcm_channels[dev] > 0) {
-               err = snd_gf1_pcm_new(gus, 1, 1, NULL);
+               err = snd_gf1_pcm_new(gus, 1, 1);
                if (err < 0)
                        return err;
        }
@@ -740,7 +740,7 @@ static int snd_interwave_probe(struct snd_card *card, int dev)
 #endif
 
        gus->uart_enable = midi[dev];
-       if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0)
+       if ((err = snd_gf1_rawmidi_new(gus, 0)) < 0)
                return err;
 
 #ifndef SNDRV_STB
index 1cee18fb28a8941975e0caf752b9c65102053761..835d4aa26761e5beea169912cbdde1a884036d89 100644 (file)
@@ -679,8 +679,7 @@ static struct snd_pcm_ops snd_msnd_capture_ops = {
 };
 
 
-int snd_msnd_pcm(struct snd_card *card, int device,
-                       struct snd_pcm **rpcm)
+int snd_msnd_pcm(struct snd_card *card, int device)
 {
        struct snd_msnd *chip = card->private_data;
        struct snd_pcm  *pcm;
@@ -696,9 +695,6 @@ int snd_msnd_pcm(struct snd_card *card, int device,
        pcm->private_data = chip;
        strcpy(pcm->name, "Hurricane");
 
-
-       if (rpcm)
-               *rpcm = pcm;
        return 0;
 }
 EXPORT_SYMBOL(snd_msnd_pcm);
index dbac3a42347b7db65a2394daeebf4a6a86529f41..5f3c7dcd9f9dda1da7335d984f08f1e03fa47701 100644 (file)
@@ -297,7 +297,7 @@ int snd_msnd_disable_irq(struct snd_msnd *chip);
 void snd_msnd_dsp_halt(struct snd_msnd *chip, struct file *file);
 int snd_msnd_DAPQ(struct snd_msnd *chip, int start);
 int snd_msnd_DARQ(struct snd_msnd *chip, int start);
-int snd_msnd_pcm(struct snd_card *card, int device, struct snd_pcm **rpcm);
+int snd_msnd_pcm(struct snd_card *card, int device);
 
 int snd_msndmidi_new(struct snd_card *card, int device);
 void snd_msndmidi_input_read(void *mpu);
index 5016bf957f51d69778b2ff57b5ad4d7abe5acb97..4c072666115dbd1d2559974fb5701592e7b8ba2a 100644 (file)
@@ -582,7 +582,7 @@ static int snd_msnd_attach(struct snd_card *card)
        if (err < 0)
                goto err_release_region;
 
-       err = snd_msnd_pcm(card, 0, NULL);
+       err = snd_msnd_pcm(card, 0);
        if (err < 0) {
                printk(KERN_ERR LOGNAME ": error creating new PCM device\n");
                goto err_release_region;
@@ -627,8 +627,7 @@ static int snd_msnd_attach(struct snd_card *card)
        return 0;
 
 err_release_region:
-       if (chip->mappedbase)
-               iounmap(chip->mappedbase);
+       iounmap(chip->mappedbase);
        release_mem_region(chip->base, BUFFSIZE);
        release_region(chip->io, DSP_NUMIO);
        free_irq(chip->irq, chip);
index a219bc37816b30228d5fefd6b984deab70307585..ae133633a420c4886181326f933161820de85696 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/pm.h>
 #include <linux/pnp.h>
 #include <linux/module.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/wss.h>
 #include <sound/mpu401.h>
@@ -33,8 +34,6 @@
 #include <sound/initval.h>
 #include <sound/tlv.h>
 
-#include <asm/io.h>
-
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Yamaha OPL3SA2+");
 MODULE_LICENSE("GPL");
@@ -684,7 +683,7 @@ static int snd_opl3sa2_probe(struct snd_card *card, int dev)
                return err;
        }
        chip->wss = wss;
-       err = snd_wss_pcm(wss, 0, NULL);
+       err = snd_wss_pcm(wss, 0);
        if (err < 0)
                return err;
        err = snd_wss_mixer(wss);
@@ -693,7 +692,7 @@ static int snd_opl3sa2_probe(struct snd_card *card, int dev)
        err = snd_opl3sa2_mixer(card);
        if (err < 0)
                return err;
-       err = snd_wss_timer(wss, 0, NULL);
+       err = snd_wss_timer(wss, 0);
        if (err < 0)
                return err;
        if (fm_port[dev] >= 0x340 && fm_port[dev] < 0x400) {
index c2ca681ac51ba7516cf93834df76cf613a6eff2f..3a9067db1a842605518c70eabf84f5691413db00 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/dma.h>
 #include <sound/core.h>
 #include <sound/wss.h>
@@ -1270,8 +1270,6 @@ static int snd_miro_probe(struct snd_card *card)
        int error;
        struct snd_miro *miro = card->private_data;
        struct snd_wss *codec;
-       struct snd_timer *timer;
-       struct snd_pcm *pcm;
        struct snd_rawmidi *rmidi;
 
        if (!miro->res_mc_base) {
@@ -1310,7 +1308,7 @@ static int snd_miro_probe(struct snd_card *card)
        if (error < 0)
                return error;
 
-       error = snd_wss_pcm(codec, 0, &pcm);
+       error = snd_wss_pcm(codec, 0);
        if (error < 0)
                return error;
 
@@ -1318,11 +1316,11 @@ static int snd_miro_probe(struct snd_card *card)
        if (error < 0)
                return error;
 
-       error = snd_wss_timer(codec, 0, &timer);
+       error = snd_wss_timer(codec, 0);
        if (error < 0)
                return error;
 
-       miro->pcm = pcm;
+       miro->pcm = codec->pcm;
 
        error = snd_miro_mixer(card, miro);
        if (error < 0)
@@ -1356,8 +1354,8 @@ static int snd_miro_probe(struct snd_card *card)
 
        strcpy(card->driver, "miro");
        sprintf(card->longname, "%s: OPTi%s, %s at 0x%lx, irq %d, dma %d&%d",
-               card->shortname, miro->name, pcm->name, miro->wss_base + 4,
-               miro->irq, miro->dma1, miro->dma2);
+               card->shortname, miro->name, codec->pcm->name,
+               miro->wss_base + 4, miro->irq, miro->dma1, miro->dma2);
 
        if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
                rmidi = NULL;
index c9b5828486037b187c5ec64252c19fefb681f54d..0a52660037866b75480f125d04d6ef9a96413bf6 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/delay.h>
 #include <linux/pnp.h>
 #include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/dma.h>
 #include <sound/core.h>
 #include <sound/tlv.h>
@@ -820,10 +820,6 @@ static int snd_opti9xx_probe(struct snd_card *card)
        int xdma2;
        struct snd_opti9xx *chip = card->private_data;
        struct snd_wss *codec;
-#ifdef CS4231
-       struct snd_timer *timer;
-#endif
-       struct snd_pcm *pcm;
        struct snd_rawmidi *rmidi;
        struct snd_hwdep *synth;
 
@@ -855,7 +851,7 @@ static int snd_opti9xx_probe(struct snd_card *card)
        if (error < 0)
                return error;
        chip->codec = codec;
-       error = snd_wss_pcm(codec, 0, &pcm);
+       error = snd_wss_pcm(codec, 0);
        if (error < 0)
                return error;
        error = snd_wss_mixer(codec);
@@ -867,7 +863,7 @@ static int snd_opti9xx_probe(struct snd_card *card)
                return error;
 #endif
 #ifdef CS4231
-       error = snd_wss_timer(codec, 0, &timer);
+       error = snd_wss_timer(codec, 0);
        if (error < 0)
                return error;
 #endif
@@ -884,11 +880,12 @@ static int snd_opti9xx_probe(struct snd_card *card)
        sprintf(card->shortname, "OPTi %s", card->driver);
 #if defined(CS4231) || defined(OPTi93X)
        sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
-               card->shortname, pcm->name,
+               card->shortname, codec->pcm->name,
                chip->wss_base + 4, irq, dma1, xdma2);
 #else
        sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
-               card->shortname, pcm->name, chip->wss_base + 4, irq, dma1);
+               card->shortname, codec->pcm->name, chip->wss_base + 4, irq,
+               dma1);
 #endif /* CS4231 || OPTi93X */
 
        if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
index 45fcdff611f919263d335875144ee67dc78585bf..94c411299e5a0d75b91abeb598eb53dcdb002b19 100644 (file)
 #include <linux/ioport.h>
 #include <linux/export.h>
 #include <linux/delay.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/emu8000.h>
 #include <sound/emu8000_reg.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <linux/init.h>
 #include <sound/control.h>
 #include <sound/initval.h>
@@ -378,13 +378,12 @@ init_arrays(struct snd_emu8000 *emu)
 static void
 size_dram(struct snd_emu8000 *emu)
 {
-       int i, size, detected_size;
+       int i, size;
 
        if (emu->dram_checked)
                return;
 
        size = 0;
-       detected_size = 0;
 
        /* write out a magic number */
        snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_WRITE);
@@ -392,10 +391,19 @@ size_dram(struct snd_emu8000 *emu)
        EMU8000_SMALW_WRITE(emu, EMU8000_DRAM_OFFSET);
        EMU8000_SMLD_WRITE(emu, UNIQUE_ID1);
        snd_emu8000_init_fm(emu); /* This must really be here and not 2 lines back even */
+       snd_emu8000_write_wait(emu);
 
-       while (size < EMU8000_MAX_DRAM) {
+       /*
+        * Detect first 512 KiB.  If a write succeeds at the beginning of a
+        * 512 KiB page we assume that the whole page is there.
+        */
+       EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET);
+       EMU8000_SMLD_READ(emu); /* discard stale data  */
+       if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1)
+               goto skip_detect;   /* No RAM */
+       snd_emu8000_read_wait(emu);
 
-               size += 512 * 1024;  /* increment 512kbytes */
+       for (size = 512 * 1024; size < EMU8000_MAX_DRAM; size += 512 * 1024) {
 
                /* Write a unique data on the test address.
                 * if the address is out of range, the data is written on
@@ -431,18 +439,9 @@ size_dram(struct snd_emu8000 *emu)
                snd_emu8000_read_wait(emu);
 
                /* Otherwise, it's valid memory. */
-               detected_size = size + 512 * 1024;
-       }
-
-       /* Distinguish 512 KiB from 0. */
-       if (detected_size == 0) {
-               snd_emu8000_read_wait(emu);
-               EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET);
-               EMU8000_SMLD_READ(emu); /* discard stale data  */
-               if (EMU8000_SMLD_READ(emu) == UNIQUE_ID1)
-                       detected_size = 512 * 1024;
        }
 
+skip_detect:
        /* wait until FULL bit in SMAxW register is false */
        for (i = 0; i < 10000; i++) {
                if ((EMU8000_SMALW_READ(emu) & 0x80000000) == 0)
@@ -454,10 +453,10 @@ size_dram(struct snd_emu8000 *emu)
        snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_CLOSE);
        snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_CLOSE);
 
-       snd_printdd("EMU8000 [0x%lx]: %d Kb on-board memory detected\n",
-                   emu->port1, detected_size/1024);
+       pr_info("EMU8000 [0x%lx]: %d KiB on-board DRAM detected\n",
+                   emu->port1, size/1024);
 
-       emu->mem_size = detected_size;
+       emu->mem_size = size;
        emu->dram_checked = 1;
 }
 
index c99c6078be3376fa792f8b335e31f57a80a7c221..71d13c0bb7463c9147d5b7169fa71ca2e458d766 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 #include "emu8000_local.h"
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <linux/moduleparam.h>
 
 static int emu8000_reset_addr;
index 2f85c66f8e383c9feed771021a66626d775a4947..250fd0006b5360fb5ac2befd534e38c9cd5a7a20 100644 (file)
@@ -207,8 +207,7 @@ static void emu8k_pcm_timer_func(unsigned long data)
        rec->last_ptr = ptr;
 
        /* reprogram timer */
-       rec->timer.expires = jiffies + 1;
-       add_timer(&rec->timer);
+       mod_timer(&rec->timer, jiffies + 1);
 
        /* update period */
        if (rec->period_pos >= (int)rec->period_size) {
@@ -240,9 +239,7 @@ static int emu8k_pcm_open(struct snd_pcm_substream *subs)
        runtime->private_data = rec;
 
        spin_lock_init(&rec->timer_lock);
-       init_timer(&rec->timer);
-       rec->timer.function = emu8k_pcm_timer_func;
-       rec->timer.data = (unsigned long)rec;
+       setup_timer(&rec->timer, emu8k_pcm_timer_func, (unsigned long)rec);
 
        runtime->hw = emu8k_pcm_hw;
        runtime->hw.buffer_bytes_max = emu->mem_size - LOOP_BLANK_SIZE * 3;
@@ -359,8 +356,7 @@ static void start_voice(struct snd_emu8k_pcm *rec, int ch)
        /* start timer */
        spin_lock_irqsave(&rec->timer_lock, flags);
        if (! rec->timer_running) {
-               rec->timer.expires = jiffies + 1;
-               add_timer(&rec->timer);
+               mod_timer(&rec->timer, jiffies + 1);
                rec->timer_running = 1;
        }
        spin_unlock_irqrestore(&rec->timer_lock, flags);
index 95b39beb61c19b8d10f38b5e65e86b1fb7acdf9b..72332dfada9a3f2d089cecd7d257ae0121223a8d 100644 (file)
@@ -103,8 +103,7 @@ static int snd_emu8000_delete_device(struct snd_seq_device *dev)
        hw = dev->driver_data;
        if (hw->pcm)
                snd_device_free(dev->card, hw->pcm);
-       if (hw->emu)
-               snd_emux_free(hw->emu);
+       snd_emux_free(hw->emu);
        snd_util_memhdr_free(hw->memhdr);
        hw->emu = NULL;
        hw->memhdr = NULL;
index 90d2eba549e90d51fde8c71834dfb6f2cd52e895..6b4884d052a56097c38feea055f94ede24103f70 100644 (file)
@@ -297,7 +297,7 @@ static int snd_jazz16_probe(struct device *devptr, unsigned int dev)
                "Media Vision Jazz16 at 0x%lx, irq %d, dma8 %d, dma16 %d",
                port[dev], xirq, xdma8, xdma16);
 
-       err = snd_sb8dsp_pcm(chip, 0, NULL);
+       err = snd_sb8dsp_pcm(chip, 0);
        if (err < 0)
                goto err_free;
        err = snd_sbmixer_new(chip);
index 3f694543a7ea7774f3719647adc0cc3a399c0809..4a7d7c89808fd0fbc574a0e3b66b4b31ea7c11e2 100644 (file)
@@ -374,7 +374,7 @@ static int snd_sb16_probe(struct snd_card *card, int dev)
        if (! is_isapnp_selected(dev) && (err = snd_sb16dsp_configure(chip)) < 0)
                return err;
 
-       if ((err = snd_sb16dsp_pcm(chip, 0, &chip->pcm)) < 0)
+       if ((err = snd_sb16dsp_pcm(chip, 0)) < 0)
                return err;
 
        strcpy(card->driver,
index 72b10f4f3e707385f980342820df5a226823e3f7..8b2d6c6bfe97e14585cee17ab5159829787173b6 100644 (file)
@@ -33,7 +33,7 @@
  *
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/dma.h>
 #include <linux/init.h>
 #include <linux/time.h>
@@ -860,19 +860,18 @@ static struct snd_pcm_ops snd_sb16_capture_ops = {
        .pointer =      snd_sb16_capture_pointer,
 };
 
-int snd_sb16dsp_pcm(struct snd_sb * chip, int device, struct snd_pcm ** rpcm)
+int snd_sb16dsp_pcm(struct snd_sb *chip, int device)
 {
        struct snd_card *card = chip->card;
        struct snd_pcm *pcm;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
        if ((err = snd_pcm_new(card, "SB16 DSP", device, 1, 1, &pcm)) < 0)
                return err;
        sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff);
        pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
        pcm->private_data = chip;
+       chip->pcm = pcm;
 
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb16_playback_ops);
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb16_capture_ops);
@@ -885,9 +884,6 @@ int snd_sb16dsp_pcm(struct snd_sb * chip, int device, struct snd_pcm ** rpcm)
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                              snd_dma_isa_data(),
                                              64*1024, 128*1024);
-
-       if (rpcm)
-               *rpcm = pcm;
        return 0;
 }
 
index 6c32b3aa34af169b3c409768ce5d82e4cb86539b..b8e2391c33ff1de53f2a66620329c34f3f1604eb 100644 (file)
@@ -157,7 +157,7 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev)
                goto _err;
        }
 
-       if ((err = snd_sb8dsp_pcm(chip, 0, NULL)) < 0)
+       if ((err = snd_sb8dsp_pcm(chip, 0)) < 0)
                goto _err;
 
        if ((err = snd_sbmixer_new(chip)) < 0)
@@ -182,7 +182,7 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev)
                        goto _err;
        }
 
-       if ((err = snd_sb8dsp_midi(chip, 0, NULL)) < 0)
+       if ((err = snd_sb8dsp_midi(chip, 0)) < 0)
                goto _err;
 
        strcpy(card->driver, chip->hardware == SB_HW_PRO ? "SB Pro" : "SB8");
index 24d4121ab0e06a7c083cfeb7ba8486fd91b4217e..9043397fe62fa63e7113cce3b0148c1a1a260c72 100644 (file)
@@ -30,7 +30,7 @@
  *   Cleaned up and rewrote lowlevel routines.
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/dma.h>
 #include <linux/init.h>
 #include <linux/time.h>
@@ -594,15 +594,13 @@ static struct snd_pcm_ops snd_sb8_capture_ops = {
        .pointer =              snd_sb8_capture_pointer,
 };
 
-int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm)
+int snd_sb8dsp_pcm(struct snd_sb *chip, int device)
 {
        struct snd_card *card = chip->card;
        struct snd_pcm *pcm;
        int err;
        size_t max_prealloc = 64 * 1024;
 
-       if (rpcm)
-               *rpcm = NULL;
        if ((err = snd_pcm_new(card, "SB8 DSP", device, 1, 1, &pcm)) < 0)
                return err;
        sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff);
@@ -618,8 +616,6 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm)
                                              snd_dma_isa_data(),
                                              64*1024, max_prealloc);
 
-       if (rpcm)
-               *rpcm = pcm;
        return 0;
 }
 
index 988a8b73475f26f65e1f7f8bbb344cfff16532ba..d551c50e549f92d8e954405b96294ee7a83f0ec3 100644 (file)
@@ -26,7 +26,7 @@
  *   Added full duplex UART mode for DSP version 2.0 and later.
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/sb.h>
@@ -216,8 +216,7 @@ static void snd_sb8dsp_midi_output_timer(unsigned long data)
        unsigned long flags;
 
        spin_lock_irqsave(&chip->open_lock, flags);
-       chip->midi_timer.expires = 1 + jiffies;
-       add_timer(&chip->midi_timer);
+       mod_timer(&chip->midi_timer, 1 + jiffies);
        spin_unlock_irqrestore(&chip->open_lock, flags);        
        snd_sb8dsp_midi_output_write(substream);
 }
@@ -231,11 +230,10 @@ static void snd_sb8dsp_midi_output_trigger(struct snd_rawmidi_substream *substre
        spin_lock_irqsave(&chip->open_lock, flags);
        if (up) {
                if (!(chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER)) {
-                       init_timer(&chip->midi_timer);
-                       chip->midi_timer.function = snd_sb8dsp_midi_output_timer;
-                       chip->midi_timer.data = (unsigned long) substream;
-                       chip->midi_timer.expires = 1 + jiffies;
-                       add_timer(&chip->midi_timer);
+                       setup_timer(&chip->midi_timer,
+                                   snd_sb8dsp_midi_output_timer,
+                                   (unsigned long) substream);
+                       mod_timer(&chip->midi_timer, 1 + jiffies);
                        chip->open |= SB_OPEN_MIDI_OUTPUT_TRIGGER;
                }
        } else {
@@ -263,13 +261,11 @@ static struct snd_rawmidi_ops snd_sb8dsp_midi_input =
        .trigger =      snd_sb8dsp_midi_input_trigger,
 };
 
-int snd_sb8dsp_midi(struct snd_sb *chip, int device, struct snd_rawmidi ** rrawmidi)
+int snd_sb8dsp_midi(struct snd_sb *chip, int device)
 {
        struct snd_rawmidi *rmidi;
        int err;
 
-       if (rrawmidi)
-               *rrawmidi = NULL;
        if ((err = snd_rawmidi_new(chip->card, "SB8 MIDI", device, 1, 1, &rmidi)) < 0)
                return err;
        strcpy(rmidi->name, "SB8 MIDI");
@@ -280,7 +276,5 @@ int snd_sb8dsp_midi(struct snd_sb *chip, int device, struct snd_rawmidi ** rrawm
                rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
        rmidi->private_data = chip;
        chip->rmidi = rmidi;
-       if (rrawmidi)
-               *rrawmidi = rmidi;
        return 0;
 }
index f22b4480828e031e761dbd8ee52dbcae2c0160db..787a4ade4afdd56e3687a6146db94addb9982dbe 100644 (file)
 #include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/sb.h>
 #include <sound/initval.h>
 
-#include <asm/io.h>
 #include <asm/dma.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
index e403334a19ad0b98d73e79c4df5de705995da8f3..add1d3f99609b90100cb73063a3cc80b514c4ca9 100644 (file)
@@ -19,7 +19,7 @@
  *
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/time.h>
 #include <sound/core.h>
index 15a152eaa2e89ee2cd8c7d10fc3c670b1c6ff3c8..51cfa7615f72e82064373401e6bed9842c2c2019 100644 (file)
@@ -625,7 +625,7 @@ static int snd_sc6000_probe(struct device *devptr, unsigned int dev)
        if (err < 0)
                goto err_unmap2;
 
-       err = snd_wss_pcm(chip, 0, NULL);
+       err = snd_wss_pcm(chip, 0);
        if (err < 0) {
                snd_printk(KERN_ERR PFX
                           "error creating new WSS PCM device\n");
index 44405df7d4becffcf82db3b5e9a1152f65eed304..7b248cdf06e2166d82dfc69ea318247fc8eca6f7 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <linux/init.h>
 #include <linux/err.h>
+#include <linux/io.h>
 #include <linux/isa.h>
 #include <linux/delay.h>
 #include <linux/firmware.h>
@@ -877,7 +878,6 @@ static int create_ad1845(struct snd_card *card, unsigned port,
                             codec_type, WSS_HWSHARE_DMA1, &chip);
        if (!err) {
                unsigned long flags;
-               struct snd_pcm *pcm;
 
                if (sscape->type != SSCAPE_VIVO) {
                        /*
@@ -893,7 +893,7 @@ static int create_ad1845(struct snd_card *card, unsigned port,
 
                }
 
-               err = snd_wss_pcm(chip, 0, &pcm);
+               err = snd_wss_pcm(chip, 0);
                if (err < 0) {
                        snd_printk(KERN_ERR "sscape: No PCM device "
                                            "for AD1845 chip\n");
@@ -907,7 +907,7 @@ static int create_ad1845(struct snd_card *card, unsigned port,
                        goto _error;
                }
                if (chip->hardware != WSS_HW_AD1848) {
-                       err = snd_wss_timer(chip, 0, NULL);
+                       err = snd_wss_timer(chip, 0);
                        if (err < 0) {
                                snd_printk(KERN_ERR "sscape: No timer device "
                                                    "for AD1845 chip\n");
index bfbf38cf984175966e2cdfca4a83647f56c99192..a0987a57c8a918e6eff7fd94a871da35db0a3839 100644 (file)
@@ -380,11 +380,11 @@ snd_wavefront_probe (struct snd_card *card, int dev)
                return err;
        }
 
-       err = snd_wss_pcm(chip, 0, NULL);
+       err = snd_wss_pcm(chip, 0);
        if (err < 0)
                return err;
 
-       err = snd_wss_timer(chip, 0, NULL);
+       err = snd_wss_timer(chip, 0);
        if (err < 0)
                return err;
 
index b77883c7ee762f5ff86891754f31a536627e3be7..b5a19708473aaff9713cd19479b8cd3ff8367a93 100644 (file)
@@ -16,7 +16,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/init.h>
 #include <linux/time.h>
 #include <linux/wait.h>
index 7dc9916822977d1eb739fba86a57caeae7a87b0e..8a80fc6a616b6ada647a70ccef9f80abd33352e1 100644 (file)
@@ -47,7 +47,7 @@
  *  
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/init.h>
 #include <linux/time.h>
 #include <linux/wait.h>
@@ -356,8 +356,7 @@ static void snd_wavefront_midi_output_timer(unsigned long data)
        unsigned long flags;
        
        spin_lock_irqsave (&midi->virtual, flags);
-       midi->timer.expires = 1 + jiffies;
-       add_timer(&midi->timer);
+       mod_timer(&midi->timer, 1 + jiffies);
        spin_unlock_irqrestore (&midi->virtual, flags);
        snd_wavefront_midi_output_write(card);
 }
@@ -384,11 +383,10 @@ static void snd_wavefront_midi_output_trigger(struct snd_rawmidi_substream *subs
        if (up) {
                if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) {
                        if (!midi->istimer) {
-                               init_timer(&midi->timer);
-                               midi->timer.function = snd_wavefront_midi_output_timer;
-                               midi->timer.data = (unsigned long) substream->rmidi->card->private_data;
-                               midi->timer.expires = 1 + jiffies;
-                               add_timer(&midi->timer);
+                               setup_timer(&midi->timer,
+                                           snd_wavefront_midi_output_timer,
+                                           (unsigned long) substream->rmidi->card->private_data);
+                               mod_timer(&midi->timer, 1 + jiffies);
                        }
                        midi->istimer++;
                        midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER;
index e5db001363eee9376d23e79f8a94483f62cd42d1..33f5ec14fcfa27cf1f2e7a7ec9c76fb8c5deb9f6 100644 (file)
@@ -20,7 +20,7 @@
  *
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/delay.h>
index 347bb1bda110920737f37145f14907a4123c4277..913b731d2236a566bc93a7884fa2ab44131f69be 100644 (file)
 #include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/wss.h>
 #include <sound/pcm_params.h>
 #include <sound/tlv.h>
 
-#include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 
@@ -1923,7 +1923,7 @@ static struct snd_pcm_ops snd_wss_capture_ops = {
        .pointer =      snd_wss_capture_pointer,
 };
 
-int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm)
+int snd_wss_pcm(struct snd_wss *chip, int device)
 {
        struct snd_pcm *pcm;
        int err;
@@ -1949,8 +1949,6 @@ int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm)
                                              64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
 
        chip->pcm = pcm;
-       if (rpcm)
-               *rpcm = pcm;
        return 0;
 }
 EXPORT_SYMBOL(snd_wss_pcm);
@@ -1961,7 +1959,7 @@ static void snd_wss_timer_free(struct snd_timer *timer)
        chip->timer = NULL;
 }
 
-int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer)
+int snd_wss_timer(struct snd_wss *chip, int device)
 {
        struct snd_timer *timer;
        struct snd_timer_id tid;
@@ -1980,8 +1978,6 @@ int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer)
        timer->private_free = snd_wss_timer_free;
        timer->hw = snd_wss_timer_table;
        chip->timer = timer;
-       if (rtimer)
-               *rtimer = timer;
        return 0;
 }
 EXPORT_SYMBOL(snd_wss_timer);
index c23f9f95bfa55ec28fc8f0f028739f20765d6434..a8ceef8d1a8ded7ae7de190243e8474e722b17cf 100644 (file)
@@ -675,7 +675,7 @@ static void dsp_write_flush(void)
                timeout);
        clear_bit(F_WRITEFLUSH, &dev.flags);
        if (!signal_pending(current)) {
-               current->state = TASK_INTERRUPTIBLE;
+               __set_current_state(TASK_INTERRUPTIBLE);
                schedule_timeout(get_play_delay_jiffies(DAP_BUFF_SIZE));
        }
        clear_bit(F_WRITING, &dev.flags);
@@ -1288,7 +1288,7 @@ static int __init calibrate_adc(WORD srate)
                       & ~0x0001, dev.SMA + SMA_wCurrHostStatusFlags);
        if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
            chk_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) {
-               current->state = TASK_INTERRUPTIBLE;
+               __set_current_state(TASK_INTERRUPTIBLE);
                schedule_timeout(HZ / 3);
                return 0;
        }
index ca0d6e9f49f5b4a7895a0e1c99408db528b7db80..81314f9e2ccb9c8bffccdc699cca698820081625 100644 (file)
@@ -1228,7 +1228,7 @@ static void __exit cleanup_pss(void)
 {
        if(!pss_no_sound)
        {
-               if(fw_load && pss_synth)
+               if (fw_load)
                        vfree(pss_synth);
                if(pssmss)
                        unload_pss_mss(&cfg2);
index a33e8ce8085bdf2954338727c0404d735dce7b00..213a416b6e0b2c8cc9080742fdbfbe1010c200bc 100644 (file)
@@ -1654,7 +1654,7 @@ static int drain_dac(struct cs4297a_state *s, int nonblock)
         s->dma_dac.hwptr = s->dma_dac.swptr = hwptr;
         spin_unlock_irqrestore(&s->lock, flags);
        remove_wait_queue(&s->dma_dac.wait, &wait);
-       current->state = TASK_RUNNING;
+       __set_current_state(TASK_RUNNING);
        return 0;
 }
 
index 944e0c0154853d8fb31fe4cfa3fbf1b963a3137e..3c494dc93b936d4680aca2a70ccee94d1fba7938 100644 (file)
@@ -487,7 +487,7 @@ static int __init init_trix(void)
 
 static void __exit cleanup_trix(void)
 {
-       if (fw_load && trix_boot)
+       if (fw_load)
                vfree(trix_boot);
        if (sb)
                unload_trix_sb(&cfg2);
index 29604a239c4447b82d14541c5337a62dc10e6f21..99b64cb3cef85245c8895fda62d9025304019fd0 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/dma-mapping.h>
+#include <linux/io.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -52,7 +53,6 @@
 #include <sound/initval.h>
 #include <sound/info.h>
 
-#include <asm/io.h>
 #include <asm/hardware.h>
 #include <asm/parisc-device.h>
 
@@ -893,9 +893,7 @@ snd_harmony_free(struct snd_harmony *h)
        if (h->irq >= 0)
                free_irq(h->irq, h);
 
-       if (h->iobase)
-               iounmap(h->iobase);
-
+       iounmap(h->iobase);
        kfree(h);
        return 0;
 }
index 50dd0086cfb1a3361beffa533990b7aed7f59304..edfc1b8d553ee3c6e1ad4bfd4d424fce7631b292 100644 (file)
@@ -793,6 +793,15 @@ config SND_RME9652
          To compile this driver as a module, choose M here: the module
          will be called snd-rme9652.
 
+config SND_SE6X
+       tristate "Studio Evolution SE6X"
+       depends on SND_OXYGEN=n && SND_VIRTUOSO=n  # PCI ID conflict
+       select SND_OXYGEN_LIB
+       select SND_PCM
+       select SND_MPU401_UART
+       help
+         Say Y or M here only if you actually have this sound card.
+
 config SND_SIS7019
        tristate "SiS 7019 Audio Accelerator"
        depends on X86_32
index 1610c38337afe6887e02074f98446a6c18aadc6e..850a8c984c25005ec9a2c4dca24c7395054d880c 100644 (file)
 #include <linux/compiler.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/io.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/initval.h>
 #include <sound/ac97_codec.h>
 
-#include <asm/io.h>
-
 #include "ad1889.h"
 #include "ac97/ac97_id.h"
 
@@ -623,14 +622,11 @@ snd_ad1889_interrupt(int irq, void *dev_id)
 }
 
 static int
-snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device, struct snd_pcm **rpcm)
+snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device)
 {
        int err;
        struct snd_pcm *pcm;
 
-       if (rpcm)
-               *rpcm = NULL;
-
        err = snd_pcm_new(chip->card, chip->card->driver, device, 1, 1, &pcm);
        if (err < 0)
                return err;
@@ -658,9 +654,6 @@ snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device, struct snd_pcm **rpcm)
                return err;
        }
        
-       if (rpcm)
-               *rpcm = pcm;
-       
        return 0;
 }
 
@@ -859,12 +852,9 @@ snd_ad1889_free(struct snd_ad1889 *chip)
                free_irq(chip->irq, chip);
 
 skip_hw:
-       if (chip->iobase)
-               iounmap(chip->iobase);
-
+       iounmap(chip->iobase);
        pci_release_regions(chip->pci);
        pci_disable_device(chip->pci);
-
        kfree(chip);
        return 0;
 }
@@ -1016,7 +1006,7 @@ snd_ad1889_probe(struct pci_dev *pci,
        if (err < 0)
                goto free_and_ret;
        
-       err = snd_ad1889_pcm_init(chip, 0, NULL);
+       err = snd_ad1889_pcm_init(chip, 0);
        if (err < 0)
                goto free_and_ret;
 
index af89e42b21602c1a3ba9e125e3a643f0a751b35c..c8d499575c012f35e24d3c9472a7f8d196a84fde 100644 (file)
@@ -25,7 +25,7 @@
  *
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -1873,7 +1873,6 @@ static int snd_ali_mixer(struct snd_ali *codec)
 #ifdef CONFIG_PM_SLEEP
 static int ali_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_ali *chip = card->private_data;
        struct snd_ali_image *im;
@@ -1914,16 +1913,11 @@ static int ali_suspend(struct device *dev)
        outl(0xffffffff, ALI_REG(chip, ALI_STOP));
 
        spin_unlock_irq(&chip->reg_lock);
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int ali_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_ali *chip = card->private_data;
        struct snd_ali_image *im;
@@ -1933,15 +1927,6 @@ static int ali_resume(struct device *dev)
        if (!im)
                return 0;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
-
        spin_lock_irq(&chip->reg_lock);
        
        for (i = 0; i < ALI_CHANNELS; i++) {
index 7bb6ac565107ac45bbce62e11938be3637cdced8..57e034f208dc164363323b833c926afe170b195b 100644 (file)
@@ -37,8 +37,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
 
 #include <sound/core.h>
 #include <sound/control.h>
@@ -728,35 +727,20 @@ static int snd_als300_create(struct snd_card *card,
 #ifdef CONFIG_PM_SLEEP
 static int snd_als300_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_als300 *chip = card->private_data;
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        snd_pcm_suspend_all(chip->pcm);
        snd_ac97_suspend(chip->ac97);
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int snd_als300_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_als300 *chip = card->private_data;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
-
        snd_als300_init(chip);
        snd_ac97_resume(chip->ac97);
 
index d3e6424ee65697d774f0de00f108624f6d975c95..a3dea464134d79524a59dbb000b16a73379b4562 100644 (file)
@@ -65,7 +65,7 @@
  * - power management? (card can do voice wakeup according to datasheet!!)
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/gameport.h>
@@ -988,7 +988,6 @@ static void snd_card_als4000_remove(struct pci_dev *pci)
 #ifdef CONFIG_PM_SLEEP
 static int snd_als4000_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_card_als4000 *acard = card->private_data;
        struct snd_sb *chip = acard->chip;
@@ -997,29 +996,15 @@ static int snd_als4000_suspend(struct device *dev)
        
        snd_pcm_suspend_all(chip->pcm);
        snd_sbmixer_suspend(chip);
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int snd_als4000_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_card_als4000 *acard = card->private_data;
        struct snd_sb *chip = acard->chip;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
-
        snd_als4000_configure(chip);
        snd_sbdsp_reset(chip);
        snd_sbmixer_resume(chip);
index e9273fb2a505d44c4d2d4dd2633131f7cfecfc90..e5cd7be85355199d30c5c5db969afe58d9d38fbd 100644 (file)
@@ -540,9 +540,8 @@ static void snd_card_asihpi_pcm_timer_start(struct snd_pcm_substream *
        expiry = HZ / 200;
 
        expiry = max(expiry, 1); /* don't let it be zero! */
-       dpcm->timer.expires = jiffies + expiry;
+       mod_timer(&dpcm->timer, jiffies + expiry);
        dpcm->respawn_timer = 1;
-       add_timer(&dpcm->timer);
 }
 
 static void snd_card_asihpi_pcm_timer_stop(struct snd_pcm_substream *substream)
@@ -1064,9 +1063,8 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
            If internal and other stream playing, can't switch
        */
 
-       init_timer(&dpcm->timer);
-       dpcm->timer.data = (unsigned long) dpcm;
-       dpcm->timer.function = snd_card_asihpi_timer_function;
+       setup_timer(&dpcm->timer, snd_card_asihpi_timer_function,
+                   (unsigned long) dpcm);
        dpcm->substream = substream;
        runtime->private_data = dpcm;
        runtime->private_free = snd_card_asihpi_runtime_free;
@@ -1246,9 +1244,8 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
        if (err)
                return -EIO;
 
-       init_timer(&dpcm->timer);
-       dpcm->timer.data = (unsigned long) dpcm;
-       dpcm->timer.function = snd_card_asihpi_timer_function;
+       setup_timer(&dpcm->timer, snd_card_asihpi_timer_function,
+                   (unsigned long) dpcm);
        dpcm->substream = substream;
        runtime->private_data = dpcm;
        runtime->private_free = snd_card_asihpi_runtime_free;
@@ -2832,14 +2829,11 @@ static int snd_asihpi_hpi_ioctl(struct snd_hwdep *hw, struct file *file,
 /* results in /dev/snd/hwC#D0 file for each card with index #
    also /proc/asound/hwdep will contain '#-00: asihpi (HPI) for each card'
 */
-static int snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi,
-                             int device, struct snd_hwdep **rhwdep)
+static int snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, int device)
 {
        struct snd_hwdep *hw;
        int err;
 
-       if (rhwdep)
-               *rhwdep = NULL;
        err = snd_hwdep_new(asihpi->card, "HPI", device, &hw);
        if (err < 0)
                return err;
@@ -2849,8 +2843,6 @@ static int snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi,
        hw->ops.ioctl = snd_asihpi_hpi_ioctl;
        hw->ops.release = snd_asihpi_hpi_release;
        hw->private_data = asihpi;
-       if (rhwdep)
-               *rhwdep = hw;
        return 0;
 }
 
@@ -2993,7 +2985,7 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
 
        /* always create, can be enabled or disabled dynamically
            by enable_hwdep  module param*/
-       snd_asihpi_hpi_new(asihpi, 0, NULL);
+       snd_asihpi_hpi_new(asihpi, 0);
 
        strcpy(card->driver, "ASIHPI");
 
index 2414d7a2239d325b95cf08077654fad970343f22..2d6364825d4d2a05a81002253b4556ef6999ca10 100644 (file)
@@ -47,7 +47,7 @@
 
 /* operational/messaging errors */
 #define HPI6000_ERROR_MSG_RESP_IDLE_TIMEOUT             901
-
+#define HPI6000_ERROR_RESP_GET_LEN                      902
 #define HPI6000_ERROR_MSG_RESP_GET_RESP_ACK             903
 #define HPI6000_ERROR_MSG_GET_ADR                       904
 #define HPI6000_ERROR_RESP_GET_ADR                      905
@@ -1365,7 +1365,10 @@ static short hpi6000_message_response_sequence(struct hpi_adapter_obj *pao,
                length = hpi_read_word(pdo, HPI_HIF_ADDR(length));
        } while (hpi6000_check_PCI2040_error_flag(pao, H6READ) && --timeout);
        if (!timeout)
-               length = sizeof(struct hpi_response);
+               return HPI6000_ERROR_RESP_GET_LEN;
+
+       if (length > phr->size)
+               return HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL;
 
        /* get the response */
        p_data = (u32 *)phr;
index 6aa677e60555723058acb4a8c0a9cdc5deb17aa5..6610bd096fc93560fd463c5abf5bce44840497be 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <linux/pci.h>
 #include <linux/stringify.h>
 #include <linux/module.h>
@@ -153,6 +153,8 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                goto out;
        }
 
+       res_max_size = min_t(size_t, res_max_size, sizeof(*hr));
+
        switch (hm->h.function) {
        case HPI_SUBSYS_CREATE_ADAPTER:
        case HPI_ADAPTER_DELETE:
@@ -539,10 +541,8 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev)
        hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
 
        /* unmap PCI memory space, mapped during device init. */
-       for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) {
-               if (pci.ap_mem_base[idx])
-                       iounmap(pci.ap_mem_base[idx]);
-       }
+       for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; ++idx)
+               iounmap(pci.ap_mem_base[idx]);
 
        if (pa->irq)
                free_irq(pa->irq, pa);
index 9c1c4452a8ee416c4ea343780a9dfee89a84b94b..d5f15c9bbeda321b949221a9d48be480befd01c7 100644 (file)
@@ -19,7 +19,7 @@
  *
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -1474,7 +1474,6 @@ static int snd_atiixp_mixer_new(struct atiixp *chip, int clock,
  */
 static int snd_atiixp_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct atiixp *chip = card->private_data;
        int i;
@@ -1492,29 +1491,15 @@ static int snd_atiixp_suspend(struct device *dev)
                snd_ac97_suspend(chip->ac97[i]);
        snd_atiixp_aclink_down(chip);
        snd_atiixp_chip_stop(chip);
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int snd_atiixp_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct atiixp *chip = card->private_data;
        int i;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
-
        snd_atiixp_aclink_reset(chip);
        snd_atiixp_chip_start(chip);
 
@@ -1585,8 +1570,7 @@ static int snd_atiixp_free(struct atiixp *chip)
       __hw_end:
        if (chip->irq >= 0)
                free_irq(chip->irq, chip);
-       if (chip->remap_addr)
-               iounmap(chip->remap_addr);
+       iounmap(chip->remap_addr);
        pci_release_regions(chip->pci);
        pci_disable_device(chip->pci);
        kfree(chip);
index b2f63e0727de36345d5fc5915d13f72c65e14f3b..0a38e08164ab8d75c2c92e0a4895878dd90175f3 100644 (file)
@@ -19,7 +19,7 @@
  *
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -1120,7 +1120,6 @@ static int snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock)
  */
 static int snd_atiixp_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct atiixp_modem *chip = card->private_data;
        int i;
@@ -1132,29 +1131,15 @@ static int snd_atiixp_suspend(struct device *dev)
                snd_ac97_suspend(chip->ac97[i]);
        snd_atiixp_aclink_down(chip);
        snd_atiixp_chip_stop(chip);
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int snd_atiixp_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct atiixp_modem *chip = card->private_data;
        int i;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
-
        snd_atiixp_aclink_reset(chip);
        snd_atiixp_chip_start(chip);
 
@@ -1211,8 +1196,7 @@ static int snd_atiixp_free(struct atiixp_modem *chip)
       __hw_end:
        if (chip->irq >= 0)
                free_irq(chip->irq, chip);
-       if (chip->remap_addr)
-               iounmap(chip->remap_addr);
+       iounmap(chip->remap_addr);
        pci_release_regions(chip->pci);
        pci_disable_device(chip->pci);
        kfree(chip);
index 3a8fefefea77cc6b5a73aebcd9d9d89a2000d235..bcc648bf647802fc747b0dfed82ff0dd4742a239 100644 (file)
@@ -17,9 +17,8 @@
 #ifndef __SOUND_AU88X0_H
 #define __SOUND_AU88X0_H
 
-#ifdef __KERNEL__
 #include <linux/pci.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/rawmidi.h>
@@ -27,7 +26,6 @@
 #include <sound/hwdep.h>
 #include <sound/ac97_codec.h>
 #include <sound/tlv.h>
-#endif
 
 #ifndef CHIP_AU8820
 #include "au88x0_eq.h"
index e1cf01949fda7a2959388e1d64c2309566496394..8d2fee7b33bd75edcb634602788ae70b6946418a 100644 (file)
@@ -229,9 +229,7 @@ static int snd_aw2_dev_free(struct snd_device *device)
        if (chip->irq >= 0)
                free_irq(chip->irq, (void *)chip);
        /* release the i/o ports & memory */
-       if (chip->iobase_virt)
-               iounmap(chip->iobase_virt);
-
+       iounmap(chip->iobase_virt);
        pci_release_regions(chip->pci);
        /* disable the PCI entry */
        pci_disable_device(chip->pci);
index 6d24e95367772c352f6ed903ca410e876d1812e5..1d7890459334521d1d2679567d7ba5a1ec26a862 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/pcm.h>
index fdbb9c05c77b74274ee7c07e4056fc7fbc7944e6..a40a2b4c8fd7ac8ae992a928e67c00d1c4091473 100644 (file)
  *  - use MMIO (memory-mapped I/O)? Slightly faster access, e.g. for gameport.
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/init.h>
 #include <linux/bug.h> /* WARN_ONCE */
 #include <linux/pci.h>
@@ -2694,7 +2694,6 @@ snd_azf3328_resume_ac97(const struct snd_azf3328 *chip)
 static int
 snd_azf3328_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_azf3328 *chip = card->private_data;
        u16 *saved_regs_ctrl_u16;
@@ -2720,29 +2719,15 @@ snd_azf3328_suspend(struct device *dev)
                ARRAY_SIZE(chip->saved_regs_mpu), chip->saved_regs_mpu);
        snd_azf3328_suspend_regs(chip, chip->opl3_io,
                ARRAY_SIZE(chip->saved_regs_opl3), chip->saved_regs_opl3);
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int
 snd_azf3328_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        const struct snd_azf3328 *chip = card->private_data;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
-
        snd_azf3328_resume_regs(chip, chip->saved_regs_game, chip->game_io,
                                        ARRAY_SIZE(chip->saved_regs_game));
        snd_azf3328_resume_regs(chip, chip->saved_regs_mpu, chip->mpu_io,
index 058b9973c09c487ad6b4ffa5ccbd7ceb1fe19a8e..5925b7170e25f131e2cdce1fbf9b48f51f557b5b 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/bitops.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -690,8 +690,7 @@ static int snd_bt87x_free(struct snd_bt87x *chip)
                snd_bt87x_stop(chip);
        if (chip->irq >= 0)
                free_irq(chip->irq, chip);
-       if (chip->mmio)
-               iounmap(chip->mmio);
+       iounmap(chip->mmio);
        pci_release_regions(chip->pci);
        pci_disable_device(chip->pci);
        kfree(chip);
index 96af33965b51a19800d38da83a3796f96b56f1a2..dd75b7536fa2ccc457c09e89fe8bcff88e1e47e3 100644 (file)
@@ -1910,7 +1910,6 @@ static void snd_ca0106_remove(struct pci_dev *pci)
 #ifdef CONFIG_PM_SLEEP
 static int snd_ca0106_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_ca0106 *chip = card->private_data;
        int i;
@@ -1923,30 +1922,15 @@ static int snd_ca0106_suspend(struct device *dev)
        snd_ca0106_mixer_suspend(chip);
 
        ca0106_stop_chip(chip);
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int snd_ca0106_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_ca0106 *chip = card->private_data;
        int i;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-
-       if (pci_enable_device(pci) < 0) {
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-
-       pci_set_master(pci);
-
        ca0106_init_chip(chip, 1);
 
        if (chip->details->ac97)
index 68c0eb0a280751b15f9910720b5a5bb38a696981..025805cba7795e27ab365fcf7dd7f5495ace0ee7 100644 (file)
@@ -70,7 +70,7 @@
 #include <sound/ac97_codec.h>
 #include <sound/info.h>
 #include <sound/tlv.h>
-#include <asm/io.h>
+#include <linux/io.h>
 
 #include "ca0106.h"
 
index 4f9c2821bb31188ec2ff9ca9d55999b64bc1a5c7..2c5c28adbefd03175375048c13a9b809ec70862c 100644 (file)
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/moduleparam.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
 #include <sound/info.h>
 #include <sound/asoundef.h>
-#include <asm/io.h>
 
 #include "ca0106.h"
 
index 85ed40339db90f783bd61ae530014c30970f4b43..1d0f2cad2f5a64e84c37f69ce264445f732c99fd 100644 (file)
@@ -20,7 +20,7 @@
 /* Does not work. Warning may block system in capture mode */
 /* #define USE_VAR48KRATE */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -3347,7 +3347,6 @@ static unsigned char saved_mixers[] = {
 
 static int snd_cmipci_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct cmipci *cm = card->private_data;
        int i;
@@ -3366,29 +3365,15 @@ static int snd_cmipci_suspend(struct device *dev)
 
        /* disable ints */
        snd_cmipci_write(cm, CM_REG_INT_HLDCLR, 0);
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int snd_cmipci_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct cmipci *cm = card->private_data;
        int i;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
-
        /* reset / initialize to a sane state */
        snd_cmipci_write(cm, CM_REG_INT_HLDCLR, 0);
        snd_cmipci_ch_reset(cm, CM_CH_PLAY);
index 4c49b5c8a7b3a743cb1c24d4576160e307b0eacb..c296fd0dbc9c4d939e422a32ad42033db571ecee 100644 (file)
@@ -19,7 +19,7 @@
  *
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -973,14 +973,11 @@ static struct snd_pcm_ops snd_cs4281_capture_ops = {
        .pointer =      snd_cs4281_pointer,
 };
 
-static int snd_cs4281_pcm(struct cs4281 *chip, int device,
-                         struct snd_pcm **rpcm)
+static int snd_cs4281_pcm(struct cs4281 *chip, int device)
 {
        struct snd_pcm *pcm;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
        err = snd_pcm_new(chip->card, "CS4281", device, 1, 1, &pcm);
        if (err < 0)
                return err;
@@ -996,8 +993,6 @@ static int snd_cs4281_pcm(struct cs4281 *chip, int device,
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                              snd_dma_pci_data(chip->pci), 64*1024, 512*1024);
 
-       if (rpcm)
-               *rpcm = pcm;
        return 0;
 }
 
@@ -1321,10 +1316,8 @@ static int snd_cs4281_free(struct cs4281 *chip)
 
        if (chip->irq >= 0)
                free_irq(chip->irq, chip);
-       if (chip->ba0)
-               iounmap(chip->ba0);
-       if (chip->ba1)
-               iounmap(chip->ba1);
+       iounmap(chip->ba0);
+       iounmap(chip->ba1);
        pci_release_regions(chip->pci);
        pci_disable_device(chip->pci);
 
@@ -1788,14 +1781,11 @@ static struct snd_rawmidi_ops snd_cs4281_midi_input =
        .trigger =      snd_cs4281_midi_input_trigger,
 };
 
-static int snd_cs4281_midi(struct cs4281 *chip, int device,
-                          struct snd_rawmidi **rrawmidi)
+static int snd_cs4281_midi(struct cs4281 *chip, int device)
 {
        struct snd_rawmidi *rmidi;
        int err;
 
-       if (rrawmidi)
-               *rrawmidi = NULL;
        if ((err = snd_rawmidi_new(chip->card, "CS4281", device, 1, 1, &rmidi)) < 0)
                return err;
        strcpy(rmidi->name, "CS4281");
@@ -1804,8 +1794,6 @@ static int snd_cs4281_midi(struct cs4281 *chip, int device,
        rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
        rmidi->private_data = chip;
        chip->rmidi = rmidi;
-       if (rrawmidi)
-               *rrawmidi = rmidi;
        return 0;
 }
 
@@ -1941,11 +1929,11 @@ static int snd_cs4281_probe(struct pci_dev *pci,
                snd_card_free(card);
                return err;
        }
-       if ((err = snd_cs4281_pcm(chip, 0, NULL)) < 0) {
+       if ((err = snd_cs4281_pcm(chip, 0)) < 0) {
                snd_card_free(card);
                return err;
        }
-       if ((err = snd_cs4281_midi(chip, 0, NULL)) < 0) {
+       if ((err = snd_cs4281_midi(chip, 0)) < 0) {
                snd_card_free(card);
                return err;
        }
@@ -2008,7 +1996,6 @@ static int saved_regs[SUSPEND_REGISTERS] = {
 
 static int cs4281_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct cs4281 *chip = card->private_data;
        u32 ulCLK;
@@ -2047,30 +2034,16 @@ static int cs4281_suspend(struct device *dev)
        ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1);
        ulCLK &= ~CLKCR1_CKRA;
        snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK);
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int cs4281_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct cs4281 *chip = card->private_data;
        unsigned int i;
        u32 ulCLK;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
-
        ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1);
        ulCLK |= CLKCR1_CKRA;
        snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK);
index 6a6858c0782647e4db30ef18e4e39bba7d8e8df9..655fbea1692c0b63c1e7c08d603c1d4c9c449444 100644 (file)
@@ -100,16 +100,16 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci,
        }
        card->private_data = chip;
        chip->accept_valid = mmap_valid[dev];
-       if ((err = snd_cs46xx_pcm(chip, 0, NULL)) < 0) {
+       if ((err = snd_cs46xx_pcm(chip, 0)) < 0) {
                snd_card_free(card);
                return err;
        }
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-       if ((err = snd_cs46xx_pcm_rear(chip,1, NULL)) < 0) {
+       if ((err = snd_cs46xx_pcm_rear(chip, 1)) < 0) {
                snd_card_free(card);
                return err;
        }
-       if ((err = snd_cs46xx_pcm_iec958(chip,2,NULL)) < 0) {
+       if ((err = snd_cs46xx_pcm_iec958(chip, 2)) < 0) {
                snd_card_free(card);
                return err;
        }
@@ -120,13 +120,13 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci,
        }
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
        if (chip->nr_ac97_codecs ==2) {
-               if ((err = snd_cs46xx_pcm_center_lfe(chip,3,NULL)) < 0) {
+               if ((err = snd_cs46xx_pcm_center_lfe(chip, 3)) < 0) {
                        snd_card_free(card);
                        return err;
                }
        }
 #endif
-       if ((err = snd_cs46xx_midi(chip, 0, NULL)) < 0) {
+       if ((err = snd_cs46xx_midi(chip, 0)) < 0) {
                snd_card_free(card);
                return err;
        }
index c49a082c378b6c711e36d74187ef742318be56ce..9c9f89a8be5f4540c7d5f3f822e53147c7c7cf74 100644 (file)
@@ -1737,12 +1737,12 @@ int snd_cs46xx_create(struct snd_card *card,
                      struct snd_cs46xx **rcodec);
 extern const struct dev_pm_ops snd_cs46xx_pm;
 
-int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm);
-int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm);
-int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm);
-int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm);
+int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device);
+int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device);
+int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device);
+int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device);
 int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device);
-int snd_cs46xx_midi(struct snd_cs46xx *chip, int device, struct snd_rawmidi **rmidi);
+int snd_cs46xx_midi(struct snd_cs46xx *chip, int device);
 int snd_cs46xx_start_dsp(struct snd_cs46xx *chip);
 int snd_cs46xx_gameport(struct snd_cs46xx *chip);
 
index 32b44f25b5c8240a8b40e414a2e09ec7d43b2cc8..8d74004b1ed22d0a4478eeddc602e0b1b3b3ed74 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/module.h>
 #include <linux/firmware.h>
 #include <linux/vmalloc.h>
+#include <linux/io.h>
 
 #include <sound/core.h>
 #include <sound/control.h>
@@ -65,8 +66,6 @@
 #include <sound/pcm_params.h>
 #include "cs46xx.h"
 
-#include <asm/io.h>
-
 #include "cs46xx_lib.h"
 #include "dsp_spos.h"
 
@@ -1778,13 +1777,11 @@ static struct snd_pcm_ops snd_cs46xx_capture_indirect_ops = {
 #define MAX_PLAYBACK_CHANNELS  1
 #endif
 
-int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm)
+int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device)
 {
        struct snd_pcm *pcm;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
        if ((err = snd_pcm_new(chip->card, "CS46xx", device, MAX_PLAYBACK_CHANNELS, 1, &pcm)) < 0)
                return err;
 
@@ -1801,23 +1798,16 @@ int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm)
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                              snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
 
-       if (rpcm)
-               *rpcm = pcm;
-
        return 0;
 }
 
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device,
-                       struct snd_pcm **rpcm)
+int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device)
 {
        struct snd_pcm *pcm;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
-
        if ((err = snd_pcm_new(chip->card, "CS46xx - Rear", device, MAX_PLAYBACK_CHANNELS, 0, &pcm)) < 0)
                return err;
 
@@ -1833,21 +1823,14 @@ int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device,
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                              snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
 
-       if (rpcm)
-               *rpcm = pcm;
-
        return 0;
 }
 
-int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device,
-                             struct snd_pcm **rpcm)
+int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device)
 {
        struct snd_pcm *pcm;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
-
        if ((err = snd_pcm_new(chip->card, "CS46xx - Center LFE", device, MAX_PLAYBACK_CHANNELS, 0, &pcm)) < 0)
                return err;
 
@@ -1863,21 +1846,14 @@ int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device,
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                              snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
 
-       if (rpcm)
-               *rpcm = pcm;
-
        return 0;
 }
 
-int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device,
-                         struct snd_pcm **rpcm)
+int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device)
 {
        struct snd_pcm *pcm;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
-
        if ((err = snd_pcm_new(chip->card, "CS46xx - IEC958", device, 1, 0, &pcm)) < 0)
                return err;
 
@@ -1893,9 +1869,6 @@ int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device,
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                              snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
 
-       if (rpcm)
-               *rpcm = pcm;
-
        return 0;
 }
 #endif
@@ -2724,13 +2697,11 @@ static struct snd_rawmidi_ops snd_cs46xx_midi_input =
        .trigger =      snd_cs46xx_midi_input_trigger,
 };
 
-int snd_cs46xx_midi(struct snd_cs46xx *chip, int device, struct snd_rawmidi **rrawmidi)
+int snd_cs46xx_midi(struct snd_cs46xx *chip, int device)
 {
        struct snd_rawmidi *rmidi;
        int err;
 
-       if (rrawmidi)
-               *rrawmidi = NULL;
        if ((err = snd_rawmidi_new(chip->card, "CS46XX", device, 1, 1, &rmidi)) < 0)
                return err;
        strcpy(rmidi->name, "CS46XX");
@@ -2739,8 +2710,6 @@ int snd_cs46xx_midi(struct snd_cs46xx *chip, int device, struct snd_rawmidi **rr
        rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
        rmidi->private_data = chip;
        chip->rmidi = rmidi;
-       if (rrawmidi)
-               *rrawmidi = NULL;
        return 0;
 }
 
@@ -2979,8 +2948,8 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip)
 
        for (idx = 0; idx < 5; idx++) {
                struct snd_cs46xx_region *region = &chip->region.idx[idx];
-               if (region->remap_addr)
-                       iounmap(region->remap_addr);
+
+               iounmap(region->remap_addr);
                release_and_free_resource(region->resource);
        }
 
@@ -3804,7 +3773,6 @@ static unsigned int saved_regs[] = {
 
 static int snd_cs46xx_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_cs46xx *chip = card->private_data;
        int i, amp_saved;
@@ -3829,16 +3797,11 @@ static int snd_cs46xx_suspend(struct device *dev)
        /* disable CLKRUN */
        chip->active_ctrl(chip, -chip->amplifier);
        chip->amplifier = amp_saved; /* restore the status */
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int snd_cs46xx_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_cs46xx *chip = card->private_data;
        int amp_saved;
@@ -3847,15 +3810,6 @@ static int snd_cs46xx_resume(struct device *dev)
 #endif
        unsigned int tmp;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
-
        amp_saved = chip->amplifier;
        chip->amplifier = 0;
        chip->active_ctrl(chip, 1); /* force to on */
index 1c4a0fb3ffefd4144b32acfc4f81fdb2bd19259c..5c99efb004c002336bf09fb618fc832df0ebd64f 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/init.h>
index 8284bc9b585822a12ffba887a3233fd077af98b3..2c90c0bded69c2756a37078c6897d0a7dc40d9b2 100644 (file)
@@ -21,7 +21,7 @@
  */
 
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/init.h>
index b1025507a4670fa538e7e5ddbd5da50b21f3be64..0a8cf94c48581277266cf1d069e17bf8a5886934 100644 (file)
@@ -223,7 +223,7 @@ static int snd_cs5530_create(struct snd_card *card,
                return err;
        }
 
-       err = snd_sb16dsp_pcm(chip->sb, 0, &chip->sb->pcm);
+       err = snd_sb16dsp_pcm(chip->sb, 0);
        if (err < 0) {
                dev_err(card->dev, "Could not create PCM\n");
                snd_cs5530_free(chip);
index 16288e4d338abbb8bb9f09c1dc272813cecd9436..802c33f1cc5957ea7fed404bf49a13c7c351ff85 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
index 34cc60057d0c45c34da1f852a87e19be252c5a3d..06ac5d8da3624c612212b1eb85e7b60c91ec3b30 100644 (file)
@@ -57,7 +57,6 @@ static void snd_cs5535audio_stop_hardware(struct cs5535audio *cs5535au)
 
 static int snd_cs5535audio_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct cs5535audio *cs5535au = card->private_data;
        int i;
@@ -72,34 +71,17 @@ static int snd_cs5535audio_suspend(struct device *dev)
        }
        /* save important regs, then disable aclink in hw */
        snd_cs5535audio_stop_hardware(cs5535au);
-
-       if (pci_save_state(pci)) {
-               dev_err(dev, "pci_save_state failed!\n");
-               return -EIO;
-       }
-       pci_disable_device(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int snd_cs5535audio_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct cs5535audio *cs5535au = card->private_data;
        u32 tmp;
        int timeout;
        int i;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
-
        /* set LNK_WRM_RST to reset AC link */
        cs_writel(cs5535au, ACC_CODEC_CNTL, ACC_CODEC_CNTL_LNK_WRM_RST);
 
index b425aa8ee57858fb11c43f5c1b56bfa6adc8bbca..1cac55fd113992020585ceba4b61a3478a6557f1 100644 (file)
@@ -1985,10 +1985,7 @@ static int hw_card_shutdown(struct hw *hw)
                free_irq(hw->irq, hw);
 
        hw->irq = -1;
-
-       if (hw->mem_base)
-               iounmap(hw->mem_base);
-
+       iounmap(hw->mem_base);
        hw->mem_base = NULL;
 
        if (hw->io_base)
@@ -2099,20 +2096,11 @@ static int hw_suspend(struct hw *hw)
                pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x0);
        }
 
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
-
        return 0;
 }
 
 static int hw_resume(struct hw *hw, struct card_conf *info)
 {
-       struct pci_dev *pci = hw->pci;
-
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-
        /* Re-initialize card hardware. */
        return hw_card_init(hw, info);
 }
index 253899d1379096ea3108c5588aa012b3e4bd9a80..955ad871e9a861dfd444e5ec85f4b9736548778e 100644 (file)
@@ -2110,10 +2110,7 @@ static int hw_card_shutdown(struct hw *hw)
                free_irq(hw->irq, hw);
 
        hw->irq = -1;
-
-       if (hw->mem_base)
-               iounmap(hw->mem_base);
-
+       iounmap(hw->mem_base);
        hw->mem_base = NULL;
 
        if (hw->io_base)
@@ -2209,24 +2206,12 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
 #ifdef CONFIG_PM_SLEEP
 static int hw_suspend(struct hw *hw)
 {
-       struct pci_dev *pci = hw->pci;
-
        hw_card_stop(hw);
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
-
        return 0;
 }
 
 static int hw_resume(struct hw *hw, struct card_conf *info)
 {
-       struct pci_dev *pci = hw->pci;
-
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-
        /* Re-initialize card hardware. */
        return hw_card_init(hw, info);
 }
index 4632946205a82887144e38d849d96973c33b8975..c95da6301677ac47657632af862129d2fa9895d5 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/module.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -51,7 +52,6 @@
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
 #include <sound/initval.h>
-#include <asm/io.h>
 #include <linux/atomic.h>
 #include "echoaudio.h"
 
index f81c839cc8878031cae0b598750dcd7cf9f1a595..3013b4daa19e3b431c2da8d091b3571b4a6d7de4 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/module.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -55,7 +56,6 @@
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
 #include <sound/initval.h>
-#include <asm/io.h>
 #include <linux/atomic.h>
 #include "echoaudio.h"
 
index 3a5346c33d760a16d53c5047bdabd1b63a0468be..1f34a07b0b195925a2640db196000980a0b9a094 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/module.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -63,7 +64,6 @@
 #include <sound/asoundef.h>
 #include <sound/initval.h>
 #include <sound/rawmidi.h>
-#include <asm/io.h>
 #include <linux/atomic.h>
 #include "echoaudio.h"
 
index 21228adaa70cb104b58580ec6392f129a9011708..a962de03ebb68c3fbd32454a5cf4facd521e99c1 100644 (file)
@@ -1872,12 +1872,8 @@ static int snd_echo_free(struct echoaudio *chip)
        if (chip->comm_page)
                snd_dma_free_pages(&chip->commpage_dma_buf);
 
-       if (chip->dsp_registers)
-               iounmap(chip->dsp_registers);
-
+       iounmap(chip->dsp_registers);
        release_and_free_resource(chip->iores);
-
-
        pci_disable_device(chip->pci);
 
        /* release chip data */
@@ -2162,7 +2158,6 @@ ctl_error:
 
 static int snd_echo_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct echoaudio *chip = dev_get_drvdata(dev);
 
        snd_pcm_suspend_all(chip->analog_pcm);
@@ -2188,9 +2183,6 @@ static int snd_echo_suspend(struct device *dev)
        chip->dsp_code = NULL;
        free_irq(chip->irq, chip);
        chip->irq = -1;
-       pci_save_state(pci);
-       pci_disable_device(pci);
-
        return 0;
 }
 
@@ -2204,7 +2196,6 @@ static int snd_echo_resume(struct device *dev)
        u32 pipe_alloc_mask;
        int err;
 
-       pci_restore_state(pci);
        commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL);
        if (commpage_bak == NULL)
                return -ENOMEM;
index 9cb81c5008245916e806b29716aa408f9e750db0..4fa32a2e97dbbcb4164d5babcd2ede7f65f35bb0 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/module.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -55,7 +56,6 @@
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
 #include <sound/initval.h>
-#include <asm/io.h>
 #include <linux/atomic.h>
 #include "echoaudio.h"
 
index 35d3e6eac990ec39a21b6985b528537048726d53..b1bcacaef257a897b69fdc3361e09c23d7452267 100644 (file)
@@ -53,6 +53,7 @@
 #include <linux/module.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -61,7 +62,6 @@
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
 #include <sound/initval.h>
-#include <asm/io.h>
 #include <linux/atomic.h>
 #include "echoaudio.h"
 
index 8d91842d1268b109b74765937019384aac0d4e8e..175af9b1435fcdca3daae39b576ed7776f4e9c2c 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/module.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -53,7 +54,6 @@
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
 #include <sound/initval.h>
-#include <asm/io.h>
 #include <linux/atomic.h>
 #include "echoaudio.h"
 
index 289cb969f5b99ca77862aeb1f841c7ec17fb8512..8c60314e4901c35363a9313b73a8b8b18be90e16 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/module.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -53,7 +54,6 @@
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
 #include <sound/initval.h>
-#include <asm/io.h>
 #include <linux/atomic.h>
 #include "echoaudio.h"
 
index 405a3f2e496f070081dfbc937e3f9bb9e839003b..f7618edfd79c702ec0a5f61166a2e24f435eed45 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/module.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -54,7 +55,6 @@
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
 #include <sound/initval.h>
-#include <asm/io.h>
 #include <linux/atomic.h>
 #include "echoaudio.h"
 
index b392dd776b710c09102a85e7d27423797c66e9b7..12e5d2164dc49d91824946c5367181995c6f922b 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/module.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -61,7 +62,6 @@
 #include <sound/asoundef.h>
 #include <sound/initval.h>
 #include <sound/rawmidi.h>
-#include <asm/io.h>
 #include <linux/atomic.h>
 #include "echoaudio.h"
 
index bc7f730b0ec68360ba59372b6c48161ea27f3e09..6e4023728ef58f46682878d844e245f066cf736c 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/module.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -63,7 +64,6 @@
 #include <sound/asoundef.h>
 #include <sound/initval.h>
 #include <sound/rawmidi.h>
-#include <asm/io.h>
 #include <linux/atomic.h>
 #include "echoaudio.h"
 
index 27a9a6e5db2dc8ad0802e3f32340a15febca40fe..2f7562f1aefb6b77f9931d0c8729a2c338657dbb 100644 (file)
@@ -53,6 +53,7 @@
 #include <linux/module.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -62,7 +63,6 @@
 #include <sound/asoundef.h>
 #include <sound/initval.h>
 #include <sound/rawmidi.h>
-#include <asm/io.h>
 #include <linux/atomic.h>
 #include "echoaudio.h"
 
index d913749d154a352928fcab83bcafc71b134138f6..a8fe58335ddc0659aa19113266fc657860618ac5 100644 (file)
@@ -257,9 +257,8 @@ static void snd_echo_midi_output_trigger(struct snd_rawmidi_substream *substream
        spin_lock_irq(&chip->lock);
        if (up) {
                if (!chip->tinuse) {
-                       init_timer(&chip->timer);
-                       chip->timer.function = snd_echo_midi_output_write;
-                       chip->timer.data = (unsigned long)chip;
+                       setup_timer(&chip->timer, snd_echo_midi_output_write,
+                                   (unsigned long)chip);
                        chip->tinuse = 1;
                }
        } else {
index 3d13875c303d2d7d537405586857e1881bdc521c..34d499466393bbfc635219e87719cc33e211dc6d 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/module.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -59,7 +60,6 @@
 #include <sound/pcm_params.h>
 #include <sound/asoundef.h>
 #include <sound/initval.h>
-#include <asm/io.h>
 #include <linux/atomic.h>
 #include "echoaudio.h"
 
index 4c171636efcd6cbb76a3e593f4e4e1ee3fa5f509..37d0220a094cb55451cff620c5e455f83d8a894d 100644 (file)
@@ -132,11 +132,11 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
                goto error;
        card->private_data = emu;
        emu->delay_pcm_irq = delay_pcm_irq[dev] & 0x1f;
-       if ((err = snd_emu10k1_pcm(emu, 0, NULL)) < 0)
+       if ((err = snd_emu10k1_pcm(emu, 0)) < 0)
                goto error;
-       if ((err = snd_emu10k1_pcm_mic(emu, 1, NULL)) < 0)
+       if ((err = snd_emu10k1_pcm_mic(emu, 1)) < 0)
                goto error;
-       if ((err = snd_emu10k1_pcm_efx(emu, 2, NULL)) < 0)
+       if ((err = snd_emu10k1_pcm_efx(emu, 2)) < 0)
                goto error;
        /* This stores the periods table. */
        if (emu->card_capabilities->ca0151_chip) { /* P16V */   
@@ -151,10 +151,10 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
        if ((err = snd_emu10k1_timer(emu, 0)) < 0)
                goto error;
 
-       if ((err = snd_emu10k1_pcm_multi(emu, 3, NULL)) < 0)
+       if ((err = snd_emu10k1_pcm_multi(emu, 3)) < 0)
                goto error;
        if (emu->card_capabilities->ca0151_chip) { /* P16V */
-               if ((err = snd_p16v_pcm(emu, 4, NULL)) < 0)
+               if ((err = snd_p16v_pcm(emu, 4)) < 0)
                        goto error;
        }
        if (emu->audigy) {
@@ -164,7 +164,7 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
                if ((err = snd_emu10k1_midi(emu)) < 0)
                        goto error;
        }
-       if ((err = snd_emu10k1_fx8010_new(emu, 0, NULL)) < 0)
+       if ((err = snd_emu10k1_fx8010_new(emu, 0)) < 0)
                goto error;
 #ifdef ENABLE_SYNTH
        if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH,
@@ -210,7 +210,6 @@ static void snd_card_emu10k1_remove(struct pci_dev *pci)
 #ifdef CONFIG_PM_SLEEP
 static int snd_emu10k1_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_emu10k1 *emu = card->private_data;
 
@@ -232,28 +231,14 @@ static int snd_emu10k1_suspend(struct device *dev)
                snd_p16v_suspend(emu);
 
        snd_emu10k1_done(emu);
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int snd_emu10k1_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_emu10k1 *emu = card->private_data;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
-
        snd_emu10k1_resume_init(emu);
        snd_emu10k1_efx_resume(emu);
        snd_ac97_resume(emu->ac97);
index 15933f92f63afcfca38c828fe9c0d4b529c3938f..6d1b98d14327c2ec3ffc5cb2ff91e5cadc413e32 100644 (file)
@@ -847,15 +847,13 @@ static const struct snd_pcm_chmap_elem clfe_map[] = {
        { }
 };
 
-static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct snd_pcm **rpcm)
+static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device)
 {
        struct snd_pcm *pcm;
        const struct snd_pcm_chmap_elem *map = NULL;
        int err;
        int capture = 0;
   
-       if (rpcm)
-               *rpcm = NULL;
        if (device == 0)
                capture = 1;
        
@@ -896,15 +894,8 @@ static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct snd_pcm **r
                                              snd_dma_pci_data(emu->pci), 
                                              32*1024, 32*1024);
   
-       err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2,
+       return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2,
                                     1 << 2, NULL);
-       if (err < 0)
-               return err;
-
-       if (rpcm)
-               *rpcm = pcm;
-  
-       return 0;
 }
 
 static int snd_emu10k1x_create(struct snd_card *card,
@@ -1583,15 +1574,15 @@ static int snd_emu10k1x_probe(struct pci_dev *pci,
                return err;
        }
 
-       if ((err = snd_emu10k1x_pcm(chip, 0, NULL)) < 0) {
+       if ((err = snd_emu10k1x_pcm(chip, 0)) < 0) {
                snd_card_free(card);
                return err;
        }
-       if ((err = snd_emu10k1x_pcm(chip, 1, NULL)) < 0) {
+       if ((err = snd_emu10k1x_pcm(chip, 1)) < 0) {
                snd_card_free(card);
                return err;
        }
-       if ((err = snd_emu10k1x_pcm(chip, 2, NULL)) < 0) {
+       if ((err = snd_emu10k1x_pcm(chip, 2)) < 0) {
                snd_card_free(card);
                return err;
        }
index eb5c0aba41c1a56d2d1bd07f8c63fed6da2e3835..56fc47bd6dbab381ad6b9453fbf1c4cb2e23ceb1 100644 (file)
@@ -2641,14 +2641,11 @@ static int snd_emu10k1_fx8010_release(struct snd_hwdep * hw, struct file *file)
        return 0;
 }
 
-int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device,
-                          struct snd_hwdep **rhwdep)
+int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device)
 {
        struct snd_hwdep *hw;
        int err;
        
-       if (rhwdep)
-               *rhwdep = NULL;
        if ((err = snd_hwdep_new(emu->card, "FX8010", device, &hw)) < 0)
                return err;
        strcpy(hw->name, "EMU10K1 (FX8010)");
@@ -2657,8 +2654,6 @@ int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device,
        hw->ops.ioctl = snd_emu10k1_fx8010_ioctl;
        hw->ops.release = snd_emu10k1_fx8010_release;
        hw->private_data = emu;
-       if (rhwdep)
-               *rhwdep = hw;
        return 0;
 }
 
index f82481bd2542a912924088e8725dc56bf9bbdf23..0dc07385af0ebaee5ea66126bf8d758e17f71054 100644 (file)
@@ -1400,15 +1400,12 @@ static struct snd_pcm_ops snd_emu10k1_efx_playback_ops = {
        .page =                 snd_pcm_sgbuf_ops_page,
 };
 
-int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm)
+int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device)
 {
        struct snd_pcm *pcm;
        struct snd_pcm_substream *substream;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
-
        if ((err = snd_pcm_new(emu->card, "emu10k1", device, 32, 1, &pcm)) < 0)
                return err;
 
@@ -1429,22 +1426,15 @@ int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm)
        for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next)
                snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024);
 
-       if (rpcm)
-               *rpcm = pcm;
-
        return 0;
 }
 
-int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device,
-                         struct snd_pcm **rpcm)
+int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device)
 {
        struct snd_pcm *pcm;
        struct snd_pcm_substream *substream;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
-
        if ((err = snd_pcm_new(emu->card, "emu10k1", device, 1, 0, &pcm)) < 0)
                return err;
 
@@ -1461,9 +1451,6 @@ int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device,
                if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(emu->pci), 64*1024, 64*1024)) < 0)
                        return err;
 
-       if (rpcm)
-               *rpcm = pcm;
-
        return 0;
 }
 
@@ -1479,15 +1466,11 @@ static struct snd_pcm_ops snd_emu10k1_capture_mic_ops = {
        .pointer =              snd_emu10k1_capture_pointer,
 };
 
-int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device,
-                       struct snd_pcm **rpcm)
+int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device)
 {
        struct snd_pcm *pcm;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
-
        if ((err = snd_pcm_new(emu->card, "emu10k1 mic", device, 0, 1, &pcm)) < 0)
                return err;
 
@@ -1501,8 +1484,6 @@ int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device,
 
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024);
 
-       if (rpcm)
-               *rpcm = pcm;
        return 0;
 }
 
@@ -1822,16 +1803,12 @@ static struct snd_pcm_ops snd_emu10k1_fx8010_playback_ops = {
        .ack =                  snd_emu10k1_fx8010_playback_transfer,
 };
 
-int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device,
-                       struct snd_pcm **rpcm)
+int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device)
 {
        struct snd_pcm *pcm;
        struct snd_kcontrol *kctl;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
-
        if ((err = snd_pcm_new(emu->card, "emu10k1 efx", device, 8, 1, &pcm)) < 0)
                return err;
 
@@ -1843,8 +1820,6 @@ int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device,
        pcm->info_flags = 0;
        strcpy(pcm->name, "Multichannel Capture/PT Playback");
        emu->pcm_efx = pcm;
-       if (rpcm)
-               *rpcm = pcm;
 
        /* EFX capture - record the "FXBUS2" channels, by default we connect the EXTINs 
         * to these
index 7ef3898a78061b8955f218d98679ce73a97ddaa2..3c60b433de9ff5d25686563c2458a411951e52f0 100644 (file)
@@ -166,11 +166,8 @@ static struct snd_pcm_hardware snd_p16v_capture_hw = {
 static void snd_p16v_pcm_free_substream(struct snd_pcm_runtime *runtime)
 {
        struct snd_emu10k1_pcm *epcm = runtime->private_data;
-  
-       if (epcm) {
-               /* dev_dbg(emu->card->dev, "epcm free: %p\n", epcm); */
-               kfree(epcm);
-       }
+
+       kfree(epcm);
 }
 
 /* open_playback callback */
@@ -640,7 +637,7 @@ int snd_p16v_free(struct snd_emu10k1 *chip)
        return 0;
 }
 
-int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm)
+int snd_p16v_pcm(struct snd_emu10k1 *emu, int device)
 {
        struct snd_pcm *pcm;
        struct snd_pcm_substream *substream;
@@ -649,8 +646,6 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm)
   
        /* dev_dbg(emu->card->dev, "snd_p16v_pcm called. device=%d\n", device); */
        emu->p16v_device_offset = device;
-       if (rpcm)
-               *rpcm = NULL;
 
        if ((err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm)) < 0)
                return err;
@@ -694,9 +689,6 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm)
                */
        }
   
-       if (rpcm)
-               *rpcm = pcm;
-  
        return 0;
 }
 
index d94cb3ca7a643a918f7ae21bdcbf95eb5ab78bd3..0dc44ebb00329e3266d6bad2e20b424588c9a321 100644 (file)
@@ -26,7 +26,7 @@
  * by Kurt J. Bosch
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -1268,14 +1268,11 @@ static const struct snd_pcm_chmap_elem surround_map[] = {
        { }
 };
 
-static int snd_ensoniq_pcm(struct ensoniq *ensoniq, int device,
-                          struct snd_pcm **rpcm)
+static int snd_ensoniq_pcm(struct ensoniq *ensoniq, int device)
 {
        struct snd_pcm *pcm;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
        err = snd_pcm_new(ensoniq->card, CHIP_NAME "/1", device, 1, 1, &pcm);
        if (err < 0)
                return err;
@@ -1302,22 +1299,14 @@ static int snd_ensoniq_pcm(struct ensoniq *ensoniq, int device,
        err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
                                     snd_pcm_std_chmaps, 2, 0, NULL);
 #endif
-       if (err < 0)
-               return err;
-
-       if (rpcm)
-               *rpcm = pcm;
-       return 0;
+       return err;
 }
 
-static int snd_ensoniq_pcm2(struct ensoniq *ensoniq, int device,
-                           struct snd_pcm **rpcm)
+static int snd_ensoniq_pcm2(struct ensoniq *ensoniq, int device)
 {
        struct snd_pcm *pcm;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
        err = snd_pcm_new(ensoniq->card, CHIP_NAME "/2", device, 1, 0, &pcm);
        if (err < 0)
                return err;
@@ -1342,12 +1331,7 @@ static int snd_ensoniq_pcm2(struct ensoniq *ensoniq, int device,
        err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
                                     surround_map, 2, 0, NULL);
 #endif
-       if (err < 0)
-               return err;
-
-       if (rpcm)
-               *rpcm = pcm;
-       return 0;
+       return err;
 }
 
 /*
@@ -2049,7 +2033,6 @@ static void snd_ensoniq_chip_init(struct ensoniq *ensoniq)
 #ifdef CONFIG_PM_SLEEP
 static int snd_ensoniq_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct ensoniq *ensoniq = card->private_data;
        
@@ -2070,28 +2053,14 @@ static int snd_ensoniq_suspend(struct device *dev)
        udelay(100);
        snd_ak4531_suspend(ensoniq->u.es1370.ak4531);
 #endif 
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int snd_ensoniq_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct ensoniq *ensoniq = card->private_data;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
-
        snd_ensoniq_chip_init(ensoniq);
 
 #ifdef CHIP1371        
@@ -2362,14 +2331,11 @@ static struct snd_rawmidi_ops snd_ensoniq_midi_input =
        .trigger =      snd_ensoniq_midi_input_trigger,
 };
 
-static int snd_ensoniq_midi(struct ensoniq *ensoniq, int device,
-                           struct snd_rawmidi **rrawmidi)
+static int snd_ensoniq_midi(struct ensoniq *ensoniq, int device)
 {
        struct snd_rawmidi *rmidi;
        int err;
 
-       if (rrawmidi)
-               *rrawmidi = NULL;
        if ((err = snd_rawmidi_new(ensoniq->card, "ES1370/1", device, 1, 1, &rmidi)) < 0)
                return err;
        strcpy(rmidi->name, CHIP_NAME);
@@ -2379,8 +2345,6 @@ static int snd_ensoniq_midi(struct ensoniq *ensoniq, int device,
                SNDRV_RAWMIDI_INFO_DUPLEX;
        rmidi->private_data = ensoniq;
        ensoniq->rmidi = rmidi;
-       if (rrawmidi)
-               *rrawmidi = rmidi;
        return 0;
 }
 
@@ -2462,15 +2426,15 @@ static int snd_audiopci_probe(struct pci_dev *pci,
                return err;
        }
 #endif
-       if ((err = snd_ensoniq_pcm(ensoniq, 0, NULL)) < 0) {
+       if ((err = snd_ensoniq_pcm(ensoniq, 0)) < 0) {
                snd_card_free(card);
                return err;
        }
-       if ((err = snd_ensoniq_pcm2(ensoniq, 1, NULL)) < 0) {
+       if ((err = snd_ensoniq_pcm2(ensoniq, 1)) < 0) {
                snd_card_free(card);
                return err;
        }
-       if ((err = snd_ensoniq_midi(ensoniq, 0, NULL)) < 0) {
+       if ((err = snd_ensoniq_midi(ensoniq, 0)) < 0) {
                snd_card_free(card);
                return err;
        }
index 0fc46eb4e251cc81aee07b1dd4bd095eacc0b44c..e1858d9d23d8711d29ee131363c7997a090db847 100644 (file)
@@ -55,6 +55,7 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
@@ -63,8 +64,6 @@
 #include <sound/initval.h>
 #include <sound/tlv.h>
 
-#include <asm/io.h>
-
 MODULE_AUTHOR("Jaromir Koutek <miri@punknet.cz>");
 MODULE_DESCRIPTION("ESS Solo-1");
 MODULE_LICENSE("GPL");
@@ -1454,7 +1453,6 @@ static unsigned char saved_regs[SAVED_REG_SIZE+1] = {
 
 static int es1938_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct es1938 *chip = card->private_data;
        unsigned char *s, *d;
@@ -1471,9 +1469,6 @@ static int es1938_suspend(struct device *dev)
                free_irq(chip->irq, chip);
                chip->irq = -1;
        }
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
@@ -1484,14 +1479,6 @@ static int es1938_resume(struct device *dev)
        struct es1938 *chip = card->private_data;
        unsigned char *s, *d;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-
        if (request_irq(pci->irq, snd_es1938_interrupt,
                        IRQF_SHARED, KBUILD_MODNAME, chip)) {
                dev_err(dev, "unable to grab IRQ %d, disabling device\n",
index 6039700f8579cfbd97c2e9d80c767fc4a2a23b2f..059f3846d7b814af26f15e624e4c861b81d9cc9c 100644 (file)
@@ -94,7 +94,7 @@
  *     places.
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -2383,7 +2383,6 @@ static void snd_es1968_start_irq(struct es1968 *chip)
  */
 static int es1968_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct es1968 *chip = card->private_data;
 
@@ -2396,16 +2395,11 @@ static int es1968_suspend(struct device *dev)
        snd_pcm_suspend_all(chip->pcm);
        snd_ac97_suspend(chip->ac97);
        snd_es1968_bob_stop(chip);
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int es1968_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct es1968 *chip = card->private_data;
        struct esschan *es;
@@ -2413,16 +2407,6 @@ static int es1968_resume(struct device *dev)
        if (! chip->do_pm)
                return 0;
 
-       /* restore all our config */
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
-
        snd_es1968_chip_init(chip);
 
        /* need to restore the base pointers.. */ 
index d167afffce5fb5dcda4e20abea2df7a8d275682d..1fdd92b6f18f377585b2c36813fcb9ff444fc691 100644 (file)
@@ -2,8 +2,6 @@
  *  The driver for the ForteMedia FM801 based soundcards
  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
  *
- *  Support FM only card by Andy Shevchenko <andy@smile.org.ua>
- *
  *   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
  *   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/delay.h>
@@ -704,13 +698,11 @@ static struct snd_pcm_ops snd_fm801_capture_ops = {
        .pointer =      snd_fm801_capture_pointer,
 };
 
-static int snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pcm **rpcm)
+static int snd_fm801_pcm(struct fm801 *chip, int device)
 {
        struct snd_pcm *pcm;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
        if ((err = snd_pcm_new(chip->card, "FM801", device, 1, 1, &pcm)) < 0)
                return err;
 
@@ -726,16 +718,10 @@ static int snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pcm **rpcm)
                                              snd_dma_pci_data(chip->pci),
                                              chip->multichannel ? 128*1024 : 64*1024, 128*1024);
 
-       err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+       return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
                                     snd_pcm_alt_chmaps,
                                     chip->multichannel ? 6 : 2, 0,
                                     NULL);
-       if (err < 0)
-               return err;
-
-       if (rpcm)
-               *rpcm = pcm;
-       return 0;
 }
 
 /*
@@ -1186,12 +1172,6 @@ static int snd_fm801_free(struct fm801 *chip)
                v4l2_device_unregister(&chip->v4l2_dev);
        }
 #endif
-       if (chip->irq >= 0)
-               free_irq(chip->irq, chip);
-       pci_release_regions(chip->pci);
-       pci_disable_device(chip->pci);
-
-       kfree(chip);
        return 0;
 }
 
@@ -1214,28 +1194,23 @@ static int snd_fm801_create(struct snd_card *card,
        };
 
        *rchip = NULL;
-       if ((err = pci_enable_device(pci)) < 0)
+       if ((err = pcim_enable_device(pci)) < 0)
                return err;
-       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-       if (chip == NULL) {
-               pci_disable_device(pci);
+       chip = devm_kzalloc(&pci->dev, sizeof(*chip), GFP_KERNEL);
+       if (chip == NULL)
                return -ENOMEM;
-       }
        spin_lock_init(&chip->reg_lock);
        chip->card = card;
        chip->pci = pci;
        chip->irq = -1;
        chip->tea575x_tuner = tea575x_tuner;
-       if ((err = pci_request_regions(pci, "FM801")) < 0) {
-               kfree(chip);
-               pci_disable_device(pci);
+       if ((err = pci_request_regions(pci, "FM801")) < 0)
                return err;
-       }
        chip->port = pci_resource_start(pci, 0);
        if ((tea575x_tuner & TUNER_ONLY) == 0) {
-               if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
-                               KBUILD_MODNAME, chip)) {
-                       dev_err(card->dev, "unable to grab IRQ %d\n", chip->irq);
+               if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt,
+                               IRQF_SHARED, KBUILD_MODNAME, chip)) {
+                       dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
                        snd_fm801_free(chip);
                        return -EBUSY;
                }
@@ -1250,12 +1225,6 @@ static int snd_fm801_create(struct snd_card *card,
        /* init might set tuner access method */
        tea575x_tuner = chip->tea575x_tuner;
 
-       if (chip->irq >= 0 && (tea575x_tuner & TUNER_ONLY)) {
-               pci_clear_master(pci);
-               free_irq(chip->irq, chip);
-               chip->irq = -1;
-       }
-
        if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
                snd_fm801_free(chip);
                return err;
@@ -1340,7 +1309,7 @@ static int snd_card_fm801_probe(struct pci_dev *pci,
        if (chip->tea575x_tuner & TUNER_ONLY)
                goto __fm801_tuner_only;
 
-       if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) {
+       if ((err = snd_fm801_pcm(chip, 0)) < 0) {
                snd_card_free(card);
                return err;
        }
@@ -1392,7 +1361,6 @@ static unsigned char saved_regs[] = {
 
 static int snd_fm801_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct fm801 *chip = card->private_data;
        int i;
@@ -1404,29 +1372,15 @@ static int snd_fm801_suspend(struct device *dev)
        for (i = 0; i < ARRAY_SIZE(saved_regs); i++)
                chip->saved_regs[i] = inw(chip->port + saved_regs[i]);
        /* FIXME: tea575x suspend */
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int snd_fm801_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct fm801 *chip = card->private_data;
        int i;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
-
        snd_fm801_chip_init(chip, 1);
        snd_ac97_resume(chip->ac97);
        snd_ac97_resume(chip->ac97_sec);
index ebf4c2fb99df0e02a3169e1f4d2be1afb6963bed..7f0f2c5a4e97388200e25ac8a04900f1206eaf38 100644 (file)
@@ -107,6 +107,7 @@ config SND_HDA_PATCH_LOADER
 config SND_HDA_CODEC_REALTEK
        tristate "Build Realtek HD-audio codec support"
        select SND_HDA_GENERIC
+       select INPUT
        help
          Say Y or M here to include Realtek HD-audio codec support in
          snd-hda-intel driver, such as ALC880.
index 1ede82200ee571c07dc47d247f40c1e37ac94732..3f8706bb3d16349d8893178c637df589eb146036 100644 (file)
@@ -409,10 +409,10 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
        /*
         * debug prints of the parsed results
         */
-       codec_info(codec, "autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
-                  cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1],
-                  cfg->line_out_pins[2], cfg->line_out_pins[3],
-                  cfg->line_out_pins[4],
+       codec_info(codec, "autoconfig for %s: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
+                  codec->chip_name, cfg->line_outs, cfg->line_out_pins[0],
+                  cfg->line_out_pins[1], cfg->line_out_pins[2],
+                  cfg->line_out_pins[3], cfg->line_out_pins[4],
                   cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" :
                   (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ?
                    "speaker" : "line"));
@@ -920,6 +920,8 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec,
                        codec->fixup_id = pq->value;
 #ifdef CONFIG_SND_DEBUG_VERBOSE
                        codec->fixup_name = pq->name;
+                       codec_dbg(codec, "%s: picked fixup %s (pin match)\n",
+                                 codec->chip_name, codec->fixup_name);
 #endif
                        codec->fixup_list = fixlist;
                        return;
@@ -960,6 +962,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
                codec->fixup_list = NULL;
                codec->fixup_name = NULL;
                codec->fixup_id = HDA_FIXUP_ID_NO_FIXUP;
+               codec_dbg(codec, "%s: picked no fixup (nofixup specified)\n",
+                         codec->chip_name);
                return;
        }
 
@@ -969,6 +973,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
                                codec->fixup_id = models->id;
                                codec->fixup_name = models->name;
                                codec->fixup_list = fixlist;
+                               codec_dbg(codec, "%s: picked fixup %s (model specified)\n",
+                                         codec->chip_name, codec->fixup_name);
                                return;
                        }
                        models++;
@@ -980,6 +986,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
                        id = q->value;
 #ifdef CONFIG_SND_DEBUG_VERBOSE
                        name = q->name;
+                       codec_dbg(codec, "%s: picked fixup %s (PCI SSID%s)\n",
+                                 codec->chip_name, name, q->subdevice_mask ? "" : " - vendor generic");
 #endif
                }
        }
@@ -992,6 +1000,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
                                id = q->value;
 #ifdef CONFIG_SND_DEBUG_VERBOSE
                                name = q->name;
+                               codec_dbg(codec, "%s: picked fixup %s (codec SSID)\n",
+                                         codec->chip_name, name);
 #endif
                                break;
                        }
index 0cfc9c8c4b4e811ac6f0b6bbeb0d24377c95232d..dfcb5e929f9fc9643701eb33f04aa8efd7f101d3 100644 (file)
@@ -657,6 +657,9 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits);
        if (start) {
                azx_timecounter_init(substream, 0, 0);
+               snd_pcm_gettime(substream->runtime, &substream->runtime->trigger_tstamp);
+               substream->runtime->trigger_tstamp_latched = true;
+
                if (nsync > 1) {
                        cycle_t cycle_last;
 
@@ -939,7 +942,8 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
                                              chip->card->dev,
                                              size, MAX_PREALLOC_SIZE);
        /* link to codec */
-       pcm->dev = &codec->dev;
+       for (s = 0; s < 2; s++)
+               pcm->streams[s].dev.parent = &codec->dev;
        return 0;
 }
 
@@ -1993,4 +1997,4 @@ void azx_notifier_unregister(struct azx *chip)
 EXPORT_SYMBOL_GPL(azx_notifier_unregister);
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Common HDA driver funcitons");
+MODULE_DESCRIPTION("Common HDA driver functions");
index 014a7849e8fdbf2a2f18c55e281f7499561f89db..11b5a42b4ec8cf33571631b8ceab890b29f31a15 100644 (file)
@@ -109,7 +109,6 @@ int snd_hda_create_hwdep(struct hda_codec *codec)
        hwdep->iface = SNDRV_HWDEP_IFACE_HDA;
        hwdep->private_data = codec;
        hwdep->exclusive = 1;
-       hwdep->groups = snd_hda_dev_attr_groups;
 
        hwdep->ops.open = hda_hwdep_open;
        hwdep->ops.ioctl = hda_hwdep_ioctl;
@@ -118,7 +117,11 @@ int snd_hda_create_hwdep(struct hda_codec *codec)
 #endif
 
        /* link to codec */
-       hwdep->dev = &codec->dev;
+       hwdep->dev.parent = &codec->dev;
+
+       /* for sysfs */
+       hwdep->dev.groups = snd_hda_dev_attr_groups;
+       dev_set_drvdata(&hwdep->dev, codec);
 
        return 0;
 }
index d4d0375ac181adcedccfcf4ebcaa9ce85b997f3a..714894527e06a50c9dc3903928b610b8a7035423 100644 (file)
 
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/component.h>
+#include <drm/i915_component.h>
 #include <sound/core.h>
-#include <drm/i915_powerwell.h>
 #include "hda_priv.h"
-#include "hda_i915.h"
+#include "hda_intel.h"
 
 /* Intel HSW/BDW display HDA controller Extended Mode registers.
  * EM4 (M value) and EM5 (N Value) are used to convert CDClk (Core Display
 #define AZX_REG_EM4                    0x100c
 #define AZX_REG_EM5                    0x1010
 
-static int (*get_power)(void);
-static int (*put_power)(void);
-static int (*get_cdclk)(void);
-
-int hda_display_power(bool enable)
+int hda_display_power(struct hda_intel *hda, bool enable)
 {
-       if (!get_power || !put_power)
+       struct i915_audio_component *acomp = &hda->audio_component;
+
+       if (!acomp->ops)
                return -ENODEV;
 
-       pr_debug("HDA display power %s \n",
-                       enable ? "Enable" : "Disable");
+       dev_dbg(&hda->chip.pci->dev, "display power %s\n",
+               enable ? "enable" : "disable");
        if (enable)
-               return get_power();
+               acomp->ops->get_power(acomp->dev);
        else
-               return put_power();
+               acomp->ops->put_power(acomp->dev);
+
+       return 0;
 }
 
-void haswell_set_bclk(struct azx *chip)
+void haswell_set_bclk(struct hda_intel *hda)
 {
        int cdclk_freq;
        unsigned int bclk_m, bclk_n;
+       struct i915_audio_component *acomp = &hda->audio_component;
 
-       if (!get_cdclk)
+       if (!acomp->ops)
                return;
 
-       cdclk_freq = get_cdclk();
+       cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev);
        switch (cdclk_freq) {
        case 337500:
                bclk_m = 16;
@@ -80,51 +83,108 @@ void haswell_set_bclk(struct azx *chip)
                break;
        }
 
-       azx_writew(chip, EM4, bclk_m);
-       azx_writew(chip, EM5, bclk_n);
+       azx_writew(&hda->chip, EM4, bclk_m);
+       azx_writew(&hda->chip, EM5, bclk_n);
 }
 
-
-int hda_i915_init(void)
+static int hda_component_master_bind(struct device *dev)
 {
-       int err = 0;
-
-       get_power = symbol_request(i915_request_power_well);
-       if (!get_power) {
-               pr_warn("hda-i915: get_power symbol get fail\n");
-               return -ENODEV;
+       struct snd_card *card = dev_get_drvdata(dev);
+       struct azx *chip = card->private_data;
+       struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
+       struct i915_audio_component *acomp = &hda->audio_component;
+       int ret;
+
+       ret = component_bind_all(dev, acomp);
+       if (ret < 0)
+               return ret;
+
+       if (WARN_ON(!(acomp->dev && acomp->ops && acomp->ops->get_power &&
+                     acomp->ops->put_power && acomp->ops->get_cdclk_freq))) {
+               ret = -EINVAL;
+               goto out_unbind;
        }
 
-       put_power = symbol_request(i915_release_power_well);
-       if (!put_power) {
-               symbol_put(i915_request_power_well);
-               get_power = NULL;
-               return -ENODEV;
+       /*
+        * Atm, we don't support dynamic unbinding initiated by the child
+        * component, so pin its containing module until we unbind.
+        */
+       if (!try_module_get(acomp->ops->owner)) {
+               ret = -ENODEV;
+               goto out_unbind;
        }
 
-       get_cdclk = symbol_request(i915_get_cdclk_freq);
-       if (!get_cdclk) /* may have abnormal BCLK and audio playback rate */
-               pr_warn("hda-i915: get_cdclk symbol get fail\n");
+       return 0;
 
-       pr_debug("HDA driver get symbol successfully from i915 module\n");
+out_unbind:
+       component_unbind_all(dev, acomp);
 
-       return err;
+       return ret;
 }
 
-int hda_i915_exit(void)
+static void hda_component_master_unbind(struct device *dev)
 {
-       if (get_power) {
-               symbol_put(i915_request_power_well);
-               get_power = NULL;
-       }
-       if (put_power) {
-               symbol_put(i915_release_power_well);
-               put_power = NULL;
-       }
-       if (get_cdclk) {
-               symbol_put(i915_get_cdclk_freq);
-               get_cdclk = NULL;
+       struct snd_card *card = dev_get_drvdata(dev);
+       struct azx *chip = card->private_data;
+       struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
+       struct i915_audio_component *acomp = &hda->audio_component;
+
+       module_put(acomp->ops->owner);
+       component_unbind_all(dev, acomp);
+       WARN_ON(acomp->ops || acomp->dev);
+}
+
+static const struct component_master_ops hda_component_master_ops = {
+       .bind = hda_component_master_bind,
+       .unbind = hda_component_master_unbind,
+};
+
+static int hda_component_master_match(struct device *dev, void *data)
+{
+       /* i915 is the only supported component */
+       return !strcmp(dev->driver->name, "i915");
+}
+
+int hda_i915_init(struct hda_intel *hda)
+{
+       struct component_match *match = NULL;
+       struct device *dev = &hda->chip.pci->dev;
+       struct i915_audio_component *acomp = &hda->audio_component;
+       int ret;
+
+       component_match_add(dev, &match, hda_component_master_match, hda);
+       ret = component_master_add_with_match(dev, &hda_component_master_ops,
+                                             match);
+       if (ret < 0)
+               goto out_err;
+
+       /*
+        * Atm, we don't support deferring the component binding, so make sure
+        * i915 is loaded and that the binding successfully completes.
+        */
+       request_module("i915");
+
+       if (!acomp->ops) {
+               ret = -ENODEV;
+               goto out_master_del;
        }
 
+       dev_dbg(dev, "bound to i915 component master\n");
+
+       return 0;
+out_master_del:
+       component_master_del(dev, &hda_component_master_ops);
+out_err:
+       dev_err(dev, "failed to add i915 component master (%d)\n", ret);
+
+       return ret;
+}
+
+int hda_i915_exit(struct hda_intel *hda)
+{
+       struct device *dev = &hda->chip.pci->dev;
+
+       component_master_del(dev, &hda_component_master_ops);
+
        return 0;
 }
diff --git a/sound/pci/hda/hda_i915.h b/sound/pci/hda/hda_i915.h
deleted file mode 100644 (file)
index e6072c6..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- *  This program is free software; you can redistribute it and/or modify it
- *  under the terms of the GNU General Public License as published by the Free
- *  Software Foundation; either version 2 of the License, or (at your option)
- *  any later version.
- *
- *  This program is distributed in the hope that it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- *  more details.
- *
- *  You should have received a copy of the GNU General Public License along with
- *  this program; if not, write to the Free Software Foundation, Inc., 59
- *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-#ifndef __SOUND_HDA_I915_H
-#define __SOUND_HDA_I915_H
-
-#ifdef CONFIG_SND_HDA_I915
-int hda_display_power(bool enable);
-void haswell_set_bclk(struct azx *chip);
-int hda_i915_init(void);
-int hda_i915_exit(void);
-#else
-static inline int hda_display_power(bool enable) { return 0; }
-static inline void haswell_set_bclk(struct azx *chip) { return; }
-static inline int hda_i915_init(void)
-{
-       return -ENODEV;
-}
-static inline int hda_i915_exit(void)
-{
-       return 0;
-}
-#endif
-
-#endif
index d426a0bd6a5f7e86adf482c83ad86e3203a8a3ad..36d2f20db7a4201b999155e759e3e22b6fe3f753 100644 (file)
@@ -63,7 +63,7 @@
 #include "hda_codec.h"
 #include "hda_controller.h"
 #include "hda_priv.h"
-#include "hda_i915.h"
+#include "hda_intel.h"
 
 /* position fix mode */
 enum {
@@ -354,31 +354,6 @@ static char *driver_short_names[] = {
        [AZX_DRIVER_GENERIC] = "HD-Audio Generic",
 };
 
-struct hda_intel {
-       struct azx chip;
-
-       /* for pending irqs */
-       struct work_struct irq_pending_work;
-
-       /* sync probing */
-       struct completion probe_wait;
-       struct work_struct probe_work;
-
-       /* card list (for power_save trigger) */
-       struct list_head list;
-
-       /* extra flags */
-       unsigned int irq_pending_warned:1;
-
-       /* VGA-switcheroo setup */
-       unsigned int use_vga_switcheroo:1;
-       unsigned int vga_switcheroo_registered:1;
-       unsigned int init_failed:1; /* delayed init failed */
-
-       /* secondary power domain for hdmi audio under vga device */
-       struct dev_pm_domain hdmi_pm_domain;
-};
-
 #ifdef CONFIG_X86
 static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on)
 {
@@ -795,7 +770,6 @@ static int param_set_xint(const char *val, const struct kernel_param *kp)
  */
 static int azx_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct azx *chip;
        struct hda_intel *hda;
@@ -824,11 +798,8 @@ static int azx_suspend(struct device *dev)
 
        if (chip->msi)
                pci_disable_msi(chip->pci);
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
-               hda_display_power(false);
+               hda_display_power(hda, false);
        return 0;
 }
 
@@ -848,18 +819,9 @@ static int azx_resume(struct device *dev)
                return 0;
 
        if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
-               hda_display_power(true);
-               haswell_set_bclk(chip);
+               hda_display_power(hda, true);
+               haswell_set_bclk(hda);
        }
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(chip->card->dev,
-                       "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
        if (chip->msi)
                if (pci_enable_msi(pci) < 0)
                        chip->msi = 0;
@@ -901,7 +863,7 @@ static int azx_runtime_suspend(struct device *dev)
        azx_enter_link_reset(chip);
        azx_clear_irq_pending(chip);
        if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
-               hda_display_power(false);
+               hda_display_power(hda, false);
 
        return 0;
 }
@@ -927,8 +889,8 @@ static int azx_runtime_resume(struct device *dev)
                return 0;
 
        if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
-               hda_display_power(true);
-               haswell_set_bclk(chip);
+               hda_display_power(hda, true);
+               haswell_set_bclk(hda);
        }
 
        /* Read STATESTS before controller reset */
@@ -1138,8 +1100,7 @@ static int azx_free(struct azx *chip)
                free_irq(chip->irq, (void*)chip);
        if (chip->msi)
                pci_disable_msi(chip->pci);
-       if (chip->remap_addr)
-               iounmap(chip->remap_addr);
+       iounmap(chip->remap_addr);
 
        azx_free_stream_pages(chip);
        if (chip->region_requested)
@@ -1150,8 +1111,8 @@ static int azx_free(struct azx *chip)
        release_firmware(chip->fw);
 #endif
        if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
-               hda_display_power(false);
-               hda_i915_exit();
+               hda_display_power(hda, false);
+               hda_i915_exit(hda);
        }
        kfree(hda);
 
@@ -1629,8 +1590,12 @@ static int azx_first_init(struct azx *chip)
        /* initialize chip */
        azx_init_pci(chip);
 
-       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
-               haswell_set_bclk(chip);
+       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
+               struct hda_intel *hda;
+
+               hda = container_of(chip, struct hda_intel, chip);
+               haswell_set_bclk(hda);
+       }
 
        azx_init_chip(chip, (probe_only[dev] & 2) == 0);
 
@@ -1910,13 +1875,10 @@ static int azx_probe_continue(struct azx *chip)
        /* Request power well for Haswell HDA controller and codec */
        if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
 #ifdef CONFIG_SND_HDA_I915
-               err = hda_i915_init();
-               if (err < 0) {
-                       dev_err(chip->card->dev,
-                               "Error request power-well from i915\n");
+               err = hda_i915_init(hda);
+               if (err < 0)
                        goto out_free;
-               }
-               err = hda_display_power(true);
+               err = hda_display_power(hda, true);
                if (err < 0) {
                        dev_err(chip->card->dev,
                                "Cannot turn on display power on i915\n");
diff --git a/sound/pci/hda/hda_intel.h b/sound/pci/hda/hda_intel.h
new file mode 100644 (file)
index 0000000..3486118
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ *  more details.
+ *
+ *  You should have received a copy of the GNU General Public License along with
+ *  this program; if not, write to the Free Software Foundation, Inc., 59
+ *  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+#ifndef __SOUND_HDA_INTEL_H
+#define __SOUND_HDA_INTEL_H
+
+#include <drm/i915_component.h>
+#include "hda_priv.h"
+
+struct hda_intel {
+       struct azx chip;
+
+       /* for pending irqs */
+       struct work_struct irq_pending_work;
+
+       /* sync probing */
+       struct completion probe_wait;
+       struct work_struct probe_work;
+
+       /* card list (for power_save trigger) */
+       struct list_head list;
+
+       /* extra flags */
+       unsigned int irq_pending_warned:1;
+
+       /* VGA-switcheroo setup */
+       unsigned int use_vga_switcheroo:1;
+       unsigned int vga_switcheroo_registered:1;
+       unsigned int init_failed:1; /* delayed init failed */
+
+       /* secondary power domain for hdmi audio under vga device */
+       struct dev_pm_domain hdmi_pm_domain;
+
+       /* i915 component interface */
+       struct i915_audio_component audio_component;
+};
+
+#ifdef CONFIG_SND_HDA_I915
+int hda_display_power(struct hda_intel *hda, bool enable);
+void haswell_set_bclk(struct hda_intel *hda);
+int hda_i915_init(struct hda_intel *hda);
+int hda_i915_exit(struct hda_intel *hda);
+#else
+static inline int hda_display_power(struct hda_intel *hda, bool enable)
+{
+       return 0;
+}
+static inline void haswell_set_bclk(struct hda_intel *hda) { return; }
+static inline int hda_i915_init(struct hda_intel *hda)
+{
+       return -ENODEV;
+}
+static inline int hda_i915_exit(struct hda_intel *hda)
+{
+       return 0;
+}
+#endif
+
+#endif
index a9d78e275138573b1248a71aeb7236a69b879974..d285904cdb64a0e88a51e5ee107a013500b25a0f 100644 (file)
@@ -739,39 +739,6 @@ static int patch_ad1981(struct hda_codec *codec)
  *      E/F quad mic array
  */
 
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_info *uinfo)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-       return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
-                                   spec->num_channel_mode);
-}
-
-static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-       return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
-                                  spec->num_channel_mode, spec->multiout.max_channels);
-}
-
-static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-       int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
-                                     spec->num_channel_mode,
-                                     &spec->multiout.max_channels);
-       if (err >= 0 && spec->need_dac_fix)
-               spec->multiout.num_dacs = spec->multiout.max_channels / 2;
-       return err;
-}
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
 static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
                                      struct snd_ctl_elem_info *uinfo)
 {
index 65f1f4e18ea5c5885d4a0e9daedf189c92c7fe3f..ddb93083a2af1ea15ffe2374a81193481a2f0da1 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/pci.h>
 #include <linux/dmi.h>
 #include <linux/module.h>
+#include <linux/input.h>
 #include <sound/core.h>
 #include <sound/jack.h>
 #include "hda_codec.h"
@@ -120,6 +121,7 @@ struct alc_spec {
        hda_nid_t pll_nid;
        unsigned int pll_coef_idx, pll_coef_bit;
        unsigned int coef0;
+       struct input_dev *kb_dev;
 };
 
 /*
@@ -3472,6 +3474,79 @@ static void alc280_fixup_hp_gpio4(struct hda_codec *codec,
        }
 }
 
+static void gpio2_mic_hotkey_event(struct hda_codec *codec,
+                                  struct hda_jack_callback *event)
+{
+       struct alc_spec *spec = codec->spec;
+
+       /* GPIO2 just toggles on a keypress/keyrelease cycle. Therefore
+          send both key on and key off event for every interrupt. */
+       input_report_key(spec->kb_dev, KEY_MICMUTE, 1);
+       input_sync(spec->kb_dev);
+       input_report_key(spec->kb_dev, KEY_MICMUTE, 0);
+       input_sync(spec->kb_dev);
+}
+
+static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
+                                            const struct hda_fixup *fix, int action)
+{
+       /* GPIO1 = set according to SKU external amp
+          GPIO2 = mic mute hotkey
+          GPIO3 = mute LED
+          GPIO4 = mic mute LED */
+       static const struct hda_verb gpio_init[] = {
+               { 0x01, AC_VERB_SET_GPIO_MASK, 0x1e },
+               { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x1a },
+               { 0x01, AC_VERB_SET_GPIO_DATA, 0x02 },
+               {}
+       };
+
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->kb_dev = input_allocate_device();
+               if (!spec->kb_dev) {
+                       codec_err(codec, "Out of memory (input_allocate_device)\n");
+                       return;
+               }
+               spec->kb_dev->name = "Microphone Mute Button";
+               spec->kb_dev->evbit[0] = BIT_MASK(EV_KEY);
+               spec->kb_dev->keybit[BIT_WORD(KEY_MICMUTE)] = BIT_MASK(KEY_MICMUTE);
+               if (input_register_device(spec->kb_dev)) {
+                       codec_err(codec, "input_register_device failed\n");
+                       input_free_device(spec->kb_dev);
+                       spec->kb_dev = NULL;
+                       return;
+               }
+
+               snd_hda_add_verbs(codec, gpio_init);
+               snd_hda_codec_write_cache(codec, codec->afg, 0,
+                                         AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x04);
+               snd_hda_jack_detect_enable_callback(codec, codec->afg,
+                                                   gpio2_mic_hotkey_event);
+
+               spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
+               spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
+               spec->gpio_led = 0;
+               spec->mute_led_polarity = 0;
+               spec->gpio_mute_led_mask = 0x08;
+               spec->gpio_mic_led_mask = 0x10;
+               return;
+       }
+
+       if (!spec->kb_dev)
+               return;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PROBE:
+               spec->init_amp = ALC_INIT_DEFAULT;
+               break;
+       case HDA_FIXUP_ACT_FREE:
+               input_unregister_device(spec->kb_dev);
+               spec->kb_dev = NULL;
+       }
+}
+
 static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
                                const struct hda_fixup *fix, int action)
 {
@@ -4341,6 +4416,8 @@ enum {
        ALC282_FIXUP_ASPIRE_V5_PINS,
        ALC280_FIXUP_HP_GPIO4,
        ALC286_FIXUP_HP_GPIO_LED,
+       ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY,
+       ALC280_FIXUP_HP_DOCK_PINS,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -4814,6 +4891,21 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc286_fixup_hp_gpio_led,
        },
+       [ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc280_fixup_hp_gpio2_mic_hotkey,
+       },
+       [ALC280_FIXUP_HP_DOCK_PINS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x21011020 }, /* line-out */
+                       { 0x1a, 0x01a1903c }, /* headset mic */
+                       { 0x18, 0x2181103f }, /* line-in */
+                       { },
+               },
+               .chained = true,
+               .chain_id = ALC280_FIXUP_HP_GPIO4
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -4843,6 +4935,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
        SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x225f, "HP", ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY),
        /* ALC282 */
        SND_PCI_QUIRK(0x103c, 0x2210, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
@@ -4856,6 +4949,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x226e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2271, "HP", ALC286_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x2272, "HP", ALC280_FIXUP_HP_DOCK_PINS),
+       SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC280_FIXUP_HP_DOCK_PINS),
        SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
index 605d14003d257cb645b3519541d18a9b3045790a..6d36c5b7880504457430718a8f23f2dbc0e9a9ba 100644 (file)
@@ -99,6 +99,7 @@ enum {
        STAC_HP_ENVY_BASS,
        STAC_HP_BNB13_EQ,
        STAC_HP_ENVY_TS_BASS,
+       STAC_92HD83XXX_GPIO10_EAPD,
        STAC_92HD83XXX_MODELS
 };
 
@@ -2141,6 +2142,19 @@ static void stac92hd83xxx_fixup_headset_jack(struct hda_codec *codec,
                spec->headset_jack = 1;
 }
 
+static void stac92hd83xxx_fixup_gpio10_eapd(struct hda_codec *codec,
+                                           const struct hda_fixup *fix,
+                                           int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+       spec->eapd_mask = spec->gpio_mask = spec->gpio_dir =
+               spec->gpio_data = 0x10;
+       spec->eapd_switch = 0;
+}
+
 static const struct hda_verb hp_bnb13_eq_verbs[] = {
        /* 44.1KHz base */
        { 0x22, 0x7A6, 0x3E },
@@ -2656,6 +2670,10 @@ static const struct hda_fixup stac92hd83xxx_fixups[] = {
                        {}
                },
        },
+       [STAC_92HD83XXX_GPIO10_EAPD] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd83xxx_fixup_gpio10_eapd,
+       },
 };
 
 static const struct hda_model_fixup stac92hd83xxx_models[] = {
@@ -2861,6 +2879,8 @@ static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = {
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x148a,
                      "HP Mini", STAC_92HD83XXX_HP_LED),
        SND_PCI_QUIRK_VENDOR(PCI_VENDOR_ID_HP, "HP", STAC_92HD83XXX_HP),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_TOSHIBA, 0xfa91,
+                     "Toshiba Satellite S50D", STAC_92HD83XXX_GPIO10_EAPD),
        {} /* terminator */
 };
 
index 3981823f9094b84faeec099fb951d30fcfa30277..179ef7a5f0d1b595a6c8c3c4a4ab46128b3f209c 100644 (file)
@@ -21,7 +21,7 @@
  *
  */      
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
index b039b46152c62ff0f5ff20359e58e2c4bdb50080..f7b1523e8a82a071f64960634204313a1fb3b529 100644 (file)
@@ -880,13 +880,11 @@ static struct snd_pcm_ops snd_ice1712_capture_ops = {
        .pointer =      snd_ice1712_capture_pointer,
 };
 
-static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm)
+static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device)
 {
        struct snd_pcm *pcm;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
        err = snd_pcm_new(ice->card, "ICE1712 consumer", device, 1, 1, &pcm);
        if (err < 0)
                return err;
@@ -902,22 +900,17 @@ static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device, struct snd_pcm *
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                              snd_dma_pci_data(ice->pci), 64*1024, 64*1024);
 
-       if (rpcm)
-               *rpcm = pcm;
-
        dev_warn(ice->card->dev,
                 "Consumer PCM code does not work well at the moment --jk\n");
 
        return 0;
 }
 
-static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm)
+static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device)
 {
        struct snd_pcm *pcm;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
        err = snd_pcm_new(ice->card, "ICE1712 consumer (DS)", device, 6, 0, &pcm);
        if (err < 0)
                return err;
@@ -932,9 +925,6 @@ static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device, struct snd_pc
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                              snd_dma_pci_data(ice->pci), 64*1024, 128*1024);
 
-       if (rpcm)
-               *rpcm = pcm;
-
        return 0;
 }
 
@@ -1260,13 +1250,11 @@ static struct snd_pcm_ops snd_ice1712_capture_pro_ops = {
        .pointer =      snd_ice1712_capture_pro_pointer,
 };
 
-static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm)
+static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device)
 {
        struct snd_pcm *pcm;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
        err = snd_pcm_new(ice->card, "ICE1712 multi", device, 1, 1, &pcm);
        if (err < 0)
                return err;
@@ -1282,8 +1270,6 @@ static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device, struct snd
                                              snd_dma_pci_data(ice->pci), 256*1024, 256*1024);
 
        ice->pcm_pro = pcm;
-       if (rpcm)
-               *rpcm = pcm;
 
        if (ice->cs8427) {
                /* assign channels to iec958 */
@@ -2691,14 +2677,14 @@ static int snd_ice1712_probe(struct pci_dev *pci,
        c = &no_matched;
  __found:
 
-       err = snd_ice1712_pcm_profi(ice, pcm_dev++, NULL);
+       err = snd_ice1712_pcm_profi(ice, pcm_dev++);
        if (err < 0) {
                snd_card_free(card);
                return err;
        }
 
        if (ice_has_con_ac97(ice)) {
-               err = snd_ice1712_pcm(ice, pcm_dev++, NULL);
+               err = snd_ice1712_pcm(ice, pcm_dev++);
                if (err < 0) {
                        snd_card_free(card);
                        return err;
@@ -2726,7 +2712,7 @@ static int snd_ice1712_probe(struct pci_dev *pci,
        }
 
        if (ice_has_con_ac97(ice)) {
-               err = snd_ice1712_pcm_ds(ice, pcm_dev++, NULL);
+               err = snd_ice1712_pcm_ds(ice, pcm_dev++);
                if (err < 0) {
                        snd_card_free(card);
                        return err;
@@ -2798,7 +2784,6 @@ static void snd_ice1712_remove(struct pci_dev *pci)
 #ifdef CONFIG_PM_SLEEP
 static int snd_ice1712_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_ice1712 *ice = card->private_data;
 
@@ -2820,16 +2805,11 @@ static int snd_ice1712_suspend(struct device *dev)
 
        if (ice->pm_suspend)
                ice->pm_suspend(ice);
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int snd_ice1712_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_ice1712 *ice = card->private_data;
        int rate;
@@ -2837,16 +2817,6 @@ static int snd_ice1712_resume(struct device *dev)
        if (!ice->pm_suspend_enabled)
                return 0;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-
-       if (pci_enable_device(pci) < 0) {
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-
-       pci_set_master(pci);
-
        if (ice->cur_rate)
                rate = ice->cur_rate;
        else
index d73da157ea14adb4393b16c9aa126f1caf78e9f8..0b22c00642bba475629007a7920426cbb1b84fbe 100644 (file)
@@ -2798,7 +2798,6 @@ static void snd_vt1724_remove(struct pci_dev *pci)
 #ifdef CONFIG_PM_SLEEP
 static int snd_vt1724_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_ice1712 *ice = card->private_data;
 
@@ -2821,32 +2820,17 @@ static int snd_vt1724_suspend(struct device *dev)
 
        if (ice->pm_suspend)
                ice->pm_suspend(ice);
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int snd_vt1724_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_ice1712 *ice = card->private_data;
 
        if (!ice->pm_suspend_enabled)
                return 0;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-
-       if (pci_enable_device(pci) < 0) {
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-
-       pci_set_master(pci);
-
        snd_vt1724_chip_reset(ice);
 
        if (snd_vt1724_chip_init(ice) < 0) {
index a1536c1a7ed457c7b41d9648de55614e1edccc7c..4f0213427152afcfb389e01192ec4b8a5dfef631 100644 (file)
@@ -491,15 +491,17 @@ static int juli_resume(struct snd_ice1712 *ice)
        /* akm4358 un-reset, un-mute */
        snd_akm4xxx_reset(ak, 0);
        /* reinit ak4114 */
-       snd_ak4114_reinit(spec->ak4114);
+       snd_ak4114_resume(spec->ak4114);
        return 0;
 }
 
 static int juli_suspend(struct snd_ice1712 *ice)
 {
        struct snd_akm4xxx *ak = ice->akm;
+       struct juli_spec *spec = ice->spec;
        /* akm4358 reset and soft-mute */
        snd_akm4xxx_reset(ak, 1);
+       snd_ak4114_suspend(spec->ak4114);
        return 0;
 }
 #endif
index 21b373b2e2600e7f91f7ee680512502f79a96479..f7ac8d5e862cf9b0e861ad790095c2d2295dc807 100644 (file)
@@ -183,22 +183,6 @@ void snd_wm8766_set_if(struct snd_wm8766 *wm, u16 dac)
        snd_wm8766_write(wm, WM8766_REG_IFCTRL, val | dac);
 }
 
-void snd_wm8766_set_master_mode(struct snd_wm8766 *wm, u16 mode)
-{
-       u16 val = wm->regs[WM8766_REG_DACCTRL3] & ~WM8766_DAC3_MSTR_MASK;
-
-       mode &= WM8766_DAC3_MSTR_MASK;
-       snd_wm8766_write(wm, WM8766_REG_DACCTRL3, val | mode);
-}
-
-void snd_wm8766_set_power(struct snd_wm8766 *wm, u16 power)
-{
-       u16 val = wm->regs[WM8766_REG_DACCTRL3] & ~WM8766_DAC3_POWER_MASK;
-
-       power &= WM8766_DAC3_POWER_MASK;
-       snd_wm8766_write(wm, WM8766_REG_DACCTRL3, val | power);
-}
-
 void snd_wm8766_volume_restore(struct snd_wm8766 *wm)
 {
        u16 val = wm->regs[WM8766_REG_DACR1];
index c119f84bd2c26a63cfce79027a480a5075fc2483..18c8d9d47b386fff00b34026e7ff38efd2460a6e 100644 (file)
@@ -155,8 +155,6 @@ struct snd_wm8766 {
 void snd_wm8766_init(struct snd_wm8766 *wm);
 void snd_wm8766_resume(struct snd_wm8766 *wm);
 void snd_wm8766_set_if(struct snd_wm8766 *wm, u16 dac);
-void snd_wm8766_set_master_mode(struct snd_wm8766 *wm, u16 mode);
-void snd_wm8766_set_power(struct snd_wm8766 *wm, u16 power);
 void snd_wm8766_volume_restore(struct snd_wm8766 *wm);
 int snd_wm8766_build_controls(struct snd_wm8766 *wm);
 
index e66c0da62014bfd75453770a2fdc8ddec106e827..ebd2fe4b4a57c4e25b5905d741602ba8ef58ca9b 100644 (file)
@@ -452,21 +452,6 @@ void snd_wm8776_resume(struct snd_wm8776 *wm)
                snd_wm8776_write(wm, i, wm->regs[i]);
 }
 
-void snd_wm8776_set_dac_if(struct snd_wm8776 *wm, u16 dac)
-{
-       snd_wm8776_write(wm, WM8776_REG_DACIFCTRL, dac);
-}
-
-void snd_wm8776_set_adc_if(struct snd_wm8776 *wm, u16 adc)
-{
-       snd_wm8776_write(wm, WM8776_REG_ADCIFCTRL, adc);
-}
-
-void snd_wm8776_set_master_mode(struct snd_wm8776 *wm, u16 mode)
-{
-       snd_wm8776_write(wm, WM8776_REG_MSTRCTRL, mode);
-}
-
 void snd_wm8776_set_power(struct snd_wm8776 *wm, u16 power)
 {
        snd_wm8776_write(wm, WM8776_REG_PWRDOWN, power);
index 93a2d6971154e7426b7901c67967d1ded8324fe4..42acef05540c2134761b6541bae25a6a944ed35b 100644 (file)
@@ -216,9 +216,6 @@ struct snd_wm8776 {
 
 void snd_wm8776_init(struct snd_wm8776 *wm);
 void snd_wm8776_resume(struct snd_wm8776 *wm);
-void snd_wm8776_set_dac_if(struct snd_wm8776 *wm, u16 dac);
-void snd_wm8776_set_adc_if(struct snd_wm8776 *wm, u16 adc);
-void snd_wm8776_set_master_mode(struct snd_wm8776 *wm, u16 mode);
 void snd_wm8776_set_power(struct snd_wm8776 *wm, u16 power);
 void snd_wm8776_volume_restore(struct snd_wm8776 *wm);
 int snd_wm8776_build_controls(struct snd_wm8776 *wm);
index 4a28252a42b961c568b278ee904133b31bedbb52..2c5484eeb96386a9dc4f06177eae71afc3b8fcc4 100644 (file)
@@ -26,7 +26,7 @@
  *
  */      
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -2654,7 +2654,6 @@ static int snd_intel8x0_free(struct intel8x0 *chip)
  */
 static int intel8x0_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct intel8x0 *chip = card->private_data;
        int i;
@@ -2682,12 +2681,6 @@ static int intel8x0_suspend(struct device *dev)
                free_irq(chip->irq, chip);
                chip->irq = -1;
        }
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       /* The call below may disable built-in speaker on some laptops
-        * after S2RAM.  So, don't touch it.
-        */
-       /* pci_set_power_state(pci, PCI_D3hot); */
        return 0;
 }
 
@@ -2698,14 +2691,6 @@ static int intel8x0_resume(struct device *dev)
        struct intel8x0 *chip = card->private_data;
        int i;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
        snd_intel8x0_chip_init(chip, 0);
        if (request_irq(pci->irq, snd_intel8x0_interrupt,
                        IRQF_SHARED, KBUILD_MODNAME, chip)) {
index 6b40235be13c6c493d483ac1b2c9a9025b6025a2..7577f31cd5047447effe05b7a1746734ceb6edf5 100644 (file)
@@ -23,7 +23,7 @@
  *
  */      
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -1023,7 +1023,6 @@ static int snd_intel8x0m_free(struct intel8x0m *chip)
  */
 static int intel8x0m_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct intel8x0m *chip = card->private_data;
        int i;
@@ -1036,9 +1035,6 @@ static int intel8x0m_suspend(struct device *dev)
                free_irq(chip->irq, chip);
                chip->irq = -1;
        }
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
@@ -1048,14 +1044,6 @@ static int intel8x0m_resume(struct device *dev)
        struct snd_card *card = dev_get_drvdata(dev);
        struct intel8x0m *chip = card->private_data;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
        if (request_irq(pci->irq, snd_intel8x0m_interrupt,
                        IRQF_SHARED, KBUILD_MODNAME, chip)) {
                dev_err(dev, "unable to grab IRQ %d, disabling device\n",
index 59d21c9401d2ef95843c8c2e0214528b06da016d..7acbc21d642a53fe8658c52bdcf91992f08816ac 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/firmware.h>
+#include <linux/io.h>
 
 #include <sound/core.h>
 #include <sound/info.h>
@@ -36,8 +37,6 @@
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
 
-#include <asm/io.h>
-
 // ----------------------------------------------------------------------------
 // Debug Stuff
 // ----------------------------------------------------------------------------
@@ -585,8 +584,7 @@ static void snd_korg1212_SendStop(struct snd_korg1212 *korg1212)
                korg1212->sharedBufferPtr->cardCommand = 0xffffffff;
                /* program the timer */
                korg1212->stop_pending_cnt = HZ;
-               korg1212->timer.expires = jiffies + 1;
-               add_timer(&korg1212->timer);
+               mod_timer(&korg1212->timer, jiffies + 1);
        }
 }
 
@@ -617,8 +615,7 @@ static void snd_korg1212_timer_func(unsigned long data)
        } else {
                if (--korg1212->stop_pending_cnt > 0) {
                        /* reprogram timer */
-                       korg1212->timer.expires = jiffies + 1;
-                       add_timer(&korg1212->timer);
+                       mod_timer(&korg1212->timer, jiffies + 1);
                } else {
                        snd_printd("korg1212_timer_func timeout\n");
                        korg1212->sharedBufferPtr->cardCommand = 0;
@@ -2172,9 +2169,8 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci,
         init_waitqueue_head(&korg1212->wait);
         spin_lock_init(&korg1212->lock);
        mutex_init(&korg1212->open_mutex);
-       init_timer(&korg1212->timer);
-       korg1212->timer.function = snd_korg1212_timer_func;
-       korg1212->timer.data = (unsigned long)korg1212;
+       setup_timer(&korg1212->timer, snd_korg1212_timer_func,
+                   (unsigned long)korg1212);
 
         korg1212->irq = -1;
         korg1212->clkSource = K1212_CLKIDX_Local;
index 4cf4be5ef82a3b0377b853af6aef59beafa9d38a..9ff6000849732cdb66a80fc8aaad81eb38a77327 100644 (file)
@@ -551,10 +551,8 @@ static void lola_free(struct lola *chip)
        lola_free_mixer(chip);
        if (chip->irq >= 0)
                free_irq(chip->irq, (void *)chip);
-       if (chip->bar[0].remap_addr)
-               iounmap(chip->bar[0].remap_addr);
-       if (chip->bar[1].remap_addr)
-               iounmap(chip->bar[1].remap_addr);
+       iounmap(chip->bar[0].remap_addr);
+       iounmap(chip->bar[1].remap_addr);
        if (chip->rb.area)
                snd_dma_free_pages(&chip->rb);
        pci_release_regions(chip->pci);
index 98823d11d485073dbbd0a6f2fc53988663d94277..9be660993bd022bb7f662a213f6662dce1a7de98 100644 (file)
@@ -31,7 +31,7 @@
 #define CARD_NAME "ESS Maestro3/Allegro/Canyon3D-2"
 #define DRIVER_NAME "Maestro3"
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -2395,7 +2395,6 @@ static int snd_m3_free(struct snd_m3 *chip)
 #ifdef CONFIG_PM_SLEEP
 static int m3_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_m3 *chip = card->private_data;
        int i, dsp_index;
@@ -2421,16 +2420,11 @@ static int m3_suspend(struct device *dev)
        for (i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++)
                chip->suspend_mem[dsp_index++] =
                        snd_m3_assp_read(chip, MEMTYPE_INTERNAL_DATA, i);
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int m3_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_m3 *chip = card->private_data;
        int i, dsp_index;
@@ -2438,15 +2432,6 @@ static int m3_resume(struct device *dev)
        if (chip->suspend_mem == NULL)
                return 0;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
-
        /* first lets just bring everything back. .*/
        snd_m3_outw(chip, 0, 0x54);
        snd_m3_outw(chip, 0, 0x56);
index 1faf47e81570f889c5800165402a6c4cbea745d4..c3a9f39f8d61a822921e647b2bea5e147c10c7ae 100644 (file)
@@ -1114,10 +1114,9 @@ static int snd_mixart_free(struct mixart_mgr *mgr)
        }
 
        /* release the i/o ports */
-       for (i = 0; i < 2; i++) {
-               if (mgr->mem[i].virt)
-                       iounmap(mgr->mem[i].virt);
-       }
+       for (i = 0; i < 2; ++i)
+               iounmap(mgr->mem[i].virt);
+
        pci_release_regions(mgr->pci);
 
        /* free flowarray */
index fe80313674d9ce7e30ba9cc1b2278dfc521d9089..dccf3db48fe06cdd4acd7dca661430abb50e4f1e 100644 (file)
@@ -23,8 +23,8 @@
 #include <linux/interrupt.h>
 #include <linux/mutex.h>
 #include <linux/pci.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <sound/core.h>
 #include "mixart.h"
 #include "mixart_hwdep.h"
index 9996a4dead0fc3edba23c8b46b8cb1449794330c..5bfd3ac80db5a24505a54fb133def69c13da5166 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include "mixart.h"
 #include "mixart_mixer.h"
index 4e41a4e29a1e4dd48fb11ec4981b0da8a90c0b56..4735e27cc773688fe672a9bc7f609b3b38be85e4 100644 (file)
@@ -24,7 +24,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
   
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -1392,7 +1392,6 @@ snd_nm256_peek_for_sig(struct nm256 *chip)
  */
 static int nm256_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct nm256 *chip = card->private_data;
 
@@ -1400,15 +1399,11 @@ static int nm256_suspend(struct device *dev)
        snd_pcm_suspend_all(chip->pcm);
        snd_ac97_suspend(chip->ac97);
        chip->coeffs_current = 0;
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int nm256_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct nm256 *chip = card->private_data;
        int i;
@@ -1416,15 +1411,6 @@ static int nm256_resume(struct device *dev)
        /* Perform a full reset on the hardware */
        chip->in_resume = 1;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
-
        snd_nm256_init_chip(chip);
 
        /* restore ac97 */
@@ -1460,10 +1446,8 @@ static int snd_nm256_free(struct nm256 *chip)
        if (chip->irq >= 0)
                free_irq(chip->irq, chip);
 
-       if (chip->cport)
-               iounmap(chip->cport);
-       if (chip->buffer)
-               iounmap(chip->buffer);
+       iounmap(chip->cport);
+       iounmap(chip->buffer);
        release_and_free_resource(chip->res_cport);
        release_and_free_resource(chip->res_buffer);
 
index 8f4c409f7e4528984f1f4dd1326ab014d8a7f3ea..ab085d7536616fb3bb3dab86ed88a69432e841ea 100644 (file)
@@ -1,8 +1,10 @@
 snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o
 snd-oxygen-objs := oxygen.o xonar_dg_mixer.o xonar_dg.o
+snd-se6x-objs := se6x.o
 snd-virtuoso-objs := virtuoso.o xonar_lib.o \
        xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o
 
 obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o
 obj-$(CONFIG_SND_OXYGEN) += snd-oxygen.o
+obj-$(CONFIG_SND_SE6X) += snd-se6x.o
 obj-$(CONFIG_SND_VIRTUOSO) += snd-virtuoso.o
index c10ab077afd89aa3ec03681093e6c50743a36bca..293d0b9a50c3fbdde4ec73a93939b80286dc648d 100644 (file)
@@ -35,7 +35,7 @@
 #define CAPTURE_1_FROM_SPDIF   0x0080
 #define CAPTURE_2_FROM_I2S_2   0x0100
 #define CAPTURE_2_FROM_AC97_1  0x0200
-     /* CAPTURE_3_FROM_I2S_3           not implemented */
+#define CAPTURE_3_FROM_I2S_3   0x0400
 #define MIDI_OUTPUT            0x0800
 #define MIDI_INPUT             0x1000
 #define AC97_CD_INPUT          0x2000
index 4b8a32c37e3105ef22bce70d881cdbda400ae89a..c7851da377490b0e4b8c339c25c010518c635571 100644 (file)
@@ -20,9 +20,9 @@
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/export.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/mpu401.h>
-#include <asm/io.h>
 #include "oxygen.h"
 
 u8 oxygen_read8(struct oxygen *chip, unsigned int reg)
index b67e306024738e3932001e05306708282967e009..ffff3b25fd73ffe6f473b548964a69beeb0894d0 100644 (file)
@@ -319,11 +319,12 @@ static void oxygen_restore_eeprom(struct oxygen *chip,
 
 static void configure_pcie_bridge(struct pci_dev *pci)
 {
-       enum { PEX811X, PI7C9X110 };
+       enum { PEX811X, PI7C9X110, XIO2001 };
        static const struct pci_device_id bridge_ids[] = {
                { PCI_VDEVICE(PLX, 0x8111), .driver_data = PEX811X },
                { PCI_VDEVICE(PLX, 0x8112), .driver_data = PEX811X },
                { PCI_DEVICE(0x12d8, 0xe110), .driver_data = PI7C9X110 },
+               { PCI_VDEVICE(TI, 0x8240), .driver_data = XIO2001 },
                { }
        };
        struct pci_dev *bridge;
@@ -357,6 +358,14 @@ static void configure_pcie_bridge(struct pci_dev *pci)
                tmp |= 1;       /* park the PCI arbiter to the sound chip */
                pci_write_config_dword(bridge, 0x40, tmp);
                break;
+
+       case XIO2001: /* Texas Instruments XIO2001 PCIe/PCI bridge */
+               pci_read_config_dword(bridge, 0xe8, &tmp);
+               tmp &= ~0xf;    /* request length limit: 64 bytes */
+               tmp &= ~(0xf << 8);
+               tmp |= 1 << 8;  /* request count limit: one buffer */
+               pci_write_config_dword(bridge, 0xe8, tmp);
+               break;
        }
 }
 
@@ -441,9 +450,18 @@ static void oxygen_init(struct oxygen *chip)
                oxygen_write16(chip, OXYGEN_I2S_B_FORMAT,
                               OXYGEN_I2S_MASTER |
                               OXYGEN_I2S_MUTE_MCLK);
-       oxygen_write16(chip, OXYGEN_I2S_C_FORMAT,
-                      OXYGEN_I2S_MASTER |
-                      OXYGEN_I2S_MUTE_MCLK);
+       if (chip->model.device_config & CAPTURE_3_FROM_I2S_3)
+               oxygen_write16(chip, OXYGEN_I2S_C_FORMAT,
+                              OXYGEN_RATE_48000 |
+                              chip->model.adc_i2s_format |
+                              OXYGEN_I2S_MCLK(chip->model.adc_mclks) |
+                              OXYGEN_I2S_BITS_16 |
+                              OXYGEN_I2S_MASTER |
+                              OXYGEN_I2S_BCLK_64);
+       else
+               oxygen_write16(chip, OXYGEN_I2S_C_FORMAT,
+                              OXYGEN_I2S_MASTER |
+                              OXYGEN_I2S_MUTE_MCLK);
        oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL,
                            OXYGEN_SPDIF_OUT_ENABLE |
                            OXYGEN_SPDIF_LOOPBACK);
@@ -728,7 +746,6 @@ EXPORT_SYMBOL(oxygen_pci_remove);
 #ifdef CONFIG_PM_SLEEP
 static int oxygen_pci_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct oxygen *chip = card->private_data;
        unsigned int i, saved_interrupt_mask;
@@ -736,8 +753,7 @@ static int oxygen_pci_suspend(struct device *dev)
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
 
        for (i = 0; i < PCM_COUNT; ++i)
-               if (chip->streams[i])
-                       snd_pcm_suspend(chip->streams[i]);
+               snd_pcm_suspend(chip->streams[i]);
 
        if (chip->model.suspend)
                chip->model.suspend(chip);
@@ -753,10 +769,6 @@ static int oxygen_pci_suspend(struct device *dev)
        flush_work(&chip->spdif_input_bits_work);
        flush_work(&chip->gpio_work);
        chip->interrupt_mask = saved_interrupt_mask;
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
@@ -788,20 +800,10 @@ static void oxygen_restore_ac97(struct oxygen *chip, unsigned int codec)
 
 static int oxygen_pci_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct oxygen *chip = card->private_data;
        unsigned int i;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "cannot reenable device");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
-
        oxygen_write16(chip, OXYGEN_DMA_STATUS, 0);
        oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0);
        for (i = 0; i < OXYGEN_IO_SIZE; ++i)
index 5988e044c5194e0650ab78c2ec4cf1eff069f8d0..6492bca8c70f8bbfdf31e2fb13321904f5a5b00a 100644 (file)
@@ -786,6 +786,9 @@ static const struct snd_kcontrol_new controls[] = {
                .get = upmix_get,
                .put = upmix_put,
        },
+};
+
+static const struct snd_kcontrol_new spdif_output_controls[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH),
@@ -937,6 +940,33 @@ static const struct {
                        },
                },
        },
+       {
+               .pcm_dev = CAPTURE_3_FROM_I2S_3,
+               .controls = {
+                       {
+                               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+                               .name = "Analog Input Monitor Playback Switch",
+                               .index = 2,
+                               .info = snd_ctl_boolean_mono_info,
+                               .get = monitor_get,
+                               .put = monitor_put,
+                               .private_value = OXYGEN_ADC_MONITOR_C,
+                       },
+                       {
+                               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+                               .name = "Analog Input Monitor Playback Volume",
+                               .index = 2,
+                               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+                               .info = monitor_volume_info,
+                               .get = monitor_get,
+                               .put = monitor_put,
+                               .private_value = OXYGEN_ADC_MONITOR_C_HALF_VOL
+                                               | (1 << 8),
+                               .tlv = { .p = monitor_db_scale, },
+                       },
+               },
+       },
        {
                .pcm_dev = CAPTURE_1_FROM_SPDIF,
                .controls = {
@@ -1073,6 +1103,12 @@ int oxygen_mixer_init(struct oxygen *chip)
        err = add_controls(chip, controls, ARRAY_SIZE(controls));
        if (err < 0)
                return err;
+       if (chip->model.device_config & PLAYBACK_1_TO_SPDIF) {
+               err = add_controls(chip, spdif_output_controls,
+                                  ARRAY_SIZE(spdif_output_controls));
+               if (err < 0)
+                       return err;
+       }
        if (chip->model.device_config & CAPTURE_1_FROM_SPDIF) {
                err = add_controls(chip, spdif_input_controls,
                                   ARRAY_SIZE(spdif_input_controls));
index 02828240ba15740600a65b2eaf07b3f663c3463b..aa2ebd1d6d12ed2fe9714a5664f4c809c4f93a51 100644 (file)
@@ -144,9 +144,11 @@ static int oxygen_open(struct snd_pcm_substream *substream,
                runtime->hw = *oxygen_hardware[channel];
        switch (channel) {
        case PCM_C:
-               runtime->hw.rates &= ~(SNDRV_PCM_RATE_32000 |
-                                      SNDRV_PCM_RATE_64000);
-               runtime->hw.rate_min = 44100;
+               if (chip->model.device_config & CAPTURE_1_FROM_SPDIF) {
+                       runtime->hw.rates &= ~(SNDRV_PCM_RATE_32000 |
+                                              SNDRV_PCM_RATE_64000);
+                       runtime->hw.rate_min = 44100;
+               }
                /* fall through */
        case PCM_A:
        case PCM_B:
@@ -430,17 +432,36 @@ static int oxygen_rec_c_hw_params(struct snd_pcm_substream *substream,
                                  struct snd_pcm_hw_params *hw_params)
 {
        struct oxygen *chip = snd_pcm_substream_chip(substream);
+       bool is_spdif;
        int err;
 
        err = oxygen_hw_params(substream, hw_params);
        if (err < 0)
                return err;
 
+       is_spdif = chip->model.device_config & CAPTURE_1_FROM_SPDIF;
+
        spin_lock_irq(&chip->reg_lock);
        oxygen_write8_masked(chip, OXYGEN_REC_FORMAT,
                             oxygen_format(hw_params) << OXYGEN_REC_FORMAT_C_SHIFT,
                             OXYGEN_REC_FORMAT_C_MASK);
+       if (!is_spdif)
+               oxygen_write16_masked(chip, OXYGEN_I2S_C_FORMAT,
+                                     oxygen_rate(hw_params) |
+                                     chip->model.adc_i2s_format |
+                                     get_mclk(chip, PCM_B, hw_params) |
+                                     oxygen_i2s_bits(hw_params),
+                                     OXYGEN_I2S_RATE_MASK |
+                                     OXYGEN_I2S_FORMAT_MASK |
+                                     OXYGEN_I2S_MCLK_MASK |
+                                     OXYGEN_I2S_BITS_MASK);
        spin_unlock_irq(&chip->reg_lock);
+
+       if (!is_spdif) {
+               mutex_lock(&chip->mutex);
+               chip->model.set_adc_params(chip, hw_params);
+               mutex_unlock(&chip->mutex);
+       }
        return 0;
 }
 
@@ -676,11 +697,6 @@ static struct snd_pcm_ops oxygen_ac97_ops = {
        .pointer   = oxygen_pointer,
 };
 
-static void oxygen_pcm_free(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 int oxygen_pcm_init(struct oxygen *chip)
 {
        struct snd_pcm *pcm;
@@ -705,7 +721,6 @@ int oxygen_pcm_init(struct oxygen *chip)
                        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
                                        &oxygen_rec_b_ops);
                pcm->private_data = chip;
-               pcm->private_free = oxygen_pcm_free;
                strcpy(pcm->name, "Multichannel");
                if (outs)
                        snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
@@ -734,7 +749,6 @@ int oxygen_pcm_init(struct oxygen *chip)
                        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
                                        &oxygen_rec_c_ops);
                pcm->private_data = chip;
-               pcm->private_free = oxygen_pcm_free;
                strcpy(pcm->name, "Digital");
                snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                                      snd_dma_pci_data(chip->pci),
@@ -765,12 +779,29 @@ int oxygen_pcm_init(struct oxygen *chip)
                        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
                                        &oxygen_rec_b_ops);
                pcm->private_data = chip;
-               pcm->private_free = oxygen_pcm_free;
                strcpy(pcm->name, outs ? "Front Panel" : "Analog 2");
                snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                                      snd_dma_pci_data(chip->pci),
                                                      DEFAULT_BUFFER_BYTES,
                                                      BUFFER_BYTES_MAX);
        }
+
+       ins = !!(chip->model.device_config & CAPTURE_3_FROM_I2S_3);
+       if (ins) {
+               err = snd_pcm_new(chip->card, "Analog3", 3, 0, ins, &pcm);
+               if (err < 0)
+                       return err;
+               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+                               &oxygen_rec_c_ops);
+               oxygen_write8_masked(chip, OXYGEN_REC_ROUTING,
+                                    OXYGEN_REC_C_ROUTE_I2S_ADC_3,
+                                    OXYGEN_REC_C_ROUTE_MASK);
+               pcm->private_data = chip;
+               strcpy(pcm->name, "Analog 3");
+               snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+                                                     snd_dma_pci_data(chip->pci),
+                                                     DEFAULT_BUFFER_BYTES,
+                                                     BUFFER_BYTES_MAX);
+       }
        return 0;
 }
diff --git a/sound/pci/oxygen/se6x.c b/sound/pci/oxygen/se6x.c
new file mode 100644 (file)
index 0000000..f70d514
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * C-Media CMI8787 driver for the Studio Evolution SE6X
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License, version 2.
+ *
+ *  This driver is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * CMI8787:
+ *
+ *   SPI    -> microcontroller (not actually used)
+ *   GPIO 0 -> do.
+ *   GPIO 2 -> do.
+ *
+ *   DAC0   -> both PCM1792A (L+R, each in mono mode)
+ *   ADC1  <-  1st PCM1804
+ *   ADC2  <-  2nd PCM1804
+ *   ADC3  <-  3rd PCM1804
+ */
+
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include "oxygen.h"
+
+MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
+MODULE_DESCRIPTION("Studio Evolution SE6X driver");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("{{Studio Evolution,SE6X}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "card index");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "enable card");
+
+static const struct pci_device_id se6x_ids[] = {
+       { OXYGEN_PCI_SUBID(0x13f6, 0x8788) },
+       { }
+};
+MODULE_DEVICE_TABLE(pci, se6x_ids);
+
+static void se6x_init(struct oxygen *chip)
+{
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, 0x005);
+
+       snd_component_add(chip->card, "PCM1792A");
+       snd_component_add(chip->card, "PCM1804");
+}
+
+static int se6x_control_filter(struct snd_kcontrol_new *template)
+{
+       /* no DAC volume/mute */
+       if (!strncmp(template->name, "Master Playback ", 16))
+               return 1;
+       return 0;
+}
+
+static void se6x_cleanup(struct oxygen *chip)
+{
+}
+
+static void set_pcm1792a_params(struct oxygen *chip,
+                               struct snd_pcm_hw_params *params)
+{
+       /* nothing to do (the microcontroller monitors DAC_LRCK) */
+}
+
+static void set_pcm1804_params(struct oxygen *chip,
+                              struct snd_pcm_hw_params *params)
+{
+}
+
+static unsigned int se6x_adjust_dac_routing(struct oxygen *chip,
+                                           unsigned int play_routing)
+{
+       /* route the same stereo pair to DAC0 and DAC1 */
+       return ( play_routing       & OXYGEN_PLAY_DAC0_SOURCE_MASK) |
+              ((play_routing << 2) & OXYGEN_PLAY_DAC1_SOURCE_MASK);
+}
+
+static const struct oxygen_model model_se6x = {
+       .shortname = "Studio Evolution SE6X",
+       .longname = "C-Media Oxygen HD Audio",
+       .chip = "CMI8787",
+       .init = se6x_init,
+       .control_filter = se6x_control_filter,
+       .cleanup = se6x_cleanup,
+       .set_dac_params = set_pcm1792a_params,
+       .set_adc_params = set_pcm1804_params,
+       .adjust_dac_routing = se6x_adjust_dac_routing,
+       .device_config = PLAYBACK_0_TO_I2S |
+                        CAPTURE_0_FROM_I2S_1 |
+                        CAPTURE_2_FROM_I2S_2 |
+                        CAPTURE_3_FROM_I2S_3,
+       .dac_channels_pcm = 2,
+       .function_flags = OXYGEN_FUNCTION_SPI,
+       .dac_mclks = OXYGEN_MCLKS(256, 128, 128),
+       .adc_mclks = OXYGEN_MCLKS(256, 256, 128),
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+       .adc_i2s_format = OXYGEN_I2S_FORMAT_I2S,
+};
+
+static int se6x_get_model(struct oxygen *chip,
+                         const struct pci_device_id *pci_id)
+{
+       chip->model = model_se6x;
+       return 0;
+}
+
+static int se6x_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+{
+       static int dev;
+       int err;
+
+       if (dev >= SNDRV_CARDS)
+               return -ENODEV;
+       if (!enable[dev]) {
+               ++dev;
+               return -ENOENT;
+       }
+       err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE,
+                              se6x_ids, se6x_get_model);
+       if (err >= 0)
+               ++dev;
+       return err;
+}
+
+static struct pci_driver se6x_driver = {
+       .name = KBUILD_MODNAME,
+       .id_table = se6x_ids,
+       .probe = se6x_probe,
+       .remove = oxygen_pci_remove,
+#ifdef CONFIG_PM_SLEEP
+       .driver = {
+               .pm = &oxygen_pci_pm,
+       },
+#endif
+       .shutdown = oxygen_pci_shutdown,
+};
+
+module_pci_driver(se6x_driver);
index 181f7729d409e50fe2cd2f592e9410186827d4f2..c5194f5b150aadb7d0b08cd5831aab2a03f2392d 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/firmware.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include "pcxhr.h"
 #include "pcxhr_mixer.h"
index 15a8ce5f1f48d84e2a71f1e4557f6fa07bc31279..80633055e17e35c56131a24e1b373cd6d63d3989 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/firmware.h>
 #include <linux/pci.h>
 #include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/hwdep.h>
 #include "pcxhr.h"
index 6abc2ac8fffb3e5b8d358b68d4c604eff4102606..94639d6b5fb5a3cb19031afbe0dc4432f33dcfe7 100644 (file)
@@ -99,7 +99,7 @@
 #include <linux/firmware.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -1153,7 +1153,6 @@ static void riptide_handleirq(unsigned long dev_id)
 #ifdef CONFIG_PM_SLEEP
 static int riptide_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_riptide *chip = card->private_data;
 
@@ -1161,27 +1160,14 @@ static int riptide_suspend(struct device *dev)
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        snd_pcm_suspend_all(chip->pcm);
        snd_ac97_suspend(chip->ac97);
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int riptide_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_riptide *chip = card->private_data;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               printk(KERN_ERR "riptide: pci_enable_device failed, "
-                      "disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
        snd_riptide_initialize(chip);
        snd_ac97_resume(chip->ac97);
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
@@ -1706,14 +1692,11 @@ static struct snd_pcm_ops snd_riptide_capture_ops = {
        .pointer = snd_riptide_pointer,
 };
 
-static int
-snd_riptide_pcm(struct snd_riptide *chip, int device, struct snd_pcm **rpcm)
+static int snd_riptide_pcm(struct snd_riptide *chip, int device)
 {
        struct snd_pcm *pcm;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
        if ((err =
             snd_pcm_new(chip->card, "RIPTIDE", device, PLAYBACK_SUBSTREAMS, 1,
                         &pcm)) < 0)
@@ -1729,8 +1712,6 @@ snd_riptide_pcm(struct snd_riptide *chip, int device, struct snd_pcm **rpcm)
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
                                              snd_dma_pci_data(chip->pci),
                                              64 * 1024, 128 * 1024);
-       if (rpcm)
-               *rpcm = pcm;
        return 0;
 }
 
@@ -2030,32 +2011,43 @@ snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id)
 {
        static int dev;
        struct gameport *gameport;
+       int ret;
 
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
+
        if (!enable[dev]) {
-               dev++;
-               return -ENOENT;
+               ret = -ENOENT;
+               goto inc_dev;
        }
 
-       if (!joystick_port[dev++])
-               return 0;
+       if (!joystick_port[dev]) {
+               ret = 0;
+               goto inc_dev;
+       }
 
        gameport = gameport_allocate_port();
-       if (!gameport)
-               return -ENOMEM;
+       if (!gameport) {
+               ret = -ENOMEM;
+               goto inc_dev;
+       }
        if (!request_region(joystick_port[dev], 8, "Riptide gameport")) {
                snd_printk(KERN_WARNING
                           "Riptide: cannot grab gameport 0x%x\n",
                           joystick_port[dev]);
                gameport_free_port(gameport);
-               return -EBUSY;
+               ret = -EBUSY;
+               goto inc_dev;
        }
 
        gameport->io = joystick_port[dev];
        gameport_register_port(gameport);
        pci_set_drvdata(pci, gameport);
-       return 0;
+
+       ret = 0;
+inc_dev:
+       dev++;
+       return ret;
 }
 
 static void snd_riptide_joystick_remove(struct pci_dev *pci)
@@ -2092,7 +2084,7 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
        if (err < 0)
                goto error;
        card->private_data = chip;
-       err = snd_riptide_pcm(chip, 0, NULL);
+       err = snd_riptide_pcm(chip, 0);
        if (err < 0)
                goto error;
        err = snd_riptide_mixer(chip);
index 6c60dcd2e5a1daf45479702c51f9223d6155516c..23d7f5d30c4106e107436999673358e0fb65ff8b 100644 (file)
@@ -75,6 +75,7 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/module.h>
+#include <linux/io.h>
 
 #include <sound/core.h>
 #include <sound/info.h>
@@ -85,8 +86,6 @@
 #include <sound/asoundef.h>
 #include <sound/initval.h>
 
-#include <asm/io.h>
-
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
 static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;    /* Enable this card */
@@ -632,7 +631,7 @@ snd_rme32_setframelog(struct rme32 * rme32, int n_channels, int is_playback)
        }
 }
 
-static int snd_rme32_setformat(struct rme32 * rme32, int format)
+static int snd_rme32_setformat(struct rme32 *rme32, snd_pcm_format_t format)
 {
        switch (format) {
        case SNDRV_PCM_FORMAT_S16_LE:
index 2f1a85185a16afc618f96273223f80cda384f738..2306ccf7281e29c9e428b4349c34ade9d12e2296 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/pci.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
+#include <linux/io.h>
 
 #include <sound/core.h>
 #include <sound/info.h>
@@ -38,8 +39,6 @@
 #include <sound/asoundef.h>
 #include <sound/initval.h>
 
-#include <asm/io.h>
-
 /* note, two last pcis should be equal, it is not a bug */
 
 MODULE_AUTHOR("Anders Torger <torger@ludd.luth.se>");
@@ -922,8 +921,7 @@ snd_rme96_setframelog(struct rme96 *rme96,
 }
 
 static int
-snd_rme96_playback_setformat(struct rme96 *rme96,
-                            int format)
+snd_rme96_playback_setformat(struct rme96 *rme96, snd_pcm_format_t format)
 {
        switch (format) {
        case SNDRV_PCM_FORMAT_S16_LE:
@@ -940,8 +938,7 @@ snd_rme96_playback_setformat(struct rme96 *rme96,
 }
 
 static int
-snd_rme96_capture_setformat(struct rme96 *rme96,
-                           int format)
+snd_rme96_capture_setformat(struct rme96 *rme96, snd_pcm_format_t format)
 {
        switch (format) {
        case SNDRV_PCM_FORMAT_S16_LE:
@@ -2358,7 +2355,6 @@ snd_rme96_create_switches(struct snd_card *card,
 
 static int rme96_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct rme96 *rme96 = card->private_data;
 
@@ -2381,26 +2377,14 @@ static int rme96_suspend(struct device *dev)
        /* disable the DAC  */
        rme96->areg &= ~RME96_AR_DAC_EN;
        writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-
        return 0;
 }
 
 static int rme96_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct rme96 *rme96 = card->private_data;
 
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-
        /* reset playback and record buffer pointers */
        writel(0, rme96->iobase + RME96_IO_SET_PLAY_POS
                  + rme96->playback_pointer);
index cf5a6c8b9a63a36aee58b438e58190be9f6231df..c19e021ccf668af1aadec6377b1d3e1ebca9b090 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/math64.h>
 #include <linux/vmalloc.h>
+#include <linux/io.h>
 
 #include <sound/core.h>
 #include <sound/control.h>
@@ -42,7 +43,6 @@
 
 #include <asm/byteorder.h>
 #include <asm/current.h>
-#include <asm/io.h>
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
@@ -1428,10 +1428,8 @@ static void snd_hdsp_midi_output_timer(unsigned long data)
           leaving istimer wherever it was set before.
        */
 
-       if (hmidi->istimer) {
-               hmidi->timer.expires = 1 + jiffies;
-               add_timer(&hmidi->timer);
-       }
+       if (hmidi->istimer)
+               mod_timer(&hmidi->timer, 1 + jiffies);
 
        spin_unlock_irqrestore (&hmidi->lock, flags);
 }
@@ -1445,11 +1443,9 @@ static void snd_hdsp_midi_output_trigger(struct snd_rawmidi_substream *substream
        spin_lock_irqsave (&hmidi->lock, flags);
        if (up) {
                if (!hmidi->istimer) {
-                       init_timer(&hmidi->timer);
-                       hmidi->timer.function = snd_hdsp_midi_output_timer;
-                       hmidi->timer.data = (unsigned long) hmidi;
-                       hmidi->timer.expires = 1 + jiffies;
-                       add_timer(&hmidi->timer);
+                       setup_timer(&hmidi->timer, snd_hdsp_midi_output_timer,
+                                   (unsigned long) hmidi);
+                       mod_timer(&hmidi->timer, 1 + jiffies);
                        hmidi->istimer++;
                }
        } else {
@@ -5309,9 +5305,7 @@ static int snd_hdsp_free(struct hdsp *hdsp)
 
        release_firmware(hdsp->firmware);
        vfree(hdsp->fw_uploaded);
-
-       if (hdsp->iobase)
-               iounmap(hdsp->iobase);
+       iounmap(hdsp->iobase);
 
        if (hdsp->port)
                pci_release_regions(hdsp->pci);
index 3342705a571506c66358840d74a579499b866d1c..2c363fdca9fd00e0b82b99d029a4bd53a9728467 100644 (file)
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/math64.h>
-#include <asm/io.h>
+#include <linux/io.h>
 
 #include <sound/core.h>
 #include <sound/control.h>
@@ -1957,10 +1957,8 @@ static void snd_hdspm_midi_output_timer(unsigned long data)
           leaving istimer wherever it was set before.
        */
 
-       if (hmidi->istimer) {
-               hmidi->timer.expires = 1 + jiffies;
-               add_timer(&hmidi->timer);
-       }
+       if (hmidi->istimer)
+               mod_timer(&hmidi->timer, 1 + jiffies);
 
        spin_unlock_irqrestore (&hmidi->lock, flags);
 }
@@ -1975,11 +1973,9 @@ snd_hdspm_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
        spin_lock_irqsave (&hmidi->lock, flags);
        if (up) {
                if (!hmidi->istimer) {
-                       init_timer(&hmidi->timer);
-                       hmidi->timer.function = snd_hdspm_midi_output_timer;
-                       hmidi->timer.data = (unsigned long) hmidi;
-                       hmidi->timer.expires = 1 + jiffies;
-                       add_timer(&hmidi->timer);
+                       setup_timer(&hmidi->timer, snd_hdspm_midi_output_timer,
+                                   (unsigned long) hmidi);
+                       mod_timer(&hmidi->timer, 1 + jiffies);
                        hmidi->istimer++;
                }
        } else {
@@ -6965,9 +6961,7 @@ static int snd_hdspm_free(struct hdspm * hdspm)
                free_irq(hdspm->irq, (void *) hdspm);
 
        kfree(hdspm->mixer);
-
-       if (hdspm->iobase)
-               iounmap(hdspm->iobase);
+       iounmap(hdspm->iobase);
 
        if (hdspm->port)
                pci_release_regions(hdspm->pci);
index 6521521853b8ca74881dab96d8845d7e1770912c..fdbc0aa2776a3934e9f71aba48e52d0808650493 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/module.h>
+#include <linux/io.h>
 
 #include <sound/core.h>
 #include <sound/control.h>
@@ -34,7 +35,6 @@
 #include <sound/initval.h>
 
 #include <asm/current.h>
-#include <asm/io.h>
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;      /* ID for this card */
@@ -1756,8 +1756,7 @@ static int snd_rme9652_free(struct snd_rme9652 *rme9652)
 
        if (rme9652->irq >= 0)
                free_irq(rme9652->irq, (void *)rme9652);
-       if (rme9652->iobase)
-               iounmap(rme9652->iobase);
+       iounmap(rme9652->iobase);
        if (rme9652->port)
                pci_release_regions(rme9652->pci);
 
index 7f6a0a0d115a9a65dbbcfaec7ad01842a95829e0..efe669b802569904a211f7cef8235d95b505cf71 100644 (file)
@@ -1064,12 +1064,9 @@ static int sis_chip_free(struct sis7019 *sis)
        if (sis->irq >= 0)
                free_irq(sis->irq, sis);
 
-       if (sis->ioaddr)
-               iounmap(sis->ioaddr);
-
+       iounmap(sis->ioaddr);
        pci_release_regions(sis->pci);
        pci_disable_device(sis->pci);
-
        sis_free_suspend(sis);
        return 0;
 }
@@ -1211,7 +1208,6 @@ static int sis_chip_init(struct sis7019 *sis)
 #ifdef CONFIG_PM_SLEEP
 static int sis_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct sis7019 *sis = card->private_data;
        void __iomem *ioaddr = sis->ioaddr;
@@ -1240,9 +1236,6 @@ static int sis_suspend(struct device *dev)
                ioaddr += 4096;
        }
 
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
@@ -1254,14 +1247,6 @@ static int sis_resume(struct device *dev)
        void __iomem *ioaddr = sis->ioaddr;
        int i;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-
-       if (pci_enable_device(pci) < 0) {
-               dev_err(&pci->dev, "unable to re-enable device\n");
-               goto error;
-       }
-
        if (sis_chip_init(sis)) {
                dev_err(&pci->dev, "unable to re-init controller\n");
                goto error;
@@ -1284,7 +1269,6 @@ static int sis_resume(struct device *dev)
        memset(sis->suspend_state[0], 0, 4096);
 
        sis->irq = pci->irq;
-       pci_set_master(pci);
 
        if (sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT)
                snd_ac97_resume(sis->ac97[0]);
index 313a7328bf9c884b3a88127a29ef147932246ac0..0f40624a427577caa5feab5aeda799be19bc4955 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/gameport.h>
 #include <linux/module.h>
 #include <linux/dma-mapping.h>
+#include <linux/io.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -39,8 +40,6 @@
 #include <sound/opl3.h>
 #include <sound/initval.h>
 
-#include <asm/io.h>
-
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("S3 SonicVibes PCI");
 MODULE_LICENSE("GPL");
@@ -880,8 +879,7 @@ static struct snd_pcm_ops snd_sonicvibes_capture_ops = {
        .pointer =      snd_sonicvibes_capture_pointer,
 };
 
-static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device,
-                             struct snd_pcm **rpcm)
+static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device)
 {
        struct snd_pcm *pcm;
        int err;
@@ -902,8 +900,6 @@ static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device,
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                              snd_dma_pci_data(sonic->pci), 64*1024, 128*1024);
 
-       if (rpcm)
-               *rpcm = pcm;
        return 0;
 }
 
@@ -1491,7 +1487,7 @@ static int snd_sonic_probe(struct pci_dev *pci,
                (unsigned long long)pci_resource_start(pci, 1),
                sonic->irq);
 
-       if ((err = snd_sonicvibes_pcm(sonic, 0, NULL)) < 0) {
+       if ((err = snd_sonicvibes_pcm(sonic, 0)) < 0) {
                snd_card_free(card);
                return err;
        }
index a54cd6879b310106414e1886e566eb72b3ce4c52..cedf13b64803acd167c704a2281ba340ffb1e044 100644 (file)
@@ -127,21 +127,21 @@ static int snd_trident_probe(struct pci_dev *pci,
        sprintf(card->longname, "%s PCI Audio at 0x%lx, irq %d",
                card->shortname, trident->port, trident->irq);
 
-       if ((err = snd_trident_pcm(trident, pcm_dev++, NULL)) < 0) {
+       if ((err = snd_trident_pcm(trident, pcm_dev++)) < 0) {
                snd_card_free(card);
                return err;
        }
        switch (trident->device) {
        case TRIDENT_DEVICE_ID_DX:
        case TRIDENT_DEVICE_ID_NX:
-               if ((err = snd_trident_foldback_pcm(trident, pcm_dev++, NULL)) < 0) {
+               if ((err = snd_trident_foldback_pcm(trident, pcm_dev++)) < 0) {
                        snd_card_free(card);
                        return err;
                }
                break;
        }
        if (trident->device == TRIDENT_DEVICE_ID_NX || trident->device == TRIDENT_DEVICE_ID_SI7018) {
-               if ((err = snd_trident_spdif_pcm(trident, pcm_dev++, NULL)) < 0) {
+               if ((err = snd_trident_spdif_pcm(trident, pcm_dev++)) < 0) {
                        snd_card_free(card);
                        return err;
                }
index 5f110eb56e4760700f853dd12d8e1a632bf83067..9624e5937719b01629bf04245447e404a4822fb5 100644 (file)
@@ -420,9 +420,9 @@ int snd_trident_create(struct snd_card *card,
                       struct snd_trident ** rtrident);
 int snd_trident_create_gameport(struct snd_trident *trident);
 
-int snd_trident_pcm(struct snd_trident * trident, int device, struct snd_pcm **rpcm);
-int snd_trident_foldback_pcm(struct snd_trident * trident, int device, struct snd_pcm **rpcm);
-int snd_trident_spdif_pcm(struct snd_trident * trident, int device, struct snd_pcm **rpcm);
+int snd_trident_pcm(struct snd_trident *trident, int device);
+int snd_trident_foldback_pcm(struct snd_trident *trident, int device);
+int snd_trident_spdif_pcm(struct snd_trident *trident, int device);
 int snd_trident_attach_synthesizer(struct snd_trident * trident);
 struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident, int type,
                                             int client, int port);
index 57cd757acfe7a96cb92aadc48e5ffbfaaaa56533..b72be035f785b632a415dfcaa9772e0f602eb320 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/gameport.h>
 #include <linux/dma-mapping.h>
 #include <linux/export.h>
+#include <linux/io.h>
 
 #include <sound/core.h>
 #include <sound/info.h>
@@ -44,8 +45,6 @@
 #include "trident.h"
 #include <sound/asoundef.h>
 
-#include <asm/io.h>
-
 static int snd_trident_pcm_mixer_build(struct snd_trident *trident,
                                       struct snd_trident_voice * voice,
                                       struct snd_pcm_substream *substream);
@@ -2172,14 +2171,11 @@ static struct snd_pcm_ops snd_trident_spdif_7018_ops = {
   
   ---------------------------------------------------------------------------*/
 
-int snd_trident_pcm(struct snd_trident *trident,
-                   int device, struct snd_pcm **rpcm)
+int snd_trident_pcm(struct snd_trident *trident, int device)
 {
        struct snd_pcm *pcm;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
        if ((err = snd_pcm_new(trident->card, "trident_dx_nx", device, trident->ChanPCM, 1, &pcm)) < 0)
                return err;
 
@@ -2214,8 +2210,6 @@ int snd_trident_pcm(struct snd_trident *trident,
                                                      snd_dma_pci_data(trident->pci), 64*1024, 128*1024);
        }
 
-       if (rpcm)
-               *rpcm = pcm;
        return 0;
 }
 
@@ -2230,16 +2224,13 @@ int snd_trident_pcm(struct snd_trident *trident,
   
   ---------------------------------------------------------------------------*/
 
-int snd_trident_foldback_pcm(struct snd_trident *trident,
-                            int device, struct snd_pcm **rpcm)
+int snd_trident_foldback_pcm(struct snd_trident *trident, int device)
 {
        struct snd_pcm *foldback;
        int err;
        int num_chan = 3;
        struct snd_pcm_substream *substream;
 
-       if (rpcm)
-               *rpcm = NULL;
        if (trident->device == TRIDENT_DEVICE_ID_NX)
                num_chan = 4;
        if ((err = snd_pcm_new(trident->card, "trident_dx_nx", device, 0, num_chan, &foldback)) < 0)
@@ -2271,8 +2262,6 @@ int snd_trident_foldback_pcm(struct snd_trident *trident,
                snd_pcm_lib_preallocate_pages_for_all(foldback, SNDRV_DMA_TYPE_DEV,
                                                      snd_dma_pci_data(trident->pci), 64*1024, 128*1024);
 
-       if (rpcm)
-               *rpcm = foldback;
        return 0;
 }
 
@@ -2287,14 +2276,11 @@ int snd_trident_foldback_pcm(struct snd_trident *trident,
   
   ---------------------------------------------------------------------------*/
 
-int snd_trident_spdif_pcm(struct snd_trident *trident,
-                         int device, struct snd_pcm **rpcm)
+int snd_trident_spdif_pcm(struct snd_trident *trident, int device)
 {
        struct snd_pcm *spdif;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
        if ((err = snd_pcm_new(trident->card, "trident_dx_nx IEC958", device, 1, 0, &spdif)) < 0)
                return err;
 
@@ -2310,8 +2296,6 @@ int snd_trident_spdif_pcm(struct snd_trident *trident,
 
        snd_pcm_lib_preallocate_pages_for_all(spdif, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci), 64*1024, 128*1024);
 
-       if (rpcm)
-               *rpcm = spdif;
        return 0;
 }
 
@@ -3926,7 +3910,6 @@ static void snd_trident_clear_voices(struct snd_trident * trident, unsigned shor
 #ifdef CONFIG_PM_SLEEP
 static int snd_trident_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_trident *trident = card->private_data;
 
@@ -3938,28 +3921,14 @@ static int snd_trident_suspend(struct device *dev)
 
        snd_ac97_suspend(trident->ac97);
        snd_ac97_suspend(trident->ac97_sec);
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int snd_trident_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_trident *trident = card->private_data;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
-
        switch (trident->device) {
        case TRIDENT_DEVICE_ID_DX:
                snd_trident_4d_dx_init(trident);
index 04c474658e3c469a7d986394e509fcf4b65b8d9c..b9ebb51893c5267c30ece7356fb6b3e4456c56d2 100644 (file)
@@ -23,7 +23,7 @@
  *
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/pci.h>
 #include <linux/time.h>
 #include <linux/mutex.h>
index e088467fb7366d3b33c751815417fe58d19dee67..8622283e89f3e03d073acef9d511355ac92b13ec 100644 (file)
@@ -46,7 +46,7 @@
  *     - Optimize position calculation for the 823x chips. 
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -2271,7 +2271,6 @@ static int snd_via82xx_chip_init(struct via82xx *chip)
  */
 static int snd_via82xx_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct via82xx *chip = card->private_data;
        int i;
@@ -2291,28 +2290,15 @@ static int snd_via82xx_suspend(struct device *dev)
                chip->capture_src_saved[1] = inb(chip->port + VIA_REG_CAPTURE_CHANNEL + 0x10);
        }
 
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int snd_via82xx_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct via82xx *chip = card->private_data;
        int i;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
-
        snd_via82xx_chip_init(chip);
 
        if (chip->chip_type == TYPE_VIA686) {
index fd46ffe12e4ff50c6eb5248a10ed855bd85c8ce9..99b9137bc67726f28750eb5fd07636cf301994e2 100644 (file)
@@ -31,7 +31,7 @@
  *      modems.
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
@@ -1031,7 +1031,6 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip)
  */
 static int snd_via82xx_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct via82xx_modem *chip = card->private_data;
        int i;
@@ -1043,29 +1042,15 @@ static int snd_via82xx_suspend(struct device *dev)
                snd_via82xx_channel_reset(chip, &chip->devs[i]);
        synchronize_irq(chip->irq);
        snd_ac97_suspend(chip->ac97);
-
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
 static int snd_via82xx_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct via82xx_modem *chip = card->private_data;
        int i;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
-
        snd_via82xx_chip_init(chip);
 
        snd_ac97_resume(chip->ac97);
index c5a25e39e3a8ea8f231d94e15ca8fea4cecc6dcf..ecbaf473fc1e8cb0fb855b99505e8e528ecfe17e 100644 (file)
@@ -259,32 +259,17 @@ static void snd_vx222_remove(struct pci_dev *pci)
 #ifdef CONFIG_PM_SLEEP
 static int snd_vx222_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_vx222 *vx = card->private_data;
-       int err;
 
-       err = snd_vx_suspend(&vx->core);
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
-       return err;
+       return snd_vx_suspend(&vx->core);
 }
 
 static int snd_vx222_resume(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_vx222 *vx = card->private_data;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
        return snd_vx_resume(&vx->core);
 }
 
index 52c1a8d5b88ad2778c11bdeb19a4183ba9e62307..af83b3b380523e75c897695a292bfecbdb2734fb 100644 (file)
 #include <linux/device.h>
 #include <linux/firmware.h>
 #include <linux/mutex.h>
+#include <linux/io.h>
 
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/tlv.h>
-#include <asm/io.h>
 #include "vx222.h"
 
 
index 47a192369e8fef63c1b47bc74d8b29c298f59424..812e27a1bcbc04b0fbd7fbbab3efd44e41aded48 100644 (file)
@@ -283,11 +283,11 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci,
                card->shortname,
                chip->reg_area_phys,
                chip->irq);
-       if ((err = snd_ymfpci_pcm(chip, 0, NULL)) < 0) {
+       if ((err = snd_ymfpci_pcm(chip, 0)) < 0) {
                snd_card_free(card);
                return err;
        }
-       if ((err = snd_ymfpci_pcm_spdif(chip, 1, NULL)) < 0) {
+       if ((err = snd_ymfpci_pcm_spdif(chip, 1)) < 0) {
                snd_card_free(card);
                return err;
        }
@@ -297,12 +297,12 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci,
                return err;
        }
        if (chip->ac97->ext_id & AC97_EI_SDAC) {
-               err = snd_ymfpci_pcm_4ch(chip, 2, NULL);
+               err = snd_ymfpci_pcm_4ch(chip, 2);
                if (err < 0) {
                        snd_card_free(card);
                        return err;
                }
-               err = snd_ymfpci_pcm2(chip, 3, NULL);
+               err = snd_ymfpci_pcm2(chip, 3);
                if (err < 0) {
                        snd_card_free(card);
                        return err;
index 4631a23489151f8631e878e4a98fe31b51ab066b..149d4cb469988d4091f58aea271a6fe1f8c71dee 100644 (file)
@@ -379,10 +379,10 @@ void snd_ymfpci_free_gameport(struct snd_ymfpci *chip);
 
 extern const struct dev_pm_ops snd_ymfpci_pm;
 
-int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
-int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
-int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
-int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
+int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device);
+int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device);
+int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device);
+int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device);
 int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch);
 int snd_ymfpci_timer(struct snd_ymfpci *chip, int device);
 
index 81c916a5eb96a09ba4f4cb8cec1f75339f9f2dca..4c26076dbf78ba10decce834e019d64dccd9a51b 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/module.h>
+#include <linux/io.h>
 
 #include <sound/core.h>
 #include <sound/control.h>
@@ -36,7 +37,6 @@
 #include <sound/asoundef.h>
 #include <sound/mpu401.h>
 
-#include <asm/io.h>
 #include <asm/byteorder.h>
 
 /*
@@ -1145,13 +1145,11 @@ static struct snd_pcm_ops snd_ymfpci_capture_rec_ops = {
        .pointer =              snd_ymfpci_capture_pointer,
 };
 
-int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm)
+int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device)
 {
        struct snd_pcm *pcm;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
        if ((err = snd_pcm_new(chip->card, "YMFPCI", device, 32, 1, &pcm)) < 0)
                return err;
        pcm->private_data = chip;
@@ -1167,14 +1165,8 @@ int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm)
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                              snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
 
-       err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+       return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
                                     snd_pcm_std_chmaps, 2, 0, NULL);
-       if (err < 0)
-               return err;
-
-       if (rpcm)
-               *rpcm = pcm;
-       return 0;
 }
 
 static struct snd_pcm_ops snd_ymfpci_capture_ac97_ops = {
@@ -1188,13 +1180,11 @@ static struct snd_pcm_ops snd_ymfpci_capture_ac97_ops = {
        .pointer =              snd_ymfpci_capture_pointer,
 };
 
-int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm)
+int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device)
 {
        struct snd_pcm *pcm;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
        if ((err = snd_pcm_new(chip->card, "YMFPCI - PCM2", device, 0, 1, &pcm)) < 0)
                return err;
        pcm->private_data = chip;
@@ -1210,8 +1200,6 @@ int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm)
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                              snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
 
-       if (rpcm)
-               *rpcm = pcm;
        return 0;
 }
 
@@ -1226,14 +1214,11 @@ static struct snd_pcm_ops snd_ymfpci_playback_spdif_ops = {
        .pointer =              snd_ymfpci_playback_pointer,
 };
 
-int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device,
-                        struct snd_pcm **rpcm)
+int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device)
 {
        struct snd_pcm *pcm;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
        if ((err = snd_pcm_new(chip->card, "YMFPCI - IEC958", device, 1, 0, &pcm)) < 0)
                return err;
        pcm->private_data = chip;
@@ -1248,8 +1233,6 @@ int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device,
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                              snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
 
-       if (rpcm)
-               *rpcm = pcm;
        return 0;
 }
 
@@ -1272,14 +1255,11 @@ static const struct snd_pcm_chmap_elem surround_map[] = {
        { }
 };
 
-int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device,
-                      struct snd_pcm **rpcm)
+int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device)
 {
        struct snd_pcm *pcm;
        int err;
 
-       if (rpcm)
-               *rpcm = NULL;
        if ((err = snd_pcm_new(chip->card, "YMFPCI - Rear", device, 1, 0, &pcm)) < 0)
                return err;
        pcm->private_data = chip;
@@ -1294,14 +1274,8 @@ int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device,
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                              snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
 
-       err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+       return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
                                     surround_map, 2, 0, NULL);
-       if (err < 0)
-               return err;
-
-       if (rpcm)
-               *rpcm = pcm;
-       return 0;
 }
 
 static int snd_ymfpci_spdif_default_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
@@ -2272,8 +2246,7 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip)
        release_and_free_resource(chip->mpu_res);
        release_and_free_resource(chip->fm_res);
        snd_ymfpci_free_gameport(chip);
-       if (chip->reg_area_virt)
-               iounmap(chip->reg_area_virt);
+       iounmap(chip->reg_area_virt);
        if (chip->work_ptr.area)
                snd_dma_free_pages(&chip->work_ptr);
        
@@ -2326,7 +2299,6 @@ static int saved_regs_index[] = {
 
 static int snd_ymfpci_suspend(struct device *dev)
 {
-       struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_ymfpci *chip = card->private_data;
        unsigned int i;
@@ -2347,9 +2319,6 @@ static int snd_ymfpci_suspend(struct device *dev)
        snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0);
        snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0);
        snd_ymfpci_disable_dsp(chip);
-       pci_disable_device(pci);
-       pci_save_state(pci);
-       pci_set_power_state(pci, PCI_D3hot);
        return 0;
 }
 
@@ -2360,14 +2329,6 @@ static int snd_ymfpci_resume(struct device *dev)
        struct snd_ymfpci *chip = card->private_data;
        unsigned int i;
 
-       pci_set_power_state(pci, PCI_D0);
-       pci_restore_state(pci);
-       if (pci_enable_device(pci) < 0) {
-               dev_err(dev, "pci_enable_device failed, disabling device\n");
-               snd_card_disconnect(card);
-               return -EIO;
-       }
-       pci_set_master(pci);
        snd_ymfpci_aclink_reset(pci);
        snd_ymfpci_codec_ready(chip, 0);
        snd_ymfpci_download_image(chip);
index 5fbf5db2543d40c531efdac069df3ffd13b8a2a8..09da7b52bc2e6deba601d876a9578cfbb485b768 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/nvram.h>
 #include <linux/init.h>
 #include <linux/delay.h>
index 0040f048221fa39553ab35398a3d872101bb306c..d3524f9fa05de1a5f7fc7dc870c5374d2588b8a2 100644 (file)
@@ -18,7 +18,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/irq.h>
 #include <linux/init.h>
 #include <linux/slab.h>
index cb4f0a5e984e9572ed47e433715db7f047753fe5..b86159e04493a521f61661816b9da4a2113f5d7a 100644 (file)
@@ -19,7 +19,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <sound/core.h>
index 5a13b22748b217b08571cdd90d3f8a8078ac8223..13146d7014139b9c7b780ecc09f610a462d6ecab 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/irq.h>
 #include <linux/init.h>
 #include <linux/delay.h>
@@ -867,16 +867,11 @@ static int snd_pmac_free(struct snd_pmac *chip)
        snd_pmac_dbdma_free(chip, &chip->capture.cmd);
        snd_pmac_dbdma_free(chip, &chip->extra_dma);
        snd_pmac_dbdma_free(chip, &emergency_dbdma);
-       if (chip->macio_base)
-               iounmap(chip->macio_base);
-       if (chip->latch_base)
-               iounmap(chip->latch_base);
-       if (chip->awacs)
-               iounmap(chip->awacs);
-       if (chip->playback.dma)
-               iounmap(chip->playback.dma);
-       if (chip->capture.dma)
-               iounmap(chip->capture.dma);
+       iounmap(chip->macio_base);
+       iounmap(chip->latch_base);
+       iounmap(chip->awacs);
+       iounmap(chip->playback.dma);
+       iounmap(chip->capture.dma);
 
        if (chip->node) {
                int i;
index 58f292a87f98fcc7eae969b4676b7feb487e4dfa..368242519279ae56054d1cfe097104f8a1bbd2cc 100644 (file)
@@ -1044,7 +1044,7 @@ static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
        if (!the_card.null_buffer_start_vaddr) {
                pr_info("%s: nullbuffer alloc failed\n", __func__);
                ret = -ENOMEM;
-               goto clean_preallocate;
+               goto clean_card;
        }
        pr_debug("%s: null vaddr=%p dma=%#llx\n", __func__,
                 the_card.null_buffer_start_vaddr,
@@ -1066,8 +1066,6 @@ clean_dma_map:
                          PAGE_SIZE,
                          the_card.null_buffer_start_vaddr,
                          the_card.null_buffer_start_dma_addr);
-clean_preallocate:
-       snd_pcm_lib_preallocate_free_for_all(the_card.pcm);
 clean_card:
        snd_card_free(the_card.card);
 clean_irq:
index 24c8766a925d05dab14400e885c97da8e8fc0e32..c8fafba218a594570208ad4576fc61f0f98834f5 100644 (file)
@@ -32,8 +32,8 @@
 #include <linux/interrupt.h>
 #include <linux/string.h>
 #include <linux/of_irq.h>
+#include <linux/io.h>
 #include <sound/core.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/machdep.h>
 #include <asm/pmac_feature.h>
index f44dda610ed2e28f4f04251a6eb21c4eac83bd16..ad3d9ae380349ddb4d367645a4deb841d6ea4452 100644 (file)
 #include <linux/timer.h>
 #include <linux/delay.h>
 #include <linux/workqueue.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
 #include <sound/initval.h>
 #include <sound/info.h>
-#include <asm/io.h>
 #include <asm/dma.h>
 #include <mach/sysasic.h>
 #include "aica.h"
@@ -343,11 +343,9 @@ static void spu_begin_dma(struct snd_pcm_substream *substream)
                mod_timer(&dreamcastcard->timer, jiffies + 4);
                return;
        }
-       init_timer(&(dreamcastcard->timer));
-       dreamcastcard->timer.data = (unsigned long) substream;
-       dreamcastcard->timer.function = aica_period_elapsed;
-       dreamcastcard->timer.expires = jiffies + 4;
-       add_timer(&(dreamcastcard->timer));
+       setup_timer(&dreamcastcard->timer, aica_period_elapsed,
+                   (unsigned long) substream);
+       mod_timer(&dreamcastcard->timer, jiffies + 4);
 }
 
 static int snd_aicapcm_pcm_open(struct snd_pcm_substream
index 7d5d6444a83737ffa3c01acbe1925de619e0390a..dcc79aa0236b548bfe5408fe56689241fc597e97 100644 (file)
@@ -55,6 +55,7 @@ source "sound/soc/spear/Kconfig"
 source "sound/soc/tegra/Kconfig"
 source "sound/soc/txx9/Kconfig"
 source "sound/soc/ux500/Kconfig"
+source "sound/soc/xtensa/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
index 865e090c80616024a552da5e33d2796b9be1dbbd..5b3c8f67c8db7a29ff7199a6103d445428978125 100644 (file)
@@ -36,3 +36,4 @@ obj-$(CONFIG_SND_SOC) += spear/
 obj-$(CONFIG_SND_SOC)  += tegra/
 obj-$(CONFIG_SND_SOC)  += txx9/
 obj-$(CONFIG_SND_SOC)  += ux500/
+obj-$(CONFIG_SND_SOC)  += xtensa/
index fb3878312bf80b2b99c1b22344e498e7fb3a4434..1579e994acf881dfacb1aae23afb6095f32ff13f 100644 (file)
@@ -45,7 +45,7 @@ config SND_ATMEL_SOC_WM8904
 
 config SND_AT91_SOC_SAM9X5_WM8731
        tristate "SoC Audio support for WM8731-based at91sam9x5 board"
-       depends on ATMEL_SSC && SND_ATMEL_SOC && SOC_AT91SAM9X5
+       depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC
        select SND_ATMEL_SOC_SSC
        select SND_ATMEL_SOC_DMA
        select SND_SOC_WM8731
index 33fb3bb133df281429be1be2914006e575f011f1..b8e7bad05eb14a9ef7e6393646f776c910c0f898 100644 (file)
@@ -105,13 +105,11 @@ static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
                return ret;
        }
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               slave_config->dst_addr = ssc->phybase + SSC_THR;
-               slave_config->dst_maxburst = 1;
-       } else {
-               slave_config->src_addr = ssc->phybase + SSC_RHR;
-               slave_config->src_maxburst = 1;
-       }
+       slave_config->dst_addr = ssc->phybase + SSC_THR;
+       slave_config->dst_maxburst = 1;
+
+       slave_config->src_addr = ssc->phybase + SSC_RHR;
+       slave_config->src_maxburst = 1;
 
        prtd->dma_intr_handler = atmel_pcm_dma_irq;
 
index 35e44e463cfe580f538e7c1d7524fd3b9cc4249f..fb0b7e8b08ff4cd11a2656fe76fe10898aeded6b 100644 (file)
@@ -204,6 +204,13 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
        pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
                ssc_readl(ssc_p->ssc->regs, SR));
 
+       /* Enable PMC peripheral clock for this SSC */
+       pr_debug("atmel_ssc_dai: Starting clock\n");
+       clk_enable(ssc_p->ssc->clk);
+
+       /* Reset the SSC to keep it at a clean status */
+       ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
+
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                dir = 0;
                dir_mask = SSC_DIR_MASK_PLAYBACK;
@@ -250,11 +257,6 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
        dma_params = ssc_p->dma_params[dir];
 
        if (dma_params != NULL) {
-               ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_disable);
-               pr_debug("atmel_ssc_shutdown: %s disabled SSC_SR=0x%08x\n",
-                       (dir ? "receive" : "transmit"),
-                       ssc_readl(ssc_p->ssc->regs, SR));
-
                dma_params->ssc = NULL;
                dma_params->substream = NULL;
                ssc_p->dma_params[dir] = NULL;
@@ -266,10 +268,6 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
        ssc_p->dir_mask &= ~dir_mask;
        if (!ssc_p->dir_mask) {
                if (ssc_p->initialized) {
-                       /* Shutdown the SSC clock. */
-                       pr_debug("atmel_ssc_dai: Stopping clock\n");
-                       clk_disable(ssc_p->ssc->clk);
-
                        free_irq(ssc_p->ssc->irq, ssc_p);
                        ssc_p->initialized = 0;
                }
@@ -280,6 +278,10 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
                ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0;
        }
        spin_unlock_irq(&ssc_p->lock);
+
+       /* Shutdown the SSC clock. */
+       pr_debug("atmel_ssc_dai: Stopping clock\n");
+       clk_disable(ssc_p->ssc->clk);
 }
 
 
@@ -450,13 +452,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                break;
 
        case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
-               /*
-                * I2S format, CODEC supplies BCLK and LRC clocks.
-                *
-                * The SSC transmit clock is obtained from the BCLK signal on
-                * on the TK line, and the SSC receive clock is
-                * generated from the transmit clock.
-                */
+               /* I2S format, CODEC supplies BCLK and LRC clocks. */
                rcmr =    SSC_BF(RCMR_PERIOD, 0)
                        | SSC_BF(RCMR_STTDLY, START_DELAY)
                        | SSC_BF(RCMR_START, SSC_START_FALLING_RF)
@@ -491,6 +487,54 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                        | SSC_BF(TFMR_DATLEN, (bits - 1));
                break;
 
+       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFS:
+               /* I2S format, CODEC supplies BCLK, SSC supplies LRCLK. */
+               if (bits > 16 && !ssc->pdata->has_fslen_ext) {
+                       dev_err(dai->dev,
+                               "sample size %d is too large for SSC device\n",
+                               bits);
+                       return -EINVAL;
+               }
+
+               fslen_ext = (bits - 1) / 16;
+               fslen = (bits - 1) % 16;
+
+               rcmr =    SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
+                       | SSC_BF(RCMR_STTDLY, START_DELAY)
+                       | SSC_BF(RCMR_START, SSC_START_FALLING_RF)
+                       | SSC_BF(RCMR_CKI, SSC_CKI_RISING)
+                       | SSC_BF(RCMR_CKO, SSC_CKO_NONE)
+                       | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?
+                                          SSC_CKS_PIN : SSC_CKS_CLOCK);
+
+               rfmr =    SSC_BF(RFMR_FSLEN_EXT, fslen_ext)
+                       | SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+                       | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE)
+                       | SSC_BF(RFMR_FSLEN, fslen)
+                       | SSC_BF(RFMR_DATNB, (channels - 1))
+                       | SSC_BIT(RFMR_MSBF)
+                       | SSC_BF(RFMR_LOOP, 0)
+                       | SSC_BF(RFMR_DATLEN, (bits - 1));
+
+               tcmr =    SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period)
+                       | SSC_BF(TCMR_STTDLY, START_DELAY)
+                       | SSC_BF(TCMR_START, SSC_START_FALLING_RF)
+                       | SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
+                       | SSC_BF(TCMR_CKO, SSC_CKO_NONE)
+                       | SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ?
+                                          SSC_CKS_CLOCK : SSC_CKS_PIN);
+
+               tfmr =    SSC_BF(TFMR_FSLEN_EXT, fslen_ext)
+                       | SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_NEGATIVE)
+                       | SSC_BF(TFMR_FSDEN, 0)
+                       | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE)
+                       | SSC_BF(TFMR_FSLEN, fslen)
+                       | SSC_BF(TFMR_DATNB, (channels - 1))
+                       | SSC_BIT(TFMR_MSBF)
+                       | SSC_BF(TFMR_DATDEF, 0)
+                       | SSC_BF(TFMR_DATLEN, (bits - 1));
+               break;
+
        case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
                /*
                 * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks.
@@ -535,10 +579,6 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                /*
                 * DSP/PCM Mode A format, CODEC supplies BCLK and LRC clocks.
                 *
-                * The SSC transmit clock is obtained from the BCLK signal on
-                * on the TK line, and the SSC receive clock is
-                * generated from the transmit clock.
-                *
                 * Data is transferred on first BCLK after LRC pulse rising
                 * edge.If stereo, the right channel data is contiguous with
                 * the left channel data.
@@ -587,23 +627,17 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                        rcmr, rfmr, tcmr, tfmr);
 
        if (!ssc_p->initialized) {
-
-               /* Enable PMC peripheral clock for this SSC */
-               pr_debug("atmel_ssc_dai: Starting clock\n");
-               clk_enable(ssc_p->ssc->clk);
-
-               /* Reset the SSC and its PDC registers */
-               ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
-
-               ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0);
-               ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0);
-               ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0);
-               ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0);
-
-               ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0);
-               ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0);
-               ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0);
-               ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0);
+               if (!ssc_p->ssc->pdata->use_dma) {
+                       ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0);
+                       ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0);
+                       ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0);
+                       ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0);
+
+                       ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0);
+                       ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0);
+                       ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0);
+                       ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0);
+               }
 
                ret = request_irq(ssc_p->ssc->irq, atmel_ssc_interrupt, 0,
                                ssc_p->name, ssc_p);
index 66b66d0e751474358f6eff03d0a2ae897dddc1ad..f5ad214663f98b4dbbdc3c2a4180d6142d09688c 100644 (file)
@@ -47,7 +47,6 @@
 #include <sound/soc.h>
 
 #include <asm/mach-types.h>
-#include <mach/hardware.h>
 
 #include "../codecs/wm8731.h"
 #include "atmel-pcm.h"
 
 static struct clk *mclk;
 
-static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int ret;
-
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static struct snd_soc_ops at91sam9g20ek_ops = {
-       .hw_params = at91sam9g20ek_hw_params,
-};
-
 static int at91sam9g20ek_set_bias_level(struct snd_soc_card *card,
                                        struct snd_soc_dapm_context *dapm,
                                        enum snd_soc_bias_level level)
@@ -173,7 +145,8 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = {
        .init = at91sam9g20ek_wm8731_init,
        .platform_name = "at91rm9200_ssc.0",
        .codec_name = "wm8731.0-001b",
-       .ops = &at91sam9g20ek_ops,
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBM_CFM,
 };
 
 static struct snd_soc_card snd_soc_at91sam9g20ek = {
index a747ac0b399fae766ddbe85695d2db9140f42884..c75995f2779cf57604de8d1ef37c4aa42c31d2a5 100644 (file)
@@ -91,27 +91,12 @@ static int db1200_i2s_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int ret;
 
        /* WM8731 has its own 12MHz crystal */
        snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
                                12000000, SND_SOC_CLOCK_IN);
 
-       /* codec is bitclock and lrclk master */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               goto out;
-
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_LEFT_J |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               goto out;
-
-       ret = 0;
-out:
-       return ret;
+       return 0;
 }
 
 static struct snd_soc_ops db1200_i2s_wm8731_ops = {
@@ -125,6 +110,8 @@ static struct snd_soc_dai_link db1200_i2s_dai = {
        .cpu_dai_name   = "au1xpsc_i2s.1",
        .platform_name  = "au1xpsc-pcm.1",
        .codec_name     = "wm8731.0-001b",
+       .dai_fmt        = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF |
+                         SND_SOC_DAIFMT_CBM_CFM,
        .ops            = &db1200_i2s_wm8731_ops,
 };
 
index b06b8d8128c661d3c8645672224147164122f36e..dd94fea72d5d240cf8d6c37f344dbabe10b55e0f 100644 (file)
@@ -315,11 +315,6 @@ static struct snd_pcm_ops au1xpsc_pcm_ops = {
        .pointer        = au1xpsc_pcm_pointer,
 };
 
-static void au1xpsc_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
@@ -335,7 +330,6 @@ static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_platform_driver au1xpsc_soc_platform = {
        .ops            = &au1xpsc_pcm_ops,
        .pcm_new        = au1xpsc_pcm_new,
-       .pcm_free       = au1xpsc_pcm_free_dma_buffers,
 };
 
 static int au1xpsc_pcm_drvprobe(struct platform_device *pdev)
index 6ffaaff469c7d13ecc623833a14c18838486b3f0..24cc7f40d87a61ba16850a57566a395455f302f2 100644 (file)
@@ -287,11 +287,6 @@ static struct snd_pcm_ops alchemy_pcm_ops = {
        .pointer                = alchemy_pcm_pointer,
 };
 
-static void alchemy_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static int alchemy_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_pcm *pcm = rtd->pcm;
@@ -305,7 +300,6 @@ static int alchemy_pcm_new(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_platform_driver alchemy_pcm_soc_platform = {
        .ops            = &alchemy_pcm_ops,
        .pcm_new        = alchemy_pcm_new,
-       .pcm_free       = alchemy_pcm_free_dma_buffers,
 };
 
 static int alchemy_pcm_drvprobe(struct platform_device *pdev)
index a2bf27f4baab6339f03fc2b040fe81b80bdb9714..a0f265327fdf8949e15b17187732d1da8702a7a9 100644 (file)
@@ -386,7 +386,7 @@ static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,
 static int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
                              struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        /*
         * In order to avoid current on the load, mute power-on and power-off
@@ -403,7 +403,7 @@ static int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
 static int pm860x_dac_event(struct snd_soc_dapm_widget *w,
                            struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        unsigned int dac = 0;
        int data;
 
index 8349f982a586841a3ac9e7b0526af05699c7deaf..064e6c18e10923fd75609b750405dbc33f9db6af 100644 (file)
@@ -69,6 +69,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_MAX98088 if I2C
        select SND_SOC_MAX98090 if I2C
        select SND_SOC_MAX98095 if I2C
+       select SND_SOC_MAX98357A
        select SND_SOC_MAX9850 if I2C
        select SND_SOC_MAX9768 if I2C
        select SND_SOC_MAX9877 if I2C
@@ -456,6 +457,9 @@ config SND_SOC_MAX98090
 config SND_SOC_MAX98095
        tristate
 
+config SND_SOC_MAX98357A
+       tristate
+
 config SND_SOC_MAX9850
        tristate
 
@@ -525,7 +529,7 @@ config SND_SOC_RT5677
 
 config SND_SOC_RT5677_SPI
        tristate
-       default SND_SOC_RT5677
+       default SND_SOC_RT5677 && SPI
 
 #Freescale sgtl5000 codec
 config SND_SOC_SGTL5000
@@ -580,7 +584,9 @@ config SND_SOC_SSM4567
        depends on I2C
 
 config SND_SOC_STA32X
-       tristate
+       tristate "STA326, STA328 and STA329 speaker amplifier"
+       depends on I2C
+       select REGMAP_I2C
 
 config SND_SOC_STA350
        tristate "STA350 speaker amplifier"
index bbdfd1e1c182f9ee102f532f391f522e77a8922b..69b8666d187a0e8d1e2a532e68e2509acc95da7e 100644 (file)
@@ -64,6 +64,7 @@ snd-soc-max9768-objs := max9768.o
 snd-soc-max98088-objs := max98088.o
 snd-soc-max98090-objs := max98090.o
 snd-soc-max98095-objs := max98095.o
+snd-soc-max98357a-objs := max98357a.o
 snd-soc-max9850-objs := max9850.o
 snd-soc-mc13783-objs := mc13783.o
 snd-soc-ml26124-objs := ml26124.o
@@ -245,6 +246,7 @@ obj-$(CONFIG_SND_SOC_MAX9768)       += snd-soc-max9768.o
 obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
 obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o
 obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o
+obj-$(CONFIG_SND_SOC_MAX98357A)        += snd-soc-max98357a.o
 obj-$(CONFIG_SND_SOC_MAX9850)  += snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_MC13783)  += snd-soc-mc13783.o
 obj-$(CONFIG_SND_SOC_ML26124)  += snd-soc-ml26124.o
index 387530b0b0fd91058bbf08e663207867c693d9b5..17c9535956609c0df1a04f631da8f79a25a1e044 100644 (file)
@@ -333,8 +333,8 @@ static int ad193x_codec_probe(struct snd_soc_codec *codec)
        regmap_write(ad193x->regmap, AD193X_DAC_CHNL_MUTE, 0x0);
        /* de-emphasis: 48kHz, powedown dac */
        regmap_write(ad193x->regmap, AD193X_DAC_CTRL2, 0x1A);
-       /* powerdown dac, dac in tdm mode */
-       regmap_write(ad193x->regmap, AD193X_DAC_CTRL0, 0x41);
+       /* dac in tdm mode */
+       regmap_write(ad193x->regmap, AD193X_DAC_CTRL0, 0x40);
        /* high-pass filter enable */
        regmap_write(ad193x->regmap, AD193X_ADC_CTRL0, 0x3);
        /* sata delay=1, adc aux mode */
index 686cacb0e835aad904f79778ea83f65fabfab16b..632e89f793a78d2691dfb2e33b3516f0f483aeee 100644 (file)
@@ -163,7 +163,7 @@ static const struct snd_kcontrol_new ak4671_snd_controls[] = {
 static int ak4671_out2_event(struct snd_soc_dapm_widget *w,
                struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
index bdf8c5ac8ca460b8e07310674f90109cc6e6965a..0e357996864bd141f4d57283c03fba3b0e11b8d7 100644 (file)
@@ -55,18 +55,20 @@ static inline int alc5623_reset(struct snd_soc_codec *codec)
 static int amp_mixer_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
        /* to power-on/off class-d amp generators/speaker */
        /* need to write to 'index-46h' register :        */
        /* so write index num (here 0x46) to reg 0x6a     */
        /* and then 0xffff/0 to reg 0x6c                  */
-       snd_soc_write(w->codec, ALC5623_HID_CTRL_INDEX, 0x46);
+       snd_soc_write(codec, ALC5623_HID_CTRL_INDEX, 0x46);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
-               snd_soc_write(w->codec, ALC5623_HID_CTRL_DATA, 0xFFFF);
+               snd_soc_write(codec, ALC5623_HID_CTRL_DATA, 0xFFFF);
                break;
        case SND_SOC_DAPM_POST_PMD:
-               snd_soc_write(w->codec, ALC5623_HID_CTRL_DATA, 0);
+               snd_soc_write(codec, ALC5623_HID_CTRL_DATA, 0);
                break;
        }
 
index d1fdbc266631b36aebf4c249bf2bea9e94c8064c..db3283abbe180788f10b3d7e5b70df996087867b 100644 (file)
@@ -116,18 +116,20 @@ static inline int alc5632_reset(struct regmap *map)
 static int amp_mixer_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
        /* to power-on/off class-d amp generators/speaker */
        /* need to write to 'index-46h' register :        */
        /* so write index num (here 0x46) to reg 0x6a     */
        /* and then 0xffff/0 to reg 0x6c                  */
-       snd_soc_write(w->codec, ALC5632_HID_CTRL_INDEX, 0x46);
+       snd_soc_write(codec, ALC5632_HID_CTRL_INDEX, 0x46);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
-               snd_soc_write(w->codec, ALC5632_HID_CTRL_DATA, 0xFFFF);
+               snd_soc_write(codec, ALC5632_HID_CTRL_DATA, 0xFFFF);
                break;
        case SND_SOC_DAPM_POST_PMD:
-               snd_soc_write(w->codec, ALC5632_HID_CTRL_DATA, 0);
+               snd_soc_write(codec, ALC5632_HID_CTRL_DATA, 0);
                break;
        }
 
@@ -1066,7 +1068,7 @@ static int alc5632_probe(struct snd_soc_codec *codec)
        return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_device_alc5632 = {
+static const struct snd_soc_codec_driver soc_codec_device_alc5632 = {
        .probe = alc5632_probe,
        .resume = alc5632_resume,
        .set_bias_level = alc5632_set_bias_level,
@@ -1080,7 +1082,7 @@ static struct snd_soc_codec_driver soc_codec_device_alc5632 = {
        .num_dapm_routes = ARRAY_SIZE(alc5632_dapm_routes),
 };
 
-static struct regmap_config alc5632_regmap = {
+static const struct regmap_config alc5632_regmap = {
        .reg_bits = 8,
        .val_bits = 16,
 
index 9550d7433ad0e391708a85c88a0adfc6fb2d1831..29202610dd0dd90d72329265633844a3d833d640 100644 (file)
@@ -84,7 +84,7 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *kcontrol,
                          int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
        struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
        bool manual_ena = false;
@@ -692,7 +692,8 @@ static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
 int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
                  int event)
 {
-       struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
        unsigned int reg;
 
        if (w->shift % 2)
@@ -705,25 +706,25 @@ int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
                priv->in_pending++;
                break;
        case SND_SOC_DAPM_POST_PMU:
-               snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
+               snd_soc_update_bits(codec, reg, ARIZONA_IN1L_MUTE, 0);
 
                /* If this is the last input pending then allow VU */
                priv->in_pending--;
                if (priv->in_pending == 0) {
                        msleep(1);
-                       arizona_in_set_vu(w->codec, 1);
+                       arizona_in_set_vu(codec, 1);
                }
                break;
        case SND_SOC_DAPM_PRE_PMD:
-               snd_soc_update_bits(w->codec, reg,
+               snd_soc_update_bits(codec, reg,
                                    ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
                                    ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
                break;
        case SND_SOC_DAPM_POST_PMD:
                /* Disable volume updates if no inputs are enabled */
-               reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES);
+               reg = snd_soc_read(codec, ARIZONA_INPUT_ENABLES);
                if (reg == 0)
-                       arizona_in_set_vu(w->codec, 0);
+                       arizona_in_set_vu(codec, 0);
        }
 
        return 0;
@@ -734,7 +735,25 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol,
                   int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+
        switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               switch (w->shift) {
+               case ARIZONA_OUT1L_ENA_SHIFT:
+               case ARIZONA_OUT1R_ENA_SHIFT:
+               case ARIZONA_OUT2L_ENA_SHIFT:
+               case ARIZONA_OUT2R_ENA_SHIFT:
+               case ARIZONA_OUT3L_ENA_SHIFT:
+               case ARIZONA_OUT3R_ENA_SHIFT:
+                       priv->out_up_pending++;
+                       priv->out_up_delay += 17;
+                       break;
+               default:
+                       break;
+               }
+               break;
        case SND_SOC_DAPM_POST_PMU:
                switch (w->shift) {
                case ARIZONA_OUT1L_ENA_SHIFT:
@@ -743,13 +762,50 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
                case ARIZONA_OUT2R_ENA_SHIFT:
                case ARIZONA_OUT3L_ENA_SHIFT:
                case ARIZONA_OUT3R_ENA_SHIFT:
-                       msleep(17);
+                       priv->out_up_pending--;
+                       if (!priv->out_up_pending) {
+                               msleep(priv->out_up_delay);
+                               priv->out_up_delay = 0;
+                       }
                        break;
 
                default:
                        break;
                }
                break;
+       case SND_SOC_DAPM_PRE_PMD:
+               switch (w->shift) {
+               case ARIZONA_OUT1L_ENA_SHIFT:
+               case ARIZONA_OUT1R_ENA_SHIFT:
+               case ARIZONA_OUT2L_ENA_SHIFT:
+               case ARIZONA_OUT2R_ENA_SHIFT:
+               case ARIZONA_OUT3L_ENA_SHIFT:
+               case ARIZONA_OUT3R_ENA_SHIFT:
+                       priv->out_down_pending++;
+                       priv->out_down_delay++;
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               switch (w->shift) {
+               case ARIZONA_OUT1L_ENA_SHIFT:
+               case ARIZONA_OUT1R_ENA_SHIFT:
+               case ARIZONA_OUT2L_ENA_SHIFT:
+               case ARIZONA_OUT2R_ENA_SHIFT:
+               case ARIZONA_OUT3L_ENA_SHIFT:
+               case ARIZONA_OUT3R_ENA_SHIFT:
+                       priv->out_down_pending--;
+                       if (!priv->out_down_pending) {
+                               msleep(priv->out_down_delay);
+                               priv->out_down_delay = 0;
+                       }
+                       break;
+               default:
+                       break;
+               }
+               break;
        }
 
        return 0;
@@ -760,7 +816,8 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol,
                   int event)
 {
-       struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
        struct arizona *arizona = priv->arizona;
        unsigned int mask = 1 << w->shift;
        unsigned int val;
@@ -772,6 +829,9 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,
        case SND_SOC_DAPM_PRE_PMD:
                val = 0;
                break;
+       case SND_SOC_DAPM_PRE_PMU:
+       case SND_SOC_DAPM_POST_PMD:
+               return arizona_out_ev(w, kcontrol, event);
        default:
                return -EINVAL;
        }
index 942cfb197b6daafa74de6fa64975bed128600c0a..11ff899b02724fae943d2bc1ce98550b26a62985 100644 (file)
@@ -77,6 +77,11 @@ struct arizona_priv {
        int num_inputs;
        unsigned int in_pending;
 
+       unsigned int out_up_pending;
+       unsigned int out_up_delay;
+       unsigned int out_down_pending;
+       unsigned int out_down_delay;
+
        unsigned int spk_ena:2;
        unsigned int spk_ena_pending:1;
 };
index 5075bf0a7276b02417d9ae7346f887075c8b653d..e7238b8904bceec6f0903bd2974d00b4c6c262aa 100644 (file)
@@ -86,5 +86,5 @@ static struct platform_driver bt_sco_driver = {
 module_platform_driver(bt_sco_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
-MODULE_DESCRIPTION("ASoC generic bluethooth sco link driver");
+MODULE_DESCRIPTION("ASoC generic bluetooth sco link driver");
 MODULE_LICENSE("GPL");
index ec55c590afd00b90e9bee89bcfa1fb96f765ec7d..f2b8aad21274aec951fdabc20887b970ef2e1aaa 100644 (file)
@@ -264,7 +264,7 @@ static int cs35l32_codec_set_sysclk(struct snd_soc_codec *codec,
                        CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO_MASK, val);
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_cs35l32 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs35l32 = {
        .set_sysclk = cs35l32_codec_set_sysclk,
 
        .dapm_widgets = cs35l32_dapm_widgets,
@@ -288,7 +288,7 @@ static const struct reg_default cs35l32_monitor_patch[] = {
        { 0x00, 0x00 },
 };
 
-static struct regmap_config cs35l32_regmap = {
+static const struct regmap_config cs35l32_regmap = {
        .reg_bits = 8,
        .val_bits = 8,
 
index 35fbef743fbe21883db9d2e645ea018a5c8c9080..1589e7a881d817ab403f7a7a149cecfda4797a92 100644 (file)
@@ -1103,7 +1103,7 @@ static int cs42l52_remove(struct snd_soc_codec *codec)
        return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_cs42l52 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs42l52 = {
        .probe = cs42l52_probe,
        .remove = cs42l52_remove,
        .set_bias_level = cs42l52_set_bias_level,
@@ -1130,7 +1130,7 @@ static const struct reg_default cs42l52_threshold_patch[] = {
 
 };
 
-static struct regmap_config cs42l52_regmap = {
+static const struct regmap_config cs42l52_regmap = {
        .reg_bits = 8,
        .val_bits = 8,
 
index 2ddc7ac10ad7a311ccda24f7add9613891b068c9..cbc654fe48c76d7fa1c231a874f0e60588ecfc2f 100644 (file)
@@ -1164,7 +1164,7 @@ static int cs42l56_remove(struct snd_soc_codec *codec)
        return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_cs42l56 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs42l56 = {
        .probe = cs42l56_probe,
        .remove = cs42l56_remove,
        .set_bias_level = cs42l56_set_bias_level,
@@ -1179,7 +1179,7 @@ static struct snd_soc_codec_driver soc_codec_dev_cs42l56 = {
        .num_controls = ARRAY_SIZE(cs42l56_snd_controls),
 };
 
-static struct regmap_config cs42l56_regmap = {
+static const struct regmap_config cs42l56_regmap = {
        .reg_bits = 8,
        .val_bits = 8,
 
index 7c55537c69cf0804bcb03a3afa573660fbaee304..8ecedba79606c561c0a385e04091513074662210 100644 (file)
@@ -1347,7 +1347,7 @@ static int cs42l73_probe(struct snd_soc_codec *codec)
        return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_cs42l73 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs42l73 = {
        .probe = cs42l73_probe,
        .set_bias_level = cs42l73_set_bias_level,
        .suspend_bias_off = true,
@@ -1361,7 +1361,7 @@ static struct snd_soc_codec_driver soc_codec_dev_cs42l73 = {
        .num_controls = ARRAY_SIZE(cs42l73_snd_controls),
 };
 
-static struct regmap_config cs42l73_regmap = {
+static const struct regmap_config cs42l73_regmap = {
        .reg_bits = 8,
        .val_bits = 8,
 
index 61b2f9a2eef1b87d8daea13ab83d90779a883fc5..ffe96175a8a5ac62ee4721c1f17a54c305d447c7 100644 (file)
@@ -609,7 +609,7 @@ static const struct snd_kcontrol_new da732x_snd_controls[] = {
 static int da732x_adc_event(struct snd_soc_dapm_widget *w,
                            struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -663,7 +663,7 @@ static int da732x_adc_event(struct snd_soc_dapm_widget *w,
 static int da732x_out_pga_event(struct snd_soc_dapm_widget *w,
                                struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c
new file mode 100644 (file)
index 0000000..1806333
--- /dev/null
@@ -0,0 +1,138 @@
+/* Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * max98357a.c -- MAX98357A ALSA SoC Codec driver
+ */
+
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <sound/soc.h>
+
+#define DRV_NAME "max98357a"
+
+static int max98357a_daiops_trigger(struct snd_pcm_substream *substream,
+               int cmd, struct snd_soc_dai *dai)
+{
+       struct gpio_desc *sdmode = snd_soc_dai_get_drvdata(dai);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               gpiod_set_value(sdmode, 1);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               gpiod_set_value(sdmode, 0);
+               break;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget max98357a_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("SDMode", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_OUTPUT("Speaker"),
+};
+
+static const struct snd_soc_dapm_route max98357a_dapm_routes[] = {
+       {"Speaker", NULL, "SDMode"},
+};
+
+static int max98357a_codec_probe(struct snd_soc_codec *codec)
+{
+       struct gpio_desc *sdmode;
+
+       sdmode = devm_gpiod_get(codec->dev, "sdmode");
+       if (IS_ERR(sdmode)) {
+               dev_err(codec->dev, "%s() unable to get sdmode GPIO: %ld\n",
+                               __func__, PTR_ERR(sdmode));
+               return PTR_ERR(sdmode);
+       }
+       gpiod_direction_output(sdmode, 0);
+       snd_soc_codec_set_drvdata(codec, sdmode);
+
+       return 0;
+}
+
+static struct snd_soc_codec_driver max98357a_codec_driver = {
+       .probe                  = max98357a_codec_probe,
+       .dapm_widgets           = max98357a_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(max98357a_dapm_widgets),
+       .dapm_routes            = max98357a_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(max98357a_dapm_routes),
+};
+
+static struct snd_soc_dai_ops max98357a_dai_ops = {
+       .trigger        = max98357a_daiops_trigger,
+};
+
+static struct snd_soc_dai_driver max98357a_dai_driver = {
+       .name = DRV_NAME,
+       .playback = {
+               .stream_name    = DRV_NAME "-playback",
+               .formats        = SNDRV_PCM_FMTBIT_S16 |
+                                       SNDRV_PCM_FMTBIT_S24 |
+                                       SNDRV_PCM_FMTBIT_S32,
+               .rates          = SNDRV_PCM_RATE_8000 |
+                                       SNDRV_PCM_RATE_16000 |
+                                       SNDRV_PCM_RATE_48000 |
+                                       SNDRV_PCM_RATE_96000,
+               .rate_min       = 8000,
+               .rate_max       = 96000,
+               .channels_min   = 1,
+               .channels_max   = 2,
+       },
+       .ops    = &max98357a_dai_ops,
+};
+
+static int max98357a_platform_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       ret = snd_soc_register_codec(&pdev->dev, &max98357a_codec_driver,
+                       &max98357a_dai_driver, 1);
+       if (ret)
+               dev_err(&pdev->dev, "%s() error registering codec driver: %d\n",
+                               __func__, ret);
+
+       return ret;
+}
+
+static int max98357a_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id max98357a_device_id[] = {
+       { .compatible = "maxim," DRV_NAME, },
+       {}
+};
+MODULE_DEVICE_TABLE(of, max98357a_device_id);
+#endif
+
+static struct platform_driver max98357a_platform_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .of_match_table = of_match_ptr(max98357a_device_id),
+       },
+       .probe  = max98357a_platform_probe,
+       .remove = max98357a_platform_remove,
+};
+module_platform_driver(max98357a_platform_driver);
+
+MODULE_DESCRIPTION("Maxim MAX98357A Codec Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
index c1e441c2c8af5326b3125188fd4ecf19f0b740e1..2ffb9a0570dc8db3625cc8224f034995ea88d7dd 100644 (file)
@@ -328,16 +328,16 @@ static int mc13783_set_tdm_slot_dac(struct snd_soc_dai *dai,
        }
 
        switch (rx_mask) {
-       case 0xfffffffc:
+       case 0x03:
                val |= SSI_NETWORK_DAC_RXSLOT_0_1;
                break;
-       case 0xfffffff3:
+       case 0x0c:
                val |= SSI_NETWORK_DAC_RXSLOT_2_3;
                break;
-       case 0xffffffcf:
+       case 0x30:
                val |= SSI_NETWORK_DAC_RXSLOT_4_5;
                break;
-       case 0xffffff3f:
+       case 0xc0:
                val |= SSI_NETWORK_DAC_RXSLOT_6_7;
                break;
        default:
@@ -360,7 +360,7 @@ static int mc13783_set_tdm_slot_codec(struct snd_soc_dai *dai,
        if (slots != 4)
                return -EINVAL;
 
-       if (tx_mask != 0xfffffffc)
+       if (tx_mask != 0x3)
                return -EINVAL;
 
        val |= (0x00 << 2);     /* primary timeslot RX/TX(?) is 0 */
index 7e73fa4b3183851f55d5660ce3e7ee4d95c549d5..8fb445f33f6f2a23c0d30f15c37ef590609c91cc 100644 (file)
@@ -32,7 +32,7 @@ static int pcm3008_dac_ev(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *kcontrol,
                          int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct pcm3008_setup_data *setup = codec->dev->platform_data;
 
        gpio_set_value_cansleep(setup->pdda_pin,
@@ -45,7 +45,7 @@ static int pcm3008_adc_ev(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *kcontrol,
                          int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct pcm3008_setup_data *setup = codec->dev->platform_data;
 
        gpio_set_value_cansleep(setup->pdad_pin,
index d0547fa275fc307d8ff40b7d6dcf2585061dc317..dcdfac0ffeb15c2fbe6c91883af6bf7bfb156dc6 100644 (file)
@@ -46,6 +46,8 @@ static int pcm512x_i2c_remove(struct i2c_client *i2c)
 static const struct i2c_device_id pcm512x_i2c_id[] = {
        { "pcm5121", },
        { "pcm5122", },
+       { "pcm5141", },
+       { "pcm5142", },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id);
@@ -53,6 +55,8 @@ MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id);
 static const struct of_device_id pcm512x_of_match[] = {
        { .compatible = "ti,pcm5121", },
        { .compatible = "ti,pcm5122", },
+       { .compatible = "ti,pcm5141", },
+       { .compatible = "ti,pcm5142", },
        { }
 };
 MODULE_DEVICE_TABLE(of, pcm512x_of_match);
index f297058c0038d1a7c2a7bd999fe664cbf4282433..7b64a9cef70481bab82875f4589f68e4fb63508f 100644 (file)
@@ -43,6 +43,8 @@ static int pcm512x_spi_remove(struct spi_device *spi)
 static const struct spi_device_id pcm512x_spi_id[] = {
        { "pcm5121", },
        { "pcm5122", },
+       { "pcm5141", },
+       { "pcm5142", },
        { },
 };
 MODULE_DEVICE_TABLE(spi, pcm512x_spi_id);
@@ -50,6 +52,8 @@ MODULE_DEVICE_TABLE(spi, pcm512x_spi_id);
 static const struct of_device_id pcm512x_of_match[] = {
        { .compatible = "ti,pcm5121", },
        { .compatible = "ti,pcm5122", },
+       { .compatible = "ti,pcm5141", },
+       { .compatible = "ti,pcm5142", },
        { }
 };
 MODULE_DEVICE_TABLE(of, pcm512x_of_match);
index 30c673cdc12ed409a720836d139cd48b7ed5d134..9974f201a08f44ee25b109c7ff78e13440146c4b 100644 (file)
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
+#include <linux/gcd.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
+#include <sound/pcm_params.h>
 #include <sound/tlv.h>
 
 #include "pcm512x.h"
 
+#define DIV_ROUND_DOWN_ULL(ll, d) \
+       ({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; })
+#define DIV_ROUND_CLOSEST_ULL(ll, d) \
+       ({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; })
+
 #define PCM512x_NUM_SUPPLIES 3
 static const char * const pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = {
        "AVDD",
@@ -39,6 +46,14 @@ struct pcm512x_priv {
        struct clk *sclk;
        struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES];
        struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES];
+       int fmt;
+       int pll_in;
+       int pll_out;
+       int pll_r;
+       int pll_j;
+       int pll_d;
+       int pll_p;
+       unsigned long real_pll;
 };
 
 /*
@@ -69,6 +84,7 @@ static const struct reg_default pcm512x_reg_defaults[] = {
        { PCM512x_MUTE,              0x00 },
        { PCM512x_DSP,               0x00 },
        { PCM512x_PLL_REF,           0x00 },
+       { PCM512x_DAC_REF,           0x00 },
        { PCM512x_DAC_ROUTING,       0x11 },
        { PCM512x_DSP_PROGRAM,       0x01 },
        { PCM512x_CLKDET,            0x00 },
@@ -87,6 +103,25 @@ static const struct reg_default pcm512x_reg_defaults[] = {
        { PCM512x_ANALOG_GAIN_BOOST, 0x00 },
        { PCM512x_VCOM_CTRL_1,       0x00 },
        { PCM512x_VCOM_CTRL_2,       0x01 },
+       { PCM512x_BCLK_LRCLK_CFG,    0x00 },
+       { PCM512x_MASTER_MODE,       0x7c },
+       { PCM512x_GPIO_DACIN,        0x00 },
+       { PCM512x_GPIO_PLLIN,        0x00 },
+       { PCM512x_SYNCHRONIZE,       0x10 },
+       { PCM512x_PLL_COEFF_0,       0x00 },
+       { PCM512x_PLL_COEFF_1,       0x00 },
+       { PCM512x_PLL_COEFF_2,       0x00 },
+       { PCM512x_PLL_COEFF_3,       0x00 },
+       { PCM512x_PLL_COEFF_4,       0x00 },
+       { PCM512x_DSP_CLKDIV,        0x00 },
+       { PCM512x_DAC_CLKDIV,        0x00 },
+       { PCM512x_NCP_CLKDIV,        0x00 },
+       { PCM512x_OSR_CLKDIV,        0x00 },
+       { PCM512x_MASTER_CLKDIV_1,   0x00 },
+       { PCM512x_MASTER_CLKDIV_2,   0x00 },
+       { PCM512x_FS_SPEED_MODE,     0x00 },
+       { PCM512x_IDAC_1,            0x01 },
+       { PCM512x_IDAC_2,            0x00 },
 };
 
 static bool pcm512x_readable(struct device *dev, unsigned int reg)
@@ -103,6 +138,10 @@ static bool pcm512x_readable(struct device *dev, unsigned int reg)
        case PCM512x_DSP_GPIO_INPUT:
        case PCM512x_MASTER_MODE:
        case PCM512x_PLL_REF:
+       case PCM512x_DAC_REF:
+       case PCM512x_GPIO_DACIN:
+       case PCM512x_GPIO_PLLIN:
+       case PCM512x_SYNCHRONIZE:
        case PCM512x_PLL_COEFF_0:
        case PCM512x_PLL_COEFF_1:
        case PCM512x_PLL_COEFF_2:
@@ -143,6 +182,7 @@ static bool pcm512x_readable(struct device *dev, unsigned int reg)
        case PCM512x_RATE_DET_2:
        case PCM512x_RATE_DET_3:
        case PCM512x_RATE_DET_4:
+       case PCM512x_CLOCK_STATUS:
        case PCM512x_ANALOG_MUTE_DET:
        case PCM512x_GPIN:
        case PCM512x_DIGITAL_MUTE_DET:
@@ -154,6 +194,8 @@ static bool pcm512x_readable(struct device *dev, unsigned int reg)
        case PCM512x_VCOM_CTRL_1:
        case PCM512x_VCOM_CTRL_2:
        case PCM512x_CRAM_CTRL:
+       case PCM512x_FLEX_A:
+       case PCM512x_FLEX_B:
                return true;
        default:
                /* There are 256 raw register addresses */
@@ -170,6 +212,7 @@ static bool pcm512x_volatile(struct device *dev, unsigned int reg)
        case PCM512x_RATE_DET_2:
        case PCM512x_RATE_DET_3:
        case PCM512x_RATE_DET_4:
+       case PCM512x_CLOCK_STATUS:
        case PCM512x_ANALOG_MUTE_DET:
        case PCM512x_GPIN:
        case PCM512x_DIGITAL_MUTE_DET:
@@ -277,7 +320,7 @@ SOC_ENUM("Auto Mute Time Right", pcm512x_autom_r),
 SOC_SINGLE("Auto Mute Mono Switch", PCM512x_DIGITAL_MUTE_3,
           PCM512x_ACTL_SHIFT, 1, 0),
 SOC_DOUBLE("Auto Mute Switch", PCM512x_DIGITAL_MUTE_3, PCM512x_AMLE_SHIFT,
-          PCM512x_AMLR_SHIFT, 1, 0),
+          PCM512x_AMRE_SHIFT, 1, 0),
 
 SOC_ENUM("Volume Ramp Down Rate", pcm512x_vndf),
 SOC_ENUM("Volume Ramp Down Step", pcm512x_vnds),
@@ -303,6 +346,136 @@ static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = {
        { "OUTR", NULL, "DACR" },
 };
 
+static const u32 pcm512x_dai_rates[] = {
+       8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
+       88200, 96000, 176400, 192000, 384000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_slave = {
+       .count = ARRAY_SIZE(pcm512x_dai_rates),
+       .list  = pcm512x_dai_rates,
+};
+
+static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params,
+                               struct snd_pcm_hw_rule *rule)
+{
+       struct snd_interval ranges[2];
+       int frame_size;
+
+       frame_size = snd_soc_params_to_frame_size(params);
+       if (frame_size < 0)
+               return frame_size;
+
+       switch (frame_size) {
+       case 32:
+               /* No hole when the frame size is 32. */
+               return 0;
+       case 48:
+       case 64:
+               /* There is only one hole in the range of supported
+                * rates, but it moves with the frame size.
+                */
+               memset(ranges, 0, sizeof(ranges));
+               ranges[0].min = 8000;
+               ranges[0].max = 25000000 / frame_size / 2;
+               ranges[1].min = DIV_ROUND_UP(16000000, frame_size);
+               ranges[1].max = 384000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return snd_interval_ranges(hw_param_interval(params, rule->var),
+                                  ARRAY_SIZE(ranges), ranges, 0);
+}
+
+static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream,
+                                     struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+       struct device *dev = dai->dev;
+       struct snd_pcm_hw_constraint_ratnums *constraints_no_pll;
+       struct snd_ratnum *rats_no_pll;
+
+       if (IS_ERR(pcm512x->sclk)) {
+               dev_err(dev, "Need SCLK for master mode: %ld\n",
+                       PTR_ERR(pcm512x->sclk));
+               return PTR_ERR(pcm512x->sclk);
+       }
+
+       if (pcm512x->pll_out)
+               return snd_pcm_hw_rule_add(substream->runtime, 0,
+                                          SNDRV_PCM_HW_PARAM_RATE,
+                                          pcm512x_hw_rule_rate,
+                                          NULL,
+                                          SNDRV_PCM_HW_PARAM_FRAME_BITS,
+                                          SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+
+       constraints_no_pll = devm_kzalloc(dev, sizeof(*constraints_no_pll),
+                                         GFP_KERNEL);
+       if (!constraints_no_pll)
+               return -ENOMEM;
+       constraints_no_pll->nrats = 1;
+       rats_no_pll = devm_kzalloc(dev, sizeof(*rats_no_pll), GFP_KERNEL);
+       if (!rats_no_pll)
+               return -ENOMEM;
+       constraints_no_pll->rats = rats_no_pll;
+       rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64;
+       rats_no_pll->den_min = 1;
+       rats_no_pll->den_max = 128;
+       rats_no_pll->den_step = 1;
+
+       return snd_pcm_hw_constraint_ratnums(substream->runtime, 0,
+                                            SNDRV_PCM_HW_PARAM_RATE,
+                                            constraints_no_pll);
+}
+
+static int pcm512x_dai_startup_slave(struct snd_pcm_substream *substream,
+                                    struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+       struct device *dev = dai->dev;
+       struct regmap *regmap = pcm512x->regmap;
+
+       if (IS_ERR(pcm512x->sclk)) {
+               dev_info(dev, "No SCLK, using BCLK: %ld\n",
+                        PTR_ERR(pcm512x->sclk));
+
+               /* Disable reporting of missing SCLK as an error */
+               regmap_update_bits(regmap, PCM512x_ERROR_DETECT,
+                                  PCM512x_IDCH, PCM512x_IDCH);
+
+               /* Switch PLL input to BCLK */
+               regmap_update_bits(regmap, PCM512x_PLL_REF,
+                                  PCM512x_SREF, PCM512x_SREF_BCK);
+       }
+
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                                         SNDRV_PCM_HW_PARAM_RATE,
+                                         &constraints_slave);
+}
+
+static int pcm512x_dai_startup(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+       switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_CBM_CFS:
+               return pcm512x_dai_startup_master(substream, dai);
+
+       case SND_SOC_DAIFMT_CBS_CFS:
+               return pcm512x_dai_startup_slave(substream, dai);
+
+       default:
+               return -EINVAL;
+       }
+}
+
 static int pcm512x_set_bias_level(struct snd_soc_codec *codec,
                                  enum snd_soc_bias_level level)
 {
@@ -340,17 +513,717 @@ static int pcm512x_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
+static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai,
+                                     unsigned long bclk_rate)
+{
+       struct device *dev = dai->dev;
+       unsigned long sck_rate;
+       int pow2;
+
+       /* 64 MHz <= pll_rate <= 100 MHz, VREF mode */
+       /* 16 MHz <= sck_rate <=  25 MHz, VREF mode */
+
+       /* select sck_rate as a multiple of bclk_rate but still with
+        * as many factors of 2 as possible, as that makes it easier
+        * to find a fast DAC rate
+        */
+       pow2 = 1 << fls((25000000 - 16000000) / bclk_rate);
+       for (; pow2; pow2 >>= 1) {
+               sck_rate = rounddown(25000000, bclk_rate * pow2);
+               if (sck_rate >= 16000000)
+                       break;
+       }
+       if (!pow2) {
+               dev_err(dev, "Impossible to generate a suitable SCK\n");
+               return 0;
+       }
+
+       dev_dbg(dev, "sck_rate %lu\n", sck_rate);
+       return sck_rate;
+}
+
+/* pll_rate = pllin_rate * R * J.D / P
+ * 1 <= R <= 16
+ * 1 <= J <= 63
+ * 0 <= D <= 9999
+ * 1 <= P <= 15
+ * 64 MHz <= pll_rate <= 100 MHz
+ * if D == 0
+ *     1 MHz <= pllin_rate / P <= 20 MHz
+ * else if D > 0
+ *     6.667 MHz <= pllin_rate / P <= 20 MHz
+ *     4 <= J <= 11
+ *     R = 1
+ */
+static int pcm512x_find_pll_coeff(struct snd_soc_dai *dai,
+                                 unsigned long pllin_rate,
+                                 unsigned long pll_rate)
+{
+       struct device *dev = dai->dev;
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+       unsigned long common;
+       int R, J, D, P;
+       unsigned long K; /* 10000 * J.D */
+       unsigned long num;
+       unsigned long den;
+
+       common = gcd(pll_rate, pllin_rate);
+       dev_dbg(dev, "pll %lu pllin %lu common %lu\n",
+               pll_rate, pllin_rate, common);
+       num = pll_rate / common;
+       den = pllin_rate / common;
+
+       /* pllin_rate / P (or here, den) cannot be greater than 20 MHz */
+       if (pllin_rate / den > 20000000 && num < 8) {
+               num *= 20000000 / (pllin_rate / den);
+               den *= 20000000 / (pllin_rate / den);
+       }
+       dev_dbg(dev, "num / den = %lu / %lu\n", num, den);
+
+       P = den;
+       if (den <= 15 && num <= 16 * 63
+           && 1000000 <= pllin_rate / P && pllin_rate / P <= 20000000) {
+               /* Try the case with D = 0 */
+               D = 0;
+               /* factor 'num' into J and R, such that R <= 16 and J <= 63 */
+               for (R = 16; R; R--) {
+                       if (num % R)
+                               continue;
+                       J = num / R;
+                       if (J == 0 || J > 63)
+                               continue;
+
+                       dev_dbg(dev, "R * J / P = %d * %d / %d\n", R, J, P);
+                       pcm512x->real_pll = pll_rate;
+                       goto done;
+               }
+               /* no luck */
+       }
+
+       R = 1;
+
+       if (num > 0xffffffffUL / 10000)
+               goto fallback;
+
+       /* Try to find an exact pll_rate using the D > 0 case */
+       common = gcd(10000 * num, den);
+       num = 10000 * num / common;
+       den /= common;
+       dev_dbg(dev, "num %lu den %lu common %lu\n", num, den, common);
+
+       for (P = den; P <= 15; P++) {
+               if (pllin_rate / P < 6667000 || 200000000 < pllin_rate / P)
+                       continue;
+               if (num * P % den)
+                       continue;
+               K = num * P / den;
+               /* J == 12 is ok if D == 0 */
+               if (K < 40000 || K > 120000)
+                       continue;
+
+               J = K / 10000;
+               D = K % 10000;
+               dev_dbg(dev, "J.D / P = %d.%04d / %d\n", J, D, P);
+               pcm512x->real_pll = pll_rate;
+               goto done;
+       }
+
+       /* Fall back to an approximate pll_rate */
+
+fallback:
+       /* find smallest possible P */
+       P = DIV_ROUND_UP(pllin_rate, 20000000);
+       if (!P)
+               P = 1;
+       else if (P > 15) {
+               dev_err(dev, "Need a slower clock as pll-input\n");
+               return -EINVAL;
+       }
+       if (pllin_rate / P < 6667000) {
+               dev_err(dev, "Need a faster clock as pll-input\n");
+               return -EINVAL;
+       }
+       K = DIV_ROUND_CLOSEST_ULL(10000ULL * pll_rate * P, pllin_rate);
+       if (K < 40000)
+               K = 40000;
+       /* J == 12 is ok if D == 0 */
+       if (K > 120000)
+               K = 120000;
+       J = K / 10000;
+       D = K % 10000;
+       dev_dbg(dev, "J.D / P ~ %d.%04d / %d\n", J, D, P);
+       pcm512x->real_pll = DIV_ROUND_DOWN_ULL((u64)K * pllin_rate, 10000 * P);
+
+done:
+       pcm512x->pll_r = R;
+       pcm512x->pll_j = J;
+       pcm512x->pll_d = D;
+       pcm512x->pll_p = P;
+       return 0;
+}
+
+static unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai,
+                                           unsigned long osr_rate,
+                                           unsigned long pllin_rate)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+       unsigned long dac_rate;
+
+       if (!pcm512x->pll_out)
+               return 0; /* no PLL to bypass, force SCK as DAC input */
+
+       if (pllin_rate % osr_rate)
+               return 0; /* futile, quit early */
+
+       /* run DAC no faster than 6144000 Hz */
+       for (dac_rate = rounddown(6144000, osr_rate);
+            dac_rate;
+            dac_rate -= osr_rate) {
+
+               if (pllin_rate / dac_rate > 128)
+                       return 0; /* DAC divider would be too big */
+
+               if (!(pllin_rate % dac_rate))
+                       return dac_rate;
+
+               dac_rate -= osr_rate;
+       }
+
+       return 0;
+}
+
+static int pcm512x_set_dividers(struct snd_soc_dai *dai,
+                               struct snd_pcm_hw_params *params)
+{
+       struct device *dev = dai->dev;
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+       unsigned long pllin_rate = 0;
+       unsigned long pll_rate;
+       unsigned long sck_rate;
+       unsigned long mck_rate;
+       unsigned long bclk_rate;
+       unsigned long sample_rate;
+       unsigned long osr_rate;
+       unsigned long dacsrc_rate;
+       int bclk_div;
+       int lrclk_div;
+       int dsp_div;
+       int dac_div;
+       unsigned long dac_rate;
+       int ncp_div;
+       int osr_div;
+       int ret;
+       int idac;
+       int fssp;
+       int gpio;
+
+       lrclk_div = snd_soc_params_to_frame_size(params);
+       if (lrclk_div == 0) {
+               dev_err(dev, "No LRCLK?\n");
+               return -EINVAL;
+       }
+
+       if (!pcm512x->pll_out) {
+               sck_rate = clk_get_rate(pcm512x->sclk);
+               bclk_div = params->rate_den * 64 / lrclk_div;
+               bclk_rate = DIV_ROUND_CLOSEST(sck_rate, bclk_div);
+
+               mck_rate = sck_rate;
+       } else {
+               ret = snd_soc_params_to_bclk(params);
+               if (ret < 0) {
+                       dev_err(dev, "Failed to find suitable BCLK: %d\n", ret);
+                       return ret;
+               }
+               if (ret == 0) {
+                       dev_err(dev, "No BCLK?\n");
+                       return -EINVAL;
+               }
+               bclk_rate = ret;
+
+               pllin_rate = clk_get_rate(pcm512x->sclk);
+
+               sck_rate = pcm512x_find_sck(dai, bclk_rate);
+               if (!sck_rate)
+                       return -EINVAL;
+               pll_rate = 4 * sck_rate;
+
+               ret = pcm512x_find_pll_coeff(dai, pllin_rate, pll_rate);
+               if (ret != 0)
+                       return ret;
+
+               ret = regmap_write(pcm512x->regmap,
+                                  PCM512x_PLL_COEFF_0, pcm512x->pll_p - 1);
+               if (ret != 0) {
+                       dev_err(dev, "Failed to write PLL P: %d\n", ret);
+                       return ret;
+               }
+
+               ret = regmap_write(pcm512x->regmap,
+                                  PCM512x_PLL_COEFF_1, pcm512x->pll_j);
+               if (ret != 0) {
+                       dev_err(dev, "Failed to write PLL J: %d\n", ret);
+                       return ret;
+               }
+
+               ret = regmap_write(pcm512x->regmap,
+                                  PCM512x_PLL_COEFF_2, pcm512x->pll_d >> 8);
+               if (ret != 0) {
+                       dev_err(dev, "Failed to write PLL D msb: %d\n", ret);
+                       return ret;
+               }
+
+               ret = regmap_write(pcm512x->regmap,
+                                  PCM512x_PLL_COEFF_3, pcm512x->pll_d & 0xff);
+               if (ret != 0) {
+                       dev_err(dev, "Failed to write PLL D lsb: %d\n", ret);
+                       return ret;
+               }
+
+               ret = regmap_write(pcm512x->regmap,
+                                  PCM512x_PLL_COEFF_4, pcm512x->pll_r - 1);
+               if (ret != 0) {
+                       dev_err(dev, "Failed to write PLL R: %d\n", ret);
+                       return ret;
+               }
+
+               mck_rate = pcm512x->real_pll;
+
+               bclk_div = DIV_ROUND_CLOSEST(sck_rate, bclk_rate);
+       }
+
+       if (bclk_div > 128) {
+               dev_err(dev, "Failed to find BCLK divider\n");
+               return -EINVAL;
+       }
+
+       /* the actual rate */
+       sample_rate = sck_rate / bclk_div / lrclk_div;
+       osr_rate = 16 * sample_rate;
+
+       /* run DSP no faster than 50 MHz */
+       dsp_div = mck_rate > 50000000 ? 2 : 1;
+
+       dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate);
+       if (dac_rate) {
+               /* the desired clock rate is "compatible" with the pll input
+                * clock, so use that clock as dac input instead of the pll
+                * output clock since the pll will introduce jitter and thus
+                * noise.
+                */
+               dev_dbg(dev, "using pll input as dac input\n");
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF,
+                                        PCM512x_SDAC, PCM512x_SDAC_GPIO);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to set gpio as dacref: %d\n", ret);
+                       return ret;
+               }
+
+               gpio = PCM512x_GREF_GPIO1 + pcm512x->pll_in - 1;
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_DACIN,
+                                        PCM512x_GREF, gpio);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to set gpio %d as dacin: %d\n",
+                               pcm512x->pll_in, ret);
+                       return ret;
+               }
+
+               dacsrc_rate = pllin_rate;
+       } else {
+               /* run DAC no faster than 6144000 Hz */
+               unsigned long dac_mul = 6144000 / osr_rate;
+               unsigned long sck_mul = sck_rate / osr_rate;
+
+               for (; dac_mul; dac_mul--) {
+                       if (!(sck_mul % dac_mul))
+                               break;
+               }
+               if (!dac_mul) {
+                       dev_err(dev, "Failed to find DAC rate\n");
+                       return -EINVAL;
+               }
+
+               dac_rate = dac_mul * osr_rate;
+               dev_dbg(dev, "dac_rate %lu sample_rate %lu\n",
+                       dac_rate, sample_rate);
+
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF,
+                                        PCM512x_SDAC, PCM512x_SDAC_SCK);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to set sck as dacref: %d\n", ret);
+                       return ret;
+               }
+
+               dacsrc_rate = sck_rate;
+       }
+
+       dac_div = DIV_ROUND_CLOSEST(dacsrc_rate, dac_rate);
+       if (dac_div > 128) {
+               dev_err(dev, "Failed to find DAC divider\n");
+               return -EINVAL;
+       }
+
+       ncp_div = DIV_ROUND_CLOSEST(dacsrc_rate / dac_div, 1536000);
+       if (ncp_div > 128 || dacsrc_rate / dac_div / ncp_div > 2048000) {
+               /* run NCP no faster than 2048000 Hz, but why? */
+               ncp_div = DIV_ROUND_UP(dacsrc_rate / dac_div, 2048000);
+               if (ncp_div > 128) {
+                       dev_err(dev, "Failed to find NCP divider\n");
+                       return -EINVAL;
+               }
+       }
+
+       osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate);
+       if (osr_div > 128) {
+               dev_err(dev, "Failed to find OSR divider\n");
+               return -EINVAL;
+       }
+
+       idac = mck_rate / (dsp_div * sample_rate);
+
+       ret = regmap_write(pcm512x->regmap, PCM512x_DSP_CLKDIV, dsp_div - 1);
+       if (ret != 0) {
+               dev_err(dev, "Failed to write DSP divider: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_write(pcm512x->regmap, PCM512x_DAC_CLKDIV, dac_div - 1);
+       if (ret != 0) {
+               dev_err(dev, "Failed to write DAC divider: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_write(pcm512x->regmap, PCM512x_NCP_CLKDIV, ncp_div - 1);
+       if (ret != 0) {
+               dev_err(dev, "Failed to write NCP divider: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_write(pcm512x->regmap, PCM512x_OSR_CLKDIV, osr_div - 1);
+       if (ret != 0) {
+               dev_err(dev, "Failed to write OSR divider: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_write(pcm512x->regmap,
+                          PCM512x_MASTER_CLKDIV_1, bclk_div - 1);
+       if (ret != 0) {
+               dev_err(dev, "Failed to write BCLK divider: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_write(pcm512x->regmap,
+                          PCM512x_MASTER_CLKDIV_2, lrclk_div - 1);
+       if (ret != 0) {
+               dev_err(dev, "Failed to write LRCLK divider: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_write(pcm512x->regmap, PCM512x_IDAC_1, idac >> 8);
+       if (ret != 0) {
+               dev_err(dev, "Failed to write IDAC msb divider: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_write(pcm512x->regmap, PCM512x_IDAC_2, idac & 0xff);
+       if (ret != 0) {
+               dev_err(dev, "Failed to write IDAC lsb divider: %d\n", ret);
+               return ret;
+       }
+
+       if (sample_rate <= 48000)
+               fssp = PCM512x_FSSP_48KHZ;
+       else if (sample_rate <= 96000)
+               fssp = PCM512x_FSSP_96KHZ;
+       else if (sample_rate <= 192000)
+               fssp = PCM512x_FSSP_192KHZ;
+       else
+               fssp = PCM512x_FSSP_384KHZ;
+       ret = regmap_update_bits(pcm512x->regmap, PCM512x_FS_SPEED_MODE,
+                                PCM512x_FSSP, fssp);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set fs speed: %d\n", ret);
+               return ret;
+       }
+
+       dev_dbg(codec->dev, "DSP divider %d\n", dsp_div);
+       dev_dbg(codec->dev, "DAC divider %d\n", dac_div);
+       dev_dbg(codec->dev, "NCP divider %d\n", ncp_div);
+       dev_dbg(codec->dev, "OSR divider %d\n", osr_div);
+       dev_dbg(codec->dev, "BCK divider %d\n", bclk_div);
+       dev_dbg(codec->dev, "LRCK divider %d\n", lrclk_div);
+       dev_dbg(codec->dev, "IDAC %d\n", idac);
+       dev_dbg(codec->dev, "1<<FSSP %d\n", 1 << fssp);
+
+       return 0;
+}
+
+static int pcm512x_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *params,
+                            struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+       int alen;
+       int gpio;
+       int clock_output;
+       int master_mode;
+       int ret;
+
+       dev_dbg(codec->dev, "hw_params %u Hz, %u channels\n",
+               params_rate(params),
+               params_channels(params));
+
+       switch (snd_pcm_format_width(params_format(params))) {
+       case 16:
+               alen = PCM512x_ALEN_16;
+               break;
+       case 20:
+               alen = PCM512x_ALEN_20;
+               break;
+       case 24:
+               alen = PCM512x_ALEN_24;
+               break;
+       case 32:
+               alen = PCM512x_ALEN_32;
+               break;
+       default:
+               dev_err(codec->dev, "Bad frame size: %d\n",
+                       snd_pcm_format_width(params_format(params)));
+               return -EINVAL;
+       }
+
+       switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               ret = regmap_update_bits(pcm512x->regmap,
+                                        PCM512x_BCLK_LRCLK_CFG,
+                                        PCM512x_BCKP
+                                        | PCM512x_BCKO | PCM512x_LRKO,
+                                        0);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to enable slave mode: %d\n", ret);
+                       return ret;
+               }
+
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT,
+                                        PCM512x_DCAS, 0);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to enable clock divider autoset: %d\n",
+                               ret);
+                       return ret;
+               }
+               return 0;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               clock_output = PCM512x_BCKO | PCM512x_LRKO;
+               master_mode = PCM512x_RLRK | PCM512x_RBCK;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               clock_output = PCM512x_BCKO;
+               master_mode = PCM512x_RBCK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1,
+                                PCM512x_ALEN, alen);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set frame size: %d\n", ret);
+               return ret;
+       }
+
+       if (pcm512x->pll_out) {
+               ret = regmap_write(pcm512x->regmap, PCM512x_FLEX_A, 0x11);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Failed to set FLEX_A: %d\n", ret);
+                       return ret;
+               }
+
+               ret = regmap_write(pcm512x->regmap, PCM512x_FLEX_B, 0xff);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Failed to set FLEX_B: %d\n", ret);
+                       return ret;
+               }
+
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT,
+                                        PCM512x_IDFS | PCM512x_IDBK
+                                        | PCM512x_IDSK | PCM512x_IDCH
+                                        | PCM512x_IDCM | PCM512x_DCAS
+                                        | PCM512x_IPLK,
+                                        PCM512x_IDFS | PCM512x_IDBK
+                                        | PCM512x_IDSK | PCM512x_IDCH
+                                        | PCM512x_DCAS);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to ignore auto-clock failures: %d\n",
+                               ret);
+                       return ret;
+               }
+       } else {
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT,
+                                        PCM512x_IDFS | PCM512x_IDBK
+                                        | PCM512x_IDSK | PCM512x_IDCH
+                                        | PCM512x_IDCM | PCM512x_DCAS
+                                        | PCM512x_IPLK,
+                                        PCM512x_IDFS | PCM512x_IDBK
+                                        | PCM512x_IDSK | PCM512x_IDCH
+                                        | PCM512x_DCAS | PCM512x_IPLK);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to ignore auto-clock failures: %d\n",
+                               ret);
+                       return ret;
+               }
+
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_EN,
+                                        PCM512x_PLLE, 0);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Failed to disable pll: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       ret = pcm512x_set_dividers(dai, params);
+       if (ret != 0)
+               return ret;
+
+       if (pcm512x->pll_out) {
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_REF,
+                                        PCM512x_SREF, PCM512x_SREF_GPIO);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to set gpio as pllref: %d\n", ret);
+                       return ret;
+               }
+
+               gpio = PCM512x_GREF_GPIO1 + pcm512x->pll_in - 1;
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_PLLIN,
+                                        PCM512x_GREF, gpio);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to set gpio %d as pllin: %d\n",
+                               pcm512x->pll_in, ret);
+                       return ret;
+               }
+
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_EN,
+                                        PCM512x_PLLE, PCM512x_PLLE);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Failed to enable pll: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       ret = regmap_update_bits(pcm512x->regmap, PCM512x_BCLK_LRCLK_CFG,
+                                PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO,
+                                clock_output);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to enable clock output: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_update_bits(pcm512x->regmap, PCM512x_MASTER_MODE,
+                                PCM512x_RLRK | PCM512x_RBCK,
+                                master_mode);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to enable master mode: %d\n", ret);
+               return ret;
+       }
+
+       if (pcm512x->pll_out) {
+               gpio = PCM512x_G1OE << (pcm512x->pll_out - 1);
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_EN,
+                                        gpio, gpio);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Failed to enable gpio %d: %d\n",
+                               pcm512x->pll_out, ret);
+                       return ret;
+               }
+
+               gpio = PCM512x_GPIO_OUTPUT_1 + pcm512x->pll_out - 1;
+               ret = regmap_update_bits(pcm512x->regmap, gpio,
+                                        PCM512x_GxSL, PCM512x_GxSL_PLLCK);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Failed to output pll on %d: %d\n",
+                               ret, pcm512x->pll_out);
+                       return ret;
+               }
+
+               gpio = PCM512x_G1OE << (4 - 1);
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_EN,
+                                        gpio, gpio);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Failed to enable gpio %d: %d\n",
+                               4, ret);
+                       return ret;
+               }
+
+               gpio = PCM512x_GPIO_OUTPUT_1 + 4 - 1;
+               ret = regmap_update_bits(pcm512x->regmap, gpio,
+                                        PCM512x_GxSL, PCM512x_GxSL_PLLLK);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to output pll lock on %d: %d\n",
+                               ret, 4);
+                       return ret;
+               }
+       }
+
+       ret = regmap_update_bits(pcm512x->regmap, PCM512x_SYNCHRONIZE,
+                                PCM512x_RQSY, PCM512x_RQSY_HALT);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to halt clocks: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_update_bits(pcm512x->regmap, PCM512x_SYNCHRONIZE,
+                                PCM512x_RQSY, PCM512x_RQSY_RESUME);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to resume clocks: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+       pcm512x->fmt = fmt;
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops pcm512x_dai_ops = {
+       .startup = pcm512x_dai_startup,
+       .hw_params = pcm512x_hw_params,
+       .set_fmt = pcm512x_set_fmt,
+};
+
 static struct snd_soc_dai_driver pcm512x_dai = {
        .name = "pcm512x-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
                .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_192000,
+               .rates = SNDRV_PCM_RATE_CONTINUOUS,
+               .rate_min = 8000,
+               .rate_max = 384000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE |
                           SNDRV_PCM_FMTBIT_S24_LE |
                           SNDRV_PCM_FMTBIT_S32_LE
        },
+       .ops = &pcm512x_dai_ops,
 };
 
 static struct snd_soc_codec_driver pcm512x_codec_driver = {
@@ -448,21 +1321,9 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
        }
 
        pcm512x->sclk = devm_clk_get(dev, NULL);
-       if (IS_ERR(pcm512x->sclk)) {
-               if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-
-               dev_info(dev, "No SCLK, using BCLK: %ld\n",
-                        PTR_ERR(pcm512x->sclk));
-
-               /* Disable reporting of missing SCLK as an error */
-               regmap_update_bits(regmap, PCM512x_ERROR_DETECT,
-                                  PCM512x_IDCH, PCM512x_IDCH);
-
-               /* Switch PLL input to BCLK */
-               regmap_update_bits(regmap, PCM512x_PLL_REF,
-                                  PCM512x_SREF, PCM512x_SREF);
-       } else {
+       if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       if (!IS_ERR(pcm512x->sclk)) {
                ret = clk_prepare_enable(pcm512x->sclk);
                if (ret != 0) {
                        dev_err(dev, "Failed to enable SCLK: %d\n", ret);
@@ -483,6 +1344,43 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
        pm_runtime_enable(dev);
        pm_runtime_idle(dev);
 
+#ifdef CONFIG_OF
+       if (dev->of_node) {
+               const struct device_node *np = dev->of_node;
+               u32 val;
+
+               if (of_property_read_u32(np, "pll-in", &val) >= 0) {
+                       if (val > 6) {
+                               dev_err(dev, "Invalid pll-in\n");
+                               ret = -EINVAL;
+                               goto err_clk;
+                       }
+                       pcm512x->pll_in = val;
+               }
+
+               if (of_property_read_u32(np, "pll-out", &val) >= 0) {
+                       if (val > 6) {
+                               dev_err(dev, "Invalid pll-out\n");
+                               ret = -EINVAL;
+                               goto err_clk;
+                       }
+                       pcm512x->pll_out = val;
+               }
+
+               if (!pcm512x->pll_in != !pcm512x->pll_out) {
+                       dev_err(dev,
+                               "Error: both pll-in and pll-out, or none\n");
+                       ret = -EINVAL;
+                       goto err_clk;
+               }
+               if (pcm512x->pll_in && pcm512x->pll_in == pcm512x->pll_out) {
+                       dev_err(dev, "Error: pll-in == pll-out\n");
+                       ret = -EINVAL;
+                       goto err_clk;
+               }
+       }
+#endif
+
        ret = snd_soc_register_codec(dev, &pcm512x_codec_driver,
                                    &pcm512x_dai, 1);
        if (ret != 0) {
index 6ee76aaca09a0a5ebca6fde6b885e7d10cb558b0..b7c3102072232336feedc6e9af7dc5e14bfffdb6 100644 (file)
 #define PCM512x_DSP_GPIO_INPUT    (PCM512x_PAGE_BASE(0) +  10)
 #define PCM512x_MASTER_MODE       (PCM512x_PAGE_BASE(0) +  12)
 #define PCM512x_PLL_REF           (PCM512x_PAGE_BASE(0) +  13)
+#define PCM512x_DAC_REF           (PCM512x_PAGE_BASE(0) +  14)
+#define PCM512x_GPIO_DACIN        (PCM512x_PAGE_BASE(0) +  16)
+#define PCM512x_GPIO_PLLIN        (PCM512x_PAGE_BASE(0) +  18)
+#define PCM512x_SYNCHRONIZE       (PCM512x_PAGE_BASE(0) +  19)
 #define PCM512x_PLL_COEFF_0       (PCM512x_PAGE_BASE(0) +  20)
 #define PCM512x_PLL_COEFF_1       (PCM512x_PAGE_BASE(0) +  21)
 #define PCM512x_PLL_COEFF_2       (PCM512x_PAGE_BASE(0) +  22)
@@ -77,6 +81,7 @@
 #define PCM512x_RATE_DET_2        (PCM512x_PAGE_BASE(0) +  92)
 #define PCM512x_RATE_DET_3        (PCM512x_PAGE_BASE(0) +  93)
 #define PCM512x_RATE_DET_4        (PCM512x_PAGE_BASE(0) +  94)
+#define PCM512x_CLOCK_STATUS      (PCM512x_PAGE_BASE(0) +  95)
 #define PCM512x_ANALOG_MUTE_DET   (PCM512x_PAGE_BASE(0) + 108)
 #define PCM512x_GPIN              (PCM512x_PAGE_BASE(0) + 119)
 #define PCM512x_DIGITAL_MUTE_DET  (PCM512x_PAGE_BASE(0) + 120)
 
 #define PCM512x_CRAM_CTRL         (PCM512x_PAGE_BASE(44) +  1)
 
-#define PCM512x_MAX_REGISTER      (PCM512x_PAGE_BASE(44) +  1)
+#define PCM512x_FLEX_A            (PCM512x_PAGE_BASE(253) + 63)
+#define PCM512x_FLEX_B            (PCM512x_PAGE_BASE(253) + 64)
+
+#define PCM512x_MAX_REGISTER      (PCM512x_PAGE_BASE(253) + 64)
 
 /* Page 0, Register 1 - reset */
 #define PCM512x_RSTR (1 << 0)
 #define PCM512x_RQML_SHIFT 4
 
 /* Page 0, Register 4 - PLL */
-#define PCM512x_PLCE       (1 << 0)
-#define PCM512x_RLCE_SHIFT 0
+#define PCM512x_PLLE       (1 << 0)
+#define PCM512x_PLLE_SHIFT 0
 #define PCM512x_PLCK       (1 << 4)
 #define PCM512x_PLCK_SHIFT 4
 
 #define PCM512x_DEMP       (1 << 4)
 #define PCM512x_DEMP_SHIFT 4
 
+/* Page 0, Register 8 - GPIO output enable */
+#define PCM512x_G1OE       (1 << 0)
+#define PCM512x_G2OE       (1 << 1)
+#define PCM512x_G3OE       (1 << 2)
+#define PCM512x_G4OE       (1 << 3)
+#define PCM512x_G5OE       (1 << 4)
+#define PCM512x_G6OE       (1 << 5)
+
+/* Page 0, Register 9 - BCK, LRCLK configuration */
+#define PCM512x_LRKO       (1 << 0)
+#define PCM512x_LRKO_SHIFT 0
+#define PCM512x_BCKO       (1 << 4)
+#define PCM512x_BCKO_SHIFT 4
+#define PCM512x_BCKP       (1 << 5)
+#define PCM512x_BCKP_SHIFT 5
+
+/* Page 0, Register 12 - Master mode BCK, LRCLK reset */
+#define PCM512x_RLRK       (1 << 0)
+#define PCM512x_RLRK_SHIFT 0
+#define PCM512x_RBCK       (1 << 1)
+#define PCM512x_RBCK_SHIFT 1
+
 /* Page 0, Register 13 - PLL reference */
-#define PCM512x_SREF (1 << 4)
+#define PCM512x_SREF        (7 << 4)
+#define PCM512x_SREF_SHIFT  4
+#define PCM512x_SREF_SCK    (0 << 4)
+#define PCM512x_SREF_BCK    (1 << 4)
+#define PCM512x_SREF_GPIO   (3 << 4)
+
+/* Page 0, Register 14 - DAC reference */
+#define PCM512x_SDAC        (7 << 4)
+#define PCM512x_SDAC_SHIFT  4
+#define PCM512x_SDAC_MCK    (0 << 4)
+#define PCM512x_SDAC_PLL    (1 << 4)
+#define PCM512x_SDAC_SCK    (3 << 4)
+#define PCM512x_SDAC_BCK    (4 << 4)
+#define PCM512x_SDAC_GPIO   (5 << 4)
+
+/* Page 0, Register 16, 18 - GPIO source for DAC, PLL */
+#define PCM512x_GREF        (7 << 0)
+#define PCM512x_GREF_SHIFT  0
+#define PCM512x_GREF_GPIO1  (0 << 0)
+#define PCM512x_GREF_GPIO2  (1 << 0)
+#define PCM512x_GREF_GPIO3  (2 << 0)
+#define PCM512x_GREF_GPIO4  (3 << 0)
+#define PCM512x_GREF_GPIO5  (4 << 0)
+#define PCM512x_GREF_GPIO6  (5 << 0)
+
+/* Page 0, Register 19 - synchronize */
+#define PCM512x_RQSY        (1 << 0)
+#define PCM512x_RQSY_RESUME (0 << 0)
+#define PCM512x_RQSY_HALT   (1 << 0)
+
+/* Page 0, Register 34 - fs speed mode */
+#define PCM512x_FSSP        (3 << 0)
+#define PCM512x_FSSP_SHIFT  0
+#define PCM512x_FSSP_48KHZ  (0 << 0)
+#define PCM512x_FSSP_96KHZ  (1 << 0)
+#define PCM512x_FSSP_192KHZ (2 << 0)
+#define PCM512x_FSSP_384KHZ (3 << 0)
 
 /* Page 0, Register 37 - Error detection */
 #define PCM512x_IPLK (1 << 0)
 #define PCM512x_IDBK (1 << 5)
 #define PCM512x_IDFS (1 << 6)
 
+/* Page 0, Register 40 - I2S configuration */
+#define PCM512x_ALEN       (3 << 0)
+#define PCM512x_ALEN_SHIFT 0
+#define PCM512x_ALEN_16    (0 << 0)
+#define PCM512x_ALEN_20    (1 << 0)
+#define PCM512x_ALEN_24    (2 << 0)
+#define PCM512x_ALEN_32    (3 << 0)
+#define PCM512x_AFMT       (3 << 4)
+#define PCM512x_AFMT_SHIFT 4
+#define PCM512x_AFMT_I2S   (0 << 4)
+#define PCM512x_AFMT_DSP   (1 << 4)
+#define PCM512x_AFMT_RTJ   (2 << 4)
+#define PCM512x_AFMT_LTJ   (3 << 4)
+
 /* Page 0, Register 42 - DAC routing */
 #define PCM512x_AUPR_SHIFT 0
 #define PCM512x_AUPL_SHIFT 4
 /* Page 0, Register 65 - Digital mute enables */
 #define PCM512x_ACTL_SHIFT 2
 #define PCM512x_AMLE_SHIFT 1
-#define PCM512x_AMLR_SHIFT 0
+#define PCM512x_AMRE_SHIFT 0
+
+/* Page 0, Register 80-85, GPIO output selection */
+#define PCM512x_GxSL       (31 << 0)
+#define PCM512x_GxSL_SHIFT 0
+#define PCM512x_GxSL_OFF   (0 << 0)
+#define PCM512x_GxSL_DSP   (1 << 0)
+#define PCM512x_GxSL_REG   (2 << 0)
+#define PCM512x_GxSL_AMUTB (3 << 0)
+#define PCM512x_GxSL_AMUTL (4 << 0)
+#define PCM512x_GxSL_AMUTR (5 << 0)
+#define PCM512x_GxSL_CLKI  (6 << 0)
+#define PCM512x_GxSL_SDOUT (7 << 0)
+#define PCM512x_GxSL_ANMUL (8 << 0)
+#define PCM512x_GxSL_ANMUR (9 << 0)
+#define PCM512x_GxSL_PLLLK (10 << 0)
+#define PCM512x_GxSL_CPCLK (11 << 0)
+#define PCM512x_GxSL_UV0_7 (14 << 0)
+#define PCM512x_GxSL_UV0_3 (15 << 0)
+#define PCM512x_GxSL_PLLCK (16 << 0)
 
 /* Page 1, Register 2 - analog volume control */
 #define PCM512x_RAGN_SHIFT 0
index 1d1c7f8a9af27329a10dacf22c8752093dba91f8..f374840a5a7ce376272d8f7e3290f91c099cb19f 100644 (file)
@@ -34,6 +34,7 @@
 #include "rt286.h"
 
 #define RT286_VENDOR_ID 0x10ec0286
+#define RT288_VENDOR_ID 0x10ec0288
 
 struct rt286_priv {
        struct regmap *regmap;
@@ -305,6 +306,8 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
        *hp = false;
        *mic = false;
 
+       if (!rt286->codec)
+               return -EINVAL;
        if (rt286->pdata.cbj_en) {
                regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf);
                *hp = buf & 0x80000000;
@@ -403,7 +406,8 @@ EXPORT_SYMBOL_GPL(rt286_mic_detect);
 static int is_mclk_mode(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
-       struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(source->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+       struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
 
        if (rt286->clk_id == RT286_SCLK_S_MCLK)
                return 1;
@@ -417,6 +421,8 @@ static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
 static const struct snd_kcontrol_new rt286_snd_controls[] = {
        SOC_DOUBLE_R_TLV("DAC0 Playback Volume", RT286_DACL_GAIN,
                            RT286_DACR_GAIN, 0, 0x7f, 0, out_vol_tlv),
+       SOC_DOUBLE_R("ADC0 Capture Switch", RT286_ADCL_GAIN,
+                           RT286_ADCR_GAIN, 7, 1, 1),
        SOC_DOUBLE_R_TLV("ADC0 Capture Volume", RT286_ADCL_GAIN,
                            RT286_ADCR_GAIN, 0, 0x7f, 0, out_vol_tlv),
        SOC_SINGLE_TLV("AMIC Volume", RT286_MIC_GAIN,
@@ -500,7 +506,7 @@ SOC_DAPM_ENUM("SPO source", rt286_spo_enum);
 static int rt286_spk_event(struct snd_soc_dapm_widget *w,
                            struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -522,7 +528,7 @@ static int rt286_spk_event(struct snd_soc_dapm_widget *w,
 static int rt286_set_dmic1_event(struct snd_soc_dapm_widget *w,
                                  struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -538,36 +544,10 @@ static int rt286_set_dmic1_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
-static int rt286_adc_event(struct snd_soc_dapm_widget *w,
-                            struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_codec *codec = w->codec;
-       unsigned int nid;
-
-       nid = (w->reg >> 20) & 0xff;
-
-       switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
-               snd_soc_update_bits(codec,
-                       VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0),
-                       0x7080, 0x7000);
-               break;
-       case SND_SOC_DAPM_PRE_PMD:
-               snd_soc_update_bits(codec,
-                       VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0),
-                       0x7080, 0x7080);
-               break;
-       default:
-               return 0;
-       }
-
-       return 0;
-}
-
 static int rt286_vref_event(struct snd_soc_dapm_widget *w,
                             struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
@@ -585,7 +565,7 @@ static int rt286_vref_event(struct snd_soc_dapm_widget *w,
 static int rt286_ldo2_event(struct snd_soc_dapm_widget *w,
                             struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -604,7 +584,7 @@ static int rt286_ldo2_event(struct snd_soc_dapm_widget *w,
 static int rt286_mic1_event(struct snd_soc_dapm_widget *w,
                             struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
@@ -667,12 +647,10 @@ static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = {
        SND_SOC_DAPM_ADC("ADC 1", NULL, SND_SOC_NOPM, 0, 0),
 
        /* ADC Mux */
-       SND_SOC_DAPM_MUX_E("ADC 0 Mux", RT286_SET_POWER(RT286_ADC_IN1), 0, 1,
-               &rt286_adc0_mux, rt286_adc_event, SND_SOC_DAPM_PRE_PMD |
-               SND_SOC_DAPM_POST_PMU),
-       SND_SOC_DAPM_MUX_E("ADC 1 Mux", RT286_SET_POWER(RT286_ADC_IN2), 0, 1,
-               &rt286_adc1_mux, rt286_adc_event, SND_SOC_DAPM_PRE_PMD |
-               SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_MUX("ADC 0 Mux", RT286_SET_POWER(RT286_ADC_IN1), 0, 1,
+               &rt286_adc0_mux),
+       SND_SOC_DAPM_MUX("ADC 1 Mux", RT286_SET_POWER(RT286_ADC_IN2), 0, 1,
+               &rt286_adc1_mux),
 
        /* Audio Interface */
        SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
@@ -1194,6 +1172,7 @@ static const struct regmap_config rt286_regmap = {
 
 static const struct i2c_device_id rt286_i2c_id[] = {
        {"rt286", 0},
+       {"rt288", 0},
        {}
 };
 MODULE_DEVICE_TABLE(i2c, rt286_i2c_id);
@@ -1214,6 +1193,17 @@ static struct dmi_system_id force_combo_jack_table[] = {
        { }
 };
 
+static struct dmi_system_id dmi_dell_dino[] = {
+       {
+               .ident = "Dell Dino",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_BOARD_NAME, "0144P8")
+               }
+       },
+       { }
+};
+
 static int rt286_i2c_probe(struct i2c_client *i2c,
                           const struct i2c_device_id *id)
 {
@@ -1236,7 +1226,7 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
 
        regmap_read(rt286->regmap,
                RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &ret);
-       if (ret != RT286_VENDOR_ID) {
+       if (ret != RT286_VENDOR_ID && ret != RT288_VENDOR_ID) {
                dev_err(&i2c->dev,
                        "Device with ID register %x is not rt286\n", ret);
                return -ENODEV;
@@ -1249,7 +1239,8 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
        if (pdata)
                rt286->pdata = *pdata;
 
-       if (dmi_check_system(force_combo_jack_table))
+       if (dmi_check_system(force_combo_jack_table) ||
+               dmi_check_system(dmi_dell_dino))
                rt286->pdata.cbj_en = true;
 
        regmap_write(rt286->regmap, RT286_SET_AUDIO_POWER, AC_PWRST_D3);
@@ -1288,6 +1279,17 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
        regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL3, 0xf777, 0x4737);
        regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f);
 
+       if (dmi_check_system(dmi_dell_dino)) {
+               regmap_update_bits(rt286->regmap,
+                       RT286_SET_GPIO_MASK, 0x40, 0x40);
+               regmap_update_bits(rt286->regmap,
+                       RT286_SET_GPIO_DIRECTION, 0x40, 0x40);
+               regmap_update_bits(rt286->regmap,
+                       RT286_SET_GPIO_DATA, 0x40, 0x40);
+               regmap_update_bits(rt286->regmap,
+                       RT286_GPIO_CTRL, 0xc, 0x8);
+       }
+
        if (rt286->i2c->irq) {
                ret = request_threaded_irq(rt286->i2c->irq, NULL, rt286_irq,
                        IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt286", rt286);
index b539b7320a79074605fb51b42a3e0a2507dcfc53..7130edb152efb42db071bcb9ca706d59c894e61e 100644 (file)
        VERB_CMD(AC_VERB_SET_COEF_INDEX, RT286_VENDOR_REGISTERS, 0)
 #define RT286_PROC_COEF\
        VERB_CMD(AC_VERB_SET_PROC_COEF, RT286_VENDOR_REGISTERS, 0)
+#define RT286_SET_GPIO_MASK\
+       VERB_CMD(AC_VERB_SET_GPIO_MASK, RT286_AUDIO_FUNCTION_GROUP, 0)
+#define RT286_SET_GPIO_DIRECTION\
+       VERB_CMD(AC_VERB_SET_GPIO_DIRECTION, RT286_AUDIO_FUNCTION_GROUP, 0)
+#define RT286_SET_GPIO_DATA\
+       VERB_CMD(AC_VERB_SET_GPIO_DATA, RT286_AUDIO_FUNCTION_GROUP, 0)
 
 /* Index registers */
 #define RT286_A_BIAS_CTRL1     0x01
 #define RT286_POWER_CTRL3      0x0f
 #define RT286_MIC1_DET_CTRL    0x19
 #define RT286_MISC_CTRL1       0x20
+#define RT286_GPIO_CTRL                0x29
 #define RT286_IRQ_CTRL         0x33
 #define RT286_PLL_CTRL1                0x49
 #define RT286_CBJ_CTRL1                0x4f
index 6d7b7ca7d530f034d2e972ba8070c03280e22bd0..c61852742ee30889c3fa482135acd1960324602f 100644 (file)
@@ -287,70 +287,78 @@ static const struct snd_kcontrol_new rt5631_snd_controls[] = {
 static int check_sysclk1_source(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg;
 
-       reg = snd_soc_read(source->codec, RT5631_GLOBAL_CLK_CTRL);
+       reg = snd_soc_read(codec, RT5631_GLOBAL_CLK_CTRL);
        return reg & RT5631_SYSCLK_SOUR_SEL_PLL;
 }
 
 static int check_dmic_used(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
-       struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(source->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+       struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
        return rt5631->dmic_used_flag;
 }
 
 static int check_dacl_to_outmixl(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg;
 
-       reg = snd_soc_read(source->codec, RT5631_OUTMIXER_L_CTRL);
+       reg = snd_soc_read(codec, RT5631_OUTMIXER_L_CTRL);
        return !(reg & RT5631_M_DAC_L_TO_OUTMIXER_L);
 }
 
 static int check_dacr_to_outmixr(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg;
 
-       reg = snd_soc_read(source->codec, RT5631_OUTMIXER_R_CTRL);
+       reg = snd_soc_read(codec, RT5631_OUTMIXER_R_CTRL);
        return !(reg & RT5631_M_DAC_R_TO_OUTMIXER_R);
 }
 
 static int check_dacl_to_spkmixl(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg;
 
-       reg = snd_soc_read(source->codec, RT5631_SPK_MIXER_CTRL);
+       reg = snd_soc_read(codec, RT5631_SPK_MIXER_CTRL);
        return !(reg & RT5631_M_DAC_L_TO_SPKMIXER_L);
 }
 
 static int check_dacr_to_spkmixr(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg;
 
-       reg = snd_soc_read(source->codec, RT5631_SPK_MIXER_CTRL);
+       reg = snd_soc_read(codec, RT5631_SPK_MIXER_CTRL);
        return !(reg & RT5631_M_DAC_R_TO_SPKMIXER_R);
 }
 
 static int check_adcl_select(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg;
 
-       reg = snd_soc_read(source->codec, RT5631_ADC_REC_MIXER);
+       reg = snd_soc_read(codec, RT5631_ADC_REC_MIXER);
        return !(reg & RT5631_M_MIC1_TO_RECMIXER_L);
 }
 
 static int check_adcr_select(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg;
 
-       reg = snd_soc_read(source->codec, RT5631_ADC_REC_MIXER);
+       reg = snd_soc_read(codec, RT5631_ADC_REC_MIXER);
        return !(reg & RT5631_M_MIC2_TO_RECMIXER_R);
 }
 
@@ -556,7 +564,7 @@ static void depop_seq_mute_stage(struct snd_soc_codec *codec, int enable)
 static int hp_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -590,7 +598,7 @@ static int hp_event(struct snd_soc_dapm_widget *w,
 static int set_dmic_params(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
 
        switch (rt5631->rx_rate) {
index 1ff726c292491eaf14f09ad235e779b65bca0041..178e55d4d48146b9bfee3a211bd297f67a822790 100644 (file)
@@ -458,7 +458,7 @@ static const struct snd_kcontrol_new rt5640_specific_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
        int idx = -EINVAL;
 
@@ -475,9 +475,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int val;
 
-       val = snd_soc_read(source->codec, RT5640_GLB_CLK);
+       val = snd_soc_read(codec, RT5640_GLB_CLK);
        val &= RT5640_SCLK_SRC_MASK;
        if (val == RT5640_SCLK_SRC_PLL1)
                return 1;
@@ -963,7 +964,7 @@ static void rt5640_pmu_depop(struct snd_soc_codec *codec)
 static int rt5640_hp_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -987,7 +988,7 @@ static int rt5640_hp_event(struct snd_soc_dapm_widget *w,
 static int rt5640_hp_power_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -1003,7 +1004,7 @@ static int rt5640_hp_power_event(struct snd_soc_dapm_widget *w,
 static int rt5640_hp_post_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
index 27141e2df878a65204fc31cc9486fb099319bd26..c9a4c5be083b454230c1a0d9bf0424fd8c279056 100644 (file)
@@ -31,6 +31,7 @@
 #include "rt5645.h"
 
 #define RT5645_DEVICE_ID 0x6308
+#define RT5650_DEVICE_ID 0x6419
 
 #define RT5645_PR_RANGE_BASE (0xff + 1)
 #define RT5645_PR_SPACING 0x100
@@ -59,6 +60,10 @@ static const struct reg_default init_list[] = {
 };
 #define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list)
 
+static const struct reg_default rt5650_init_list[] = {
+       {0xf6,  0x0100},
+};
+
 static const struct reg_default rt5645_reg[] = {
        { 0x00, 0x0000 },
        { 0x01, 0xc8c8 },
@@ -86,6 +91,7 @@ static const struct reg_default rt5645_reg[] = {
        { 0x2a, 0x5656 },
        { 0x2b, 0x5454 },
        { 0x2c, 0xaaa0 },
+       { 0x2d, 0x0000 },
        { 0x2f, 0x1002 },
        { 0x31, 0x5000 },
        { 0x32, 0x0000 },
@@ -193,6 +199,8 @@ static const struct reg_default rt5645_reg[] = {
        { 0xdb, 0x0003 },
        { 0xdc, 0x0049 },
        { 0xdd, 0x001b },
+       { 0xdf, 0x0008 },
+       { 0xe0, 0x4000 },
        { 0xe6, 0x8000 },
        { 0xe7, 0x0200 },
        { 0xec, 0xb300 },
@@ -242,6 +250,7 @@ static bool rt5645_volatile_register(struct device *dev, unsigned int reg)
        case RT5645_IRQ_CTRL3:
        case RT5645_INT_IRQ_ST:
        case RT5645_IL_CMD:
+       case RT5650_4BTN_IL_CMD1:
        case RT5645_VENDOR_ID:
        case RT5645_VENDOR_ID1:
        case RT5645_VENDOR_ID2:
@@ -287,6 +296,7 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg)
        case RT5645_STO_DAC_MIXER:
        case RT5645_MONO_DAC_MIXER:
        case RT5645_DIG_MIXER:
+       case RT5650_A_DAC_SOUR:
        case RT5645_DIG_INF1_DATA:
        case RT5645_PDM_OUT_CTRL:
        case RT5645_REC_L1_MIXER:
@@ -378,6 +388,8 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg)
        case RT5645_IL_CMD:
        case RT5645_IL_CMD2:
        case RT5645_IL_CMD3:
+       case RT5650_4BTN_IL_CMD1:
+       case RT5650_4BTN_IL_CMD2:
        case RT5645_DRC1_HL_CTRL1:
        case RT5645_DRC2_HL_CTRL1:
        case RT5645_ADC_MONO_HP_CTRL1:
@@ -527,7 +539,7 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
        int idx = -EINVAL;
 
@@ -544,9 +556,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int val;
 
-       val = snd_soc_read(source->codec, RT5645_GLB_CLK);
+       val = snd_soc_read(codec, RT5645_GLB_CLK);
        val &= RT5645_SCLK_SRC_MASK;
        if (val == RT5645_SCLK_SRC_PLL1)
                return 1;
@@ -557,6 +570,7 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 static int is_using_asrc(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg, shift, val;
 
        switch (source->shift) {
@@ -588,7 +602,7 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
                return 0;
        }
 
-       val = (snd_soc_read(source->codec, reg) >> shift) & 0xf;
+       val = (snd_soc_read(codec, reg) >> shift) & 0xf;
        switch (val) {
        case 1:
        case 2:
@@ -601,6 +615,87 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
 
 }
 
+/**
+ * rt5645_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @codec: SoC audio codec device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5645 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the codec driver will turn on ASRC
+ * for these filters if ASRC is selected as their clock source.
+ */
+int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec,
+               unsigned int filter_mask, unsigned int clk_src)
+{
+       unsigned int asrc2_mask = 0;
+       unsigned int asrc2_value = 0;
+       unsigned int asrc3_mask = 0;
+       unsigned int asrc3_value = 0;
+
+       switch (clk_src) {
+       case RT5645_CLK_SEL_SYS:
+       case RT5645_CLK_SEL_I2S1_ASRC:
+       case RT5645_CLK_SEL_I2S2_ASRC:
+       case RT5645_CLK_SEL_SYS2:
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       if (filter_mask & RT5645_DA_STEREO_FILTER) {
+               asrc2_mask |= RT5645_DA_STO_CLK_SEL_MASK;
+               asrc2_value = (asrc2_value & ~RT5645_DA_STO_CLK_SEL_MASK)
+                       | (clk_src << RT5645_DA_STO_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5645_DA_MONO_L_FILTER) {
+               asrc2_mask |= RT5645_DA_MONOL_CLK_SEL_MASK;
+               asrc2_value = (asrc2_value & ~RT5645_DA_MONOL_CLK_SEL_MASK)
+                       | (clk_src << RT5645_DA_MONOL_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5645_DA_MONO_R_FILTER) {
+               asrc2_mask |= RT5645_DA_MONOR_CLK_SEL_MASK;
+               asrc2_value = (asrc2_value & ~RT5645_DA_MONOR_CLK_SEL_MASK)
+                       | (clk_src << RT5645_DA_MONOR_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5645_AD_STEREO_FILTER) {
+               asrc2_mask |= RT5645_AD_STO1_CLK_SEL_MASK;
+               asrc2_value = (asrc2_value & ~RT5645_AD_STO1_CLK_SEL_MASK)
+                       | (clk_src << RT5645_AD_STO1_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5645_AD_MONO_L_FILTER) {
+               asrc3_mask |= RT5645_AD_MONOL_CLK_SEL_MASK;
+               asrc3_value = (asrc3_value & ~RT5645_AD_MONOL_CLK_SEL_MASK)
+                       | (clk_src << RT5645_AD_MONOL_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5645_AD_MONO_R_FILTER)  {
+               asrc3_mask |= RT5645_AD_MONOR_CLK_SEL_MASK;
+               asrc3_value = (asrc3_value & ~RT5645_AD_MONOR_CLK_SEL_MASK)
+                       | (clk_src << RT5645_AD_MONOR_CLK_SEL_SFT);
+       }
+
+       if (asrc2_mask)
+               snd_soc_update_bits(codec, RT5645_ASRC_2,
+                       asrc2_mask, asrc2_value);
+
+       if (asrc3_mask)
+               snd_soc_update_bits(codec, RT5645_ASRC_3,
+                       asrc3_mask, asrc3_value);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rt5645_sel_asrc_clk_src);
+
 /* Digital Mixer */
 static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = {
        SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER,
@@ -1007,6 +1102,44 @@ static SOC_ENUM_SINGLE_DECL(
 static const struct snd_kcontrol_new rt5645_if1_adc_in_mux =
        SOC_DAPM_ENUM("IF1 ADC IN source", rt5645_if1_adc_in_enum);
 
+/* MX-2d [3] [2] */
+static const char * const rt5650_a_dac1_src[] = {
+       "DAC1", "Stereo DAC Mixer"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5650_a_dac1_l_enum, RT5650_A_DAC_SOUR,
+       RT5650_A_DAC1_L_IN_SFT, rt5650_a_dac1_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac1_l_mux =
+       SOC_DAPM_ENUM("A DAC1 L source", rt5650_a_dac1_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5650_a_dac1_r_enum, RT5650_A_DAC_SOUR,
+       RT5650_A_DAC1_R_IN_SFT, rt5650_a_dac1_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac1_r_mux =
+       SOC_DAPM_ENUM("A DAC1 R source", rt5650_a_dac1_r_enum);
+
+/* MX-2d [1] [0] */
+static const char * const rt5650_a_dac2_src[] = {
+       "Stereo DAC Mixer", "Mono DAC Mixer"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5650_a_dac2_l_enum, RT5650_A_DAC_SOUR,
+       RT5650_A_DAC2_L_IN_SFT, rt5650_a_dac2_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac2_l_mux =
+       SOC_DAPM_ENUM("A DAC2 L source", rt5650_a_dac2_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5650_a_dac2_r_enum, RT5650_A_DAC_SOUR,
+       RT5650_A_DAC2_R_IN_SFT, rt5650_a_dac2_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac2_r_mux =
+       SOC_DAPM_ENUM("A DAC2 R source", rt5650_a_dac2_r_enum);
+
 /* MX-2F [13:12] */
 static const char * const rt5645_if2_adc_in_src[] = {
        "IF_ADC1", "IF_ADC2", "VAD_ADC"
@@ -1144,18 +1277,23 @@ static void hp_amp_power(struct snd_soc_codec *codec, int on)
 static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                hp_amp_power(codec, 1);
                /* headphone unmute sequence */
-               snd_soc_update_bits(codec, RT5645_DEPOP_M3, RT5645_CP_FQ1_MASK |
-                       RT5645_CP_FQ2_MASK | RT5645_CP_FQ3_MASK,
-                       (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) |
-                       (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
-                       (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT));
+               if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+                       snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
+               } else {
+                       snd_soc_update_bits(codec, RT5645_DEPOP_M3,
+                               RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
+                               RT5645_CP_FQ3_MASK,
+                               (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) |
+                               (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
+                               (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT));
+               }
                regmap_write(rt5645->regmap,
                        RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00);
                snd_soc_update_bits(codec, RT5645_DEPOP_M1,
@@ -1175,12 +1313,16 @@ static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
 
        case SND_SOC_DAPM_PRE_PMD:
                /* headphone mute sequence */
-               snd_soc_update_bits(codec, RT5645_DEPOP_M3,
-                       RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
-                       RT5645_CP_FQ3_MASK,
-                       (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) |
-                       (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
-                       (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT));
+               if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+                       snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
+               } else {
+                       snd_soc_update_bits(codec, RT5645_DEPOP_M3,
+                               RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
+                               RT5645_CP_FQ3_MASK,
+                               (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) |
+                               (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
+                               (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT));
+               }
                regmap_write(rt5645->regmap,
                        RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00);
                snd_soc_update_bits(codec, RT5645_DEPOP_M1,
@@ -1205,7 +1347,7 @@ static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
 static int rt5645_spk_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -1232,7 +1374,7 @@ static int rt5645_spk_event(struct snd_soc_dapm_widget *w,
 static int rt5645_lout_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -1262,7 +1404,7 @@ static int rt5645_lout_event(struct snd_soc_dapm_widget *w,
 static int rt5645_bst2_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -1574,6 +1716,17 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
        SND_SOC_DAPM_OUTPUT("SPOR"),
 };
 
+static const struct snd_soc_dapm_widget rt5650_specific_dapm_widgets[] = {
+       SND_SOC_DAPM_MUX("A DAC1 L Mux", SND_SOC_NOPM,
+               0, 0, &rt5650_a_dac1_l_mux),
+       SND_SOC_DAPM_MUX("A DAC1 R Mux", SND_SOC_NOPM,
+               0, 0, &rt5650_a_dac1_r_mux),
+       SND_SOC_DAPM_MUX("A DAC2 L Mux", SND_SOC_NOPM,
+               0, 0, &rt5650_a_dac2_l_mux),
+       SND_SOC_DAPM_MUX("A DAC2 R Mux", SND_SOC_NOPM,
+               0, 0, &rt5650_a_dac2_r_mux),
+};
+
 static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
        { "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc },
        { "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc },
@@ -1779,13 +1932,9 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
        { "DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" },
        { "DAC MIXR", "DAC L2 Switch", "DAC L2 Volume" },
 
-       { "DAC L1", NULL, "Stereo DAC MIXL" },
        { "DAC L1", NULL, "PLL1", is_sys_clk_from_pll },
-       { "DAC R1", NULL, "Stereo DAC MIXR" },
        { "DAC R1", NULL, "PLL1", is_sys_clk_from_pll },
-       { "DAC L2", NULL, "Mono DAC MIXL" },
        { "DAC L2", NULL, "PLL1", is_sys_clk_from_pll },
-       { "DAC R2", NULL, "Mono DAC MIXR" },
        { "DAC R2", NULL, "PLL1", is_sys_clk_from_pll },
 
        { "SPK MIXL", "BST1 Switch", "BST1" },
@@ -1874,6 +2023,30 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
        { "SPOR", NULL, "SPK amp" },
 };
 
+static const struct snd_soc_dapm_route rt5650_specific_dapm_routes[] = {
+       { "A DAC1 L Mux", "DAC1",  "DAC1 MIXL"},
+       { "A DAC1 L Mux", "Stereo DAC Mixer", "Stereo DAC MIXL"},
+       { "A DAC1 R Mux", "DAC1",  "DAC1 MIXR"},
+       { "A DAC1 R Mux", "Stereo DAC Mixer", "Stereo DAC MIXR"},
+
+       { "A DAC2 L Mux", "Stereo DAC Mixer", "Stereo DAC MIXL"},
+       { "A DAC2 L Mux", "Mono DAC Mixer", "Mono DAC MIXL"},
+       { "A DAC2 R Mux", "Stereo DAC Mixer", "Stereo DAC MIXR"},
+       { "A DAC2 R Mux", "Mono DAC Mixer", "Mono DAC MIXR"},
+
+       { "DAC L1", NULL, "A DAC1 L Mux" },
+       { "DAC R1", NULL, "A DAC1 R Mux" },
+       { "DAC L2", NULL, "A DAC2 L Mux" },
+       { "DAC R2", NULL, "A DAC2 R Mux" },
+};
+
+static const struct snd_soc_dapm_route rt5645_specific_dapm_routes[] = {
+       { "DAC L1", NULL, "Stereo DAC MIXL" },
+       { "DAC R1", NULL, "Stereo DAC MIXR" },
+       { "DAC L2", NULL, "Mono DAC MIXL" },
+       { "DAC R2", NULL, "Mono DAC MIXR" },
+};
+
 static int rt5645_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
@@ -2293,6 +2466,22 @@ static int rt5645_probe(struct snd_soc_codec *codec)
 
        rt5645->codec = codec;
 
+       switch (rt5645->codec_type) {
+       case CODEC_TYPE_RT5645:
+               snd_soc_dapm_add_routes(&codec->dapm,
+                       rt5645_specific_dapm_routes,
+                       ARRAY_SIZE(rt5645_specific_dapm_routes));
+               break;
+       case CODEC_TYPE_RT5650:
+               snd_soc_dapm_new_controls(&codec->dapm,
+                       rt5650_specific_dapm_widgets,
+                       ARRAY_SIZE(rt5650_specific_dapm_widgets));
+               snd_soc_dapm_add_routes(&codec->dapm,
+                       rt5650_specific_dapm_routes,
+                       ARRAY_SIZE(rt5650_specific_dapm_routes));
+               break;
+       }
+
        rt5645_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200);
@@ -2424,6 +2613,7 @@ static const struct regmap_config rt5645_regmap = {
 
 static const struct i2c_device_id rt5645_i2c_id[] = {
        { "rt5645", 0 },
+       { "rt5650", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id);
@@ -2456,9 +2646,18 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
        }
 
        regmap_read(rt5645->regmap, RT5645_VENDOR_ID2, &val);
-       if (val != RT5645_DEVICE_ID) {
+
+       switch (val) {
+       case RT5645_DEVICE_ID:
+               rt5645->codec_type = CODEC_TYPE_RT5645;
+               break;
+       case RT5650_DEVICE_ID:
+               rt5645->codec_type = CODEC_TYPE_RT5650;
+               break;
+       default:
                dev_err(&i2c->dev,
-                       "Device with ID register %x is not rt5645\n", val);
+                       "Device with ID register %x is not rt5645 or rt5650\n",
+                       val);
                return -ENODEV;
        }
 
@@ -2469,6 +2668,14 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
        if (ret != 0)
                dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
 
+       if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+               ret = regmap_register_patch(rt5645->regmap, rt5650_init_list,
+                                   ARRAY_SIZE(rt5650_init_list));
+               if (ret != 0)
+                       dev_warn(&i2c->dev, "Apply rt5650 patch failed: %d\n",
+                                          ret);
+       }
+
        if (rt5645->pdata.in2_diff)
                regmap_update_bits(rt5645->regmap, RT5645_IN2_CTRL,
                                        RT5645_IN_DF2, RT5645_IN_DF2);
index a815e36a2bdbcf27f2dc7e091e23d1ea28aaae75..dbfd98c22f4dea617b48b7fbbf214452421bd13e 100644 (file)
@@ -47,6 +47,7 @@
 #define RT5645_STO_DAC_MIXER                   0x2a
 #define RT5645_MONO_DAC_MIXER                  0x2b
 #define RT5645_DIG_MIXER                       0x2c
+#define RT5650_A_DAC_SOUR                      0x2d
 #define RT5645_DIG_INF1_DATA                   0x2f
 /* Mixer - PDM */
 #define RT5645_PDM_OUT_CTRL                    0x31
 #define RT5645_IL_CMD                          0xdb
 #define RT5645_IL_CMD2                         0xdc
 #define RT5645_IL_CMD3                         0xdd
+#define RT5650_4BTN_IL_CMD1                    0xdf
+#define RT5650_4BTN_IL_CMD2                    0xe0
 #define RT5645_DRC1_HL_CTRL1                   0xe7
 #define RT5645_DRC2_HL_CTRL1                   0xe9
 #define RT5645_MUTI_DRC_CTRL1                  0xea
 #define RT5645_DAC_L2_DAC_R_VOL_MASK           (0x1 << 4)
 #define RT5645_DAC_L2_DAC_R_VOL_SFT            4
 
+/* Analog DAC1/2 Input Source Control (0x2d) */
+#define RT5650_A_DAC1_L_IN_SFT                 3
+#define RT5650_A_DAC1_R_IN_SFT                 2
+#define RT5650_A_DAC2_L_IN_SFT                 1
+#define RT5650_A_DAC2_R_IN_SFT                 0
+
 /* Digital Interface Data Control (0x2f) */
 #define RT5645_IF1_ADC2_IN_SEL                 (0x1 << 15)
 #define RT5645_IF1_ADC2_IN_SFT                 15
 #define RT5645_DMIC_2_M_NOR                    (0x0 << 8)
 #define RT5645_DMIC_2_M_ASYN                   (0x1 << 8)
 
+/* ASRC clock source selection (0x84, 0x85) */
+#define RT5645_CLK_SEL_SYS                     (0x0)
+#define RT5645_CLK_SEL_I2S1_ASRC               (0x1)
+#define RT5645_CLK_SEL_I2S2_ASRC               (0x2)
+#define RT5645_CLK_SEL_SYS2                    (0x5)
+
 /* ASRC Control 2 (0x84) */
-#define RT5645_MDA_L_M_MASK                    (0x1 << 15)
-#define RT5645_MDA_L_M_SFT                     15
-#define RT5645_MDA_L_M_NOR                     (0x0 << 15)
-#define RT5645_MDA_L_M_ASYN                    (0x1 << 15)
-#define RT5645_MDA_R_M_MASK                    (0x1 << 14)
-#define RT5645_MDA_R_M_SFT                     14
-#define RT5645_MDA_R_M_NOR                     (0x0 << 14)
-#define RT5645_MDA_R_M_ASYN                    (0x1 << 14)
-#define RT5645_MAD_L_M_MASK                    (0x1 << 13)
-#define RT5645_MAD_L_M_SFT                     13
-#define RT5645_MAD_L_M_NOR                     (0x0 << 13)
-#define RT5645_MAD_L_M_ASYN                    (0x1 << 13)
-#define RT5645_MAD_R_M_MASK                    (0x1 << 12)
-#define RT5645_MAD_R_M_SFT                     12
-#define RT5645_MAD_R_M_NOR                     (0x0 << 12)
-#define RT5645_MAD_R_M_ASYN                    (0x1 << 12)
-#define RT5645_ADC_M_MASK                      (0x1 << 11)
-#define RT5645_ADC_M_SFT                       11
-#define RT5645_ADC_M_NOR                       (0x0 << 11)
-#define RT5645_ADC_M_ASYN                      (0x1 << 11)
-#define RT5645_STO_DAC_M_MASK                  (0x1 << 5)
-#define RT5645_STO_DAC_M_SFT                   5
-#define RT5645_STO_DAC_M_NOR                   (0x0 << 5)
-#define RT5645_STO_DAC_M_ASYN                  (0x1 << 5)
-#define RT5645_I2S1_R_D_MASK                   (0x1 << 4)
-#define RT5645_I2S1_R_D_SFT                    4
-#define RT5645_I2S1_R_D_DIS                    (0x0 << 4)
-#define RT5645_I2S1_R_D_EN                     (0x1 << 4)
-#define RT5645_I2S2_R_D_MASK                   (0x1 << 3)
-#define RT5645_I2S2_R_D_SFT                    3
-#define RT5645_I2S2_R_D_DIS                    (0x0 << 3)
-#define RT5645_I2S2_R_D_EN                     (0x1 << 3)
-#define RT5645_PRE_SCLK_MASK                   (0x3)
-#define RT5645_PRE_SCLK_SFT                    0
-#define RT5645_PRE_SCLK_512                    (0x0)
-#define RT5645_PRE_SCLK_1024                   (0x1)
-#define RT5645_PRE_SCLK_2048                   (0x2)
+#define RT5645_DA_STO_CLK_SEL_MASK             (0xf << 12)
+#define RT5645_DA_STO_CLK_SEL_SFT              12
+#define RT5645_DA_MONOL_CLK_SEL_MASK           (0xf << 8)
+#define RT5645_DA_MONOL_CLK_SEL_SFT            8
+#define RT5645_DA_MONOR_CLK_SEL_MASK           (0xf << 4)
+#define RT5645_DA_MONOR_CLK_SEL_SFT            4
+#define RT5645_AD_STO1_CLK_SEL_MASK            (0xf << 0)
+#define RT5645_AD_STO1_CLK_SEL_SFT             0
 
 /* ASRC Control 3 (0x85) */
-#define RT5645_I2S1_RATE_MASK                  (0xf << 12)
-#define RT5645_I2S1_RATE_SFT                   12
-#define RT5645_I2S2_RATE_MASK                  (0xf << 8)
-#define RT5645_I2S2_RATE_SFT                   8
+#define RT5645_AD_MONOL_CLK_SEL_MASK           (0xf << 4)
+#define RT5645_AD_MONOL_CLK_SEL_SFT            4
+#define RT5645_AD_MONOR_CLK_SEL_MASK           (0xf << 0)
+#define RT5645_AD_MONOR_CLK_SEL_SFT            0
 
 /* ASRC Control 4 (0x89) */
 #define RT5645_I2S1_PD_MASK                    (0x7 << 12)
@@ -2175,6 +2161,24 @@ enum {
        RT5645_DMIC_DATA_GPIO11,
 };
 
+enum {
+       CODEC_TYPE_RT5645,
+       CODEC_TYPE_RT5650,
+};
+
+/* filter mask */
+enum {
+       RT5645_DA_STEREO_FILTER = 0x1,
+       RT5645_DA_MONO_L_FILTER = (0x1 << 1),
+       RT5645_DA_MONO_R_FILTER = (0x1 << 2),
+       RT5645_AD_STEREO_FILTER = (0x1 << 3),
+       RT5645_AD_MONO_L_FILTER = (0x1 << 4),
+       RT5645_AD_MONO_R_FILTER = (0x1 << 5),
+};
+
+int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec,
+               unsigned int filter_mask, unsigned int clk_src);
+
 struct rt5645_priv {
        struct snd_soc_codec *codec;
        struct rt5645_platform_data pdata;
@@ -2184,6 +2188,7 @@ struct rt5645_priv {
        struct snd_soc_jack *mic_jack;
        struct delayed_work jack_detect_work;
 
+       int codec_type;
        int sysclk;
        int sysclk_src;
        int lrck[RT5645_AIFS];
index bb0a3ab5416cb2fe9fbc4e79c40e31340b374935..9f4c7be6d798691c70b953c65751904b68c66db1 100644 (file)
@@ -376,7 +376,7 @@ static const struct snd_kcontrol_new rt5651_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
        int idx = -EINVAL;
 
@@ -394,9 +394,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int is_sysclk_from_pll(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int val;
 
-       val = snd_soc_read(source->codec, RT5651_GLB_CLK);
+       val = snd_soc_read(codec, RT5651_GLB_CLK);
        val &= RT5651_SCLK_SRC_MASK;
        if (val == RT5651_SCLK_SRC_PLL1)
                return 1;
@@ -731,7 +732,7 @@ static const struct snd_kcontrol_new rt5651_pdm_r_mux =
 static int rt5651_amp_power_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -769,7 +770,7 @@ static int rt5651_amp_power_event(struct snd_soc_dapm_widget *w,
 static int rt5651_hp_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -813,7 +814,8 @@ static int rt5651_hp_event(struct snd_soc_dapm_widget *w,
 static int rt5651_hp_post_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -833,7 +835,7 @@ static int rt5651_hp_post_event(struct snd_soc_dapm_widget *w,
 static int rt5651_bst1_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -856,7 +858,7 @@ static int rt5651_bst1_event(struct snd_soc_dapm_widget *w,
 static int rt5651_bst2_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -879,7 +881,7 @@ static int rt5651_bst2_event(struct snd_soc_dapm_widget *w,
 static int rt5651_bst3_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
index 8a0833de1665bcd39594d27bbc323e4ea3d35ba0..e1a4a45c57e229b12dcd174ac8453f8772b6e3b1 100644 (file)
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
+#include <linux/pm_runtime.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/acpi.h>
 #include <linux/spi/spi.h>
+#include <linux/dmi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -498,7 +500,7 @@ static const struct snd_kcontrol_new rt5670_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
        int idx = -EINVAL;
 
@@ -515,9 +517,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int val;
 
-       val = snd_soc_read(source->codec, RT5670_GLB_CLK);
+       val = snd_soc_read(codec, RT5670_GLB_CLK);
        val &= RT5670_SCLK_SRC_MASK;
        if (val == RT5670_SCLK_SRC_PLL1)
                return 1;
@@ -528,6 +531,7 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 static int is_using_asrc(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg, shift, val;
 
        switch (source->shift) {
@@ -563,7 +567,7 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
                return 0;
        }
 
-       val = (snd_soc_read(source->codec, reg) >> shift) & 0xf;
+       val = (snd_soc_read(codec, reg) >> shift) & 0xf;
        switch (val) {
        case 1:
        case 2:
@@ -588,6 +592,89 @@ static int can_use_asrc(struct snd_soc_dapm_widget *source,
        return 0;
 }
 
+
+/**
+ * rt5670_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @codec: SoC audio codec device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5670 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the codec driver will turn on ASRC
+ * for these filters if ASRC is selected as their clock source.
+ */
+int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec,
+                           unsigned int filter_mask, unsigned int clk_src)
+{
+       unsigned int asrc2_mask = 0, asrc2_value = 0;
+       unsigned int asrc3_mask = 0, asrc3_value = 0;
+
+       if (clk_src > RT5670_CLK_SEL_SYS3)
+               return -EINVAL;
+
+       if (filter_mask & RT5670_DA_STEREO_FILTER) {
+               asrc2_mask |= RT5670_DA_STO_CLK_SEL_MASK;
+               asrc2_value = (asrc2_value & ~RT5670_DA_STO_CLK_SEL_MASK)
+                               | (clk_src <<  RT5670_DA_STO_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5670_DA_MONO_L_FILTER) {
+               asrc2_mask |= RT5670_DA_MONOL_CLK_SEL_MASK;
+               asrc2_value = (asrc2_value & ~RT5670_DA_MONOL_CLK_SEL_MASK)
+                               | (clk_src <<  RT5670_DA_MONOL_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5670_DA_MONO_R_FILTER) {
+               asrc2_mask |= RT5670_DA_MONOR_CLK_SEL_MASK;
+               asrc2_value = (asrc2_value & ~RT5670_DA_MONOR_CLK_SEL_MASK)
+                               | (clk_src <<  RT5670_DA_MONOR_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5670_AD_STEREO_FILTER) {
+               asrc2_mask |= RT5670_AD_STO1_CLK_SEL_MASK;
+               asrc2_value = (asrc2_value & ~RT5670_AD_STO1_CLK_SEL_MASK)
+                               | (clk_src <<  RT5670_AD_STO1_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5670_AD_MONO_L_FILTER) {
+               asrc3_mask |= RT5670_AD_MONOL_CLK_SEL_MASK;
+               asrc3_value = (asrc3_value & ~RT5670_AD_MONOL_CLK_SEL_MASK)
+                               | (clk_src <<  RT5670_AD_MONOL_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5670_AD_MONO_R_FILTER)  {
+               asrc3_mask |= RT5670_AD_MONOR_CLK_SEL_MASK;
+               asrc3_value = (asrc3_value & ~RT5670_AD_MONOR_CLK_SEL_MASK)
+                               | (clk_src <<  RT5670_AD_MONOR_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5670_UP_RATE_FILTER) {
+               asrc3_mask |= RT5670_UP_CLK_SEL_MASK;
+               asrc3_value = (asrc3_value & ~RT5670_UP_CLK_SEL_MASK)
+                               | (clk_src <<  RT5670_UP_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5670_DOWN_RATE_FILTER) {
+               asrc3_mask |= RT5670_DOWN_CLK_SEL_MASK;
+               asrc3_value = (asrc3_value & ~RT5670_DOWN_CLK_SEL_MASK)
+                               | (clk_src <<  RT5670_DOWN_CLK_SEL_SFT);
+       }
+
+       if (asrc2_mask)
+               snd_soc_update_bits(codec, RT5670_ASRC_2,
+                                   asrc2_mask, asrc2_value);
+
+       if (asrc3_mask)
+               snd_soc_update_bits(codec, RT5670_ASRC_3,
+                                   asrc3_mask, asrc3_value);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rt5670_sel_asrc_clk_src);
+
 /* Digital Mixer */
 static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = {
        SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER,
@@ -1146,7 +1233,7 @@ static const struct snd_kcontrol_new rt5670_vad_adc_mux =
 static int rt5670_hp_power_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -1182,7 +1269,7 @@ static int rt5670_hp_power_event(struct snd_soc_dapm_widget *w,
 static int rt5670_hp_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -1232,7 +1319,7 @@ static int rt5670_hp_event(struct snd_soc_dapm_widget *w,
 static int rt5670_bst1_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -1255,7 +1342,7 @@ static int rt5670_bst1_event(struct snd_soc_dapm_widget *w,
 static int rt5670_bst2_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -2188,6 +2275,13 @@ static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai,
        if (freq == rt5670->sysclk && clk_id == rt5670->sysclk_src)
                return 0;
 
+       if (rt5670->pdata.jd_mode) {
+               if (clk_id == RT5670_SCLK_S_PLL1)
+                       snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1");
+               else
+                       snd_soc_dapm_disable_pin(&codec->dapm, "PLL1");
+               snd_soc_dapm_sync(&codec->dapm);
+       }
        switch (clk_id) {
        case RT5670_SCLK_S_MCLK:
                reg_val |= RT5670_SCLK_SRC_MCLK;
@@ -2522,6 +2616,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5670 = {
 static const struct regmap_config rt5670_regmap = {
        .reg_bits = 8,
        .val_bits = 16,
+       .use_single_rw = true,
        .max_register = RT5670_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5670_ranges) *
                                               RT5670_PR_SPACING),
        .volatile_reg = rt5670_volatile_register,
@@ -2549,6 +2644,17 @@ static struct acpi_device_id rt5670_acpi_match[] = {
 MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match);
 #endif
 
+static const struct dmi_system_id dmi_platform_intel_braswell[] = {
+       {
+               .ident = "Intel Braswell",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+                       DMI_MATCH(DMI_BOARD_NAME, "Braswell CRB"),
+               },
+       },
+       {}
+};
+
 static int rt5670_i2c_probe(struct i2c_client *i2c,
                    const struct i2c_device_id *id)
 {
@@ -2568,6 +2674,12 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
        if (pdata)
                rt5670->pdata = *pdata;
 
+       if (dmi_check_system(dmi_platform_intel_braswell)) {
+               rt5670->pdata.dmic_en = true;
+               rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
+               rt5670->pdata.jd_mode = 1;
+       }
+
        rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap);
        if (IS_ERR(rt5670->regmap)) {
                ret = PTR_ERR(rt5670->regmap);
@@ -2609,6 +2721,10 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
        }
 
        if (rt5670->pdata.jd_mode) {
+               regmap_update_bits(rt5670->regmap, RT5670_GLB_CLK,
+                                  RT5670_SCLK_SRC_MASK, RT5670_SCLK_SRC_RCCLK);
+               rt5670->sysclk = 0;
+               rt5670->sysclk_src = RT5670_SCLK_S_RCCLK;
                regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG1,
                                   RT5670_PWR_MB, RT5670_PWR_MB);
                regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG2,
@@ -2716,18 +2832,26 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
 
        }
 
+       pm_runtime_enable(&i2c->dev);
+       pm_request_idle(&i2c->dev);
+
        ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5670,
                        rt5670_dai, ARRAY_SIZE(rt5670_dai));
        if (ret < 0)
                goto err;
 
+       pm_runtime_put(&i2c->dev);
+
        return 0;
 err:
+       pm_runtime_disable(&i2c->dev);
+
        return ret;
 }
 
 static int rt5670_i2c_remove(struct i2c_client *i2c)
 {
+       pm_runtime_disable(&i2c->dev);
        snd_soc_unregister_codec(&i2c->dev);
 
        return 0;
index d11b9c207e26799ba6cbb85cd3979ace7c76ea4d..21f8e18c13c48d606deb315b6abc82838029e14d 100644 (file)
 #define RT5670_DMIC_2_M_NOR                    (0x0 << 8)
 #define RT5670_DMIC_2_M_ASYN                   (0x1 << 8)
 
+/* ASRC clock source selection (0x84, 0x85) */
+#define RT5670_CLK_SEL_SYS                     (0x0)
+#define RT5670_CLK_SEL_I2S1_ASRC               (0x1)
+#define RT5670_CLK_SEL_I2S2_ASRC               (0x2)
+#define RT5670_CLK_SEL_I2S3_ASRC               (0x3)
+#define RT5670_CLK_SEL_SYS2                    (0x5)
+#define RT5670_CLK_SEL_SYS3                    (0x6)
+
 /* ASRC Control 2 (0x84) */
-#define RT5670_MDA_L_M_MASK                    (0x1 << 15)
-#define RT5670_MDA_L_M_SFT                     15
-#define RT5670_MDA_L_M_NOR                     (0x0 << 15)
-#define RT5670_MDA_L_M_ASYN                    (0x1 << 15)
-#define RT5670_MDA_R_M_MASK                    (0x1 << 14)
-#define RT5670_MDA_R_M_SFT                     14
-#define RT5670_MDA_R_M_NOR                     (0x0 << 14)
-#define RT5670_MDA_R_M_ASYN                    (0x1 << 14)
-#define RT5670_MAD_L_M_MASK                    (0x1 << 13)
-#define RT5670_MAD_L_M_SFT                     13
-#define RT5670_MAD_L_M_NOR                     (0x0 << 13)
-#define RT5670_MAD_L_M_ASYN                    (0x1 << 13)
-#define RT5670_MAD_R_M_MASK                    (0x1 << 12)
-#define RT5670_MAD_R_M_SFT                     12
-#define RT5670_MAD_R_M_NOR                     (0x0 << 12)
-#define RT5670_MAD_R_M_ASYN                    (0x1 << 12)
-#define RT5670_ADC_M_MASK                      (0x1 << 11)
-#define RT5670_ADC_M_SFT                       11
-#define RT5670_ADC_M_NOR                       (0x0 << 11)
-#define RT5670_ADC_M_ASYN                      (0x1 << 11)
-#define RT5670_STO_DAC_M_MASK                  (0x1 << 5)
-#define RT5670_STO_DAC_M_SFT                   5
-#define RT5670_STO_DAC_M_NOR                   (0x0 << 5)
-#define RT5670_STO_DAC_M_ASYN                  (0x1 << 5)
-#define RT5670_I2S1_R_D_MASK                   (0x1 << 4)
-#define RT5670_I2S1_R_D_SFT                    4
-#define RT5670_I2S1_R_D_DIS                    (0x0 << 4)
-#define RT5670_I2S1_R_D_EN                     (0x1 << 4)
-#define RT5670_I2S2_R_D_MASK                   (0x1 << 3)
-#define RT5670_I2S2_R_D_SFT                    3
-#define RT5670_I2S2_R_D_DIS                    (0x0 << 3)
-#define RT5670_I2S2_R_D_EN                     (0x1 << 3)
-#define RT5670_PRE_SCLK_MASK                   (0x3)
-#define RT5670_PRE_SCLK_SFT                    0
-#define RT5670_PRE_SCLK_512                    (0x0)
-#define RT5670_PRE_SCLK_1024                   (0x1)
-#define RT5670_PRE_SCLK_2048                   (0x2)
+#define RT5670_DA_STO_CLK_SEL_MASK             (0xf << 12)
+#define RT5670_DA_STO_CLK_SEL_SFT              12
+#define RT5670_DA_MONOL_CLK_SEL_MASK           (0xf << 8)
+#define RT5670_DA_MONOL_CLK_SEL_SFT            8
+#define RT5670_DA_MONOR_CLK_SEL_MASK           (0xf << 4)
+#define RT5670_DA_MONOR_CLK_SEL_SFT            4
+#define RT5670_AD_STO1_CLK_SEL_MASK            (0xf << 0)
+#define RT5670_AD_STO1_CLK_SEL_SFT             0
 
 /* ASRC Control 3 (0x85) */
-#define RT5670_I2S1_RATE_MASK                  (0xf << 12)
-#define RT5670_I2S1_RATE_SFT                   12
-#define RT5670_I2S2_RATE_MASK                  (0xf << 8)
-#define RT5670_I2S2_RATE_SFT                   8
+#define RT5670_UP_CLK_SEL_MASK                 (0xf << 12)
+#define RT5670_UP_CLK_SEL_SFT                  12
+#define RT5670_DOWN_CLK_SEL_MASK               (0xf << 8)
+#define RT5670_DOWN_CLK_SEL_SFT                        8
+#define RT5670_AD_MONOL_CLK_SEL_MASK           (0xf << 4)
+#define RT5670_AD_MONOL_CLK_SEL_SFT            4
+#define RT5670_AD_MONOR_CLK_SEL_MASK           (0xf << 0)
+#define RT5670_AD_MONOR_CLK_SEL_SFT            0
 
 /* ASRC Control 4 (0x89) */
 #define RT5670_I2S1_PD_MASK                    (0x7 << 12)
@@ -1983,6 +1966,21 @@ enum {
        RT5670_DMIC_DATA_GPIO5,
 };
 
+/* filter mask */
+enum {
+       RT5670_DA_STEREO_FILTER = 0x1,
+       RT5670_DA_MONO_L_FILTER = (0x1 << 1),
+       RT5670_DA_MONO_R_FILTER = (0x1 << 2),
+       RT5670_AD_STEREO_FILTER = (0x1 << 3),
+       RT5670_AD_MONO_L_FILTER = (0x1 << 4),
+       RT5670_AD_MONO_R_FILTER = (0x1 << 5),
+       RT5670_UP_RATE_FILTER   = (0x1 << 6),
+       RT5670_DOWN_RATE_FILTER = (0x1 << 7),
+};
+
+int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec,
+                           unsigned int filter_mask, unsigned int clk_src);
+
 struct rt5670_priv {
        struct snd_soc_codec *codec;
        struct rt5670_platform_data pdata;
index 918ada9738b0431e9d47d0dc5155cd42d9e2fb2a..5d0bb8748dd1df5cd6a262d7e3a925fe4b4b5efd 100644 (file)
@@ -702,6 +702,9 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on)
        static bool activity;
        int ret;
 
+       if (!IS_ENABLED(CONFIG_SND_SOC_RT5677_SPI))
+               return -ENXIO;
+
        if (on && !activity) {
                activity = true;
 
@@ -896,7 +899,7 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
        int idx = rl6231_calc_dmic_clk(rt5677->sysclk);
 
@@ -911,7 +914,8 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
-       struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(source->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+       struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
        unsigned int val;
 
        regmap_read(rt5677->regmap, RT5677_GLB_CLK1, &val);
@@ -922,6 +926,101 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
                return 0;
 }
 
+static int is_using_asrc(struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+       struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+       unsigned int reg, shift, val;
+
+       if (source->reg == RT5677_ASRC_1) {
+               switch (source->shift) {
+               case 12:
+                       reg = RT5677_ASRC_4;
+                       shift = 0;
+                       break;
+               case 13:
+                       reg = RT5677_ASRC_4;
+                       shift = 4;
+                       break;
+               case 14:
+                       reg = RT5677_ASRC_4;
+                       shift = 8;
+                       break;
+               case 15:
+                       reg = RT5677_ASRC_4;
+                       shift = 12;
+                       break;
+               default:
+                       return 0;
+               }
+       } else {
+               switch (source->shift) {
+               case 0:
+                       reg = RT5677_ASRC_6;
+                       shift = 8;
+                       break;
+               case 1:
+                       reg = RT5677_ASRC_6;
+                       shift = 12;
+                       break;
+               case 2:
+                       reg = RT5677_ASRC_5;
+                       shift = 0;
+                       break;
+               case 3:
+                       reg = RT5677_ASRC_5;
+                       shift = 4;
+                       break;
+               case 4:
+                       reg = RT5677_ASRC_5;
+                       shift = 8;
+                       break;
+               case 5:
+                       reg = RT5677_ASRC_5;
+                       shift = 12;
+                       break;
+               case 12:
+                       reg = RT5677_ASRC_3;
+                       shift = 0;
+                       break;
+               case 13:
+                       reg = RT5677_ASRC_3;
+                       shift = 4;
+                       break;
+               case 14:
+                       reg = RT5677_ASRC_3;
+                       shift = 12;
+                       break;
+               default:
+                       return 0;
+               }
+       }
+
+       regmap_read(rt5677->regmap, reg, &val);
+       val = (val >> shift) & 0xf;
+
+       switch (val) {
+       case 1 ... 6:
+               return 1;
+       default:
+               return 0;
+       }
+
+}
+
+static int can_use_asrc(struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+       struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+
+       if (rt5677->sysclk > rt5677->lrck[RT5677_AIF1] * 384)
+               return 1;
+
+       return 0;
+}
+
 /* Digital Mixer */
 static const struct snd_kcontrol_new rt5677_sto1_adc_l_mix[] = {
        SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO1_ADC_MIXER,
@@ -2031,7 +2130,7 @@ static const struct snd_kcontrol_new rt5677_if2_dac7_tdm_sel_mux =
 static int rt5677_bst1_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -2055,7 +2154,7 @@ static int rt5677_bst1_event(struct snd_soc_dapm_widget *w,
 static int rt5677_bst2_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -2079,7 +2178,7 @@ static int rt5677_bst2_event(struct snd_soc_dapm_widget *w,
 static int rt5677_set_pll1_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -2101,7 +2200,7 @@ static int rt5677_set_pll1_event(struct snd_soc_dapm_widget *w,
 static int rt5677_set_pll2_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -2123,7 +2222,7 @@ static int rt5677_set_pll2_event(struct snd_soc_dapm_widget *w,
 static int rt5677_set_micbias1_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -2150,7 +2249,7 @@ static int rt5677_set_micbias1_event(struct snd_soc_dapm_widget *w,
 static int rt5677_if1_adc_tdm_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
        unsigned int value;
 
@@ -2173,7 +2272,7 @@ static int rt5677_if1_adc_tdm_event(struct snd_soc_dapm_widget *w,
 static int rt5677_if2_adc_tdm_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
        unsigned int value;
 
@@ -2196,7 +2295,7 @@ static int rt5677_if2_adc_tdm_event(struct snd_soc_dapm_widget *w,
 static int rt5677_vref_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -2226,6 +2325,45 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
                0, rt5677_set_pll2_event, SND_SOC_DAPM_PRE_PMU |
                SND_SOC_DAPM_POST_PMU),
 
+       /* ASRC */
+       SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5677_ASRC_1, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5677_ASRC_1, 1, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("I2S3 ASRC", 1, RT5677_ASRC_1, 2, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("I2S4 ASRC", 1, RT5677_ASRC_1, 3, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5677_ASRC_2, 14, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DAC MONO2 L ASRC", 1, RT5677_ASRC_2, 13, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DAC MONO2 R ASRC", 1, RT5677_ASRC_2, 12, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DAC MONO3 L ASRC", 1, RT5677_ASRC_1, 15, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DAC MONO3 R ASRC", 1, RT5677_ASRC_1, 14, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DAC MONO4 L ASRC", 1, RT5677_ASRC_1, 13, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DAC MONO4 R ASRC", 1, RT5677_ASRC_1, 12, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5677_ASRC_2, 11, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DMIC STO2 ASRC", 1, RT5677_ASRC_2, 10, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DMIC STO3 ASRC", 1, RT5677_ASRC_2, 9, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DMIC STO4 ASRC", 1, RT5677_ASRC_2, 8, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5677_ASRC_2, 7, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5677_ASRC_2, 6, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5677_ASRC_2, 5, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("ADC STO2 ASRC", 1, RT5677_ASRC_2, 4, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("ADC STO3 ASRC", 1, RT5677_ASRC_2, 3, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("ADC STO4 ASRC", 1, RT5677_ASRC_2, 2, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("ADC MONO L ASRC", 1, RT5677_ASRC_2, 1, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("ADC MONO R ASRC", 1, RT5677_ASRC_2, 0, 0, NULL,
+               0),
+
        /* Input Side */
        /* micbias */
        SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5677_PWR_ANLG2, RT5677_PWR_MB1_BIT,
@@ -2656,10 +2794,18 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
        /* DAC Mixer */
        SND_SOC_DAPM_SUPPLY("dac stereo1 filter", RT5677_PWR_DIG2,
                RT5677_PWR_DAC_S1F_BIT, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("dac mono left filter", RT5677_PWR_DIG2,
+       SND_SOC_DAPM_SUPPLY("dac mono2 left filter", RT5677_PWR_DIG2,
                RT5677_PWR_DAC_M2F_L_BIT, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("dac mono right filter", RT5677_PWR_DIG2,
+       SND_SOC_DAPM_SUPPLY("dac mono2 right filter", RT5677_PWR_DIG2,
                RT5677_PWR_DAC_M2F_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("dac mono3 left filter", RT5677_PWR_DIG2,
+               RT5677_PWR_DAC_M3F_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("dac mono3 right filter", RT5677_PWR_DIG2,
+               RT5677_PWR_DAC_M3F_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("dac mono4 left filter", RT5677_PWR_DIG2,
+               RT5677_PWR_DAC_M4F_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("dac mono4 right filter", RT5677_PWR_DIG2,
+               RT5677_PWR_DAC_M4F_R_BIT, 0, NULL, 0),
 
        SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
                rt5677_sto1_dac_l_mix, ARRAY_SIZE(rt5677_sto1_dac_l_mix)),
@@ -2732,6 +2878,31 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
 };
 
 static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
+       { "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", can_use_asrc },
+       { "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", can_use_asrc },
+       { "Stereo3 DMIC Mux", NULL, "DMIC STO3 ASRC", can_use_asrc },
+       { "Stereo4 DMIC Mux", NULL, "DMIC STO4 ASRC", can_use_asrc },
+       { "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", can_use_asrc },
+       { "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", can_use_asrc },
+       { "I2S1", NULL, "I2S1 ASRC", can_use_asrc},
+       { "I2S2", NULL, "I2S2 ASRC", can_use_asrc},
+       { "I2S3", NULL, "I2S3 ASRC", can_use_asrc},
+       { "I2S4", NULL, "I2S4 ASRC", can_use_asrc},
+
+       { "dac stereo1 filter", NULL, "DAC STO ASRC", is_using_asrc },
+       { "dac mono2 left filter", NULL, "DAC MONO2 L ASRC", is_using_asrc },
+       { "dac mono2 right filter", NULL, "DAC MONO2 R ASRC", is_using_asrc },
+       { "dac mono3 left filter", NULL, "DAC MONO3 L ASRC", is_using_asrc },
+       { "dac mono3 right filter", NULL, "DAC MONO3 R ASRC", is_using_asrc },
+       { "dac mono4 left filter", NULL, "DAC MONO4 L ASRC", is_using_asrc },
+       { "dac mono4 right filter", NULL, "DAC MONO4 R ASRC", is_using_asrc },
+       { "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc },
+       { "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc },
+       { "adc stereo3 filter", NULL, "ADC STO3 ASRC", is_using_asrc },
+       { "adc stereo4 filter", NULL, "ADC STO4 ASRC", is_using_asrc },
+       { "adc mono left filter", NULL, "ADC MONO L ASRC", is_using_asrc },
+       { "adc mono right filter", NULL, "ADC MONO R ASRC", is_using_asrc },
+
        { "DMIC1", NULL, "DMIC L1" },
        { "DMIC1", NULL, "DMIC R1" },
        { "DMIC2", NULL, "DMIC L2" },
@@ -2862,8 +3033,6 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
 
        { "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" },
        { "Stereo1 ADC MIXL", NULL, "adc stereo1 filter" },
-       { "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll },
-
        { "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" },
        { "Stereo1 ADC MIXR", NULL, "adc stereo1 filter" },
        { "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll },
@@ -2884,8 +3053,6 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
 
        { "Stereo2 ADC MIXL", NULL, "Stereo2 ADC LR Mux" },
        { "Stereo2 ADC MIXL", NULL, "adc stereo2 filter" },
-       { "adc stereo2 filter", NULL, "PLL1", is_sys_clk_from_pll },
-
        { "Stereo2 ADC MIXR", NULL, "Sto2 ADC MIXR" },
        { "Stereo2 ADC MIXR", NULL, "adc stereo2 filter" },
        { "adc stereo2 filter", NULL, "PLL1", is_sys_clk_from_pll },
@@ -2900,8 +3067,6 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
 
        { "Stereo3 ADC MIXL", NULL, "Sto3 ADC MIXL" },
        { "Stereo3 ADC MIXL", NULL, "adc stereo3 filter" },
-       { "adc stereo3 filter", NULL, "PLL1", is_sys_clk_from_pll },
-
        { "Stereo3 ADC MIXR", NULL, "Sto3 ADC MIXR" },
        { "Stereo3 ADC MIXR", NULL, "adc stereo3 filter" },
        { "adc stereo3 filter", NULL, "PLL1", is_sys_clk_from_pll },
@@ -2916,8 +3081,6 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
 
        { "Stereo4 ADC MIXL", NULL, "Sto4 ADC MIXL" },
        { "Stereo4 ADC MIXL", NULL, "adc stereo4 filter" },
-       { "adc stereo4 filter", NULL, "PLL1", is_sys_clk_from_pll },
-
        { "Stereo4 ADC MIXR", NULL, "Sto4 ADC MIXR" },
        { "Stereo4 ADC MIXR", NULL, "adc stereo4 filter" },
        { "adc stereo4 filter", NULL, "PLL1", is_sys_clk_from_pll },
@@ -3466,10 +3629,8 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
 
        { "DAC1 MIXL", "Stereo ADC Switch", "ADDA1 Mux" },
        { "DAC1 MIXL", "DAC1 Switch", "DAC1 Mux" },
-       { "DAC1 MIXL", NULL, "dac stereo1 filter" },
        { "DAC1 MIXR", "Stereo ADC Switch", "ADDA1 Mux" },
        { "DAC1 MIXR", "DAC1 Switch", "DAC1 Mux" },
-       { "DAC1 MIXR", NULL, "dac stereo1 filter" },
 
        { "DAC1 FS", NULL, "DAC1 MIXL" },
        { "DAC1 FS", NULL, "DAC1 MIXR" },
@@ -3536,35 +3697,46 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
        { "Stereo DAC MIXR", "DAC2 R Switch", "DAC2 R Mux" },
        { "Stereo DAC MIXR", "DAC1 L Switch", "DAC1 MIXL" },
        { "Stereo DAC MIXR", NULL, "dac stereo1 filter" },
+       { "dac stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll },
 
        { "Mono DAC MIXL", "ST L Switch", "Sidetone Mux" },
        { "Mono DAC MIXL", "DAC1 L Switch", "DAC1 MIXL" },
        { "Mono DAC MIXL", "DAC2 L Switch", "DAC2 L Mux" },
        { "Mono DAC MIXL", "DAC2 R Switch", "DAC2 R Mux" },
-       { "Mono DAC MIXL", NULL, "dac mono left filter" },
+       { "Mono DAC MIXL", NULL, "dac mono2 left filter" },
+       { "dac mono2 left filter", NULL, "PLL1", is_sys_clk_from_pll },
        { "Mono DAC MIXR", "ST R Switch", "Sidetone Mux" },
        { "Mono DAC MIXR", "DAC1 R Switch", "DAC1 MIXR" },
        { "Mono DAC MIXR", "DAC2 R Switch", "DAC2 R Mux" },
        { "Mono DAC MIXR", "DAC2 L Switch", "DAC2 L Mux" },
-       { "Mono DAC MIXR", NULL, "dac mono right filter" },
+       { "Mono DAC MIXR", NULL, "dac mono2 right filter" },
+       { "dac mono2 right filter", NULL, "PLL1", is_sys_clk_from_pll },
 
        { "DD1 MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" },
        { "DD1 MIXL", "Mono DAC Mix L Switch", "Mono DAC MIXL" },
        { "DD1 MIXL", "DAC3 L Switch", "DAC3 L Mux" },
        { "DD1 MIXL", "DAC3 R Switch", "DAC3 R Mux" },
+       { "DD1 MIXL", NULL, "dac mono3 left filter" },
+       { "dac mono3 left filter", NULL, "PLL1", is_sys_clk_from_pll },
        { "DD1 MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" },
        { "DD1 MIXR", "Mono DAC Mix R Switch", "Mono DAC MIXR" },
        { "DD1 MIXR", "DAC3 L Switch", "DAC3 L Mux" },
        { "DD1 MIXR", "DAC3 R Switch", "DAC3 R Mux" },
+       { "DD1 MIXR", NULL, "dac mono3 right filter" },
+       { "dac mono3 right filter", NULL, "PLL1", is_sys_clk_from_pll },
 
        { "DD2 MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" },
        { "DD2 MIXL", "Mono DAC Mix L Switch", "Mono DAC MIXL" },
        { "DD2 MIXL", "DAC4 L Switch", "DAC4 L Mux" },
        { "DD2 MIXL", "DAC4 R Switch", "DAC4 R Mux" },
+       { "DD2 MIXL", NULL, "dac mono4 left filter" },
+       { "dac mono4 left filter", NULL, "PLL1", is_sys_clk_from_pll },
        { "DD2 MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" },
        { "DD2 MIXR", "Mono DAC Mix R Switch", "Mono DAC MIXR" },
        { "DD2 MIXR", "DAC4 L Switch", "DAC4 L Mux" },
        { "DD2 MIXR", "DAC4 R Switch", "DAC4 R Mux" },
+       { "DD2 MIXR", NULL, "dac mono4 right filter" },
+       { "dac mono4 right filter", NULL, "PLL1", is_sys_clk_from_pll },
 
        { "Stereo DAC MIX", NULL, "Stereo DAC MIXL" },
        { "Stereo DAC MIX", NULL, "Stereo DAC MIXR" },
@@ -3586,11 +3758,8 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
        { "DAC3 SRC Mux", "DD MIX2L", "DD2 MIXL" },
 
        { "DAC 1", NULL, "DAC12 SRC Mux" },
-       { "DAC 1", NULL, "PLL1", is_sys_clk_from_pll },
        { "DAC 2", NULL, "DAC12 SRC Mux" },
-       { "DAC 2", NULL, "PLL1", is_sys_clk_from_pll },
        { "DAC 3", NULL, "DAC3 SRC Mux" },
-       { "DAC 3", NULL, "PLL1", is_sys_clk_from_pll },
 
        { "PDM1 L Mux", "STO1 DAC MIX", "Stereo DAC MIXL" },
        { "PDM1 L Mux", "MONO DAC MIX", "Mono DAC MIXL" },
@@ -3937,7 +4106,8 @@ static int rt5677_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
                        unsigned int rx_mask, int slots, int slot_width)
 {
        struct snd_soc_codec *codec = dai->codec;
-       unsigned int val = 0;
+       struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+       unsigned int val = 0, slot_width_25 = 0;
 
        if (rx_mask || tx_mask)
                val |= (1 << 12);
@@ -3961,6 +4131,8 @@ static int rt5677_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
        case 20:
                val |= (1 << 8);
                break;
+       case 25:
+               slot_width_25 = 0x8080;
        case 24:
                val |= (2 << 8);
                break;
@@ -3974,10 +4146,16 @@ static int rt5677_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 
        switch (dai->id) {
        case RT5677_AIF1:
-               snd_soc_update_bits(codec, RT5677_TDM1_CTRL1, 0x1f00, val);
+               regmap_update_bits(rt5677->regmap, RT5677_TDM1_CTRL1, 0x1f00,
+                       val);
+               regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x8000,
+                       slot_width_25);
                break;
        case RT5677_AIF2:
-               snd_soc_update_bits(codec, RT5677_TDM2_CTRL1, 0x1f00, val);
+               regmap_update_bits(rt5677->regmap, RT5677_TDM2_CTRL1, 0x1f00,
+                       val);
+               regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x80,
+                       slot_width_25);
                break;
        default:
                break;
@@ -4762,6 +4940,11 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
                                        RT5677_GPIO5_DIR_OUT);
        }
 
+       if (rt5677->pdata.micbias1_vdd_3v3)
+               regmap_update_bits(rt5677->regmap, RT5677_MICBIAS,
+                       RT5677_MICBIAS1_CTRL_VDD_MASK,
+                       RT5677_MICBIAS1_CTRL_VDD_3_3V);
+
        rt5677_init_gpio(i2c);
        rt5677_init_irq(i2c);
 
index aa98be32bb60cfdb37ed150b4cffabf7dd4ee071..e182e6569bbd138713ec0047de606136254d81c4 100644 (file)
@@ -155,18 +155,19 @@ struct sgtl5000_priv {
 static int mic_bias_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                /* change mic bias resistor */
-               snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
+               snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL,
                        SGTL5000_BIAS_R_MASK,
                        sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT);
                break;
 
        case SND_SOC_DAPM_PRE_PMD:
-               snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
+               snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL,
                                SGTL5000_BIAS_R_MASK, 0);
                break;
        }
@@ -181,11 +182,12 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w,
 static int power_vag_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        const u32 mask = SGTL5000_DAC_POWERUP | SGTL5000_ADC_POWERUP;
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
-               snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER,
+               snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
                        SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP);
                break;
 
@@ -195,9 +197,9 @@ static int power_vag_event(struct snd_soc_dapm_widget *w,
                 * operational to prevent inadvertently starving the
                 * other one of them.
                 */
-               if ((snd_soc_read(w->codec, SGTL5000_CHIP_ANA_POWER) &
+               if ((snd_soc_read(codec, SGTL5000_CHIP_ANA_POWER) &
                                mask) != mask) {
-                       snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER,
+                       snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
                                SGTL5000_VAG_POWERUP, 0);
                        msleep(400);
                }
index 1f451a1946eb259c4734b68a2e2f273279c35dec..47b257e4180965f38be5c393cab204945f444b7f 100644 (file)
@@ -233,16 +233,18 @@ static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
 static int sn95031_vhs_event(struct snd_soc_dapm_widget *w,
                    struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
        if (SND_SOC_DAPM_EVENT_ON(event)) {
                pr_debug("VHS SND_SOC_DAPM_EVENT_ON doing rail startup now\n");
                /* power up the rail */
-               snd_soc_write(w->codec, SN95031_VHSP, 0x3D);
-               snd_soc_write(w->codec, SN95031_VHSN, 0x3F);
+               snd_soc_write(codec, SN95031_VHSP, 0x3D);
+               snd_soc_write(codec, SN95031_VHSN, 0x3F);
                msleep(1);
        } else if (SND_SOC_DAPM_EVENT_OFF(event)) {
                pr_debug("VHS SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n");
-               snd_soc_write(w->codec, SN95031_VHSP, 0xC4);
-               snd_soc_write(w->codec, SN95031_VHSN, 0x04);
+               snd_soc_write(codec, SN95031_VHSP, 0xC4);
+               snd_soc_write(codec, SN95031_VHSN, 0x04);
        }
        return 0;
 }
@@ -250,14 +252,16 @@ static int sn95031_vhs_event(struct snd_soc_dapm_widget *w,
 static int sn95031_vihf_event(struct snd_soc_dapm_widget *w,
                    struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
        if (SND_SOC_DAPM_EVENT_ON(event)) {
                pr_debug("VIHF SND_SOC_DAPM_EVENT_ON doing rail startup now\n");
                /* power up the rail */
-               snd_soc_write(w->codec, SN95031_VIHF, 0x27);
+               snd_soc_write(codec, SN95031_VIHF, 0x27);
                msleep(1);
        } else if (SND_SOC_DAPM_EVENT_OFF(event)) {
                pr_debug("VIHF SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n");
-               snd_soc_write(w->codec, SN95031_VIHF, 0x24);
+               snd_soc_write(codec, SN95031_VIHF, 0x24);
        }
        return 0;
 }
@@ -265,6 +269,7 @@ static int sn95031_vihf_event(struct snd_soc_dapm_widget *w,
 static int sn95031_dmic12_event(struct snd_soc_dapm_widget *w,
                        struct snd_kcontrol *k, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        unsigned int ldo = 0, clk_dir = 0, data_dir = 0;
 
        if (SND_SOC_DAPM_EVENT_ON(event)) {
@@ -273,15 +278,16 @@ static int sn95031_dmic12_event(struct snd_soc_dapm_widget *w,
                data_dir = BIT(7);
        }
        /* program DMIC LDO, clock and set clock */
-       snd_soc_update_bits(w->codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo);
-       snd_soc_update_bits(w->codec, SN95031_DMICBUF0123, BIT(0), clk_dir);
-       snd_soc_update_bits(w->codec, SN95031_DMICBUF0123, BIT(7), data_dir);
+       snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo);
+       snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(0), clk_dir);
+       snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(7), data_dir);
        return 0;
 }
 
 static int sn95031_dmic34_event(struct snd_soc_dapm_widget *w,
                        struct snd_kcontrol *k, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        unsigned int ldo = 0, clk_dir = 0, data_dir = 0;
 
        if (SND_SOC_DAPM_EVENT_ON(event)) {
@@ -290,22 +296,23 @@ static int sn95031_dmic34_event(struct snd_soc_dapm_widget *w,
                data_dir = BIT(1);
        }
        /* program DMIC LDO, clock and set clock */
-       snd_soc_update_bits(w->codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo);
-       snd_soc_update_bits(w->codec, SN95031_DMICBUF0123, BIT(2), clk_dir);
-       snd_soc_update_bits(w->codec, SN95031_DMICBUF45, BIT(1), data_dir);
+       snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo);
+       snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(2), clk_dir);
+       snd_soc_update_bits(codec, SN95031_DMICBUF45, BIT(1), data_dir);
        return 0;
 }
 
 static int sn95031_dmic56_event(struct snd_soc_dapm_widget *w,
                        struct snd_kcontrol *k, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        unsigned int ldo = 0;
 
        if (SND_SOC_DAPM_EVENT_ON(event))
                ldo = BIT(7)|BIT(6);
 
        /* program DMIC LDO */
-       snd_soc_update_bits(w->codec, SN95031_MICBIAS, BIT(7)|BIT(6), ldo);
+       snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(7)|BIT(6), ldo);
        return 0;
 }
 
index 7e18200dd6a9f5b29469dedf6bbdc26cd9bc8032..3a1343fa109b482860811baea1566d354e574399 100644 (file)
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <sound/core.h>
@@ -102,6 +105,35 @@ static const struct reg_default sta32x_regs[] = {
        { 0x2c, 0x0c },
 };
 
+static const struct regmap_range sta32x_write_regs_range[] = {
+       regmap_reg_range(STA32X_CONFA,  STA32X_AUTO2),
+       regmap_reg_range(STA32X_C1CFG,  STA32X_FDRC2),
+};
+
+static const struct regmap_range sta32x_read_regs_range[] = {
+       regmap_reg_range(STA32X_CONFA,  STA32X_AUTO2),
+       regmap_reg_range(STA32X_C1CFG,  STA32X_FDRC2),
+};
+
+static const struct regmap_range sta32x_volatile_regs_range[] = {
+       regmap_reg_range(STA32X_CFADDR2, STA32X_CFUD),
+};
+
+static const struct regmap_access_table sta32x_write_regs = {
+       .yes_ranges =   sta32x_write_regs_range,
+       .n_yes_ranges = ARRAY_SIZE(sta32x_write_regs_range),
+};
+
+static const struct regmap_access_table sta32x_read_regs = {
+       .yes_ranges =   sta32x_read_regs_range,
+       .n_yes_ranges = ARRAY_SIZE(sta32x_read_regs_range),
+};
+
+static const struct regmap_access_table sta32x_volatile_regs = {
+       .yes_ranges =   sta32x_volatile_regs_range,
+       .n_yes_ranges = ARRAY_SIZE(sta32x_volatile_regs_range),
+};
+
 /* regulator power supply names */
 static const char *sta32x_supply_names[] = {
        "Vdda", /* analog supply, 3.3VV */
@@ -122,6 +154,8 @@ struct sta32x_priv {
        u32 coef_shadow[STA32X_COEF_COUNT];
        struct delayed_work watchdog_work;
        int shutdown;
+       struct gpio_desc *gpiod_nreset;
+       struct mutex coeff_lock;
 };
 
 static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1);
@@ -155,37 +189,32 @@ static const char *sta32x_limiter_release_rate[] = {
        "0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299",
        "0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137",
        "0.0134", "0.0117", "0.0110", "0.0104" };
-
-static const unsigned int sta32x_limiter_ac_attack_tlv[] = {
-       TLV_DB_RANGE_HEAD(2),
+static DECLARE_TLV_DB_RANGE(sta32x_limiter_ac_attack_tlv,
        0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0),
        8, 16, TLV_DB_SCALE_ITEM(300, 100, 0),
-};
+);
 
-static const unsigned int sta32x_limiter_ac_release_tlv[] = {
-       TLV_DB_RANGE_HEAD(5),
+static DECLARE_TLV_DB_RANGE(sta32x_limiter_ac_release_tlv,
        0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
        1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0),
        2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0),
        3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0),
        8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0),
-};
+);
 
-static const unsigned int sta32x_limiter_drc_attack_tlv[] = {
-       TLV_DB_RANGE_HEAD(3),
+static DECLARE_TLV_DB_RANGE(sta32x_limiter_drc_attack_tlv,
        0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0),
        8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0),
        14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0),
-};
+);
 
-static const unsigned int sta32x_limiter_drc_release_tlv[] = {
-       TLV_DB_RANGE_HEAD(5),
+static DECLARE_TLV_DB_RANGE(sta32x_limiter_drc_release_tlv,
        0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
        1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0),
        3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0),
        5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0),
        13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0),
-};
+);
 
 static SOC_ENUM_SINGLE_DECL(sta32x_drc_ac_enum,
                            STA32X_CONFD, STA32X_CONFD_DRC_SHIFT,
@@ -244,29 +273,42 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
        int numcoef = kcontrol->private_value >> 16;
        int index = kcontrol->private_value & 0xffff;
-       unsigned int cfud;
-       int i;
+       unsigned int cfud, val;
+       int i, ret = 0;
+
+       mutex_lock(&sta32x->coeff_lock);
 
        /* preserve reserved bits in STA32X_CFUD */
-       cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0;
-       /* chip documentation does not say if the bits are self clearing,
-        * so do it explicitly */
-       snd_soc_write(codec, STA32X_CFUD, cfud);
+       regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
+       cfud &= 0xf0;
+       /*
+        * chip documentation does not say if the bits are self clearing,
+        * so do it explicitly
+        */
+       regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
 
-       snd_soc_write(codec, STA32X_CFADDR2, index);
-       if (numcoef == 1)
-               snd_soc_write(codec, STA32X_CFUD, cfud | 0x04);
-       else if (numcoef == 5)
-               snd_soc_write(codec, STA32X_CFUD, cfud | 0x08);
-       else
-               return -EINVAL;
-       for (i = 0; i < 3 * numcoef; i++)
-               ucontrol->value.bytes.data[i] =
-                       snd_soc_read(codec, STA32X_B1CF1 + i);
+       regmap_write(sta32x->regmap, STA32X_CFADDR2, index);
+       if (numcoef == 1) {
+               regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x04);
+       } else if (numcoef == 5) {
+               regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x08);
+       } else {
+               ret = -EINVAL;
+               goto exit_unlock;
+       }
 
-       return 0;
+       for (i = 0; i < 3 * numcoef; i++) {
+               regmap_read(sta32x->regmap, STA32X_B1CF1 + i, &val);
+               ucontrol->value.bytes.data[i] = val;
+       }
+
+exit_unlock:
+       mutex_unlock(&sta32x->coeff_lock);
+
+       return ret;
 }
 
 static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
@@ -280,24 +322,27 @@ static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
        int i;
 
        /* preserve reserved bits in STA32X_CFUD */
-       cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0;
-       /* chip documentation does not say if the bits are self clearing,
-        * so do it explicitly */
-       snd_soc_write(codec, STA32X_CFUD, cfud);
+       regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
+       cfud &= 0xf0;
+       /*
+        * chip documentation does not say if the bits are self clearing,
+        * so do it explicitly
+        */
+       regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
 
-       snd_soc_write(codec, STA32X_CFADDR2, index);
+       regmap_write(sta32x->regmap, STA32X_CFADDR2, index);
        for (i = 0; i < numcoef && (index + i < STA32X_COEF_COUNT); i++)
                sta32x->coef_shadow[index + i] =
                          (ucontrol->value.bytes.data[3 * i] << 16)
                        | (ucontrol->value.bytes.data[3 * i + 1] << 8)
                        | (ucontrol->value.bytes.data[3 * i + 2]);
        for (i = 0; i < 3 * numcoef; i++)
-               snd_soc_write(codec, STA32X_B1CF1 + i,
-                             ucontrol->value.bytes.data[i]);
+               regmap_write(sta32x->regmap, STA32X_B1CF1 + i,
+                            ucontrol->value.bytes.data[i]);
        if (numcoef == 1)
-               snd_soc_write(codec, STA32X_CFUD, cfud | 0x01);
+               regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01);
        else if (numcoef == 5)
-               snd_soc_write(codec, STA32X_CFUD, cfud | 0x02);
+               regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x02);
        else
                return -EINVAL;
 
@@ -311,20 +356,23 @@ static int sta32x_sync_coef_shadow(struct snd_soc_codec *codec)
        int i;
 
        /* preserve reserved bits in STA32X_CFUD */
-       cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0;
+       regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
+       cfud &= 0xf0;
 
        for (i = 0; i < STA32X_COEF_COUNT; i++) {
-               snd_soc_write(codec, STA32X_CFADDR2, i);
-               snd_soc_write(codec, STA32X_B1CF1,
-                             (sta32x->coef_shadow[i] >> 16) & 0xff);
-               snd_soc_write(codec, STA32X_B1CF2,
-                             (sta32x->coef_shadow[i] >> 8) & 0xff);
-               snd_soc_write(codec, STA32X_B1CF3,
-                             (sta32x->coef_shadow[i]) & 0xff);
-               /* chip documentation does not say if the bits are
-                * self-clearing, so do it explicitly */
-               snd_soc_write(codec, STA32X_CFUD, cfud);
-               snd_soc_write(codec, STA32X_CFUD, cfud | 0x01);
+               regmap_write(sta32x->regmap, STA32X_CFADDR2, i);
+               regmap_write(sta32x->regmap, STA32X_B1CF1,
+                            (sta32x->coef_shadow[i] >> 16) & 0xff);
+               regmap_write(sta32x->regmap, STA32X_B1CF2,
+                            (sta32x->coef_shadow[i] >> 8) & 0xff);
+               regmap_write(sta32x->regmap, STA32X_B1CF3,
+                            (sta32x->coef_shadow[i]) & 0xff);
+               /*
+                * chip documentation does not say if the bits are
+                * self-clearing, so do it explicitly
+                */
+               regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
+               regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01);
        }
        return 0;
 }
@@ -336,11 +384,11 @@ static int sta32x_cache_sync(struct snd_soc_codec *codec)
        int rc;
 
        /* mute during register sync */
-       mute = snd_soc_read(codec, STA32X_MMUTE);
-       snd_soc_write(codec, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE);
+       regmap_read(sta32x->regmap, STA32X_MMUTE, &mute);
+       regmap_write(sta32x->regmap, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE);
        sta32x_sync_coef_shadow(codec);
        rc = regcache_sync(sta32x->regmap);
-       snd_soc_write(codec, STA32X_MMUTE, mute);
+       regmap_write(sta32x->regmap, STA32X_MMUTE, mute);
        return rc;
 }
 
@@ -508,17 +556,12 @@ static struct {
 };
 
 /* MCLK to fs clock ratios */
-static struct {
-       int ratio;
-       int mcs;
-} mclk_ratios[3][7] = {
-       { { 768, 0 }, { 512, 1 }, { 384, 2 }, { 256, 3 },
-         { 128, 4 }, { 576, 5 }, { 0, 0 } },
-       { { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } },
-       { { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } },
+static int mcs_ratio_table[3][7] = {
+       { 768, 512, 384, 256, 128, 576, 0 },
+       { 384, 256, 192, 128,  64,   0 },
+       { 384, 256, 192, 128,  64,   0 },
 };
 
-
 /**
  * sta32x_set_dai_sysclk - configure MCLK
  * @codec_dai: the codec DAI
@@ -543,46 +586,10 @@ static int sta32x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
-       int i, j, ir, fs;
-       unsigned int rates = 0;
-       unsigned int rate_min = -1;
-       unsigned int rate_max = 0;
 
-       pr_debug("mclk=%u\n", freq);
+       dev_dbg(codec->dev, "mclk=%u\n", freq);
        sta32x->mclk = freq;
 
-       if (sta32x->mclk) {
-               for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) {
-                       ir = interpolation_ratios[i].ir;
-                       fs = interpolation_ratios[i].fs;
-                       for (j = 0; mclk_ratios[ir][j].ratio; j++) {
-                               if (mclk_ratios[ir][j].ratio * fs == freq) {
-                                       rates |= snd_pcm_rate_to_rate_bit(fs);
-                                       if (fs < rate_min)
-                                               rate_min = fs;
-                                       if (fs > rate_max)
-                                               rate_max = fs;
-                                       break;
-                               }
-                       }
-               }
-               /* FIXME: soc should support a rate list */
-               rates &= ~SNDRV_PCM_RATE_KNOT;
-
-               if (!rates) {
-                       dev_err(codec->dev, "could not find a valid sample rate\n");
-                       return -EINVAL;
-               }
-       } else {
-               /* enable all possible rates */
-               rates = STA32X_RATES;
-               rate_min = 32000;
-               rate_max = 192000;
-       }
-
-       codec_dai->driver->playback.rates = rates;
-       codec_dai->driver->playback.rate_min = rate_min;
-       codec_dai->driver->playback.rate_max = rate_max;
        return 0;
 }
 
@@ -599,10 +606,7 @@ static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai,
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
-       u8 confb = snd_soc_read(codec, STA32X_CONFB);
-
-       pr_debug("\n");
-       confb &= ~(STA32X_CONFB_C1IM | STA32X_CONFB_C2IM);
+       u8 confb = 0;
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBS_CFS:
@@ -632,8 +636,8 @@ static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai,
                return -EINVAL;
        }
 
-       snd_soc_write(codec, STA32X_CONFB, confb);
-       return 0;
+       return regmap_update_bits(sta32x->regmap, STA32X_CONFB,
+                                 STA32X_CONFB_C1IM | STA32X_CONFB_C2IM, confb);
 }
 
 /**
@@ -651,39 +655,55 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_codec *codec = dai->codec;
        struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
-       unsigned int rate;
-       int i, mcs = -1, ir = -1;
-       u8 confa, confb;
+       int i, mcs = -EINVAL, ir = -EINVAL;
+       unsigned int confa, confb;
+       unsigned int rate, ratio;
+       int ret;
+
+       if (!sta32x->mclk) {
+               dev_err(codec->dev,
+                       "sta32x->mclk is unset. Unable to determine ratio\n");
+               return -EIO;
+       }
 
        rate = params_rate(params);
-       pr_debug("rate: %u\n", rate);
-       for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++)
+       ratio = sta32x->mclk / rate;
+       dev_dbg(codec->dev, "rate: %u, ratio: %u\n", rate, ratio);
+
+       for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) {
                if (interpolation_ratios[i].fs == rate) {
                        ir = interpolation_ratios[i].ir;
                        break;
                }
-       if (ir < 0)
+       }
+
+       if (ir < 0) {
+               dev_err(codec->dev, "Unsupported samplerate: %u\n", rate);
                return -EINVAL;
-       for (i = 0; mclk_ratios[ir][i].ratio; i++)
-               if (mclk_ratios[ir][i].ratio * rate == sta32x->mclk) {
-                       mcs = mclk_ratios[ir][i].mcs;
+       }
+
+       for (i = 0; i < 6; i++) {
+               if (mcs_ratio_table[ir][i] == ratio) {
+                       mcs = i;
                        break;
                }
-       if (mcs < 0)
+       }
+
+       if (mcs < 0) {
+               dev_err(codec->dev, "Unresolvable ratio: %u\n", ratio);
                return -EINVAL;
+       }
 
-       confa = snd_soc_read(codec, STA32X_CONFA);
-       confa &= ~(STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK);
-       confa |= (ir << STA32X_CONFA_IR_SHIFT) | (mcs << STA32X_CONFA_MCS_SHIFT);
+       confa = (ir << STA32X_CONFA_IR_SHIFT) |
+               (mcs << STA32X_CONFA_MCS_SHIFT);
+       confb = 0;
 
-       confb = snd_soc_read(codec, STA32X_CONFB);
-       confb &= ~(STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB);
        switch (params_width(params)) {
        case 24:
-               pr_debug("24bit\n");
+               dev_dbg(codec->dev, "24bit\n");
                /* fall through */
        case 32:
-               pr_debug("24bit or 32bit\n");
+               dev_dbg(codec->dev, "24bit or 32bit\n");
                switch (sta32x->format) {
                case SND_SOC_DAIFMT_I2S:
                        confb |= 0x0;
@@ -698,7 +718,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
 
                break;
        case 20:
-               pr_debug("20bit\n");
+               dev_dbg(codec->dev, "20bit\n");
                switch (sta32x->format) {
                case SND_SOC_DAIFMT_I2S:
                        confb |= 0x4;
@@ -713,7 +733,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
 
                break;
        case 18:
-               pr_debug("18bit\n");
+               dev_dbg(codec->dev, "18bit\n");
                switch (sta32x->format) {
                case SND_SOC_DAIFMT_I2S:
                        confb |= 0x8;
@@ -728,7 +748,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
 
                break;
        case 16:
-               pr_debug("16bit\n");
+               dev_dbg(codec->dev, "16bit\n");
                switch (sta32x->format) {
                case SND_SOC_DAIFMT_I2S:
                        confb |= 0x0;
@@ -746,8 +766,30 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       snd_soc_write(codec, STA32X_CONFA, confa);
-       snd_soc_write(codec, STA32X_CONFB, confb);
+       ret = regmap_update_bits(sta32x->regmap, STA32X_CONFA,
+                                STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK,
+                                confa);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_update_bits(sta32x->regmap, STA32X_CONFB,
+                                STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB,
+                                confb);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int sta32x_startup_sequence(struct sta32x_priv *sta32x)
+{
+       if (sta32x->gpiod_nreset) {
+               gpiod_set_value(sta32x->gpiod_nreset, 0);
+               mdelay(1);
+               gpiod_set_value(sta32x->gpiod_nreset, 1);
+               mdelay(1);
+       }
+
        return 0;
 }
 
@@ -766,14 +808,14 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
        int ret;
        struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
 
-       pr_debug("level = %d\n", level);
+       dev_dbg(codec->dev, "level = %d\n", level);
        switch (level) {
        case SND_SOC_BIAS_ON:
                break;
 
        case SND_SOC_BIAS_PREPARE:
                /* Full power on */
-               snd_soc_update_bits(codec, STA32X_CONFF,
+               regmap_update_bits(sta32x->regmap, STA32X_CONFF,
                                    STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
                                    STA32X_CONFF_PWDN | STA32X_CONFF_EAPD);
                break;
@@ -788,25 +830,28 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
                                return ret;
                        }
 
+                       sta32x_startup_sequence(sta32x);
                        sta32x_cache_sync(codec);
                        sta32x_watchdog_start(sta32x);
                }
 
-               /* Power up to mute */
-               /* FIXME */
-               snd_soc_update_bits(codec, STA32X_CONFF,
-                                   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
-                                   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD);
+               /* Power down */
+               regmap_update_bits(sta32x->regmap, STA32X_CONFF,
+                                  STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
+                                  0);
 
                break;
 
        case SND_SOC_BIAS_OFF:
                /* The chip runs through the power down sequence for us. */
-               snd_soc_update_bits(codec, STA32X_CONFF,
-                                   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
-                                   STA32X_CONFF_PWDN);
+               regmap_update_bits(sta32x->regmap, STA32X_CONFF,
+                                  STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, 0);
                msleep(300);
                sta32x_watchdog_stop(sta32x);
+
+               if (sta32x->gpiod_nreset)
+                       gpiod_set_value(sta32x->gpiod_nreset, 0);
+
                regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies),
                                       sta32x->supplies);
                break;
@@ -822,7 +867,7 @@ static const struct snd_soc_dai_ops sta32x_dai_ops = {
 };
 
 static struct snd_soc_dai_driver sta32x_dai = {
-       .name = "STA32X",
+       .name = "sta32x-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -836,11 +881,8 @@ static struct snd_soc_dai_driver sta32x_dai = {
 static int sta32x_probe(struct snd_soc_codec *codec)
 {
        struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
+       struct sta32x_platform_data *pdata = sta32x->pdata;
        int i, ret = 0, thermal = 0;
-
-       sta32x->codec = codec;
-       sta32x->pdata = dev_get_platdata(codec->dev);
-
        ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
                                    sta32x->supplies);
        if (ret != 0) {
@@ -848,50 +890,73 @@ static int sta32x_probe(struct snd_soc_codec *codec)
                return ret;
        }
 
-       /* Chip documentation explicitly requires that the reset values
-        * of reserved register bits are left untouched.
-        * Write the register default value to cache for reserved registers,
-        * so the write to the these registers are suppressed by the cache
-        * restore code when it skips writes of default registers.
-        */
-       regcache_cache_only(sta32x->regmap, true);
-       snd_soc_write(codec, STA32X_CONFC, 0xc2);
-       snd_soc_write(codec, STA32X_CONFE, 0xc2);
-       snd_soc_write(codec, STA32X_CONFF, 0x5c);
-       snd_soc_write(codec, STA32X_MMUTE, 0x10);
-       snd_soc_write(codec, STA32X_AUTO1, 0x60);
-       snd_soc_write(codec, STA32X_AUTO3, 0x00);
-       snd_soc_write(codec, STA32X_C3CFG, 0x40);
-       regcache_cache_only(sta32x->regmap, false);
-
-       /* set thermal warning adjustment and recovery */
-       if (!(sta32x->pdata->thermal_conf & STA32X_THERMAL_ADJUSTMENT_ENABLE))
+       ret = sta32x_startup_sequence(sta32x);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to startup device\n");
+               return ret;
+       }
+
+       /* CONFA */
+       if (!pdata->thermal_warning_recovery)
                thermal |= STA32X_CONFA_TWAB;
-       if (!(sta32x->pdata->thermal_conf & STA32X_THERMAL_RECOVERY_ENABLE))
+       if (!pdata->thermal_warning_adjustment)
                thermal |= STA32X_CONFA_TWRB;
-       snd_soc_update_bits(codec, STA32X_CONFA,
-                           STA32X_CONFA_TWAB | STA32X_CONFA_TWRB,
-                           thermal);
+       if (!pdata->fault_detect_recovery)
+               thermal |= STA32X_CONFA_FDRB;
+       regmap_update_bits(sta32x->regmap, STA32X_CONFA,
+                          STA32X_CONFA_TWAB | STA32X_CONFA_TWRB |
+                          STA32X_CONFA_FDRB,
+                          thermal);
+
+       /* CONFC */
+       regmap_update_bits(sta32x->regmap, STA32X_CONFC,
+                          STA32X_CONFC_CSZ_MASK,
+                          pdata->drop_compensation_ns
+                               << STA32X_CONFC_CSZ_SHIFT);
+
+       /* CONFE */
+       regmap_update_bits(sta32x->regmap, STA32X_CONFE,
+                          STA32X_CONFE_MPCV,
+                          pdata->max_power_use_mpcc ?
+                               STA32X_CONFE_MPCV : 0);
+       regmap_update_bits(sta32x->regmap, STA32X_CONFE,
+                          STA32X_CONFE_MPC,
+                          pdata->max_power_correction ?
+                               STA32X_CONFE_MPC : 0);
+       regmap_update_bits(sta32x->regmap, STA32X_CONFE,
+                          STA32X_CONFE_AME,
+                          pdata->am_reduction_mode ?
+                               STA32X_CONFE_AME : 0);
+       regmap_update_bits(sta32x->regmap, STA32X_CONFE,
+                          STA32X_CONFE_PWMS,
+                          pdata->odd_pwm_speed_mode ?
+                               STA32X_CONFE_PWMS : 0);
+
+       /*  CONFF */
+       regmap_update_bits(sta32x->regmap, STA32X_CONFF,
+                          STA32X_CONFF_IDE,
+                          pdata->invalid_input_detect_mute ?
+                               STA32X_CONFF_IDE : 0);
 
        /* select output configuration  */
-       snd_soc_update_bits(codec, STA32X_CONFF,
-                           STA32X_CONFF_OCFG_MASK,
-                           sta32x->pdata->output_conf
-                           << STA32X_CONFF_OCFG_SHIFT);
+       regmap_update_bits(sta32x->regmap, STA32X_CONFF,
+                          STA32X_CONFF_OCFG_MASK,
+                          pdata->output_conf
+                               << STA32X_CONFF_OCFG_SHIFT);
 
        /* channel to output mapping */
-       snd_soc_update_bits(codec, STA32X_C1CFG,
-                           STA32X_CxCFG_OM_MASK,
-                           sta32x->pdata->ch1_output_mapping
-                           << STA32X_CxCFG_OM_SHIFT);
-       snd_soc_update_bits(codec, STA32X_C2CFG,
-                           STA32X_CxCFG_OM_MASK,
-                           sta32x->pdata->ch2_output_mapping
-                           << STA32X_CxCFG_OM_SHIFT);
-       snd_soc_update_bits(codec, STA32X_C3CFG,
-                           STA32X_CxCFG_OM_MASK,
-                           sta32x->pdata->ch3_output_mapping
-                           << STA32X_CxCFG_OM_SHIFT);
+       regmap_update_bits(sta32x->regmap, STA32X_C1CFG,
+                          STA32X_CxCFG_OM_MASK,
+                          pdata->ch1_output_mapping
+                               << STA32X_CxCFG_OM_SHIFT);
+       regmap_update_bits(sta32x->regmap, STA32X_C2CFG,
+                          STA32X_CxCFG_OM_MASK,
+                          pdata->ch2_output_mapping
+                               << STA32X_CxCFG_OM_SHIFT);
+       regmap_update_bits(sta32x->regmap, STA32X_C3CFG,
+                          STA32X_CxCFG_OM_MASK,
+                          pdata->ch3_output_mapping
+                               << STA32X_CxCFG_OM_SHIFT);
 
        /* initialize coefficient shadow RAM with reset values */
        for (i = 4; i <= 49; i += 5)
@@ -924,16 +989,6 @@ static int sta32x_remove(struct snd_soc_codec *codec)
        return 0;
 }
 
-static bool sta32x_reg_is_volatile(struct device *dev, unsigned int reg)
-{
-       switch (reg) {
-       case STA32X_CONFA ... STA32X_L2ATRT:
-       case STA32X_MPCC1 ... STA32X_FDRC2:
-               return 0;
-       }
-       return 1;
-}
-
 static const struct snd_soc_codec_driver sta32x_codec = {
        .probe =                sta32x_probe,
        .remove =               sta32x_remove,
@@ -954,12 +1009,75 @@ static const struct regmap_config sta32x_regmap = {
        .reg_defaults =         sta32x_regs,
        .num_reg_defaults =     ARRAY_SIZE(sta32x_regs),
        .cache_type =           REGCACHE_RBTREE,
-       .volatile_reg =         sta32x_reg_is_volatile,
+       .wr_table =             &sta32x_write_regs,
+       .rd_table =             &sta32x_read_regs,
+       .volatile_table =       &sta32x_volatile_regs,
 };
 
+#ifdef CONFIG_OF
+static const struct of_device_id st32x_dt_ids[] = {
+       { .compatible = "st,sta32x", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, st32x_dt_ids);
+
+static int sta32x_probe_dt(struct device *dev, struct sta32x_priv *sta32x)
+{
+       struct device_node *np = dev->of_node;
+       struct sta32x_platform_data *pdata;
+       u16 tmp;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+
+       of_property_read_u8(np, "st,output-conf",
+                           &pdata->output_conf);
+       of_property_read_u8(np, "st,ch1-output-mapping",
+                           &pdata->ch1_output_mapping);
+       of_property_read_u8(np, "st,ch2-output-mapping",
+                           &pdata->ch2_output_mapping);
+       of_property_read_u8(np, "st,ch3-output-mapping",
+                           &pdata->ch3_output_mapping);
+
+       if (of_get_property(np, "st,thermal-warning-recovery", NULL))
+               pdata->thermal_warning_recovery = 1;
+       if (of_get_property(np, "st,thermal-warning-adjustment", NULL))
+               pdata->thermal_warning_adjustment = 1;
+       if (of_get_property(np, "st,needs_esd_watchdog", NULL))
+               pdata->needs_esd_watchdog = 1;
+
+       tmp = 140;
+       of_property_read_u16(np, "st,drop-compensation-ns", &tmp);
+       pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20;
+
+       /* CONFE */
+       if (of_get_property(np, "st,max-power-use-mpcc", NULL))
+               pdata->max_power_use_mpcc = 1;
+
+       if (of_get_property(np, "st,max-power-correction", NULL))
+               pdata->max_power_correction = 1;
+
+       if (of_get_property(np, "st,am-reduction-mode", NULL))
+               pdata->am_reduction_mode = 1;
+
+       if (of_get_property(np, "st,odd-pwm-speed-mode", NULL))
+               pdata->odd_pwm_speed_mode = 1;
+
+       /* CONFF */
+       if (of_get_property(np, "st,invalid-input-detect-mute", NULL))
+               pdata->invalid_input_detect_mute = 1;
+
+       sta32x->pdata = pdata;
+
+       return 0;
+}
+#endif
+
 static int sta32x_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
+       struct device *dev = &i2c->dev;
        struct sta32x_priv *sta32x;
        int ret, i;
 
@@ -968,6 +1086,29 @@ static int sta32x_i2c_probe(struct i2c_client *i2c,
        if (!sta32x)
                return -ENOMEM;
 
+       mutex_init(&sta32x->coeff_lock);
+       sta32x->pdata = dev_get_platdata(dev);
+
+#ifdef CONFIG_OF
+       if (dev->of_node) {
+               ret = sta32x_probe_dt(dev, sta32x);
+               if (ret < 0)
+                       return ret;
+       }
+#endif
+
+       /* GPIOs */
+       sta32x->gpiod_nreset = devm_gpiod_get(dev, "reset");
+       if (IS_ERR(sta32x->gpiod_nreset)) {
+               ret = PTR_ERR(sta32x->gpiod_nreset);
+               if (ret != -ENOENT && ret != -ENOSYS)
+                       return ret;
+
+               sta32x->gpiod_nreset = NULL;
+       } else {
+               gpiod_direction_output(sta32x->gpiod_nreset, 0);
+       }
+
        /* regulators */
        for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++)
                sta32x->supplies[i].supply = sta32x_supply_names[i];
@@ -982,15 +1123,15 @@ static int sta32x_i2c_probe(struct i2c_client *i2c,
        sta32x->regmap = devm_regmap_init_i2c(i2c, &sta32x_regmap);
        if (IS_ERR(sta32x->regmap)) {
                ret = PTR_ERR(sta32x->regmap);
-               dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
+               dev_err(dev, "Failed to init regmap: %d\n", ret);
                return ret;
        }
 
        i2c_set_clientdata(i2c, sta32x);
 
-       ret = snd_soc_register_codec(&i2c->dev, &sta32x_codec, &sta32x_dai, 1);
-       if (ret != 0)
-               dev_err(&i2c->dev, "Failed to register codec (%d)\n", ret);
+       ret = snd_soc_register_codec(dev, &sta32x_codec, &sta32x_dai, 1);
+       if (ret < 0)
+               dev_err(dev, "Failed to register codec (%d)\n", ret);
 
        return ret;
 }
@@ -1013,6 +1154,7 @@ static struct i2c_driver sta32x_i2c_driver = {
        .driver = {
                .name = "sta32x",
                .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(st32x_dt_ids),
        },
        .probe =    sta32x_i2c_probe,
        .remove =   sta32x_i2c_remove,
index d8e32a6262ee087ec13e73d24e57b936eefaa42b..d3191c983d712b5c02fb8a94733b75c21cb6b447 100644 (file)
 #define STA32X_CONFF_OCFG_MASK 0x03
 #define STA32X_CONFF_OCFG_SHIFT        0
 #define STA32X_CONFF_IDE       0x04
-#define STA32X_CONFF_IDE_SHIFT 3
+#define STA32X_CONFF_IDE_SHIFT 2
 #define STA32X_CONFF_BCLE      0x08
 #define STA32X_CONFF_ECLE      0x20
 #define STA32X_CONFF_PWDN      0x40
index dc3223d6eca1884a0faa44f9510e1ecb946ceae2..c86dd9aae1576670925b0ae1ce4b7959e5f199e4 100644 (file)
@@ -349,7 +349,8 @@ static int aic31xx_wait_bits(struct aic31xx_priv *aic31xx, unsigned int reg,
 static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
                                    struct snd_kcontrol *kcontrol, int event)
 {
-       struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
        unsigned int reg = AIC31XX_DACFLAG1;
        unsigned int mask;
 
@@ -377,7 +378,7 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
                reg = AIC31XX_ADCFLAG;
                break;
        default:
-               dev_err(w->codec->dev, "Unknown widget '%s' calling %s\n",
+               dev_err(codec->dev, "Unknown widget '%s' calling %s\n",
                        w->name, __func__);
                return -EINVAL;
        }
@@ -388,7 +389,7 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
        case SND_SOC_DAPM_POST_PMD:
                return aic31xx_wait_bits(aic31xx, reg, mask, 0, 5000, 100);
        default:
-               dev_dbg(w->codec->dev,
+               dev_dbg(codec->dev,
                        "Unhandled dapm widget event %d from %s\n",
                        event, w->name);
        }
@@ -433,7 +434,7 @@ static const struct snd_kcontrol_new aic31xx_dapm_spr_switch =
 static int mic_bias_event(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
index dd222b10ce132bfdfd15aecc06f19fca41e1bd7f..51c4713ac6e39059efbb6d296be7ee3527435649 100644 (file)
@@ -87,6 +87,7 @@ struct aic3x_priv {
 #define AIC3X_MODEL_3X 0
 #define AIC3X_MODEL_33 1
 #define AIC3X_MODEL_3007 2
+#define AIC3X_MODEL_3104 3
        u16 model;
 
        /* Selects the micbias voltage */
@@ -197,7 +198,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
 static int mic_bias_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -316,52 +317,37 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
         * only for swapped L-to-R and R-to-L routes. See below stereo controls
         * for direct L-to-L and R-to-R routes.
         */
-       SOC_SINGLE_TLV("Left Line Mixer Line2R Bypass Volume",
-                      LINE2R_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Left Line Mixer PGAR Bypass Volume",
                       PGAR_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Left Line Mixer DACR1 Playback Volume",
                       DACR1_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
 
-       SOC_SINGLE_TLV("Right Line Mixer Line2L Bypass Volume",
-                      LINE2L_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Right Line Mixer PGAL Bypass Volume",
                       PGAL_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Right Line Mixer DACL1 Playback Volume",
                       DACL1_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
 
-       SOC_SINGLE_TLV("Left HP Mixer Line2R Bypass Volume",
-                      LINE2R_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Left HP Mixer PGAR Bypass Volume",
                       PGAR_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Left HP Mixer DACR1 Playback Volume",
                       DACR1_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
 
-       SOC_SINGLE_TLV("Right HP Mixer Line2L Bypass Volume",
-                      LINE2L_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Right HP Mixer PGAL Bypass Volume",
                       PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Right HP Mixer DACL1 Playback Volume",
                       DACL1_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
 
-       SOC_SINGLE_TLV("Left HPCOM Mixer Line2R Bypass Volume",
-                      LINE2R_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Left HPCOM Mixer PGAR Bypass Volume",
                       PGAR_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Left HPCOM Mixer DACR1 Playback Volume",
                       DACR1_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
 
-       SOC_SINGLE_TLV("Right HPCOM Mixer Line2L Bypass Volume",
-                      LINE2L_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Right HPCOM Mixer PGAL Bypass Volume",
                       PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Right HPCOM Mixer DACL1 Playback Volume",
                       DACL1_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
 
        /* Stereo output controls for direct L-to-L and R-to-R routes */
-       SOC_DOUBLE_R_TLV("Line Line2 Bypass Volume",
-                        LINE2L_2_LLOPM_VOL, LINE2R_2_RLOPM_VOL,
-                        0, 118, 1, output_stage_tlv),
        SOC_DOUBLE_R_TLV("Line PGA Bypass Volume",
                         PGAL_2_LLOPM_VOL, PGAR_2_RLOPM_VOL,
                         0, 118, 1, output_stage_tlv),
@@ -369,9 +355,6 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
                         DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL,
                         0, 118, 1, output_stage_tlv),
 
-       SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume",
-                        LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
-                        0, 118, 1, output_stage_tlv),
        SOC_DOUBLE_R_TLV("HP PGA Bypass Volume",
                         PGAL_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL,
                         0, 118, 1, output_stage_tlv),
@@ -379,9 +362,6 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
                         DACL1_2_HPLOUT_VOL, DACR1_2_HPROUT_VOL,
                         0, 118, 1, output_stage_tlv),
 
-       SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Volume",
-                        LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL,
-                        0, 118, 1, output_stage_tlv),
        SOC_DOUBLE_R_TLV("HPCOM PGA Bypass Volume",
                         PGAL_2_HPLCOM_VOL, PGAR_2_HPRCOM_VOL,
                         0, 118, 1, output_stage_tlv),
@@ -424,6 +404,45 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
        SOC_ENUM("Output Driver Ramp-up step", aic3x_rampup_step_enum),
 };
 
+/* For other than tlv320aic3104 */
+static const struct snd_kcontrol_new aic3x_extra_snd_controls[] = {
+       /*
+        * Output controls that map to output mixer switches. Note these are
+        * only for swapped L-to-R and R-to-L routes. See below stereo controls
+        * for direct L-to-L and R-to-R routes.
+        */
+       SOC_SINGLE_TLV("Left Line Mixer Line2R Bypass Volume",
+                      LINE2R_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
+
+       SOC_SINGLE_TLV("Right Line Mixer Line2L Bypass Volume",
+                      LINE2L_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
+
+       SOC_SINGLE_TLV("Left HP Mixer Line2R Bypass Volume",
+                      LINE2R_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
+
+       SOC_SINGLE_TLV("Right HP Mixer Line2L Bypass Volume",
+                      LINE2L_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
+
+       SOC_SINGLE_TLV("Left HPCOM Mixer Line2R Bypass Volume",
+                      LINE2R_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
+
+       SOC_SINGLE_TLV("Right HPCOM Mixer Line2L Bypass Volume",
+                      LINE2L_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
+
+       /* Stereo output controls for direct L-to-L and R-to-R routes */
+       SOC_DOUBLE_R_TLV("Line Line2 Bypass Volume",
+                        LINE2L_2_LLOPM_VOL, LINE2R_2_RLOPM_VOL,
+                        0, 118, 1, output_stage_tlv),
+
+       SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume",
+                        LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
+                        0, 118, 1, output_stage_tlv),
+
+       SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Volume",
+                        LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL,
+                        0, 118, 1, output_stage_tlv),
+};
+
 static const struct snd_kcontrol_new aic3x_mono_controls[] = {
        SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume",
                         LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
@@ -464,22 +483,24 @@ SOC_DAPM_ENUM("Route", aic3x_right_hpcom_enum);
 
 /* Left Line Mixer */
 static const struct snd_kcontrol_new aic3x_left_line_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_LLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_LLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_LLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_LLOPM_VOL, 7, 1, 0),
+       /* Not on tlv320aic3104 */
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0),
 };
 
 /* Right Line Mixer */
 static const struct snd_kcontrol_new aic3x_right_line_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_RLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_RLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_RLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_RLOPM_VOL, 7, 1, 0),
+       /* Not on tlv320aic3104 */
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
 };
 
 /* Mono Mixer */
@@ -494,42 +515,46 @@ static const struct snd_kcontrol_new aic3x_mono_mixer_controls[] = {
 
 /* Left HP Mixer */
 static const struct snd_kcontrol_new aic3x_left_hp_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLOUT_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLOUT_VOL, 7, 1, 0),
+       /* Not on tlv320aic3104 */
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLOUT_VOL, 7, 1, 0),
 };
 
 /* Right HP Mixer */
 static const struct snd_kcontrol_new aic3x_right_hp_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPROUT_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPROUT_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPROUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPROUT_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPROUT_VOL, 7, 1, 0),
+       /* Not on tlv320aic3104 */
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPROUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
 };
 
 /* Left HPCOM Mixer */
 static const struct snd_kcontrol_new aic3x_left_hpcom_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLCOM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLCOM_VOL, 7, 1, 0),
+       /* Not on tlv320aic3104 */
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLCOM_VOL, 7, 1, 0),
 };
 
 /* Right HPCOM Mixer */
 static const struct snd_kcontrol_new aic3x_right_hpcom_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPRCOM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPRCOM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0),
+       /* Not on tlv320aic3104 */
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPRCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
 };
 
 /* Left PGA Mixer */
@@ -550,6 +575,22 @@ static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = {
        SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1),
 };
 
+/* Left PGA Mixer for tlv320aic3104 */
+static const struct snd_kcontrol_new aic3104_left_pga_mixer_controls[] = {
+       SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1),
+       SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_LADC_CTRL, 3, 1, 1),
+       SOC_DAPM_SINGLE_AIC3X("Mic2L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1),
+       SOC_DAPM_SINGLE_AIC3X("Mic2R Switch", MIC3LR_2_LADC_CTRL, 0, 1, 1),
+};
+
+/* Right PGA Mixer for tlv320aic3104 */
+static const struct snd_kcontrol_new aic3104_right_pga_mixer_controls[] = {
+       SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1),
+       SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_RADC_CTRL, 3, 1, 1),
+       SOC_DAPM_SINGLE_AIC3X("Mic2L Switch", MIC3LR_2_RADC_CTRL, 4, 1, 1),
+       SOC_DAPM_SINGLE_AIC3X("Mic2R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1),
+};
+
 /* Left Line1 Mux */
 static const struct snd_kcontrol_new aic3x_left_line1l_mux_controls =
 SOC_DAPM_ENUM("Route", aic3x_line1l_2_l_enum);
@@ -593,26 +634,56 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
 
        /* Inputs to Left ADC */
        SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0),
-       SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
-                          &aic3x_left_pga_mixer_controls[0],
-                          ARRAY_SIZE(aic3x_left_pga_mixer_controls)),
        SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_left_line1l_mux_controls),
        SND_SOC_DAPM_MUX("Left Line1R Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_left_line1r_mux_controls),
-       SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0,
-                        &aic3x_left_line2_mux_controls),
 
        /* Inputs to Right ADC */
        SND_SOC_DAPM_ADC("Right ADC", "Right Capture",
                         LINE1R_2_RADC_CTRL, 2, 0),
-       SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0,
-                          &aic3x_right_pga_mixer_controls[0],
-                          ARRAY_SIZE(aic3x_right_pga_mixer_controls)),
        SND_SOC_DAPM_MUX("Right Line1L Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_right_line1l_mux_controls),
        SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_right_line1r_mux_controls),
+
+       /* Mic Bias */
+       SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0,
+                        mic_bias_event,
+                        SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+       SND_SOC_DAPM_OUTPUT("LLOUT"),
+       SND_SOC_DAPM_OUTPUT("RLOUT"),
+       SND_SOC_DAPM_OUTPUT("HPLOUT"),
+       SND_SOC_DAPM_OUTPUT("HPROUT"),
+       SND_SOC_DAPM_OUTPUT("HPLCOM"),
+       SND_SOC_DAPM_OUTPUT("HPRCOM"),
+
+       SND_SOC_DAPM_INPUT("LINE1L"),
+       SND_SOC_DAPM_INPUT("LINE1R"),
+
+       /*
+        * Virtual output pin to detection block inside codec. This can be
+        * used to keep codec bias on if gpio or detection features are needed.
+        * Force pin on or construct a path with an input jack and mic bias
+        * widgets.
+        */
+       SND_SOC_DAPM_OUTPUT("Detection"),
+};
+
+/* For other than tlv320aic3104 */
+static const struct snd_soc_dapm_widget aic3x_extra_dapm_widgets[] = {
+       /* Inputs to Left ADC */
+       SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_left_pga_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_left_pga_mixer_controls)),
+       SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0,
+                        &aic3x_left_line2_mux_controls),
+
+       /* Inputs to Right ADC */
+       SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_right_pga_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_right_pga_mixer_controls)),
        SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_right_line2_mux_controls),
 
@@ -637,11 +708,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
        SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 32",
                         AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0),
 
-       /* Mic Bias */
-       SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0,
-                        mic_bias_event,
-                        SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
-
        /* Output mixers */
        SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0,
                           &aic3x_left_line_mixer_controls[0],
@@ -662,27 +728,46 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
                           &aic3x_right_hpcom_mixer_controls[0],
                           ARRAY_SIZE(aic3x_right_hpcom_mixer_controls)),
 
-       SND_SOC_DAPM_OUTPUT("LLOUT"),
-       SND_SOC_DAPM_OUTPUT("RLOUT"),
-       SND_SOC_DAPM_OUTPUT("HPLOUT"),
-       SND_SOC_DAPM_OUTPUT("HPROUT"),
-       SND_SOC_DAPM_OUTPUT("HPLCOM"),
-       SND_SOC_DAPM_OUTPUT("HPRCOM"),
-
        SND_SOC_DAPM_INPUT("MIC3L"),
        SND_SOC_DAPM_INPUT("MIC3R"),
-       SND_SOC_DAPM_INPUT("LINE1L"),
-       SND_SOC_DAPM_INPUT("LINE1R"),
        SND_SOC_DAPM_INPUT("LINE2L"),
        SND_SOC_DAPM_INPUT("LINE2R"),
+};
 
-       /*
-        * Virtual output pin to detection block inside codec. This can be
-        * used to keep codec bias on if gpio or detection features are needed.
-        * Force pin on or construct a path with an input jack and mic bias
-        * widgets.
-        */
-       SND_SOC_DAPM_OUTPUT("Detection"),
+/* For tlv320aic3104 */
+static const struct snd_soc_dapm_widget aic3104_extra_dapm_widgets[] = {
+       /* Inputs to Left ADC */
+       SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3104_left_pga_mixer_controls[0],
+                          ARRAY_SIZE(aic3104_left_pga_mixer_controls)),
+
+       /* Inputs to Right ADC */
+       SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3104_right_pga_mixer_controls[0],
+                          ARRAY_SIZE(aic3104_right_pga_mixer_controls)),
+
+       /* Output mixers */
+       SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_left_line_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_left_line_mixer_controls) - 2),
+       SND_SOC_DAPM_MIXER("Right Line Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_right_line_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_right_line_mixer_controls) - 2),
+       SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_left_hp_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_left_hp_mixer_controls) - 2),
+       SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_right_hp_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_right_hp_mixer_controls) - 2),
+       SND_SOC_DAPM_MIXER("Left HPCOM Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_left_hpcom_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_left_hpcom_mixer_controls) - 2),
+       SND_SOC_DAPM_MIXER("Right HPCOM Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_right_hpcom_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_right_hpcom_mixer_controls) - 2),
+
+       SND_SOC_DAPM_INPUT("MIC2L"),
+       SND_SOC_DAPM_INPUT("MIC2R"),
 };
 
 static const struct snd_soc_dapm_widget aic3x_dapm_mono_widgets[] = {
@@ -712,17 +797,10 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Left Line1R Mux", "single-ended", "LINE1R"},
        {"Left Line1R Mux", "differential", "LINE1R"},
 
-       {"Left Line2L Mux", "single-ended", "LINE2L"},
-       {"Left Line2L Mux", "differential", "LINE2L"},
-
        {"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"},
        {"Left PGA Mixer", "Line1R Switch", "Left Line1R Mux"},
-       {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"},
-       {"Left PGA Mixer", "Mic3L Switch", "MIC3L"},
-       {"Left PGA Mixer", "Mic3R Switch", "MIC3R"},
 
        {"Left ADC", NULL, "Left PGA Mixer"},
-       {"Left ADC", NULL, "GPIO1 dmic modclk"},
 
        /* Right Input */
        {"Right Line1R Mux", "single-ended", "LINE1R"},
@@ -730,25 +808,10 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Right Line1L Mux", "single-ended", "LINE1L"},
        {"Right Line1L Mux", "differential", "LINE1L"},
 
-       {"Right Line2R Mux", "single-ended", "LINE2R"},
-       {"Right Line2R Mux", "differential", "LINE2R"},
-
        {"Right PGA Mixer", "Line1L Switch", "Right Line1L Mux"},
        {"Right PGA Mixer", "Line1R Switch", "Right Line1R Mux"},
-       {"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"},
-       {"Right PGA Mixer", "Mic3L Switch", "MIC3L"},
-       {"Right PGA Mixer", "Mic3R Switch", "MIC3R"},
 
        {"Right ADC", NULL, "Right PGA Mixer"},
-       {"Right ADC", NULL, "GPIO1 dmic modclk"},
-
-       /*
-        * Logical path between digital mic enable and GPIO1 modulator clock
-        * output function
-        */
-       {"GPIO1 dmic modclk", NULL, "DMic Rate 128"},
-       {"GPIO1 dmic modclk", NULL, "DMic Rate 64"},
-       {"GPIO1 dmic modclk", NULL, "DMic Rate 32"},
 
        /* Left DAC Output */
        {"Left DAC Mux", "DAC_L1", "Left DAC"},
@@ -761,10 +824,8 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Right DAC Mux", "DAC_R3", "Right DAC"},
 
        /* Left Line Output */
-       {"Left Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
        {"Left Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
        {"Left Line Mixer", "DACL1 Switch", "Left DAC Mux"},
-       {"Left Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
        {"Left Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
        {"Left Line Mixer", "DACR1 Switch", "Right DAC Mux"},
 
@@ -773,10 +834,8 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"LLOUT", NULL, "Left Line Out"},
 
        /* Right Line Output */
-       {"Right Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
        {"Right Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
        {"Right Line Mixer", "DACL1 Switch", "Left DAC Mux"},
-       {"Right Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
        {"Right Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
        {"Right Line Mixer", "DACR1 Switch", "Right DAC Mux"},
 
@@ -785,10 +844,8 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"RLOUT", NULL, "Right Line Out"},
 
        /* Left HP Output */
-       {"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
        {"Left HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
        {"Left HP Mixer", "DACL1 Switch", "Left DAC Mux"},
-       {"Left HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
        {"Left HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
        {"Left HP Mixer", "DACR1 Switch", "Right DAC Mux"},
 
@@ -797,10 +854,8 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"HPLOUT", NULL, "Left HP Out"},
 
        /* Right HP Output */
-       {"Right HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
        {"Right HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
        {"Right HP Mixer", "DACL1 Switch", "Left DAC Mux"},
-       {"Right HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
        {"Right HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
        {"Right HP Mixer", "DACR1 Switch", "Right DAC Mux"},
 
@@ -809,10 +864,8 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"HPROUT", NULL, "Right HP Out"},
 
        /* Left HPCOM Output */
-       {"Left HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
        {"Left HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
        {"Left HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"},
-       {"Left HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
        {"Left HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
        {"Left HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"},
 
@@ -823,10 +876,8 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"HPLCOM", NULL, "Left HP Com"},
 
        /* Right HPCOM Output */
-       {"Right HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
        {"Right HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
        {"Right HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"},
-       {"Right HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
        {"Right HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
        {"Right HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"},
 
@@ -839,6 +890,72 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"HPRCOM", NULL, "Right HP Com"},
 };
 
+/* For other than tlv320aic3104 */
+static const struct snd_soc_dapm_route intercon_extra[] = {
+       /* Left Input */
+       {"Left Line2L Mux", "single-ended", "LINE2L"},
+       {"Left Line2L Mux", "differential", "LINE2L"},
+
+       {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"},
+       {"Left PGA Mixer", "Mic3L Switch", "MIC3L"},
+       {"Left PGA Mixer", "Mic3R Switch", "MIC3R"},
+
+       {"Left ADC", NULL, "GPIO1 dmic modclk"},
+
+       /* Right Input */
+       {"Right Line2R Mux", "single-ended", "LINE2R"},
+       {"Right Line2R Mux", "differential", "LINE2R"},
+
+       {"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"},
+       {"Right PGA Mixer", "Mic3L Switch", "MIC3L"},
+       {"Right PGA Mixer", "Mic3R Switch", "MIC3R"},
+
+       {"Right ADC", NULL, "GPIO1 dmic modclk"},
+
+       /*
+        * Logical path between digital mic enable and GPIO1 modulator clock
+        * output function
+        */
+       {"GPIO1 dmic modclk", NULL, "DMic Rate 128"},
+       {"GPIO1 dmic modclk", NULL, "DMic Rate 64"},
+       {"GPIO1 dmic modclk", NULL, "DMic Rate 32"},
+
+       /* Left Line Output */
+       {"Left Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Left Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+
+       /* Right Line Output */
+       {"Right Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Right Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+
+       /* Left HP Output */
+       {"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Left HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+
+       /* Right HP Output */
+       {"Right HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Right HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+
+       /* Left HPCOM Output */
+       {"Left HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Left HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+
+       /* Right HPCOM Output */
+       {"Right HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Right HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+};
+
+/* For tlv320aic3104 */
+static const struct snd_soc_dapm_route intercon_extra_3104[] = {
+       /* Left Input */
+       {"Left PGA Mixer", "Mic2L Switch", "MIC2L"},
+       {"Left PGA Mixer", "Mic2R Switch", "MIC2R"},
+
+       /* Right Input */
+       {"Right PGA Mixer", "Mic2L Switch", "MIC2L"},
+       {"Right PGA Mixer", "Mic2R Switch", "MIC2R"},
+};
+
 static const struct snd_soc_dapm_route intercon_mono[] = {
        /* Mono Output */
        {"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
@@ -867,17 +984,31 @@ static int aic3x_add_widgets(struct snd_soc_codec *codec)
        switch (aic3x->model) {
        case AIC3X_MODEL_3X:
        case AIC3X_MODEL_33:
+               snd_soc_dapm_new_controls(dapm, aic3x_extra_dapm_widgets,
+                                         ARRAY_SIZE(aic3x_extra_dapm_widgets));
+               snd_soc_dapm_add_routes(dapm, intercon_extra,
+                                       ARRAY_SIZE(intercon_extra));
                snd_soc_dapm_new_controls(dapm, aic3x_dapm_mono_widgets,
                        ARRAY_SIZE(aic3x_dapm_mono_widgets));
                snd_soc_dapm_add_routes(dapm, intercon_mono,
                                        ARRAY_SIZE(intercon_mono));
                break;
        case AIC3X_MODEL_3007:
+               snd_soc_dapm_new_controls(dapm, aic3x_extra_dapm_widgets,
+                                         ARRAY_SIZE(aic3x_extra_dapm_widgets));
+               snd_soc_dapm_add_routes(dapm, intercon_extra,
+                                       ARRAY_SIZE(intercon_extra));
                snd_soc_dapm_new_controls(dapm, aic3007_dapm_widgets,
                        ARRAY_SIZE(aic3007_dapm_widgets));
                snd_soc_dapm_add_routes(dapm, intercon_3007,
                                        ARRAY_SIZE(intercon_3007));
                break;
+       case AIC3X_MODEL_3104:
+               snd_soc_dapm_new_controls(dapm, aic3104_extra_dapm_widgets,
+                               ARRAY_SIZE(aic3104_extra_dapm_widgets));
+               snd_soc_dapm_add_routes(dapm, intercon_extra_3104,
+                               ARRAY_SIZE(intercon_extra_3104));
+               break;
        }
 
        return 0;
@@ -1438,23 +1569,33 @@ static int aic3x_probe(struct snd_soc_codec *codec)
        aic3x_init(codec);
 
        if (aic3x->setup) {
-               /* setup GPIO functions */
-               snd_soc_write(codec, AIC3X_GPIO1_REG,
-                             (aic3x->setup->gpio_func[0] & 0xf) << 4);
-               snd_soc_write(codec, AIC3X_GPIO2_REG,
-                             (aic3x->setup->gpio_func[1] & 0xf) << 4);
+               if (aic3x->model != AIC3X_MODEL_3104) {
+                       /* setup GPIO functions */
+                       snd_soc_write(codec, AIC3X_GPIO1_REG,
+                                     (aic3x->setup->gpio_func[0] & 0xf) << 4);
+                       snd_soc_write(codec, AIC3X_GPIO2_REG,
+                                     (aic3x->setup->gpio_func[1] & 0xf) << 4);
+               } else {
+                       dev_warn(codec->dev, "GPIO functionality is not supported on tlv320aic3104\n");
+               }
        }
 
        switch (aic3x->model) {
        case AIC3X_MODEL_3X:
        case AIC3X_MODEL_33:
+               snd_soc_add_codec_controls(codec, aic3x_extra_snd_controls,
+                               ARRAY_SIZE(aic3x_extra_snd_controls));
                snd_soc_add_codec_controls(codec, aic3x_mono_controls,
                                ARRAY_SIZE(aic3x_mono_controls));
                break;
        case AIC3X_MODEL_3007:
+               snd_soc_add_codec_controls(codec, aic3x_extra_snd_controls,
+                               ARRAY_SIZE(aic3x_extra_snd_controls));
                snd_soc_add_codec_controls(codec,
                                &aic3x_classd_amp_gain_ctrl, 1);
                break;
+       case AIC3X_MODEL_3104:
+               break;
        }
 
        /* set mic bias voltage */
@@ -1522,6 +1663,7 @@ static const struct i2c_device_id aic3x_i2c_id[] = {
        { "tlv320aic33", AIC3X_MODEL_33 },
        { "tlv320aic3007", AIC3X_MODEL_3007 },
        { "tlv320aic3106", AIC3X_MODEL_3X },
+       { "tlv320aic3104", AIC3X_MODEL_3104 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
@@ -1673,6 +1815,7 @@ static const struct of_device_id tlv320aic3x_of_match[] = {
        { .compatible = "ti,tlv320aic33" },
        { .compatible = "ti,tlv320aic3007" },
        { .compatible = "ti,tlv320aic3106" },
+       { .compatible = "ti,tlv320aic3104" },
        {},
 };
 MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match);
index 0fe2ced5b09fc72324fd2e9ac89c1ec3cf0d06cb..4e3e607dec13085df4cbc4a3d198ae5cacf78c32 100644 (file)
@@ -423,17 +423,18 @@ exit:
 static int dac33_playback_event(struct snd_soc_dapm_widget *w,
                struct snd_kcontrol *kcontrol, int event)
 {
-       struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
                if (likely(dac33->substream)) {
-                       dac33_calculate_times(dac33->substream, w->codec);
-                       dac33_prepare_chip(dac33->substream, w->codec);
+                       dac33_calculate_times(dac33->substream, codec);
+                       dac33_prepare_chip(dac33->substream, codec);
                }
                break;
        case SND_SOC_DAPM_POST_PMD:
-               dac33_disable_digital(w->codec);
+               dac33_disable_digital(codec);
                break;
        }
        return 0;
index 9f2dced046de4b0ade76fcb8f088237f9443a643..9fd80ac1897f5b369bc14a0420c0b834da748343 100644 (file)
@@ -20,6 +20,8 @@
 #include <sound/jack.h>
 #include <sound/soc.h>
 
+#include "ts3a227e.h"
+
 struct ts3a227e {
        struct regmap *regmap;
        struct snd_soc_jack *jack;
@@ -79,6 +81,10 @@ static const int ts3a227e_buttons[] = {
 /* TS3A227E_REG_SETTING_2 0x05 */
 #define KP_ENABLE 0x04
 
+/* TS3A227E_REG_SETTING_3 0x06 */
+#define MICBIAS_SETTING_SFT (3)
+#define MICBIAS_SETTING_MASK (0x7 << MICBIAS_SETTING_SFT)
+
 /* TS3A227E_REG_ACCESSORY_STATUS  0x0b */
 #define TYPE_3_POLE 0x01
 #define TYPE_4_POLE_OMTP 0x02
@@ -221,9 +227,9 @@ int ts3a227e_enable_jack_detect(struct snd_soc_component *component,
        struct ts3a227e *ts3a227e = snd_soc_component_get_drvdata(component);
 
        snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA);
-       snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
-       snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
-       snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
 
        ts3a227e->jack = jack;
        ts3a227e_jack_report(ts3a227e);
@@ -248,6 +254,21 @@ static const struct regmap_config ts3a227e_regmap_config = {
        .num_reg_defaults = ARRAY_SIZE(ts3a227e_reg_defaults),
 };
 
+static int ts3a227e_parse_dt(struct ts3a227e *ts3a227e, struct device_node *np)
+{
+       u32 micbias;
+       int err;
+
+       err = of_property_read_u32(np, "ti,micbias", &micbias);
+       if (!err) {
+               regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_SETTING_3,
+                       MICBIAS_SETTING_MASK,
+                       (micbias & 0x07) << MICBIAS_SETTING_SFT);
+       }
+
+       return 0;
+}
+
 static int ts3a227e_i2c_probe(struct i2c_client *i2c,
                              const struct i2c_device_id *id)
 {
@@ -266,6 +287,14 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c,
        if (IS_ERR(ts3a227e->regmap))
                return PTR_ERR(ts3a227e->regmap);
 
+       if (dev->of_node) {
+               ret = ts3a227e_parse_dt(ts3a227e, dev->of_node);
+               if (ret) {
+                       dev_err(dev, "Failed to parse device tree: %d\n", ret);
+                       return ret;
+               }
+       }
+
        ret = devm_request_threaded_irq(dev, i2c->irq, NULL, ts3a227e_interrupt,
                                        IRQF_TRIGGER_LOW | IRQF_ONESHOT,
                                        "TS3A227E", ts3a227e);
index 44af3188afb9c6e50e9e097e4c97c0ffb15f4023..d04693e9cf9f8c9b362b212b04058e7fe6ee2278 100644 (file)
@@ -567,12 +567,13 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control =
 static int pin_name##pga_event(struct snd_soc_dapm_widget *w,          \
                               struct snd_kcontrol *kcontrol, int event) \
 {                                                                      \
-       struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); \
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);   \
+       struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); \
                                                                        \
        switch (event) {                                                \
        case SND_SOC_DAPM_POST_PMU:                                     \
                twl4030->pin_name##_enabled = 1;                        \
-               twl4030_write(w->codec, reg, twl4030_read(w->codec, reg)); \
+               twl4030_write(codec, reg, twl4030_read(codec, reg));    \
                break;                                                  \
        case SND_SOC_DAPM_POST_PMD:                                     \
                twl4030->pin_name##_enabled = 0;                        \
@@ -621,12 +622,14 @@ static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp)
 static int handsfreelpga_event(struct snd_soc_dapm_widget *w,
                               struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
-               handsfree_ramp(w->codec, TWL4030_REG_HFL_CTL, 1);
+               handsfree_ramp(codec, TWL4030_REG_HFL_CTL, 1);
                break;
        case SND_SOC_DAPM_POST_PMD:
-               handsfree_ramp(w->codec, TWL4030_REG_HFL_CTL, 0);
+               handsfree_ramp(codec, TWL4030_REG_HFL_CTL, 0);
                break;
        }
        return 0;
@@ -635,12 +638,14 @@ static int handsfreelpga_event(struct snd_soc_dapm_widget *w,
 static int handsfreerpga_event(struct snd_soc_dapm_widget *w,
                               struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
-               handsfree_ramp(w->codec, TWL4030_REG_HFR_CTL, 1);
+               handsfree_ramp(codec, TWL4030_REG_HFR_CTL, 1);
                break;
        case SND_SOC_DAPM_POST_PMD:
-               handsfree_ramp(w->codec, TWL4030_REG_HFR_CTL, 0);
+               handsfree_ramp(codec, TWL4030_REG_HFR_CTL, 0);
                break;
        }
        return 0;
@@ -649,19 +654,23 @@ static int handsfreerpga_event(struct snd_soc_dapm_widget *w,
 static int vibramux_event(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *kcontrol, int event)
 {
-       twl4030_write(w->codec, TWL4030_REG_VIBRA_SET, 0xff);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+       twl4030_write(codec, TWL4030_REG_VIBRA_SET, 0xff);
        return 0;
 }
 
 static int apll_event(struct snd_soc_dapm_widget *w,
                      struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
-               twl4030_apll_enable(w->codec, 1);
+               twl4030_apll_enable(codec, 1);
                break;
        case SND_SOC_DAPM_POST_PMD:
-               twl4030_apll_enable(w->codec, 0);
+               twl4030_apll_enable(codec, 0);
                break;
        }
        return 0;
@@ -670,23 +679,24 @@ static int apll_event(struct snd_soc_dapm_widget *w,
 static int aif_event(struct snd_soc_dapm_widget *w,
                     struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        u8 audio_if;
 
-       audio_if = twl4030_read(w->codec, TWL4030_REG_AUDIO_IF);
+       audio_if = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
                /* Enable AIF */
                /* enable the PLL before we use it to clock the DAI */
-               twl4030_apll_enable(w->codec, 1);
+               twl4030_apll_enable(codec, 1);
 
-               twl4030_write(w->codec, TWL4030_REG_AUDIO_IF,
+               twl4030_write(codec, TWL4030_REG_AUDIO_IF,
                              audio_if | TWL4030_AIF_EN);
                break;
        case SND_SOC_DAPM_POST_PMD:
                /* disable the DAI before we stop it's source PLL */
-               twl4030_write(w->codec, TWL4030_REG_AUDIO_IF,
+               twl4030_write(codec, TWL4030_REG_AUDIO_IF,
                              audio_if &  ~TWL4030_AIF_EN);
-               twl4030_apll_enable(w->codec, 0);
+               twl4030_apll_enable(codec, 0);
                break;
        }
        return 0;
@@ -758,20 +768,21 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 static int headsetlpga_event(struct snd_soc_dapm_widget *w,
                             struct snd_kcontrol *kcontrol, int event)
 {
-       struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                /* Do the ramp-up only once */
                if (!twl4030->hsr_enabled)
-                       headset_ramp(w->codec, 1);
+                       headset_ramp(codec, 1);
 
                twl4030->hsl_enabled = 1;
                break;
        case SND_SOC_DAPM_POST_PMD:
                /* Do the ramp-down only if both headsetL/R is disabled */
                if (!twl4030->hsr_enabled)
-                       headset_ramp(w->codec, 0);
+                       headset_ramp(codec, 0);
 
                twl4030->hsl_enabled = 0;
                break;
@@ -782,20 +793,21 @@ static int headsetlpga_event(struct snd_soc_dapm_widget *w,
 static int headsetrpga_event(struct snd_soc_dapm_widget *w,
                             struct snd_kcontrol *kcontrol, int event)
 {
-       struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                /* Do the ramp-up only once */
                if (!twl4030->hsl_enabled)
-                       headset_ramp(w->codec, 1);
+                       headset_ramp(codec, 1);
 
                twl4030->hsr_enabled = 1;
                break;
        case SND_SOC_DAPM_POST_PMD:
                /* Do the ramp-down only if both headsetL/R is disabled */
                if (!twl4030->hsl_enabled)
-                       headset_ramp(w->codec, 0);
+                       headset_ramp(codec, 0);
 
                twl4030->hsr_enabled = 0;
                break;
@@ -806,7 +818,8 @@ static int headsetrpga_event(struct snd_soc_dapm_widget *w,
 static int digimic_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
-       struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        struct twl4030_codec_data *pdata = twl4030->pdata;
 
        if (pdata && pdata->digimic_delay)
index 90f47f988b3fe3b1e28321df538c1ba2f7d9bb4f..aeec27b6f1af76aca729aacd35e872b01eb05362 100644 (file)
@@ -234,7 +234,7 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
 static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
                        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        u8 hslctl, hsrctl;
 
        /*
@@ -261,7 +261,7 @@ static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
 static int twl6040_ep_drv_event(struct snd_soc_dapm_widget *w,
                        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
 
index 34ef65c52a7d9425e84a6c9ba475f5cfdb664ea9..8d9de49a50524bb4e88ebd62cb580e17239b07d6 100644 (file)
@@ -683,7 +683,7 @@ static const struct snd_kcontrol_new wm2000_controls[] = {
 static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w,
                                  struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
        int ret;
 
index b80970dc2d2f14c9edbbe2e333f65843f0e33b88..ea09db585aa1fd266f391aadbde5fa78c71318db 100644 (file)
@@ -775,7 +775,8 @@ static int wm5100_out_ev(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol,
                         int event)
 {
-       struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
 
        switch (w->reg) {
        case WM5100_CHANNEL_ENABLES_1:
@@ -839,7 +840,7 @@ static int wm5100_post_ev(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *kcontrol,
                          int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
index f439ae052128c145c3f65d09f42d1531bdfe89a0..6d0fe0ac95a3f6121d87c52cfa4f17f6ec844651 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <linux/mfd/arizona/core.h>
 #include <linux/mfd/arizona/registers.h>
+#include <asm/unaligned.h>
 
 #include "arizona.h"
 #include "wm5102.h"
@@ -580,7 +581,7 @@ static const struct reg_default wm5102_sysclk_revb_patch[] = {
 static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
                            struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
        struct regmap *regmap = arizona->regmap;
        const struct reg_default *patch = NULL;
@@ -617,11 +618,10 @@ static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
-       uint16_t data;
 
        mutex_lock(&arizona->dac_comp_lock);
-       data = cpu_to_be16(arizona->dac_comp_coeff);
-       memcpy(ucontrol->value.bytes.data, &data, sizeof(data));
+       put_unaligned_be16(arizona->dac_comp_coeff,
+                          ucontrol->value.bytes.data);
        mutex_unlock(&arizona->dac_comp_lock);
 
        return 0;
@@ -1272,19 +1272,24 @@ SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
 
 SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
                   ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
                   ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT2R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
index 4456b38a3ef59543591260505e177144f66fcd54..fbaeddb3e9033a3044b4995265dce2849b348160 100644 (file)
@@ -134,7 +134,7 @@ static const struct reg_default wm5110_sysclk_revd_patch[] = {
 static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
                            struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
        struct regmap *regmap = arizona->regmap;
        const struct reg_default *patch = NULL;
@@ -905,22 +905,28 @@ SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
 
 SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
                   ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
                   ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT2R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT3R", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT3R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
index 574579b988726a41b7b8d7b4e8615359b1aa4e12..c81a9eab3e3e5113121a9e2c90f1971a410d41fe 100644 (file)
@@ -259,7 +259,7 @@ static void wm8350_pga_work(struct work_struct *work)
 static int pga_event(struct snd_soc_dapm_widget *w,
                     struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
        struct wm8350_output *out;
 
index 8ee446987aa9e4999f9b0a4098adee220b7d0f66..b0d84e552fca758786100c5eca18b746013a1d61 100644 (file)
@@ -324,6 +324,7 @@ SOC_SINGLE("RIN34 Mute Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME,
 static int outmixer_event (struct snd_soc_dapm_widget *w,
        struct snd_kcontrol * kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        u32 reg_shift = mc->shift;
@@ -332,7 +333,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
 
        switch (reg_shift) {
        case WM8400_SPEAKER_MIXER | (WM8400_LDSPK << 8) :
-               reg = snd_soc_read(w->codec, WM8400_OUTPUT_MIXER1);
+               reg = snd_soc_read(codec, WM8400_OUTPUT_MIXER1);
                if (reg & WM8400_LDLO) {
                        printk(KERN_WARNING
                        "Cannot set as Output Mixer 1 LDLO Set\n");
@@ -340,7 +341,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
                }
                break;
        case WM8400_SPEAKER_MIXER | (WM8400_RDSPK << 8):
-               reg = snd_soc_read(w->codec, WM8400_OUTPUT_MIXER2);
+               reg = snd_soc_read(codec, WM8400_OUTPUT_MIXER2);
                if (reg & WM8400_RDRO) {
                        printk(KERN_WARNING
                        "Cannot set as Output Mixer 2 RDRO Set\n");
@@ -348,7 +349,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
                }
                break;
        case WM8400_OUTPUT_MIXER1 | (WM8400_LDLO << 8):
-               reg = snd_soc_read(w->codec, WM8400_SPEAKER_MIXER);
+               reg = snd_soc_read(codec, WM8400_SPEAKER_MIXER);
                if (reg & WM8400_LDSPK) {
                        printk(KERN_WARNING
                        "Cannot set as Speaker Mixer LDSPK Set\n");
@@ -356,7 +357,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
                }
                break;
        case WM8400_OUTPUT_MIXER2 | (WM8400_RDRO << 8):
-               reg = snd_soc_read(w->codec, WM8400_SPEAKER_MIXER);
+               reg = snd_soc_read(codec, WM8400_SPEAKER_MIXER);
                if (reg & WM8400_RDSPK) {
                        printk(KERN_WARNING
                        "Cannot set as Speaker Mixer RDSPK Set\n");
index b115ed815db97329bb9d6a4c6d7b50faf42f5f40..098c143f44d653d99c33f36e02edde9eca6600d8 100644 (file)
@@ -217,7 +217,8 @@ SND_SOC_DAPM_INPUT("LLINEIN"),
 static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
                            struct snd_soc_dapm_widget *sink)
 {
-       struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(source->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+       struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
 
        return wm8731->sysclk_type == WM8731_SYSCLK_XTAL;
 }
index f6847fdd6dddd1e7833acf1eaa2f89244e229c12..eb0a1644ba1142d05cc8ac561945a507f776e066 100644 (file)
@@ -323,7 +323,7 @@ static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
        SND_SOC_DAPM_OUTPUT("ROUT2"),
        SND_SOC_DAPM_OUTPUT("MONO1"),
        SND_SOC_DAPM_OUTPUT("OUT3"),
-       SND_SOC_DAPM_OUTPUT("VREF"),
+       SND_SOC_DAPM_VMID("VREF"),
 
        SND_SOC_DAPM_INPUT("LINPUT1"),
        SND_SOC_DAPM_INPUT("LINPUT2"),
index 180e7a09872618469e59f7b9b845c2553c460262..53e977da2f86d325c0366efae3e3ba121e49fedd 100644 (file)
@@ -308,9 +308,7 @@ static const struct snd_soc_dapm_route wm8770_intercon[] = {
 static int vout12supply_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec;
-
-       codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
@@ -327,9 +325,7 @@ static int vout12supply_event(struct snd_soc_dapm_widget *w,
 static int vout34supply_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec;
-
-       codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
index 1315f76425031686629b8af397b0996969c570c7..b2b0e68f707e32037fe8dc623aed5be1b2cda73c 100644 (file)
@@ -648,7 +648,7 @@ static struct snd_soc_dai_driver wm8804_dai = {
        .symmetric_rates = 1
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
        .probe = wm8804_probe,
        .remove = wm8804_remove,
        .set_bias_level = wm8804_set_bias_level,
@@ -664,7 +664,7 @@ static const struct of_device_id wm8804_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, wm8804_of_match);
 
-static struct regmap_config wm8804_regmap_config = {
+static const struct regmap_config wm8804_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
 
index 3a0d4b7d692fcc2bd77eb017374d6139a3bb5df3..2eb986c19b886a48e9d367623adf353a94796689 100644 (file)
@@ -224,7 +224,7 @@ static void wm8900_reset(struct snd_soc_codec *codec)
 static int wm8900_hp_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        u16 hpctl1 = snd_soc_read(codec, WM8900_REG_HPCTL1);
 
        switch (event) {
index cc6b0ef98a345e9b8832bb4c09d1312451d7d070..dde462c082be0eb6124e0f881b9a1ed936e34c77 100644 (file)
@@ -260,7 +260,7 @@ static int wm8903_cp_event(struct snd_soc_dapm_widget *w,
 static int wm8903_dcs_event(struct snd_soc_dapm_widget *w,
                            struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
index 75b87c5c0f046286f41ceace869091f6323d9f4c..d3b3f57668ccae412f0a75d61f91f9f34f1f0fb0 100644 (file)
@@ -673,7 +673,7 @@ static int cp_event(struct snd_soc_dapm_widget *w,
 static int sysclk_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -711,7 +711,7 @@ static int sysclk_event(struct snd_soc_dapm_widget *w,
 static int out_pga_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
        int reg, val;
        int dcs_mask;
@@ -2105,6 +2105,24 @@ static const struct regmap_config wm8904_regmap = {
        .num_reg_defaults = ARRAY_SIZE(wm8904_reg_defaults),
 };
 
+#ifdef CONFIG_OF
+static enum wm8904_type wm8904_data = WM8904;
+static enum wm8904_type wm8912_data = WM8912;
+
+static const struct of_device_id wm8904_of_match[] = {
+       {
+               .compatible = "wlf,wm8904",
+               .data = &wm8904_data,
+       }, {
+               .compatible = "wlf,wm8912",
+               .data = &wm8912_data,
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(of, wm8904_of_match);
+#endif
+
 static int wm8904_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
@@ -2132,7 +2150,17 @@ static int wm8904_i2c_probe(struct i2c_client *i2c,
                return ret;
        }
 
-       wm8904->devtype = id->driver_data;
+       if (i2c->dev.of_node) {
+               const struct of_device_id *match;
+
+               match = of_match_node(wm8904_of_match, i2c->dev.of_node);
+               if (match == NULL)
+                       return -EINVAL;
+               wm8904->devtype = *((enum wm8904_type *)match->data);
+       } else {
+               wm8904->devtype = id->driver_data;
+       }
+
        i2c_set_clientdata(i2c, wm8904);
        wm8904->pdata = i2c->dev.platform_data;
 
@@ -2266,6 +2294,7 @@ static struct i2c_driver wm8904_i2c_driver = {
        .driver = {
                .name = "wm8904",
                .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(wm8904_of_match),
        },
        .probe =    wm8904_i2c_probe,
        .remove =   wm8904_i2c_remove,
index 1173f7fef5a76dcb9f1954c2c23568e7f5c99123..1ab2d462afadfb24a7205638a779bb0152eb702a 100644 (file)
@@ -333,7 +333,7 @@ static int wm8955_configure_clocking(struct snd_soc_codec *codec)
 static int wm8955_sysclk(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        int ret = 0;
 
        /* Always disable the clocks - if we're doing reconfiguration this
index 3cbc82b3329288e8d16f33acaa4782dac147a542..c799cca5abeb704645687b863ccedfc6749e9ac2 100644 (file)
@@ -418,7 +418,7 @@ static void wm8958_dsp_apply(struct snd_soc_codec *codec, int path, int start)
 int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
                  struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        int i;
 
        switch (event) {
index a96eb497a3796e9b67b539eae255a316af52864b..cf8fecf97f2c7ee06fff2741bea074bd32ceb7fc 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
+#include <linux/clk.h>
 #include <linux/i2c.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -117,6 +118,7 @@ static bool wm8960_volatile(struct device *dev, unsigned int reg)
 }
 
 struct wm8960_priv {
+       struct clk *mclk;
        struct regmap *regmap;
        int (*set_bias_level)(struct snd_soc_codec *,
                              enum snd_soc_bias_level level);
@@ -618,14 +620,38 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
                                      enum snd_soc_bias_level level)
 {
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+       int ret;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
                break;
 
        case SND_SOC_BIAS_PREPARE:
-               /* Set VMID to 2x50k */
-               snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80);
+               switch (codec->dapm.bias_level) {
+               case SND_SOC_BIAS_STANDBY:
+                       if (!IS_ERR(wm8960->mclk)) {
+                               ret = clk_prepare_enable(wm8960->mclk);
+                               if (ret) {
+                                       dev_err(codec->dev,
+                                               "Failed to enable MCLK: %d\n",
+                                               ret);
+                                       return ret;
+                               }
+                       }
+
+                       /* Set VMID to 2x50k */
+                       snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80);
+                       break;
+
+               case SND_SOC_BIAS_ON:
+                       if (!IS_ERR(wm8960->mclk))
+                               clk_disable_unprepare(wm8960->mclk);
+                       break;
+
+               default:
+                       break;
+               }
+
                break;
 
        case SND_SOC_BIAS_STANDBY:
@@ -674,7 +700,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
                                         enum snd_soc_bias_level level)
 {
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
-       int reg;
+       int reg, ret;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
@@ -715,9 +741,22 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
                                            WM8960_VREF, WM8960_VREF);
 
                        msleep(100);
+
+                       if (!IS_ERR(wm8960->mclk)) {
+                               ret = clk_prepare_enable(wm8960->mclk);
+                               if (ret) {
+                                       dev_err(codec->dev,
+                                               "Failed to enable MCLK: %d\n",
+                                               ret);
+                                       return ret;
+                               }
+                       }
                        break;
 
                case SND_SOC_BIAS_ON:
+                       if (!IS_ERR(wm8960->mclk))
+                               clk_disable_unprepare(wm8960->mclk);
+
                        /* Enable anti-pop mode */
                        snd_soc_update_bits(codec, WM8960_APOP1,
                                            WM8960_POBCTRL | WM8960_SOFT_ST |
@@ -1002,6 +1041,12 @@ static int wm8960_i2c_probe(struct i2c_client *i2c,
        if (wm8960 == NULL)
                return -ENOMEM;
 
+       wm8960->mclk = devm_clk_get(&i2c->dev, "mclk");
+       if (IS_ERR(wm8960->mclk)) {
+               if (PTR_ERR(wm8960->mclk) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+       }
+
        wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap);
        if (IS_ERR(wm8960->regmap))
                return PTR_ERR(wm8960->regmap);
index eeffd05384b40e5e15c11f22cbf2cbe7d46a33f7..95e2c1bfc809ff1a0d9c20b6f280c0afed491239 100644 (file)
@@ -194,7 +194,7 @@ static bool wm8961_readable(struct device *dev, unsigned int reg)
 static int wm8961_hp_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        u16 hp_reg = snd_soc_read(codec, WM8961_ANALOGUE_HP_0);
        u16 cp_reg = snd_soc_read(codec, WM8961_CHARGE_PUMP_1);
        u16 pwr_reg = snd_soc_read(codec, WM8961_PWR_MGMT_2);
@@ -286,7 +286,7 @@ static int wm8961_hp_event(struct snd_soc_dapm_widget *w,
 static int wm8961_spk_event(struct snd_soc_dapm_widget *w,
                            struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        u16 pwr_reg = snd_soc_read(codec, WM8961_PWR_MGMT_2);
        u16 spk_reg = snd_soc_read(codec, WM8961_CLASS_D_CONTROL_1);
 
index d32d554f5b34e5c3c3a0d0786aa0fe501dc1368e..118b0034ba235d238bfc5c137db7681126bba45b 100644 (file)
@@ -1866,7 +1866,7 @@ static int cp_event(struct snd_soc_dapm_widget *w,
 static int hp_event(struct snd_soc_dapm_widget *w,
                    struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        int timeout;
        int reg;
        int expected = (WM8962_DCS_STARTUP_DONE_HP1L |
@@ -1960,7 +1960,7 @@ static int hp_event(struct snd_soc_dapm_widget *w,
 static int out_pga_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        int reg;
 
        switch (w->shift) {
@@ -1993,7 +1993,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
 static int dsp2_event(struct snd_soc_dapm_widget *w,
                      struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
index e418199155a8824d0a5cb6fb2cb02b22ffd1c3b8..24968aa8618a52e705fdbfe3f04de156abb5a6da 100644 (file)
@@ -244,7 +244,7 @@ SOC_DOUBLE_R_TLV("Output 2 Playback Volume", WM8988_LOUT2V, WM8988_ROUT2V,
 static int wm8988_lrc_control(struct snd_soc_dapm_widget *w,
                              struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        u16 adctl2 = snd_soc_read(codec, WM8988_ADCTL2);
 
        /* Use the DAC to gate LRC if active, otherwise use ADC */
@@ -813,7 +813,7 @@ static int wm8988_probe(struct snd_soc_codec *codec)
        return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8988 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8988 = {
        .probe =        wm8988_probe,
        .set_bias_level = wm8988_set_bias_level,
        .suspend_bias_off = true,
@@ -826,7 +826,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8988 = {
        .num_dapm_routes = ARRAY_SIZE(wm8988_dapm_routes),
 };
 
-static struct regmap_config wm8988_regmap = {
+static const struct regmap_config wm8988_regmap = {
        .reg_bits = 7,
        .val_bits = 9,
 
index 8a584229310a72daba726678b8e2342b3e431d23..c93bffcb3cfba2e3953b53b571e046a9553ff5a0 100644 (file)
@@ -374,13 +374,14 @@ SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME,
 static int outmixer_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        u32 reg_shift = kcontrol->private_value & 0xfff;
        int ret = 0;
        u16 reg;
 
        switch (reg_shift) {
        case WM8990_SPEAKER_MIXER | (WM8990_LDSPK_BIT << 8) :
-               reg = snd_soc_read(w->codec, WM8990_OUTPUT_MIXER1);
+               reg = snd_soc_read(codec, WM8990_OUTPUT_MIXER1);
                if (reg & WM8990_LDLO) {
                        printk(KERN_WARNING
                        "Cannot set as Output Mixer 1 LDLO Set\n");
@@ -388,7 +389,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
                }
                break;
        case WM8990_SPEAKER_MIXER | (WM8990_RDSPK_BIT << 8):
-               reg = snd_soc_read(w->codec, WM8990_OUTPUT_MIXER2);
+               reg = snd_soc_read(codec, WM8990_OUTPUT_MIXER2);
                if (reg & WM8990_RDRO) {
                        printk(KERN_WARNING
                        "Cannot set as Output Mixer 2 RDRO Set\n");
@@ -396,7 +397,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
                }
                break;
        case WM8990_OUTPUT_MIXER1 | (WM8990_LDLO_BIT << 8):
-               reg = snd_soc_read(w->codec, WM8990_SPEAKER_MIXER);
+               reg = snd_soc_read(codec, WM8990_SPEAKER_MIXER);
                if (reg & WM8990_LDSPK) {
                        printk(KERN_WARNING
                        "Cannot set as Speaker Mixer LDSPK Set\n");
@@ -404,7 +405,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
                }
                break;
        case WM8990_OUTPUT_MIXER2 | (WM8990_RDRO_BIT << 8):
-               reg = snd_soc_read(w->codec, WM8990_SPEAKER_MIXER);
+               reg = snd_soc_read(codec, WM8990_SPEAKER_MIXER);
                if (reg & WM8990_RDSPK) {
                        printk(KERN_WARNING
                        "Cannot set as Speaker Mixer RDSPK Set\n");
index b0ac2c3e31b9b09a84552eeda9765dec043d023f..49df0dc607e67f41252cd6c56eb38cc0abdf06dc 100644 (file)
@@ -382,13 +382,14 @@ static const struct snd_kcontrol_new wm8991_snd_controls[] = {
 static int outmixer_event(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        u32 reg_shift = kcontrol->private_value & 0xfff;
        int ret = 0;
        u16 reg;
 
        switch (reg_shift) {
        case WM8991_SPEAKER_MIXER | (WM8991_LDSPK_BIT << 8):
-               reg = snd_soc_read(w->codec, WM8991_OUTPUT_MIXER1);
+               reg = snd_soc_read(codec, WM8991_OUTPUT_MIXER1);
                if (reg & WM8991_LDLO) {
                        printk(KERN_WARNING
                               "Cannot set as Output Mixer 1 LDLO Set\n");
@@ -397,7 +398,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
                break;
 
        case WM8991_SPEAKER_MIXER | (WM8991_RDSPK_BIT << 8):
-               reg = snd_soc_read(w->codec, WM8991_OUTPUT_MIXER2);
+               reg = snd_soc_read(codec, WM8991_OUTPUT_MIXER2);
                if (reg & WM8991_RDRO) {
                        printk(KERN_WARNING
                               "Cannot set as Output Mixer 2 RDRO Set\n");
@@ -406,7 +407,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
                break;
 
        case WM8991_OUTPUT_MIXER1 | (WM8991_LDLO_BIT << 8):
-               reg = snd_soc_read(w->codec, WM8991_SPEAKER_MIXER);
+               reg = snd_soc_read(codec, WM8991_SPEAKER_MIXER);
                if (reg & WM8991_LDSPK) {
                        printk(KERN_WARNING
                               "Cannot set as Speaker Mixer LDSPK Set\n");
@@ -415,7 +416,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
                break;
 
        case WM8991_OUTPUT_MIXER2 | (WM8991_RDRO_BIT << 8):
-               reg = snd_soc_read(w->codec, WM8991_SPEAKER_MIXER);
+               reg = snd_soc_read(codec, WM8991_SPEAKER_MIXER);
                if (reg & WM8991_RDSPK) {
                        printk(KERN_WARNING
                               "Cannot set as Speaker Mixer RDSPK Set\n");
index 53c6fe35949675fab58000a661390adefd802f89..2e70a270eb2894f36ccb5cacd3fd618dee45256c 100644 (file)
@@ -810,7 +810,7 @@ SOC_SINGLE_TLV("EQ5 Volume", WM8993_EQ6, 0, 24, 0, eq_tlv),
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
index 1b97de2e4e67126f918097abc24e8932d40995ec..4fbc7689339a8903f724fa9aefcb6feb31dad54f 100644 (file)
@@ -249,7 +249,8 @@ static int configure_clock(struct snd_soc_codec *codec)
 static int check_clk_sys(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
-       int reg = snd_soc_read(source->codec, WM8994_CLOCKING_1);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+       int reg = snd_soc_read(codec, WM8994_CLOCKING_1);
        const char *clk;
 
        /* Check what we're currently using for CLK_SYS */
@@ -806,7 +807,7 @@ static void active_dereference(struct snd_soc_codec *codec)
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -981,7 +982,7 @@ static void vmid_dereference(struct snd_soc_codec *codec)
 static int vmid_event(struct snd_soc_dapm_widget *w,
                      struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
@@ -1037,7 +1038,7 @@ static bool wm8994_check_class_w_digital(struct snd_soc_codec *codec)
 static int aif1clk_ev(struct snd_soc_dapm_widget *w,
                      struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994 *control = wm8994->wm8994;
        int mask = WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA;
@@ -1135,7 +1136,7 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w,
 static int aif2clk_ev(struct snd_soc_dapm_widget *w,
                      struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        int i;
        int dac;
        int adc;
@@ -1220,7 +1221,7 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w,
 static int aif1clk_late_ev(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -1238,7 +1239,7 @@ static int aif1clk_late_ev(struct snd_soc_dapm_widget *w,
 static int aif2clk_late_ev(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -1256,7 +1257,7 @@ static int aif2clk_late_ev(struct snd_soc_dapm_widget *w,
 static int late_enable_ev(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -1289,7 +1290,7 @@ static int late_enable_ev(struct snd_soc_dapm_widget *w,
 static int late_disable_ev(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -1331,7 +1332,7 @@ static int micbias_ev(struct snd_soc_dapm_widget *w,
 static int dac_ev(struct snd_soc_dapm_widget *w,
                  struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        unsigned int mask = 1 << w->shift;
 
        snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
@@ -1372,7 +1373,7 @@ SOC_DAPM_SINGLE("DAC1 Switch", WM8994_SPEAKER_MIXER, 0, 1, 0),
 static int post_ev(struct snd_soc_dapm_widget *w,
            struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        dev_dbg(codec->dev, "SRC status: %x\n",
                snd_soc_read(codec,
                             WM8994_RATE_STATUS));
index c280f0a3a424303ebba6def4972d4e644fc479f8..66103c2b012e522062a9d29d5f92a099223c6015 100644 (file)
@@ -44,7 +44,7 @@ static const char *wm8995_supply_names[WM8995_NUM_SUPPLIES] = {
        "MICVDD"
 };
 
-static struct reg_default wm8995_reg_defaults[] = {
+static const struct reg_default wm8995_reg_defaults[] = {
        { 0, 0x8995 },
        { 5, 0x0100 },
        { 16, 0x000b },
@@ -534,10 +534,11 @@ static void wm8995_update_class_w(struct snd_soc_codec *codec)
 static int check_clk_sys(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg;
        const char *clk;
 
-       reg = snd_soc_read(source->codec, WM8995_CLOCKING_1);
+       reg = snd_soc_read(codec, WM8995_CLOCKING_1);
        /* Check what we're currently using for CLK_SYS */
        if (reg & WM8995_SYSCLK_SRC)
                clk = "AIF2CLK";
@@ -560,9 +561,7 @@ static int wm8995_put_class_w(struct snd_kcontrol *kcontrol,
 static int hp_supply_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec;
-
-       codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
@@ -611,10 +610,9 @@ static void dc_servo_cmd(struct snd_soc_codec *codec,
 static int hp_event(struct snd_soc_dapm_widget *w,
                    struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        unsigned int reg;
 
-       codec = w->codec;
        reg = snd_soc_read(codec, WM8995_ANALOGUE_HP_1);
 
        switch (event) {
@@ -761,9 +759,7 @@ static int configure_clock(struct snd_soc_codec *codec)
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec;
-
-       codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
@@ -2190,7 +2186,7 @@ static struct snd_soc_dai_driver wm8995_dai[] = {
        }
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8995 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8995 = {
        .probe = wm8995_probe,
        .remove = wm8995_remove,
        .set_bias_level = wm8995_set_bias_level,
@@ -2204,7 +2200,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8995 = {
        .num_dapm_routes = ARRAY_SIZE(wm8995_intercon),
 };
 
-static struct regmap_config wm8995_regmap = {
+static const struct regmap_config wm8995_regmap = {
        .reg_bits = 16,
        .val_bits = 16,
 
index b1dcc11c1b23bd0134940d2f9571d14b9e1dac92..dc92d5e4e9426e8157104361d4a71f675769f00d 100644 (file)
@@ -599,7 +599,7 @@ static void wm8996_bg_disable(struct snd_soc_codec *codec)
 static int bg_event(struct snd_soc_dapm_widget *w,
                    struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        int ret = 0;
 
        switch (event) {
@@ -634,7 +634,8 @@ static int cp_event(struct snd_soc_dapm_widget *w,
 static int rmv_short_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
 
        /* Record which outputs we enabled */
        switch (event) {
@@ -758,7 +759,8 @@ static void wm8996_seq_notifier(struct snd_soc_dapm_context *dapm,
 static int dcs_start(struct snd_soc_dapm_widget *w,
                     struct snd_kcontrol *kcontrol, int event)
 {
-       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
index 7e8bfe27566bd10be11b0dfdc736bf346c02489a..a4d11770630cdd9bd169836c5e14e0f8dfc5633b 100644 (file)
@@ -84,7 +84,7 @@ static const struct reg_default wm8997_sysclk_reva_patch[] = {
 static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,
                            struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
        struct regmap *regmap = arizona->regmap;
        const struct reg_default *patch = NULL;
@@ -610,13 +610,16 @@ SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
 
 SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
                   ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
                   ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
index b1d946facd57f1796815f5f157848f0569d547b5..13a3f335ea5b6cb4bfeecd8ed0eb9ce13a1bb7ce 100644 (file)
@@ -734,7 +734,7 @@ static int configure_clock(struct snd_soc_codec *codec)
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
 
        /* This should be done on init() for bypass paths */
index 6ffe8dc4f3fad5ba5a08544bda7e062fecef3f79..60d243c904f529597399c408c8426c2ca879ccd6 100644 (file)
@@ -254,7 +254,7 @@ SOC_SINGLE_TLV("MIXOUTR IN2B Volume", WM9090_OUTPUT_MIXER4, 0, 3, 1,
 static int hp_ev(struct snd_soc_dapm_widget *w,
                 struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        unsigned int reg = snd_soc_read(codec, WM9090_ANALOGUE_HP_0);
 
        switch (event) {
index 6ab1122a3872dedeefe0460ac065a2f675e231a1..68222917b396666b975cc2aa96e13d983bf52fc2 100644 (file)
@@ -217,7 +217,7 @@ SOC_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1),
 static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w,
                                 struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        u16 status, rate;
 
        if (WARN_ON(event != SND_SOC_DAPM_PRE_PMD))
index 720d6e852986c3e7c6b0b1128876b7c4c4fa4ffb..ff67b334065badc1011807648ac671a4d07765bf 100644 (file)
@@ -1373,7 +1373,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol,
                   int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
        struct wm_adsp *dsp = &dsps[w->shift];
        struct wm_adsp_alg_region *alg_region;
@@ -1605,7 +1605,7 @@ err:
 int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
        struct wm_adsp *dsp = &dsps[w->shift];
 
@@ -1626,7 +1626,7 @@ EXPORT_SYMBOL_GPL(wm_adsp2_early_event);
 int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
        struct wm_adsp *dsp = &dsps[w->shift];
        struct wm_adsp_alg_region *alg_region;
index 374537d5e179c6615ec98e1787536659c4a83ff0..8366e19657a73708fc4d65f5c3a13a449618ca92 100644 (file)
@@ -500,7 +500,7 @@ SOC_SINGLE_TLV("LINEOUT2 Volume", WM8993_LINE_OUTPUTS_VOLUME, 0, 1, 1,
 static int hp_supply_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -542,7 +542,7 @@ static int hp_supply_event(struct snd_soc_dapm_widget *w,
 static int hp_event(struct snd_soc_dapm_widget *w,
                    struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        unsigned int reg = snd_soc_read(codec, WM8993_ANALOGUE_HP_0);
 
        switch (event) {
@@ -594,7 +594,7 @@ static int hp_event(struct snd_soc_dapm_widget *w,
 static int earpiece_event(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *control, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        u16 reg = snd_soc_read(codec, WM8993_ANTIPOP1) & ~WM8993_HPOUT2_IN_ENA;
 
        switch (event) {
@@ -619,7 +619,7 @@ static int earpiece_event(struct snd_soc_dapm_widget *w,
 static int lineout_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *control, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
        bool *flag;
 
@@ -649,7 +649,7 @@ static int lineout_event(struct snd_soc_dapm_widget *w,
 static int micbias_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
 
        switch (w->shift) {
index 8e948c63f3d96ec6dab93a2891d41f6eee0912da..2b81ca418d2a67d93087e0acd0fc896cb2478210 100644 (file)
@@ -58,13 +58,12 @@ choice
        depends on MACH_DAVINCI_DM365_EVM
 
 config SND_DM365_AIC3X_CODEC
-       bool "Audio Codec - AIC3101"
+       tristate "Audio Codec - AIC3101"
        help
          Say Y if you want to add support for AIC3101 audio codec
 
 config SND_DM365_VOICE_CODEC
        tristate "Voice Codec - CQ93VC"
-       depends on SND_DAVINCI_SOC
        select MFD_DAVINCI_VOICECODEC
        select SND_DAVINCI_SOC_VCIF
        select SND_SOC_CQ0093VC
index 158cb3d1db70c91fce6853e38a99c89dc63d6a95..b6bb5947a8a8435f5219d4d8efb541e842e531f4 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
-#include <linux/platform_data/edma.h>
 #include <linux/i2c.h>
 #include <linux/of_platform.h>
 #include <linux/clk.h>
 #include <asm/dma.h>
 #include <asm/mach-types.h>
 
-#include <linux/edma.h>
-
-#include "davinci-pcm.h"
-#include "davinci-i2s.h"
-
 struct snd_soc_card_drvdata_davinci {
        struct clk *mclk;
        unsigned sysclk;
index 30b94d4f9c5de369531713517adc2a9f1d3a46f7..de3b155a50116f4e533c8f22e0fc6b933e8040ae 100644 (file)
@@ -364,6 +364,20 @@ static irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data)
        return IRQ_RETVAL(handled_mask);
 }
 
+static irqreturn_t davinci_mcasp_common_irq_handler(int irq, void *data)
+{
+       struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
+       irqreturn_t ret = IRQ_NONE;
+
+       if (mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK])
+               ret = davinci_mcasp_tx_irq_handler(irq, data);
+
+       if (mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE])
+               ret |= davinci_mcasp_rx_irq_handler(irq, data);
+
+       return ret;
+}
+
 static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                                         unsigned int fmt)
 {
@@ -1313,16 +1327,19 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
 
        pdata->tx_dma_channel = dma_spec.args[0];
 
-       ret = of_property_match_string(np, "dma-names", "rx");
-       if (ret < 0)
-               goto nodata;
+       /* RX is not valid in DIT mode */
+       if (pdata->op_mode != DAVINCI_MCASP_DIT_MODE) {
+               ret = of_property_match_string(np, "dma-names", "rx");
+               if (ret < 0)
+                       goto nodata;
 
-       ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
-                                        &dma_spec);
-       if (ret < 0)
-               goto nodata;
+               ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
+                                                &dma_spec);
+               if (ret < 0)
+                       goto nodata;
 
-       pdata->rx_dma_channel = dma_spec.args[0];
+               pdata->rx_dma_channel = dma_spec.args[0];
+       }
 
        ret = of_property_read_u32(np, "tx-num-evt", &val);
        if (ret >= 0)
@@ -1441,6 +1458,23 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 
        mcasp->dev = &pdev->dev;
 
+       irq = platform_get_irq_byname(pdev, "common");
+       if (irq >= 0) {
+               irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_common\n",
+                                         dev_name(&pdev->dev));
+               ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+                                               davinci_mcasp_common_irq_handler,
+                                               IRQF_ONESHOT | IRQF_SHARED,
+                                               irq_name, mcasp);
+               if (ret) {
+                       dev_err(&pdev->dev, "common IRQ request failed\n");
+                       goto err;
+               }
+
+               mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN;
+               mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
+       }
+
        irq = platform_get_irq_byname(pdev, "rx");
        if (irq >= 0) {
                irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx\n",
@@ -1501,19 +1535,34 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        else
                dma_data->filter_data = &dma_params->channel;
 
-       dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE];
-       dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
-       dma_params->asp_chan_q = pdata->asp_chan_q;
-       dma_params->ram_chan_q = pdata->ram_chan_q;
-       dma_params->sram_pool = pdata->sram_pool;
-       dma_params->sram_size = pdata->sram_size_capture;
-       if (dat)
-               dma_params->dma_addr = dat->start;
-       else
-               dma_params->dma_addr = mem->start + pdata->rx_dma_offset;
-
-       /* Unconditional dmaengine stuff */
-       dma_data->addr = dma_params->dma_addr;
+       /* RX is not valid in DIT mode */
+       if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
+               dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE];
+               dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+               dma_params->asp_chan_q = pdata->asp_chan_q;
+               dma_params->ram_chan_q = pdata->ram_chan_q;
+               dma_params->sram_pool = pdata->sram_pool;
+               dma_params->sram_size = pdata->sram_size_capture;
+               if (dat)
+                       dma_params->dma_addr = dat->start;
+               else
+                       dma_params->dma_addr = mem->start + pdata->rx_dma_offset;
+
+               /* Unconditional dmaengine stuff */
+               dma_data->addr = dma_params->dma_addr;
+
+               res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+               if (res)
+                       dma_params->channel = res->start;
+               else
+                       dma_params->channel = pdata->rx_dma_channel;
+
+               /* dmaengine filter data for DT and non-DT boot */
+               if (pdev->dev.of_node)
+                       dma_data->filter_data = "rx";
+               else
+                       dma_data->filter_data = &dma_params->channel;
+       }
 
        if (mcasp->version < MCASP_VERSION_3) {
                mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE;
@@ -1523,18 +1572,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
                mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-       if (res)
-               dma_params->channel = res->start;
-       else
-               dma_params->channel = pdata->rx_dma_channel;
-
-       /* dmaengine filter data for DT and non-DT boot */
-       if (pdev->dev.of_node)
-               dma_data->filter_data = "rx";
-       else
-               dma_data->filter_data = &dma_params->channel;
-
        dev_set_drvdata(&pdev->dev, mcasp);
 
        mcasp_reparent_fck(pdev);
index e334900cf0b8e2bd740acaf60360f50251dcf280..d50e08517dce57502d6548d7852d5792c9c56ad7 100644 (file)
@@ -1,6 +1,7 @@
 config SND_DESIGNWARE_I2S
        tristate "Synopsys I2S Device Driver"
        depends on CLKDEV_LOOKUP
+       select SND_SOC_GENERIC_DMAENGINE_PCM
        help
         Say Y or M if you want to add support for I2S driver for
         Synopsys desigwnware I2S device. The device supports upto
index 8d18bbda661b66412dba2b93246bc7069cc61c80..a3e97b46b64e3871ec9362b231d19f9334628229 100644 (file)
@@ -22,6 +22,7 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 /* common register for all channel */
 #define IER            0x000
 #define I2S_COMP_VERSION       0x01F8
 #define I2S_COMP_TYPE          0x01FC
 
+/*
+ * Component parameter register fields - define the I2S block's
+ * configuration.
+ */
+#define        COMP1_TX_WORDSIZE_3(r)  (((r) & GENMASK(27, 25)) >> 25)
+#define        COMP1_TX_WORDSIZE_2(r)  (((r) & GENMASK(24, 22)) >> 22)
+#define        COMP1_TX_WORDSIZE_1(r)  (((r) & GENMASK(21, 19)) >> 19)
+#define        COMP1_TX_WORDSIZE_0(r)  (((r) & GENMASK(18, 16)) >> 16)
+#define        COMP1_TX_CHANNELS(r)    (((r) & GENMASK(10, 9)) >> 9)
+#define        COMP1_RX_CHANNELS(r)    (((r) & GENMASK(8, 7)) >> 7)
+#define        COMP1_RX_ENABLED(r)     (((r) & BIT(6)) >> 6)
+#define        COMP1_TX_ENABLED(r)     (((r) & BIT(5)) >> 5)
+#define        COMP1_MODE_EN(r)        (((r) & BIT(4)) >> 4)
+#define        COMP1_FIFO_DEPTH_GLOBAL(r)      (((r) & GENMASK(3, 2)) >> 2)
+#define        COMP1_APB_DATA_WIDTH(r) (((r) & GENMASK(1, 0)) >> 0)
+
+#define        COMP2_RX_WORDSIZE_3(r)  (((r) & GENMASK(12, 10)) >> 10)
+#define        COMP2_RX_WORDSIZE_2(r)  (((r) & GENMASK(9, 7)) >> 7)
+#define        COMP2_RX_WORDSIZE_1(r)  (((r) & GENMASK(5, 3)) >> 3)
+#define        COMP2_RX_WORDSIZE_0(r)  (((r) & GENMASK(2, 0)) >> 0)
+
+/* Number of entries in WORDSIZE and DATA_WIDTH parameter registers */
+#define        COMP_MAX_WORDSIZE       (1 << 3)
+#define        COMP_MAX_DATA_WIDTH     (1 << 2)
+
 #define MAX_CHANNEL_NUM                8
 #define MIN_CHANNEL_NUM                2
 
+union dw_i2s_snd_dma_data {
+       struct i2s_dma_data pd;
+       struct snd_dmaengine_dai_dma_data dt;
+};
+
 struct dw_i2s_dev {
        void __iomem *i2s_base;
        struct clk *clk;
@@ -65,8 +96,8 @@ struct dw_i2s_dev {
        struct device *dev;
 
        /* data related to DMA transfers b/w i2s and DMAC */
-       struct i2s_dma_data play_dma_data;
-       struct i2s_dma_data capture_dma_data;
+       union dw_i2s_snd_dma_data play_dma_data;
+       union dw_i2s_snd_dma_data capture_dma_data;
        struct i2s_clk_config_data config;
        int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
 };
@@ -153,7 +184,7 @@ static int dw_i2s_startup(struct snd_pcm_substream *substream,
                struct snd_soc_dai *cpu_dai)
 {
        struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
-       struct i2s_dma_data *dma_data = NULL;
+       union dw_i2s_snd_dma_data *dma_data = NULL;
 
        if (!(dev->capability & DWC_I2S_RECORD) &&
                        (substream->stream == SNDRV_PCM_STREAM_CAPTURE))
@@ -242,13 +273,21 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
 
        config->sample_rate = params_rate(params);
 
-       if (!dev->i2s_clk_cfg)
-               return -EINVAL;
+       if (dev->i2s_clk_cfg) {
+               ret = dev->i2s_clk_cfg(config);
+               if (ret < 0) {
+                       dev_err(dev->dev, "runtime audio clk config fail\n");
+                       return ret;
+               }
+       } else {
+               u32 bitclk = config->sample_rate * config->data_width * 2;
 
-       ret = dev->i2s_clk_cfg(config);
-       if (ret < 0) {
-               dev_err(dev->dev, "runtime audio clk config fail\n");
-               return ret;
+               ret = clk_set_rate(dev->clk, bitclk);
+               if (ret) {
+                       dev_err(dev->dev, "Can't set I2S clock rate: %d\n",
+                               ret);
+                       return ret;
+               }
        }
 
        return 0;
@@ -335,20 +374,162 @@ static int dw_i2s_resume(struct snd_soc_dai *dai)
 #define dw_i2s_resume  NULL
 #endif
 
+/*
+ * The following tables allow a direct lookup of various parameters
+ * defined in the I2S block's configuration in terms of sound system
+ * parameters.  Each table is sized to the number of entries possible
+ * according to the number of configuration bits describing an I2S
+ * block parameter.
+ */
+
+/* Maximum bit resolution of a channel - not uniformly spaced */
+static const u32 fifo_width[COMP_MAX_WORDSIZE] = {
+       12, 16, 20, 24, 32, 0, 0, 0
+};
+
+/* Width of (DMA) bus */
+static const u32 bus_widths[COMP_MAX_DATA_WIDTH] = {
+       DMA_SLAVE_BUSWIDTH_1_BYTE,
+       DMA_SLAVE_BUSWIDTH_2_BYTES,
+       DMA_SLAVE_BUSWIDTH_4_BYTES,
+       DMA_SLAVE_BUSWIDTH_UNDEFINED
+};
+
+/* PCM format to support channel resolution */
+static const u32 formats[COMP_MAX_WORDSIZE] = {
+       SNDRV_PCM_FMTBIT_S16_LE,
+       SNDRV_PCM_FMTBIT_S16_LE,
+       SNDRV_PCM_FMTBIT_S24_LE,
+       SNDRV_PCM_FMTBIT_S24_LE,
+       SNDRV_PCM_FMTBIT_S32_LE,
+       0,
+       0,
+       0
+};
+
+static int dw_configure_dai(struct dw_i2s_dev *dev,
+                                  struct snd_soc_dai_driver *dw_i2s_dai,
+                                  unsigned int rates)
+{
+       /*
+        * Read component parameter registers to extract
+        * the I2S block's configuration.
+        */
+       u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1);
+       u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2);
+       u32 idx;
+
+       if (COMP1_TX_ENABLED(comp1)) {
+               dev_dbg(dev->dev, " designware: play supported\n");
+               idx = COMP1_TX_WORDSIZE_0(comp1);
+               if (WARN_ON(idx >= ARRAY_SIZE(formats)))
+                       return -EINVAL;
+               dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM;
+               dw_i2s_dai->playback.channels_max =
+                               1 << (COMP1_TX_CHANNELS(comp1) + 1);
+               dw_i2s_dai->playback.formats = formats[idx];
+               dw_i2s_dai->playback.rates = rates;
+       }
+
+       if (COMP1_RX_ENABLED(comp1)) {
+               dev_dbg(dev->dev, "designware: record supported\n");
+               idx = COMP2_RX_WORDSIZE_0(comp2);
+               if (WARN_ON(idx >= ARRAY_SIZE(formats)))
+                       return -EINVAL;
+               dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM;
+               dw_i2s_dai->capture.channels_max =
+                               1 << (COMP1_RX_CHANNELS(comp1) + 1);
+               dw_i2s_dai->capture.formats = formats[idx];
+               dw_i2s_dai->capture.rates = rates;
+       }
+
+       return 0;
+}
+
+static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev,
+                                  struct snd_soc_dai_driver *dw_i2s_dai,
+                                  struct resource *res,
+                                  const struct i2s_platform_data *pdata)
+{
+       u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1);
+       u32 idx = COMP1_APB_DATA_WIDTH(comp1);
+       int ret;
+
+       if (WARN_ON(idx >= ARRAY_SIZE(bus_widths)))
+               return -EINVAL;
+
+       ret = dw_configure_dai(dev, dw_i2s_dai, pdata->snd_rates);
+       if (ret < 0)
+               return ret;
+
+       /* Set DMA slaves info */
+       dev->play_dma_data.pd.data = pdata->play_dma_data;
+       dev->capture_dma_data.pd.data = pdata->capture_dma_data;
+       dev->play_dma_data.pd.addr = res->start + I2S_TXDMA;
+       dev->capture_dma_data.pd.addr = res->start + I2S_RXDMA;
+       dev->play_dma_data.pd.max_burst = 16;
+       dev->capture_dma_data.pd.max_burst = 16;
+       dev->play_dma_data.pd.addr_width = bus_widths[idx];
+       dev->capture_dma_data.pd.addr_width = bus_widths[idx];
+       dev->play_dma_data.pd.filter = pdata->filter;
+       dev->capture_dma_data.pd.filter = pdata->filter;
+
+       return 0;
+}
+
+static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev,
+                                  struct snd_soc_dai_driver *dw_i2s_dai,
+                                  struct resource *res)
+{
+       u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1);
+       u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2);
+       u32 fifo_depth = 1 << (1 + COMP1_FIFO_DEPTH_GLOBAL(comp1));
+       u32 idx = COMP1_APB_DATA_WIDTH(comp1);
+       u32 idx2;
+       int ret;
+
+       if (WARN_ON(idx >= ARRAY_SIZE(bus_widths)))
+               return -EINVAL;
+
+       ret = dw_configure_dai(dev, dw_i2s_dai, SNDRV_PCM_RATE_8000_192000);
+       if (ret < 0)
+               return ret;
+
+       if (COMP1_TX_ENABLED(comp1)) {
+               idx2 = COMP1_TX_WORDSIZE_0(comp1);
+
+               dev->capability |= DWC_I2S_PLAY;
+               dev->play_dma_data.dt.addr = res->start + I2S_TXDMA;
+               dev->play_dma_data.dt.addr_width = bus_widths[idx];
+               dev->play_dma_data.dt.chan_name = "TX";
+               dev->play_dma_data.dt.fifo_size = fifo_depth *
+                       (fifo_width[idx2]) >> 8;
+               dev->play_dma_data.dt.maxburst = 16;
+       }
+       if (COMP1_RX_ENABLED(comp1)) {
+               idx2 = COMP2_RX_WORDSIZE_0(comp2);
+
+               dev->capability |= DWC_I2S_RECORD;
+               dev->capture_dma_data.dt.addr = res->start + I2S_RXDMA;
+               dev->capture_dma_data.dt.addr_width = bus_widths[idx];
+               dev->capture_dma_data.dt.chan_name = "RX";
+               dev->capture_dma_data.dt.fifo_size = fifo_depth *
+                       (fifo_width[idx2] >> 8);
+               dev->capture_dma_data.dt.maxburst = 16;
+       }
+
+       return 0;
+
+}
+
 static int dw_i2s_probe(struct platform_device *pdev)
 {
        const struct i2s_platform_data *pdata = pdev->dev.platform_data;
        struct dw_i2s_dev *dev;
        struct resource *res;
        int ret;
-       unsigned int cap;
        struct snd_soc_dai_driver *dw_i2s_dai;
 
-       if (!pdata) {
-               dev_err(&pdev->dev, "Invalid platform data\n");
-               return -EINVAL;
-       }
-
        dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
        if (!dev) {
                dev_warn(&pdev->dev, "kzalloc fail\n");
@@ -356,83 +537,67 @@ static int dw_i2s_probe(struct platform_device *pdev)
        }
 
        dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL);
-       if (!dw_i2s_dai) {
-               dev_err(&pdev->dev, "mem allocation failed for dai driver\n");
+       if (!dw_i2s_dai)
                return -ENOMEM;
-       }
 
        dw_i2s_dai->ops = &dw_i2s_dai_ops;
        dw_i2s_dai->suspend = dw_i2s_suspend;
        dw_i2s_dai->resume = dw_i2s_resume;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "no i2s resource defined\n");
-               return -ENODEV;
-       }
-
        dev->i2s_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(dev->i2s_base)) {
-               dev_err(&pdev->dev, "ioremap fail for i2s_region\n");
+       if (IS_ERR(dev->i2s_base))
                return PTR_ERR(dev->i2s_base);
-       }
 
-       cap = pdata->cap;
-       dev->capability = cap;
-       dev->i2s_clk_cfg = pdata->i2s_clk_cfg;
+       dev->dev = &pdev->dev;
+       if (pdata) {
+               ret = dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata);
+               if (ret < 0)
+                       return ret;
+
+               dev->capability = pdata->cap;
+               dev->i2s_clk_cfg = pdata->i2s_clk_cfg;
+               if (!dev->i2s_clk_cfg) {
+                       dev_err(&pdev->dev, "no clock configure method\n");
+                       return -ENODEV;
+               }
 
-       /* Set DMA slaves info */
+               dev->clk = devm_clk_get(&pdev->dev, NULL);
+       } else {
+               ret = dw_configure_dai_by_dt(dev, dw_i2s_dai, res);
+               if (ret < 0)
+                       return ret;
 
-       dev->play_dma_data.data = pdata->play_dma_data;
-       dev->capture_dma_data.data = pdata->capture_dma_data;
-       dev->play_dma_data.addr = res->start + I2S_TXDMA;
-       dev->capture_dma_data.addr = res->start + I2S_RXDMA;
-       dev->play_dma_data.max_burst = 16;
-       dev->capture_dma_data.max_burst = 16;
-       dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
-       dev->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
-       dev->play_dma_data.filter = pdata->filter;
-       dev->capture_dma_data.filter = pdata->filter;
-
-       dev->clk = clk_get(&pdev->dev, NULL);
+               dev->clk = devm_clk_get(&pdev->dev, "i2sclk");
+       }
        if (IS_ERR(dev->clk))
-               return  PTR_ERR(dev->clk);
+               return PTR_ERR(dev->clk);
 
-       ret = clk_enable(dev->clk);
+       ret = clk_prepare_enable(dev->clk);
        if (ret < 0)
-               goto err_clk_put;
-
-       if (cap & DWC_I2S_PLAY) {
-               dev_dbg(&pdev->dev, " designware: play supported\n");
-               dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM;
-               dw_i2s_dai->playback.channels_max = pdata->channel;
-               dw_i2s_dai->playback.formats = pdata->snd_fmts;
-               dw_i2s_dai->playback.rates = pdata->snd_rates;
-       }
-
-       if (cap & DWC_I2S_RECORD) {
-               dev_dbg(&pdev->dev, "designware: record supported\n");
-               dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM;
-               dw_i2s_dai->capture.channels_max = pdata->channel;
-               dw_i2s_dai->capture.formats = pdata->snd_fmts;
-               dw_i2s_dai->capture.rates = pdata->snd_rates;
-       }
+               return ret;
 
-       dev->dev = &pdev->dev;
        dev_set_drvdata(&pdev->dev, dev);
-       ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component,
+       ret = devm_snd_soc_register_component(&pdev->dev, &dw_i2s_component,
                                         dw_i2s_dai, 1);
        if (ret != 0) {
                dev_err(&pdev->dev, "not able to register dai\n");
                goto err_clk_disable;
        }
 
+       if (!pdata) {
+               ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "Could not register PCM: %d\n", ret);
+                       goto err_clk_disable;
+               }
+       }
+
        return 0;
 
 err_clk_disable:
-       clk_disable(dev->clk);
-err_clk_put:
-       clk_put(dev->clk);
+       clk_disable_unprepare(dev->clk);
        return ret;
 }
 
@@ -440,18 +605,26 @@ static int dw_i2s_remove(struct platform_device *pdev)
 {
        struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_component(&pdev->dev);
-
-       clk_put(dev->clk);
+       clk_disable_unprepare(dev->clk);
 
        return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id dw_i2s_of_match[] = {
+       { .compatible = "snps,designware-i2s",   },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, dw_i2s_of_match);
+#endif
+
 static struct platform_driver dw_i2s_driver = {
        .probe          = dw_i2s_probe,
        .remove         = dw_i2s_remove,
        .driver         = {
                .name   = "designware-i2s",
+               .of_match_table = of_match_ptr(dw_i2s_of_match),
        },
 };
 
index 9ce70fc67b0950b432a5be5d5e23d6cd4e631f43..e1aa3834b101e6cf19f4e1adac4b4e7cb1f074f0 100644 (file)
@@ -42,25 +42,6 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBM_CFM);
-       /* fsl_ssi lacks the set_fmt ops. */
-       if (ret && ret != -ENOTSUPP) {
-               dev_err(cpu_dai->dev,
-                       "Failed to set the cpu dai format.\n");
-               return ret;
-       }
-
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBM_CFM);
-       if (ret) {
-               dev_err(cpu_dai->dev,
-                       "Failed to set the codec format.\n");
-               return ret;
-       }
-
        ret = snd_soc_dai_set_sysclk(codec_dai, 0,
                                     CODEC_CLOCK, SND_SOC_CLOCK_OUT);
        if (ret) {
@@ -69,7 +50,7 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream,
                return ret;
        }
 
-       snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0);
+       snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 0);
 
        ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
                                SND_SOC_CLOCK_IN);
@@ -91,6 +72,8 @@ static struct snd_soc_dai_link eukrea_tlv320_dai = {
        .name           = "tlv320aic23",
        .stream_name    = "TLV320AIC23",
        .codec_dai_name = "tlv320aic23-hifi",
+       .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                         SND_SOC_DAIFMT_CBM_CFM,
        .ops            = &eukrea_tlv320_snd_ops,
 };
 
index 026a80117540be10568d92d2d95f000295c7074c..c068494bae305caaf1015f92636e32e16e475a55 100644 (file)
@@ -818,7 +818,6 @@ static int fsl_asrc_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        asrc_priv->pdev = pdev;
-       strncpy(asrc_priv->name, np->name, sizeof(asrc_priv->name) - 1);
 
        /* Get the addresses and IRQ */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -837,12 +836,12 @@ static int fsl_asrc_probe(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+               dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
                return irq;
        }
 
        ret = devm_request_irq(&pdev->dev, irq, fsl_asrc_isr, 0,
-                              asrc_priv->name, asrc_priv);
+                              dev_name(&pdev->dev), asrc_priv);
        if (ret) {
                dev_err(&pdev->dev, "failed to claim irq %u: %d\n", irq, ret);
                return ret;
index a3f211f53c23bfdf08d34acc0e518e79ce50f0e3..4aed63c4b431b519f3bccaa8f138bfabd1dcb6bf 100644 (file)
@@ -433,7 +433,6 @@ struct fsl_asrc_pair {
  * @channel_avail: non-occupied channel numbers
  * @asrc_rate: default sample rate for ASoC Back-Ends
  * @asrc_width: default sample width for ASoC Back-Ends
- * @name: driver name
  */
 struct fsl_asrc {
        struct snd_dmaengine_dai_dma_data dma_params_rx;
@@ -452,8 +451,6 @@ struct fsl_asrc {
 
        int asrc_rate;
        int asrc_width;
-
-       char name[32];
 };
 
 extern struct snd_soc_platform_driver fsl_asrc_platform;
index 1c08ab13637c6c5d65fb823f60db7c65538d07f6..5c7597191e3ffc682d1f813cdd9a6da8afbde397 100644 (file)
@@ -774,7 +774,7 @@ static int fsl_esai_probe(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+               dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
                return irq;
        }
 
index 032d2d33619c20be9aa9d63c807a238af26417b6..ec79c3d5e65e28acb24b6be4190a1fe091252e7a 100644 (file)
@@ -612,7 +612,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+               dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
                return irq;
        }
 
index af0429421fc8b4997874777acf58950908ec317f..75870c0ea2c9f613d9b4ebe3e10efd53430e5363 100644 (file)
@@ -90,7 +90,6 @@ struct spdif_mixer_control {
  * @sysclk: system clock for rx clock rate measurement
  * @dma_params_tx: DMA parameters for transmit channel
  * @dma_params_rx: DMA parameters for receive channel
- * @name: driver name
  */
 struct fsl_spdif_priv {
        struct spdif_mixer_control fsl_spdif_control;
@@ -109,12 +108,8 @@ struct fsl_spdif_priv {
        struct clk *sysclk;
        struct snd_dmaengine_dai_dma_data dma_params_tx;
        struct snd_dmaengine_dai_dma_data dma_params_rx;
-
-       /* The name space will be allocated dynamically */
-       char name[0];
 };
 
-
 /* DPLL locked and lock loss interrupt handler */
 static void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv)
 {
@@ -1169,19 +1164,15 @@ static int fsl_spdif_probe(struct platform_device *pdev)
        if (!np)
                return -ENODEV;
 
-       spdif_priv = devm_kzalloc(&pdev->dev,
-                       sizeof(struct fsl_spdif_priv) + strlen(np->name) + 1,
-                       GFP_KERNEL);
+       spdif_priv = devm_kzalloc(&pdev->dev, sizeof(*spdif_priv), GFP_KERNEL);
        if (!spdif_priv)
                return -ENOMEM;
 
-       strcpy(spdif_priv->name, np->name);
-
        spdif_priv->pdev = pdev;
 
        /* Initialize this copy of the CPU DAI driver structure */
        memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai));
-       spdif_priv->cpu_dai_drv.name = spdif_priv->name;
+       spdif_priv->cpu_dai_drv.name = dev_name(&pdev->dev);
 
        /* Get the addresses and IRQ */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1198,12 +1189,12 @@ static int fsl_spdif_probe(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+               dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
                return irq;
        }
 
        ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0,
-                       spdif_priv->name, spdif_priv);
+                              dev_name(&pdev->dev), spdif_priv);
        if (ret) {
                dev_err(&pdev->dev, "could not claim irq %u\n", irq);
                return ret;
index 059496ed9ad76c4771ccafbe593a1e0c971f9420..2595611e8a6ded3876345767bde2ce51e079c9ee 100644 (file)
@@ -160,7 +160,7 @@ struct fsl_ssi_soc_data {
  */
 struct fsl_ssi_private {
        struct regmap *regs;
-       unsigned int irq;
+       int irq;
        struct snd_soc_dai_driver cpu_dai_drv;
 
        unsigned int dai_fmt;
@@ -992,8 +992,8 @@ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
        regmap_update_bits(regs, CCSR_SSI_SCR, CCSR_SSI_SCR_SSIEN,
                        CCSR_SSI_SCR_SSIEN);
 
-       regmap_write(regs, CCSR_SSI_STMSK, tx_mask);
-       regmap_write(regs, CCSR_SSI_SRMSK, rx_mask);
+       regmap_write(regs, CCSR_SSI_STMSK, ~tx_mask);
+       regmap_write(regs, CCSR_SSI_SRMSK, ~rx_mask);
 
        regmap_update_bits(regs, CCSR_SSI_SCR, CCSR_SSI_SCR_SSIEN, val);
 
@@ -1362,8 +1362,8 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        }
 
        ssi_private->irq = platform_get_irq(pdev, 0);
-       if (ssi_private->irq < 0) {
-               dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+       if (!ssi_private->irq) {
+               dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
                return ssi_private->irq;
        }
 
index 2ac7755da8768dfe2b12a9d35a5aa5eda9e1d766..b9e42b503a37728b8a20a14a3979ada69ed82872 100644 (file)
@@ -86,33 +86,6 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np,
 }
 EXPORT_SYMBOL(fsl_asoc_get_dma_channel);
 
-/**
- * fsl_asoc_xlate_tdm_slot_mask - generate TDM slot TX/RX mask.
- *
- * @slots: Number of slots in use.
- * @tx_mask: bitmask representing active TX slots.
- * @rx_mask: bitmask representing active RX slots.
- *
- * This function used to generate the TDM slot TX/RX mask. And the TX/RX
- * mask will use a 0 bit for an active slot as default, and the default
- * active bits are at the LSB of the mask value.
- */
-int fsl_asoc_xlate_tdm_slot_mask(unsigned int slots,
-                                   unsigned int *tx_mask,
-                                   unsigned int *rx_mask)
-{
-       if (!slots)
-               return -EINVAL;
-
-       if (tx_mask)
-               *tx_mask = ~((1 << slots) - 1);
-       if (rx_mask)
-               *rx_mask = ~((1 << slots) - 1);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(fsl_asoc_xlate_tdm_slot_mask);
-
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
 MODULE_DESCRIPTION("Freescale ASoC utility code");
 MODULE_LICENSE("GPL v2");
index df535db40313e61ae25d6e46ba68a149c5e62346..1687b66ef18eb5dee972d28fd1da334fa3fe6b6d 100644 (file)
@@ -22,7 +22,4 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np, const char *name,
                             struct snd_soc_dai_link *dai,
                             unsigned int *dma_channel_id,
                             unsigned int *dma_id);
-int fsl_asoc_xlate_tdm_slot_mask(unsigned int slots,
-                                   unsigned int *tx_mask,
-                                   unsigned int *rx_mask);
 #endif /* _FSL_UTILS_H */
index 6bf5bce01a92124cbf8e84eeb67157fa8727a0f4..9e6493d4e7ff92e6a328dfa2d062349a314d88a0 100644 (file)
@@ -37,8 +37,7 @@ static int imx_mc13783_hifi_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int ret;
 
-       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xfffffffc, 0xfffffffc,
-                                       4, 16);
+       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 4, 16);
        if (ret)
                return ret;
 
@@ -46,7 +45,7 @@ static int imx_mc13783_hifi_hw_params(struct snd_pcm_substream *substream,
        if (ret)
                return ret;
 
-       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x0, 0xfffffffc, 2, 16);
+       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 16);
        if (ret)
                return ret;
 
index e94704f1b9ee52ed5dcea4006c6321ff30e26a6b..33da26a1245718f4b6e814bb22e04218ecc340fc 100644 (file)
@@ -60,6 +60,7 @@ static int imx_spdif_audio_probe(struct platform_device *pdev)
        data->card.dev = &pdev->dev;
        data->card.dai_link = &data->dai;
        data->card.num_links = 1;
+       data->card.owner = THIS_MODULE;
 
        ret = snd_soc_of_parse_card_name(&data->card, "model");
        if (ret)
index fa801e17c51e6222abbbce12e40e5cc9f50a56c2..461ce27b884f0f0b22dd6bb03216a1ee05f7e0fc 100644 (file)
@@ -74,8 +74,8 @@ static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
        sccr |= SSI_STCCR_DC(slots - 1);
        writel(sccr, ssi->base + SSI_SRCCR);
 
-       writel(tx_mask, ssi->base + SSI_STMSK);
-       writel(rx_mask, ssi->base + SSI_SRMSK);
+       writel(~tx_mask, ssi->base + SSI_STMSK);
+       writel(~rx_mask, ssi->base + SSI_SRMSK);
 
        return 0;
 }
@@ -340,7 +340,6 @@ static const struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
        .set_fmt        = imx_ssi_set_dai_fmt,
        .set_clkdiv     = imx_ssi_set_dai_clkdiv,
        .set_sysclk     = imx_ssi_set_dai_sysclk,
-       .xlate_tdm_slot_mask = fsl_asoc_xlate_tdm_slot_mask,
        .set_tdm_slot   = imx_ssi_set_dai_tdm_slot,
        .trigger        = imx_ssi_trigger,
 };
index b1ced7b8d80c472be45f1d578c622db1f07275fa..198eeb3f3f7a05b570f7a1e280b7228ce7cb0706 100644 (file)
@@ -55,16 +55,6 @@ static int mx27vis_aic32x4_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
-       u32 dai_format;
-
-       dai_format = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
-               SND_SOC_DAIFMT_CBM_CFM;
-
-       /* set codec DAI configuration */
-       snd_soc_dai_set_fmt(codec_dai, dai_format);
-
-       /* set cpu DAI configuration */
-       snd_soc_dai_set_fmt(cpu_dai, dai_format);
 
        ret = snd_soc_dai_set_sysclk(codec_dai, 0,
                                     25000000, SND_SOC_CLOCK_OUT);
@@ -164,6 +154,8 @@ static struct snd_soc_dai_link mx27vis_aic32x4_dai = {
        .platform_name  = "imx-ssi.0",
        .codec_name     = "tlv320aic32x4.0-0018",
        .cpu_dai_name   = "imx-ssi.0",
+       .dai_fmt        = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
+                         SND_SOC_DAIFMT_CBM_CFM,
        .ops            = &mx27vis_aic32x4_snd_ops,
 };
 
index 804749a6c61e3241763eace3f935f95b978a0d17..a958937ab405ce0d79e43942942c875ad69f66da 100644 (file)
@@ -87,7 +87,6 @@ static int wm1133_ev1_hw_params(struct snd_pcm_substream *substream,
        snd_pcm_format_t format = params_format(params);
        unsigned int rate = params_rate(params);
        unsigned int channels = params_channels(params);
-       u32 dai_format;
 
        /* find the correct audio parameters */
        for (i = 0; i < ARRAY_SIZE(wm8350_audio); i++) {
@@ -104,22 +103,13 @@ static int wm1133_ev1_hw_params(struct snd_pcm_substream *substream,
        /* codec FLL input is 14.75 MHz from MCLK */
        snd_soc_dai_set_pll(codec_dai, 0, 0, 14750000, wm8350_audio[i].sysclk);
 
-       dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-               SND_SOC_DAIFMT_CBM_CFM;
-
-       /* set codec DAI configuration */
-       snd_soc_dai_set_fmt(codec_dai, dai_format);
-
-       /* set cpu DAI configuration */
-       snd_soc_dai_set_fmt(cpu_dai, dai_format);
-
        /* TODO: The SSI driver should figure this out for us */
        switch (channels) {
        case 2:
-               snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0);
+               snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 0);
                break;
        case 1:
-               snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffe, 0xffffffe, 1, 0);
+               snd_soc_dai_set_tdm_slot(cpu_dai, 0x1, 0x1, 1, 0);
                break;
        default:
                return -EINVAL;
@@ -244,6 +234,8 @@ static struct snd_soc_dai_link wm1133_ev1_dai = {
        .init = wm1133_ev1_init,
        .ops = &wm1133_ev1_ops,
        .symmetric_rates = 1,
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBM_CFM,
 };
 
 static struct snd_soc_card wm1133_ev1 = {
index 7fe3009b1c43c63c055c4f9ea8f2b25376ad5c7b..f7c6734bd5daee1dafd76ba8b6feafa05b2a6c52 100644 (file)
@@ -39,6 +39,37 @@ struct simple_card_data {
 #define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i)
 #define simple_priv_to_props(priv, i) ((priv)->dai_props + i)
 
+static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct simple_dai_props *dai_props =
+               &priv->dai_props[rtd - rtd->card->rtd];
+       int ret;
+
+       ret = clk_prepare_enable(dai_props->cpu_dai.clk);
+       if (ret)
+               return ret;
+       
+       ret = clk_prepare_enable(dai_props->codec_dai.clk);
+       if (ret)
+               clk_disable_unprepare(dai_props->cpu_dai.clk);
+
+       return ret;
+}
+
+static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct simple_dai_props *dai_props =
+               &priv->dai_props[rtd - rtd->card->rtd];
+
+       clk_disable_unprepare(dai_props->cpu_dai.clk);
+
+       clk_disable_unprepare(dai_props->codec_dai.clk);
+}
+
 static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
                                      struct snd_pcm_hw_params *params)
 {
@@ -58,6 +89,8 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
 }
 
 static struct snd_soc_ops asoc_simple_card_ops = {
+       .startup = asoc_simple_card_startup,
+       .shutdown = asoc_simple_card_shutdown,
        .hw_params = asoc_simple_card_hw_params,
 };
 
@@ -219,6 +252,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
                }
 
                dai->sysclk = clk_get_rate(clk);
+               dai->clk = clk;
        } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) {
                dai->sysclk = val;
        } else {
index f86de1211b966c300fd43411254e8fdcb994297f..ee03dbdda235d7153507267226de62ccc2c4001a 100644 (file)
@@ -46,7 +46,7 @@ config SND_SOC_INTEL_BAYTRAIL
 
 config SND_SOC_INTEL_HASWELL_MACH
        tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
-       depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \\
+       depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \
                   I2C_DESIGNWARE_PLATFORM
        select SND_SOC_INTEL_HASWELL
        select SND_SOC_RT5640
@@ -76,7 +76,7 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH
 
 config SND_SOC_INTEL_BROADWELL_MACH
        tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
-       depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \\
+       depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \
                   I2C_DESIGNWARE_PLATFORM
        select SND_SOC_INTEL_HASWELL
        select SND_COMPRESS_OFFLOAD
@@ -110,3 +110,14 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
           platforms with RT5672 audio codec.
           Say Y if you have such a device
           If unsure select "N".
+
+config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
+       tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645 codec"
+       depends on X86_INTEL_LPSS
+       select SND_SOC_RT5645
+       select SND_SST_MFLD_PLATFORM
+       select SND_SST_IPC_ACPI
+       help
+         This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
+         platforms with RT5645 audio codec.
+         If unsure select "N".
index e928ec3853007fda4df561676925bd4d3ded2225..a8e53c45c6b655953ef93034bbc238707611b313 100644 (file)
@@ -28,6 +28,7 @@ snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o
 snd-soc-sst-broadwell-objs := broadwell.o
 snd-soc-sst-bytcr-dpcm-rt5640-objs := bytcr_dpcm_rt5640.o
 snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
+snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o
 
 obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
 obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
@@ -35,6 +36,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o
 obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o
 obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-dpcm-rt5640.o
 obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
+obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o
 
 # DSP driver
 obj-$(CONFIG_SND_SST_IPC) += sst/
index 7cf95d5d5d808f77d0558ecb8a521bdd1e26f541..9cf7d01479adcbd82661c70344b5f5d4ad0969fe 100644 (file)
@@ -140,8 +140,6 @@ static struct snd_soc_ops broadwell_rt286_ops = {
 
 static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev);
        struct sst_hsw *broadwell = pdata->dsp;
        int ret;
@@ -155,14 +153,6 @@ static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd)
                return ret;
        }
 
-       /* always connected - check HP for jack detect */
-       snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
-       snd_soc_dapm_enable_pin(dapm, "Speaker");
-       snd_soc_dapm_enable_pin(dapm, "Mic Jack");
-       snd_soc_dapm_enable_pin(dapm, "Line Jack");
-       snd_soc_dapm_enable_pin(dapm, "DMIC1");
-       snd_soc_dapm_enable_pin(dapm, "DMIC2");
-
        return 0;
 }
 
index 0cba7830c5e9df4d20ce90bab96625bf0596ff4b..354eaad886e1c09619b0d1e2f1269b9ef715aa3a 100644 (file)
@@ -132,7 +132,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 {
        int ret;
        struct snd_soc_codec *codec = runtime->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        struct snd_soc_card *card = runtime->card;
        const struct snd_soc_dapm_route *custom_map;
        int num_routes;
@@ -161,7 +160,7 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
                num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map);
        }
 
-       ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes);
+       ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes);
        if (ret)
                return ret;
 
@@ -171,13 +170,8 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
                        return ret;
        }
 
-       snd_soc_dapm_ignore_suspend(dapm, "HPOL");
-       snd_soc_dapm_ignore_suspend(dapm, "HPOR");
-
-       snd_soc_dapm_ignore_suspend(dapm, "SPOLP");
-       snd_soc_dapm_ignore_suspend(dapm, "SPOLN");
-       snd_soc_dapm_ignore_suspend(dapm, "SPORP");
-       snd_soc_dapm_ignore_suspend(dapm, "SPORN");
+       snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
+       snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
 
        return ret;
 }
index eef0c56ec32e8d8733c9780b5dc5d07ab56fc90f..59308629043e62dd2c2fa0bcc9e4cb126d7a74ba 100644 (file)
@@ -215,7 +215,6 @@ static int snd_byt_mc_probe(struct platform_device *pdev)
 
 static struct platform_driver snd_byt_mc_driver = {
        .driver = {
-               .owner = THIS_MODULE,
                .name = "bytt100_rt5640",
                .pm = &snd_soc_pm_ops,
        },
diff --git a/sound/soc/intel/cht_bsw_rt5645.c b/sound/soc/intel/cht_bsw_rt5645.c
new file mode 100644 (file)
index 0000000..bd29617
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ *  cht-bsw-rt5645.c - ASoc Machine driver for Intel Cherryview-based platforms
+ *                     Cherrytrail and Braswell, with RT5645 codec.
+ *
+ *  Copyright (C) 2015 Intel Corp
+ *  Author: Fang, Yang A <yang.a.fang@intel.com>
+ *             N,Harshapriya <harshapriya.n@intel.com>
+ *  This file is modified from cht_bsw_rt5672.c
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include "../codecs/rt5645.h"
+#include "sst-atom-controls.h"
+
+#define CHT_PLAT_CLK_3_HZ      19200000
+#define CHT_CODEC_DAI  "rt5645-aif1"
+
+struct cht_mc_private {
+       struct snd_soc_jack hp_jack;
+       struct snd_soc_jack mic_jack;
+};
+
+static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
+{
+       int i;
+
+       for (i = 0; i < card->num_rtd; i++) {
+               struct snd_soc_pcm_runtime *rtd;
+
+               rtd = card->rtd + i;
+               if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
+                            strlen(CHT_CODEC_DAI)))
+                       return rtd->codec_dai;
+       }
+       return NULL;
+}
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *k, int  event)
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct snd_soc_card *card = dapm->card;
+       struct snd_soc_dai *codec_dai;
+       int ret;
+
+       codec_dai = cht_get_codec_dai(card);
+       if (!codec_dai) {
+               dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
+               return -EIO;
+       }
+
+       if (!SND_SOC_DAPM_EVENT_OFF(event))
+               return 0;
+
+       /* Set codec sysclk source to its internal clock because codec PLL will
+        * be off when idle and MCLK will also be off by ACPI when codec is
+        * runtime suspended. Codec needs clock for jack detection and button
+        * press.
+        */
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_RCCLK,
+                       0, SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               dev_err(card->dev, "can't set codec sysclk: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Int Mic", NULL),
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),
+       SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+                       platform_clock_control, SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route cht_audio_map[] = {
+       {"IN1P", NULL, "Headset Mic"},
+       {"IN1N", NULL, "Headset Mic"},
+       {"DMIC L1", NULL, "Int Mic"},
+       {"DMIC R1", NULL, "Int Mic"},
+       {"Headphone", NULL, "HPOL"},
+       {"Headphone", NULL, "HPOR"},
+       {"Ext Spk", NULL, "SPOL"},
+       {"Ext Spk", NULL, "SPOR"},
+       {"AIF1 Playback", NULL, "ssp2 Tx"},
+       {"ssp2 Tx", NULL, "codec_out0"},
+       {"ssp2 Tx", NULL, "codec_out1"},
+       {"codec_in0", NULL, "ssp2 Rx" },
+       {"codec_in1", NULL, "ssp2 Rx" },
+       {"ssp2 Rx", NULL, "AIF1 Capture"},
+       {"Headphone", NULL, "Platform Clock"},
+       {"Headset Mic", NULL, "Platform Clock"},
+       {"Int Mic", NULL, "Platform Clock"},
+       {"Ext Spk", NULL, "Platform Clock"},
+};
+
+static const struct snd_kcontrol_new cht_mc_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Int Mic"),
+       SOC_DAPM_PIN_SWITCH("Ext Spk"),
+};
+
+static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       /* set codec PLL source to the 19.2MHz platform clock (MCLK) */
+       ret = snd_soc_dai_set_pll(codec_dai, 0, RT5645_PLL1_S_MCLK,
+                                 CHT_PLAT_CLK_3_HZ, params_rate(params) * 512);
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_PLL1,
+                               params_rate(params) * 512, SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+       int ret;
+       struct snd_soc_codec *codec = runtime->codec;
+       struct snd_soc_dai *codec_dai = runtime->codec_dai;
+       struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
+
+       /* Select clk_i2s1_asrc as ASRC clock source */
+       rt5645_sel_asrc_clk_src(codec,
+                               RT5645_DA_STEREO_FILTER |
+                               RT5645_DA_MONO_L_FILTER |
+                               RT5645_DA_MONO_R_FILTER |
+                               RT5645_AD_STEREO_FILTER,
+                               RT5645_CLK_SEL_I2S1_ASRC);
+
+       /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
+       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
+       if (ret < 0) {
+               dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_jack_new(codec, "Headphone Jack",
+                               SND_JACK_HEADPHONE,
+                               &ctx->hp_jack);
+       if (ret) {
+               dev_err(runtime->dev, "HP jack creation failed %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_jack_new(codec, "Mic Jack",
+                               SND_JACK_MICROPHONE,
+                               &ctx->mic_jack);
+       if (ret) {
+               dev_err(runtime->dev, "Mic jack creation failed %d\n", ret);
+               return ret;
+       }
+
+       rt5645_set_jack_detect(codec, &ctx->hp_jack, &ctx->mic_jack);
+
+       return ret;
+}
+
+static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
+                           struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate = hw_param_interval(params,
+                       SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval *channels = hw_param_interval(params,
+                                               SNDRV_PCM_HW_PARAM_CHANNELS);
+
+       /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+       rate->min = rate->max = 48000;
+       channels->min = channels->max = 2;
+
+       /* set SSP2 to 24-bit */
+       snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
+                                   SNDRV_PCM_HW_PARAM_FIRST_MASK],
+                                   SNDRV_PCM_FORMAT_S24_LE);
+       return 0;
+}
+
+static unsigned int rates_48000[] = {
+       48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_48000 = {
+       .count = ARRAY_SIZE(rates_48000),
+       .list  = rates_48000,
+};
+
+static int cht_aif1_startup(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE,
+                       &constraints_48000);
+}
+
+static struct snd_soc_ops cht_aif1_ops = {
+       .startup = cht_aif1_startup,
+};
+
+static struct snd_soc_ops cht_be_ssp2_ops = {
+       .hw_params = cht_aif1_hw_params,
+};
+
+static struct snd_soc_dai_link cht_dailink[] = {
+       [MERR_DPCM_AUDIO] = {
+               .name = "Audio Port",
+               .stream_name = "Audio",
+               .cpu_dai_name = "media-cpu-dai",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .codec_name = "snd-soc-dummy",
+               .platform_name = "sst-mfld-platform",
+               .ignore_suspend = 1,
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ops = &cht_aif1_ops,
+       },
+       [MERR_DPCM_COMPR] = {
+               .name = "Compressed Port",
+               .stream_name = "Compress",
+               .cpu_dai_name = "compress-cpu-dai",
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .codec_name = "snd-soc-dummy",
+               .platform_name = "sst-mfld-platform",
+       },
+       /* CODEC<->CODEC link */
+       /* back ends */
+       {
+               .name = "SSP2-Codec",
+               .be_id = 1,
+               .cpu_dai_name = "ssp2-port",
+               .platform_name = "sst-mfld-platform",
+               .no_pcm = 1,
+               .codec_dai_name = "rt5645-aif1",
+               .codec_name = "i2c-10EC5645:00",
+               .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
+                                       | SND_SOC_DAIFMT_CBS_CFS,
+               .init = cht_codec_init,
+               .be_hw_params_fixup = cht_codec_fixup,
+               .ignore_suspend = 1,
+               .dpcm_playback = 1,
+               .dpcm_capture = 1,
+               .ops = &cht_be_ssp2_ops,
+       },
+};
+
+/* SoC card */
+static struct snd_soc_card snd_soc_card_cht = {
+       .name = "chtrt5645",
+       .dai_link = cht_dailink,
+       .num_links = ARRAY_SIZE(cht_dailink),
+       .dapm_widgets = cht_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
+       .dapm_routes = cht_audio_map,
+       .num_dapm_routes = ARRAY_SIZE(cht_audio_map),
+       .controls = cht_mc_controls,
+       .num_controls = ARRAY_SIZE(cht_mc_controls),
+};
+
+static int snd_cht_mc_probe(struct platform_device *pdev)
+{
+       int ret_val = 0;
+       struct cht_mc_private *drv;
+
+       drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
+       if (!drv)
+               return -ENOMEM;
+
+       snd_soc_card_cht.dev = &pdev->dev;
+       snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
+       ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
+       if (ret_val) {
+               dev_err(&pdev->dev,
+                       "snd_soc_register_card failed %d\n", ret_val);
+               return ret_val;
+       }
+       platform_set_drvdata(pdev, &snd_soc_card_cht);
+       return ret_val;
+}
+
+static struct platform_driver snd_cht_mc_driver = {
+       .driver = {
+               .name = "cht-bsw-rt5645",
+               .pm = &snd_soc_pm_ops,
+       },
+       .probe = snd_cht_mc_probe,
+};
+
+module_platform_driver(snd_cht_mc_driver)
+
+MODULE_DESCRIPTION("ASoC Intel(R) Braswell Machine driver");
+MODULE_AUTHOR("Fang, Yang A,N,Harshapriya");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:cht-bsw-rt5645");
index 9b8b561171b72c421c297ca92e5491b85e1aa50a..ff016621583a63c85c96689270405cbc5640ab77 100644 (file)
@@ -140,6 +140,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
 {
        int ret;
        struct snd_soc_dai *codec_dai = runtime->codec_dai;
+       struct snd_soc_codec *codec = codec_dai->codec;
 
        /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
        ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
@@ -148,6 +149,19 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
                return ret;
        }
 
+       /* Select codec ASRC clock source to track I2S1 clock, because codec
+        * is in slave mode and 100fs I2S format (BCLK = 100 * LRCLK) cannot
+        * be supported by RT5672. Otherwise, ASRC will be disabled and cause
+        * noise.
+        */
+       rt5670_sel_asrc_clk_src(codec,
+                               RT5670_DA_STEREO_FILTER
+                               | RT5670_DA_MONO_L_FILTER
+                               | RT5670_DA_MONO_R_FILTER
+                               | RT5670_AD_STEREO_FILTER
+                               | RT5670_AD_MONO_L_FILTER
+                               | RT5670_AD_MONO_R_FILTER,
+                               RT5670_CLK_SEL_I2S1_ASRC);
        return 0;
 }
 
@@ -270,7 +284,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 
 static struct platform_driver snd_cht_mc_driver = {
        .driver = {
-               .owner = THIS_MODULE,
                .name = "cht-bsw-rt5672",
                .pm = &snd_soc_pm_ops,
        },
index 3bb6288d8b4d8af42a7ff866fd67832c7cc43466..224c49c9f1354200672e2a3cf782dfbb16b6aa7f 100644 (file)
@@ -320,11 +320,6 @@ static struct snd_pcm_ops sst_byt_pcm_ops = {
        .mmap           = sst_byt_pcm_mmap,
 };
 
-static void sst_byt_pcm_free(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_pcm *pcm = rtd->pcm;
@@ -403,7 +398,6 @@ static struct snd_soc_platform_driver byt_soc_platform = {
        .remove         = sst_byt_pcm_remove,
        .ops            = &sst_byt_pcm_ops,
        .pcm_new        = sst_byt_pcm_new,
-       .pcm_free       = sst_byt_pcm_free,
 };
 
 static const struct snd_soc_component_driver byt_dai_component = {
index 86e41084567002ebb999dca591b598a7224690fe..64e94212d2d2b129ebeddf9f1e4e55ac24775826 100644 (file)
@@ -410,8 +410,7 @@ void sst_dsp_free(struct sst_dsp *sst)
        if (sst->ops->free)
                sst->ops->free(sst);
 
-       if (sst->dma)
-               sst_dma_free(sst->dma);
+       sst_dma_free(sst->dma);
 }
 EXPORT_SYMBOL_GPL(sst_dsp_free);
 
index b3f9489794a6acad776fc2cf7670b6e12ab06bf6..5f71ef607a57e417715154b1697ee04ef0a13772 100644 (file)
@@ -497,6 +497,7 @@ struct sst_module *sst_module_new(struct sst_fw *sst_fw,
        sst_module->sst_fw = sst_fw;
        sst_module->scratch_size = template->scratch_size;
        sst_module->persistent_size = template->persistent_size;
+       sst_module->entry = template->entry;
 
        INIT_LIST_HEAD(&sst_module->block_list);
        INIT_LIST_HEAD(&sst_module->runtime_list);
@@ -790,6 +791,7 @@ int sst_module_alloc_blocks(struct sst_module *module)
        struct sst_block_allocator ba;
        int ret;
 
+       memset(&ba, 0, sizeof(ba));
        ba.size = module->size;
        ba.type = module->type;
        ba.offset = module->offset;
@@ -863,6 +865,7 @@ int sst_module_runtime_alloc_blocks(struct sst_module_runtime *runtime,
        if (module->persistent_size == 0)
                return 0;
 
+       memset(&ba, 0, sizeof(ba));
        ba.size = module->persistent_size;
        ba.type = SST_MEM_DRAM;
 
index 57039b00efc222481f872e2c0426c85cdf84391d..c42ffae5fe9f6acab9ebe5723862c4e3a3b4bf8d 100644 (file)
@@ -306,7 +306,7 @@ static void hsw_reset(struct sst_dsp *sst)
 static int hsw_set_dsp_D0(struct sst_dsp *sst)
 {
        int tries = 10;
-       u32 reg;
+       u32 reg, fw_dump_bit;
 
        /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
        reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
@@ -368,7 +368,9 @@ finish:
        can't be accessed, please enable each block before accessing. */
        reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
        reg |= SST_VDRTCL0_DSRAMPGE_MASK | SST_VDRTCL0_ISRAMPGE_MASK;
-       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
+       /* for D0, always enable the block(DSRAM[0]) used for FW dump */
+       fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT;
+       writel(reg & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0);
 
 
        /* disable DMA finish function for SSP0 & SSP1 */
@@ -491,6 +493,7 @@ static const struct sst_sram_shift sram_shift[] = {
        {SST_DEV_ID_LYNX_POINT, 6, 16}, /* lp */
        {SST_DEV_ID_WILDCAT_POINT, 2, 12}, /* wpt */
 };
+
 static u32 hsw_block_get_bit(struct sst_mem_block *block)
 {
        u32 bit = 0, shift = 0, index;
@@ -587,7 +590,9 @@ static int hsw_block_disable(struct sst_mem_block *block)
 
        val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
        bit = hsw_block_get_bit(block);
-       writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0);
+       /* don't disable DSRAM[0], keep it always enable for FW dump*/
+       if (bit != (1 << SST_VDRTCL0_DSRAMPGE_SHIFT))
+               writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0);
 
        /* wait 18 DSP clock ticks */
        udelay(10);
@@ -612,7 +617,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
        const struct sst_adsp_memregion *region;
        struct device *dev;
        int ret = -ENODEV, i, j, region_count;
-       u32 offset, size;
+       u32 offset, size, fw_dump_bit;
 
        dev = sst->dma_dev;
 
@@ -669,9 +674,11 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
                }
        }
 
+       /* always enable the block(DSRAM[0]) used for FW dump */
+       fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT;
        /* set default power gating control, enable power gating control for all blocks. that is,
        can't be accessed, please enable each block before accessing. */
-       writel(0xffffffff, sst->addr.pci_cfg + SST_VDRTCTL0);
+       writel(0xffffffff & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0);
 
        return 0;
 }
index 8156cc1accb79aec1c21751d51cd1dd2817bc48c..394af5684c05e37403b50b67ebaa7ead69d14f1f 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/debugfs.h>
 #include <linux/pm_runtime.h>
+#include <sound/asound.h>
 
 #include "sst-haswell-ipc.h"
 #include "sst-dsp.h"
@@ -94,6 +95,8 @@
 /* Mailbox */
 #define IPC_MAX_MAILBOX_BYTES  256
 
+#define INVALID_STREAM_HW_ID   0xffffffff
+
 /* Global Message - Types and Replies */
 enum ipc_glb_type {
        IPC_GLB_GET_FW_VERSION = 0,             /* Retrieves firmware version */
@@ -240,6 +243,9 @@ struct sst_hsw_stream {
        u32 (*notify_position)(struct sst_hsw_stream *stream, void *data);
        void *pdata;
 
+       /* record the fw read position when playback */
+       snd_pcm_uframes_t old_position;
+       bool play_silence;
        struct list_head node;
 };
 
@@ -275,7 +281,6 @@ struct sst_hsw {
        /* FW config */
        struct sst_hsw_ipc_fw_ready fw_ready;
        struct sst_hsw_ipc_fw_version version;
-       struct sst_module *scratch;
        bool fw_done;
        struct sst_fw *sst_fw;
 
@@ -337,12 +342,6 @@ static inline u32 msg_get_stage_type(u32 msg)
        return (msg & IPC_STG_TYPE_MASK) >>  IPC_STG_TYPE_SHIFT;
 }
 
-static inline u32 msg_set_stage_type(u32 msg, u32 type)
-{
-       return (msg & ~IPC_STG_TYPE_MASK) +
-               (type << IPC_STG_TYPE_SHIFT);
-}
-
 static inline u32 msg_get_stream_id(u32 msg)
 {
        return (msg & IPC_STR_ID_MASK) >>  IPC_STR_ID_SHIFT;
@@ -969,45 +968,6 @@ int sst_hsw_fw_get_version(struct sst_hsw *hsw,
 }
 
 /* Mixer Controls */
-int sst_hsw_stream_mute(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
-       u32 stage_id, u32 channel)
-{
-       int ret;
-
-       ret = sst_hsw_stream_get_volume(hsw, stream, stage_id, channel,
-               &stream->mute_volume[channel]);
-       if (ret < 0)
-               return ret;
-
-       ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel, 0);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n",
-                       stream->reply.stream_hw_id, channel);
-               return ret;
-       }
-
-       stream->mute[channel] = 1;
-       return 0;
-}
-
-int sst_hsw_stream_unmute(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
-       u32 stage_id, u32 channel)
-
-{
-       int ret;
-
-       stream->mute[channel] = 0;
-       ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel,
-               stream->mute_volume[channel]);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n",
-                       stream->reply.stream_hw_id, channel);
-               return ret;
-       }
-
-       return 0;
-}
-
 int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
        u32 stage_id, u32 channel, u32 *volume)
 {
@@ -1021,17 +981,6 @@ int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream
        return 0;
 }
 
-int sst_hsw_stream_set_volume_curve(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u64 curve_duration,
-       enum sst_hsw_volume_curve curve)
-{
-       /* curve duration in steps of 100ns */
-       stream->vol_req.curve_duration = curve_duration;
-       stream->vol_req.curve_type = curve;
-
-       return 0;
-}
-
 /* stream volume */
 int sst_hsw_stream_set_volume(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume)
@@ -1083,42 +1032,6 @@ int sst_hsw_stream_set_volume(struct sst_hsw *hsw,
        return 0;
 }
 
-int sst_hsw_mixer_mute(struct sst_hsw *hsw, u32 stage_id, u32 channel)
-{
-       int ret;
-
-       ret = sst_hsw_mixer_get_volume(hsw, stage_id, channel,
-               &hsw->mute_volume[channel]);
-       if (ret < 0)
-               return ret;
-
-       ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel, 0);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n",
-                       channel);
-               return ret;
-       }
-
-       hsw->mute[channel] = 1;
-       return 0;
-}
-
-int sst_hsw_mixer_unmute(struct sst_hsw *hsw, u32 stage_id, u32 channel)
-{
-       int ret;
-
-       ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel,
-               hsw->mixer_info.volume_register_address[channel]);
-       if (ret < 0) {
-               dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n",
-                       channel);
-               return ret;
-       }
-
-       hsw->mute[channel] = 0;
-       return 0;
-}
-
 int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
        u32 *volume)
 {
@@ -1132,16 +1045,6 @@ int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
        return 0;
 }
 
-int sst_hsw_mixer_set_volume_curve(struct sst_hsw *hsw,
-        u64 curve_duration, enum sst_hsw_volume_curve curve)
-{
-       /* curve duration in steps of 100ns */
-       hsw->curve_duration = curve_duration;
-       hsw->curve_type = curve;
-
-       return 0;
-}
-
 /* global mixer volume */
 int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
        u32 volume)
@@ -1208,6 +1111,7 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
                return NULL;
 
        spin_lock_irqsave(&sst->spinlock, flags);
+       stream->reply.stream_hw_id = INVALID_STREAM_HW_ID;
        list_add(&stream->node, &hsw->stream_list);
        stream->notify_position = notify_position;
        stream->pdata = data;
@@ -1447,50 +1351,32 @@ int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
        return 0;
 }
 
-/* Stream Information - these calls could be inline but we want the IPC
- ABI to be opaque to client PCM drivers to cope with any future ABI changes */
-int sst_hsw_stream_get_hw_id(struct sst_hsw *hsw,
+snd_pcm_uframes_t sst_hsw_stream_get_old_position(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream)
 {
-       return stream->reply.stream_hw_id;
+       return stream->old_position;
 }
 
-int sst_hsw_stream_get_mixer_id(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream)
+void sst_hsw_stream_set_old_position(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, snd_pcm_uframes_t val)
 {
-       return stream->reply.mixer_hw_id;
+       stream->old_position = val;
 }
 
-u32 sst_hsw_stream_get_read_reg(struct sst_hsw *hsw,
+bool sst_hsw_stream_get_silence_start(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream)
 {
-       return stream->reply.read_position_register_address;
-}
-
-u32 sst_hsw_stream_get_pointer_reg(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream)
-{
-       return stream->reply.presentation_position_register_address;
-}
-
-u32 sst_hsw_stream_get_peak_reg(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u32 channel)
-{
-       if (channel >= 2)
-               return 0;
-
-       return stream->reply.peak_meter_register_address[channel];
+       return stream->play_silence;
 }
 
-u32 sst_hsw_stream_get_vol_reg(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u32 channel)
+void sst_hsw_stream_set_silence_start(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, bool val)
 {
-       if (channel >= 2)
-               return 0;
-
-       return stream->reply.volume_register_address[channel];
+       stream->play_silence = val;
 }
 
+/* Stream Information - these calls could be inline but we want the IPC
+ ABI to be opaque to client PCM drivers to cope with any future ABI changes */
 int sst_hsw_mixer_get_info(struct sst_hsw *hsw)
 {
        struct sst_hsw_ipc_stream_info_reply *reply;
@@ -1628,30 +1514,6 @@ u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw,
        return ppos;
 }
 
-int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u32 stage_id, u32 position)
-{
-       u32 header;
-       int ret;
-
-       trace_stream_write_position(stream->reply.stream_hw_id, position);
-
-       header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) |
-               IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE);
-       header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT);
-       header |= (IPC_STG_SET_WRITE_POSITION << IPC_STG_TYPE_SHIFT);
-       header |= (stage_id << IPC_STG_ID_SHIFT);
-       stream->wpos.position = position;
-
-       ret = ipc_tx_message_nowait(hsw, header, &stream->wpos,
-               sizeof(stream->wpos));
-       if (ret < 0)
-               dev_err(hsw->dev, "error: stream %d set position %d failed\n",
-                       stream->reply.stream_hw_id, position);
-
-       return ret;
-}
-
 /* physical BE config */
 int sst_hsw_device_set_config(struct sst_hsw *hsw,
        enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk,
@@ -2132,7 +1994,6 @@ void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata)
        dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE,
                        hsw->dx_context, hsw->dx_context_paddr);
        sst_dsp_free(hsw->dsp);
-       kfree(hsw->scratch);
        kthread_stop(hsw->tx_thread);
        kfree(hsw->msg);
 }
index 138e894ab41338fe1ebfa289b5f4507d2d6ee3dd..858096041cb1bb2ca604c4823f1b7e521f240494 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
+#include <sound/asound.h>
 
 #define SST_HSW_NO_CHANNELS            4
 #define SST_HSW_MAX_DX_REGIONS         14
@@ -376,32 +377,17 @@ int sst_hsw_fw_get_version(struct sst_hsw *hsw,
 u32 create_channel_map(enum sst_hsw_channel_config config);
 
 /* Stream Mixer Controls - */
-int sst_hsw_stream_mute(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
-       u32 stage_id, u32 channel);
-int sst_hsw_stream_unmute(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
-       u32 stage_id, u32 channel);
-
 int sst_hsw_stream_set_volume(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume);
 int sst_hsw_stream_get_volume(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 *volume);
 
-int sst_hsw_stream_set_volume_curve(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u64 curve_duration,
-       enum sst_hsw_volume_curve curve);
-
 /* Global Mixer Controls - */
-int sst_hsw_mixer_mute(struct sst_hsw *hsw, u32 stage_id, u32 channel);
-int sst_hsw_mixer_unmute(struct sst_hsw *hsw, u32 stage_id, u32 channel);
-
 int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
        u32 volume);
 int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
        u32 *volume);
 
-int sst_hsw_mixer_set_volume_curve(struct sst_hsw *hsw,
-       u64 curve_duration, enum sst_hsw_volume_curve curve);
-
 /* Stream API */
 struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
        u32 (*get_write_position)(struct sst_hsw_stream *stream, void *data),
@@ -440,18 +426,14 @@ int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream, u32 offset, u32 size);
 int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream, u32 offset, u32 size);
-int sst_hsw_stream_get_hw_id(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream);
-int sst_hsw_stream_get_mixer_id(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream);
-u32 sst_hsw_stream_get_read_reg(struct sst_hsw *hsw,
+snd_pcm_uframes_t sst_hsw_stream_get_old_position(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream);
-u32 sst_hsw_stream_get_pointer_reg(struct sst_hsw *hsw,
+void sst_hsw_stream_set_old_position(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, snd_pcm_uframes_t val);
+bool sst_hsw_stream_get_silence_start(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream);
-u32 sst_hsw_stream_get_peak_reg(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u32 channel);
-u32 sst_hsw_stream_get_vol_reg(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u32 channel);
+void sst_hsw_stream_set_silence_start(struct sst_hsw *hsw,
+       struct sst_hsw_stream *stream, bool val);
 int sst_hsw_mixer_get_info(struct sst_hsw *hsw);
 
 /* Stream ALSA trigger operations */
@@ -466,8 +448,6 @@ int sst_hsw_stream_get_read_pos(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream, u32 *position);
 int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream, u32 *position);
-int sst_hsw_stream_set_write_position(struct sst_hsw *hsw,
-       struct sst_hsw_stream *stream, u32 stage_id, u32 position);
 u32 sst_hsw_get_dsp_position(struct sst_hsw *hsw,
        struct sst_hsw_stream *stream);
 u64 sst_hsw_get_dsp_presentation_position(struct sst_hsw *hsw,
@@ -481,8 +461,6 @@ int sst_hsw_device_set_config(struct sst_hsw *hsw,
 /* DX Config */
 int sst_hsw_dx_set_state(struct sst_hsw *hsw,
        enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx);
-int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item,
-       u32 *offset, u32 *size, u32 *source);
 
 /* init */
 int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata);
index 619525200705e3651be1780a229d3b7dc2d35537..d6fa9d5514e1923997066ec1e14c7dafac281387 100644 (file)
 #define HSW_PCM_COUNT          6
 #define HSW_VOLUME_MAX         0x7FFFFFFF      /* 0dB */
 
+#define SST_OLD_POSITION(d, r, o) ((d) +               \
+                       frames_to_bytes(r, o))
+#define SST_SAMPLES(r, x) (bytes_to_samples(r, \
+                       frames_to_bytes(r, (x))))
+
 /* simple volume table */
 static const u32 volume_map[] = {
        HSW_VOLUME_MAX >> 30,
@@ -78,7 +83,6 @@ static const u32 volume_map[] = {
 #define HSW_PCM_DAI_ID_OFFLOAD0        1
 #define HSW_PCM_DAI_ID_OFFLOAD1        2
 #define HSW_PCM_DAI_ID_LOOPBACK        3
-#define HSW_PCM_DAI_ID_CAPTURE 4
 
 
 static const struct snd_pcm_hardware hsw_pcm_hardware = {
@@ -99,6 +103,7 @@ static const struct snd_pcm_hardware hsw_pcm_hardware = {
 
 struct hsw_pcm_module_map {
        int dai_id;
+       int stream;
        enum sst_hsw_module_id mod_id;
 };
 
@@ -119,8 +124,9 @@ struct hsw_pcm_data {
 };
 
 enum hsw_pm_state {
-       HSW_PM_STATE_D3 = 0,
-       HSW_PM_STATE_D0 = 1,
+       HSW_PM_STATE_D0 = 0,
+       HSW_PM_STATE_RTD3 = 1,
+       HSW_PM_STATE_D3 = 2,
 };
 
 /* private data for the driver */
@@ -135,7 +141,17 @@ struct hsw_priv_data {
        struct snd_dma_buffer dmab[HSW_PCM_COUNT][2];
 
        /* DAI data */
-       struct hsw_pcm_data pcm[HSW_PCM_COUNT];
+       struct hsw_pcm_data pcm[HSW_PCM_COUNT][2];
+};
+
+
+/* static mappings between PCMs and modules - may be dynamic in future */
+static struct hsw_pcm_module_map mod_map[] = {
+       {HSW_PCM_DAI_ID_SYSTEM, 0, SST_HSW_MODULE_PCM_SYSTEM},
+       {HSW_PCM_DAI_ID_OFFLOAD0, 0, SST_HSW_MODULE_PCM},
+       {HSW_PCM_DAI_ID_OFFLOAD1, 0, SST_HSW_MODULE_PCM},
+       {HSW_PCM_DAI_ID_LOOPBACK, 1, SST_HSW_MODULE_PCM_REFERENCE},
+       {HSW_PCM_DAI_ID_SYSTEM, 1, SST_HSW_MODULE_PCM_CAPTURE},
 };
 
 static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data);
@@ -168,9 +184,14 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
                (struct soc_mixer_control *)kcontrol->private_value;
        struct hsw_priv_data *pdata =
                snd_soc_platform_get_drvdata(platform);
-       struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
+       struct hsw_pcm_data *pcm_data;
        struct sst_hsw *hsw = pdata->hsw;
        u32 volume;
+       int dai, stream;
+
+       dai = mod_map[mc->reg].dai_id;
+       stream = mod_map[mc->reg].stream;
+       pcm_data = &pdata->pcm[dai][stream];
 
        mutex_lock(&pcm_data->mutex);
        pm_runtime_get_sync(pdata->dev);
@@ -212,9 +233,14 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
                (struct soc_mixer_control *)kcontrol->private_value;
        struct hsw_priv_data *pdata =
                snd_soc_platform_get_drvdata(platform);
-       struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
+       struct hsw_pcm_data *pcm_data;
        struct sst_hsw *hsw = pdata->hsw;
        u32 volume;
+       int dai, stream;
+
+       dai = mod_map[mc->reg].dai_id;
+       stream = mod_map[mc->reg].stream;
+       pcm_data = &pdata->pcm[dai][stream];
 
        mutex_lock(&pcm_data->mutex);
        pm_runtime_get_sync(pdata->dev);
@@ -309,7 +335,7 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = {
                ARRAY_SIZE(volume_map) - 1, 0,
                hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
        /* Mic Capture volume */
-       SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 0, 0, 8,
+       SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8,
                ARRAY_SIZE(volume_map) - 1, 0,
                hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
 };
@@ -353,7 +379,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct hsw_priv_data *pdata =
                snd_soc_platform_get_drvdata(rtd->platform);
-       struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+       struct hsw_pcm_data *pcm_data;
        struct sst_hsw *hsw = pdata->hsw;
        struct sst_module *module_data;
        struct sst_dsp *dsp;
@@ -362,7 +388,10 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
        enum sst_hsw_stream_path_id path_id;
        u32 rate, bits, map, pages, module_id;
        u8 channels;
-       int ret;
+       int ret, dai;
+
+       dai = mod_map[rtd->cpu_dai->id].dai_id;
+       pcm_data = &pdata->pcm[dai][substream->stream];
 
        /* check if we are being called a subsequent time */
        if (pcm_data->allocated) {
@@ -552,20 +581,35 @@ static int hsw_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct hsw_priv_data *pdata =
                snd_soc_platform_get_drvdata(rtd->platform);
-       struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+       struct hsw_pcm_data *pcm_data;
+       struct sst_hsw_stream *sst_stream;
        struct sst_hsw *hsw = pdata->hsw;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       snd_pcm_uframes_t pos;
+       int dai;
+
+       dai = mod_map[rtd->cpu_dai->id].dai_id;
+       pcm_data = &pdata->pcm[dai][substream->stream];
+       sst_stream = pcm_data->stream;
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               sst_hsw_stream_set_silence_start(hsw, sst_stream, false);
                sst_hsw_stream_resume(hsw, pcm_data->stream, 0);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               sst_hsw_stream_set_silence_start(hsw, sst_stream, false);
                sst_hsw_stream_pause(hsw, pcm_data->stream, 0);
                break;
+       case SNDRV_PCM_TRIGGER_DRAIN:
+               pos = runtime->control->appl_ptr % runtime->buffer_size;
+               sst_hsw_stream_set_old_position(hsw, pcm_data->stream, pos);
+               sst_hsw_stream_set_silence_start(hsw, sst_stream, true);
+               break;
        default:
                break;
        }
@@ -579,13 +623,62 @@ static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data)
        struct snd_pcm_substream *substream = pcm_data->substream;
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct hsw_priv_data *pdata =
+               snd_soc_platform_get_drvdata(rtd->platform);
+       struct sst_hsw *hsw = pdata->hsw;
        u32 pos;
+       snd_pcm_uframes_t position = bytes_to_frames(runtime,
+                sst_hsw_get_dsp_position(hsw, pcm_data->stream));
+       unsigned char *dma_area = runtime->dma_area;
+       snd_pcm_uframes_t dma_frames =
+               bytes_to_frames(runtime, runtime->dma_bytes);
+       snd_pcm_uframes_t old_position;
+       ssize_t samples;
 
        pos = frames_to_bytes(runtime,
                (runtime->control->appl_ptr % runtime->buffer_size));
 
        dev_vdbg(rtd->dev, "PCM: App pointer %d bytes\n", pos);
 
+       /* SST fw don't know where to stop dma
+        * So, SST driver need to clean the data which has been consumed
+        */
+       if (dma_area == NULL || dma_frames <= 0
+               || (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+               || !sst_hsw_stream_get_silence_start(hsw, stream)) {
+               snd_pcm_period_elapsed(substream);
+               return pos;
+       }
+
+       old_position = sst_hsw_stream_get_old_position(hsw, stream);
+       if (position > old_position) {
+               if (position < dma_frames) {
+                       samples = SST_SAMPLES(runtime, position - old_position);
+                       snd_pcm_format_set_silence(runtime->format,
+                               SST_OLD_POSITION(dma_area,
+                                       runtime, old_position),
+                               samples);
+               } else
+                       dev_err(rtd->dev, "PCM: position is wrong\n");
+       } else {
+               if (old_position < dma_frames) {
+                       samples = SST_SAMPLES(runtime,
+                               dma_frames - old_position);
+                       snd_pcm_format_set_silence(runtime->format,
+                               SST_OLD_POSITION(dma_area,
+                                       runtime, old_position),
+                               samples);
+               } else
+                       dev_err(rtd->dev, "PCM: dma_bytes is wrong\n");
+               if (position < dma_frames) {
+                       samples = SST_SAMPLES(runtime, position);
+                       snd_pcm_format_set_silence(runtime->format,
+                               dma_area, samples);
+               } else
+                       dev_err(rtd->dev, "PCM: position is wrong\n");
+       }
+       sst_hsw_stream_set_old_position(hsw, stream, position);
+
        /* let alsa know we have play a period */
        snd_pcm_period_elapsed(substream);
        return pos;
@@ -597,11 +690,16 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct hsw_priv_data *pdata =
                snd_soc_platform_get_drvdata(rtd->platform);
-       struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+       struct hsw_pcm_data *pcm_data;
        struct sst_hsw *hsw = pdata->hsw;
        snd_pcm_uframes_t offset;
        uint64_t ppos;
-       u32 position = sst_hsw_get_dsp_position(hsw, pcm_data->stream);
+       u32 position;
+       int dai;
+
+       dai = mod_map[rtd->cpu_dai->id].dai_id;
+       pcm_data = &pdata->pcm[dai][substream->stream];
+       position = sst_hsw_get_dsp_position(hsw, pcm_data->stream);
 
        offset = bytes_to_frames(runtime, position);
        ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream);
@@ -618,8 +716,10 @@ static int hsw_pcm_open(struct snd_pcm_substream *substream)
                snd_soc_platform_get_drvdata(rtd->platform);
        struct hsw_pcm_data *pcm_data;
        struct sst_hsw *hsw = pdata->hsw;
+       int dai;
 
-       pcm_data = &pdata->pcm[rtd->cpu_dai->id];
+       dai = mod_map[rtd->cpu_dai->id].dai_id;
+       pcm_data = &pdata->pcm[dai][substream->stream];
 
        mutex_lock(&pcm_data->mutex);
        pm_runtime_get_sync(pdata->dev);
@@ -648,9 +748,12 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream)
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct hsw_priv_data *pdata =
                snd_soc_platform_get_drvdata(rtd->platform);
-       struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+       struct hsw_pcm_data *pcm_data;
        struct sst_hsw *hsw = pdata->hsw;
-       int ret;
+       int ret, dai;
+
+       dai = mod_map[rtd->cpu_dai->id].dai_id;
+       pcm_data = &pdata->pcm[dai][substream->stream];
 
        mutex_lock(&pcm_data->mutex);
        ret = sst_hsw_stream_reset(hsw, pcm_data->stream);
@@ -685,15 +788,6 @@ static struct snd_pcm_ops hsw_pcm_ops = {
        .page           = snd_pcm_sgbuf_ops_page,
 };
 
-/* static mappings between PCMs and modules - may be dynamic in future */
-static struct hsw_pcm_module_map mod_map[] = {
-       {HSW_PCM_DAI_ID_SYSTEM, SST_HSW_MODULE_PCM_SYSTEM},
-       {HSW_PCM_DAI_ID_OFFLOAD0, SST_HSW_MODULE_PCM},
-       {HSW_PCM_DAI_ID_OFFLOAD1, SST_HSW_MODULE_PCM},
-       {HSW_PCM_DAI_ID_LOOPBACK, SST_HSW_MODULE_PCM_REFERENCE},
-       {HSW_PCM_DAI_ID_CAPTURE, SST_HSW_MODULE_PCM_CAPTURE},
-};
-
 static int hsw_pcm_create_modules(struct hsw_priv_data *pdata)
 {
        struct sst_hsw *hsw = pdata->hsw;
@@ -701,7 +795,7 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata)
        int i;
 
        for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
-               pcm_data = &pdata->pcm[i];
+               pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
 
                /* create new runtime module, use same offset if recreated */
                pcm_data->runtime = sst_hsw_runtime_module_create(hsw,
@@ -716,7 +810,7 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata)
 
 err:
        for (--i; i >= 0; i--) {
-               pcm_data = &pdata->pcm[i];
+               pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
                sst_hsw_runtime_module_free(pcm_data->runtime);
        }
 
@@ -729,17 +823,12 @@ static void hsw_pcm_free_modules(struct hsw_priv_data *pdata)
        int i;
 
        for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
-               pcm_data = &pdata->pcm[i];
+               pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
 
                sst_hsw_runtime_module_free(pcm_data->runtime);
        }
 }
 
-static void hsw_pcm_free(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_pcm *pcm = rtd->pcm;
@@ -762,7 +851,10 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
                        return ret;
                }
        }
-       priv_data->pcm[rtd->cpu_dai->id].hsw_pcm = pcm;
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
+               priv_data->pcm[rtd->cpu_dai->id][SNDRV_PCM_STREAM_PLAYBACK].hsw_pcm = pcm;
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream)
+               priv_data->pcm[rtd->cpu_dai->id][SNDRV_PCM_STREAM_CAPTURE].hsw_pcm = pcm;
 
        return ret;
 }
@@ -871,10 +963,9 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
        /* allocate DSP buffer page tables */
        for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
 
-               mutex_init(&priv_data->pcm[i].mutex);
-
                /* playback */
                if (hsw_dais[i].playback.channels_min) {
+                       mutex_init(&priv_data->pcm[i][SNDRV_PCM_STREAM_PLAYBACK].mutex);
                        ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev,
                                PAGE_SIZE, &priv_data->dmab[i][0]);
                        if (ret < 0)
@@ -883,6 +974,7 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
 
                /* capture */
                if (hsw_dais[i].capture.channels_min) {
+                       mutex_init(&priv_data->pcm[i][SNDRV_PCM_STREAM_CAPTURE].mutex);
                        ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev,
                                PAGE_SIZE, &priv_data->dmab[i][1]);
                        if (ret < 0)
@@ -936,7 +1028,6 @@ static struct snd_soc_platform_driver hsw_soc_platform = {
        .remove         = hsw_pcm_remove,
        .ops            = &hsw_pcm_ops,
        .pcm_new        = hsw_pcm_new,
-       .pcm_free       = hsw_pcm_free,
 };
 
 static const struct snd_soc_component_driver hsw_dai_component = {
@@ -1010,12 +1101,12 @@ static int hsw_pcm_runtime_suspend(struct device *dev)
        struct hsw_priv_data *pdata = dev_get_drvdata(dev);
        struct sst_hsw *hsw = pdata->hsw;
 
-       if (pdata->pm_state == HSW_PM_STATE_D3)
+       if (pdata->pm_state >= HSW_PM_STATE_RTD3)
                return 0;
 
        sst_hsw_dsp_runtime_suspend(hsw);
        sst_hsw_dsp_runtime_sleep(hsw);
-       pdata->pm_state = HSW_PM_STATE_D3;
+       pdata->pm_state = HSW_PM_STATE_RTD3;
 
        return 0;
 }
@@ -1026,7 +1117,7 @@ static int hsw_pcm_runtime_resume(struct device *dev)
        struct sst_hsw *hsw = pdata->hsw;
        int ret;
 
-       if (pdata->pm_state == HSW_PM_STATE_D0)
+       if (pdata->pm_state != HSW_PM_STATE_RTD3)
                return 0;
 
        ret = sst_hsw_dsp_load(hsw);
@@ -1066,7 +1157,7 @@ static void hsw_pcm_complete(struct device *dev)
        struct hsw_pcm_data *pcm_data;
        int i, err;
 
-       if (pdata->pm_state == HSW_PM_STATE_D0)
+       if (pdata->pm_state != HSW_PM_STATE_D3)
                return;
 
        err = sst_hsw_dsp_load(hsw);
@@ -1081,8 +1172,8 @@ static void hsw_pcm_complete(struct device *dev)
                return;
        }
 
-       for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) {
-               pcm_data = &pdata->pcm[i];
+       for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
+               pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
 
                if (!pcm_data->substream)
                        continue;
@@ -1114,41 +1205,42 @@ static int hsw_pcm_prepare(struct device *dev)
 
        if (pdata->pm_state == HSW_PM_STATE_D3)
                return 0;
-       /* suspend all active streams */
-       for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) {
-               pcm_data = &pdata->pcm[i];
+       else if (pdata->pm_state == HSW_PM_STATE_D0) {
+               /* suspend all active streams */
+               for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
+                       pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
+
+                       if (!pcm_data->substream)
+                               continue;
+                       dev_dbg(dev, "suspending pcm %d\n", i);
+                       snd_pcm_suspend_all(pcm_data->hsw_pcm);
+
+                       /* We need to wait until the DSP FW stops the streams */
+                       msleep(2);
+               }
 
-               if (!pcm_data->substream)
-                       continue;
-               dev_dbg(dev, "suspending pcm %d\n", i);
-               snd_pcm_suspend_all(pcm_data->hsw_pcm);
+               /* preserve persistent memory */
+               for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
+                       pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
+
+                       if (!pcm_data->substream)
+                               continue;
 
-               /* We need to wait until the DSP FW stops the streams */
-               msleep(2);
+                       dev_dbg(dev, "saving context pcm %d\n", i);
+                       err = sst_module_runtime_save(pcm_data->runtime,
+                               &pcm_data->context);
+                       if (err < 0)
+                               dev_err(dev, "failed to save context for PCM %d\n", i);
+               }
+               /* enter D3 state and stall */
+               sst_hsw_dsp_runtime_suspend(hsw);
+               /* put the DSP to sleep */
+               sst_hsw_dsp_runtime_sleep(hsw);
        }
 
        snd_soc_suspend(pdata->soc_card->dev);
        snd_soc_poweroff(pdata->soc_card->dev);
 
-       /* enter D3 state and stall */
-       sst_hsw_dsp_runtime_suspend(hsw);
-
-       /* preserve persistent memory */
-       for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) {
-               pcm_data = &pdata->pcm[i];
-
-               if (!pcm_data->substream)
-                       continue;
-
-               dev_dbg(dev, "saving context pcm %d\n", i);
-               err = sst_module_runtime_save(pcm_data->runtime,
-                       &pcm_data->context);
-               if (err < 0)
-                       dev_err(dev, "failed to save context for PCM %d\n", i);
-       }
-
-       /* put the DSP to sleep */
-       sst_hsw_dsp_runtime_sleep(hsw);
        pdata->pm_state = HSW_PM_STATE_D3;
 
        return 0;
index a1a8d9d91539cb6625042d0a5c530a2b0d84c3a9..7523cbef87807f2b3ac0d4209e939a5b1bda7567 100644 (file)
@@ -643,12 +643,6 @@ static struct snd_pcm_ops sst_platform_ops = {
        .pointer = sst_platform_pcm_pointer,
 };
 
-static void sst_pcm_free(struct snd_pcm *pcm)
-{
-       dev_dbg(pcm->dev, "sst_pcm_free called\n");
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_dai *dai = rtd->cpu_dai;
@@ -679,7 +673,6 @@ static struct snd_soc_platform_driver sst_soc_platform_drv  = {
        .ops            = &sst_platform_ops,
        .compr_ops      = &sst_platform_compr_ops,
        .pcm_new        = sst_pcm_new,
-       .pcm_free       = sst_pcm_free,
 };
 
 static const struct snd_soc_component_driver sst_component = {
index 7f4bbfcbc6f552956977954b1cea39d12927fa81..562bc483d6b7f73924c6cd25fd2770b8c48bdc6b 100644 (file)
@@ -58,6 +58,7 @@ enum sst_algo_ops {
 #define SST_BLOCK_TIMEOUT      1000
 
 #define FW_SIGNATURE_SIZE      4
+#define FW_NAME_SIZE           32
 
 /* stream states */
 enum sst_stream_states {
@@ -426,7 +427,7 @@ struct intel_sst_drv {
         * Holder for firmware name. Due to async call it needs to be
         * persistent till worker thread gets called
         */
-       char firmware_name[20];
+       char firmware_name[FW_NAME_SIZE];
 };
 
 /* misc definitions */
index b3360139c41a905ba9575574d42b7477dd0cbc26..b782dfdcdbba10202150257e3aa695e55ec63e24 100644 (file)
@@ -47,7 +47,7 @@ struct sst_machines {
        char board[32];
        char machine[32];
        void (*machine_quirk)(void);
-       char firmware[32];
+       char firmware[FW_NAME_SIZE];
        struct sst_platform_info *pdata;
 
 };
@@ -245,7 +245,7 @@ static struct sst_machines *sst_acpi_find_machine(
        return NULL;
 }
 
-int sst_acpi_probe(struct platform_device *pdev)
+static int sst_acpi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        int ret = 0;
@@ -332,7 +332,7 @@ do_sst_cleanup:
 * This function is called by OS when a device is unloaded
 * This frees the interrupt etc
 */
-int sst_acpi_remove(struct platform_device *pdev)
+static int sst_acpi_remove(struct platform_device *pdev)
 {
        struct intel_sst_drv *ctx;
 
@@ -352,6 +352,8 @@ static struct sst_machines sst_acpi_bytcr[] = {
 static struct sst_machines sst_acpi_chv[] = {
        {"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "intel/fw_sst_22a8.bin",
                                                &chv_platform_data },
+       {"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin",
+                                               &chv_platform_data },
        {},
 };
 
@@ -366,7 +368,6 @@ MODULE_DEVICE_TABLE(acpi, sst_acpi_ids);
 static struct platform_driver sst_acpi_driver = {
        .driver = {
                .name                   = "intel_sst_acpi",
-               .owner                  = THIS_MODULE,
                .acpi_match_table       = ACPI_PTR(sst_acpi_ids),
                .pm                     = &intel_sst_pm,
        },
index b580f96e25e5e0c57a6699765adb8fe4ac9a8dba..7888cd707853db0a9819125d71cb063629514d9d 100644 (file)
@@ -324,8 +324,7 @@ void sst_firmware_load_cb(const struct firmware *fw, void *context)
 
        if (ctx->sst_state != SST_RESET ||
                        ctx->fw_in_mem != NULL) {
-               if (fw != NULL)
-                       release_firmware(fw);
+               release_firmware(fw);
                mutex_unlock(&ctx->sst_lock);
                return;
        }
index d3d45c6f064f37d7f72647d8aca6948a8772a077..07f77815a586fea295cf40f14a66f4c2cdedf73c 100644 (file)
@@ -14,6 +14,8 @@
 
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
@@ -83,6 +85,8 @@
 #define JZ_AIC_I2S_STATUS_BUSY BIT(2)
 
 #define JZ_AIC_CLK_DIV_MASK 0xf
+#define I2SDIV_DV_SHIFT 8
+#define I2SDIV_DV_MASK (0xf << I2SDIV_DV_SHIFT)
 
 struct jz4740_i2s {
        struct resource *mem;
@@ -237,10 +241,14 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
 {
        struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
        unsigned int sample_size;
-       uint32_t ctrl;
+       uint32_t ctrl, div_reg;
+       int div;
 
        ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL);
 
+       div_reg = jz4740_i2s_read(i2s, JZ_REG_AIC_CLK_DIV);
+       div = clk_get_rate(i2s->clk_i2s) / (64 * params_rate(params));
+
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S8:
                sample_size = 0;
@@ -264,7 +272,10 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
                ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET;
        }
 
+       div_reg &= ~I2SDIV_DV_MASK;
+       div_reg |= (div - 1) << I2SDIV_DV_SHIFT;
        jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
+       jz4740_i2s_write(i2s, JZ_REG_AIC_CLK_DIV, div_reg);
 
        return 0;
 }
@@ -415,6 +426,13 @@ static const struct snd_soc_component_driver jz4740_i2s_component = {
        .name           = "jz4740-i2s",
 };
 
+#ifdef CONFIG_OF
+static const struct of_device_id jz4740_of_matches[] = {
+       { .compatible = "ingenic,jz4740-i2s" },
+       { /* sentinel */ }
+};
+#endif
+
 static int jz4740_i2s_dev_probe(struct platform_device *pdev)
 {
        struct jz4740_i2s *i2s;
@@ -455,6 +473,7 @@ static struct platform_driver jz4740_i2s_driver = {
        .probe = jz4740_i2s_dev_probe,
        .driver = {
                .name = "jz4740-i2s",
+               .of_match_table = of_match_ptr(jz4740_of_matches)
        },
 };
 
index d9865082160cbe6b2081a5c2748c04e048343459..c866ade28ad0a6a0005a9ec97e09c05bfa63a783 100644 (file)
@@ -710,7 +710,7 @@ static int mxs_saif_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        struct resource *iores;
        struct mxs_saif *saif;
-       int ret = 0;
+       int irq, ret = 0;
        struct device_node *master;
 
        if (!np)
@@ -763,16 +763,16 @@ static int mxs_saif_probe(struct platform_device *pdev)
        if (IS_ERR(saif->base))
                return PTR_ERR(saif->base);
 
-       saif->irq = platform_get_irq(pdev, 0);
-       if (saif->irq < 0) {
-               ret = saif->irq;
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               ret = irq;
                dev_err(&pdev->dev, "failed to get irq resource: %d\n",
                        ret);
                return ret;
        }
 
        saif->dev = &pdev->dev;
-       ret = devm_request_irq(&pdev->dev, saif->irq, mxs_saif_irq, 0,
+       ret = devm_request_irq(&pdev->dev, irq, mxs_saif_irq, 0,
                               dev_name(&pdev->dev), saif);
        if (ret) {
                dev_err(&pdev->dev, "failed to request irq\n");
index fbaf7badfdfb03b7d26eb84fd5c1be5850d06d1a..9a4c0b291b9e4c3675ed221f8c862266d290e01a 100644 (file)
@@ -116,7 +116,6 @@ struct mxs_saif {
        unsigned int mclk;
        unsigned int mclk_in_use;
        void __iomem *base;
-       int irq;
        unsigned int id;
        unsigned int master_id;
        unsigned int cur_rate;
index 6f1916b71815f3d5e509e2abbee69d1ccfdc8df4..6e6fce6a14ba6dc1c2ab14d054df8f5b07b2caea 100644 (file)
@@ -36,7 +36,7 @@ static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int rate = params_rate(params);
-       u32 dai_format, mclk;
+       u32 mclk;
        int ret;
 
        /* sgtl5000 does not support 512*rate when in 96000 fs */
@@ -65,26 +65,6 @@ static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream,
                return ret;
        }
 
-       /* set codec to slave mode */
-       dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-                       SND_SOC_DAIFMT_CBS_CFS;
-
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, dai_format);
-       if (ret) {
-               dev_err(codec_dai->dev, "Failed to set dai format to %08x\n",
-                       dai_format);
-               return ret;
-       }
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, dai_format);
-       if (ret) {
-               dev_err(cpu_dai->dev, "Failed to set dai format to %08x\n",
-                       dai_format);
-               return ret;
-       }
-
        return 0;
 }
 
@@ -92,17 +72,22 @@ static struct snd_soc_ops mxs_sgtl5000_hifi_ops = {
        .hw_params = mxs_sgtl5000_hw_params,
 };
 
+#define MXS_SGTL5000_DAI_FMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \
+       SND_SOC_DAIFMT_CBS_CFS)
+
 static struct snd_soc_dai_link mxs_sgtl5000_dai[] = {
        {
                .name           = "HiFi Tx",
                .stream_name    = "HiFi Playback",
                .codec_dai_name = "sgtl5000",
+               .dai_fmt        = MXS_SGTL5000_DAI_FMT,
                .ops            = &mxs_sgtl5000_hifi_ops,
                .playback_only  = true,
        }, {
                .name           = "HiFi Rx",
                .stream_name    = "HiFi Capture",
                .codec_dai_name = "sgtl5000",
+               .dai_fmt        = MXS_SGTL5000_DAI_FMT,
                .ops            = &mxs_sgtl5000_hifi_ops,
                .capture_only   = true,
        },
index b779a3d9b5dd4ded757e565141e98f5cbc0f3394..b809fa909e4d6d6f91a78bdf5e9cda0e7f9c2fa8 100644 (file)
@@ -306,11 +306,6 @@ static struct snd_pcm_ops nuc900_dma_ops = {
        .mmap           = nuc900_dma_mmap,
 };
 
-static void nuc900_dma_free_dma_buffers(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static int nuc900_dma_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
@@ -330,7 +325,6 @@ static int nuc900_dma_new(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_platform_driver nuc900_soc_platform = {
        .ops            = &nuc900_dma_ops,
        .pcm_new        = nuc900_dma_new,
-       .pcm_free       = nuc900_dma_free_dma_buffers,
 };
 
 static int nuc900_soc_platform_probe(struct platform_device *pdev)
index 4c6afb75eea61eeb5c89014f2fc27fb80e3bae96..706613077c155e93d7952aab02c49ccfccafaecc 100644 (file)
@@ -412,21 +412,7 @@ static struct tty_ldisc_ops cx81801_ops = {
  * over the modem port.
  */
 
-static int ams_delta_hw_params(struct snd_pcm_substream *substream,
-                        struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-
-       /* Set cpu DAI configuration */
-       return snd_soc_dai_set_fmt(rtd->cpu_dai,
-                                  SND_SOC_DAIFMT_DSP_A |
-                                  SND_SOC_DAIFMT_NB_NF |
-                                  SND_SOC_DAIFMT_CBM_CFM);
-}
-
-static struct snd_soc_ops ams_delta_ops = {
-       .hw_params = ams_delta_hw_params,
-};
+static struct snd_soc_ops ams_delta_ops;
 
 
 /* Digital mute implemented using modem/CPU multiplexer.
@@ -546,6 +532,8 @@ static struct snd_soc_dai_link ams_delta_dai_link = {
        .platform_name = "omap-mcbsp.1",
        .codec_name = "cx20442-codec",
        .ops = &ams_delta_ops,
+       .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBM_CFM,
 };
 
 /* Audio card driver */
index 3f9ac7dbdc80141e15737105b8c29a0f5317caba..ccfb41c22e53b11cedbf5d8272a56a757ad283d1 100644 (file)
@@ -393,7 +393,6 @@ static int omap_hdmi_audio_remove(struct platform_device *pdev)
 static struct platform_driver hdmi_audio_driver = {
        .driver = {
                .name = DRV_NAME,
-               .owner = THIS_MODULE,
        },
        .probe = omap_hdmi_audio_probe,
        .remove = omap_hdmi_audio_remove,
index 5e551c762b7a9ccc04532b1bf4855e3dfeba42c2..fb1f6bb87cd430d816e250a2b5d7317c4744c6a7 100644 (file)
@@ -53,11 +53,7 @@ static int omap_twl4030_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_card *card = rtd->card;
        unsigned int fmt;
-       int ret;
 
        switch (params_channels(params)) {
        case 2: /* Stereo I2S mode */
@@ -74,21 +70,7 @@ static int omap_twl4030_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       /* Set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, fmt);
-       if (ret < 0) {
-               dev_err(card->dev, "can't set codec DAI configuration\n");
-               return ret;
-       }
-
-       /* Set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
-       if (ret < 0) {
-               dev_err(card->dev, "can't set cpu DAI configuration\n");
-               return ret;
-       }
-
-       return 0;
+       return snd_soc_runtime_set_dai_fmt(rtd, fmt);
 }
 
 static struct snd_soc_ops omap_twl4030_ops = {
index 04896d6252a23909ff62a6cb36121e312718d9ce..7f299357c2d207c457cb9918a5b0a9cc618a3253 100644 (file)
@@ -250,14 +250,14 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"FM Transmitter", NULL, "LLOUT"},
        {"FM Transmitter", NULL, "RLOUT"},
 
-       {"DMic Rate 64", NULL, "Mic Bias"},
-       {"Mic Bias", NULL, "DMic"},
+       {"DMic Rate 64", NULL, "DMic"},
+       {"DMic", NULL, "Mic Bias"},
 
        {"b LINE2R", NULL, "MONO_LOUT"},
        {"Earphone", NULL, "b HPLOUT"},
 
-       {"LINE1L", NULL, "b Mic Bias"},
-       {"b Mic Bias", NULL, "HS Mic"}
+       {"LINE1L", NULL, "HS Mic"},
+       {"HS Mic", NULL, "b Mic Bias"},
 };
 
 static const char * const spk_function[] = {"Off", "On"};
index 2434b6d61675af01959c2f20db2af26db3ffb639..39cea80846c313f552a1a39f4ba9e015b9958a5a 100644 (file)
@@ -140,7 +140,7 @@ config SND_PXA910_SOC
          Marvell PXA910 reference platform.
 
 config SND_SOC_TTC_DKB
-       bool "SoC Audio support for TTC DKB"
+       tristate "SoC Audio support for TTC DKB"
        depends on SND_PXA910_SOC && MACH_TTC_DKB && I2C=y
        select PXA_SSP
        select SND_PXA_SOC_SSP
index b7cd0a71fd707bc2d27807a4813be4f0025d762b..3580d10c9f282312056d6ad3952b6adbcf632ffe 100644 (file)
@@ -259,20 +259,6 @@ static const struct snd_kcontrol_new wm8731_corgi_controls[] = {
                corgi_set_spk),
 };
 
-/*
- * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device
- */
-static int corgi_wm8731_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_nc_pin(dapm, "LLINEIN");
-       snd_soc_dapm_nc_pin(dapm, "RLINEIN");
-
-       return 0;
-}
-
 /* corgi digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link corgi_dai = {
        .name = "WM8731",
@@ -281,7 +267,6 @@ static struct snd_soc_dai_link corgi_dai = {
        .codec_dai_name = "wm8731-hifi",
        .platform_name = "pxa-pcm-audio",
        .codec_name = "wm8731.0-001b",
-       .init = corgi_wm8731_init,
        .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                   SND_SOC_DAIFMT_CBS_CFS,
        .ops = &corgi_ops,
@@ -300,6 +285,7 @@ static struct snd_soc_card corgi = {
        .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
        .dapm_routes = corgi_audio_map,
        .num_dapm_routes = ARRAY_SIZE(corgi_audio_map),
+       .fully_routed = true,
 };
 
 static int corgi_probe(struct platform_device *pdev)
index 7c691aae8af29f4307a2a1c5be4ef4df47747ed0..d72e124a3676bf545be9d0afa49e6180973a00b2 100644 (file)
@@ -88,24 +88,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Mic Amp", NULL, "Mic (Internal)"},
 };
 
-static int e740_ac97_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_nc_pin(dapm, "HPOUTL");
-       snd_soc_dapm_nc_pin(dapm, "HPOUTR");
-       snd_soc_dapm_nc_pin(dapm, "PHONE");
-       snd_soc_dapm_nc_pin(dapm, "LINEINL");
-       snd_soc_dapm_nc_pin(dapm, "LINEINR");
-       snd_soc_dapm_nc_pin(dapm, "CDINL");
-       snd_soc_dapm_nc_pin(dapm, "CDINR");
-       snd_soc_dapm_nc_pin(dapm, "PCBEEP");
-       snd_soc_dapm_nc_pin(dapm, "MIC2");
-
-       return 0;
-}
-
 static struct snd_soc_dai_link e740_dai[] = {
        {
                .name = "AC97",
@@ -114,7 +96,6 @@ static struct snd_soc_dai_link e740_dai[] = {
                .codec_dai_name = "wm9705-hifi",
                .platform_name = "pxa-pcm-audio",
                .codec_name = "wm9705-codec",
-               .init = e740_ac97_init,
        },
        {
                .name = "AC97 Aux",
@@ -136,6 +117,7 @@ static struct snd_soc_card e740 = {
        .num_dapm_widgets = ARRAY_SIZE(e740_dapm_widgets),
        .dapm_routes = audio_map,
        .num_dapm_routes = ARRAY_SIZE(audio_map),
+       .fully_routed = true,
 };
 
 static struct gpio e740_audio_gpios[] = {
index 30544b65b5a812a6f62f9de1757900a2c929af05..48f2d7c2e68c2621f7cce3c6225a166ae8f0920f 100644 (file)
@@ -70,24 +70,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"MIC1", NULL, "Mic (Internal)"},
 };
 
-static int e750_ac97_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_nc_pin(dapm, "LOUT");
-       snd_soc_dapm_nc_pin(dapm, "ROUT");
-       snd_soc_dapm_nc_pin(dapm, "PHONE");
-       snd_soc_dapm_nc_pin(dapm, "LINEINL");
-       snd_soc_dapm_nc_pin(dapm, "LINEINR");
-       snd_soc_dapm_nc_pin(dapm, "CDINL");
-       snd_soc_dapm_nc_pin(dapm, "CDINR");
-       snd_soc_dapm_nc_pin(dapm, "PCBEEP");
-       snd_soc_dapm_nc_pin(dapm, "MIC2");
-
-       return 0;
-}
-
 static struct snd_soc_dai_link e750_dai[] = {
        {
                .name = "AC97",
@@ -96,7 +78,6 @@ static struct snd_soc_dai_link e750_dai[] = {
                .codec_dai_name = "wm9705-hifi",
                .platform_name = "pxa-pcm-audio",
                .codec_name = "wm9705-codec",
-               .init = e750_ac97_init,
                /* use ops to check startup state */
        },
        {
@@ -119,6 +100,7 @@ static struct snd_soc_card e750 = {
        .num_dapm_widgets = ARRAY_SIZE(e750_dapm_widgets),
        .dapm_routes = audio_map,
        .num_dapm_routes = ARRAY_SIZE(audio_map),
+       .fully_routed = true,
 };
 
 static struct gpio e750_audio_gpios[] = {
index ce26551052a325eb7f8f496b6679d422db71e398..73eb5ddf9753beb405b7d64fae88ede40d57bab2 100644 (file)
@@ -127,15 +127,8 @@ static const struct snd_soc_dapm_route hx4700_audio_map[] = {
 static int hx4700_ak4641_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int err;
 
-       /* NC codec pins */
-       /* FIXME: is anything connected here? */
-       snd_soc_dapm_nc_pin(dapm, "MOUT1");
-       snd_soc_dapm_nc_pin(dapm, "MICEXT");
-       snd_soc_dapm_nc_pin(dapm, "AUX");
-
        /* Jack detection API stuff */
        err = snd_soc_jack_new(codec, "Headphone Jack",
                                SND_JACK_HEADPHONE, &hs_jack);
@@ -184,6 +177,7 @@ static struct snd_soc_card snd_soc_card_hx4700 = {
        .num_dapm_widgets       = ARRAY_SIZE(hx4700_dapm_widgets),
        .dapm_routes            = hx4700_audio_map,
        .num_dapm_routes        = ARRAY_SIZE(hx4700_audio_map),
+       .fully_routed           = true,
 };
 
 static struct gpio hx4700_audio_gpios[] = {
index 259e048681c0fd4bdfc1d4e67c3b3b804fe73504..241d0be42d7a0c6779bb6459c5165728cbedb302 100644 (file)
@@ -391,25 +391,6 @@ static const struct snd_kcontrol_new uda1380_magician_controls[] = {
                        magician_get_input, magician_set_input),
 };
 
-/*
- * Logic for a uda1380 as connected on a HTC Magician
- */
-static int magician_uda1380_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       /* NC codec pins */
-       snd_soc_dapm_nc_pin(dapm, "VOUTLHP");
-       snd_soc_dapm_nc_pin(dapm, "VOUTRHP");
-
-       /* FIXME: is anything connected here? */
-       snd_soc_dapm_nc_pin(dapm, "VINL");
-       snd_soc_dapm_nc_pin(dapm, "VINR");
-
-       return 0;
-}
-
 /* magician digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link magician_dai[] = {
 {
@@ -419,7 +400,6 @@ static struct snd_soc_dai_link magician_dai[] = {
        .codec_dai_name = "uda1380-hifi-playback",
        .platform_name = "pxa-pcm-audio",
        .codec_name = "uda1380-codec.0-0018",
-       .init = magician_uda1380_init,
        .ops = &magician_playback_ops,
 },
 {
@@ -446,6 +426,7 @@ static struct snd_soc_card snd_soc_card_magician = {
        .num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets),
        .dapm_routes = audio_map,
        .num_dapm_routes = ARRAY_SIZE(audio_map),
+       .fully_routed = true,
 };
 
 static struct platform_device *magician_snd_device;
index 396dbd51a64f0183d787841b78a35adffd96de2f..a9615a574546988f6fc8e83fe5a018dc05528cba 100644 (file)
@@ -81,7 +81,7 @@ static int rear_amp_power(struct snd_soc_codec *codec, int power)
 static int rear_amp_event(struct snd_soc_dapm_widget *widget,
                          struct snd_kcontrol *kctl, int event)
 {
-       struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_codec *codec = widget->dapm->card->rtd[0].codec;
 
        return rear_amp_power(codec, SND_SOC_DAPM_EVENT_ON(event));
 }
index 1eebca2f0a97e9356c09273e1c94eed1ef7da14d..910336c5ebebd1486048552af7f598b6d7747b0d 100644 (file)
@@ -68,7 +68,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Ext. Speaker", NULL, "ROUT2"},
 
        /* mic connected to MIC1 */
-       {"Ext. Microphone", NULL, "MIC1"},
+       {"MIC1", NULL, "Ext. Microphone"},
 };
 
 static struct snd_soc_card palm27x_asoc;
@@ -76,18 +76,8 @@ static struct snd_soc_card palm27x_asoc;
 static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int err;
 
-       /* not connected pins */
-       snd_soc_dapm_nc_pin(dapm, "OUT3");
-       snd_soc_dapm_nc_pin(dapm, "MONOOUT");
-       snd_soc_dapm_nc_pin(dapm, "LINEINL");
-       snd_soc_dapm_nc_pin(dapm, "LINEINR");
-       snd_soc_dapm_nc_pin(dapm, "PCBEEP");
-       snd_soc_dapm_nc_pin(dapm, "PHONE");
-       snd_soc_dapm_nc_pin(dapm, "MIC2");
-
        /* Jack detection API stuff */
        err = snd_soc_jack_new(codec, "Headphone Jack",
                                SND_JACK_HEADPHONE, &hs_jack);
@@ -133,7 +123,8 @@ static struct snd_soc_card palm27x_asoc = {
        .dapm_widgets = palm27x_dapm_widgets,
        .num_dapm_widgets = ARRAY_SIZE(palm27x_dapm_widgets),
        .dapm_routes = audio_map,
-       .num_dapm_routes = ARRAY_SIZE(audio_map)
+       .num_dapm_routes = ARRAY_SIZE(audio_map),
+       .fully_routed = true,
 };
 
 static int palm27x_asoc_probe(struct platform_device *pdev)
index 083706595495956005fa6b91e731dc1796de44db..552b763005ed34d14ae46ebb82cb71bafa6c6c40 100644 (file)
@@ -88,7 +88,7 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       unsigned int fmt, clk = 0;
+       unsigned int clk = 0;
        int ret = 0;
 
        switch (params_rate(params)) {
@@ -112,15 +112,6 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       fmt = SND_SOC_DAIFMT_I2S |
-             SND_SOC_DAIFMT_NB_NF |
-             SND_SOC_DAIFMT_CBS_CFS;
-
-       /* setup the CODEC DAI */
-       ret = snd_soc_dai_set_fmt(codec_dai, fmt);
-       if (ret < 0)
-               return ret;
-
        ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, 0);
        if (ret < 0)
                return ret;
@@ -130,10 +121,6 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
-       if (ret < 0)
-               return ret;
-
        ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
        if (ret < 0)
                return ret;
@@ -169,9 +156,8 @@ static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream,
                                     struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int fmt, ret = 0, clk = 0;
+       int ret = 0, clk = 0;
 
        switch (params_rate(params)) {
        case 44100:
@@ -194,22 +180,11 @@ static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF;
-
-       /* setup the CODEC DAI */
-       ret = snd_soc_dai_set_fmt(codec_dai, fmt | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        /* setup the CPU DAI */
        ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_fmt(cpu_dai, fmt | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
        if (ret < 0)
                return ret;
@@ -233,6 +208,9 @@ static struct snd_soc_ops raumfeld_ak4104_ops = {
        .platform_name  = "pxa-pcm-audio",              \
        .codec_dai_name = "cs4270-hifi",                \
        .codec_name     = "cs4270.0-0048",      \
+       .dai_fmt        = SND_SOC_DAIFMT_I2S |          \
+                         SND_SOC_DAIFMT_NB_NF |        \
+                         SND_SOC_DAIFMT_CBS_CFS,       \
        .ops            = &raumfeld_cs4270_ops,         \
 }
 
@@ -243,6 +221,9 @@ static struct snd_soc_ops raumfeld_ak4104_ops = {
        .cpu_dai_name   = "pxa-ssp-dai.1",              \
        .codec_dai_name = "ak4104-hifi",                \
        .platform_name  = "pxa-pcm-audio",              \
+       .dai_fmt        = SND_SOC_DAIFMT_I2S |          \
+                         SND_SOC_DAIFMT_NB_NF |        \
+                         SND_SOC_DAIFMT_CBS_CFS,       \
        .ops            = &raumfeld_ak4104_ops,         \
        .codec_name     = "spi0.0",                     \
 }
index d7d5fb20ea6f461f70fcfca85f928db617fba1bb..461123ad5ff2d4c56e21a97a14e27f8ce7d841c4 100644 (file)
@@ -256,26 +256,6 @@ static const struct snd_kcontrol_new wm8750_spitz_controls[] = {
                spitz_set_spk),
 };
 
-/*
- * Logic for a wm8750 as connected on a Sharp SL-Cxx00 Device
- */
-static int spitz_wm8750_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       /* NC codec pins */
-       snd_soc_dapm_nc_pin(dapm, "RINPUT1");
-       snd_soc_dapm_nc_pin(dapm, "LINPUT2");
-       snd_soc_dapm_nc_pin(dapm, "RINPUT2");
-       snd_soc_dapm_nc_pin(dapm, "LINPUT3");
-       snd_soc_dapm_nc_pin(dapm, "RINPUT3");
-       snd_soc_dapm_nc_pin(dapm, "OUT3");
-       snd_soc_dapm_nc_pin(dapm, "MONO1");
-
-       return 0;
-}
-
 /* spitz digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link spitz_dai = {
        .name = "wm8750",
@@ -284,7 +264,6 @@ static struct snd_soc_dai_link spitz_dai = {
        .codec_dai_name = "wm8750-hifi",
        .platform_name = "pxa-pcm-audio",
        .codec_name = "wm8750.0-001b",
-       .init = spitz_wm8750_init,
        .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                   SND_SOC_DAIFMT_CBS_CFS,
        .ops = &spitz_ops,
@@ -303,6 +282,7 @@ static struct snd_soc_card snd_soc_spitz = {
        .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
        .dapm_routes = spitz_audio_map,
        .num_dapm_routes = ARRAY_SIZE(spitz_audio_map),
+       .fully_routed = true,
 };
 
 static int spitz_probe(struct platform_device *pdev)
@@ -352,7 +332,6 @@ static int spitz_remove(struct platform_device *pdev)
 static struct platform_driver spitz_driver = {
        .driver         = {
                .name   = "spitz-audio",
-               .owner  = THIS_MODULE,
                .pm     = &snd_soc_pm_ops,
        },
        .probe          = spitz_probe,
index e3d7257ad09ca1fa115c674d0d75eb6abae653e7..5001dbb9b257764d9b88427de5bc86bebfba5a7b 100644 (file)
@@ -76,10 +76,6 @@ static const struct snd_soc_dapm_route ttc_audio_map[] = {
 static int ttc_pm860x_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_disable_pin(dapm, "Headset Mic 2");
-       snd_soc_dapm_disable_pin(dapm, "Headset Stereophone");
 
        /* Headset jack detection */
        snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
index 23bf991e95d53fa282f3b8e6dfbd2e9e2eeada21..8f301c72ee5e2b9ffe8eeb975db0f75afd1d1a16 100644 (file)
@@ -130,16 +130,6 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        return 0;
 }
 
@@ -172,6 +162,8 @@ static struct snd_soc_dai_link zylonite_dai[] = {
        .platform_name = "pxa-pcm-audio",
        .cpu_dai_name = "pxa-ssp-dai.2",
        .codec_dai_name = "wm9713-voice",
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBS_CFS,
        .ops = &zylonite_voice_ops,
 },
 };
index dcc26eda0539b470f37382dacdc78622a8da0a95..acb5be53bfb4ddbd6879437e58b7dcfe990bd201 100644 (file)
@@ -247,6 +247,10 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
 
        regmap_update_bits(i2s->regmap, I2S_TXCR, I2S_TXCR_VDW_MASK, val);
        regmap_update_bits(i2s->regmap, I2S_RXCR, I2S_RXCR_VDW_MASK, val);
+       regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK,
+                          I2S_DMACR_TDL(16));
+       regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK,
+                          I2S_DMACR_RDL(16));
 
        return 0;
 }
index fc67f97f19f6338bdc01ddded64310181edcfc75..3cebf6ca03dfb91891cd6e6d5eb51649b504c0b1 100644 (file)
@@ -54,7 +54,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750
 config SND_SOC_SAMSUNG_SMDK_WM8580
        tristate "SoC I2S Audio support for WM8580 on SMDK"
        depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
-       depends on REGMAP_I2C
+       depends on I2C
        select SND_SOC_WM8580
        select SND_SAMSUNG_I2S
        help
@@ -146,17 +146,6 @@ config SND_SOC_SMARTQ
        select SND_SAMSUNG_I2S
        select SND_SOC_WM8750
 
-config SND_SOC_GONI_AQUILA_WM8994
-       tristate "SoC I2S Audio support for AQUILA/GONI - WM8994"
-       depends on SND_SOC_SAMSUNG && (MACH_GONI || MACH_AQUILA)
-       depends on I2C=y
-       select SND_SAMSUNG_I2S
-       select MFD_WM8994
-       select SND_SOC_WM8994
-       help
-         Say Y if you want to add support for SoC audio on goni or aquila
-         with the WM8994.
-
 config SND_SOC_SAMSUNG_SMDK_SPDIF
        tristate "SoC S/PDIF Audio support for SMDK"
        depends on SND_SOC_SAMSUNG
@@ -167,7 +156,7 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF
 config SND_SOC_SMDK_WM8580_PCM
        tristate "SoC PCM Audio support for WM8580 on SMDK"
        depends on SND_SOC_SAMSUNG && (MACH_SMDKV210 || MACH_SMDKC110)
-       depends on REGMAP_I2C
+       depends on I2C
        select SND_SOC_WM8580
        select SND_SAMSUNG_PCM
        help
index 31e3dba7e3b58d8bc623b245663e22dbbd67af6e..052fe71be518311fda390ea913b6170d66cab985 100644 (file)
@@ -35,7 +35,6 @@ snd-soc-smdk-wm8994-objs := smdk_wm8994.o
 snd-soc-snow-objs := snow.o
 snd-soc-smdk-wm9713-objs := smdk_wm9713.o
 snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
-snd-soc-goni-wm8994-objs := goni_wm8994.o
 snd-soc-smdk-spdif-objs := smdk_spdif.o
 snd-soc-smdk-wm8580pcm-objs := smdk_wm8580pcm.o
 snd-soc-smdk-wm8994pcm-objs := smdk_wm8994pcm.o
@@ -63,7 +62,6 @@ obj-$(CONFIG_SND_SOC_SNOW) += snd-soc-snow.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM9713) += snd-soc-smdk-wm9713.o
 obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o
-obj-$(CONFIG_SND_SOC_GONI_AQUILA_WM8994) += snd-soc-goni-wm8994.o
 obj-$(CONFIG_SND_SOC_SMDK_WM8580_PCM) += snd-soc-smdk-wm8580pcm.o
 obj-$(CONFIG_SND_SOC_SMDK_WM8994_PCM) += snd-soc-smdk-wm8994pcm.o
 obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o
index 1e2b61ca8db2f04860415aa71a0486c9478500a8..8bf2e2c4bafb97f64eafab4d81a87be20e68f8f7 100644 (file)
@@ -135,7 +135,6 @@ MODULE_DEVICE_TABLE(of, samsung_arndale_rt5631_of_match);
 static struct platform_driver arndale_audio_driver = {
        .driver = {
                .name   = "arndale-audio",
-               .owner  = THIS_MODULE,
                .pm = &snd_soc_pm_ops,
                .of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match),
        },
diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c
deleted file mode 100644 (file)
index 3b527dc..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * goni_wm8994.c
- *
- * Copyright (C) 2010 Samsung Electronics Co.Ltd
- * Author: Chanwoo Choi <cw00.choi@samsung.com>
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- */
-
-#include <linux/module.h>
-#include <sound/soc.h>
-#include <sound/jack.h>
-
-#include <asm/mach-types.h>
-#include <mach/gpio-samsung.h>
-
-#include "../codecs/wm8994.h"
-
-#define MACHINE_NAME   0
-#define CPU_VOICE_DAI  1
-
-static const char *aquila_str[] = {
-       [MACHINE_NAME] = "aquila",
-       [CPU_VOICE_DAI] = "aquila-voice-dai",
-};
-
-static struct snd_soc_card goni;
-static struct platform_device *goni_snd_device;
-
-/* 3.5 pie jack */
-static struct snd_soc_jack jack;
-
-/* 3.5 pie jack detection DAPM pins */
-static struct snd_soc_jack_pin jack_pins[] = {
-       {
-               .pin = "Headset Mic",
-               .mask = SND_JACK_MICROPHONE,
-       }, {
-               .pin = "Headset Stereophone",
-               .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL |
-                       SND_JACK_AVOUT,
-       },
-};
-
-/* 3.5 pie jack detection gpios */
-static struct snd_soc_jack_gpio jack_gpios[] = {
-       {
-               .gpio = S5PV210_GPH0(6),
-               .name = "DET_3.5",
-               .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL |
-                       SND_JACK_AVOUT,
-               .debounce_time = 200,
-       },
-};
-
-static const struct snd_soc_dapm_widget goni_dapm_widgets[] = {
-       SND_SOC_DAPM_SPK("Ext Left Spk", NULL),
-       SND_SOC_DAPM_SPK("Ext Right Spk", NULL),
-       SND_SOC_DAPM_SPK("Ext Rcv", NULL),
-       SND_SOC_DAPM_HP("Headset Stereophone", NULL),
-       SND_SOC_DAPM_MIC("Headset Mic", NULL),
-       SND_SOC_DAPM_MIC("Main Mic", NULL),
-       SND_SOC_DAPM_MIC("2nd Mic", NULL),
-       SND_SOC_DAPM_LINE("Radio In", NULL),
-};
-
-static const struct snd_soc_dapm_route goni_dapm_routes[] = {
-       {"Ext Left Spk", NULL, "SPKOUTLP"},
-       {"Ext Left Spk", NULL, "SPKOUTLN"},
-
-       {"Ext Right Spk", NULL, "SPKOUTRP"},
-       {"Ext Right Spk", NULL, "SPKOUTRN"},
-
-       {"Ext Rcv", NULL, "HPOUT2N"},
-       {"Ext Rcv", NULL, "HPOUT2P"},
-
-       {"Headset Stereophone", NULL, "HPOUT1L"},
-       {"Headset Stereophone", NULL, "HPOUT1R"},
-
-       {"IN1RN", NULL, "Headset Mic"},
-       {"IN1RP", NULL, "Headset Mic"},
-
-       {"IN1RN", NULL, "2nd Mic"},
-       {"IN1RP", NULL, "2nd Mic"},
-
-       {"IN1LN", NULL, "Main Mic"},
-       {"IN1LP", NULL, "Main Mic"},
-
-       {"IN2LN", NULL, "Radio In"},
-       {"IN2RN", NULL, "Radio In"},
-};
-
-static int goni_wm8994_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int ret;
-
-       /* set endpoints to not connected */
-       snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN");
-       snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP");
-       snd_soc_dapm_nc_pin(dapm, "LINEOUT1N");
-       snd_soc_dapm_nc_pin(dapm, "LINEOUT1P");
-       snd_soc_dapm_nc_pin(dapm, "LINEOUT2N");
-       snd_soc_dapm_nc_pin(dapm, "LINEOUT2P");
-
-       if (machine_is_aquila()) {
-               snd_soc_dapm_nc_pin(dapm, "SPKOUTRN");
-               snd_soc_dapm_nc_pin(dapm, "SPKOUTRP");
-       }
-
-       /* Headset jack detection */
-       ret = snd_soc_jack_new(codec, "Headset Jack",
-                       SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT,
-                       &jack);
-       if (ret)
-               return ret;
-
-       ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins);
-       if (ret)
-               return ret;
-
-       ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
-static int goni_hifi_hw_params(struct snd_pcm_substream *substream,
-               struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       unsigned int pll_out = 24000000;
-       int ret = 0;
-
-       /* set the cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* set the codec FLL */
-       ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out,
-                       params_rate(params) * 256);
-       if (ret < 0)
-               return ret;
-
-       /* set the codec system clock */
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
-                       params_rate(params) * 256, SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static struct snd_soc_ops goni_hifi_ops = {
-       .hw_params = goni_hifi_hw_params,
-};
-
-static int goni_voice_hw_params(struct snd_pcm_substream *substream,
-               struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       unsigned int pll_out = 24000000;
-       int ret = 0;
-
-       if (params_rate(params) != 8000)
-               return -EINVAL;
-
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
-                       SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* set the codec FLL */
-       ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out,
-                       params_rate(params) * 256);
-       if (ret < 0)
-               return ret;
-
-       /* set the codec system clock */
-       ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
-                       params_rate(params) * 256, SND_SOC_CLOCK_IN);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static struct snd_soc_dai_driver voice_dai = {
-       .name = "goni-voice-dai",
-       .id = 0,
-       .playback = {
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .capture = {
-               .channels_min = 1,
-               .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-};
-
-static const struct snd_soc_component_driver voice_component = {
-       .name           = "goni-voice",
-};
-
-static struct snd_soc_ops goni_voice_ops = {
-       .hw_params = goni_voice_hw_params,
-};
-
-static struct snd_soc_dai_link goni_dai[] = {
-{
-       .name = "WM8994",
-       .stream_name = "WM8994 HiFi",
-       .cpu_dai_name = "samsung-i2s.0",
-       .codec_dai_name = "wm8994-aif1",
-       .platform_name = "samsung-i2s.0",
-       .codec_name = "wm8994-codec.0-001a",
-       .init = goni_wm8994_init,
-       .ops = &goni_hifi_ops,
-}, {
-       .name = "WM8994 Voice",
-       .stream_name = "Voice",
-       .cpu_dai_name = "goni-voice-dai",
-       .codec_dai_name = "wm8994-aif2",
-       .codec_name = "wm8994-codec.0-001a",
-       .ops = &goni_voice_ops,
-},
-};
-
-static struct snd_soc_card goni = {
-       .name = "goni",
-       .owner = THIS_MODULE,
-       .dai_link = goni_dai,
-       .num_links = ARRAY_SIZE(goni_dai),
-
-       .dapm_widgets = goni_dapm_widgets,
-       .num_dapm_widgets = ARRAY_SIZE(goni_dapm_widgets),
-       .dapm_routes = goni_dapm_routes,
-       .num_dapm_routes = ARRAY_SIZE(goni_dapm_routes),
-};
-
-static int __init goni_init(void)
-{
-       int ret;
-
-       if (machine_is_aquila()) {
-               voice_dai.name = aquila_str[CPU_VOICE_DAI];
-               goni_dai[1].cpu_dai_name = aquila_str[CPU_VOICE_DAI];
-               goni.name = aquila_str[MACHINE_NAME];
-       } else if (!machine_is_goni())
-               return -ENODEV;
-
-       goni_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!goni_snd_device)
-               return -ENOMEM;
-
-       /* register voice DAI here */
-       ret = devm_snd_soc_register_component(&goni_snd_device->dev,
-                       &voice_component, &voice_dai, 1);
-       if (ret) {
-               platform_device_put(goni_snd_device);
-               return ret;
-       }
-
-       platform_set_drvdata(goni_snd_device, &goni);
-       ret = platform_device_add(goni_snd_device);
-
-       if (ret)
-               platform_device_put(goni_snd_device);
-
-       return ret;
-}
-
-static void __exit goni_exit(void)
-{
-       platform_device_unregister(goni_snd_device);
-}
-
-module_init(goni_init);
-module_exit(goni_exit);
-
-/* Module information */
-MODULE_DESCRIPTION("ALSA SoC WM8994 GONI(S5PV210)");
-MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
-MODULE_LICENSE("GPL");
index f2d7980d7ddc56ffea24da2cb6efcdddb4e081de..59b044255b781c68c733f30f397ff266059ac507 100644 (file)
@@ -76,7 +76,6 @@ static int h1940_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int div;
        int ret;
        unsigned int rate = params_rate(params);
@@ -95,18 +94,6 @@ static int h1940_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        /* select clock source */
        ret = snd_soc_dai_set_sysclk(cpu_dai, S3C24XX_CLKSRC_PCLK, rate,
                        SND_SOC_CLOCK_OUT);
@@ -207,6 +194,8 @@ static struct snd_soc_dai_link h1940_uda1380_dai[] = {
                .init           = h1940_uda1380_init,
                .platform_name  = "s3c24xx-iis",
                .codec_name     = "uda1380-codec.0-001a",
+               .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBS_CFS,
                .ops            = &h1940_ops,
        },
 };
index b5a80c528d869e58cbbb58c44ba3cf6a531616ae..b92ab40d2be6ebf46b67bc355c6d75da1a065692 100644 (file)
  * published by the Free Software Foundation.
  */
 
+#include <dt-bindings/sound/samsung-i2s.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -59,10 +61,8 @@ struct samsung_i2s_dai_data {
 struct i2s_dai {
        /* Platform device for this DAI */
        struct platform_device *pdev;
-       /* IOREMAP'd SFRs */
+       /* Memory mapped SFR region */
        void __iomem    *addr;
-       /* Physical base address of SFRs */
-       u32     base;
        /* Rate of RCLK source clock */
        unsigned long rclk_srcrate;
        /* Frame Clock */
@@ -83,8 +83,6 @@ struct i2s_dai {
 #define DAI_OPENED     (1 << 0) /* Dai is opened */
 #define DAI_MANAGER    (1 << 1) /* Dai is the manager */
        unsigned mode;
-       /* CDCLK pin direction: 0  - input, 1 - output */
-       unsigned int cdclk_out:1;
        /* Driver for this DAI */
        struct snd_soc_dai_driver i2s_dai_drv;
        /* DMA parameters */
@@ -95,8 +93,15 @@ struct i2s_dai {
        u32     suspend_i2smod;
        u32     suspend_i2scon;
        u32     suspend_i2spsr;
-       unsigned long gpios[7]; /* i2s gpio line numbers */
        const struct samsung_i2s_variant_regs *variant_regs;
+
+       /* Spinlock protecting access to the device's registers */
+       spinlock_t spinlock;
+       spinlock_t *lock;
+
+       /* Below fields are only valid if this is the primary FIFO */
+       struct clk *clk_table[3];
+       struct clk_onecell_data clk_data;
 };
 
 /* Lock for cross i/f checks */
@@ -133,10 +138,16 @@ static inline bool tx_active(struct i2s_dai *i2s)
        return active ? true : false;
 }
 
+/* Return pointer to the other DAI */
+static inline struct i2s_dai *get_other_dai(struct i2s_dai *i2s)
+{
+       return i2s->pri_dai ? : i2s->sec_dai;
+}
+
 /* If the other interface of the controller is transmitting data */
 static inline bool other_tx_active(struct i2s_dai *i2s)
 {
-       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+       struct i2s_dai *other = get_other_dai(i2s);
 
        return tx_active(other);
 }
@@ -163,7 +174,7 @@ static inline bool rx_active(struct i2s_dai *i2s)
 /* If the other interface of the controller is receiving data */
 static inline bool other_rx_active(struct i2s_dai *i2s)
 {
-       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+       struct i2s_dai *other = get_other_dai(i2s);
 
        return rx_active(other);
 }
@@ -464,18 +475,23 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
          int clk_id, unsigned int rfs, int dir)
 {
        struct i2s_dai *i2s = to_info(dai);
-       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
-       u32 mod = readl(i2s->addr + I2SMOD);
+       struct i2s_dai *other = get_other_dai(i2s);
        const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs;
        unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off;
        unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off;
+       u32 mod, mask, val = 0;
+
+       spin_lock(i2s->lock);
+       mod = readl(i2s->addr + I2SMOD);
+       spin_unlock(i2s->lock);
 
        switch (clk_id) {
        case SAMSUNG_I2S_OPCLK:
-               mod &= ~MOD_OPCLK_MASK;
-               mod |= dir;
+               mask = MOD_OPCLK_MASK;
+               val = dir;
                break;
        case SAMSUNG_I2S_CDCLK:
+               mask = 1 << i2s_regs->cdclkcon_off;
                /* Shouldn't matter in GATING(CLOCK_IN) mode */
                if (dir == SND_SOC_CLOCK_IN)
                        rfs = 0;
@@ -492,15 +508,15 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
                }
 
                if (dir == SND_SOC_CLOCK_IN)
-                       mod |= 1 << i2s_regs->cdclkcon_off;
-               else
-                       mod &= ~(1 << i2s_regs->cdclkcon_off);
+                       val = 1 << i2s_regs->cdclkcon_off;
 
                i2s->rfs = rfs;
                break;
 
        case SAMSUNG_I2S_RCLKSRC_0: /* clock corrsponding to IISMOD[10] := 0 */
        case SAMSUNG_I2S_RCLKSRC_1: /* clock corrsponding to IISMOD[10] := 1 */
+               mask = 1 << i2s_regs->rclksrc_off;
+
                if ((i2s->quirks & QUIRK_NO_MUXPSR)
                                || (clk_id == SAMSUNG_I2S_RCLKSRC_0))
                        clk_id = 0;
@@ -550,18 +566,19 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
                        return 0;
                }
 
-               if (clk_id == 0)
-                       mod &= ~(1 << i2s_regs->rclksrc_off);
-               else
-                       mod |= 1 << i2s_regs->rclksrc_off;
-
+               if (clk_id == 1)
+                       val = 1 << i2s_regs->rclksrc_off;
                break;
        default:
                dev_err(&i2s->pdev->dev, "We don't serve that!\n");
                return -EINVAL;
        }
 
+       spin_lock(i2s->lock);
+       mod = readl(i2s->addr + I2SMOD);
+       mod = (mod & ~mask) | val;
        writel(mod, i2s->addr + I2SMOD);
+       spin_unlock(i2s->lock);
 
        return 0;
 }
@@ -570,9 +587,8 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
        unsigned int fmt)
 {
        struct i2s_dai *i2s = to_info(dai);
-       u32 mod = readl(i2s->addr + I2SMOD);
        int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave;
-       u32 tmp = 0;
+       u32 mod, tmp = 0;
 
        lrp_shift = i2s->variant_regs->lrp_off;
        sdf_shift = i2s->variant_regs->sdf_off;
@@ -632,12 +648,15 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
                return -EINVAL;
        }
 
+       spin_lock(i2s->lock);
+       mod = readl(i2s->addr + I2SMOD);
        /*
         * Don't change the I2S mode if any controller is active on this
         * channel.
         */
        if (any_active(i2s) &&
                ((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) {
+               spin_unlock(i2s->lock);
                dev_err(&i2s->pdev->dev,
                                "%s:%d Other DAI busy\n", __func__, __LINE__);
                return -EAGAIN;
@@ -646,6 +665,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
        mod &= ~(sdf_mask | lrp_rlow | mod_slave);
        mod |= tmp;
        writel(mod, i2s->addr + I2SMOD);
+       spin_unlock(i2s->lock);
 
        return 0;
 }
@@ -654,16 +674,16 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
        struct i2s_dai *i2s = to_info(dai);
-       u32 mod = readl(i2s->addr + I2SMOD);
+       u32 mod, mask = 0, val = 0;
 
        if (!is_secondary(i2s))
-               mod &= ~(MOD_DC2_EN | MOD_DC1_EN);
+               mask |= (MOD_DC2_EN | MOD_DC1_EN);
 
        switch (params_channels(params)) {
        case 6:
-               mod |= MOD_DC2_EN;
+               val |= MOD_DC2_EN;
        case 4:
-               mod |= MOD_DC1_EN;
+               val |= MOD_DC1_EN;
                break;
        case 2:
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -685,44 +705,49 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
        }
 
        if (is_secondary(i2s))
-               mod &= ~MOD_BLCS_MASK;
+               mask |= MOD_BLCS_MASK;
        else
-               mod &= ~MOD_BLCP_MASK;
+               mask |= MOD_BLCP_MASK;
 
        if (is_manager(i2s))
-               mod &= ~MOD_BLC_MASK;
+               mask |= MOD_BLC_MASK;
 
        switch (params_width(params)) {
        case 8:
                if (is_secondary(i2s))
-                       mod |= MOD_BLCS_8BIT;
+                       val |= MOD_BLCS_8BIT;
                else
-                       mod |= MOD_BLCP_8BIT;
+                       val |= MOD_BLCP_8BIT;
                if (is_manager(i2s))
-                       mod |= MOD_BLC_8BIT;
+                       val |= MOD_BLC_8BIT;
                break;
        case 16:
                if (is_secondary(i2s))
-                       mod |= MOD_BLCS_16BIT;
+                       val |= MOD_BLCS_16BIT;
                else
-                       mod |= MOD_BLCP_16BIT;
+                       val |= MOD_BLCP_16BIT;
                if (is_manager(i2s))
-                       mod |= MOD_BLC_16BIT;
+                       val |= MOD_BLC_16BIT;
                break;
        case 24:
                if (is_secondary(i2s))
-                       mod |= MOD_BLCS_24BIT;
+                       val |= MOD_BLCS_24BIT;
                else
-                       mod |= MOD_BLCP_24BIT;
+                       val |= MOD_BLCP_24BIT;
                if (is_manager(i2s))
-                       mod |= MOD_BLC_24BIT;
+                       val |= MOD_BLC_24BIT;
                break;
        default:
                dev_err(&i2s->pdev->dev, "Format(%d) not supported\n",
                                params_format(params));
                return -EINVAL;
        }
+
+       spin_lock(i2s->lock);
+       mod = readl(i2s->addr + I2SMOD);
+       mod = (mod & ~mask) | val;
        writel(mod, i2s->addr + I2SMOD);
+       spin_unlock(i2s->lock);
 
        samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
 
@@ -736,7 +761,7 @@ static int i2s_startup(struct snd_pcm_substream *substream,
          struct snd_soc_dai *dai)
 {
        struct i2s_dai *i2s = to_info(dai);
-       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+       struct i2s_dai *other = get_other_dai(i2s);
        unsigned long flags;
 
        spin_lock_irqsave(&lock, flags);
@@ -753,9 +778,6 @@ static int i2s_startup(struct snd_pcm_substream *substream,
 
        spin_unlock_irqrestore(&lock, flags);
 
-       if (!is_opened(other) && i2s->cdclk_out)
-               i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
-                               0, SND_SOC_CLOCK_OUT);
        return 0;
 }
 
@@ -763,38 +785,27 @@ static void i2s_shutdown(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct i2s_dai *i2s = to_info(dai);
-       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+       struct i2s_dai *other = get_other_dai(i2s);
        unsigned long flags;
-       const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs;
 
        spin_lock_irqsave(&lock, flags);
 
        i2s->mode &= ~DAI_OPENED;
        i2s->mode &= ~DAI_MANAGER;
 
-       if (is_opened(other)) {
+       if (is_opened(other))
                other->mode |= DAI_MANAGER;
-       } else {
-               u32 mod = readl(i2s->addr + I2SMOD);
-               i2s->cdclk_out = !(mod & (1 << i2s_regs->cdclkcon_off));
-               if (other)
-                       other->cdclk_out = i2s->cdclk_out;
-       }
+
        /* Reset any constraint on RFS and BFS */
        i2s->rfs = 0;
        i2s->bfs = 0;
 
        spin_unlock_irqrestore(&lock, flags);
-
-       /* Gate CDCLK by default */
-       if (!is_opened(other))
-               i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
-                               0, SND_SOC_CLOCK_IN);
 }
 
 static int config_setup(struct i2s_dai *i2s)
 {
-       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+       struct i2s_dai *other = get_other_dai(i2s);
        unsigned rfs, bfs, blc;
        u32 psr;
 
@@ -864,10 +875,10 @@ static int i2s_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               local_irq_save(flags);
+               spin_lock_irqsave(i2s->lock, flags);
 
                if (config_setup(i2s)) {
-                       local_irq_restore(flags);
+                       spin_unlock_irqrestore(i2s->lock, flags);
                        return -EINVAL;
                }
 
@@ -876,12 +887,12 @@ static int i2s_trigger(struct snd_pcm_substream *substream,
                else
                        i2s_txctrl(i2s, 1);
 
-               local_irq_restore(flags);
+               spin_unlock_irqrestore(i2s->lock, flags);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               local_irq_save(flags);
+               spin_lock_irqsave(i2s->lock, flags);
 
                if (capture) {
                        i2s_rxctrl(i2s, 0);
@@ -891,7 +902,7 @@ static int i2s_trigger(struct snd_pcm_substream *substream,
                        i2s_fifo(i2s, FIC_TXFLUSH);
                }
 
-               local_irq_restore(flags);
+               spin_unlock_irqrestore(i2s->lock, flags);
                break;
        }
 
@@ -902,7 +913,7 @@ static int i2s_set_clkdiv(struct snd_soc_dai *dai,
        int div_id, int div)
 {
        struct i2s_dai *i2s = to_info(dai);
-       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+       struct i2s_dai *other = get_other_dai(i2s);
 
        switch (div_id) {
        case SAMSUNG_I2S_DIV_BCLK:
@@ -971,58 +982,36 @@ static int i2s_resume(struct snd_soc_dai *dai)
 static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
 {
        struct i2s_dai *i2s = to_info(dai);
-       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
-       int ret;
+       struct i2s_dai *other = get_other_dai(i2s);
+       unsigned long flags;
 
-       if (other && other->clk) { /* If this is probe on secondary */
+       if (is_secondary(i2s)) { /* If this is probe on the secondary DAI */
                samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback,
                                           NULL);
-               goto probe_exit;
-       }
-
-       i2s->addr = ioremap(i2s->base, 0x100);
-       if (i2s->addr == NULL) {
-               dev_err(&i2s->pdev->dev, "cannot ioremap registers\n");
-               return -ENXIO;
-       }
-
-       i2s->clk = clk_get(&i2s->pdev->dev, "iis");
-       if (IS_ERR(i2s->clk)) {
-               dev_err(&i2s->pdev->dev, "failed to get i2s_clock\n");
-               iounmap(i2s->addr);
-               return PTR_ERR(i2s->clk);
-       }
-
-       ret = clk_prepare_enable(i2s->clk);
-       if (ret != 0) {
-               dev_err(&i2s->pdev->dev, "failed to enable clock: %d\n", ret);
-               return ret;
-       }
-
-       samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
-
-       if (other) {
-               other->addr = i2s->addr;
-               other->clk = i2s->clk;
-       }
+       } else {
+               samsung_asoc_init_dma_data(dai, &i2s->dma_playback,
+                                          &i2s->dma_capture);
 
-       if (i2s->quirks & QUIRK_NEED_RSTCLR)
-               writel(CON_RSTCLR, i2s->addr + I2SCON);
+               if (i2s->quirks & QUIRK_NEED_RSTCLR)
+                       writel(CON_RSTCLR, i2s->addr + I2SCON);
 
-       if (i2s->quirks & QUIRK_SUPPORTS_IDMA)
-               idma_reg_addr_init(i2s->addr,
+               if (i2s->quirks & QUIRK_SUPPORTS_IDMA)
+                       idma_reg_addr_init(i2s->addr,
                                        i2s->sec_dai->idma_playback.dma_addr);
+       }
 
-probe_exit:
        /* Reset any constraint on RFS and BFS */
        i2s->rfs = 0;
        i2s->bfs = 0;
        i2s->rclk_srcrate = 0;
+
+       spin_lock_irqsave(i2s->lock, flags);
        i2s_txctrl(i2s, 0);
        i2s_rxctrl(i2s, 0);
        i2s_fifo(i2s, FIC_TXFLUSH);
        i2s_fifo(other, FIC_TXFLUSH);
        i2s_fifo(i2s, FIC_RXFLUSH);
+       spin_unlock_irqrestore(i2s->lock, flags);
 
        /* Gate CDCLK by default */
        if (!is_opened(other))
@@ -1035,21 +1024,15 @@ probe_exit:
 static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)
 {
        struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai);
-       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
-
-       if (!other || !other->clk) {
 
-               if (i2s->quirks & QUIRK_NEED_RSTCLR)
+       if (!is_secondary(i2s)) {
+               if (i2s->quirks & QUIRK_NEED_RSTCLR) {
+                       spin_lock(i2s->lock);
                        writel(0, i2s->addr + I2SCON);
-
-               clk_disable_unprepare(i2s->clk);
-               clk_put(i2s->clk);
-
-               iounmap(i2s->addr);
+                       spin_unlock(i2s->lock);
+               }
        }
 
-       i2s->clk = NULL;
-
        return 0;
 }
 
@@ -1124,15 +1107,14 @@ static const struct of_device_id exynos_i2s_match[];
 static inline const struct samsung_i2s_dai_data *samsung_i2s_get_driver_data(
                                                struct platform_device *pdev)
 {
-#ifdef CONFIG_OF
-       if (pdev->dev.of_node) {
+       if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
                const struct of_device_id *match;
                match = of_match_node(exynos_i2s_match, pdev->dev.of_node);
-               return match->data;
-       } else
-#endif
+               return match ? match->data : NULL;
+       } else {
                return (struct samsung_i2s_dai_data *)
                                platform_get_device_id(pdev)->driver_data;
+       }
 }
 
 #ifdef CONFIG_PM
@@ -1155,6 +1137,87 @@ static int i2s_runtime_resume(struct device *dev)
 }
 #endif /* CONFIG_PM */
 
+static void i2s_unregister_clocks(struct i2s_dai *i2s)
+{
+       int i;
+
+       for (i = 0; i < i2s->clk_data.clk_num; i++) {
+               if (!IS_ERR(i2s->clk_table[i]))
+                       clk_unregister(i2s->clk_table[i]);
+       }
+}
+
+static void i2s_unregister_clock_provider(struct platform_device *pdev)
+{
+       struct i2s_dai *i2s = dev_get_drvdata(&pdev->dev);
+
+       of_clk_del_provider(pdev->dev.of_node);
+       i2s_unregister_clocks(i2s);
+}
+
+static int i2s_register_clock_provider(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct i2s_dai *i2s = dev_get_drvdata(dev);
+       const char *clk_name[2] = { "i2s_opclk0", "i2s_opclk1" };
+       const char *p_names[2] = { NULL };
+       const struct samsung_i2s_variant_regs *reg_info = i2s->variant_regs;
+       struct clk *rclksrc;
+       int ret, i;
+
+       /* Register the clock provider only if it's expected in the DTB */
+       if (!of_find_property(dev->of_node, "#clock-cells", NULL))
+               return 0;
+
+       /* Get the RCLKSRC mux clock parent clock names */
+       for (i = 0; i < ARRAY_SIZE(p_names); i++) {
+               rclksrc = clk_get(dev, clk_name[i]);
+               if (IS_ERR(rclksrc))
+                       continue;
+               p_names[i] = __clk_get_name(rclksrc);
+               clk_put(rclksrc);
+       }
+
+       if (!(i2s->quirks & QUIRK_NO_MUXPSR)) {
+               /* Activate the prescaler */
+               u32 val = readl(i2s->addr + I2SPSR);
+               writel(val | PSR_PSREN, i2s->addr + I2SPSR);
+
+               i2s->clk_table[CLK_I2S_RCLK_SRC] = clk_register_mux(NULL,
+                               "i2s_rclksrc", p_names, ARRAY_SIZE(p_names),
+                               CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
+                               i2s->addr + I2SMOD, reg_info->rclksrc_off,
+                               1, 0, i2s->lock);
+
+               i2s->clk_table[CLK_I2S_RCLK_PSR] = clk_register_divider(NULL,
+                               "i2s_presc", "i2s_rclksrc",
+                               CLK_SET_RATE_PARENT,
+                               i2s->addr + I2SPSR, 8, 6, 0, i2s->lock);
+
+               p_names[0] = "i2s_presc";
+               i2s->clk_data.clk_num = 2;
+       }
+       of_property_read_string_index(dev->of_node,
+                               "clock-output-names", 0, &clk_name[0]);
+
+       i2s->clk_table[CLK_I2S_CDCLK] = clk_register_gate(NULL, clk_name[0],
+                               p_names[0], CLK_SET_RATE_PARENT,
+                               i2s->addr + I2SMOD, reg_info->cdclkcon_off,
+                               CLK_GATE_SET_TO_DISABLE, i2s->lock);
+
+       i2s->clk_data.clk_num += 1;
+       i2s->clk_data.clks = i2s->clk_table;
+
+       ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
+                                 &i2s->clk_data);
+       if (ret < 0) {
+               dev_err(dev, "failed to add clock provider: %d\n", ret);
+               i2s_unregister_clocks(i2s);
+       }
+
+       return ret;
+}
+
 static int samsung_i2s_probe(struct platform_device *pdev)
 {
        struct i2s_dai *pri_dai, *sec_dai = NULL;
@@ -1164,7 +1227,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
        u32 regs_base, quirks = 0, idma_addr = 0;
        struct device_node *np = pdev->dev.of_node;
        const struct samsung_i2s_dai_data *i2s_dai_data;
-       int ret = 0;
+       int ret;
 
        /* Call during Seconday interface registration */
        i2s_dai_data = samsung_i2s_get_driver_data(pdev);
@@ -1175,11 +1238,13 @@ static int samsung_i2s_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev, "Unable to get drvdata\n");
                        return -EFAULT;
                }
-               devm_snd_soc_register_component(&sec_dai->pdev->dev,
+               ret = devm_snd_soc_register_component(&sec_dai->pdev->dev,
                                                &samsung_i2s_component,
                                                &sec_dai->i2s_dai_drv, 1);
-               samsung_asoc_dma_platform_register(&pdev->dev);
-               return 0;
+               if (ret != 0)
+                       return ret;
+
+               return samsung_asoc_dma_platform_register(&pdev->dev);
        }
 
        pri_dai = i2s_alloc_dai(pdev, false);
@@ -1188,6 +1253,9 @@ static int samsung_i2s_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       spin_lock_init(&pri_dai->spinlock);
+       pri_dai->lock = &pri_dai->spinlock;
+
        if (!np) {
                res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
                if (!res) {
@@ -1229,25 +1297,29 @@ static int samsung_i2s_probe(struct platform_device *pdev)
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "Unable to get I2S SFR address\n");
-               return -ENXIO;
-       }
+       pri_dai->addr = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(pri_dai->addr))
+               return PTR_ERR(pri_dai->addr);
 
-       if (!request_mem_region(res->start, resource_size(res),
-                                                       "samsung-i2s")) {
-               dev_err(&pdev->dev, "Unable to request SFR region\n");
-               return -EBUSY;
-       }
        regs_base = res->start;
 
+       pri_dai->clk = devm_clk_get(&pdev->dev, "iis");
+       if (IS_ERR(pri_dai->clk)) {
+               dev_err(&pdev->dev, "Failed to get iis clock\n");
+               return PTR_ERR(pri_dai->clk);
+       }
+
+       ret = clk_prepare_enable(pri_dai->clk);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "failed to enable clock: %d\n", ret);
+               return ret;
+       }
        pri_dai->dma_playback.dma_addr = regs_base + I2STXD;
        pri_dai->dma_capture.dma_addr = regs_base + I2SRXD;
        pri_dai->dma_playback.ch_name = "tx";
        pri_dai->dma_capture.ch_name = "rx";
        pri_dai->dma_playback.dma_size = 4;
        pri_dai->dma_capture.dma_size = 4;
-       pri_dai->base = regs_base;
        pri_dai->quirks = quirks;
        pri_dai->variant_regs = i2s_dai_data->i2s_variant_regs;
 
@@ -1258,10 +1330,10 @@ static int samsung_i2s_probe(struct platform_device *pdev)
                sec_dai = i2s_alloc_dai(pdev, true);
                if (!sec_dai) {
                        dev_err(&pdev->dev, "Unable to alloc I2S_sec\n");
-                       ret = -ENOMEM;
-                       goto err;
+                       return -ENOMEM;
                }
 
+               sec_dai->lock = &pri_dai->spinlock;
                sec_dai->variant_regs = pri_dai->variant_regs;
                sec_dai->dma_playback.dma_addr = regs_base + I2STXDS;
                sec_dai->dma_playback.ch_name = "tx-sec";
@@ -1273,7 +1345,8 @@ static int samsung_i2s_probe(struct platform_device *pdev)
                }
 
                sec_dai->dma_playback.dma_size = 4;
-               sec_dai->base = regs_base;
+               sec_dai->addr = pri_dai->addr;
+               sec_dai->clk = pri_dai->clk;
                sec_dai->quirks = quirks;
                sec_dai->idma_playback.dma_addr = idma_addr;
                sec_dai->pri_dai = pri_dai;
@@ -1282,8 +1355,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
 
        if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
                dev_err(&pdev->dev, "Unable to configure gpio\n");
-               ret = -EINVAL;
-               goto err;
+               return -EINVAL;
        }
 
        devm_snd_soc_register_component(&pri_dai->pdev->dev,
@@ -1292,32 +1364,30 @@ static int samsung_i2s_probe(struct platform_device *pdev)
 
        pm_runtime_enable(&pdev->dev);
 
-       samsung_asoc_dma_platform_register(&pdev->dev);
-
-       return 0;
-err:
-       if (res)
-               release_mem_region(regs_base, resource_size(res));
+       ret = samsung_asoc_dma_platform_register(&pdev->dev);
+       if (ret != 0)
+               return ret;
 
-       return ret;
+       return i2s_register_clock_provider(pdev);
 }
 
 static int samsung_i2s_remove(struct platform_device *pdev)
 {
        struct i2s_dai *i2s, *other;
-       struct resource *res;
 
        i2s = dev_get_drvdata(&pdev->dev);
-       other = i2s->pri_dai ? : i2s->sec_dai;
+       other = get_other_dai(i2s);
 
        if (other) {
                other->pri_dai = NULL;
                other->sec_dai = NULL;
        } else {
                pm_runtime_disable(&pdev->dev);
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-               if (res)
-                       release_mem_region(res->start, resource_size(res));
+       }
+
+       if (!is_secondary(i2s)) {
+               i2s_unregister_clock_provider(pdev);
+               clk_disable_unprepare(i2s->clk);
        }
 
        i2s->pri_dai = NULL;
index b5f6abd9d2216d7f9664ca337468ff7792c93b0d..7fcb51faa2a0e98803cbc8ac67cd370b7f2fd02b 100644 (file)
@@ -61,20 +61,6 @@ static int jive_hw_params(struct snd_pcm_substream *substream,
        s3c_i2sv2_iis_calc_rate(&div, NULL, params_rate(params),
                                s3c_i2sv2_get_clock(cpu_dai));
 
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        /* set the codec system clock for DAC and ADC */
        ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
                                     SND_SOC_CLOCK_IN);
@@ -97,22 +83,6 @@ static struct snd_soc_ops jive_ops = {
        .hw_params      = jive_hw_params,
 };
 
-static int jive_wm8750_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       /* These endpoints are not being used. */
-       snd_soc_dapm_nc_pin(dapm, "LINPUT2");
-       snd_soc_dapm_nc_pin(dapm, "RINPUT2");
-       snd_soc_dapm_nc_pin(dapm, "LINPUT3");
-       snd_soc_dapm_nc_pin(dapm, "RINPUT3");
-       snd_soc_dapm_nc_pin(dapm, "OUT3");
-       snd_soc_dapm_nc_pin(dapm, "MONO");
-
-       return 0;
-}
-
 static struct snd_soc_dai_link jive_dai = {
        .name           = "wm8750",
        .stream_name    = "WM8750",
@@ -120,7 +90,8 @@ static struct snd_soc_dai_link jive_dai = {
        .codec_dai_name = "wm8750-hifi",
        .platform_name  = "s3c2412-i2s",
        .codec_name     = "wm8750.0-001a",
-       .init           = jive_wm8750_init,
+       .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                         SND_SOC_DAIFMT_CBS_CFS,
        .ops            = &jive_ops,
 };
 
@@ -135,6 +106,7 @@ static struct snd_soc_card snd_soc_machine_jive = {
        .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
        .dapm_routes    = audio_map,
        .num_dapm_routes = ARRAY_SIZE(audio_map),
+       .fully_routed   = true,
 };
 
 static struct platform_device *jive_snd_device;
index 9b4a09f14b6c4b2ed859dc45eb890049efac8de7..65602b935377df161562489f4b93ca4125a8a9cc 100644 (file)
@@ -70,20 +70,6 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai,
-               SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-               SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai,
-               SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-               SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
        /* set the codec system clock for DAC and ADC */
        ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
                SND_SOC_CLOCK_IN);
@@ -151,13 +137,6 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
 
        pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
 
-       /* todo: gg check mode (DSP_B) against CSR datasheet */
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        /* set the codec system clock for DAC and ADC */
        ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
                SND_SOC_CLOCK_IN);
@@ -300,6 +279,8 @@ static struct snd_soc_dai_link neo1973_dai[] = {
        .cpu_dai_name = "s3c24xx-iis",
        .codec_dai_name = "wm8753-hifi",
        .codec_name = "wm8753.0-001a",
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBM_CFM,
        .init = neo1973_wm8753_init,
        .ops = &neo1973_hifi_ops,
 },
@@ -309,6 +290,8 @@ static struct snd_soc_dai_link neo1973_dai[] = {
        .cpu_dai_name = "bt-sco-pcm",
        .codec_dai_name = "wm8753-voice",
        .codec_name = "wm8753.0-001a",
+       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBS_CFS,
        .ops = &neo1973_voice_ops,
 },
 };
index fa4f1d2f69bfa0905deea745b7260488694b5a55..596f1180a3698627844a0e8746e8d64bf0441f47 100644 (file)
@@ -21,6 +21,8 @@ struct odroidx2_drv_data {
 /* The I2S CDCLK output clock frequency for the MAX98090 codec */
 #define MAX98090_MCLK 19200000
 
+static struct snd_soc_dai_link odroidx2_dai[];
+
 static int odroidx2_late_probe(struct snd_soc_card *card)
 {
        struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
@@ -29,7 +31,9 @@ static int odroidx2_late_probe(struct snd_soc_card *card)
 
        ret = snd_soc_dai_set_sysclk(codec_dai, 0, MAX98090_MCLK,
                                                SND_SOC_CLOCK_IN);
-       if (ret < 0)
+
+       if (ret < 0 || of_find_property(odroidx2_dai[0].codec_of_node,
+                                       "clocks", NULL))
                return ret;
 
        /* Set the cpu DAI configuration in order to use CDCLK */
index 37688ebbb2b4b6be954150d1e17b721ed9ddf6f3..873f2cb4bebe3e449d6d32821da672e0916626f0 100644 (file)
@@ -89,6 +89,8 @@ static struct snd_soc_dai_link rx1950_uda1380_dai[] = {
                .init           = rx1950_uda1380_init,
                .platform_name  = "s3c24xx-iis",
                .codec_name     = "uda1380-codec.0-001a",
+               .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBS_CFS,
                .ops            = &rx1950_ops,
        },
 };
@@ -154,7 +156,6 @@ static int rx1950_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int div;
        int ret;
        unsigned int rate = params_rate(params);
@@ -181,18 +182,6 @@ static int rx1950_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        /* select clock source */
        ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source, rate,
                        SND_SOC_CLOCK_OUT);
index 2c015f62ead603564683c1920ec3613ad5df7768..dcc008d1e1ab1bd896665b2c1cec40c73e497199 100644 (file)
@@ -169,24 +169,6 @@ static int simtec_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
-       /* Set the CODEC as the bus clock master, I2S */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBM_CFM);
-       if (ret) {
-               pr_err("%s: failed set cpu dai format\n", __func__);
-               return ret;
-       }
-
-       /* Set the CODEC as the bus clock master */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBM_CFM);
-       if (ret) {
-               pr_err("%s: failed set codec dai format\n", __func__);
-               return ret;
-       }
-
        ret = snd_soc_dai_set_sysclk(codec_dai, 0,
                                     CODEC_CLOCK, SND_SOC_CLOCK_IN);
        if (ret) {
@@ -320,6 +302,8 @@ int simtec_audio_core_probe(struct platform_device *pdev,
        int ret;
 
        card->dai_link->ops = &simtec_snd_ops;
+       card->dai_link->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBM_CFM;
 
        pdata = pdev->dev.platform_data;
        if (!pdata) {
index 9c6f7db56f600090be8a804b6380436707aeaa55..50849e137fc0edf2455a7d643b17c936f2e63794 100644 (file)
@@ -173,16 +173,6 @@ static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk,
                        SND_SOC_CLOCK_IN);
        if (ret < 0)
@@ -223,6 +213,8 @@ static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
        .codec_name = "uda134x-codec",
        .codec_dai_name = "uda134x-hifi",
        .cpu_dai_name = "s3c24xx-iis",
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBS_CFS,
        .ops = &s3c24xx_uda134x_ops,
        .platform_name  = "s3c24xx-iis",
 };
index 9b0ffacab790c7f216cf932dcf2d1b8733b64715..8291d2a5f1525957b6c4e021c8657d4590ce649e 100644 (file)
@@ -56,20 +56,6 @@ static int smartq_hifi_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                                            SND_SOC_DAIFMT_NB_NF |
-                                            SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                                          SND_SOC_DAIFMT_NB_NF |
-                                          SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        /* Use PCLK for I2S signal generation */
        ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0,
                                        0, SND_SOC_CLOCK_IN);
@@ -199,6 +185,8 @@ static struct snd_soc_dai_link smartq_dai[] = {
                .platform_name  = "samsung-i2s.0",
                .codec_name     = "wm8750.0-0x1a",
                .init           = smartq_wm8987_init,
+               .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBS_CFS,
                .ops            = &smartq_hifi_ops,
        },
 };
index b1a519f83b29ea439c262ef2263fab208514bebc..548bfd9937889dbe43df8a28ec3d6de9a3d568b1 100644 (file)
@@ -32,7 +32,6 @@ static int smdk_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        unsigned int pll_out;
        int bfs, rfs, ret;
@@ -77,20 +76,6 @@ static int smdk_hw_params(struct snd_pcm_substream *substream,
        }
        pll_out = params_rate(params) * rfs;
 
-       /* Set the Codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
-                                        | SND_SOC_DAIFMT_NB_NF
-                                        | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* Set the AP DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
-                                        | SND_SOC_DAIFMT_NB_NF
-                                        | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
        /* Set WM8580 to drive MCLK from its PLLA */
        ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
                                        WM8580_CLKSRC_PLLA);
@@ -151,13 +136,10 @@ static const struct snd_soc_dapm_route smdk_wm8580_audio_map[] = {
 
 static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
        /* Enabling the microphone requires the fitting of a 0R
         * resistor to connect the line from the microphone jack.
         */
-       snd_soc_dapm_disable_pin(dapm, "MicIn");
+       snd_soc_dapm_disable_pin(&rtd->card->dapm, "MicIn");
 
        return 0;
 }
@@ -168,6 +150,9 @@ enum {
        SEC_PLAYBACK,
 };
 
+#define SMDK_DAI_FMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \
+       SND_SOC_DAIFMT_CBM_CFM)
+
 static struct snd_soc_dai_link smdk_dai[] = {
        [PRI_PLAYBACK] = { /* Primary Playback i/f */
                .name = "WM8580 PAIF RX",
@@ -176,6 +161,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
                .codec_dai_name = "wm8580-hifi-playback",
                .platform_name = "samsung-i2s.0",
                .codec_name = "wm8580.0-001b",
+               .dai_fmt = SMDK_DAI_FMT,
                .ops = &smdk_ops,
        },
        [PRI_CAPTURE] = { /* Primary Capture i/f */
@@ -185,6 +171,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
                .codec_dai_name = "wm8580-hifi-capture",
                .platform_name = "samsung-i2s.0",
                .codec_name = "wm8580.0-001b",
+               .dai_fmt = SMDK_DAI_FMT,
                .init = smdk_wm8580_init_paiftx,
                .ops = &smdk_ops,
        },
@@ -195,6 +182,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
                .codec_dai_name = "wm8580-hifi-playback",
                .platform_name = "samsung-i2s-sec",
                .codec_name = "wm8580.0-001b",
+               .dai_fmt = SMDK_DAI_FMT,
                .ops = &smdk_ops,
        },
 };
index 05c609c62de9fd830298c4956e222abf8ff87e80..6deec5234c92960410a222c718e270c5dd2fe072 100644 (file)
@@ -62,20 +62,6 @@ static int smdk_wm8580_pcm_hw_params(struct snd_pcm_substream *substream,
 
        rfs = mclk_freq / params_rate(params) / 2;
 
-       /* Set the codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B
-                               | SND_SOC_DAIFMT_IB_NF
-                               | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* Set the cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_B
-                               | SND_SOC_DAIFMT_IB_NF
-                               | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        if (mclk_freq == xtal_freq) {
                ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_MCLK,
                                                mclk_freq, SND_SOC_CLOCK_IN);
@@ -121,6 +107,9 @@ static struct snd_soc_ops smdk_wm8580_pcm_ops = {
        .hw_params = smdk_wm8580_pcm_hw_params,
 };
 
+#define SMDK_DAI_FMT (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | \
+       SND_SOC_DAIFMT_CBS_CFS)
+
 static struct snd_soc_dai_link smdk_dai[] = {
        {
                .name = "WM8580 PAIF PCM RX",
@@ -129,6 +118,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
                .codec_dai_name = "wm8580-hifi-playback",
                .platform_name = "samsung-audio",
                .codec_name = "wm8580.0-001b",
+               .dai_fmt = SMDK_DAI_FMT,
                .ops = &smdk_wm8580_pcm_ops,
        }, {
                .name = "WM8580 PAIF PCM TX",
@@ -137,6 +127,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
                .codec_dai_name = "wm8580-hifi-capture",
                .platform_name = "samsung-pcm.0",
                .codec_name = "wm8580.0-001b",
+               .dai_fmt = SMDK_DAI_FMT,
                .ops = &smdk_wm8580_pcm_ops,
        },
 };
index c470e8eed6e19b1468b15720b654f225ccec434e..b1c89ec2d999ce3f410282dfdf1ecfb30b7cfe4e 100644 (file)
@@ -68,20 +68,6 @@ static int smdk_wm8994_pcm_hw_params(struct snd_pcm_substream *substream,
 
        mclk_freq = params_rate(params) * rfs;
 
-       /* Set the codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B
-                               | SND_SOC_DAIFMT_IB_NF
-                               | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* Set the cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_B
-                               | SND_SOC_DAIFMT_IB_NF
-                               | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
                                        mclk_freq, SND_SOC_CLOCK_IN);
        if (ret < 0)
@@ -118,6 +104,8 @@ static struct snd_soc_dai_link smdk_dai[] = {
                .codec_dai_name = "wm8994-aif1",
                .platform_name = "samsung-pcm.0",
                .codec_name = "wm8994-codec",
+               .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF |
+                          SND_SOC_DAIFMT_CBS_CFS,
                .ops = &smdk_wm8994_pcm_ops,
        },
 };
index a5b2c4ea90d96443f9f389f028de2a17d8fb8334..fd11404a3bc786f484774c28d64fa8c5a74c29da 100644 (file)
@@ -305,11 +305,6 @@ static struct snd_pcm_ops camelot_pcm_ops = {
        .pointer        = camelot_pos,
 };
 
-static void camelot_pcm_free(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_pcm *pcm = rtd->pcm;
@@ -328,7 +323,6 @@ static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_platform_driver sh7760_soc_platform = {
        .ops            = &camelot_pcm_ops,
        .pcm_new        = camelot_pcm_new,
-       .pcm_free       = camelot_pcm_free,
 };
 
 static int sh7760_soc_platform_probe(struct platform_device *pdev)
index 8869971d7884b93e463db07bb304f23c71b3b2c3..b87b22e88e43decf2d8e66c84ce411f2c97224fa 100644 (file)
@@ -820,12 +820,9 @@ static int fsi_clk_enable(struct device *dev,
                        return ret;
                }
 
-               if (clock->xck)
-                       clk_enable(clock->xck);
-               if (clock->ick)
-                       clk_enable(clock->ick);
-               if (clock->div)
-                       clk_enable(clock->div);
+               clk_enable(clock->xck);
+               clk_enable(clock->ick);
+               clk_enable(clock->div);
 
                clock->count++;
        }
@@ -1765,11 +1762,6 @@ static struct snd_pcm_ops fsi_pcm_ops = {
 #define PREALLOC_BUFFER                (32 * 1024)
 #define PREALLOC_BUFFER_MAX    (32 * 1024)
 
-static void fsi_pcm_free(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        return snd_pcm_lib_preallocate_pages_for_all(
@@ -1821,7 +1813,6 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = {
 static struct snd_soc_platform_driver fsi_soc_platform = {
        .ops            = &fsi_pcm_ops,
        .pcm_new        = fsi_pcm_new,
-       .pcm_free       = fsi_pcm_free,
 };
 
 static const struct snd_soc_component_driver fsi_soc_component = {
index c58c2529f10345d01745d919124c0634a70d7deb..82f582344fe7e1dfce0e39af7c69289c5c4a3a3d 100644 (file)
@@ -63,16 +63,6 @@ static int migor_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_NB_IF |
-                                 SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_fmt(rtd->cpu_dai, SND_SOC_DAIFMT_NB_IF |
-                                 SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        codec_freq = rate * 512;
        /*
         * This propagates the parent frequency change to children and
@@ -144,6 +134,8 @@ static struct snd_soc_dai_link migor_dai = {
        .codec_dai_name = "wm8978-hifi",
        .platform_name = "siu-pcm-audio",
        .codec_name = "wm8978.0-001a",
+       .dai_fmt = SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_I2S |
+                  SND_SOC_DAIFMT_CBS_CFS,
        .ops = &migor_dai_ops,
 };
 
index 14d1a71934692fb18b2155311b59a30b7cda62b1..7ac35c9d1cb8b008841a206d1eef1ed5618e4b17 100644 (file)
@@ -57,8 +57,7 @@ static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
        return (0x6 + ws) << 8;
 }
 
-int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_dai *rdai,
-                                struct rsnd_mod *mod,
+int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
                                 struct rsnd_dai_stream *io)
 {
        int id = rsnd_mod_id(mod);
@@ -75,12 +74,11 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_dai *rdai,
        return 0;
 }
 
-static int rsnd_adg_set_src_timsel_gen2(struct rsnd_dai *rdai,
-                                       struct rsnd_mod *mod,
+static int rsnd_adg_set_src_timsel_gen2(struct rsnd_mod *mod,
                                        struct rsnd_dai_stream *io,
                                        u32 timsel)
 {
-       int is_play = rsnd_dai_is_play(rdai, io);
+       int is_play = rsnd_io_is_play(io);
        int id = rsnd_mod_id(mod);
        int shift = (id % 2) ? 16 : 0;
        u32 mask, ws;
@@ -122,7 +120,6 @@ static int rsnd_adg_set_src_timsel_gen2(struct rsnd_dai *rdai,
 }
 
 int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
-                                 struct rsnd_dai *rdai,
                                  struct rsnd_dai_stream *io,
                                  unsigned int src_rate,
                                  unsigned int dst_rate)
@@ -178,7 +175,7 @@ int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
                return -EIO;
        }
 
-       ret = rsnd_adg_set_src_timsel_gen2(rdai, mod, io, val);
+       ret = rsnd_adg_set_src_timsel_gen2(mod, io, val);
        if (ret < 0) {
                dev_err(dev, "timsel error\n");
                return ret;
@@ -190,12 +187,11 @@ int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
 }
 
 int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod,
-                                    struct rsnd_dai *rdai,
                                     struct rsnd_dai_stream *io)
 {
        u32 val = rsnd_adg_ssi_ws_timing_gen2(io);
 
-       return rsnd_adg_set_src_timsel_gen2(rdai, mod, io, val);
+       return rsnd_adg_set_src_timsel_gen2(mod, io, val);
 }
 
 int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
index 75308bbc2ce896e4a266ca0830cde8f5c020a225..1b53605f7154394d1746cb0a692953e296848c2a 100644 (file)
@@ -149,16 +149,16 @@ char *rsnd_mod_dma_name(struct rsnd_mod *mod)
        return mod->ops->dma_name(mod);
 }
 
-void rsnd_mod_init(struct rsnd_priv *priv,
-                  struct rsnd_mod *mod,
+void rsnd_mod_init(struct rsnd_mod *mod,
                   struct rsnd_mod_ops *ops,
+                  struct clk *clk,
                   enum rsnd_mod_type type,
                   int id)
 {
-       mod->priv       = priv;
        mod->id         = id;
        mod->ops        = ops;
        mod->type       = type;
+       mod->clk        = clk;
 }
 
 /*
@@ -412,7 +412,7 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod)
 /*
  *     rsnd_dai functions
  */
-#define __rsnd_mod_call(mod, func, rdai...)                    \
+#define __rsnd_mod_call(mod, func, param...)                   \
 ({                                                             \
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);         \
        struct device *dev = rsnd_priv_to_dev(priv);            \
@@ -422,18 +422,18 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod)
        if ((mod->status & mask) == call) {                             \
                dev_dbg(dev, "%s[%d] %s\n",                             \
                        rsnd_mod_name(mod), rsnd_mod_id(mod), #func);   \
-               ret = (mod)->ops->func(mod, rdai);                      \
+               ret = (mod)->ops->func(mod, param);                     \
                mod->status = (mod->status & ~mask) | (~call & mask);   \
        }                                                               \
        ret;                                                            \
 })
 
-#define rsnd_mod_call(mod, func, rdai...)      \
+#define rsnd_mod_call(mod, func, param...)     \
        (!(mod) ? -ENODEV :                     \
         !((mod)->ops->func) ? 0 :              \
-        __rsnd_mod_call(mod, func, rdai))
+        __rsnd_mod_call(mod, func, param))
 
-#define rsnd_dai_call(fn, io, rdai...)                         \
+#define rsnd_dai_call(fn, io, param...)                                \
 ({                                                             \
        struct rsnd_mod *mod;                                   \
        int ret = 0, i;                                         \
@@ -441,7 +441,7 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod)
                mod = (io)->mod[i];                             \
                if (!mod)                                       \
                        continue;                               \
-               ret = rsnd_mod_call(mod, fn, rdai);             \
+               ret = rsnd_mod_call(mod, fn, param);            \
                if (ret < 0)                                    \
                        break;                                  \
        }                                                       \
@@ -477,17 +477,7 @@ static void rsnd_dai_disconnect(struct rsnd_mod *mod,
        io->mod[mod->type] = NULL;
 }
 
-int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai)
-{
-       int id = rdai - priv->rdai;
-
-       if ((id < 0) || (id >= rsnd_rdai_nr(priv)))
-               return -EINVAL;
-
-       return id;
-}
-
-struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id)
+struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id)
 {
        if ((id < 0) || (id >= rsnd_rdai_nr(priv)))
                return NULL;
@@ -499,12 +489,7 @@ static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai)
 {
        struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai);
 
-       return rsnd_dai_get(priv, dai->id);
-}
-
-int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io)
-{
-       return &rdai->playback == io;
+       return rsnd_rdai_get(priv, dai->id);
 }
 
 /*
@@ -598,20 +583,20 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
                if (ret < 0)
                        goto dai_trigger_end;
 
-               ret = rsnd_dai_call(init, io, rdai);
+               ret = rsnd_dai_call(init, io, priv);
                if (ret < 0)
                        goto dai_trigger_end;
 
-               ret = rsnd_dai_call(start, io, rdai);
+               ret = rsnd_dai_call(start, io, priv);
                if (ret < 0)
                        goto dai_trigger_end;
                break;
        case SNDRV_PCM_TRIGGER_STOP:
-               ret = rsnd_dai_call(stop, io, rdai);
+               ret = rsnd_dai_call(stop, io, priv);
                if (ret < 0)
                        goto dai_trigger_end;
 
-               ret = rsnd_dai_call(quit, io, rdai);
+               ret = rsnd_dai_call(quit, io, priv);
                if (ret < 0)
                        goto dai_trigger_end;
 
@@ -873,15 +858,15 @@ static int rsnd_dai_probe(struct platform_device *pdev,
        priv->rdai      = rdai;
 
        for (i = 0; i < dai_nr; i++) {
-               rdai[i].info = &info->dai_info[i];
 
-               pmod = rdai[i].info->playback.ssi;
-               cmod = rdai[i].info->capture.ssi;
+               pmod = info->dai_info[i].playback.ssi;
+               cmod = info->dai_info[i].capture.ssi;
 
                /*
                 *      init rsnd_dai
                 */
                snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i);
+               rdai[i].priv = priv;
 
                /*
                 *      init snd_soc_dai_driver
@@ -895,6 +880,7 @@ static int rsnd_dai_probe(struct platform_device *pdev,
                        drv[i].playback.channels_max    = 2;
 
                        rdai[i].playback.info = &info->dai_info[i].playback;
+                       rdai[i].playback.rdai = rdai + i;
                        rsnd_path_init(priv, &rdai[i], &rdai[i].playback);
                }
                if (cmod) {
@@ -904,6 +890,7 @@ static int rsnd_dai_probe(struct platform_device *pdev,
                        drv[i].capture.channels_max     = 2;
 
                        rdai[i].capture.info = &info->dai_info[i].capture;
+                       rdai[i].capture.rdai = rdai + i;
                        rsnd_path_init(priv, &rdai[i], &rdai[i].capture);
                }
 
@@ -1037,7 +1024,6 @@ static int rsnd_kctrl_put(struct snd_kcontrol *kctrl,
 }
 
 static int __rsnd_kctrl_new(struct rsnd_mod *mod,
-                           struct rsnd_dai *rdai,
                            struct snd_soc_pcm_runtime *rtd,
                            const unsigned char *name,
                            struct rsnd_kctrl_cfg *cfg,
@@ -1060,16 +1046,24 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod,
                return -ENOMEM;
 
        ret = snd_ctl_add(card, kctrl);
-       if (ret < 0)
+       if (ret < 0) {
+               snd_ctl_free_one(kctrl);
                return ret;
+       }
 
        cfg->update = update;
+       cfg->card = card;
+       cfg->kctrl = kctrl;
 
        return 0;
 }
 
+void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg)
+{
+       snd_ctl_remove(cfg->card, cfg->kctrl);
+}
+
 int rsnd_kctrl_new_m(struct rsnd_mod *mod,
-                    struct rsnd_dai *rdai,
                     struct snd_soc_pcm_runtime *rtd,
                     const unsigned char *name,
                     void (*update)(struct rsnd_mod *mod),
@@ -1079,11 +1073,10 @@ int rsnd_kctrl_new_m(struct rsnd_mod *mod,
        _cfg->cfg.max   = max;
        _cfg->cfg.size  = RSND_DVC_CHANNELS;
        _cfg->cfg.val   = _cfg->val;
-       return __rsnd_kctrl_new(mod, rdai, rtd, name, &_cfg->cfg, update);
+       return __rsnd_kctrl_new(mod, rtd, name, &_cfg->cfg, update);
 }
 
 int rsnd_kctrl_new_s(struct rsnd_mod *mod,
-                    struct rsnd_dai *rdai,
                     struct snd_soc_pcm_runtime *rtd,
                     const unsigned char *name,
                     void (*update)(struct rsnd_mod *mod),
@@ -1093,11 +1086,10 @@ int rsnd_kctrl_new_s(struct rsnd_mod *mod,
        _cfg->cfg.max   = max;
        _cfg->cfg.size  = 1;
        _cfg->cfg.val   = &_cfg->val;
-       return __rsnd_kctrl_new(mod, rdai, rtd, name, &_cfg->cfg, update);
+       return __rsnd_kctrl_new(mod, rtd, name, &_cfg->cfg, update);
 }
 
 int rsnd_kctrl_new_e(struct rsnd_mod *mod,
-                    struct rsnd_dai *rdai,
                     struct snd_soc_pcm_runtime *rtd,
                     const unsigned char *name,
                     struct rsnd_kctrl_cfg_s *_cfg,
@@ -1109,7 +1101,7 @@ int rsnd_kctrl_new_e(struct rsnd_mod *mod,
        _cfg->cfg.size  = 1;
        _cfg->cfg.val   = &_cfg->val;
        _cfg->cfg.texts = texts;
-       return __rsnd_kctrl_new(mod, rdai, rtd, name, &_cfg->cfg, update);
+       return __rsnd_kctrl_new(mod, rtd, name, &_cfg->cfg, update);
 }
 
 /*
@@ -1125,11 +1117,11 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
        struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
        int ret;
 
-       ret = rsnd_dai_call(pcm_new, &rdai->playback, rdai, rtd);
+       ret = rsnd_dai_call(pcm_new, &rdai->playback, rtd);
        if (ret)
                return ret;
 
-       ret = rsnd_dai_call(pcm_new, &rdai->capture, rdai, rtd);
+       ret = rsnd_dai_call(pcm_new, &rdai->capture, rtd);
        if (ret)
                return ret;
 
@@ -1140,15 +1132,9 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
                PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
 }
 
-static void rsnd_pcm_free(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static struct snd_soc_platform_driver rsnd_soc_platform = {
        .ops            = &rsnd_pcm_ops,
        .pcm_new        = rsnd_pcm_new,
-       .pcm_free       = rsnd_pcm_free,
 };
 
 static const struct snd_soc_component_driver rsnd_soc_component = {
@@ -1156,13 +1142,11 @@ static const struct snd_soc_component_driver rsnd_soc_component = {
 };
 
 static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
-                                      struct rsnd_dai *rdai,
-                                      int is_play)
+                                      struct rsnd_dai_stream *io)
 {
-       struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture;
        int ret;
 
-       ret = rsnd_dai_call(probe, io, rdai);
+       ret = rsnd_dai_call(probe, io, priv);
        if (ret == -EAGAIN) {
                /*
                 * Fallback to PIO mode
@@ -1175,7 +1159,7 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
                 *      rsnd_dma_init()
                 *      rsnd_ssi_fallback()
                 */
-               rsnd_dai_call(remove, io, rdai);
+               rsnd_dai_call(remove, io, priv);
 
                /*
                 * remove SRC/DVC from DAI,
@@ -1186,13 +1170,13 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
                /*
                 * fallback
                 */
-               rsnd_dai_call(fallback, io, rdai);
+               rsnd_dai_call(fallback, io, priv);
 
                /*
                 * retry to "probe".
                 * DAI has SSI which is PIO mode only now.
                 */
-               ret = rsnd_dai_call(probe, io, rdai);
+               ret = rsnd_dai_call(probe, io, priv);
        }
 
        return ret;
@@ -1259,11 +1243,11 @@ static int rsnd_probe(struct platform_device *pdev)
        }
 
        for_each_rsnd_dai(rdai, priv, i) {
-               ret = rsnd_rdai_continuance_probe(priv, rdai, 1);
+               ret = rsnd_rdai_continuance_probe(priv, &rdai->playback);
                if (ret)
                        goto exit_snd_probe;
 
-               ret = rsnd_rdai_continuance_probe(priv, rdai, 0);
+               ret = rsnd_rdai_continuance_probe(priv, &rdai->capture);
                if (ret)
                        goto exit_snd_probe;
        }
@@ -1295,8 +1279,8 @@ exit_snd_soc:
        snd_soc_unregister_platform(dev);
 exit_snd_probe:
        for_each_rsnd_dai(rdai, priv, i) {
-               rsnd_dai_call(remove, &rdai->playback, rdai);
-               rsnd_dai_call(remove, &rdai->capture, rdai);
+               rsnd_dai_call(remove, &rdai->playback, priv);
+               rsnd_dai_call(remove, &rdai->capture, priv);
        }
 
        return ret;
@@ -1311,10 +1295,13 @@ static int rsnd_remove(struct platform_device *pdev)
        pm_runtime_disable(&pdev->dev);
 
        for_each_rsnd_dai(rdai, priv, i) {
-               ret |= rsnd_dai_call(remove, &rdai->playback, rdai);
-               ret |= rsnd_dai_call(remove, &rdai->capture, rdai);
+               ret |= rsnd_dai_call(remove, &rdai->playback, priv);
+               ret |= rsnd_dai_call(remove, &rdai->capture, priv);
        }
 
+       snd_soc_unregister_component(&pdev->dev);
+       snd_soc_unregister_platform(&pdev->dev);
+
        return ret;
 }
 
index 5380a4827ba79ecb88bcaeb411bc6465aecb3019..d7f9ed959c4e208a8126174f76daee5a79af133f 100644 (file)
@@ -17,7 +17,6 @@
 struct rsnd_dvc {
        struct rsnd_dvc_platform_info *info; /* rcar_snd.h */
        struct rsnd_mod mod;
-       struct clk *clk;
        struct rsnd_kctrl_cfg_m volume;
        struct rsnd_kctrl_cfg_m mute;
        struct rsnd_kctrl_cfg_s ren;    /* Ramp Enable */
@@ -118,9 +117,8 @@ static void rsnd_dvc_volume_update(struct rsnd_mod *mod)
 }
 
 static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod,
-                              struct rsnd_dai *rdai)
+                              struct rsnd_priv *priv)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
 
        dev_dbg(dev, "%s[%d] (Gen2) is probed\n",
@@ -129,12 +127,24 @@ static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod,
        return 0;
 }
 
+static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod,
+                               struct rsnd_priv *priv)
+{
+       struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+
+       rsnd_kctrl_remove(dvc->volume);
+       rsnd_kctrl_remove(dvc->mute);
+       rsnd_kctrl_remove(dvc->ren);
+       rsnd_kctrl_remove(dvc->rup);
+       rsnd_kctrl_remove(dvc->rdown);
+
+       return 0;
+}
+
 static int rsnd_dvc_init(struct rsnd_mod *dvc_mod,
-                        struct rsnd_dai *rdai)
+                        struct rsnd_priv *priv)
 {
-       struct rsnd_dvc *dvc = rsnd_mod_to_dvc(dvc_mod);
        struct rsnd_dai_stream *io = rsnd_mod_to_io(dvc_mod);
-       struct rsnd_priv *priv = rsnd_mod_to_priv(dvc_mod);
        struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
        struct device *dev = rsnd_priv_to_dev(priv);
        int dvc_id = rsnd_mod_id(dvc_mod);
@@ -153,7 +163,7 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod,
                return -EINVAL;
        }
 
-       clk_prepare_enable(dvc->clk);
+       rsnd_mod_hw_start(dvc_mod);
 
        /*
         * fixme
@@ -173,23 +183,21 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod,
 
        rsnd_mod_write(dvc_mod, DVC_DVUIR, 0);
 
-       rsnd_adg_set_cmd_timsel_gen2(rdai, dvc_mod, io);
+       rsnd_adg_set_cmd_timsel_gen2(dvc_mod, io);
 
        return 0;
 }
 
 static int rsnd_dvc_quit(struct rsnd_mod *mod,
-                        struct rsnd_dai *rdai)
+                        struct rsnd_priv *priv)
 {
-       struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
-
-       clk_disable_unprepare(dvc->clk);
+       rsnd_mod_hw_stop(mod);
 
        return 0;
 }
 
 static int rsnd_dvc_start(struct rsnd_mod *mod,
-                         struct rsnd_dai *rdai)
+                         struct rsnd_priv *priv)
 {
        rsnd_mod_write(mod, CMD_CTRL, 0x10);
 
@@ -197,7 +205,7 @@ static int rsnd_dvc_start(struct rsnd_mod *mod,
 }
 
 static int rsnd_dvc_stop(struct rsnd_mod *mod,
-                        struct rsnd_dai *rdai)
+                        struct rsnd_priv *priv)
 {
        rsnd_mod_write(mod, CMD_CTRL, 0);
 
@@ -205,16 +213,16 @@ static int rsnd_dvc_stop(struct rsnd_mod *mod,
 }
 
 static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
-                           struct rsnd_dai *rdai,
                            struct snd_soc_pcm_runtime *rtd)
 {
        struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+       int is_play = rsnd_io_is_play(io);
        int ret;
 
        /* Volume */
-       ret = rsnd_kctrl_new_m(mod, rdai, rtd,
-                       rsnd_dai_is_play(rdai, io) ?
+       ret = rsnd_kctrl_new_m(mod, rtd,
+                       is_play ?
                        "DVC Out Playback Volume" : "DVC In Capture Volume",
                        rsnd_dvc_volume_update,
                        &dvc->volume, 0x00800000 - 1);
@@ -222,8 +230,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
                return ret;
 
        /* Mute */
-       ret = rsnd_kctrl_new_m(mod, rdai, rtd,
-                       rsnd_dai_is_play(rdai, io) ?
+       ret = rsnd_kctrl_new_m(mod, rtd,
+                       is_play ?
                        "DVC Out Mute Switch" : "DVC In Mute Switch",
                        rsnd_dvc_volume_update,
                        &dvc->mute, 1);
@@ -231,16 +239,16 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
                return ret;
 
        /* Ramp */
-       ret = rsnd_kctrl_new_s(mod, rdai, rtd,
-                       rsnd_dai_is_play(rdai, io) ?
+       ret = rsnd_kctrl_new_s(mod, rtd,
+                       is_play ?
                        "DVC Out Ramp Switch" : "DVC In Ramp Switch",
                        rsnd_dvc_volume_update,
                        &dvc->ren, 1);
        if (ret < 0)
                return ret;
 
-       ret = rsnd_kctrl_new_e(mod, rdai, rtd,
-                       rsnd_dai_is_play(rdai, io) ?
+       ret = rsnd_kctrl_new_e(mod, rtd,
+                       is_play ?
                        "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate",
                        &dvc->rup,
                        rsnd_dvc_volume_update,
@@ -248,8 +256,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
        if (ret < 0)
                return ret;
 
-       ret = rsnd_kctrl_new_e(mod, rdai, rtd,
-                       rsnd_dai_is_play(rdai, io) ?
+       ret = rsnd_kctrl_new_e(mod, rtd,
+                       is_play ?
                        "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate",
                        &dvc->rdown,
                        rsnd_dvc_volume_update,
@@ -264,6 +272,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
 static struct rsnd_mod_ops rsnd_dvc_ops = {
        .name           = DVC_NAME,
        .probe          = rsnd_dvc_probe_gen2,
+       .remove         = rsnd_dvc_remove_gen2,
        .init           = rsnd_dvc_init,
        .quit           = rsnd_dvc_quit,
        .start          = rsnd_dvc_start,
@@ -356,9 +365,9 @@ int rsnd_dvc_probe(struct platform_device *pdev,
                        return PTR_ERR(clk);
 
                dvc->info = &info->dvc_info[i];
-               dvc->clk  = clk;
 
-               rsnd_mod_init(priv, &dvc->mod, &rsnd_dvc_ops, RSND_MOD_DVC, i);
+               rsnd_mod_init(&dvc->mod, &rsnd_dvc_ops,
+                             clk, RSND_MOD_DVC, i);
 
                dev_dbg(dev, "CMD%d probed\n", i);
        }
index 87a6f2d627753c0f69ba0b51fb7e2d0bc1438f45..de0685f2abaee64f4d729745497b7a6a4ae51e0e 100644 (file)
@@ -309,8 +309,13 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
                RSND_GEN_M_REG(SRC_BUSIF_MODE,  0x0,    0x20),
                RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc,    0x20),
                RSND_GEN_M_REG(SRC_CTRL,        0x10,   0x20),
+               RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18,   0x20),
                RSND_GEN_M_REG(CMD_ROUTE_SLCT,  0x18c,  0x20),
                RSND_GEN_M_REG(CMD_CTRL,        0x190,  0x20),
+               RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8),
+               RSND_GEN_S_REG(SCU_SYS_INT_EN0, 0x1cc),
+               RSND_GEN_S_REG(SCU_SYS_STATUS1, 0x1d0),
+               RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1c4),
                RSND_GEN_M_REG(SRC_SWRSR,       0x200,  0x40),
                RSND_GEN_M_REG(SRC_SRCIR,       0x204,  0x40),
                RSND_GEN_M_REG(SRC_ADINR,       0x214,  0x40),
@@ -403,6 +408,16 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
                RSND_GEN_M_REG(SRC_IFSVR,       0x220,  0x40),
                RSND_GEN_M_REG(SRC_SRCCR,       0x224,  0x40),
                RSND_GEN_M_REG(SRC_MNFSR,       0x228,  0x40),
+               /*
+                * ADD US
+                *
+                * SRC_STATUS
+                * SRC_INT_EN
+                * SCU_SYS_STATUS0
+                * SCU_SYS_STATUS1
+                * SCU_SYS_INT_EN0
+                * SCU_SYS_INT_EN1
+                */
        };
        struct rsnd_regmap_field_conf conf_adg[] = {
                RSND_GEN_S_REG(BRRA,            0x00),
index 5826c8abf7949d3ed1807dfe1c61a7fa8a219f84..e7914bd610e2120644f616e6500bdf3ad9ec24d3 100644 (file)
@@ -44,6 +44,8 @@ enum rsnd_reg {
        RSND_REG_SRC_IFSCR,
        RSND_REG_SRC_IFSVR,
        RSND_REG_SRC_SRCCR,
+       RSND_REG_SCU_SYS_STATUS0,
+       RSND_REG_SCU_SYS_INT_EN0,
        RSND_REG_CMD_ROUTE_SLCT,
        RSND_REG_DVC_SWRSR,
        RSND_REG_DVC_DVUIR,
@@ -94,6 +96,9 @@ enum rsnd_reg {
        RSND_REG_SHARE23,
        RSND_REG_SHARE24,
        RSND_REG_SHARE25,
+       RSND_REG_SHARE26,
+       RSND_REG_SHARE27,
+       RSND_REG_SHARE28,
 
        RSND_REG_MAX,
 };
@@ -135,6 +140,9 @@ enum rsnd_reg {
 #define RSND_REG_DVC_VRCTR             RSND_REG_SHARE23
 #define RSND_REG_DVC_VRPDR             RSND_REG_SHARE24
 #define RSND_REG_DVC_VRDBR             RSND_REG_SHARE25
+#define RSND_REG_SCU_SYS_STATUS1       RSND_REG_SHARE26
+#define RSND_REG_SCU_SYS_INT_EN1       RSND_REG_SHARE27
+#define RSND_REG_SRC_INT_ENABLE0       RSND_REG_SHARE28
 
 struct rsnd_of_data;
 struct rsnd_priv;
@@ -182,9 +190,9 @@ void  rsnd_dma_quit(struct rsnd_priv *priv,
  *     R-Car sound mod
  */
 enum rsnd_mod_type {
-       RSND_MOD_SRC = 0,
+       RSND_MOD_DVC = 0,
+       RSND_MOD_SRC,
        RSND_MOD_SSI,
-       RSND_MOD_DVC,
        RSND_MOD_MAX,
 };
 
@@ -192,32 +200,31 @@ struct rsnd_mod_ops {
        char *name;
        char* (*dma_name)(struct rsnd_mod *mod);
        int (*probe)(struct rsnd_mod *mod,
-                    struct rsnd_dai *rdai);
+                    struct rsnd_priv *priv);
        int (*remove)(struct rsnd_mod *mod,
-                     struct rsnd_dai *rdai);
+                     struct rsnd_priv *priv);
        int (*init)(struct rsnd_mod *mod,
-                   struct rsnd_dai *rdai);
+                   struct rsnd_priv *priv);
        int (*quit)(struct rsnd_mod *mod,
-                   struct rsnd_dai *rdai);
+                   struct rsnd_priv *priv);
        int (*start)(struct rsnd_mod *mod,
-                    struct rsnd_dai *rdai);
+                    struct rsnd_priv *priv);
        int (*stop)(struct rsnd_mod *mod,
-                   struct rsnd_dai *rdai);
+                   struct rsnd_priv *priv);
        int (*pcm_new)(struct rsnd_mod *mod,
-                      struct rsnd_dai *rdai,
                       struct snd_soc_pcm_runtime *rtd);
        int (*fallback)(struct rsnd_mod *mod,
-                       struct rsnd_dai *rdai);
+                       struct rsnd_priv *priv);
 };
 
 struct rsnd_dai_stream;
 struct rsnd_mod {
        int id;
        enum rsnd_mod_type type;
-       struct rsnd_priv *priv;
        struct rsnd_mod_ops *ops;
        struct rsnd_dma dma;
        struct rsnd_dai_stream *io;
+       struct clk *clk;
        u32 status;
 };
 /*
@@ -248,15 +255,17 @@ struct rsnd_mod {
 #define __rsnd_mod_call_pcm_new                0
 #define __rsnd_mod_call_fallback       0
 
-#define rsnd_mod_to_priv(mod) ((mod)->priv)
+#define rsnd_mod_to_priv(mod) (rsnd_io_to_priv(rsnd_mod_to_io(mod)))
 #define rsnd_mod_to_dma(mod) (&(mod)->dma)
 #define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
 #define rsnd_mod_to_io(mod) ((mod)->io)
 #define rsnd_mod_id(mod) ((mod)->id)
+#define rsnd_mod_hw_start(mod) clk_prepare_enable((mod)->clk)
+#define rsnd_mod_hw_stop(mod)  clk_disable_unprepare((mod)->clk)
 
-void rsnd_mod_init(struct rsnd_priv *priv,
-                  struct rsnd_mod *mod,
+void rsnd_mod_init(struct rsnd_mod *mod,
                   struct rsnd_mod_ops *ops,
+                  struct clk *clk,
                   enum rsnd_mod_type type,
                   int id);
 char *rsnd_mod_name(struct rsnd_mod *mod);
@@ -270,6 +279,7 @@ struct rsnd_dai_stream {
        struct snd_pcm_substream *substream;
        struct rsnd_mod *mod[RSND_MOD_MAX];
        struct rsnd_dai_path_info *info; /* rcar_snd.h */
+       struct rsnd_dai *rdai;
        int byte_pos;
        int period_pos;
        int byte_per_period;
@@ -278,12 +288,18 @@ struct rsnd_dai_stream {
 #define rsnd_io_to_mod_ssi(io) ((io)->mod[RSND_MOD_SSI])
 #define rsnd_io_to_mod_src(io) ((io)->mod[RSND_MOD_SRC])
 #define rsnd_io_to_mod_dvc(io) ((io)->mod[RSND_MOD_DVC])
+#define rsnd_io_to_rdai(io)    ((io)->rdai)
+#define rsnd_io_to_priv(io)    (rsnd_rdai_to_priv(rsnd_io_to_rdai(io)))
+#define rsnd_io_is_play(io)    (&rsnd_io_to_rdai(io)->playback == io)
+#define rsnd_io_to_runtime(io) ((io)->substream ? \
+                               (io)->substream->runtime : NULL)
+
 
 struct rsnd_dai {
        char name[RSND_DAI_NAME_SIZE];
-       struct rsnd_dai_platform_info *info; /* rcar_snd.h */
        struct rsnd_dai_stream playback;
        struct rsnd_dai_stream capture;
+       struct rsnd_priv *priv;
 
        unsigned int clk_master:1;
        unsigned int bit_clk_inv:1;
@@ -293,22 +309,18 @@ struct rsnd_dai {
 };
 
 #define rsnd_rdai_nr(priv) ((priv)->rdai_nr)
+#define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master)
+#define rsnd_rdai_to_priv(rdai) ((rdai)->priv)
 #define for_each_rsnd_dai(rdai, priv, i)               \
        for (i = 0;                                     \
             (i < rsnd_rdai_nr(priv)) &&                \
-            ((rdai) = rsnd_dai_get(priv, i));          \
+            ((rdai) = rsnd_rdai_get(priv, i));         \
             i++)
 
-struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id);
-int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io);
-int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai);
-#define rsnd_dai_get_platform_info(rdai) ((rdai)->info)
-#define rsnd_io_to_runtime(io) ((io)->substream ? \
-                               (io)->substream->runtime : NULL)
+struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id);
 
 void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt);
 int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
-#define rsnd_dai_is_clk_master(rdai) ((rdai)->clk_master)
 
 /*
  *     R-Car Gen1/Gen2
@@ -339,15 +351,12 @@ int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
                                  unsigned int src_rate,
                                  unsigned int dst_rate);
 int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
-                                 struct rsnd_dai *rdai,
                                  struct rsnd_dai_stream *io,
                                  unsigned int src_rate,
                                  unsigned int dst_rate);
 int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod,
-                                    struct rsnd_dai *rdai,
                                     struct rsnd_dai_stream *io);
-int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_dai *rdai,
-                                struct rsnd_mod *mod,
+int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
                                 struct rsnd_dai_stream *io);
 
 /*
@@ -427,6 +436,8 @@ struct rsnd_kctrl_cfg {
        u32 *val;
        const char * const *texts;
        void (*update)(struct rsnd_mod *mod);
+       struct snd_card *card;
+       struct snd_kcontrol *kctrl;
 };
 
 #define RSND_DVC_CHANNELS      2
@@ -440,22 +451,22 @@ struct rsnd_kctrl_cfg_s {
        u32 val;
 };
 
+void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg);
+#define rsnd_kctrl_remove(_cfg)        _rsnd_kctrl_remove(&((_cfg).cfg))
+
 int rsnd_kctrl_new_m(struct rsnd_mod *mod,
-                    struct rsnd_dai *rdai,
                     struct snd_soc_pcm_runtime *rtd,
                     const unsigned char *name,
                     void (*update)(struct rsnd_mod *mod),
                     struct rsnd_kctrl_cfg_m *_cfg,
                     u32 max);
 int rsnd_kctrl_new_s(struct rsnd_mod *mod,
-                    struct rsnd_dai *rdai,
                     struct snd_soc_pcm_runtime *rtd,
                     const unsigned char *name,
                     void (*update)(struct rsnd_mod *mod),
                     struct rsnd_kctrl_cfg_s *_cfg,
                     u32 max);
 int rsnd_kctrl_new_e(struct rsnd_mod *mod,
-                    struct rsnd_dai *rdai,
                     struct snd_soc_pcm_runtime *rtd,
                     const unsigned char *name,
                     struct rsnd_kctrl_cfg_s *_cfg,
@@ -474,14 +485,10 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
                                   struct rsnd_dai_stream *io,
                                   struct snd_pcm_runtime *runtime);
 int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
-                       struct rsnd_dai *rdai,
                        int use_busif);
-int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
-                      struct rsnd_dai *rdai);
-int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod,
-                           struct rsnd_dai *rdai);
-int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod,
-                            struct rsnd_dai *rdai);
+int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod);
+int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod);
+int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod);
 
 #define rsnd_src_nr(priv) ((priv)->src_nr)
 
index eede3ac6eed232b12307881574a8d041f1d88352..81c182b4bad531c8afe3a071da4c9ad41c4d868f 100644 (file)
 
 #define SRC_NAME "src"
 
+/* SRCx_STATUS */
+#define OUF_SRCO       ((1 << 12) | (1 << 13))
+#define OUF_SRCI       ((1 <<  9) | (1 <<  8))
+
+/* SCU_SYSTEM_STATUS0/1 */
+#define OUF_SRC(id)    ((1 << (id + 16)) | (1 << id))
+
 struct rsnd_src {
        struct rsnd_src_platform_info *info; /* rcar_snd.h */
        struct rsnd_mod mod;
-       struct clk *clk;
+       int err;
 };
 
 #define RSND_SRC_NAME_SIZE 16
@@ -107,10 +114,10 @@ struct rsnd_src {
  *             Gen1/Gen2 common functions
  */
 int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
-                       struct rsnd_dai *rdai,
                        int use_busif)
 {
        struct rsnd_dai_stream *io = rsnd_mod_to_io(ssi_mod);
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        int ssi_id = rsnd_mod_id(ssi_mod);
 
@@ -140,7 +147,7 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
                if (shift >= 0)
                        rsnd_mod_bset(ssi_mod, SSI_MODE1,
                                      0x3 << shift,
-                                     rsnd_dai_is_clk_master(rdai) ?
+                                     rsnd_rdai_is_clk_master(rdai) ?
                                      0x2 << shift : 0x1 << shift);
        }
 
@@ -174,8 +181,7 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
        return 0;
 }
 
-int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
-                      struct rsnd_dai *rdai)
+int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod)
 {
        /*
         * DMA settings for SSIU
@@ -185,8 +191,7 @@ int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
        return 0;
 }
 
-int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod,
-                           struct rsnd_dai *rdai)
+int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
 
@@ -202,8 +207,7 @@ int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod,
        return 0;
 }
 
-int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod,
-                           struct rsnd_dai *rdai)
+int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
 
@@ -240,8 +244,7 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
        return rate;
 }
 
-static int rsnd_src_set_convert_rate(struct rsnd_mod *mod,
-                                    struct rsnd_dai *rdai)
+static int rsnd_src_set_convert_rate(struct rsnd_mod *mod)
 {
        struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
@@ -273,12 +276,13 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod,
        return 0;
 }
 
-static int rsnd_src_init(struct rsnd_mod *mod,
-                        struct rsnd_dai *rdai)
+static int rsnd_src_init(struct rsnd_mod *mod)
 {
        struct rsnd_src *src = rsnd_mod_to_src(mod);
 
-       clk_prepare_enable(src->clk);
+       rsnd_mod_hw_start(mod);
+
+       src->err = 0;
 
        /*
         * Initialize the operation of the SRC internal circuits
@@ -290,11 +294,16 @@ static int rsnd_src_init(struct rsnd_mod *mod,
 }
 
 static int rsnd_src_quit(struct rsnd_mod *mod,
-                        struct rsnd_dai *rdai)
+                        struct rsnd_priv *priv)
 {
        struct rsnd_src *src = rsnd_mod_to_src(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       rsnd_mod_hw_stop(mod);
 
-       clk_disable_unprepare(src->clk);
+       if (src->err)
+               dev_warn(dev, "%s[%d] under/over flow err = %d\n",
+                        rsnd_mod_name(mod), rsnd_mod_id(mod), src->err);
 
        return 0;
 }
@@ -319,8 +328,7 @@ static int rsnd_src_stop(struct rsnd_mod *mod)
 /*
  *             Gen1 functions
  */
-static int rsnd_src_set_route_gen1(struct rsnd_mod *mod,
-                                  struct rsnd_dai *rdai)
+static int rsnd_src_set_route_gen1(struct rsnd_mod *mod)
 {
        struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct src_route_config {
@@ -348,7 +356,7 @@ static int rsnd_src_set_route_gen1(struct rsnd_mod *mod,
        /*
         * SRC_ROUTE_SELECT
         */
-       val = rsnd_dai_is_play(rdai, io) ? 0x1 : 0x2;
+       val = rsnd_io_is_play(io) ? 0x1 : 0x2;
        val = val               << routes[id].shift;
        mask = routes[id].mask  << routes[id].shift;
 
@@ -357,8 +365,7 @@ static int rsnd_src_set_route_gen1(struct rsnd_mod *mod,
        return 0;
 }
 
-static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod,
-                                           struct rsnd_dai *rdai)
+static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod)
 {
        struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
@@ -416,13 +423,12 @@ static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod,
        return 0;
 }
 
-static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod,
-                                         struct rsnd_dai *rdai)
+static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod)
 {
        struct rsnd_src *src = rsnd_mod_to_src(mod);
        int ret;
 
-       ret = rsnd_src_set_convert_rate(mod, rdai);
+       ret = rsnd_src_set_convert_rate(mod);
        if (ret < 0)
                return ret;
 
@@ -443,9 +449,8 @@ static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod,
 }
 
 static int rsnd_src_probe_gen1(struct rsnd_mod *mod,
-                             struct rsnd_dai *rdai)
+                              struct rsnd_priv *priv)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
 
        dev_dbg(dev, "%s[%d] (Gen1) is probed\n",
@@ -455,23 +460,23 @@ static int rsnd_src_probe_gen1(struct rsnd_mod *mod,
 }
 
 static int rsnd_src_init_gen1(struct rsnd_mod *mod,
-                             struct rsnd_dai *rdai)
+                             struct rsnd_priv *priv)
 {
        int ret;
 
-       ret = rsnd_src_init(mod, rdai);
+       ret = rsnd_src_init(mod);
        if (ret < 0)
                return ret;
 
-       ret = rsnd_src_set_route_gen1(mod, rdai);
+       ret = rsnd_src_set_route_gen1(mod);
        if (ret < 0)
                return ret;
 
-       ret = rsnd_src_set_convert_rate_gen1(mod, rdai);
+       ret = rsnd_src_set_convert_rate_gen1(mod);
        if (ret < 0)
                return ret;
 
-       ret = rsnd_src_set_convert_timing_gen1(mod, rdai);
+       ret = rsnd_src_set_convert_timing_gen1(mod);
        if (ret < 0)
                return ret;
 
@@ -479,7 +484,7 @@ static int rsnd_src_init_gen1(struct rsnd_mod *mod,
 }
 
 static int rsnd_src_start_gen1(struct rsnd_mod *mod,
-                              struct rsnd_dai *rdai)
+                              struct rsnd_priv *priv)
 {
        int id = rsnd_mod_id(mod);
 
@@ -489,7 +494,7 @@ static int rsnd_src_start_gen1(struct rsnd_mod *mod,
 }
 
 static int rsnd_src_stop_gen1(struct rsnd_mod *mod,
-                             struct rsnd_dai *rdai)
+                             struct rsnd_priv *priv)
 {
        int id = rsnd_mod_id(mod);
 
@@ -510,8 +515,111 @@ static struct rsnd_mod_ops rsnd_src_gen1_ops = {
 /*
  *             Gen2 functions
  */
-static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
-                                         struct rsnd_dai *rdai)
+#define rsnd_src_irq_enable_gen2(mod)  rsnd_src_irq_ctrol_gen2(mod, 1)
+#define rsnd_src_irq_disable_gen2(mod) rsnd_src_irq_ctrol_gen2(mod, 0)
+static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable)
+{
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       u32 sys_int_val, int_val, sys_int_mask;
+       int irq = src->info->irq;
+       int id = rsnd_mod_id(mod);
+
+       sys_int_val =
+       sys_int_mask = OUF_SRC(id);
+       int_val = 0x3300;
+
+       /*
+        * IRQ is not supported on non-DT
+        * see
+        *      rsnd_src_probe_gen2()
+        */
+       if ((irq <= 0) || !enable) {
+               sys_int_val = 0;
+               int_val = 0;
+       }
+
+       rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val);
+       rsnd_mod_bset(mod, SCU_SYS_INT_EN0, sys_int_mask, sys_int_val);
+       rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val);
+}
+
+static void rsnd_src_error_clear_gen2(struct rsnd_mod *mod)
+{
+       u32 val = OUF_SRC(rsnd_mod_id(mod));
+
+       rsnd_mod_bset(mod, SCU_SYS_STATUS0, val, val);
+       rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val);
+}
+
+static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod)
+{
+       u32 val = OUF_SRC(rsnd_mod_id(mod));
+       bool ret = false;
+
+       if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val) ||
+           (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val)) {
+               struct rsnd_src *src = rsnd_mod_to_src(mod);
+
+               src->err++;
+               ret = true;
+       }
+
+       /* clear error static */
+       rsnd_src_error_clear_gen2(mod);
+
+       return ret;
+}
+
+static int _rsnd_src_start_gen2(struct rsnd_mod *mod)
+{
+       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+       u32 val = rsnd_io_to_mod_dvc(io) ? 0x01 : 0x11;
+
+       rsnd_mod_write(mod, SRC_CTRL, val);
+
+       rsnd_src_error_clear_gen2(mod);
+
+       rsnd_src_start(mod);
+
+       rsnd_src_irq_enable_gen2(mod);
+
+       return 0;
+}
+
+static int _rsnd_src_stop_gen2(struct rsnd_mod *mod)
+{
+       rsnd_src_irq_disable_gen2(mod);
+
+       rsnd_mod_write(mod, SRC_CTRL, 0);
+
+       rsnd_src_error_record_gen2(mod);
+
+       return rsnd_src_stop(mod);
+}
+
+static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data)
+{
+       struct rsnd_mod *mod = data;
+       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+
+       if (!io)
+               return IRQ_NONE;
+
+       if (rsnd_src_error_record_gen2(mod)) {
+               struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+               struct device *dev = rsnd_priv_to_dev(priv);
+
+               _rsnd_src_stop_gen2(mod);
+               _rsnd_src_start_gen2(mod);
+
+               dev_dbg(dev, "%s[%d] restart\n",
+                       rsnd_mod_name(mod), rsnd_mod_id(mod));
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
@@ -535,7 +643,7 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
                return -EINVAL;
        }
 
-       ret = rsnd_src_set_convert_rate(mod, rdai);
+       ret = rsnd_src_set_convert_rate(mod);
        if (ret < 0)
                return ret;
 
@@ -563,8 +671,7 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
        return 0;
 }
 
-static int rsnd_src_set_convert_timing_gen2(struct rsnd_mod *mod,
-                                           struct rsnd_dai *rdai)
+static int rsnd_src_set_convert_timing_gen2(struct rsnd_mod *mod)
 {
        struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
@@ -573,59 +680,78 @@ static int rsnd_src_set_convert_timing_gen2(struct rsnd_mod *mod,
        int ret;
 
        if (convert_rate)
-               ret = rsnd_adg_set_convert_clk_gen2(mod, rdai, io,
+               ret = rsnd_adg_set_convert_clk_gen2(mod, io,
                                                    runtime->rate,
                                                    convert_rate);
        else
-               ret = rsnd_adg_set_convert_timing_gen2(mod, rdai, io);
+               ret = rsnd_adg_set_convert_timing_gen2(mod, io);
 
        return ret;
 }
 
 static int rsnd_src_probe_gen2(struct rsnd_mod *mod,
-                              struct rsnd_dai *rdai)
+                              struct rsnd_priv *priv)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct rsnd_src *src = rsnd_mod_to_src(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
+       int irq = src->info->irq;
        int ret;
 
+       if (irq > 0) {
+               /*
+                * IRQ is not supported on non-DT
+                * see
+                *      rsnd_src_irq_enable_gen2()
+                */
+               ret = devm_request_irq(dev, irq,
+                                      rsnd_src_interrupt_gen2,
+                                      IRQF_SHARED,
+                                      dev_name(dev), mod);
+               if (ret)
+                       goto rsnd_src_probe_gen2_fail;
+       }
+
        ret = rsnd_dma_init(priv,
                            rsnd_mod_to_dma(mod),
                            rsnd_info_is_playback(priv, src),
                            src->info->dma_id);
-       if (ret < 0)
-               dev_err(dev, "%s[%d] (Gen2) failed\n",
-                       rsnd_mod_name(mod), rsnd_mod_id(mod));
-       else
-               dev_dbg(dev, "%s[%d] (Gen2) is probed\n",
-                       rsnd_mod_name(mod), rsnd_mod_id(mod));
+       if (ret)
+               goto rsnd_src_probe_gen2_fail;
+
+       dev_dbg(dev, "%s[%d] (Gen2) is probed\n",
+               rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+       return ret;
+
+rsnd_src_probe_gen2_fail:
+       dev_err(dev, "%s[%d] (Gen2) failed\n",
+               rsnd_mod_name(mod), rsnd_mod_id(mod));
 
        return ret;
 }
 
 static int rsnd_src_remove_gen2(struct rsnd_mod *mod,
-                               struct rsnd_dai *rdai)
+                               struct rsnd_priv *priv)
 {
-       rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod));
+       rsnd_dma_quit(priv, rsnd_mod_to_dma(mod));
 
        return 0;
 }
 
 static int rsnd_src_init_gen2(struct rsnd_mod *mod,
-                             struct rsnd_dai *rdai)
+                             struct rsnd_priv *priv)
 {
        int ret;
 
-       ret = rsnd_src_init(mod, rdai);
+       ret = rsnd_src_init(mod);
        if (ret < 0)
                return ret;
 
-       ret = rsnd_src_set_convert_rate_gen2(mod, rdai);
+       ret = rsnd_src_set_convert_rate_gen2(mod);
        if (ret < 0)
                return ret;
 
-       ret = rsnd_src_set_convert_timing_gen2(mod, rdai);
+       ret = rsnd_src_set_convert_timing_gen2(mod);
        if (ret < 0)
                return ret;
 
@@ -633,29 +759,23 @@ static int rsnd_src_init_gen2(struct rsnd_mod *mod,
 }
 
 static int rsnd_src_start_gen2(struct rsnd_mod *mod,
-                              struct rsnd_dai *rdai)
+                              struct rsnd_priv *priv)
 {
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
-       struct rsnd_src *src = rsnd_mod_to_src(mod);
-       u32 val = rsnd_io_to_mod_dvc(io) ? 0x01 : 0x11;
-
-       rsnd_dma_start(rsnd_mod_to_dma(&src->mod));
+       rsnd_dma_start(rsnd_mod_to_dma(mod));
 
-       rsnd_mod_write(mod, SRC_CTRL, val);
-
-       return rsnd_src_start(mod);
+       return _rsnd_src_start_gen2(mod);
 }
 
 static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
-                             struct rsnd_dai *rdai)
+                             struct rsnd_priv *priv)
 {
-       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       int ret;
 
-       rsnd_mod_write(mod, SRC_CTRL, 0);
+       ret = _rsnd_src_stop_gen2(mod);
 
-       rsnd_dma_stop(rsnd_mod_to_dma(&src->mod));
+       rsnd_dma_stop(rsnd_mod_to_dma(mod));
 
-       return rsnd_src_stop(mod);
+       return ret;
 }
 
 static struct rsnd_mod_ops rsnd_src_gen2_ops = {
@@ -681,10 +801,11 @@ static void rsnd_of_parse_src(struct platform_device *pdev,
                              struct rsnd_priv *priv)
 {
        struct device_node *src_node;
+       struct device_node *np;
        struct rcar_snd_info *info = rsnd_priv_to_info(priv);
        struct rsnd_src_platform_info *src_info;
        struct device *dev = &pdev->dev;
-       int nr;
+       int nr, i;
 
        if (!of_data)
                return;
@@ -708,6 +829,13 @@ static void rsnd_of_parse_src(struct platform_device *pdev,
        info->src_info          = src_info;
        info->src_info_nr       = nr;
 
+       i = 0;
+       for_each_child_of_node(src_node, np) {
+               src_info[i].irq = irq_of_parse_and_map(np, 0);
+
+               i++;
+       }
+
 rsnd_of_parse_src_end:
        of_node_put(src_node);
 }
@@ -761,9 +889,8 @@ int rsnd_src_probe(struct platform_device *pdev,
                        return PTR_ERR(clk);
 
                src->info = &info->src_info[i];
-               src->clk = clk;
 
-               rsnd_mod_init(priv, &src->mod, ops, RSND_MOD_SRC, i);
+               rsnd_mod_init(&src->mod, ops, clk, RSND_MOD_SRC, i);
 
                dev_dbg(dev, "SRC%d probed\n", i);
        }
index 3844fbef46649db6133b7e3e4266d8f014eb28ae..9e7b627c08e2256dbe09acd063432b7b3b7c1107 100644 (file)
 #define SSI_NAME "ssi"
 
 struct rsnd_ssi {
-       struct clk *clk;
        struct rsnd_ssi_platform_info *info; /* rcar_snd.h */
        struct rsnd_ssi *parent;
        struct rsnd_mod mod;
 
-       struct rsnd_dai *rdai;
        u32 cr_own;
        u32 cr_clk;
        int err;
        unsigned int usrcnt;
-       unsigned int rate;
 };
 
 #define for_each_rsnd_ssi(pos, priv, i)                                        \
@@ -128,7 +125,7 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod,
 static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
                                     struct rsnd_dai_stream *io)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        struct device *dev = rsnd_priv_to_dev(priv);
        int i, j, ret;
@@ -157,7 +154,6 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
 
                        ret = rsnd_adg_ssi_clk_try_start(&ssi->mod, main_rate);
                        if (0 == ret) {
-                               ssi->rate       = rate;
                                ssi->cr_clk     = FORCE | SWL_32 |
                                                  SCKD | SWSD | CKDV(j);
 
@@ -176,26 +172,25 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
 
 static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi)
 {
-       ssi->rate = 0;
        ssi->cr_clk = 0;
        rsnd_adg_ssi_clk_stop(&ssi->mod);
 }
 
 static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
-                             struct rsnd_dai *rdai,
                              struct rsnd_dai_stream *io)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        struct device *dev = rsnd_priv_to_dev(priv);
        u32 cr_mode;
        u32 cr;
 
        if (0 == ssi->usrcnt) {
-               clk_prepare_enable(ssi->clk);
+               rsnd_mod_hw_start(&ssi->mod);
 
-               if (rsnd_dai_is_clk_master(rdai)) {
+               if (rsnd_rdai_is_clk_master(rdai)) {
                        if (rsnd_ssi_clk_from_parent(ssi))
-                               rsnd_ssi_hw_start(ssi->parent, rdai, io);
+                               rsnd_ssi_hw_start(ssi->parent, io);
                        else
                                rsnd_ssi_master_clk_start(ssi, io);
                }
@@ -214,7 +209,7 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
        rsnd_mod_write(&ssi->mod, SSICR, cr);
 
        /* enable WS continue */
-       if (rsnd_dai_is_clk_master(rdai))
+       if (rsnd_rdai_is_clk_master(rdai))
                rsnd_mod_write(&ssi->mod, SSIWSR, CONT);
 
        /* clear error status */
@@ -226,10 +221,11 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
                rsnd_mod_name(&ssi->mod), rsnd_mod_id(&ssi->mod));
 }
 
-static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
-                            struct rsnd_dai *rdai)
+static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
+       struct rsnd_dai_stream *io = rsnd_mod_to_io(&ssi->mod);
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        struct device *dev = rsnd_priv_to_dev(priv);
        u32 cr;
 
@@ -256,14 +252,14 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
                rsnd_mod_write(&ssi->mod, SSICR, cr);   /* disabled all */
                rsnd_ssi_status_check(&ssi->mod, IIRQ);
 
-               if (rsnd_dai_is_clk_master(rdai)) {
+               if (rsnd_rdai_is_clk_master(rdai)) {
                        if (rsnd_ssi_clk_from_parent(ssi))
-                               rsnd_ssi_hw_stop(ssi->parent, rdai);
+                               rsnd_ssi_hw_stop(ssi->parent);
                        else
                                rsnd_ssi_master_clk_stop(ssi);
                }
 
-               clk_disable_unprepare(ssi->clk);
+               rsnd_mod_hw_stop(&ssi->mod);
        }
 
        dev_dbg(dev, "%s[%d] hw stopped\n",
@@ -274,10 +270,11 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
  *     SSI mod common functions
  */
 static int rsnd_ssi_init(struct rsnd_mod *mod,
-                        struct rsnd_dai *rdai)
+                        struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        u32 cr;
 
@@ -311,13 +308,12 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
                cr |= SDTA;
        if (rdai->sys_delay)
                cr |= DEL;
-       if (rsnd_dai_is_play(rdai, io))
+       if (rsnd_io_is_play(io))
                cr |= TRMD;
 
        /*
         * set ssi parameter
         */
-       ssi->rdai       = rdai;
        ssi->cr_own     = cr;
        ssi->err        = -1; /* ignore 1st error */
 
@@ -325,16 +321,15 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
 }
 
 static int rsnd_ssi_quit(struct rsnd_mod *mod,
-                        struct rsnd_dai *rdai)
+                        struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
 
        if (ssi->err > 0)
-               dev_warn(dev, "ssi under/over flow err = %d\n", ssi->err);
+               dev_warn(dev, "%s[%d] under/over flow err = %d\n",
+                        rsnd_mod_name(mod), rsnd_mod_id(mod), ssi->err);
 
-       ssi->rdai       = NULL;
        ssi->cr_own     = 0;
        ssi->err        = 0;
 
@@ -353,32 +348,32 @@ static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status)
 }
 
 static int rsnd_ssi_start(struct rsnd_mod *mod,
-                         struct rsnd_dai *rdai)
+                         struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
 
-       rsnd_src_ssiu_start(mod, rdai, rsnd_ssi_use_busif(mod));
+       rsnd_src_ssiu_start(mod, rsnd_ssi_use_busif(mod));
 
-       rsnd_ssi_hw_start(ssi, rdai, io);
+       rsnd_ssi_hw_start(ssi, io);
 
-       rsnd_src_ssi_irq_enable(mod, rdai);
+       rsnd_src_ssi_irq_enable(mod);
 
        return 0;
 }
 
 static int rsnd_ssi_stop(struct rsnd_mod *mod,
-                        struct rsnd_dai *rdai)
+                        struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 
-       rsnd_src_ssi_irq_disable(mod, rdai);
+       rsnd_src_ssi_irq_disable(mod);
 
        rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR));
 
-       rsnd_ssi_hw_stop(ssi, rdai);
+       rsnd_ssi_hw_stop(ssi);
 
-       rsnd_src_ssiu_stop(mod, rdai);
+       rsnd_src_ssiu_stop(mod);
 
        return 0;
 }
@@ -386,16 +381,17 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod,
 static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
 {
        struct rsnd_ssi *ssi = data;
-       struct rsnd_dai *rdai = ssi->rdai;
        struct rsnd_mod *mod = &ssi->mod;
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+       int is_dma = rsnd_ssi_is_dma_mode(mod);
        u32 status = rsnd_mod_read(mod, SSISR);
 
        if (!io)
                return IRQ_NONE;
 
        /* PIO only */
-       if (status & DIRQ) {
+       if (!is_dma && (status & DIRQ)) {
                struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
                u32 *buf = (u32 *)(runtime->dma_area +
                                   rsnd_dai_pointer_offset(io, 0));
@@ -405,7 +401,7 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
                 * directly as 32bit data
                 * see rsnd_ssi_init()
                 */
-               if (rsnd_dai_is_play(rdai, io))
+               if (rsnd_io_is_play(io))
                        rsnd_mod_write(mod, SSITDR, *buf);
                else
                        *buf = rsnd_mod_read(mod, SSIRDR);
@@ -415,14 +411,13 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
 
        /* PIO / DMA */
        if (status & (UIRQ | OIRQ)) {
-               struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
                struct device *dev = rsnd_priv_to_dev(priv);
 
                /*
                 * restart SSI
                 */
-               rsnd_ssi_stop(mod, rdai);
-               rsnd_ssi_start(mod, rdai);
+               rsnd_ssi_stop(mod, priv);
+               rsnd_ssi_start(mod, priv);
 
                dev_dbg(dev, "%s[%d] restart\n",
                        rsnd_mod_name(mod), rsnd_mod_id(mod));
@@ -437,9 +432,8 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
  *             SSI PIO
  */
 static int rsnd_ssi_pio_probe(struct rsnd_mod *mod,
-                             struct rsnd_dai *rdai)
+                             struct rsnd_priv *priv)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        int ret;
@@ -468,9 +462,8 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
 };
 
 static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
-                         struct rsnd_dai *rdai)
+                             struct rsnd_priv *priv)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
        int dma_id = ssi->info->dma_id;
@@ -503,14 +496,13 @@ rsnd_ssi_dma_probe_fail:
 }
 
 static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
-                              struct rsnd_dai *rdai)
+                              struct rsnd_priv *priv)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
        int irq = ssi->info->irq;
 
-       rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod));
+       rsnd_dma_quit(priv, rsnd_mod_to_dma(mod));
 
        /* PIO will request IRQ again */
        devm_free_irq(dev, irq, ssi);
@@ -519,9 +511,8 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
 }
 
 static int rsnd_ssi_fallback(struct rsnd_mod *mod,
-                            struct rsnd_dai *rdai)
+                            struct rsnd_priv *priv)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
 
        /*
@@ -540,25 +531,25 @@ static int rsnd_ssi_fallback(struct rsnd_mod *mod,
 }
 
 static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
-                             struct rsnd_dai *rdai)
+                             struct rsnd_priv *priv)
 {
        struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
 
-       rsnd_ssi_start(mod, rdai);
-
        rsnd_dma_start(dma);
 
+       rsnd_ssi_start(mod, priv);
+
        return 0;
 }
 
 static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
-                            struct rsnd_dai *rdai)
+                            struct rsnd_priv *priv)
 {
        struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
 
-       rsnd_dma_stop(dma);
+       rsnd_ssi_stop(mod, priv);
 
-       rsnd_ssi_stop(mod, rdai);
+       rsnd_dma_stop(dma);
 
        return 0;
 }
@@ -734,7 +725,6 @@ int rsnd_ssi_probe(struct platform_device *pdev,
                        return PTR_ERR(clk);
 
                ssi->info       = pinfo;
-               ssi->clk        = clk;
 
                ops = &rsnd_ssi_non_ops;
                if (pinfo->dma_id > 0)
@@ -742,7 +732,7 @@ int rsnd_ssi_probe(struct platform_device *pdev,
                else if (rsnd_ssi_pio_available(ssi))
                        ops = &rsnd_ssi_pio_ops;
 
-               rsnd_mod_init(priv, &ssi->mod, ops, RSND_MOD_SSI, i);
+               rsnd_mod_init(&ssi->mod, ops, clk, RSND_MOD_SSI, i);
 
                rsnd_ssi_parent_clk_setup(priv, ssi);
        }
index 32eb6da2d2bde2ac994aeda90ef673fbd6d6e426..82902f56e82fec8f8d9758e4b133167dca6e54ee 100644 (file)
@@ -589,7 +589,6 @@ static void siu_pcm_free(struct snd_pcm *pcm)
        tasklet_kill(&port_info->playback.tasklet);
 
        siu_free_port(port_info);
-       snd_pcm_lib_preallocate_free_for_all(pcm);
 
        dev_dbg(pcm->card->dev, "%s\n", __func__);
 }
index 2c62620abca691af4033552518eb7138ea6485d5..30579ca5bacb985c7dfa9b9ad30f58cee45d6e1a 100644 (file)
@@ -191,6 +191,39 @@ static ssize_t pmdown_time_set(struct device *dev,
 
 static DEVICE_ATTR(pmdown_time, 0644, pmdown_time_show, pmdown_time_set);
 
+static struct attribute *soc_dev_attrs[] = {
+       &dev_attr_codec_reg.attr,
+       &dev_attr_pmdown_time.attr,
+       NULL
+};
+
+static umode_t soc_dev_attr_is_visible(struct kobject *kobj,
+                                      struct attribute *attr, int idx)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
+
+       if (attr == &dev_attr_pmdown_time.attr)
+               return attr->mode; /* always visible */
+       return rtd->codec ? attr->mode : 0; /* enabled only with codec */
+}
+
+static const struct attribute_group soc_dapm_dev_group = {
+       .attrs = soc_dapm_dev_attrs,
+       .is_visible = soc_dev_attr_is_visible,
+};
+
+static const struct attribute_group soc_dev_roup = {
+       .attrs = soc_dev_attrs,
+       .is_visible = soc_dev_attr_is_visible,
+};
+
+static const struct attribute_group *soc_dev_attr_groups[] = {
+       &soc_dapm_dev_group,
+       &soc_dev_roup,
+       NULL
+};
+
 #ifdef CONFIG_DEBUG_FS
 static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf,
                                   size_t count, loff_t *ppos)
@@ -949,8 +982,6 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
 
        /* unregister the rtd device */
        if (rtd->dev_registered) {
-               device_remove_file(rtd->dev, &dev_attr_pmdown_time);
-               device_remove_file(rtd->dev, &dev_attr_codec_reg);
                device_unregister(rtd->dev);
                rtd->dev_registered = 0;
        }
@@ -1120,6 +1151,7 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd,
        device_initialize(rtd->dev);
        rtd->dev->parent = rtd->card->dev;
        rtd->dev->release = rtd_release;
+       rtd->dev->groups = soc_dev_attr_groups;
        dev_set_name(rtd->dev, "%s", name);
        dev_set_drvdata(rtd->dev, rtd);
        mutex_init(&rtd->pcm_mutex);
@@ -1136,23 +1168,6 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd,
                return ret;
        }
        rtd->dev_registered = 1;
-
-       if (rtd->codec) {
-               /* add DAPM sysfs entries for this codec */
-               ret = snd_soc_dapm_sys_add(rtd->dev);
-               if (ret < 0)
-                       dev_err(rtd->dev,
-                               "ASoC: failed to add codec dapm sysfs entries: %d\n",
-                               ret);
-
-               /* add codec sysfs entries */
-               ret = device_create_file(rtd->dev, &dev_attr_codec_reg);
-               if (ret < 0)
-                       dev_err(rtd->dev,
-                               "ASoC: failed to add codec sysfs files: %d\n",
-                               ret);
-       }
-
        return 0;
 }
 
@@ -1308,11 +1323,6 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
        }
 #endif
 
-       ret = device_create_file(rtd->dev, &dev_attr_pmdown_time);
-       if (ret < 0)
-               dev_warn(rtd->dev, "ASoC: failed to add pmdown_time sysfs: %d\n",
-                       ret);
-
        if (cpu_dai->driver->compress_dai) {
                /*create compress_device"*/
                ret = soc_new_compress(rtd, num);
@@ -1427,11 +1437,76 @@ static int snd_soc_init_codec_cache(struct snd_soc_codec *codec)
        return 0;
 }
 
+/**
+ * snd_soc_runtime_set_dai_fmt() - Change DAI link format for a ASoC runtime
+ * @rtd: The runtime for which the DAI link format should be changed
+ * @dai_fmt: The new DAI link format
+ *
+ * This function updates the DAI link format for all DAIs connected to the DAI
+ * link for the specified runtime.
+ *
+ * Note: For setups with a static format set the dai_fmt field in the
+ * corresponding snd_dai_link struct instead of using this function.
+ *
+ * Returns 0 on success, otherwise a negative error code.
+ */
+int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
+       unsigned int dai_fmt)
+{
+       struct snd_soc_dai **codec_dais = rtd->codec_dais;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < rtd->num_codecs; i++) {
+               struct snd_soc_dai *codec_dai = codec_dais[i];
+
+               ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
+               if (ret != 0 && ret != -ENOTSUPP) {
+                       dev_warn(codec_dai->dev,
+                                "ASoC: Failed to set DAI format: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       /* Flip the polarity for the "CPU" end of a CODEC<->CODEC link */
+       if (cpu_dai->codec) {
+               unsigned int inv_dai_fmt;
+
+               inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_MASTER_MASK;
+               switch (dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+               case SND_SOC_DAIFMT_CBM_CFM:
+                       inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
+                       break;
+               case SND_SOC_DAIFMT_CBM_CFS:
+                       inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFM;
+                       break;
+               case SND_SOC_DAIFMT_CBS_CFM:
+                       inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFS;
+                       break;
+               case SND_SOC_DAIFMT_CBS_CFS:
+                       inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
+                       break;
+               }
+
+               dai_fmt = inv_dai_fmt;
+       }
+
+       ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
+       if (ret != 0 && ret != -ENOTSUPP) {
+               dev_warn(cpu_dai->dev,
+                        "ASoC: Failed to set DAI format: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt);
+
 static int snd_soc_instantiate_card(struct snd_soc_card *card)
 {
        struct snd_soc_codec *codec;
-       struct snd_soc_dai_link *dai_link;
-       int ret, i, order, dai_fmt;
+       int ret, i, order;
 
        mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
 
@@ -1542,60 +1617,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
                                        card->num_dapm_routes);
 
        for (i = 0; i < card->num_links; i++) {
-               struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
-               dai_link = &card->dai_link[i];
-               dai_fmt = dai_link->dai_fmt;
-
-               if (dai_fmt) {
-                       struct snd_soc_dai **codec_dais = rtd->codec_dais;
-                       int j;
-
-                       for (j = 0; j < rtd->num_codecs; j++) {
-                               struct snd_soc_dai *codec_dai = codec_dais[j];
-
-                               ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
-                               if (ret != 0 && ret != -ENOTSUPP)
-                                       dev_warn(codec_dai->dev,
-                                                "ASoC: Failed to set DAI format: %d\n",
-                                                ret);
-                       }
-               }
-
-               /* If this is a regular CPU link there will be a platform */
-               if (dai_fmt &&
-                   (dai_link->platform_name || dai_link->platform_of_node)) {
-                       ret = snd_soc_dai_set_fmt(card->rtd[i].cpu_dai,
-                                                 dai_fmt);
-                       if (ret != 0 && ret != -ENOTSUPP)
-                               dev_warn(card->rtd[i].cpu_dai->dev,
-                                        "ASoC: Failed to set DAI format: %d\n",
-                                        ret);
-               } else if (dai_fmt) {
-                       /* Flip the polarity for the "CPU" end */
-                       dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
-                       switch (dai_link->dai_fmt &
-                               SND_SOC_DAIFMT_MASTER_MASK) {
-                       case SND_SOC_DAIFMT_CBM_CFM:
-                               dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
-                               break;
-                       case SND_SOC_DAIFMT_CBM_CFS:
-                               dai_fmt |= SND_SOC_DAIFMT_CBS_CFM;
-                               break;
-                       case SND_SOC_DAIFMT_CBS_CFM:
-                               dai_fmt |= SND_SOC_DAIFMT_CBM_CFS;
-                               break;
-                       case SND_SOC_DAIFMT_CBS_CFS:
-                               dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
-                               break;
-                       }
-
-                       ret = snd_soc_dai_set_fmt(card->rtd[i].cpu_dai,
-                                                 dai_fmt);
-                       if (ret != 0 && ret != -ENOTSUPP)
-                               dev_warn(card->rtd[i].cpu_dai->dev,
-                                        "ASoC: Failed to set DAI format: %d\n",
-                                        ret);
-               }
+               if (card->dai_link[i].dai_fmt)
+                       snd_soc_runtime_set_dai_fmt(&card->rtd[i],
+                               card->dai_link[i].dai_fmt);
        }
 
        snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
@@ -1626,9 +1650,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
                }
        }
 
-       if (card->fully_routed)
-               snd_soc_dapm_auto_nc_pins(card);
-
        snd_soc_dapm_new_widgets(card);
 
        ret = snd_card_register(card->snd_card);
@@ -2119,15 +2140,27 @@ static int snd_soc_xlate_tdm_slot_mask(unsigned int slots,
 }
 
 /**
- * snd_soc_dai_set_tdm_slot - configure DAI TDM.
- * @dai: DAI
+ * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation
+ * @dai: The DAI to configure
  * @tx_mask: bitmask representing active TX slots.
  * @rx_mask: bitmask representing active RX slots.
  * @slots: Number of slots in use.
  * @slot_width: Width in bits for each slot.
  *
- * Configures a DAI for TDM operation. Both mask and slots are codec and DAI
- * specific.
+ * This function configures the specified DAI for TDM operation. @slot contains
+ * the total number of slots of the TDM stream and @slot_with the width of each
+ * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the
+ * active slots of the TDM stream for the specified DAI, i.e. which slots the
+ * DAI should write to or read from. If a bit is set the corresponding slot is
+ * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to
+ * the first slot, bit 1 to the second slot and so on. The first active slot
+ * maps to the first channel of the DAI, the second active slot to the second
+ * channel and so on.
+ *
+ * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask,
+ * @rx_mask and @slot_width will be ignored.
+ *
+ * Returns 0 on success, a negative error code otherwise.
  */
 int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
        unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
@@ -2386,8 +2419,8 @@ int snd_soc_unregister_card(struct snd_soc_card *card)
                card->instantiated = false;
                snd_soc_dapm_shutdown(card);
                soc_cleanup_card_resources(card);
+               dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name);
        }
-       dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name);
 
        return 0;
 }
index c5136bb1f9821afe43bae8a2f9bece210e699952..b6f88202b8c99a41c3e941bb8a8a2603e45985a8 100644 (file)
@@ -517,8 +517,8 @@ static int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm,
 {
        if (!dapm->component)
                return -EIO;
-       return snd_soc_component_update_bits_async(dapm->component, reg,
-               mask, value);
+       return snd_soc_component_update_bits(dapm->component, reg,
+                                            mask, value);
 }
 
 static int soc_dapm_test_bits(struct snd_soc_dapm_context *dapm,
@@ -2127,15 +2127,10 @@ static ssize_t dapm_widget_show(struct device *dev,
 
 static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
 
-int snd_soc_dapm_sys_add(struct device *dev)
-{
-       return device_create_file(dev, &dev_attr_dapm_widget);
-}
-
-static void snd_soc_dapm_sys_remove(struct device *dev)
-{
-       device_remove_file(dev, &dev_attr_dapm_widget);
-}
+struct attribute *soc_dapm_dev_attrs[] = {
+       &dev_attr_dapm_widget.attr,
+       NULL
+};
 
 static void dapm_free_path(struct snd_soc_dapm_path *path)
 {
@@ -2279,6 +2274,9 @@ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
 
        switch (w->id) {
        case snd_soc_dapm_input:
+               /* On a fully routed card a input is never a source */
+               if (w->dapm->card->fully_routed)
+                       break;
                w->is_source = 1;
                list_for_each_entry(p, &w->sources, list_sink) {
                        if (p->source->id == snd_soc_dapm_micbias ||
@@ -2291,6 +2289,9 @@ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
                }
                break;
        case snd_soc_dapm_output:
+               /* On a fully routed card a output is never a sink */
+               if (w->dapm->card->fully_routed)
+                       break;
                w->is_sink = 1;
                list_for_each_entry(p, &w->sinks, list_source) {
                        if (p->sink->id == snd_soc_dapm_spk ||
@@ -3085,16 +3086,24 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
 
        switch (w->id) {
        case snd_soc_dapm_mic:
-       case snd_soc_dapm_input:
                w->is_source = 1;
                w->power_check = dapm_generic_check_power;
                break;
+       case snd_soc_dapm_input:
+               if (!dapm->card->fully_routed)
+                       w->is_source = 1;
+               w->power_check = dapm_generic_check_power;
+               break;
        case snd_soc_dapm_spk:
        case snd_soc_dapm_hp:
-       case snd_soc_dapm_output:
                w->is_sink = 1;
                w->power_check = dapm_generic_check_power;
                break;
+       case snd_soc_dapm_output:
+               if (!dapm->card->fully_routed)
+                       w->is_sink = 1;
+               w->power_check = dapm_generic_check_power;
+               break;
        case snd_soc_dapm_vmid:
        case snd_soc_dapm_siggen:
                w->is_source = 1;
@@ -3130,8 +3139,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
        }
 
        w->dapm = dapm;
-       if (dapm->component)
-               w->codec = dapm->component->codec;
        INIT_LIST_HEAD(&w->sources);
        INIT_LIST_HEAD(&w->sinks);
        INIT_LIST_HEAD(&w->list);
@@ -3808,93 +3815,6 @@ int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
 
-/**
- * dapm_is_external_path() - Checks if a path is a external path
- * @card: The card the path belongs to
- * @path: The path to check
- *
- * Returns true if the path is either between two different DAPM contexts or
- * between two external pins of the same DAPM context. Otherwise returns
- * false.
- */
-static bool dapm_is_external_path(struct snd_soc_card *card,
-       struct snd_soc_dapm_path *path)
-{
-       dev_dbg(card->dev,
-               "... Path %s(id:%d dapm:%p) - %s(id:%d dapm:%p)\n",
-               path->source->name, path->source->id, path->source->dapm,
-               path->sink->name, path->sink->id, path->sink->dapm);
-
-       /* Connection between two different DAPM contexts */
-       if (path->source->dapm != path->sink->dapm)
-               return true;
-
-       /* Loopback connection from external pin to external pin */
-       if (path->sink->id == snd_soc_dapm_input) {
-               switch (path->source->id) {
-               case snd_soc_dapm_output:
-               case snd_soc_dapm_micbias:
-                       return true;
-               default:
-                       break;
-               }
-       }
-
-       return false;
-}
-
-static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card,
-                                             struct snd_soc_dapm_widget *w)
-{
-       struct snd_soc_dapm_path *p;
-
-       list_for_each_entry(p, &w->sources, list_sink) {
-               if (dapm_is_external_path(card, p))
-                       return true;
-       }
-
-       list_for_each_entry(p, &w->sinks, list_source) {
-               if (dapm_is_external_path(card, p))
-                       return true;
-       }
-
-       return false;
-}
-
-/**
- * snd_soc_dapm_auto_nc_pins - call snd_soc_dapm_nc_pin for unused pins
- * @card: The card whose pins should be processed
- *
- * Automatically call snd_soc_dapm_nc_pin() for any external pins in the card
- * which are unused. Pins are used if they are connected externally to a
- * component, whether that be to some other device, or a loop-back connection to
- * the component itself.
- */
-void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card)
-{
-       struct snd_soc_dapm_widget *w;
-
-       dev_dbg(card->dev, "ASoC: Auto NC: DAPMs: card:%p\n", &card->dapm);
-
-       list_for_each_entry(w, &card->widgets, list) {
-               switch (w->id) {
-               case snd_soc_dapm_input:
-               case snd_soc_dapm_output:
-               case snd_soc_dapm_micbias:
-                       dev_dbg(card->dev, "ASoC: Auto NC: Checking widget %s\n",
-                               w->name);
-                       if (!snd_soc_dapm_widget_in_card_paths(card, w)) {
-                               dev_dbg(card->dev,
-                                       "... Not in map; disabling\n");
-                               snd_soc_dapm_nc_pin(w->dapm, w->name);
-                       }
-                       break;
-               default:
-                       break;
-               }
-       }
-}
-
 /**
  * snd_soc_dapm_free - free dapm resources
  * @dapm: DAPM context
@@ -3903,7 +3823,6 @@ void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card)
  */
 void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
 {
-       snd_soc_dapm_sys_remove(dapm->dev);
        dapm_debugfs_cleanup(dapm);
        dapm_free_widgets(dapm);
        list_del(&dapm->list);
index 057e5ef7dcce6730bdc99bc8e5719ebe458669d0..a57921eeee81a772bd02da6acea391c3f74f7c7a 100644 (file)
@@ -60,7 +60,7 @@ static void devm_platform_release(struct device *dev, void *res)
 /**
  * devm_snd_soc_register_platform - resource managed platform registration
  * @dev: Device used to manage platform
- * @platform: platform to register
+ * @platform_drv: platform to register
  *
  * Register a platform driver with automatic unregistration when the device is
  * unregistered.
index b329b84bc5af77d50e1fd2803252d259cabf7602..4864392bfcba7c0189a37b04f495ec20c2022f9d 100644 (file)
@@ -200,11 +200,6 @@ static int dmaengine_pcm_open(struct snd_pcm_substream *substream)
        return snd_dmaengine_pcm_open(substream, chan);
 }
 
-static void dmaengine_pcm_free(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static struct dma_chan *dmaengine_pcm_compat_request_channel(
        struct snd_soc_pcm_runtime *rtd,
        struct snd_pcm_substream *substream)
@@ -283,8 +278,7 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
                if (!pcm->chan[i]) {
                        dev_err(rtd->platform->dev,
                                "Missing dma channel for stream: %d\n", i);
-                       ret = -EINVAL;
-                       goto err_free;
+                       return -EINVAL;
                }
 
                ret = snd_pcm_lib_preallocate_pages(substream,
@@ -293,7 +287,7 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
                                prealloc_buffer_size,
                                max_buffer_size);
                if (ret)
-                       goto err_free;
+                       return ret;
 
                /*
                 * This will only return false if we know for sure that at least
@@ -307,10 +301,6 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
        }
 
        return 0;
-
-err_free:
-       dmaengine_pcm_free(rtd->pcm);
-       return ret;
 }
 
 static snd_pcm_uframes_t dmaengine_pcm_pointer(
@@ -341,7 +331,6 @@ static const struct snd_soc_platform_driver dmaengine_pcm_platform = {
        },
        .ops            = &dmaengine_pcm_ops,
        .pcm_new        = dmaengine_pcm_new,
-       .pcm_free       = dmaengine_pcm_free,
 };
 
 static const char * const dmaengine_pcm_dma_channel_names[] = {
index eb87d96e2cf0a8807e34a9859918a5c672d17981..6b0136e7cb88c2cebd96b12a6a85dc200f9838d3 100644 (file)
@@ -301,34 +301,18 @@ static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
        return symmetry;
 }
 
-/*
- * List of sample sizes that might go over the bus for parameter
- * application.  There ought to be a wildcard sample size for things
- * like the DAC/ADC resolution to use but there isn't right now.
- */
-static int sample_sizes[] = {
-       24, 32,
-};
-
 static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       int ret, i;
+       int ret;
 
        if (!bits)
                return;
 
-       for (i = 0; i < ARRAY_SIZE(sample_sizes); i++) {
-               if (bits >= sample_sizes[i])
-                       continue;
-
-               ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0,
-                                                  sample_sizes[i], bits);
-               if (ret != 0)
-                       dev_warn(rtd->dev,
-                                "ASoC: Failed to set MSB %d/%d: %d\n",
-                                bits, sample_sizes[i], ret);
-       }
+       ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, bits);
+       if (ret != 0)
+               dev_warn(rtd->dev, "ASoC: Failed to set MSB %d: %d\n",
+                                bits, ret);
 }
 
 static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
@@ -746,7 +730,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
                                                              codec_dai);
                        if (ret < 0) {
                                dev_err(codec_dai->dev,
-                                       "ASoC: DAI prepare error: %d\n", ret);
+                                       "ASoC: codec DAI prepare error: %d\n",
+                                       ret);
                                goto out;
                        }
                }
@@ -755,8 +740,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
        if (cpu_dai->driver->ops && cpu_dai->driver->ops->prepare) {
                ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);
                if (ret < 0) {
-                       dev_err(cpu_dai->dev, "ASoC: DAI prepare error: %d\n",
-                               ret);
+                       dev_err(cpu_dai->dev,
+                               "ASoC: cpu DAI prepare error: %d\n", ret);
                        goto out;
                }
        }
index 31198cf7f88d93829c2ccb7c7c5118583250f0b0..a6768f832c6fe87e4679e0df7f47e51e81e3b8a4 100644 (file)
@@ -128,3 +128,13 @@ config SND_SOC_TEGRA_MAX98090
        help
          Say Y or M here if you want to add support for SoC audio on Tegra
          boards using the MAX98090 codec, such as Venice2.
+
+config SND_SOC_TEGRA_RT5677
+       tristate "SoC Audio support for Tegra boards using a RT5677 codec"
+       depends on SND_SOC_TEGRA && I2C && GPIOLIB
+       select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
+       select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
+       select SND_SOC_RT5677
+       help
+         Say Y or M here if you want to add support for SoC audio on Tegra
+         boards using the RT5677 codec, such as Ryu.
index 5ae588cd96c4c39ff8060f98a6f1248f9e4855d9..9171655ad843213c1eea2028cf8fccd74d73887e 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
 
 # Tegra machine Support
 snd-soc-tegra-rt5640-objs := tegra_rt5640.o
+snd-soc-tegra-rt5677-objs := tegra_rt5677.o
 snd-soc-tegra-wm8753-objs := tegra_wm8753.o
 snd-soc-tegra-wm8903-objs := tegra_wm8903.o
 snd-soc-tegra-wm9712-objs := tegra_wm9712.o
@@ -27,6 +28,7 @@ snd-soc-tegra-alc5632-objs := tegra_alc5632.o
 snd-soc-tegra-max98090-objs := tegra_max98090.o
 
 obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o
+obj-$(CONFIG_SND_SOC_TEGRA_RT5677) += snd-soc-tegra-rt5677.o
 obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o
 obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o
 obj-$(CONFIG_SND_SOC_TEGRA_WM9712) += snd-soc-tegra-wm9712.o
diff --git a/sound/soc/tegra/tegra_rt5677.c b/sound/soc/tegra/tegra_rt5677.c
new file mode 100644 (file)
index 0000000..e4cf978
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+* tegra_rt5677.c - Tegra machine ASoC driver for boards using RT5677 codec.
+ *
+ * Copyright (c) 2014, The Chromium OS Authors.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (C) 2010-2012 - NVIDIA, Inc.
+ * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
+ * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../codecs/rt5677.h"
+
+#include "tegra_asoc_utils.h"
+
+#define DRV_NAME "tegra-snd-rt5677"
+
+struct tegra_rt5677 {
+       struct tegra_asoc_utils_data util_data;
+       int gpio_hp_det;
+       int gpio_hp_en;
+       int gpio_mic_present;
+       int gpio_dmic_clk_en;
+};
+
+static int tegra_rt5677_asoc_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_card *card = rtd->card;
+       struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card);
+       int srate, mclk, err;
+
+       srate = params_rate(params);
+       mclk = 256 * srate;
+
+       err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
+       if (err < 0) {
+               dev_err(card->dev, "Can't configure clocks\n");
+               return err;
+       }
+
+       err = snd_soc_dai_set_sysclk(codec_dai, RT5677_SCLK_S_MCLK, mclk,
+                                       SND_SOC_CLOCK_IN);
+       if (err < 0) {
+               dev_err(card->dev, "codec_dai clock not set\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static int tegra_rt5677_event_hp(struct snd_soc_dapm_widget *w,
+                       struct snd_kcontrol *k, int event)
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct snd_soc_card *card = dapm->card;
+       struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card);
+
+       if (!gpio_is_valid(machine->gpio_hp_en))
+               return 0;
+
+       gpio_set_value_cansleep(machine->gpio_hp_en,
+               SND_SOC_DAPM_EVENT_ON(event));
+
+       return 0;
+}
+
+static struct snd_soc_ops tegra_rt5677_ops = {
+       .hw_params = tegra_rt5677_asoc_hw_params,
+};
+
+static struct snd_soc_jack tegra_rt5677_hp_jack;
+
+static struct snd_soc_jack_pin tegra_rt5677_hp_jack_pins = {
+       .pin = "Headphone",
+       .mask = SND_JACK_HEADPHONE,
+};
+static struct snd_soc_jack_gpio tegra_rt5677_hp_jack_gpio = {
+       .name = "Headphone detection",
+       .report = SND_JACK_HEADPHONE,
+       .debounce_time = 150,
+};
+
+static struct snd_soc_jack tegra_rt5677_mic_jack;
+
+static struct snd_soc_jack_pin tegra_rt5677_mic_jack_pins = {
+       .pin = "Headset Mic",
+       .mask = SND_JACK_MICROPHONE,
+};
+
+static struct snd_soc_jack_gpio tegra_rt5677_mic_jack_gpio = {
+       .name = "Headset Mic detection",
+       .report = SND_JACK_MICROPHONE,
+       .debounce_time = 150,
+       .invert = 1
+};
+
+static const struct snd_soc_dapm_widget tegra_rt5677_dapm_widgets[] = {
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+       SND_SOC_DAPM_HP("Headphone", tegra_rt5677_event_hp),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Internal Mic 1", NULL),
+       SND_SOC_DAPM_MIC("Internal Mic 2", NULL),
+};
+
+static const struct snd_kcontrol_new tegra_rt5677_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Speaker"),
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Internal Mic 1"),
+       SOC_DAPM_PIN_SWITCH("Internal Mic 2"),
+};
+
+static int tegra_rt5677_asoc_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(rtd->card);
+
+       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
+                       &tegra_rt5677_hp_jack);
+       snd_soc_jack_add_pins(&tegra_rt5677_hp_jack, 1,
+                       &tegra_rt5677_hp_jack_pins);
+
+       if (gpio_is_valid(machine->gpio_hp_det)) {
+               tegra_rt5677_hp_jack_gpio.gpio = machine->gpio_hp_det;
+               snd_soc_jack_add_gpios(&tegra_rt5677_hp_jack, 1,
+                               &tegra_rt5677_hp_jack_gpio);
+       }
+
+
+       snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
+                       &tegra_rt5677_mic_jack);
+       snd_soc_jack_add_pins(&tegra_rt5677_mic_jack, 1,
+                       &tegra_rt5677_mic_jack_pins);
+
+       if (gpio_is_valid(machine->gpio_mic_present)) {
+               tegra_rt5677_mic_jack_gpio.gpio = machine->gpio_mic_present;
+               snd_soc_jack_add_gpios(&tegra_rt5677_mic_jack, 1,
+                               &tegra_rt5677_mic_jack_gpio);
+       }
+
+       snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
+
+       return 0;
+}
+
+static int tegra_rt5677_card_remove(struct snd_soc_card *card)
+{
+       struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card);
+
+       if (gpio_is_valid(machine->gpio_hp_det)) {
+               snd_soc_jack_free_gpios(&tegra_rt5677_hp_jack, 1,
+                               &tegra_rt5677_hp_jack_gpio);
+       }
+
+       if (gpio_is_valid(machine->gpio_mic_present)) {
+               snd_soc_jack_free_gpios(&tegra_rt5677_mic_jack, 1,
+                               &tegra_rt5677_mic_jack_gpio);
+       }
+
+       return 0;
+}
+
+static struct snd_soc_dai_link tegra_rt5677_dai = {
+       .name = "RT5677",
+       .stream_name = "RT5677 PCM",
+       .codec_dai_name = "rt5677-aif1",
+       .init = tegra_rt5677_asoc_init,
+       .ops = &tegra_rt5677_ops,
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS,
+};
+
+static struct snd_soc_card snd_soc_tegra_rt5677 = {
+       .name = "tegra-rt5677",
+       .owner = THIS_MODULE,
+       .remove = tegra_rt5677_card_remove,
+       .dai_link = &tegra_rt5677_dai,
+       .num_links = 1,
+       .controls = tegra_rt5677_controls,
+       .num_controls = ARRAY_SIZE(tegra_rt5677_controls),
+       .dapm_widgets = tegra_rt5677_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(tegra_rt5677_dapm_widgets),
+       .fully_routed = true,
+};
+
+static int tegra_rt5677_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct snd_soc_card *card = &snd_soc_tegra_rt5677;
+       struct tegra_rt5677 *machine;
+       int ret;
+
+       machine = devm_kzalloc(&pdev->dev,
+                       sizeof(struct tegra_rt5677), GFP_KERNEL);
+       if (!machine)
+               return -ENOMEM;
+
+       card->dev = &pdev->dev;
+       platform_set_drvdata(pdev, card);
+       snd_soc_card_set_drvdata(card, machine);
+
+       machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
+       if (machine->gpio_hp_det == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+
+       machine->gpio_mic_present = of_get_named_gpio(np,
+                       "nvidia,mic-present-gpios", 0);
+       if (machine->gpio_mic_present == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+
+       machine->gpio_hp_en = of_get_named_gpio(np, "nvidia,hp-en-gpios", 0);
+       if (machine->gpio_hp_en == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       if (gpio_is_valid(machine->gpio_hp_en)) {
+               ret = devm_gpio_request_one(&pdev->dev, machine->gpio_hp_en,
+                               GPIOF_OUT_INIT_LOW, "hp_en");
+               if (ret) {
+                       dev_err(card->dev, "cannot get hp_en gpio\n");
+                       return ret;
+               }
+       }
+
+       machine->gpio_dmic_clk_en = of_get_named_gpio(np,
+               "nvidia,dmic-clk-en-gpios", 0);
+       if (machine->gpio_dmic_clk_en == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       if (gpio_is_valid(machine->gpio_dmic_clk_en)) {
+               ret = devm_gpio_request_one(&pdev->dev,
+                               machine->gpio_dmic_clk_en,
+                               GPIOF_OUT_INIT_HIGH, "dmic_clk_en");
+               if (ret) {
+                       dev_err(card->dev, "cannot get dmic_clk_en gpio\n");
+                       return ret;
+               }
+       }
+
+       ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+       if (ret)
+               goto err;
+
+       ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
+       if (ret)
+               goto err;
+
+       tegra_rt5677_dai.codec_of_node = of_parse_phandle(np,
+                       "nvidia,audio-codec", 0);
+       if (!tegra_rt5677_dai.codec_of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'nvidia,audio-codec' missing or invalid\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       tegra_rt5677_dai.cpu_of_node = of_parse_phandle(np,
+                       "nvidia,i2s-controller", 0);
+       if (!tegra_rt5677_dai.cpu_of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'nvidia,i2s-controller' missing or invalid\n");
+               ret = -EINVAL;
+               goto err;
+       }
+       tegra_rt5677_dai.platform_of_node = tegra_rt5677_dai.cpu_of_node;
+
+       ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+       if (ret)
+               goto err;
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+                       ret);
+               goto err_fini_utils;
+       }
+
+       return 0;
+
+err_fini_utils:
+       tegra_asoc_utils_fini(&machine->util_data);
+err:
+       return ret;
+}
+
+static int tegra_rt5677_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card);
+
+       snd_soc_unregister_card(card);
+
+       tegra_asoc_utils_fini(&machine->util_data);
+
+       return 0;
+}
+
+static const struct of_device_id tegra_rt5677_of_match[] = {
+       { .compatible = "nvidia,tegra-audio-rt5677", },
+       {},
+};
+
+static struct platform_driver tegra_rt5677_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+               .of_match_table = tegra_rt5677_of_match,
+       },
+       .probe = tegra_rt5677_probe,
+       .remove = tegra_rt5677_remove,
+};
+module_platform_driver(tegra_rt5677_driver);
+
+MODULE_AUTHOR("Anatol Pomozov <anatol@google.com>");
+MODULE_DESCRIPTION("Tegra+RT5677 machine ASoC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra_rt5677_of_match);
index 070e44e251ceef9ea128edf8c39ab08c780b2ed3..88eacfd83da6780b3d2419ab2173fa3d7e255916 100644 (file)
@@ -282,11 +282,6 @@ static struct snd_pcm_ops txx9aclc_pcm_ops = {
        .pointer        = txx9aclc_pcm_pointer,
 };
 
-static void txx9aclc_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static int txx9aclc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
@@ -412,7 +407,6 @@ static struct snd_soc_platform_driver txx9aclc_soc_platform = {
        .remove         = txx9aclc_pcm_remove,
        .ops            = &txx9aclc_pcm_ops,
        .pcm_new        = txx9aclc_pcm_new,
-       .pcm_free       = txx9aclc_pcm_free_dma_buffers,
 };
 
 static int txx9aclc_soc_platform_probe(struct platform_device *pdev)
index be4f1ac7cd5ec74afe25f4b1126751790183afef..aa65370db82aa52fb480871eb06bd5dfed667d3b 100644 (file)
@@ -290,21 +290,9 @@ static int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
                        SND_SOC_DAIFMT_GATED;
        }
 
-       ret = snd_soc_dai_set_fmt(codec_dai, fmt);
-       if (ret < 0) {
-               dev_err(dev,
-                       "%s: ERROR: snd_soc_dai_set_fmt failed for codec_dai (ret = %d)!\n",
-                       __func__, ret);
-               return ret;
-       }
-
-       ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
-       if (ret < 0) {
-               dev_err(dev,
-                       "%s: ERROR: snd_soc_dai_set_fmt failed for cpu_dai (ret = %d)!\n",
-                       __func__, ret);
+       ret = snd_soc_runtime_set_dai_fmt(rtd, fmt);
+       if (ret)
                return ret;
-       }
 
        /* Setup TDM-slots */
 
diff --git a/sound/soc/xtensa/Kconfig b/sound/soc/xtensa/Kconfig
new file mode 100644 (file)
index 0000000..c201beb
--- /dev/null
@@ -0,0 +1,7 @@
+config SND_SOC_XTFPGA_I2S
+       tristate "XTFPGA I2S master"
+       select REGMAP_MMIO
+       help
+         Say Y or M if you want to add support for codecs attached to the
+         I2S interface on XTFPGA daughter board. You will also need to select
+         the drivers for the rest of XTFPGA audio subsystem.
diff --git a/sound/soc/xtensa/Makefile b/sound/soc/xtensa/Makefile
new file mode 100644 (file)
index 0000000..15efbf9
--- /dev/null
@@ -0,0 +1,3 @@
+snd-soc-xtfpga-i2s-objs := xtfpga-i2s.o
+
+obj-$(CONFIG_SND_SOC_XTFPGA_I2S) += snd-soc-xtfpga-i2s.o
diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c
new file mode 100644 (file)
index 0000000..1cfb19e
--- /dev/null
@@ -0,0 +1,675 @@
+/*
+ * Xtfpga I2S controller driver
+ *
+ * Copyright (c) 2014 Cadence Design Systems Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define DRV_NAME       "xtfpga-i2s"
+
+#define XTFPGA_I2S_VERSION     0x00
+#define XTFPGA_I2S_CONFIG      0x04
+#define XTFPGA_I2S_INT_MASK    0x08
+#define XTFPGA_I2S_INT_STATUS  0x0c
+#define XTFPGA_I2S_CHAN0_DATA  0x10
+#define XTFPGA_I2S_CHAN1_DATA  0x14
+#define XTFPGA_I2S_CHAN2_DATA  0x18
+#define XTFPGA_I2S_CHAN3_DATA  0x1c
+
+#define XTFPGA_I2S_CONFIG_TX_ENABLE    0x1
+#define XTFPGA_I2S_CONFIG_INT_ENABLE   0x2
+#define XTFPGA_I2S_CONFIG_LEFT         0x4
+#define XTFPGA_I2S_CONFIG_RATIO_BASE   8
+#define XTFPGA_I2S_CONFIG_RATIO_MASK   0x0000ff00
+#define XTFPGA_I2S_CONFIG_RES_BASE     16
+#define XTFPGA_I2S_CONFIG_RES_MASK     0x003f0000
+#define XTFPGA_I2S_CONFIG_LEVEL_BASE   24
+#define XTFPGA_I2S_CONFIG_LEVEL_MASK   0x0f000000
+#define XTFPGA_I2S_CONFIG_CHANNEL_BASE 28
+
+#define XTFPGA_I2S_INT_UNDERRUN                0x1
+#define XTFPGA_I2S_INT_LEVEL           0x2
+#define XTFPGA_I2S_INT_VALID           0x3
+
+#define XTFPGA_I2S_FIFO_SIZE           8192
+
+/*
+ * I2S controller operation:
+ *
+ * Enabling TX: output 1 period of zeros (starting with left channel)
+ * and then queued data.
+ *
+ * Level status and interrupt: whenever FIFO level is below FIFO trigger,
+ * level status is 1 and an IRQ is asserted (if enabled).
+ *
+ * Underrun status and interrupt: whenever FIFO is empty, underrun status
+ * is 1 and an IRQ is asserted (if enabled).
+ */
+struct xtfpga_i2s {
+       struct device *dev;
+       struct clk *clk;
+       struct regmap *regmap;
+       void __iomem *regs;
+
+       /* current playback substream. NULL if not playing.
+        *
+        * Access to that field is synchronized between the interrupt handler
+        * and userspace through RCU.
+        *
+        * Interrupt handler (threaded part) does PIO on substream data in RCU
+        * read-side critical section. Trigger callback sets and clears the
+        * pointer when the playback is started and stopped with
+        * rcu_assign_pointer. When userspace is about to free the playback
+        * stream in the pcm_close callback it synchronizes with the interrupt
+        * handler by means of synchronize_rcu call.
+        */
+       struct snd_pcm_substream *tx_substream;
+       unsigned (*tx_fn)(struct xtfpga_i2s *i2s,
+                         struct snd_pcm_runtime *runtime,
+                         unsigned tx_ptr);
+       unsigned tx_ptr; /* next frame index in the sample buffer */
+
+       /* current fifo level estimate.
+        * Doesn't have to be perfectly accurate, but must be not less than
+        * the actual FIFO level in order to avoid stall on push attempt.
+        */
+       unsigned tx_fifo_level;
+
+       /* FIFO level at which level interrupt occurs */
+       unsigned tx_fifo_low;
+
+       /* maximal FIFO level */
+       unsigned tx_fifo_high;
+};
+
+static bool xtfpga_i2s_wr_reg(struct device *dev, unsigned int reg)
+{
+       return reg >= XTFPGA_I2S_CONFIG;
+}
+
+static bool xtfpga_i2s_rd_reg(struct device *dev, unsigned int reg)
+{
+       return reg < XTFPGA_I2S_CHAN0_DATA;
+}
+
+static bool xtfpga_i2s_volatile_reg(struct device *dev, unsigned int reg)
+{
+       return reg == XTFPGA_I2S_INT_STATUS;
+}
+
+static const struct regmap_config xtfpga_i2s_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .max_register = XTFPGA_I2S_CHAN3_DATA,
+       .writeable_reg = xtfpga_i2s_wr_reg,
+       .readable_reg = xtfpga_i2s_rd_reg,
+       .volatile_reg = xtfpga_i2s_volatile_reg,
+       .cache_type = REGCACHE_FLAT,
+};
+
+/* Generate functions that do PIO from TX DMA area to FIFO for all supported
+ * stream formats.
+ * Functions will be called xtfpga_pcm_tx_<channels>x<sample bits>, e.g.
+ * xtfpga_pcm_tx_2x16 for 16-bit stereo.
+ *
+ * FIFO consists of 32-bit words, one word per channel, always 2 channels.
+ * If I2S interface is configured with smaller sample resolution, only
+ * the LSB of each word is used.
+ */
+#define xtfpga_pcm_tx_fn(channels, sample_bits) \
+static unsigned xtfpga_pcm_tx_##channels##x##sample_bits( \
+       struct xtfpga_i2s *i2s, struct snd_pcm_runtime *runtime, \
+       unsigned tx_ptr) \
+{ \
+       const u##sample_bits (*p)[channels] = \
+               (void *)runtime->dma_area; \
+\
+       for (; i2s->tx_fifo_level < i2s->tx_fifo_high; \
+            i2s->tx_fifo_level += 2) { \
+               iowrite32(p[tx_ptr][0], \
+                         i2s->regs + XTFPGA_I2S_CHAN0_DATA); \
+               iowrite32(p[tx_ptr][channels - 1], \
+                         i2s->regs + XTFPGA_I2S_CHAN0_DATA); \
+               if (++tx_ptr >= runtime->buffer_size) \
+                       tx_ptr = 0; \
+       } \
+       return tx_ptr; \
+}
+
+xtfpga_pcm_tx_fn(1, 16)
+xtfpga_pcm_tx_fn(2, 16)
+xtfpga_pcm_tx_fn(1, 32)
+xtfpga_pcm_tx_fn(2, 32)
+
+#undef xtfpga_pcm_tx_fn
+
+static bool xtfpga_pcm_push_tx(struct xtfpga_i2s *i2s)
+{
+       struct snd_pcm_substream *tx_substream;
+       bool tx_active;
+
+       rcu_read_lock();
+       tx_substream = rcu_dereference(i2s->tx_substream);
+       tx_active = tx_substream && snd_pcm_running(tx_substream);
+       if (tx_active) {
+               unsigned tx_ptr = ACCESS_ONCE(i2s->tx_ptr);
+               unsigned new_tx_ptr = i2s->tx_fn(i2s, tx_substream->runtime,
+                                                tx_ptr);
+
+               cmpxchg(&i2s->tx_ptr, tx_ptr, new_tx_ptr);
+       }
+       rcu_read_unlock();
+
+       return tx_active;
+}
+
+static void xtfpga_pcm_refill_fifo(struct xtfpga_i2s *i2s)
+{
+       unsigned int_status;
+       unsigned i;
+
+       regmap_read(i2s->regmap, XTFPGA_I2S_INT_STATUS,
+                   &int_status);
+
+       for (i = 0; i < 2; ++i) {
+               bool tx_active = xtfpga_pcm_push_tx(i2s);
+
+               regmap_write(i2s->regmap, XTFPGA_I2S_INT_STATUS,
+                            XTFPGA_I2S_INT_VALID);
+               if (tx_active)
+                       regmap_read(i2s->regmap, XTFPGA_I2S_INT_STATUS,
+                                   &int_status);
+
+               if (!tx_active ||
+                   !(int_status & XTFPGA_I2S_INT_LEVEL))
+                       break;
+
+               /* After the push the level IRQ is still asserted,
+                * means FIFO level is below tx_fifo_low. Estimate
+                * it as tx_fifo_low.
+                */
+               i2s->tx_fifo_level = i2s->tx_fifo_low;
+       }
+
+       if (!(int_status & XTFPGA_I2S_INT_LEVEL))
+               regmap_write(i2s->regmap, XTFPGA_I2S_INT_MASK,
+                            XTFPGA_I2S_INT_VALID);
+       else if (!(int_status & XTFPGA_I2S_INT_UNDERRUN))
+               regmap_write(i2s->regmap, XTFPGA_I2S_INT_MASK,
+                            XTFPGA_I2S_INT_UNDERRUN);
+
+       if (!(int_status & XTFPGA_I2S_INT_UNDERRUN))
+               regmap_update_bits(i2s->regmap, XTFPGA_I2S_CONFIG,
+                                  XTFPGA_I2S_CONFIG_INT_ENABLE |
+                                  XTFPGA_I2S_CONFIG_TX_ENABLE,
+                                  XTFPGA_I2S_CONFIG_INT_ENABLE |
+                                  XTFPGA_I2S_CONFIG_TX_ENABLE);
+       else
+               regmap_update_bits(i2s->regmap, XTFPGA_I2S_CONFIG,
+                                  XTFPGA_I2S_CONFIG_INT_ENABLE |
+                                  XTFPGA_I2S_CONFIG_TX_ENABLE, 0);
+}
+
+static irqreturn_t xtfpga_i2s_threaded_irq_handler(int irq, void *dev_id)
+{
+       struct xtfpga_i2s *i2s = dev_id;
+       struct snd_pcm_substream *tx_substream;
+       unsigned config, int_status, int_mask;
+
+       regmap_read(i2s->regmap, XTFPGA_I2S_CONFIG, &config);
+       regmap_read(i2s->regmap, XTFPGA_I2S_INT_MASK, &int_mask);
+       regmap_read(i2s->regmap, XTFPGA_I2S_INT_STATUS, &int_status);
+
+       if (!(config & XTFPGA_I2S_CONFIG_INT_ENABLE) ||
+           !(int_status & int_mask & XTFPGA_I2S_INT_VALID))
+               return IRQ_NONE;
+
+       /* Update FIFO level estimate in accordance with interrupt status
+        * register.
+        */
+       if (int_status & XTFPGA_I2S_INT_UNDERRUN) {
+               i2s->tx_fifo_level = 0;
+               regmap_update_bits(i2s->regmap, XTFPGA_I2S_CONFIG,
+                                  XTFPGA_I2S_CONFIG_TX_ENABLE, 0);
+       } else {
+               /* The FIFO isn't empty, but is below tx_fifo_low. Estimate
+                * it as tx_fifo_low.
+                */
+               i2s->tx_fifo_level = i2s->tx_fifo_low;
+       }
+
+       rcu_read_lock();
+       tx_substream = rcu_dereference(i2s->tx_substream);
+
+       if (tx_substream && snd_pcm_running(tx_substream)) {
+               snd_pcm_period_elapsed(tx_substream);
+               if (int_status & XTFPGA_I2S_INT_UNDERRUN)
+                       dev_dbg_ratelimited(i2s->dev, "%s: underrun\n",
+                                           __func__);
+       }
+       rcu_read_unlock();
+
+       /* Refill FIFO, update allowed IRQ reasons, enable IRQ if FIFO is
+        * not empty.
+        */
+       xtfpga_pcm_refill_fifo(i2s);
+
+       return IRQ_HANDLED;
+}
+
+static int xtfpga_i2s_startup(struct snd_pcm_substream *substream,
+                             struct snd_soc_dai *dai)
+{
+       struct xtfpga_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+       snd_soc_dai_set_dma_data(dai, substream, i2s);
+       return 0;
+}
+
+static int xtfpga_i2s_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       struct xtfpga_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+       unsigned srate = params_rate(params);
+       unsigned channels = params_channels(params);
+       unsigned period_size = params_period_size(params);
+       unsigned sample_size = snd_pcm_format_width(params_format(params));
+       unsigned freq, ratio, level;
+       int err;
+
+       regmap_update_bits(i2s->regmap, XTFPGA_I2S_CONFIG,
+                          XTFPGA_I2S_CONFIG_RES_MASK,
+                          sample_size << XTFPGA_I2S_CONFIG_RES_BASE);
+
+       freq = 256 * srate;
+       err = clk_set_rate(i2s->clk, freq);
+       if (err < 0)
+               return err;
+
+       /* ratio field of the config register controls MCLK->I2S clock
+        * derivation: I2S clock = MCLK / (2 * (ratio + 2)).
+        *
+        * So with MCLK = 256 * sample rate ratio is 0 for 32 bit stereo
+        * and 2 for 16 bit stereo.
+        */
+       ratio = (freq - (srate * sample_size * 8)) /
+               (srate * sample_size * 4);
+
+       regmap_update_bits(i2s->regmap, XTFPGA_I2S_CONFIG,
+                          XTFPGA_I2S_CONFIG_RATIO_MASK,
+                          ratio << XTFPGA_I2S_CONFIG_RATIO_BASE);
+
+       i2s->tx_fifo_low = XTFPGA_I2S_FIFO_SIZE / 2;
+
+       /* period_size * 2: FIFO always gets 2 samples per frame */
+       for (level = 1;
+            i2s->tx_fifo_low / 2 >= period_size * 2 &&
+            level < (XTFPGA_I2S_CONFIG_LEVEL_MASK >>
+                     XTFPGA_I2S_CONFIG_LEVEL_BASE); ++level)
+               i2s->tx_fifo_low /= 2;
+
+       i2s->tx_fifo_high = 2 * i2s->tx_fifo_low;
+
+       regmap_update_bits(i2s->regmap, XTFPGA_I2S_CONFIG,
+                          XTFPGA_I2S_CONFIG_LEVEL_MASK,
+                          level << XTFPGA_I2S_CONFIG_LEVEL_BASE);
+
+       dev_dbg(i2s->dev,
+               "%s srate: %u, channels: %u, sample_size: %u, period_size: %u\n",
+               __func__, srate, channels, sample_size, period_size);
+       dev_dbg(i2s->dev, "%s freq: %u, ratio: %u, level: %u\n",
+               __func__, freq, ratio, level);
+
+       return 0;
+}
+
+static int xtfpga_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
+                             unsigned int fmt)
+{
+       if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF)
+               return -EINVAL;
+       if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
+               return -EINVAL;
+       if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S)
+               return -EINVAL;
+
+       return 0;
+}
+
+/* PCM */
+
+static const struct snd_pcm_hardware xtfpga_pcm_hardware = {
+       .info = SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER,
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE |
+                                 SNDRV_PCM_FMTBIT_S32_LE,
+       .channels_min           = 1,
+       .channels_max           = 2,
+       .period_bytes_min       = 2,
+       .period_bytes_max       = XTFPGA_I2S_FIFO_SIZE / 2 * 8,
+       .periods_min            = 2,
+       .periods_max            = XTFPGA_I2S_FIFO_SIZE * 8 / 2,
+       .buffer_bytes_max       = XTFPGA_I2S_FIFO_SIZE * 8,
+       .fifo_size              = 16,
+};
+
+static int xtfpga_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       void *p;
+
+       snd_soc_set_runtime_hwparams(substream, &xtfpga_pcm_hardware);
+       p = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+       runtime->private_data = p;
+
+       return 0;
+}
+
+static int xtfpga_pcm_close(struct snd_pcm_substream *substream)
+{
+       synchronize_rcu();
+       return 0;
+}
+
+static int xtfpga_pcm_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *hw_params)
+{
+       int ret;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct xtfpga_i2s *i2s = runtime->private_data;
+       unsigned channels = params_channels(hw_params);
+
+       switch (channels) {
+       case 1:
+       case 2:
+               break;
+
+       default:
+               return -EINVAL;
+
+       }
+
+       switch (params_format(hw_params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               i2s->tx_fn = (channels == 1) ?
+                       xtfpga_pcm_tx_1x16 :
+                       xtfpga_pcm_tx_2x16;
+               break;
+
+       case SNDRV_PCM_FORMAT_S32_LE:
+               i2s->tx_fn = (channels == 1) ?
+                       xtfpga_pcm_tx_1x32 :
+                       xtfpga_pcm_tx_2x32;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       ret = snd_pcm_lib_malloc_pages(substream,
+                                      params_buffer_bytes(hw_params));
+       return ret;
+}
+
+static int xtfpga_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       int ret = 0;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct xtfpga_i2s *i2s = runtime->private_data;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               ACCESS_ONCE(i2s->tx_ptr) = 0;
+               rcu_assign_pointer(i2s->tx_substream, substream);
+               xtfpga_pcm_refill_fifo(i2s);
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               rcu_assign_pointer(i2s->tx_substream, NULL);
+               break;
+
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+static snd_pcm_uframes_t xtfpga_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct xtfpga_i2s *i2s = runtime->private_data;
+       snd_pcm_uframes_t pos = ACCESS_ONCE(i2s->tx_ptr);
+
+       return pos < runtime->buffer_size ? pos : 0;
+}
+
+static int xtfpga_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_card *card = rtd->card->snd_card;
+       size_t size = xtfpga_pcm_hardware.buffer_bytes_max;
+
+       return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
+                                                    SNDRV_DMA_TYPE_DEV,
+                                                    card->dev, size, size);
+}
+
+static void xtfpga_pcm_free(struct snd_pcm *pcm)
+{
+       snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static const struct snd_pcm_ops xtfpga_pcm_ops = {
+       .open           = xtfpga_pcm_open,
+       .close          = xtfpga_pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = xtfpga_pcm_hw_params,
+       .trigger        = xtfpga_pcm_trigger,
+       .pointer        = xtfpga_pcm_pointer,
+};
+
+static const struct snd_soc_platform_driver xtfpga_soc_platform = {
+       .pcm_new        = xtfpga_pcm_new,
+       .pcm_free       = xtfpga_pcm_free,
+       .ops            = &xtfpga_pcm_ops,
+};
+
+static const struct snd_soc_component_driver xtfpga_i2s_component = {
+       .name           = DRV_NAME,
+};
+
+static const struct snd_soc_dai_ops xtfpga_i2s_dai_ops = {
+       .startup        = xtfpga_i2s_startup,
+       .hw_params      = xtfpga_i2s_hw_params,
+       .set_fmt        = xtfpga_i2s_set_fmt,
+};
+
+static struct snd_soc_dai_driver xtfpga_i2s_dai[] = {
+       {
+               .name = "xtfpga-i2s",
+               .id = 0,
+               .playback = {
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_8000_96000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                                  SNDRV_PCM_FMTBIT_S32_LE,
+               },
+               .ops = &xtfpga_i2s_dai_ops,
+       },
+};
+
+static int xtfpga_i2s_runtime_suspend(struct device *dev)
+{
+       struct xtfpga_i2s *i2s = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(i2s->clk);
+       return 0;
+}
+
+static int xtfpga_i2s_runtime_resume(struct device *dev)
+{
+       struct xtfpga_i2s *i2s = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(i2s->clk);
+       if (ret) {
+               dev_err(dev, "clk_prepare_enable failed: %d\n", ret);
+               return ret;
+       }
+       return 0;
+}
+
+static int xtfpga_i2s_probe(struct platform_device *pdev)
+{
+       struct xtfpga_i2s *i2s;
+       struct resource *mem;
+       int err, irq;
+
+       i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
+       if (!i2s) {
+               err = -ENOMEM;
+               goto err;
+       }
+       platform_set_drvdata(pdev, i2s);
+       i2s->dev = &pdev->dev;
+       dev_dbg(&pdev->dev, "dev: %p, i2s: %p\n", &pdev->dev, i2s);
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       i2s->regs = devm_ioremap_resource(&pdev->dev, mem);
+       if (IS_ERR(i2s->regs)) {
+               err = PTR_ERR(i2s->regs);
+               goto err;
+       }
+
+       i2s->regmap = devm_regmap_init_mmio(&pdev->dev, i2s->regs,
+                                           &xtfpga_i2s_regmap_config);
+       if (IS_ERR(i2s->regmap)) {
+               dev_err(&pdev->dev, "regmap init failed\n");
+               err = PTR_ERR(i2s->regmap);
+               goto err;
+       }
+
+       i2s->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(i2s->clk)) {
+               dev_err(&pdev->dev, "couldn't get clock\n");
+               err = PTR_ERR(i2s->clk);
+               goto err;
+       }
+
+       regmap_write(i2s->regmap, XTFPGA_I2S_CONFIG,
+                    (0x1 << XTFPGA_I2S_CONFIG_CHANNEL_BASE));
+       regmap_write(i2s->regmap, XTFPGA_I2S_INT_STATUS, XTFPGA_I2S_INT_VALID);
+       regmap_write(i2s->regmap, XTFPGA_I2S_INT_MASK, XTFPGA_I2S_INT_UNDERRUN);
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "No IRQ resource\n");
+               err = irq;
+               goto err;
+       }
+       err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+                                       xtfpga_i2s_threaded_irq_handler,
+                                       IRQF_SHARED | IRQF_ONESHOT,
+                                       pdev->name, i2s);
+       if (err < 0) {
+               dev_err(&pdev->dev, "request_irq failed\n");
+               goto err;
+       }
+
+       err = snd_soc_register_platform(&pdev->dev, &xtfpga_soc_platform);
+       if (err < 0) {
+               dev_err(&pdev->dev, "couldn't register platform\n");
+               goto err;
+       }
+       err = devm_snd_soc_register_component(&pdev->dev,
+                                             &xtfpga_i2s_component,
+                                             xtfpga_i2s_dai,
+                                             ARRAY_SIZE(xtfpga_i2s_dai));
+       if (err < 0) {
+               dev_err(&pdev->dev, "couldn't register component\n");
+               goto err_unregister_platform;
+       }
+
+       pm_runtime_enable(&pdev->dev);
+       if (!pm_runtime_enabled(&pdev->dev)) {
+               err = xtfpga_i2s_runtime_resume(&pdev->dev);
+               if (err)
+                       goto err_pm_disable;
+       }
+       return 0;
+
+err_pm_disable:
+       pm_runtime_disable(&pdev->dev);
+err_unregister_platform:
+       snd_soc_unregister_platform(&pdev->dev);
+err:
+       dev_err(&pdev->dev, "%s: err = %d\n", __func__, err);
+       return err;
+}
+
+static int xtfpga_i2s_remove(struct platform_device *pdev)
+{
+       struct xtfpga_i2s *i2s = dev_get_drvdata(&pdev->dev);
+
+       snd_soc_unregister_platform(&pdev->dev);
+       if (i2s->regmap && !IS_ERR(i2s->regmap)) {
+               regmap_write(i2s->regmap, XTFPGA_I2S_CONFIG, 0);
+               regmap_write(i2s->regmap, XTFPGA_I2S_INT_MASK, 0);
+               regmap_write(i2s->regmap, XTFPGA_I2S_INT_STATUS,
+                            XTFPGA_I2S_INT_VALID);
+       }
+       pm_runtime_disable(&pdev->dev);
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               xtfpga_i2s_runtime_suspend(&pdev->dev);
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id xtfpga_i2s_of_match[] = {
+       { .compatible = "cdns,xtfpga-i2s", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, xtfpga_i2s_of_match);
+#endif
+
+static const struct dev_pm_ops xtfpga_i2s_pm_ops = {
+       SET_RUNTIME_PM_OPS(xtfpga_i2s_runtime_suspend,
+                          xtfpga_i2s_runtime_resume, NULL)
+};
+
+static struct platform_driver xtfpga_i2s_driver = {
+       .probe   = xtfpga_i2s_probe,
+       .remove  = xtfpga_i2s_remove,
+       .driver  = {
+               .name = "xtfpga-i2s",
+               .of_match_table = of_match_ptr(xtfpga_i2s_of_match),
+               .pm = &xtfpga_i2s_pm_ops,
+       },
+};
+
+module_platform_driver(xtfpga_i2s_driver);
+
+MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>");
+MODULE_DESCRIPTION("xtfpga I2S controller driver");
+MODULE_LICENSE("GPL v2");
index 86280d63b76d66e3ed336f61484c7bc7a570abf9..1b1a89e80d1394bb253aecc3cadc683dbcff3a36 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/moduleparam.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/io.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -44,7 +45,6 @@
 #include <sound/control.h>
 #include <sound/initval.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/prom.h>
 
index 93522072bc87c9c69cf1ea8a4031bf5d60c4386e..49195325fdf6c6f7fe74ac50e3e4c3466c4ff60d 100644 (file)
@@ -53,9 +53,7 @@ int snd_emux_new(struct snd_emux **remu)
        emu->max_voices = 0;
        emu->use_time = 0;
 
-       init_timer(&emu->tlist);
-       emu->tlist.function = snd_emux_timer_callback;
-       emu->tlist.data = (unsigned long)emu;
+       setup_timer(&emu->tlist, snd_emux_timer_callback, (unsigned long)emu);
        emu->timer_active = 0;
 
        *remu = emu;
@@ -160,12 +158,8 @@ int snd_emux_free(struct snd_emux *emu)
        snd_emux_detach_seq_oss(emu);
 #endif
        snd_emux_detach_seq(emu);
-
        snd_emux_delete_hwdep(emu);
-
-       if (emu->sflist)
-               snd_sf_free(emu->sflist);
-
+       snd_sf_free(emu->sflist);
        kfree(emu->voices);
        kfree(emu->name);
        kfree(emu);
index 5ae1eae9f6dbc2491c5b6bb378ca81cc896e22dc..e557946718a9ed7006c17901060b927b43e0f31c 100644 (file)
@@ -21,7 +21,7 @@
 
 #include <sound/core.h>
 #include <sound/hwdep.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include "emux_voice.h"
 
 
index 319754cf62086ef86723a9df60c236d31edfab16..ab37add269aecd6ae00909776d954735e587f9a2 100644 (file)
@@ -26,7 +26,7 @@
 #ifdef CONFIG_SND_SEQUENCER_OSS
 
 #include <linux/export.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <sound/core.h>
 #include "emux_voice.h"
 #include <sound/asoundef.h>
index 9a38de459acb059db4d12b3ca1c9955adeebed60..599551b5af44cae35477cb010ae380d53009229c 100644 (file)
@@ -186,8 +186,7 @@ snd_emux_note_off(void *p, int note, int vel, struct snd_midi_channel *chan)
                                 */
                                vp->state = SNDRV_EMUX_ST_PENDING;
                                if (! emu->timer_active) {
-                                       emu->tlist.expires = jiffies + 1;
-                                       add_timer(&emu->tlist);
+                                       mod_timer(&emu->tlist, jiffies + 1);
                                        emu->timer_active = 1;
                                }
                        } else
@@ -223,8 +222,7 @@ void snd_emux_timer_callback(unsigned long data)
                }
        }
        if (do_again) {
-               emu->tlist.expires = jiffies + 1;
-               add_timer(&emu->tlist);
+               mod_timer(&emu->tlist, jiffies + 1);
                emu->timer_active = 1;
        } else
                emu->timer_active = 0;
index 78683b2064f709a55bf0dff1b2edba002158d114..31a4ea94830e04358932037ca0a5bd6854624348 100644 (file)
@@ -25,7 +25,7 @@
  * of doing things so that the old sfxload utility can be used.
  * Everything may change when there is an alsa way of doing things.
  */
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <linux/slab.h>
 #include <linux/export.h>
 #include <sound/core.h>
index d393153c474f2d763be5cdad6e39f4a1798d2463..a452ad7cec4016f603142e722b5d2535959c4581 100644 (file)
@@ -160,5 +160,7 @@ config SND_BCD2000
          To compile this driver as a module, choose M here: the module
          will be called snd-bcd2000.
 
+source "sound/usb/line6/Kconfig"
+
 endif  # SND_USB
 
index bcee4060fd1815f2c7cdb526807be3ba2d21178e..2d2d122b069f37974b7353d781023cf99cbe11ef 100644 (file)
@@ -25,3 +25,4 @@ obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o
 obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o
 
 obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/
+obj-$(CONFIG_SND_USB_LINE6)    += line6/
index 97acb906acc27041cebb340abaa9d69c36c34634..ef580b43f1e3b1e71dcc4ed0f6a16f11928e071e 100644 (file)
@@ -153,6 +153,8 @@ struct snd_usb_substream {
                int channel;
                int byte_idx;
        } dsd_dop;
+
+       bool trigger_tstamp_pending_update; /* trigger timestamp being updated from initial estimate */
 };
 
 struct snd_usb_stream {
diff --git a/sound/usb/line6/Kconfig b/sound/usb/line6/Kconfig
new file mode 100644 (file)
index 0000000..f4585d3
--- /dev/null
@@ -0,0 +1,42 @@
+config SND_USB_LINE6
+       tristate
+       select SND_RAWMIDI
+       select SND_PCM
+
+config SND_USB_POD
+       tristate "Line 6 POD USB support"
+       select SND_USB_LINE6
+       help
+         This is a driver for PODxt and other similar devices,
+         supporting the following features:
+           * Reading/writing individual parameters
+           * Reading/writing complete channel, effects setup, and amp
+             setup data
+           * Channel switching
+           * Virtual MIDI interface
+           * Tuner access
+           * Playback/capture/mixer device for any ALSA-compatible PCM
+             audio application
+           * Signal routing (record clean/processed guitar signal,
+             re-amping)
+
+config SND_USB_PODHD
+       tristate "Line 6 POD HD300/400/500 USB support"
+       select SND_USB_LINE6
+       help
+         This is a driver for POD HD300, 400 and 500 devices.
+
+config SND_USB_TONEPORT
+       tristate "TonePort GX, UX1 and UX2 USB support"
+       select SND_USB_LINE6
+       select NEW_LEDS
+       select LEDS_CLASS
+       help
+         This is a driver for TonePort GX, UX1 and UX2 devices.
+
+config SND_USB_VARIAX
+       tristate "Variax Workbench USB support"
+       select SND_USB_LINE6
+       help
+         This is a driver for Variax Workbench device.
+
diff --git a/sound/usb/line6/Makefile b/sound/usb/line6/Makefile
new file mode 100644 (file)
index 0000000..b8b3b2a
--- /dev/null
@@ -0,0 +1,18 @@
+snd-usb-line6-y :=             \
+               capture.o       \
+               driver.o        \
+               midi.o          \
+               midibuf.o       \
+               pcm.o           \
+               playback.o
+
+snd-usb-pod-y := pod.o
+snd-usb-podhd-y := podhd.o
+snd-usb-toneport-y := toneport.o
+snd-usb-variax-y := variax.o
+
+obj-$(CONFIG_SND_USB_LINE6)    += snd-usb-line6.o
+obj-$(CONFIG_SND_USB_POD)      += snd-usb-pod.o
+obj-$(CONFIG_SND_USB_PODHD)    += snd-usb-podhd.o
+obj-$(CONFIG_SND_USB_TONEPORT) += snd-usb-toneport.o
+obj-$(CONFIG_SND_USB_VARIAX)   += snd-usb-variax.o
diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c
new file mode 100644 (file)
index 0000000..f518fbb
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ *     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, version 2.
+ *
+ */
+
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "capture.h"
+#include "driver.h"
+#include "pcm.h"
+
+/*
+       Find a free URB and submit it.
+       must be called in line6pcm->in.lock context
+*/
+static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)
+{
+       int index;
+       int i, urb_size;
+       int ret;
+       struct urb *urb_in;
+
+       index =
+           find_first_zero_bit(&line6pcm->in.active_urbs, LINE6_ISO_BUFFERS);
+
+       if (index < 0 || index >= LINE6_ISO_BUFFERS) {
+               dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
+               return -EINVAL;
+       }
+
+       urb_in = line6pcm->in.urbs[index];
+       urb_size = 0;
+
+       for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
+               struct usb_iso_packet_descriptor *fin =
+                   &urb_in->iso_frame_desc[i];
+               fin->offset = urb_size;
+               fin->length = line6pcm->max_packet_size;
+               urb_size += line6pcm->max_packet_size;
+       }
+
+       urb_in->transfer_buffer =
+           line6pcm->in.buffer +
+           index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
+       urb_in->transfer_buffer_length = urb_size;
+       urb_in->context = line6pcm;
+
+       ret = usb_submit_urb(urb_in, GFP_ATOMIC);
+
+       if (ret == 0)
+               set_bit(index, &line6pcm->in.active_urbs);
+       else
+               dev_err(line6pcm->line6->ifcdev,
+                       "URB in #%d submission failed (%d)\n", index, ret);
+
+       return 0;
+}
+
+/*
+       Submit all currently available capture URBs.
+       must be called in line6pcm->in.lock context
+*/
+int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm)
+{
+       int ret = 0, i;
+
+       for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
+               ret = submit_audio_in_urb(line6pcm);
+               if (ret < 0)
+                       break;
+       }
+
+       return ret;
+}
+
+/*
+       Copy data into ALSA capture buffer.
+*/
+void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize)
+{
+       struct snd_pcm_substream *substream =
+           get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
+       int frames = fsize / bytes_per_frame;
+
+       if (runtime == NULL)
+               return;
+
+       if (line6pcm->in.pos_done + frames > runtime->buffer_size) {
+               /*
+                  The transferred area goes over buffer boundary,
+                  copy two separate chunks.
+                */
+               int len;
+
+               len = runtime->buffer_size - line6pcm->in.pos_done;
+
+               if (len > 0) {
+                       memcpy(runtime->dma_area +
+                              line6pcm->in.pos_done * bytes_per_frame, fbuf,
+                              len * bytes_per_frame);
+                       memcpy(runtime->dma_area, fbuf + len * bytes_per_frame,
+                              (frames - len) * bytes_per_frame);
+               } else {
+                       /* this is somewhat paranoid */
+                       dev_err(line6pcm->line6->ifcdev,
+                               "driver bug: len = %d\n", len);
+               }
+       } else {
+               /* copy single chunk */
+               memcpy(runtime->dma_area +
+                      line6pcm->in.pos_done * bytes_per_frame, fbuf, fsize);
+       }
+
+       line6pcm->in.pos_done += frames;
+       if (line6pcm->in.pos_done >= runtime->buffer_size)
+               line6pcm->in.pos_done -= runtime->buffer_size;
+}
+
+void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length)
+{
+       struct snd_pcm_substream *substream =
+           get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
+
+       line6pcm->in.bytes += length;
+       if (line6pcm->in.bytes >= line6pcm->in.period) {
+               line6pcm->in.bytes %= line6pcm->in.period;
+               spin_unlock(&line6pcm->in.lock);
+               snd_pcm_period_elapsed(substream);
+               spin_lock(&line6pcm->in.lock);
+       }
+}
+
+/*
+ * Callback for completed capture URB.
+ */
+static void audio_in_callback(struct urb *urb)
+{
+       int i, index, length = 0, shutdown = 0;
+       unsigned long flags;
+
+       struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;
+
+       line6pcm->in.last_frame = urb->start_frame;
+
+       /* find index of URB */
+       for (index = 0; index < LINE6_ISO_BUFFERS; ++index)
+               if (urb == line6pcm->in.urbs[index])
+                       break;
+
+       spin_lock_irqsave(&line6pcm->in.lock, flags);
+
+       for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
+               char *fbuf;
+               int fsize;
+               struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i];
+
+               if (fin->status == -EXDEV) {
+                       shutdown = 1;
+                       break;
+               }
+
+               fbuf = urb->transfer_buffer + fin->offset;
+               fsize = fin->actual_length;
+
+               if (fsize > line6pcm->max_packet_size) {
+                       dev_err(line6pcm->line6->ifcdev,
+                               "driver and/or device bug: packet too large (%d > %d)\n",
+                               fsize, line6pcm->max_packet_size);
+               }
+
+               length += fsize;
+
+               /* the following assumes LINE6_ISO_PACKETS == 1: */
+               line6pcm->prev_fbuf = fbuf;
+               line6pcm->prev_fsize = fsize;
+
+               if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) &&
+                   test_bit(LINE6_STREAM_PCM, &line6pcm->in.running) &&
+                   fsize > 0)
+                       line6_capture_copy(line6pcm, fbuf, fsize);
+       }
+
+       clear_bit(index, &line6pcm->in.active_urbs);
+
+       if (test_and_clear_bit(index, &line6pcm->in.unlink_urbs))
+               shutdown = 1;
+
+       if (!shutdown) {
+               submit_audio_in_urb(line6pcm);
+
+               if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) &&
+                   test_bit(LINE6_STREAM_PCM, &line6pcm->in.running))
+                       line6_capture_check_period(line6pcm, length);
+       }
+
+       spin_unlock_irqrestore(&line6pcm->in.lock, flags);
+}
+
+/* open capture callback */
+static int snd_line6_capture_open(struct snd_pcm_substream *substream)
+{
+       int err;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+
+       err = snd_pcm_hw_constraint_ratdens(runtime, 0,
+                                           SNDRV_PCM_HW_PARAM_RATE,
+                                           &line6pcm->properties->rates);
+       if (err < 0)
+               return err;
+
+       runtime->hw = line6pcm->properties->capture_hw;
+       return 0;
+}
+
+/* close capture callback */
+static int snd_line6_capture_close(struct snd_pcm_substream *substream)
+{
+       return 0;
+}
+
+/* capture operators */
+struct snd_pcm_ops snd_line6_capture_ops = {
+       .open = snd_line6_capture_open,
+       .close = snd_line6_capture_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = snd_line6_hw_params,
+       .hw_free = snd_line6_hw_free,
+       .prepare = snd_line6_prepare,
+       .trigger = snd_line6_trigger,
+       .pointer = snd_line6_pointer,
+};
+
+int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
+{
+       struct usb_line6 *line6 = line6pcm->line6;
+       int i;
+
+       /* create audio URBs and fill in constant values: */
+       for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
+               struct urb *urb;
+
+               /* URB for audio in: */
+               urb = line6pcm->in.urbs[i] =
+                   usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
+
+               if (urb == NULL)
+                       return -ENOMEM;
+
+               urb->dev = line6->usbdev;
+               urb->pipe =
+                   usb_rcvisocpipe(line6->usbdev,
+                                   line6->properties->ep_audio_r &
+                                   USB_ENDPOINT_NUMBER_MASK);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->start_frame = -1;
+               urb->number_of_packets = LINE6_ISO_PACKETS;
+               urb->interval = LINE6_ISO_INTERVAL;
+               urb->error_count = 0;
+               urb->complete = audio_in_callback;
+       }
+
+       return 0;
+}
diff --git a/sound/usb/line6/capture.h b/sound/usb/line6/capture.h
new file mode 100644 (file)
index 0000000..890b21b
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ *     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, version 2.
+ *
+ */
+
+#ifndef CAPTURE_H
+#define CAPTURE_H
+
+#include <sound/pcm.h>
+
+#include "driver.h"
+#include "pcm.h"
+
+extern struct snd_pcm_ops snd_line6_capture_ops;
+
+extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf,
+                              int fsize);
+extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm,
+                                      int length);
+extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm);
+extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm);
+
+#endif
diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c
new file mode 100644 (file)
index 0000000..99b63a7
--- /dev/null
@@ -0,0 +1,666 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ *     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, version 2.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+
+#include "capture.h"
+#include "driver.h"
+#include "midi.h"
+#include "playback.h"
+
+#define DRIVER_AUTHOR  "Markus Grabner <grabner@icg.tugraz.at>"
+#define DRIVER_DESC    "Line 6 USB Driver"
+
+/*
+       This is Line 6's MIDI manufacturer ID.
+*/
+const unsigned char line6_midi_id[] = {
+       0x00, 0x01, 0x0c
+};
+EXPORT_SYMBOL_GPL(line6_midi_id);
+
+/*
+       Code to request version of POD, Variax interface
+       (and maybe other devices).
+*/
+static const char line6_request_version[] = {
+       0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7
+};
+
+/*
+        Class for asynchronous messages.
+*/
+struct message {
+       struct usb_line6 *line6;
+       const char *buffer;
+       int size;
+       int done;
+};
+
+/*
+       Forward declarations.
+*/
+static void line6_data_received(struct urb *urb);
+static int line6_send_raw_message_async_part(struct message *msg,
+                                            struct urb *urb);
+
+/*
+       Start to listen on endpoint.
+*/
+static int line6_start_listen(struct usb_line6 *line6)
+{
+       int err;
+
+       usb_fill_int_urb(line6->urb_listen, line6->usbdev,
+               usb_rcvintpipe(line6->usbdev, line6->properties->ep_ctrl_r),
+               line6->buffer_listen, LINE6_BUFSIZE_LISTEN,
+               line6_data_received, line6, line6->interval);
+       line6->urb_listen->actual_length = 0;
+       err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC);
+       return err;
+}
+
+/*
+       Stop listening on endpoint.
+*/
+static void line6_stop_listen(struct usb_line6 *line6)
+{
+       usb_kill_urb(line6->urb_listen);
+}
+
+/*
+       Send raw message in pieces of wMaxPacketSize bytes.
+*/
+static int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
+                                 int size)
+{
+       int i, done = 0;
+
+       for (i = 0; i < size; i += line6->max_packet_size) {
+               int partial;
+               const char *frag_buf = buffer + i;
+               int frag_size = min(line6->max_packet_size, size - i);
+               int retval;
+
+               retval = usb_interrupt_msg(line6->usbdev,
+                                       usb_sndintpipe(line6->usbdev,
+                                               line6->properties->ep_ctrl_w),
+                                       (char *)frag_buf, frag_size,
+                                       &partial, LINE6_TIMEOUT * HZ);
+
+               if (retval) {
+                       dev_err(line6->ifcdev,
+                               "usb_interrupt_msg failed (%d)\n", retval);
+                       break;
+               }
+
+               done += frag_size;
+       }
+
+       return done;
+}
+
+/*
+       Notification of completion of asynchronous request transmission.
+*/
+static void line6_async_request_sent(struct urb *urb)
+{
+       struct message *msg = (struct message *)urb->context;
+
+       if (msg->done >= msg->size) {
+               usb_free_urb(urb);
+               kfree(msg);
+       } else
+               line6_send_raw_message_async_part(msg, urb);
+}
+
+/*
+       Asynchronously send part of a raw message.
+*/
+static int line6_send_raw_message_async_part(struct message *msg,
+                                            struct urb *urb)
+{
+       int retval;
+       struct usb_line6 *line6 = msg->line6;
+       int done = msg->done;
+       int bytes = min(msg->size - done, line6->max_packet_size);
+
+       usb_fill_int_urb(urb, line6->usbdev,
+               usb_sndintpipe(line6->usbdev, line6->properties->ep_ctrl_w),
+               (char *)msg->buffer + done, bytes,
+               line6_async_request_sent, msg, line6->interval);
+
+       msg->done += bytes;
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+
+       if (retval < 0) {
+               dev_err(line6->ifcdev, "%s: usb_submit_urb failed (%d)\n",
+                       __func__, retval);
+               usb_free_urb(urb);
+               kfree(msg);
+               return retval;
+       }
+
+       return 0;
+}
+
+/*
+       Setup and start timer.
+*/
+void line6_start_timer(struct timer_list *timer, unsigned long msecs,
+                      void (*function)(unsigned long), unsigned long data)
+{
+       setup_timer(timer, function, data);
+       mod_timer(timer, jiffies + msecs_to_jiffies(msecs));
+}
+EXPORT_SYMBOL_GPL(line6_start_timer);
+
+/*
+       Asynchronously send raw message.
+*/
+int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer,
+                                int size)
+{
+       struct message *msg;
+       struct urb *urb;
+
+       /* create message: */
+       msg = kmalloc(sizeof(struct message), GFP_ATOMIC);
+       if (msg == NULL)
+               return -ENOMEM;
+
+       /* create URB: */
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
+
+       if (urb == NULL) {
+               kfree(msg);
+               return -ENOMEM;
+       }
+
+       /* set message data: */
+       msg->line6 = line6;
+       msg->buffer = buffer;
+       msg->size = size;
+       msg->done = 0;
+
+       /* start sending: */
+       return line6_send_raw_message_async_part(msg, urb);
+}
+EXPORT_SYMBOL_GPL(line6_send_raw_message_async);
+
+/*
+       Send asynchronous device version request.
+*/
+int line6_version_request_async(struct usb_line6 *line6)
+{
+       char *buffer;
+       int retval;
+
+       buffer = kmemdup(line6_request_version,
+                       sizeof(line6_request_version), GFP_ATOMIC);
+       if (buffer == NULL)
+               return -ENOMEM;
+
+       retval = line6_send_raw_message_async(line6, buffer,
+                                             sizeof(line6_request_version));
+       kfree(buffer);
+       return retval;
+}
+EXPORT_SYMBOL_GPL(line6_version_request_async);
+
+/*
+       Send sysex message in pieces of wMaxPacketSize bytes.
+*/
+int line6_send_sysex_message(struct usb_line6 *line6, const char *buffer,
+                            int size)
+{
+       return line6_send_raw_message(line6, buffer,
+                                     size + SYSEX_EXTRA_SIZE) -
+           SYSEX_EXTRA_SIZE;
+}
+EXPORT_SYMBOL_GPL(line6_send_sysex_message);
+
+/*
+       Allocate buffer for sysex message and prepare header.
+       @param code sysex message code
+       @param size number of bytes between code and sysex end
+*/
+char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2,
+                              int size)
+{
+       char *buffer = kmalloc(size + SYSEX_EXTRA_SIZE, GFP_ATOMIC);
+
+       if (!buffer)
+               return NULL;
+
+       buffer[0] = LINE6_SYSEX_BEGIN;
+       memcpy(buffer + 1, line6_midi_id, sizeof(line6_midi_id));
+       buffer[sizeof(line6_midi_id) + 1] = code1;
+       buffer[sizeof(line6_midi_id) + 2] = code2;
+       buffer[sizeof(line6_midi_id) + 3 + size] = LINE6_SYSEX_END;
+       return buffer;
+}
+EXPORT_SYMBOL_GPL(line6_alloc_sysex_buffer);
+
+/*
+       Notification of data received from the Line 6 device.
+*/
+static void line6_data_received(struct urb *urb)
+{
+       struct usb_line6 *line6 = (struct usb_line6 *)urb->context;
+       struct midi_buffer *mb = &line6->line6midi->midibuf_in;
+       int done;
+
+       if (urb->status == -ESHUTDOWN)
+               return;
+
+       done =
+           line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length);
+
+       if (done < urb->actual_length) {
+               line6_midibuf_ignore(mb, done);
+               dev_dbg(line6->ifcdev, "%d %d buffer overflow - message skipped\n",
+                       done, urb->actual_length);
+       }
+
+       for (;;) {
+               done =
+                   line6_midibuf_read(mb, line6->buffer_message,
+                                      LINE6_MESSAGE_MAXLEN);
+
+               if (done == 0)
+                       break;
+
+               line6->message_length = done;
+               line6_midi_receive(line6, line6->buffer_message, done);
+
+               if (line6->process_message)
+                       line6->process_message(line6);
+       }
+
+       line6_start_listen(line6);
+}
+
+#define LINE6_READ_WRITE_STATUS_DELAY 2  /* milliseconds */
+#define LINE6_READ_WRITE_MAX_RETRIES 50
+
+/*
+       Read data from device.
+*/
+int line6_read_data(struct usb_line6 *line6, int address, void *data,
+                   size_t datalen)
+{
+       struct usb_device *usbdev = line6->usbdev;
+       int ret;
+       unsigned char len;
+       unsigned count;
+
+       /* query the serial number: */
+       ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
+                             USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+                             (datalen << 8) | 0x21, address,
+                             NULL, 0, LINE6_TIMEOUT * HZ);
+
+       if (ret < 0) {
+               dev_err(line6->ifcdev, "read request failed (error %d)\n", ret);
+               return ret;
+       }
+
+       /* Wait for data length. We'll get 0xff until length arrives. */
+       for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) {
+               mdelay(LINE6_READ_WRITE_STATUS_DELAY);
+
+               ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67,
+                                     USB_TYPE_VENDOR | USB_RECIP_DEVICE |
+                                     USB_DIR_IN,
+                                     0x0012, 0x0000, &len, 1,
+                                     LINE6_TIMEOUT * HZ);
+               if (ret < 0) {
+                       dev_err(line6->ifcdev,
+                               "receive length failed (error %d)\n", ret);
+                       return ret;
+               }
+
+               if (len != 0xff)
+                       break;
+       }
+
+       if (len == 0xff) {
+               dev_err(line6->ifcdev, "read failed after %d retries\n",
+                       count);
+               return -EIO;
+       } else if (len != datalen) {
+               /* should be equal or something went wrong */
+               dev_err(line6->ifcdev,
+                       "length mismatch (expected %d, got %d)\n",
+                       (int)datalen, (int)len);
+               return -EIO;
+       }
+
+       /* receive the result: */
+       ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67,
+                             USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                             0x0013, 0x0000, data, datalen,
+                             LINE6_TIMEOUT * HZ);
+
+       if (ret < 0) {
+               dev_err(line6->ifcdev, "read failed (error %d)\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(line6_read_data);
+
+/*
+       Write data to device.
+*/
+int line6_write_data(struct usb_line6 *line6, int address, void *data,
+                    size_t datalen)
+{
+       struct usb_device *usbdev = line6->usbdev;
+       int ret;
+       unsigned char status;
+       int count;
+
+       ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
+                             USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+                             0x0022, address, data, datalen,
+                             LINE6_TIMEOUT * HZ);
+
+       if (ret < 0) {
+               dev_err(line6->ifcdev,
+                       "write request failed (error %d)\n", ret);
+               return ret;
+       }
+
+       for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) {
+               mdelay(LINE6_READ_WRITE_STATUS_DELAY);
+
+               ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
+                                     0x67,
+                                     USB_TYPE_VENDOR | USB_RECIP_DEVICE |
+                                     USB_DIR_IN,
+                                     0x0012, 0x0000,
+                                     &status, 1, LINE6_TIMEOUT * HZ);
+
+               if (ret < 0) {
+                       dev_err(line6->ifcdev,
+                               "receiving status failed (error %d)\n", ret);
+                       return ret;
+               }
+
+               if (status != 0xff)
+                       break;
+       }
+
+       if (status == 0xff) {
+               dev_err(line6->ifcdev, "write failed after %d retries\n",
+                       count);
+               return -EIO;
+       } else if (status != 0) {
+               dev_err(line6->ifcdev, "write failed (error %d)\n", ret);
+               return -EIO;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(line6_write_data);
+
+/*
+       Read Line 6 device serial number.
+       (POD, TonePort, GuitarPort)
+*/
+int line6_read_serial_number(struct usb_line6 *line6, u32 *serial_number)
+{
+       return line6_read_data(line6, 0x80d0, serial_number,
+                              sizeof(*serial_number));
+}
+EXPORT_SYMBOL_GPL(line6_read_serial_number);
+
+/*
+       Card destructor.
+*/
+static void line6_destruct(struct snd_card *card)
+{
+       struct usb_line6 *line6 = card->private_data;
+       struct usb_device *usbdev = line6->usbdev;
+
+       /* free buffer memory first: */
+       kfree(line6->buffer_message);
+       kfree(line6->buffer_listen);
+
+       /* then free URBs: */
+       usb_free_urb(line6->urb_listen);
+
+       /* decrement reference counters: */
+       usb_put_dev(usbdev);
+}
+
+/* get data from endpoint descriptor (see usb_maxpacket): */
+static void line6_get_interval(struct usb_line6 *line6)
+{
+       struct usb_device *usbdev = line6->usbdev;
+       struct usb_host_endpoint *ep;
+       unsigned pipe = usb_rcvintpipe(usbdev, line6->properties->ep_ctrl_r);
+       unsigned epnum = usb_pipeendpoint(pipe);
+
+       ep = usbdev->ep_in[epnum];
+       if (ep) {
+               line6->interval = ep->desc.bInterval;
+               line6->max_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize);
+       } else {
+               dev_err(line6->ifcdev,
+                       "endpoint not available, using fallback values");
+               line6->interval = LINE6_FALLBACK_INTERVAL;
+               line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE;
+       }
+}
+
+static int line6_init_cap_control(struct usb_line6 *line6)
+{
+       int ret;
+
+       /* initialize USB buffers: */
+       line6->buffer_listen = kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL);
+       if (!line6->buffer_listen)
+               return -ENOMEM;
+
+       line6->buffer_message = kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL);
+       if (!line6->buffer_message)
+               return -ENOMEM;
+
+       line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL);
+       if (!line6->urb_listen)
+               return -ENOMEM;
+
+       ret = line6_start_listen(line6);
+       if (ret < 0) {
+               dev_err(line6->ifcdev, "cannot start listening: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+       Probe USB device.
+*/
+int line6_probe(struct usb_interface *interface,
+               const struct usb_device_id *id,
+               const char *driver_name,
+               const struct line6_properties *properties,
+               int (*private_init)(struct usb_line6 *, const struct usb_device_id *id),
+               size_t data_size)
+{
+       struct usb_device *usbdev = interface_to_usbdev(interface);
+       struct snd_card *card;
+       struct usb_line6 *line6;
+       int interface_number;
+       int ret;
+
+       if (WARN_ON(data_size < sizeof(*line6)))
+               return -EINVAL;
+
+       /* we don't handle multiple configurations */
+       if (usbdev->descriptor.bNumConfigurations != 1)
+               return -ENODEV;
+
+       ret = snd_card_new(&interface->dev,
+                          SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+                          THIS_MODULE, data_size, &card);
+       if (ret < 0)
+               return ret;
+
+       /* store basic data: */
+       line6 = card->private_data;
+       line6->card = card;
+       line6->properties = properties;
+       line6->usbdev = usbdev;
+       line6->ifcdev = &interface->dev;
+
+       strcpy(card->id, properties->id);
+       strcpy(card->driver, driver_name);
+       strcpy(card->shortname, properties->name);
+       sprintf(card->longname, "Line 6 %s at USB %s", properties->name,
+               dev_name(line6->ifcdev));
+       card->private_free = line6_destruct;
+
+       usb_set_intfdata(interface, line6);
+
+       /* increment reference counters: */
+       usb_get_dev(usbdev);
+
+       /* initialize device info: */
+       dev_info(&interface->dev, "Line 6 %s found\n", properties->name);
+
+       /* query interface number */
+       interface_number = interface->cur_altsetting->desc.bInterfaceNumber;
+
+       ret = usb_set_interface(usbdev, interface_number,
+                               properties->altsetting);
+       if (ret < 0) {
+               dev_err(&interface->dev, "set_interface failed\n");
+               goto error;
+       }
+
+       line6_get_interval(line6);
+
+       if (properties->capabilities & LINE6_CAP_CONTROL) {
+               ret = line6_init_cap_control(line6);
+               if (ret < 0)
+                       goto error;
+       }
+
+       /* initialize device data based on device: */
+       ret = private_init(line6, id);
+       if (ret < 0)
+               goto error;
+
+       /* creation of additional special files should go here */
+
+       dev_info(&interface->dev, "Line 6 %s now attached\n",
+                properties->name);
+
+       return 0;
+
+ error:
+       if (line6->disconnect)
+               line6->disconnect(line6);
+       snd_card_free(card);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(line6_probe);
+
+/*
+       Line 6 device disconnected.
+*/
+void line6_disconnect(struct usb_interface *interface)
+{
+       struct usb_line6 *line6 = usb_get_intfdata(interface);
+       struct usb_device *usbdev = interface_to_usbdev(interface);
+
+       if (!line6)
+               return;
+
+       if (WARN_ON(usbdev != line6->usbdev))
+               return;
+
+       if (line6->urb_listen != NULL)
+               line6_stop_listen(line6);
+
+       snd_card_disconnect(line6->card);
+       if (line6->line6pcm)
+               line6_pcm_disconnect(line6->line6pcm);
+       if (line6->disconnect)
+               line6->disconnect(line6);
+
+       dev_info(&interface->dev, "Line 6 %s now disconnected\n",
+                line6->properties->name);
+
+       /* make sure the device isn't destructed twice: */
+       usb_set_intfdata(interface, NULL);
+
+       snd_card_free_when_closed(line6->card);
+}
+EXPORT_SYMBOL_GPL(line6_disconnect);
+
+#ifdef CONFIG_PM
+
+/*
+       Suspend Line 6 device.
+*/
+int line6_suspend(struct usb_interface *interface, pm_message_t message)
+{
+       struct usb_line6 *line6 = usb_get_intfdata(interface);
+       struct snd_line6_pcm *line6pcm = line6->line6pcm;
+
+       snd_power_change_state(line6->card, SNDRV_CTL_POWER_D3hot);
+
+       if (line6->properties->capabilities & LINE6_CAP_CONTROL)
+               line6_stop_listen(line6);
+
+       if (line6pcm != NULL) {
+               snd_pcm_suspend_all(line6pcm->pcm);
+               line6pcm->flags = 0;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(line6_suspend);
+
+/*
+       Resume Line 6 device.
+*/
+int line6_resume(struct usb_interface *interface)
+{
+       struct usb_line6 *line6 = usb_get_intfdata(interface);
+
+       if (line6->properties->capabilities & LINE6_CAP_CONTROL)
+               line6_start_listen(line6);
+
+       snd_power_change_state(line6->card, SNDRV_CTL_POWER_D0);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(line6_resume);
+
+#endif /* CONFIG_PM */
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h
new file mode 100644 (file)
index 0000000..5d20294
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ *     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, version 2.
+ *
+ */
+
+#ifndef DRIVER_H
+#define DRIVER_H
+
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+#include <sound/core.h>
+
+#include "midi.h"
+
+#define USB_INTERVALS_PER_SECOND 1000
+
+/* Fallback USB interval and max packet size values */
+#define LINE6_FALLBACK_INTERVAL 10
+#define LINE6_FALLBACK_MAXPACKETSIZE 16
+
+#define LINE6_TIMEOUT 1
+#define LINE6_BUFSIZE_LISTEN 32
+#define LINE6_MESSAGE_MAXLEN 256
+
+/*
+       Line 6 MIDI control commands
+*/
+#define LINE6_PARAM_CHANGE   0xb0
+#define LINE6_PROGRAM_CHANGE 0xc0
+#define LINE6_SYSEX_BEGIN    0xf0
+#define LINE6_SYSEX_END      0xf7
+#define LINE6_RESET          0xff
+
+/*
+       MIDI channel for messages initiated by the host
+       (and eventually echoed back by the device)
+*/
+#define LINE6_CHANNEL_HOST   0x00
+
+/*
+       MIDI channel for messages initiated by the device
+*/
+#define LINE6_CHANNEL_DEVICE 0x02
+
+#define LINE6_CHANNEL_UNKNOWN 5        /* don't know yet what this is good for */
+
+#define LINE6_CHANNEL_MASK 0x0f
+
+#define CHECK_STARTUP_PROGRESS(x, n)   \
+do {                                   \
+       if ((x) >= (n))                 \
+               return;                 \
+       x = (n);                        \
+} while (0)
+
+extern const unsigned char line6_midi_id[3];
+
+static const int SYSEX_DATA_OFS = sizeof(line6_midi_id) + 3;
+static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4;
+
+/*
+        Common properties of Line 6 devices.
+*/
+struct line6_properties {
+       /* Card id string (maximum 16 characters).
+        * This can be used to address the device in ALSA programs as
+        * "default:CARD=<id>"
+        */
+       const char *id;
+
+       /* Card short name (maximum 32 characters) */
+       const char *name;
+
+       /* Bit vector defining this device's capabilities in line6usb driver */
+       int capabilities;
+
+       int altsetting;
+
+       unsigned ep_ctrl_r;
+       unsigned ep_ctrl_w;
+       unsigned ep_audio_r;
+       unsigned ep_audio_w;
+};
+
+/* Capability bits */
+enum {
+       /* device supports settings parameter via USB */
+       LINE6_CAP_CONTROL =     1 << 0,
+       /* device supports PCM input/output via USB */
+       LINE6_CAP_PCM =         1 << 1,
+       /* device support hardware monitoring */
+       LINE6_CAP_HWMON =       1 << 2,
+};
+
+/*
+        Common data shared by all Line 6 devices.
+        Corresponds to a pair of USB endpoints.
+*/
+struct usb_line6 {
+       /* USB device */
+       struct usb_device *usbdev;
+
+       /* Properties */
+       const struct line6_properties *properties;
+
+       /* Interval (ms) */
+       int interval;
+
+       /* Maximum size of USB packet */
+       int max_packet_size;
+
+       /* Device representing the USB interface */
+       struct device *ifcdev;
+
+       /* Line 6 sound card data structure.
+        * Each device has at least MIDI or PCM.
+        */
+       struct snd_card *card;
+
+       /* Line 6 PCM device data structure */
+       struct snd_line6_pcm *line6pcm;
+
+       /* Line 6 MIDI device data structure */
+       struct snd_line6_midi *line6midi;
+
+       /* URB for listening to PODxt Pro control endpoint */
+       struct urb *urb_listen;
+
+       /* Buffer for listening to PODxt Pro control endpoint */
+       unsigned char *buffer_listen;
+
+       /* Buffer for message to be processed */
+       unsigned char *buffer_message;
+
+       /* Length of message to be processed */
+       int message_length;
+
+       void (*process_message)(struct usb_line6 *);
+       void (*disconnect)(struct usb_line6 *line6);
+};
+
+extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1,
+                                     int code2, int size);
+extern int line6_read_data(struct usb_line6 *line6, int address, void *data,
+                          size_t datalen);
+extern int line6_read_serial_number(struct usb_line6 *line6,
+                                   u32 *serial_number);
+extern int line6_send_raw_message_async(struct usb_line6 *line6,
+                                       const char *buffer, int size);
+extern int line6_send_sysex_message(struct usb_line6 *line6,
+                                   const char *buffer, int size);
+extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr,
+                            const char *buf, size_t count);
+extern void line6_start_timer(struct timer_list *timer, unsigned long msecs,
+                             void (*function)(unsigned long),
+                             unsigned long data);
+extern int line6_version_request_async(struct usb_line6 *line6);
+extern int line6_write_data(struct usb_line6 *line6, int address, void *data,
+                           size_t datalen);
+
+int line6_probe(struct usb_interface *interface,
+               const struct usb_device_id *id,
+               const char *driver_name,
+               const struct line6_properties *properties,
+               int (*private_init)(struct usb_line6 *, const struct usb_device_id *id),
+               size_t data_size);
+
+void line6_disconnect(struct usb_interface *interface);
+
+#ifdef CONFIG_PM
+int line6_suspend(struct usb_interface *interface, pm_message_t message);
+int line6_resume(struct usb_interface *interface);
+#endif
+
+#endif
diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c
new file mode 100644 (file)
index 0000000..cebea9b
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ *     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, version 2.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/export.h>
+#include <sound/core.h>
+#include <sound/rawmidi.h>
+
+#include "driver.h"
+#include "midi.h"
+
+#define line6_rawmidi_substream_midi(substream) \
+       ((struct snd_line6_midi *)((substream)->rmidi->private_data))
+
+static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
+                          int length);
+
+/*
+       Pass data received via USB to MIDI.
+*/
+void line6_midi_receive(struct usb_line6 *line6, unsigned char *data,
+                       int length)
+{
+       if (line6->line6midi->substream_receive)
+               snd_rawmidi_receive(line6->line6midi->substream_receive,
+                                   data, length);
+}
+
+/*
+       Read data from MIDI buffer and transmit them via USB.
+*/
+static void line6_midi_transmit(struct snd_rawmidi_substream *substream)
+{
+       struct usb_line6 *line6 =
+           line6_rawmidi_substream_midi(substream)->line6;
+       struct snd_line6_midi *line6midi = line6->line6midi;
+       struct midi_buffer *mb = &line6midi->midibuf_out;
+       unsigned char chunk[LINE6_FALLBACK_MAXPACKETSIZE];
+       int req, done;
+
+       for (;;) {
+               req = min(line6_midibuf_bytes_free(mb), line6->max_packet_size);
+               done = snd_rawmidi_transmit_peek(substream, chunk, req);
+
+               if (done == 0)
+                       break;
+
+               line6_midibuf_write(mb, chunk, done);
+               snd_rawmidi_transmit_ack(substream, done);
+       }
+
+       for (;;) {
+               done = line6_midibuf_read(mb, chunk,
+                                         LINE6_FALLBACK_MAXPACKETSIZE);
+
+               if (done == 0)
+                       break;
+
+               send_midi_async(line6, chunk, done);
+       }
+}
+
+/*
+       Notification of completion of MIDI transmission.
+*/
+static void midi_sent(struct urb *urb)
+{
+       unsigned long flags;
+       int status;
+       int num;
+       struct usb_line6 *line6 = (struct usb_line6 *)urb->context;
+
+       status = urb->status;
+       kfree(urb->transfer_buffer);
+       usb_free_urb(urb);
+
+       if (status == -ESHUTDOWN)
+               return;
+
+       spin_lock_irqsave(&line6->line6midi->lock, flags);
+       num = --line6->line6midi->num_active_send_urbs;
+
+       if (num == 0) {
+               line6_midi_transmit(line6->line6midi->substream_transmit);
+               num = line6->line6midi->num_active_send_urbs;
+       }
+
+       if (num == 0)
+               wake_up(&line6->line6midi->send_wait);
+
+       spin_unlock_irqrestore(&line6->line6midi->lock, flags);
+}
+
+/*
+       Send an asynchronous MIDI message.
+       Assumes that line6->line6midi->lock is held
+       (i.e., this function is serialized).
+*/
+static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
+                          int length)
+{
+       struct urb *urb;
+       int retval;
+       unsigned char *transfer_buffer;
+
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
+
+       if (urb == NULL)
+               return -ENOMEM;
+
+       transfer_buffer = kmemdup(data, length, GFP_ATOMIC);
+
+       if (transfer_buffer == NULL) {
+               usb_free_urb(urb);
+               return -ENOMEM;
+       }
+
+       usb_fill_int_urb(urb, line6->usbdev,
+                        usb_sndbulkpipe(line6->usbdev,
+                                        line6->properties->ep_ctrl_w),
+                        transfer_buffer, length, midi_sent, line6,
+                        line6->interval);
+       urb->actual_length = 0;
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+
+       if (retval < 0) {
+               dev_err(line6->ifcdev, "usb_submit_urb failed\n");
+               usb_free_urb(urb);
+               return retval;
+       }
+
+       ++line6->line6midi->num_active_send_urbs;
+       return 0;
+}
+
+static int line6_midi_output_open(struct snd_rawmidi_substream *substream)
+{
+       return 0;
+}
+
+static int line6_midi_output_close(struct snd_rawmidi_substream *substream)
+{
+       return 0;
+}
+
+static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream,
+                                     int up)
+{
+       unsigned long flags;
+       struct usb_line6 *line6 =
+           line6_rawmidi_substream_midi(substream)->line6;
+
+       line6->line6midi->substream_transmit = substream;
+       spin_lock_irqsave(&line6->line6midi->lock, flags);
+
+       if (line6->line6midi->num_active_send_urbs == 0)
+               line6_midi_transmit(substream);
+
+       spin_unlock_irqrestore(&line6->line6midi->lock, flags);
+}
+
+static void line6_midi_output_drain(struct snd_rawmidi_substream *substream)
+{
+       struct usb_line6 *line6 =
+           line6_rawmidi_substream_midi(substream)->line6;
+       struct snd_line6_midi *midi = line6->line6midi;
+
+       wait_event_interruptible(midi->send_wait,
+                                midi->num_active_send_urbs == 0);
+}
+
+static int line6_midi_input_open(struct snd_rawmidi_substream *substream)
+{
+       return 0;
+}
+
+static int line6_midi_input_close(struct snd_rawmidi_substream *substream)
+{
+       return 0;
+}
+
+static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream,
+                                    int up)
+{
+       struct usb_line6 *line6 =
+           line6_rawmidi_substream_midi(substream)->line6;
+
+       if (up)
+               line6->line6midi->substream_receive = substream;
+       else
+               line6->line6midi->substream_receive = NULL;
+}
+
+static struct snd_rawmidi_ops line6_midi_output_ops = {
+       .open = line6_midi_output_open,
+       .close = line6_midi_output_close,
+       .trigger = line6_midi_output_trigger,
+       .drain = line6_midi_output_drain,
+};
+
+static struct snd_rawmidi_ops line6_midi_input_ops = {
+       .open = line6_midi_input_open,
+       .close = line6_midi_input_close,
+       .trigger = line6_midi_input_trigger,
+};
+
+/* Create a MIDI device */
+static int snd_line6_new_midi(struct usb_line6 *line6,
+                             struct snd_rawmidi **rmidi_ret)
+{
+       struct snd_rawmidi *rmidi;
+       int err;
+
+       err = snd_rawmidi_new(line6->card, "Line 6 MIDI", 0, 1, 1, rmidi_ret);
+       if (err < 0)
+               return err;
+
+       rmidi = *rmidi_ret;
+       strcpy(rmidi->id, line6->properties->id);
+       strcpy(rmidi->name, line6->properties->name);
+
+       rmidi->info_flags =
+           SNDRV_RAWMIDI_INFO_OUTPUT |
+           SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
+
+       snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+                           &line6_midi_output_ops);
+       snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+                           &line6_midi_input_ops);
+       return 0;
+}
+
+/* MIDI device destructor */
+static void snd_line6_midi_free(struct snd_rawmidi *rmidi)
+{
+       struct snd_line6_midi *line6midi = rmidi->private_data;
+
+       line6_midibuf_destroy(&line6midi->midibuf_in);
+       line6_midibuf_destroy(&line6midi->midibuf_out);
+       kfree(line6midi);
+}
+
+/*
+       Initialize the Line 6 MIDI subsystem.
+*/
+int line6_init_midi(struct usb_line6 *line6)
+{
+       int err;
+       struct snd_rawmidi *rmidi;
+       struct snd_line6_midi *line6midi;
+
+       if (!(line6->properties->capabilities & LINE6_CAP_CONTROL)) {
+               /* skip MIDI initialization and report success */
+               return 0;
+       }
+
+       err = snd_line6_new_midi(line6, &rmidi);
+       if (err < 0)
+               return err;
+
+       line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL);
+       if (!line6midi)
+               return -ENOMEM;
+
+       rmidi->private_data = line6midi;
+       rmidi->private_free = snd_line6_midi_free;
+
+       init_waitqueue_head(&line6midi->send_wait);
+       spin_lock_init(&line6midi->lock);
+       line6midi->line6 = line6;
+
+       err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0);
+       if (err < 0)
+               return err;
+
+       err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1);
+       if (err < 0)
+               return err;
+
+       line6->line6midi = line6midi;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(line6_init_midi);
diff --git a/sound/usb/line6/midi.h b/sound/usb/line6/midi.h
new file mode 100644 (file)
index 0000000..cf82d69
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ *     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, version 2.
+ *
+ */
+
+#ifndef MIDI_H
+#define MIDI_H
+
+#include <sound/rawmidi.h>
+
+#include "midibuf.h"
+
+#define MIDI_BUFFER_SIZE 1024
+
+struct snd_line6_midi {
+       /* Pointer back to the Line 6 driver data structure */
+       struct usb_line6 *line6;
+
+       /* MIDI substream for receiving (or NULL if not active) */
+       struct snd_rawmidi_substream *substream_receive;
+
+       /* MIDI substream for transmitting (or NULL if not active) */
+       struct snd_rawmidi_substream *substream_transmit;
+
+       /* Number of currently active MIDI send URBs */
+       int num_active_send_urbs;
+
+       /* Spin lock to protect MIDI buffer handling */
+       spinlock_t lock;
+
+       /* Wait queue for MIDI transmission */
+       wait_queue_head_t send_wait;
+
+       /* Buffer for incoming MIDI stream */
+       struct midi_buffer midibuf_in;
+
+       /* Buffer for outgoing MIDI stream */
+       struct midi_buffer midibuf_out;
+};
+
+extern int line6_init_midi(struct usb_line6 *line6);
+extern void line6_midi_receive(struct usb_line6 *line6, unsigned char *data,
+                              int length);
+
+#endif
diff --git a/sound/usb/line6/midibuf.c b/sound/usb/line6/midibuf.c
new file mode 100644 (file)
index 0000000..36a610b
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ *     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, version 2.
+ *
+ */
+
+#include <linux/slab.h>
+
+#include "midibuf.h"
+
+static int midibuf_message_length(unsigned char code)
+{
+       int message_length;
+
+       if (code < 0x80)
+               message_length = -1;
+       else if (code < 0xf0) {
+               static const int length[] = { 3, 3, 3, 3, 2, 2, 3 };
+
+               message_length = length[(code >> 4) - 8];
+       } else {
+               /*
+                  Note that according to the MIDI specification 0xf2 is
+                  the "Song Position Pointer", but this is used by Line 6
+                  to send sysex messages to the host.
+                */
+               static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1,
+                       1, 1, 1, -1, 1, 1
+               };
+               message_length = length[code & 0x0f];
+       }
+
+       return message_length;
+}
+
+static int midibuf_is_empty(struct midi_buffer *this)
+{
+       return (this->pos_read == this->pos_write) && !this->full;
+}
+
+static int midibuf_is_full(struct midi_buffer *this)
+{
+       return this->full;
+}
+
+void line6_midibuf_reset(struct midi_buffer *this)
+{
+       this->pos_read = this->pos_write = this->full = 0;
+       this->command_prev = -1;
+}
+
+int line6_midibuf_init(struct midi_buffer *this, int size, int split)
+{
+       this->buf = kmalloc(size, GFP_KERNEL);
+
+       if (this->buf == NULL)
+               return -ENOMEM;
+
+       this->size = size;
+       this->split = split;
+       line6_midibuf_reset(this);
+       return 0;
+}
+
+int line6_midibuf_bytes_free(struct midi_buffer *this)
+{
+       return
+           midibuf_is_full(this) ?
+           0 :
+           (this->pos_read - this->pos_write + this->size - 1) % this->size +
+           1;
+}
+
+int line6_midibuf_bytes_used(struct midi_buffer *this)
+{
+       return
+           midibuf_is_empty(this) ?
+           0 :
+           (this->pos_write - this->pos_read + this->size - 1) % this->size +
+           1;
+}
+
+int line6_midibuf_write(struct midi_buffer *this, unsigned char *data,
+                       int length)
+{
+       int bytes_free;
+       int length1, length2;
+       int skip_active_sense = 0;
+
+       if (midibuf_is_full(this) || (length <= 0))
+               return 0;
+
+       /* skip trailing active sense */
+       if (data[length - 1] == 0xfe) {
+               --length;
+               skip_active_sense = 1;
+       }
+
+       bytes_free = line6_midibuf_bytes_free(this);
+
+       if (length > bytes_free)
+               length = bytes_free;
+
+       if (length > 0) {
+               length1 = this->size - this->pos_write;
+
+               if (length < length1) {
+                       /* no buffer wraparound */
+                       memcpy(this->buf + this->pos_write, data, length);
+                       this->pos_write += length;
+               } else {
+                       /* buffer wraparound */
+                       length2 = length - length1;
+                       memcpy(this->buf + this->pos_write, data, length1);
+                       memcpy(this->buf, data + length1, length2);
+                       this->pos_write = length2;
+               }
+
+               if (this->pos_write == this->pos_read)
+                       this->full = 1;
+       }
+
+       return length + skip_active_sense;
+}
+
+int line6_midibuf_read(struct midi_buffer *this, unsigned char *data,
+                      int length)
+{
+       int bytes_used;
+       int length1, length2;
+       int command;
+       int midi_length;
+       int repeat = 0;
+       int i;
+
+       /* we need to be able to store at least a 3 byte MIDI message */
+       if (length < 3)
+               return -EINVAL;
+
+       if (midibuf_is_empty(this))
+               return 0;
+
+       bytes_used = line6_midibuf_bytes_used(this);
+
+       if (length > bytes_used)
+               length = bytes_used;
+
+       length1 = this->size - this->pos_read;
+
+       /* check MIDI command length */
+       command = this->buf[this->pos_read];
+
+       if (command & 0x80) {
+               midi_length = midibuf_message_length(command);
+               this->command_prev = command;
+       } else {
+               if (this->command_prev > 0) {
+                       int midi_length_prev =
+                           midibuf_message_length(this->command_prev);
+
+                       if (midi_length_prev > 0) {
+                               midi_length = midi_length_prev - 1;
+                               repeat = 1;
+                       } else
+                               midi_length = -1;
+               } else
+                       midi_length = -1;
+       }
+
+       if (midi_length < 0) {
+               /* search for end of message */
+               if (length < length1) {
+                       /* no buffer wraparound */
+                       for (i = 1; i < length; ++i)
+                               if (this->buf[this->pos_read + i] & 0x80)
+                                       break;
+
+                       midi_length = i;
+               } else {
+                       /* buffer wraparound */
+                       length2 = length - length1;
+
+                       for (i = 1; i < length1; ++i)
+                               if (this->buf[this->pos_read + i] & 0x80)
+                                       break;
+
+                       if (i < length1)
+                               midi_length = i;
+                       else {
+                               for (i = 0; i < length2; ++i)
+                                       if (this->buf[i] & 0x80)
+                                               break;
+
+                               midi_length = length1 + i;
+                       }
+               }
+
+               if (midi_length == length)
+                       midi_length = -1;       /* end of message not found */
+       }
+
+       if (midi_length < 0) {
+               if (!this->split)
+                       return 0;       /* command is not yet complete */
+       } else {
+               if (length < midi_length)
+                       return 0;       /* command is not yet complete */
+
+               length = midi_length;
+       }
+
+       if (length < length1) {
+               /* no buffer wraparound */
+               memcpy(data + repeat, this->buf + this->pos_read, length);
+               this->pos_read += length;
+       } else {
+               /* buffer wraparound */
+               length2 = length - length1;
+               memcpy(data + repeat, this->buf + this->pos_read, length1);
+               memcpy(data + repeat + length1, this->buf, length2);
+               this->pos_read = length2;
+       }
+
+       if (repeat)
+               data[0] = this->command_prev;
+
+       this->full = 0;
+       return length + repeat;
+}
+
+int line6_midibuf_ignore(struct midi_buffer *this, int length)
+{
+       int bytes_used = line6_midibuf_bytes_used(this);
+
+       if (length > bytes_used)
+               length = bytes_used;
+
+       this->pos_read = (this->pos_read + length) % this->size;
+       this->full = 0;
+       return length;
+}
+
+void line6_midibuf_destroy(struct midi_buffer *this)
+{
+       kfree(this->buf);
+       this->buf = NULL;
+}
diff --git a/sound/usb/line6/midibuf.h b/sound/usb/line6/midibuf.h
new file mode 100644 (file)
index 0000000..6ea21ff
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ *     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, version 2.
+ *
+ */
+
+#ifndef MIDIBUF_H
+#define MIDIBUF_H
+
+struct midi_buffer {
+       unsigned char *buf;
+       int size;
+       int split;
+       int pos_read, pos_write;
+       int full;
+       int command_prev;
+};
+
+extern int line6_midibuf_bytes_used(struct midi_buffer *mb);
+extern int line6_midibuf_bytes_free(struct midi_buffer *mb);
+extern void line6_midibuf_destroy(struct midi_buffer *mb);
+extern int line6_midibuf_ignore(struct midi_buffer *mb, int length);
+extern int line6_midibuf_init(struct midi_buffer *mb, int size, int split);
+extern int line6_midibuf_read(struct midi_buffer *mb, unsigned char *data,
+                             int length);
+extern void line6_midibuf_reset(struct midi_buffer *mb);
+extern int line6_midibuf_write(struct midi_buffer *mb, unsigned char *data,
+                              int length);
+
+#endif
diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c
new file mode 100644 (file)
index 0000000..8461d6b
--- /dev/null
@@ -0,0 +1,588 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ *     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, version 2.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/export.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "capture.h"
+#include "driver.h"
+#include "playback.h"
+
+/* impulse response volume controls */
+static int snd_line6_impulse_volume_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 = 255;
+       return 0;
+}
+
+static int snd_line6_impulse_volume_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = line6pcm->impulse_volume;
+       return 0;
+}
+
+static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+       int value = ucontrol->value.integer.value[0];
+       int err;
+
+       if (line6pcm->impulse_volume == value)
+               return 0;
+
+       line6pcm->impulse_volume = value;
+       if (value > 0) {
+               err = line6_pcm_acquire(line6pcm, LINE6_STREAM_IMPULSE);
+               if (err < 0) {
+                       line6pcm->impulse_volume = 0;
+                       line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE);
+                       return err;
+               }
+       } else {
+               line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE);
+       }
+       return 1;
+}
+
+/* impulse response period controls */
+static int snd_line6_impulse_period_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 = 2000;
+       return 0;
+}
+
+static int snd_line6_impulse_period_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = line6pcm->impulse_period;
+       return 0;
+}
+
+static int snd_line6_impulse_period_put(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+       int value = ucontrol->value.integer.value[0];
+
+       if (line6pcm->impulse_period == value)
+               return 0;
+
+       line6pcm->impulse_period = value;
+       return 1;
+}
+
+/*
+       Unlink all currently active URBs.
+*/
+static void line6_unlink_audio_urbs(struct snd_line6_pcm *line6pcm,
+                                   struct line6_pcm_stream *pcms)
+{
+       int i;
+
+       for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
+               if (test_bit(i, &pcms->active_urbs)) {
+                       if (!test_and_set_bit(i, &pcms->unlink_urbs))
+                               usb_unlink_urb(pcms->urbs[i]);
+               }
+       }
+}
+
+/*
+       Wait until unlinking of all currently active URBs has been finished.
+*/
+static void line6_wait_clear_audio_urbs(struct snd_line6_pcm *line6pcm,
+                                       struct line6_pcm_stream *pcms)
+{
+       int timeout = HZ;
+       int i;
+       int alive;
+
+       do {
+               alive = 0;
+               for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
+                       if (test_bit(i, &pcms->active_urbs))
+                               alive++;
+               }
+               if (!alive)
+                       break;
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(1);
+       } while (--timeout > 0);
+       if (alive)
+               dev_err(line6pcm->line6->ifcdev,
+                       "timeout: still %d active urbs..\n", alive);
+}
+
+static inline struct line6_pcm_stream *
+get_stream(struct snd_line6_pcm *line6pcm, int direction)
+{
+       return (direction == SNDRV_PCM_STREAM_PLAYBACK) ?
+               &line6pcm->out : &line6pcm->in;
+}
+
+/* allocate a buffer if not opened yet;
+ * call this in line6pcm.state_change mutex
+ */
+static int line6_buffer_acquire(struct snd_line6_pcm *line6pcm,
+                               struct line6_pcm_stream *pstr, int type)
+{
+       /* Invoked multiple times in a row so allocate once only */
+       if (!test_and_set_bit(type, &pstr->opened) && !pstr->buffer) {
+               pstr->buffer = kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
+                                      line6pcm->max_packet_size, GFP_KERNEL);
+               if (!pstr->buffer)
+                       return -ENOMEM;
+       }
+       return 0;
+}
+
+/* free a buffer if all streams are closed;
+ * call this in line6pcm.state_change mutex
+ */
+static void line6_buffer_release(struct snd_line6_pcm *line6pcm,
+                                struct line6_pcm_stream *pstr, int type)
+{
+
+       clear_bit(type, &pstr->opened);
+       if (!pstr->opened) {
+               line6_wait_clear_audio_urbs(line6pcm, pstr);
+               kfree(pstr->buffer);
+               pstr->buffer = NULL;
+       }
+}
+
+/* start a PCM stream */
+static int line6_stream_start(struct snd_line6_pcm *line6pcm, int direction,
+                             int type)
+{
+       unsigned long flags;
+       struct line6_pcm_stream *pstr = get_stream(line6pcm, direction);
+       int ret = 0;
+
+       spin_lock_irqsave(&pstr->lock, flags);
+       if (!test_and_set_bit(type, &pstr->running)) {
+               if (pstr->active_urbs || pstr->unlink_urbs) {
+                       ret = -EBUSY;
+                       goto error;
+               }
+
+               pstr->count = 0;
+               /* Submit all currently available URBs */
+               if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+                       ret = line6_submit_audio_out_all_urbs(line6pcm);
+               else
+                       ret = line6_submit_audio_in_all_urbs(line6pcm);
+       }
+ error:
+       if (ret < 0)
+               clear_bit(type, &pstr->running);
+       spin_unlock_irqrestore(&pstr->lock, flags);
+       return ret;
+}
+
+/* stop a PCM stream; this doesn't sync with the unlinked URBs */
+static void line6_stream_stop(struct snd_line6_pcm *line6pcm, int direction,
+                         int type)
+{
+       unsigned long flags;
+       struct line6_pcm_stream *pstr = get_stream(line6pcm, direction);
+
+       spin_lock_irqsave(&pstr->lock, flags);
+       clear_bit(type, &pstr->running);
+       if (!pstr->running) {
+               line6_unlink_audio_urbs(line6pcm, pstr);
+               if (direction == SNDRV_PCM_STREAM_CAPTURE) {
+                       line6pcm->prev_fbuf = NULL;
+                       line6pcm->prev_fsize = 0;
+               }
+       }
+       spin_unlock_irqrestore(&pstr->lock, flags);
+}
+
+/* common PCM trigger callback */
+int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+       struct snd_pcm_substream *s;
+       int err;
+
+       clear_bit(LINE6_FLAG_PREPARED, &line6pcm->flags);
+
+       snd_pcm_group_for_each_entry(s, substream) {
+               if (s->pcm->card != substream->pcm->card)
+                       continue;
+
+               switch (cmd) {
+               case SNDRV_PCM_TRIGGER_START:
+               case SNDRV_PCM_TRIGGER_RESUME:
+                       err = line6_stream_start(line6pcm, s->stream,
+                                                LINE6_STREAM_PCM);
+                       if (err < 0)
+                               return err;
+                       break;
+
+               case SNDRV_PCM_TRIGGER_STOP:
+               case SNDRV_PCM_TRIGGER_SUSPEND:
+                       line6_stream_stop(line6pcm, s->stream,
+                                         LINE6_STREAM_PCM);
+                       break;
+
+               case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+                       if (s->stream != SNDRV_PCM_STREAM_PLAYBACK)
+                               return -EINVAL;
+                       set_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags);
+                       break;
+
+               case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+                       if (s->stream != SNDRV_PCM_STREAM_PLAYBACK)
+                               return -EINVAL;
+                       clear_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags);
+                       break;
+
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+/* common PCM pointer callback */
+snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+       struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
+
+       return pstr->pos_done;
+}
+
+/* Acquire and start duplex streams:
+ * type is either LINE6_STREAM_IMPULSE or LINE6_STREAM_MONITOR
+ */
+int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type)
+{
+       struct line6_pcm_stream *pstr;
+       int ret = 0, dir;
+
+       mutex_lock(&line6pcm->state_mutex);
+       for (dir = 0; dir < 2; dir++) {
+               pstr = get_stream(line6pcm, dir);
+               ret = line6_buffer_acquire(line6pcm, pstr, type);
+               if (ret < 0)
+                       goto error;
+               if (!pstr->running)
+                       line6_wait_clear_audio_urbs(line6pcm, pstr);
+       }
+       for (dir = 0; dir < 2; dir++) {
+               ret = line6_stream_start(line6pcm, dir, type);
+               if (ret < 0)
+                       goto error;
+       }
+ error:
+       mutex_unlock(&line6pcm->state_mutex);
+       if (ret < 0)
+               line6_pcm_release(line6pcm, type);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(line6_pcm_acquire);
+
+/* Stop and release duplex streams */
+void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type)
+{
+       struct line6_pcm_stream *pstr;
+       int dir;
+
+       mutex_lock(&line6pcm->state_mutex);
+       for (dir = 0; dir < 2; dir++)
+               line6_stream_stop(line6pcm, dir, type);
+       for (dir = 0; dir < 2; dir++) {
+               pstr = get_stream(line6pcm, dir);
+               line6_buffer_release(line6pcm, pstr, type);
+       }
+       mutex_unlock(&line6pcm->state_mutex);
+}
+EXPORT_SYMBOL_GPL(line6_pcm_release);
+
+/* common PCM hw_params callback */
+int snd_line6_hw_params(struct snd_pcm_substream *substream,
+                       struct snd_pcm_hw_params *hw_params)
+{
+       int ret;
+       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+       struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
+
+       mutex_lock(&line6pcm->state_mutex);
+       ret = line6_buffer_acquire(line6pcm, pstr, LINE6_STREAM_PCM);
+       if (ret < 0)
+               goto error;
+
+       ret = snd_pcm_lib_malloc_pages(substream,
+                                      params_buffer_bytes(hw_params));
+       if (ret < 0) {
+               line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM);
+               goto error;
+       }
+
+       pstr->period = params_period_bytes(hw_params);
+ error:
+       mutex_unlock(&line6pcm->state_mutex);
+       return ret;
+}
+
+/* common PCM hw_free callback */
+int snd_line6_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+       struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
+
+       mutex_lock(&line6pcm->state_mutex);
+       line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM);
+       mutex_unlock(&line6pcm->state_mutex);
+       return snd_pcm_lib_free_pages(substream);
+}
+
+
+/* control info callback */
+static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol,
+                                          struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 256;
+       return 0;
+}
+
+/* control get callback */
+static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_value *ucontrol)
+{
+       int i;
+       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+
+       for (i = 0; i < 2; i++)
+               ucontrol->value.integer.value[i] = line6pcm->volume_playback[i];
+
+       return 0;
+}
+
+/* control put callback */
+static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_value *ucontrol)
+{
+       int i, changed = 0;
+       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+
+       for (i = 0; i < 2; i++)
+               if (line6pcm->volume_playback[i] !=
+                   ucontrol->value.integer.value[i]) {
+                       line6pcm->volume_playback[i] =
+                           ucontrol->value.integer.value[i];
+                       changed = 1;
+               }
+
+       return changed;
+}
+
+/* control definition */
+static struct snd_kcontrol_new line6_controls[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "PCM Playback Volume",
+               .info = snd_line6_control_playback_info,
+               .get = snd_line6_control_playback_get,
+               .put = snd_line6_control_playback_put
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Impulse Response Volume",
+               .info = snd_line6_impulse_volume_info,
+               .get = snd_line6_impulse_volume_get,
+               .put = snd_line6_impulse_volume_put
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Impulse Response Period",
+               .info = snd_line6_impulse_period_info,
+               .get = snd_line6_impulse_period_get,
+               .put = snd_line6_impulse_period_put
+       },
+};
+
+/*
+       Cleanup the PCM device.
+*/
+static void cleanup_urbs(struct line6_pcm_stream *pcms)
+{
+       int i;
+
+       for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
+               if (pcms->urbs[i]) {
+                       usb_kill_urb(pcms->urbs[i]);
+                       usb_free_urb(pcms->urbs[i]);
+               }
+       }
+}
+
+static void line6_cleanup_pcm(struct snd_pcm *pcm)
+{
+       struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm);
+
+       cleanup_urbs(&line6pcm->out);
+       cleanup_urbs(&line6pcm->in);
+       kfree(line6pcm);
+}
+
+/* create a PCM device */
+static int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret)
+{
+       struct snd_pcm *pcm;
+       int err;
+
+       err = snd_pcm_new(line6->card, (char *)line6->properties->name,
+                         0, 1, 1, pcm_ret);
+       if (err < 0)
+               return err;
+       pcm = *pcm_ret;
+       strcpy(pcm->name, line6->properties->name);
+
+       /* set operators */
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                       &snd_line6_playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops);
+
+       /* pre-allocation of buffers */
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+                                             snd_dma_continuous_data
+                                             (GFP_KERNEL), 64 * 1024,
+                                             128 * 1024);
+       return 0;
+}
+
+/*
+       Sync with PCM stream stops.
+*/
+void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm)
+{
+       line6_unlink_audio_urbs(line6pcm, &line6pcm->out);
+       line6_unlink_audio_urbs(line6pcm, &line6pcm->in);
+       line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out);
+       line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in);
+}
+
+/*
+       Create and register the PCM device and mixer entries.
+       Create URBs for playback and capture.
+*/
+int line6_init_pcm(struct usb_line6 *line6,
+                  struct line6_pcm_properties *properties)
+{
+       int i, err;
+       unsigned ep_read = line6->properties->ep_audio_r;
+       unsigned ep_write = line6->properties->ep_audio_w;
+       struct snd_pcm *pcm;
+       struct snd_line6_pcm *line6pcm;
+
+       if (!(line6->properties->capabilities & LINE6_CAP_PCM))
+               return 0;       /* skip PCM initialization and report success */
+
+       err = snd_line6_new_pcm(line6, &pcm);
+       if (err < 0)
+               return err;
+
+       line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL);
+       if (!line6pcm)
+               return -ENOMEM;
+
+       mutex_init(&line6pcm->state_mutex);
+       line6pcm->pcm = pcm;
+       line6pcm->properties = properties;
+       line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255;
+       line6pcm->volume_monitor = 255;
+       line6pcm->line6 = line6;
+
+       /* Read and write buffers are sized identically, so choose minimum */
+       line6pcm->max_packet_size = min(
+                       usb_maxpacket(line6->usbdev,
+                               usb_rcvisocpipe(line6->usbdev, ep_read), 0),
+                       usb_maxpacket(line6->usbdev,
+                               usb_sndisocpipe(line6->usbdev, ep_write), 1));
+
+       spin_lock_init(&line6pcm->out.lock);
+       spin_lock_init(&line6pcm->in.lock);
+       line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
+
+       line6->line6pcm = line6pcm;
+
+       pcm->private_data = line6pcm;
+       pcm->private_free = line6_cleanup_pcm;
+
+       err = line6_create_audio_out_urbs(line6pcm);
+       if (err < 0)
+               return err;
+
+       err = line6_create_audio_in_urbs(line6pcm);
+       if (err < 0)
+               return err;
+
+       /* mixer: */
+       for (i = 0; i < ARRAY_SIZE(line6_controls); i++) {
+               err = snd_ctl_add(line6->card,
+                                 snd_ctl_new1(&line6_controls[i], line6pcm));
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(line6_init_pcm);
+
+/* prepare pcm callback */
+int snd_line6_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+       struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
+
+       mutex_lock(&line6pcm->state_mutex);
+       if (!pstr->running)
+               line6_wait_clear_audio_urbs(line6pcm, pstr);
+
+       if (!test_and_set_bit(LINE6_FLAG_PREPARED, &line6pcm->flags)) {
+               line6pcm->out.count = 0;
+               line6pcm->out.pos = 0;
+               line6pcm->out.pos_done = 0;
+               line6pcm->out.bytes = 0;
+               line6pcm->in.count = 0;
+               line6pcm->in.pos_done = 0;
+               line6pcm->in.bytes = 0;
+       }
+
+       mutex_unlock(&line6pcm->state_mutex);
+       return 0;
+}
diff --git a/sound/usb/line6/pcm.h b/sound/usb/line6/pcm.h
new file mode 100644 (file)
index 0000000..508410a
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ *     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, version 2.
+ *
+ */
+
+/*
+       PCM interface to POD series devices.
+*/
+
+#ifndef PCM_H
+#define PCM_H
+
+#include <sound/pcm.h>
+
+#include "driver.h"
+
+/* number of URBs */
+#define LINE6_ISO_BUFFERS      2
+
+/*
+       number of USB frames per URB
+       The Line 6 Windows driver always transmits two frames per packet, but
+       the Linux driver performs significantly better (i.e., lower latency)
+       with only one frame per packet.
+*/
+#define LINE6_ISO_PACKETS      1
+
+/* in a "full speed" device (such as the PODxt Pro) this means 1ms */
+#define LINE6_ISO_INTERVAL     1
+
+#define LINE6_IMPULSE_DEFAULT_PERIOD 100
+
+/*
+       Get substream from Line 6 PCM data structure
+*/
+#define get_substream(line6pcm, stream)        \
+               (line6pcm->pcm->streams[stream].substream)
+
+/*
+       PCM mode bits.
+
+       There are several features of the Line 6 USB driver which require PCM
+       data to be exchanged with the device:
+       *) PCM playback and capture via ALSA
+       *) software monitoring (for devices without hardware monitoring)
+       *) optional impulse response measurement
+       However, from the device's point of view, there is just a single
+       capture and playback stream, which must be shared between these
+       subsystems. It is therefore necessary to maintain the state of the
+       subsystems with respect to PCM usage.
+
+       We define two bit flags, "opened" and "running", for each playback
+       or capture stream.  Both can contain the bit flag corresponding to
+       LINE6_STREAM_* type,
+         LINE6_STREAM_PCM = ALSA PCM playback or capture
+         LINE6_STREAM_MONITOR = software monitoring
+         IMPULSE = optional impulse response measurement
+       The opened flag indicates whether the buffer is allocated while
+       the running flag indicates whether the stream is running.
+
+       For monitor or impulse operations, the driver needs to call
+       line6_pcm_acquire() or line6_pcm_release() with the appropriate
+       LINE6_STREAM_* flag.
+*/
+
+/* stream types */
+enum {
+       LINE6_STREAM_PCM,
+       LINE6_STREAM_MONITOR,
+       LINE6_STREAM_IMPULSE,
+};
+
+/* misc bit flags for PCM operation */
+enum {
+       LINE6_FLAG_PAUSE_PLAYBACK,
+       LINE6_FLAG_PREPARED,
+};
+
+struct line6_pcm_properties {
+       struct snd_pcm_hardware playback_hw, capture_hw;
+       struct snd_pcm_hw_constraint_ratdens rates;
+       int bytes_per_frame;
+};
+
+struct line6_pcm_stream {
+       /* allocated URBs */
+       struct urb *urbs[LINE6_ISO_BUFFERS];
+
+       /* Temporary buffer;
+        * Since the packet size is not known in advance, this buffer is
+        * large enough to store maximum size packets.
+        */
+       unsigned char *buffer;
+
+       /* Free frame position in the buffer. */
+       snd_pcm_uframes_t pos;
+
+       /* Count processed bytes;
+        * This is modulo period size (to determine when a period is finished).
+        */
+       unsigned bytes;
+
+       /* Counter to create desired sample rate */
+       unsigned count;
+
+       /* period size in bytes */
+       unsigned period;
+
+       /* Processed frame position in the buffer;
+        * The contents of the ring buffer have been consumed by the USB
+        * subsystem (i.e., sent to the USB device) up to this position.
+        */
+       snd_pcm_uframes_t pos_done;
+
+       /* Bit mask of active URBs */
+       unsigned long active_urbs;
+
+       /* Bit mask of URBs currently being unlinked */
+       unsigned long unlink_urbs;
+
+       /* Spin lock to protect updates of the buffer positions (not contents)
+        */
+       spinlock_t lock;
+
+       /* Bit flags for operational stream types */
+       unsigned long opened;
+
+       /* Bit flags for running stream types */
+       unsigned long running;
+
+       int last_frame;
+};
+
+struct snd_line6_pcm {
+       /* Pointer back to the Line 6 driver data structure */
+       struct usb_line6 *line6;
+
+       /* Properties. */
+       struct line6_pcm_properties *properties;
+
+       /* ALSA pcm stream */
+       struct snd_pcm *pcm;
+
+       /* protection to state changes of in/out streams */
+       struct mutex state_mutex;
+
+       /* Capture and playback streams */
+       struct line6_pcm_stream in;
+       struct line6_pcm_stream out;
+
+       /* Previously captured frame (for software monitoring) */
+       unsigned char *prev_fbuf;
+
+       /* Size of previously captured frame (for software monitoring) */
+       int prev_fsize;
+
+       /* Maximum size of USB packet */
+       int max_packet_size;
+
+       /* PCM playback volume (left and right) */
+       int volume_playback[2];
+
+       /* PCM monitor volume */
+       int volume_monitor;
+
+       /* Volume of impulse response test signal (if zero, test is disabled) */
+       int impulse_volume;
+
+       /* Period of impulse response test signal */
+       int impulse_period;
+
+       /* Counter for impulse response test signal */
+       int impulse_count;
+
+       /* Several status bits (see LINE6_FLAG_*) */
+       unsigned long flags;
+};
+
+extern int line6_init_pcm(struct usb_line6 *line6,
+                         struct line6_pcm_properties *properties);
+extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd);
+extern int snd_line6_prepare(struct snd_pcm_substream *substream);
+extern int snd_line6_hw_params(struct snd_pcm_substream *substream,
+                              struct snd_pcm_hw_params *hw_params);
+extern int snd_line6_hw_free(struct snd_pcm_substream *substream);
+extern snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream);
+extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm);
+extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type);
+extern void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type);
+
+#endif
diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c
new file mode 100644 (file)
index 0000000..05dee69
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ *     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, version 2.
+ *
+ */
+
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "capture.h"
+#include "driver.h"
+#include "pcm.h"
+#include "playback.h"
+
+/*
+       Software stereo volume control.
+*/
+static void change_volume(struct urb *urb_out, int volume[],
+                         int bytes_per_frame)
+{
+       int chn = 0;
+
+       if (volume[0] == 256 && volume[1] == 256)
+               return;         /* maximum volume - no change */
+
+       if (bytes_per_frame == 4) {
+               __le16 *p, *buf_end;
+
+               p = (__le16 *)urb_out->transfer_buffer;
+               buf_end = p + urb_out->transfer_buffer_length / sizeof(*p);
+
+               for (; p < buf_end; ++p) {
+                       short pv = le16_to_cpu(*p);
+                       int val = (pv * volume[chn & 1]) >> 8;
+                       pv = clamp(val, 0x7fff, -0x8000);
+                       *p = cpu_to_le16(pv);
+                       ++chn;
+               }
+       } else if (bytes_per_frame == 6) {
+               unsigned char *p, *buf_end;
+
+               p = (unsigned char *)urb_out->transfer_buffer;
+               buf_end = p + urb_out->transfer_buffer_length;
+
+               for (; p < buf_end; p += 3) {
+                       int val;
+
+                       val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16);
+                       val = (val * volume[chn & 1]) >> 8;
+                       val = clamp(val, 0x7fffff, -0x800000);
+                       p[0] = val;
+                       p[1] = val >> 8;
+                       p[2] = val >> 16;
+                       ++chn;
+               }
+       }
+}
+
+/*
+       Create signal for impulse response test.
+*/
+static void create_impulse_test_signal(struct snd_line6_pcm *line6pcm,
+                                      struct urb *urb_out, int bytes_per_frame)
+{
+       int frames = urb_out->transfer_buffer_length / bytes_per_frame;
+
+       if (bytes_per_frame == 4) {
+               int i;
+               short *pi = (short *)line6pcm->prev_fbuf;
+               short *po = (short *)urb_out->transfer_buffer;
+
+               for (i = 0; i < frames; ++i) {
+                       po[0] = pi[0];
+                       po[1] = 0;
+                       pi += 2;
+                       po += 2;
+               }
+       } else if (bytes_per_frame == 6) {
+               int i, j;
+               unsigned char *pi = line6pcm->prev_fbuf;
+               unsigned char *po = urb_out->transfer_buffer;
+
+               for (i = 0; i < frames; ++i) {
+                       for (j = 0; j < bytes_per_frame / 2; ++j)
+                               po[j] = pi[j];
+
+                       for (; j < bytes_per_frame; ++j)
+                               po[j] = 0;
+
+                       pi += bytes_per_frame;
+                       po += bytes_per_frame;
+               }
+       }
+       if (--line6pcm->impulse_count <= 0) {
+               ((unsigned char *)(urb_out->transfer_buffer))[bytes_per_frame -
+                                                             1] =
+                   line6pcm->impulse_volume;
+               line6pcm->impulse_count = line6pcm->impulse_period;
+       }
+}
+
+/*
+       Add signal to buffer for software monitoring.
+*/
+static void add_monitor_signal(struct urb *urb_out, unsigned char *signal,
+                              int volume, int bytes_per_frame)
+{
+       if (volume == 0)
+               return;         /* zero volume - no change */
+
+       if (bytes_per_frame == 4) {
+               __le16 *pi, *po, *buf_end;
+
+               pi = (__le16 *)signal;
+               po = (__le16 *)urb_out->transfer_buffer;
+               buf_end = po + urb_out->transfer_buffer_length / sizeof(*po);
+
+               for (; po < buf_end; ++pi, ++po) {
+                       short pov = le16_to_cpu(*po);
+                       short piv = le16_to_cpu(*pi);
+                       int val = pov + ((piv * volume) >> 8);
+                       pov = clamp(val, 0x7fff, -0x8000);
+                       *po = cpu_to_le16(pov);
+               }
+       }
+
+       /*
+          We don't need to handle devices with 6 bytes per frame here
+          since they all support hardware monitoring.
+        */
+}
+
+/*
+       Find a free URB, prepare audio data, and submit URB.
+       must be called in line6pcm->out.lock context
+*/
+static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
+{
+       int index;
+       int i, urb_size, urb_frames;
+       int ret;
+       const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
+       const int frame_increment =
+               line6pcm->properties->rates.rats[0].num_min;
+       const int frame_factor =
+               line6pcm->properties->rates.rats[0].den *
+               (USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL);
+       struct urb *urb_out;
+
+       index =
+           find_first_zero_bit(&line6pcm->out.active_urbs, LINE6_ISO_BUFFERS);
+
+       if (index < 0 || index >= LINE6_ISO_BUFFERS) {
+               dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
+               return -EINVAL;
+       }
+
+       urb_out = line6pcm->out.urbs[index];
+       urb_size = 0;
+
+       for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
+               /* compute frame size for given sampling rate */
+               int fsize = 0;
+               struct usb_iso_packet_descriptor *fout =
+                   &urb_out->iso_frame_desc[i];
+
+               fsize = line6pcm->prev_fsize;
+               if (fsize == 0) {
+                       int n;
+
+                       line6pcm->out.count += frame_increment;
+                       n = line6pcm->out.count / frame_factor;
+                       line6pcm->out.count -= n * frame_factor;
+                       fsize = n * bytes_per_frame;
+               }
+
+               fout->offset = urb_size;
+               fout->length = fsize;
+               urb_size += fsize;
+       }
+
+       if (urb_size == 0) {
+               /* can't determine URB size */
+               dev_err(line6pcm->line6->ifcdev, "driver bug: urb_size = 0\n");
+               return -EINVAL;
+       }
+
+       urb_frames = urb_size / bytes_per_frame;
+       urb_out->transfer_buffer =
+           line6pcm->out.buffer +
+           index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
+       urb_out->transfer_buffer_length = urb_size;
+       urb_out->context = line6pcm;
+
+       if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running) &&
+           !test_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags)) {
+               struct snd_pcm_runtime *runtime =
+                   get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime;
+
+               if (line6pcm->out.pos + urb_frames > runtime->buffer_size) {
+                       /*
+                          The transferred area goes over buffer boundary,
+                          copy the data to the temp buffer.
+                        */
+                       int len;
+
+                       len = runtime->buffer_size - line6pcm->out.pos;
+
+                       if (len > 0) {
+                               memcpy(urb_out->transfer_buffer,
+                                      runtime->dma_area +
+                                      line6pcm->out.pos * bytes_per_frame,
+                                      len * bytes_per_frame);
+                               memcpy(urb_out->transfer_buffer +
+                                      len * bytes_per_frame, runtime->dma_area,
+                                      (urb_frames - len) * bytes_per_frame);
+                       } else
+                               dev_err(line6pcm->line6->ifcdev, "driver bug: len = %d\n",
+                                       len);
+               } else {
+                       memcpy(urb_out->transfer_buffer,
+                              runtime->dma_area +
+                              line6pcm->out.pos * bytes_per_frame,
+                              urb_out->transfer_buffer_length);
+               }
+
+               line6pcm->out.pos += urb_frames;
+               if (line6pcm->out.pos >= runtime->buffer_size)
+                       line6pcm->out.pos -= runtime->buffer_size;
+
+               change_volume(urb_out, line6pcm->volume_playback,
+                             bytes_per_frame);
+       } else {
+               memset(urb_out->transfer_buffer, 0,
+                      urb_out->transfer_buffer_length);
+       }
+
+       spin_lock_nested(&line6pcm->in.lock, SINGLE_DEPTH_NESTING);
+       if (line6pcm->prev_fbuf) {
+               if (test_bit(LINE6_STREAM_IMPULSE, &line6pcm->out.running)) {
+                       create_impulse_test_signal(line6pcm, urb_out,
+                                                  bytes_per_frame);
+                       if (test_bit(LINE6_STREAM_PCM, &line6pcm->in.running)) {
+                               line6_capture_copy(line6pcm,
+                                                  urb_out->transfer_buffer,
+                                                  urb_out->
+                                                  transfer_buffer_length);
+                               line6_capture_check_period(line6pcm,
+                                       urb_out->transfer_buffer_length);
+                       }
+               } else {
+                       if (!(line6pcm->line6->properties->capabilities & LINE6_CAP_HWMON)
+                           && line6pcm->out.running && line6pcm->in.running)
+                               add_monitor_signal(urb_out, line6pcm->prev_fbuf,
+                                                  line6pcm->volume_monitor,
+                                                  bytes_per_frame);
+               }
+               line6pcm->prev_fbuf = NULL;
+               line6pcm->prev_fsize = 0;
+       }
+       spin_unlock(&line6pcm->in.lock);
+
+       ret = usb_submit_urb(urb_out, GFP_ATOMIC);
+
+       if (ret == 0)
+               set_bit(index, &line6pcm->out.active_urbs);
+       else
+               dev_err(line6pcm->line6->ifcdev,
+                       "URB out #%d submission failed (%d)\n", index, ret);
+
+       return 0;
+}
+
+/*
+       Submit all currently available playback URBs.
+       must be called in line6pcm->out.lock context
+ */
+int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm)
+{
+       int ret = 0, i;
+
+       for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
+               ret = submit_audio_out_urb(line6pcm);
+               if (ret < 0)
+                       break;
+       }
+
+       return ret;
+}
+
+/*
+       Callback for completed playback URB.
+*/
+static void audio_out_callback(struct urb *urb)
+{
+       int i, index, length = 0, shutdown = 0;
+       unsigned long flags;
+       struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;
+       struct snd_pcm_substream *substream =
+           get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK);
+
+#if USE_CLEAR_BUFFER_WORKAROUND
+       memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
+#endif
+
+       line6pcm->out.last_frame = urb->start_frame;
+
+       /* find index of URB */
+       for (index = 0; index < LINE6_ISO_BUFFERS; index++)
+               if (urb == line6pcm->out.urbs[index])
+                       break;
+
+       if (index >= LINE6_ISO_BUFFERS)
+               return;         /* URB has been unlinked asynchronously */
+
+       for (i = 0; i < LINE6_ISO_PACKETS; i++)
+               length += urb->iso_frame_desc[i].length;
+
+       spin_lock_irqsave(&line6pcm->out.lock, flags);
+
+       if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running)) {
+               struct snd_pcm_runtime *runtime = substream->runtime;
+
+               line6pcm->out.pos_done +=
+                   length / line6pcm->properties->bytes_per_frame;
+
+               if (line6pcm->out.pos_done >= runtime->buffer_size)
+                       line6pcm->out.pos_done -= runtime->buffer_size;
+       }
+
+       clear_bit(index, &line6pcm->out.active_urbs);
+
+       for (i = 0; i < LINE6_ISO_PACKETS; i++)
+               if (urb->iso_frame_desc[i].status == -EXDEV) {
+                       shutdown = 1;
+                       break;
+               }
+
+       if (test_and_clear_bit(index, &line6pcm->out.unlink_urbs))
+               shutdown = 1;
+
+       if (!shutdown) {
+               submit_audio_out_urb(line6pcm);
+
+               if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running)) {
+                       line6pcm->out.bytes += length;
+                       if (line6pcm->out.bytes >= line6pcm->out.period) {
+                               line6pcm->out.bytes %= line6pcm->out.period;
+                               spin_unlock(&line6pcm->out.lock);
+                               snd_pcm_period_elapsed(substream);
+                               spin_lock(&line6pcm->out.lock);
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&line6pcm->out.lock, flags);
+}
+
+/* open playback callback */
+static int snd_line6_playback_open(struct snd_pcm_substream *substream)
+{
+       int err;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+
+       err = snd_pcm_hw_constraint_ratdens(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+                                           &line6pcm->properties->rates);
+       if (err < 0)
+               return err;
+
+       runtime->hw = line6pcm->properties->playback_hw;
+       return 0;
+}
+
+/* close playback callback */
+static int snd_line6_playback_close(struct snd_pcm_substream *substream)
+{
+       return 0;
+}
+
+/* playback operators */
+struct snd_pcm_ops snd_line6_playback_ops = {
+       .open = snd_line6_playback_open,
+       .close = snd_line6_playback_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = snd_line6_hw_params,
+       .hw_free = snd_line6_hw_free,
+       .prepare = snd_line6_prepare,
+       .trigger = snd_line6_trigger,
+       .pointer = snd_line6_pointer,
+};
+
+int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm)
+{
+       struct usb_line6 *line6 = line6pcm->line6;
+       int i;
+
+       /* create audio URBs and fill in constant values: */
+       for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
+               struct urb *urb;
+
+               /* URB for audio out: */
+               urb = line6pcm->out.urbs[i] =
+                   usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
+
+               if (urb == NULL)
+                       return -ENOMEM;
+
+               urb->dev = line6->usbdev;
+               urb->pipe =
+                   usb_sndisocpipe(line6->usbdev,
+                                   line6->properties->ep_audio_w &
+                                   USB_ENDPOINT_NUMBER_MASK);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->start_frame = -1;
+               urb->number_of_packets = LINE6_ISO_PACKETS;
+               urb->interval = LINE6_ISO_INTERVAL;
+               urb->error_count = 0;
+               urb->complete = audio_out_callback;
+       }
+
+       return 0;
+}
diff --git a/sound/usb/line6/playback.h b/sound/usb/line6/playback.h
new file mode 100644 (file)
index 0000000..51fce29
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ *     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, version 2.
+ *
+ */
+
+#ifndef PLAYBACK_H
+#define PLAYBACK_H
+
+#include <sound/pcm.h>
+
+#include "driver.h"
+
+/*
+ * When the TonePort is used with jack in full duplex mode and the outputs are
+ * not connected, the software monitor produces an ugly noise since everything
+ * written to the output buffer (i.e., the input signal) will be repeated in
+ * the next period (sounds like a delay effect). As a workaround, the output
+ * buffer is cleared after the data have been read, but there must be a better
+ * solution. Until one is found, this workaround can be used to fix the
+ * problem.
+ */
+#define USE_CLEAR_BUFFER_WORKAROUND 1
+
+extern struct snd_pcm_ops snd_line6_playback_ops;
+
+extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm);
+extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm);
+
+#endif
diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c
new file mode 100644 (file)
index 0000000..daf81d1
--- /dev/null
@@ -0,0 +1,584 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ *     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, version 2.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+
+#include "capture.h"
+#include "driver.h"
+#include "playback.h"
+
+/*
+       Locate name in binary program dump
+*/
+#define        POD_NAME_OFFSET 0
+#define        POD_NAME_LENGTH 16
+
+/*
+       Other constants
+*/
+#define POD_CONTROL_SIZE 0x80
+#define POD_BUFSIZE_DUMPREQ 7
+#define POD_STARTUP_DELAY 1000
+
+/*
+       Stages of POD startup procedure
+*/
+enum {
+       POD_STARTUP_INIT = 1,
+       POD_STARTUP_VERSIONREQ,
+       POD_STARTUP_WORKQUEUE,
+       POD_STARTUP_SETUP,
+       POD_STARTUP_LAST = POD_STARTUP_SETUP - 1
+};
+
+enum {
+       LINE6_BASSPODXT,
+       LINE6_BASSPODXTLIVE,
+       LINE6_BASSPODXTPRO,
+       LINE6_POCKETPOD,
+       LINE6_PODXT,
+       LINE6_PODXTLIVE_POD,
+       LINE6_PODXTPRO,
+};
+
+struct usb_line6_pod {
+       /* Generic Line 6 USB data */
+       struct usb_line6 line6;
+
+       /* Instrument monitor level */
+       int monitor_level;
+
+       /* Timer for device initialization */
+       struct timer_list startup_timer;
+
+       /* Work handler for device initialization */
+       struct work_struct startup_work;
+
+       /* Current progress in startup procedure */
+       int startup_progress;
+
+       /* Serial number of device */
+       u32 serial_number;
+
+       /* Firmware version (x 100) */
+       int firmware_version;
+
+       /* Device ID */
+       int device_id;
+};
+
+#define POD_SYSEX_CODE 3
+#define POD_BYTES_PER_FRAME 6  /* 24bit audio (stereo) */
+
+/* *INDENT-OFF* */
+
+enum {
+       POD_SYSEX_SAVE      = 0x24,
+       POD_SYSEX_SYSTEM    = 0x56,
+       POD_SYSEX_SYSTEMREQ = 0x57,
+       /* POD_SYSEX_UPDATE    = 0x6c, */  /* software update! */
+       POD_SYSEX_STORE     = 0x71,
+       POD_SYSEX_FINISH    = 0x72,
+       POD_SYSEX_DUMPMEM   = 0x73,
+       POD_SYSEX_DUMP      = 0x74,
+       POD_SYSEX_DUMPREQ   = 0x75
+
+       /* dumps entire internal memory of PODxt Pro */
+       /* POD_SYSEX_DUMPMEM2  = 0x76 */
+};
+
+enum {
+       POD_MONITOR_LEVEL  = 0x04,
+       POD_SYSTEM_INVALID = 0x10000
+};
+
+/* *INDENT-ON* */
+
+enum {
+       POD_DUMP_MEMORY = 2
+};
+
+enum {
+       POD_BUSY_READ,
+       POD_BUSY_WRITE,
+       POD_CHANNEL_DIRTY,
+       POD_SAVE_PRESSED,
+       POD_BUSY_MIDISEND
+};
+
+static struct snd_ratden pod_ratden = {
+       .num_min = 78125,
+       .num_max = 78125,
+       .num_step = 1,
+       .den = 2
+};
+
+static struct line6_pcm_properties pod_pcm_properties = {
+       .playback_hw = {
+                                 .info = (SNDRV_PCM_INFO_MMAP |
+                                          SNDRV_PCM_INFO_INTERLEAVED |
+                                          SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                                          SNDRV_PCM_INFO_MMAP_VALID |
+                                          SNDRV_PCM_INFO_PAUSE |
+                                          SNDRV_PCM_INFO_SYNC_START),
+                                 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                 .rates = SNDRV_PCM_RATE_KNOT,
+                                 .rate_min = 39062,
+                                 .rate_max = 39063,
+                                 .channels_min = 2,
+                                 .channels_max = 2,
+                                 .buffer_bytes_max = 60000,
+                                 .period_bytes_min = 64,
+                                 .period_bytes_max = 8192,
+                                 .periods_min = 1,
+                                 .periods_max = 1024},
+       .capture_hw = {
+                                .info = (SNDRV_PCM_INFO_MMAP |
+                                         SNDRV_PCM_INFO_INTERLEAVED |
+                                         SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                                         SNDRV_PCM_INFO_MMAP_VALID |
+                                         SNDRV_PCM_INFO_SYNC_START),
+                                .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                .rates = SNDRV_PCM_RATE_KNOT,
+                                .rate_min = 39062,
+                                .rate_max = 39063,
+                                .channels_min = 2,
+                                .channels_max = 2,
+                                .buffer_bytes_max = 60000,
+                                .period_bytes_min = 64,
+                                .period_bytes_max = 8192,
+                                .periods_min = 1,
+                                .periods_max = 1024},
+       .rates = {
+                           .nrats = 1,
+                           .rats = &pod_ratden},
+       .bytes_per_frame = POD_BYTES_PER_FRAME
+};
+
+static const char pod_version_header[] = {
+       0xf2, 0x7e, 0x7f, 0x06, 0x02
+};
+
+/* forward declarations: */
+static void pod_startup2(unsigned long data);
+static void pod_startup3(struct usb_line6_pod *pod);
+
+static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code,
+                                   int size)
+{
+       return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code,
+                                       size);
+}
+
+/*
+       Process a completely received message.
+*/
+static void line6_pod_process_message(struct usb_line6 *line6)
+{
+       struct usb_line6_pod *pod = (struct usb_line6_pod *) line6;
+       const unsigned char *buf = pod->line6.buffer_message;
+
+       if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) {
+               pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15];
+               pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) |
+                                (int) buf[10];
+               pod_startup3(pod);
+               return;
+       }
+
+       /* Only look for sysex messages from this device */
+       if (buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE) &&
+           buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN)) {
+               return;
+       }
+       if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) != 0)
+               return;
+
+       if (buf[5] == POD_SYSEX_SYSTEM && buf[6] == POD_MONITOR_LEVEL) {
+               short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) |
+                             ((int)buf[9] << 4) | (int)buf[10];
+               pod->monitor_level = value;
+       }
+}
+
+/*
+       Send system parameter (from integer).
+*/
+static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
+                                   int code)
+{
+       char *sysex;
+       static const int size = 5;
+
+       sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
+       if (!sysex)
+               return -ENOMEM;
+       sysex[SYSEX_DATA_OFS] = code;
+       sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f;
+       sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f;
+       sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f;
+       sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f;
+       line6_send_sysex_message(&pod->line6, sysex, size);
+       kfree(sysex);
+       return 0;
+}
+
+/*
+       "read" request on "serial_number" special file.
+*/
+static ssize_t serial_number_show(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct usb_interface *interface = to_usb_interface(dev);
+       struct usb_line6_pod *pod = usb_get_intfdata(interface);
+
+       return sprintf(buf, "%u\n", pod->serial_number);
+}
+
+/*
+       "read" request on "firmware_version" special file.
+*/
+static ssize_t firmware_version_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct usb_interface *interface = to_usb_interface(dev);
+       struct usb_line6_pod *pod = usb_get_intfdata(interface);
+
+       return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
+                      pod->firmware_version % 100);
+}
+
+/*
+       "read" request on "device_id" special file.
+*/
+static ssize_t device_id_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct usb_interface *interface = to_usb_interface(dev);
+       struct usb_line6_pod *pod = usb_get_intfdata(interface);
+
+       return sprintf(buf, "%d\n", pod->device_id);
+}
+
+/*
+       POD startup procedure.
+       This is a sequence of functions with special requirements (e.g., must
+       not run immediately after initialization, must not run in interrupt
+       context). After the last one has finished, the device is ready to use.
+*/
+
+static void pod_startup1(struct usb_line6_pod *pod)
+{
+       CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT);
+
+       /* delay startup procedure: */
+       line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
+                         (unsigned long)pod);
+}
+
+static void pod_startup2(unsigned long data)
+{
+       struct usb_line6_pod *pod = (struct usb_line6_pod *)data;
+       struct usb_line6 *line6 = &pod->line6;
+
+       CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ);
+
+       /* request firmware version: */
+       line6_version_request_async(line6);
+}
+
+static void pod_startup3(struct usb_line6_pod *pod)
+{
+       CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE);
+
+       /* schedule work for global work queue: */
+       schedule_work(&pod->startup_work);
+}
+
+static void pod_startup4(struct work_struct *work)
+{
+       struct usb_line6_pod *pod =
+           container_of(work, struct usb_line6_pod, startup_work);
+       struct usb_line6 *line6 = &pod->line6;
+
+       CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP);
+
+       /* serial number: */
+       line6_read_serial_number(&pod->line6, &pod->serial_number);
+
+       /* ALSA audio interface: */
+       snd_card_register(line6->card);
+}
+
+/* POD special files: */
+static DEVICE_ATTR_RO(device_id);
+static DEVICE_ATTR_RO(firmware_version);
+static DEVICE_ATTR_RO(serial_number);
+
+static struct attribute *pod_dev_attrs[] = {
+       &dev_attr_device_id.attr,
+       &dev_attr_firmware_version.attr,
+       &dev_attr_serial_number.attr,
+       NULL
+};
+
+static const struct attribute_group pod_dev_attr_group = {
+       .name = "pod",
+       .attrs = pod_dev_attrs,
+};
+
+/* control info callback */
+static int snd_pod_control_monitor_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 = 65535;
+       return 0;
+}
+
+/* control get callback */
+static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+       struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
+
+       ucontrol->value.integer.value[0] = pod->monitor_level;
+       return 0;
+}
+
+/* control put callback */
+static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+       struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
+
+       if (ucontrol->value.integer.value[0] == pod->monitor_level)
+               return 0;
+
+       pod->monitor_level = ucontrol->value.integer.value[0];
+       pod_set_system_param_int(pod, ucontrol->value.integer.value[0],
+                                POD_MONITOR_LEVEL);
+       return 1;
+}
+
+/* control definition */
+static struct snd_kcontrol_new pod_control_monitor = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Monitor Playback Volume",
+       .index = 0,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info = snd_pod_control_monitor_info,
+       .get = snd_pod_control_monitor_get,
+       .put = snd_pod_control_monitor_put
+};
+
+/*
+       POD device disconnected.
+*/
+static void line6_pod_disconnect(struct usb_line6 *line6)
+{
+       struct usb_line6_pod *pod = (struct usb_line6_pod *)line6;
+
+       del_timer_sync(&pod->startup_timer);
+       cancel_work_sync(&pod->startup_work);
+}
+
+/*
+        Try to init POD device.
+*/
+static int pod_init(struct usb_line6 *line6,
+                   const struct usb_device_id *id)
+{
+       int err;
+       struct usb_line6_pod *pod = (struct usb_line6_pod *) line6;
+
+       line6->process_message = line6_pod_process_message;
+       line6->disconnect = line6_pod_disconnect;
+
+       init_timer(&pod->startup_timer);
+       INIT_WORK(&pod->startup_work, pod_startup4);
+
+       /* create sysfs entries: */
+       err = snd_card_add_dev_attr(line6->card, &pod_dev_attr_group);
+       if (err < 0)
+               return err;
+
+       /* initialize MIDI subsystem: */
+       err = line6_init_midi(line6);
+       if (err < 0)
+               return err;
+
+       /* initialize PCM subsystem: */
+       err = line6_init_pcm(line6, &pod_pcm_properties);
+       if (err < 0)
+               return err;
+
+       /* register monitor control: */
+       err = snd_ctl_add(line6->card,
+                         snd_ctl_new1(&pod_control_monitor, line6->line6pcm));
+       if (err < 0)
+               return err;
+
+       /*
+          When the sound card is registered at this point, the PODxt Live
+          displays "Invalid Code Error 07", so we do it later in the event
+          handler.
+        */
+
+       if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) {
+               pod->monitor_level = POD_SYSTEM_INVALID;
+
+               /* initiate startup procedure: */
+               pod_startup1(pod);
+       }
+
+       return 0;
+}
+
+#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
+#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
+
+/* table of devices that work with this driver */
+static const struct usb_device_id pod_id_table[] = {
+       { LINE6_DEVICE(0x4250),    .driver_info = LINE6_BASSPODXT },
+       { LINE6_DEVICE(0x4642),    .driver_info = LINE6_BASSPODXTLIVE },
+       { LINE6_DEVICE(0x4252),    .driver_info = LINE6_BASSPODXTPRO },
+       { LINE6_IF_NUM(0x5051, 1), .driver_info = LINE6_POCKETPOD },
+       { LINE6_DEVICE(0x5044),    .driver_info = LINE6_PODXT },
+       { LINE6_IF_NUM(0x4650, 0), .driver_info = LINE6_PODXTLIVE_POD },
+       { LINE6_DEVICE(0x5050),    .driver_info = LINE6_PODXTPRO },
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, pod_id_table);
+
+static const struct line6_properties pod_properties_table[] = {
+       [LINE6_BASSPODXT] = {
+               .id = "BassPODxt",
+               .name = "BassPODxt",
+               .capabilities   = LINE6_CAP_CONTROL
+                               | LINE6_CAP_PCM
+                               | LINE6_CAP_HWMON,
+               .altsetting = 5,
+               .ep_ctrl_r = 0x84,
+               .ep_ctrl_w = 0x03,
+               .ep_audio_r = 0x82,
+               .ep_audio_w = 0x01,
+       },
+       [LINE6_BASSPODXTLIVE] = {
+               .id = "BassPODxtLive",
+               .name = "BassPODxt Live",
+               .capabilities   = LINE6_CAP_CONTROL
+                               | LINE6_CAP_PCM
+                               | LINE6_CAP_HWMON,
+               .altsetting = 1,
+               .ep_ctrl_r = 0x84,
+               .ep_ctrl_w = 0x03,
+               .ep_audio_r = 0x82,
+               .ep_audio_w = 0x01,
+       },
+       [LINE6_BASSPODXTPRO] = {
+               .id = "BassPODxtPro",
+               .name = "BassPODxt Pro",
+               .capabilities   = LINE6_CAP_CONTROL
+                               | LINE6_CAP_PCM
+                               | LINE6_CAP_HWMON,
+               .altsetting = 5,
+               .ep_ctrl_r = 0x84,
+               .ep_ctrl_w = 0x03,
+               .ep_audio_r = 0x82,
+               .ep_audio_w = 0x01,
+       },
+       [LINE6_POCKETPOD] = {
+               .id = "PocketPOD",
+               .name = "Pocket POD",
+               .capabilities   = LINE6_CAP_CONTROL,
+               .altsetting = 0,
+               .ep_ctrl_r = 0x82,
+               .ep_ctrl_w = 0x02,
+               /* no audio channel */
+       },
+       [LINE6_PODXT] = {
+               .id = "PODxt",
+               .name = "PODxt",
+               .capabilities   = LINE6_CAP_CONTROL
+                               | LINE6_CAP_PCM
+                               | LINE6_CAP_HWMON,
+               .altsetting = 5,
+               .ep_ctrl_r = 0x84,
+               .ep_ctrl_w = 0x03,
+               .ep_audio_r = 0x82,
+               .ep_audio_w = 0x01,
+       },
+       [LINE6_PODXTLIVE_POD] = {
+               .id = "PODxtLive",
+               .name = "PODxt Live",
+               .capabilities   = LINE6_CAP_CONTROL
+                               | LINE6_CAP_PCM
+                               | LINE6_CAP_HWMON,
+               .altsetting = 1,
+               .ep_ctrl_r = 0x84,
+               .ep_ctrl_w = 0x03,
+               .ep_audio_r = 0x82,
+               .ep_audio_w = 0x01,
+       },
+       [LINE6_PODXTPRO] = {
+               .id = "PODxtPro",
+               .name = "PODxt Pro",
+               .capabilities   = LINE6_CAP_CONTROL
+                               | LINE6_CAP_PCM
+                               | LINE6_CAP_HWMON,
+               .altsetting = 5,
+               .ep_ctrl_r = 0x84,
+               .ep_ctrl_w = 0x03,
+               .ep_audio_r = 0x82,
+               .ep_audio_w = 0x01,
+       },
+};
+
+/*
+       Probe USB device.
+*/
+static int pod_probe(struct usb_interface *interface,
+                    const struct usb_device_id *id)
+{
+       return line6_probe(interface, id, "Line6-POD",
+                          &pod_properties_table[id->driver_info],
+                          pod_init, sizeof(struct usb_line6_pod));
+}
+
+static struct usb_driver pod_driver = {
+       .name = KBUILD_MODNAME,
+       .probe = pod_probe,
+       .disconnect = line6_disconnect,
+#ifdef CONFIG_PM
+       .suspend = line6_suspend,
+       .resume = line6_resume,
+       .reset_resume = line6_resume,
+#endif
+       .id_table = pod_id_table,
+};
+
+module_usb_driver(pod_driver);
+
+MODULE_DESCRIPTION("Line 6 POD USB driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c
new file mode 100644 (file)
index 0000000..63dcaef
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Line 6 Pod HD
+ *
+ * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+#include "driver.h"
+#include "pcm.h"
+
+enum {
+       LINE6_PODHD300,
+       LINE6_PODHD400,
+       LINE6_PODHD500_0,
+       LINE6_PODHD500_1,
+};
+
+#define PODHD_BYTES_PER_FRAME 6        /* 24bit audio (stereo) */
+
+static struct snd_ratden podhd_ratden = {
+       .num_min = 48000,
+       .num_max = 48000,
+       .num_step = 1,
+       .den = 1,
+};
+
+static struct line6_pcm_properties podhd_pcm_properties = {
+       .playback_hw = {
+                                 .info = (SNDRV_PCM_INFO_MMAP |
+                                          SNDRV_PCM_INFO_INTERLEAVED |
+                                          SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                                          SNDRV_PCM_INFO_MMAP_VALID |
+                                          SNDRV_PCM_INFO_PAUSE |
+                                          SNDRV_PCM_INFO_SYNC_START),
+                                 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                 .rates = SNDRV_PCM_RATE_48000,
+                                 .rate_min = 48000,
+                                 .rate_max = 48000,
+                                 .channels_min = 2,
+                                 .channels_max = 2,
+                                 .buffer_bytes_max = 60000,
+                                 .period_bytes_min = 64,
+                                 .period_bytes_max = 8192,
+                                 .periods_min = 1,
+                                 .periods_max = 1024},
+       .capture_hw = {
+                                .info = (SNDRV_PCM_INFO_MMAP |
+                                         SNDRV_PCM_INFO_INTERLEAVED |
+                                         SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                                         SNDRV_PCM_INFO_MMAP_VALID |
+                                         SNDRV_PCM_INFO_SYNC_START),
+                                .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                .rates = SNDRV_PCM_RATE_48000,
+                                .rate_min = 48000,
+                                .rate_max = 48000,
+                                .channels_min = 2,
+                                .channels_max = 2,
+                                .buffer_bytes_max = 60000,
+                                .period_bytes_min = 64,
+                                .period_bytes_max = 8192,
+                                .periods_min = 1,
+                                .periods_max = 1024},
+       .rates = {
+                           .nrats = 1,
+                           .rats = &podhd_ratden},
+       .bytes_per_frame = PODHD_BYTES_PER_FRAME
+};
+
+/*
+       Try to init POD HD device.
+*/
+static int podhd_init(struct usb_line6 *line6,
+                     const struct usb_device_id *id)
+{
+       int err;
+
+       /* initialize MIDI subsystem: */
+       err = line6_init_midi(line6);
+       if (err < 0)
+               return err;
+
+       /* initialize PCM subsystem: */
+       err = line6_init_pcm(line6, &podhd_pcm_properties);
+       if (err < 0)
+               return err;
+
+       /* register USB audio system: */
+       return snd_card_register(line6->card);
+}
+
+#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
+#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
+
+/* table of devices that work with this driver */
+static const struct usb_device_id podhd_id_table[] = {
+       { LINE6_DEVICE(0x5057),    .driver_info = LINE6_PODHD300 },
+       { LINE6_DEVICE(0x5058),    .driver_info = LINE6_PODHD400 },
+       { LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500_0 },
+       { LINE6_IF_NUM(0x414D, 1), .driver_info = LINE6_PODHD500_1 },
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, podhd_id_table);
+
+static const struct line6_properties podhd_properties_table[] = {
+       [LINE6_PODHD300] = {
+               .id = "PODHD300",
+               .name = "POD HD300",
+               .capabilities   = LINE6_CAP_CONTROL
+                               | LINE6_CAP_PCM
+                               | LINE6_CAP_HWMON,
+               .altsetting = 5,
+               .ep_ctrl_r = 0x84,
+               .ep_ctrl_w = 0x03,
+               .ep_audio_r = 0x82,
+               .ep_audio_w = 0x01,
+       },
+       [LINE6_PODHD400] = {
+               .id = "PODHD400",
+               .name = "POD HD400",
+               .capabilities   = LINE6_CAP_CONTROL
+                               | LINE6_CAP_PCM
+                               | LINE6_CAP_HWMON,
+               .altsetting = 5,
+               .ep_ctrl_r = 0x84,
+               .ep_ctrl_w = 0x03,
+               .ep_audio_r = 0x82,
+               .ep_audio_w = 0x01,
+       },
+       [LINE6_PODHD500_0] = {
+               .id = "PODHD500",
+               .name = "POD HD500",
+               .capabilities   = LINE6_CAP_CONTROL
+                               | LINE6_CAP_PCM
+                               | LINE6_CAP_HWMON,
+               .altsetting = 1,
+               .ep_ctrl_r = 0x81,
+               .ep_ctrl_w = 0x01,
+               .ep_audio_r = 0x86,
+               .ep_audio_w = 0x02,
+       },
+       [LINE6_PODHD500_1] = {
+               .id = "PODHD500",
+               .name = "POD HD500",
+               .capabilities   = LINE6_CAP_CONTROL
+                               | LINE6_CAP_PCM
+                               | LINE6_CAP_HWMON,
+               .altsetting = 1,
+               .ep_ctrl_r = 0x81,
+               .ep_ctrl_w = 0x01,
+               .ep_audio_r = 0x86,
+               .ep_audio_w = 0x02,
+       },
+};
+
+/*
+       Probe USB device.
+*/
+static int podhd_probe(struct usb_interface *interface,
+                      const struct usb_device_id *id)
+{
+       return line6_probe(interface, id, "Line6-PODHD",
+                          &podhd_properties_table[id->driver_info],
+                          podhd_init, sizeof(struct usb_line6));
+}
+
+static struct usb_driver podhd_driver = {
+       .name = KBUILD_MODNAME,
+       .probe = podhd_probe,
+       .disconnect = line6_disconnect,
+#ifdef CONFIG_PM
+       .suspend = line6_suspend,
+       .resume = line6_resume,
+       .reset_resume = line6_resume,
+#endif
+       .id_table = podhd_id_table,
+};
+
+module_usb_driver(podhd_driver);
+
+MODULE_DESCRIPTION("Line 6 PODHD USB driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c
new file mode 100644 (file)
index 0000000..6d4c50c
--- /dev/null
@@ -0,0 +1,580 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *                         Emil Myhrman (emil.myhrman@gmail.com)
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include <linux/wait.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/leds.h>
+#include <sound/core.h>
+#include <sound/control.h>
+
+#include "capture.h"
+#include "driver.h"
+#include "playback.h"
+
+enum line6_device_type {
+       LINE6_GUITARPORT,
+       LINE6_PODSTUDIO_GX,
+       LINE6_PODSTUDIO_UX1,
+       LINE6_PODSTUDIO_UX2,
+       LINE6_TONEPORT_GX,
+       LINE6_TONEPORT_UX1,
+       LINE6_TONEPORT_UX2,
+};
+
+struct usb_line6_toneport;
+
+struct toneport_led {
+       struct led_classdev dev;
+       char name[64];
+       struct usb_line6_toneport *toneport;
+       bool registered;
+};
+
+struct usb_line6_toneport {
+       /* Generic Line 6 USB data */
+       struct usb_line6 line6;
+
+       /* Source selector */
+       int source;
+
+       /* Serial number of device */
+       u32 serial_number;
+
+       /* Firmware version (x 100) */
+       u8 firmware_version;
+
+       /* Timer for delayed PCM startup */
+       struct timer_list timer;
+
+       /* Device type */
+       enum line6_device_type type;
+
+       /* LED instances */
+       struct toneport_led leds[2];
+};
+
+static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2);
+
+#define TONEPORT_PCM_DELAY 1
+
+static struct snd_ratden toneport_ratden = {
+       .num_min = 44100,
+       .num_max = 44100,
+       .num_step = 1,
+       .den = 1
+};
+
+static struct line6_pcm_properties toneport_pcm_properties = {
+       .playback_hw = {
+                                 .info = (SNDRV_PCM_INFO_MMAP |
+                                          SNDRV_PCM_INFO_INTERLEAVED |
+                                          SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                                          SNDRV_PCM_INFO_MMAP_VALID |
+                                          SNDRV_PCM_INFO_PAUSE |
+                                          SNDRV_PCM_INFO_SYNC_START),
+                                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                                 .rates = SNDRV_PCM_RATE_KNOT,
+                                 .rate_min = 44100,
+                                 .rate_max = 44100,
+                                 .channels_min = 2,
+                                 .channels_max = 2,
+                                 .buffer_bytes_max = 60000,
+                                 .period_bytes_min = 64,
+                                 .period_bytes_max = 8192,
+                                 .periods_min = 1,
+                                 .periods_max = 1024},
+       .capture_hw = {
+                                .info = (SNDRV_PCM_INFO_MMAP |
+                                         SNDRV_PCM_INFO_INTERLEAVED |
+                                         SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                                         SNDRV_PCM_INFO_MMAP_VALID |
+                                         SNDRV_PCM_INFO_SYNC_START),
+                                .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                                .rates = SNDRV_PCM_RATE_KNOT,
+                                .rate_min = 44100,
+                                .rate_max = 44100,
+                                .channels_min = 2,
+                                .channels_max = 2,
+                                .buffer_bytes_max = 60000,
+                                .period_bytes_min = 64,
+                                .period_bytes_max = 8192,
+                                .periods_min = 1,
+                                .periods_max = 1024},
+       .rates = {
+                           .nrats = 1,
+                           .rats = &toneport_ratden},
+       .bytes_per_frame = 4
+};
+
+static const struct {
+       const char *name;
+       int code;
+} toneport_source_info[] = {
+       {"Microphone", 0x0a01},
+       {"Line", 0x0801},
+       {"Instrument", 0x0b01},
+       {"Inst & Mic", 0x0901}
+};
+
+static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)
+{
+       int ret;
+
+       ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
+                             USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+                             cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ);
+
+       if (ret < 0) {
+               dev_err(&usbdev->dev, "send failed (error %d)\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+/* monitor info callback */
+static int snd_toneport_monitor_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 = 256;
+       return 0;
+}
+
+/* monitor get callback */
+static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = line6pcm->volume_monitor;
+       return 0;
+}
+
+/* monitor put callback */
+static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+       int err;
+
+       if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor)
+               return 0;
+
+       line6pcm->volume_monitor = ucontrol->value.integer.value[0];
+
+       if (line6pcm->volume_monitor > 0) {
+               err = line6_pcm_acquire(line6pcm, LINE6_STREAM_MONITOR);
+               if (err < 0) {
+                       line6pcm->volume_monitor = 0;
+                       line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR);
+                       return err;
+               }
+       } else {
+               line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR);
+       }
+
+       return 1;
+}
+
+/* source info callback */
+static int snd_toneport_source_info(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_info *uinfo)
+{
+       const int size = ARRAY_SIZE(toneport_source_info);
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = size;
+
+       if (uinfo->value.enumerated.item >= size)
+               uinfo->value.enumerated.item = size - 1;
+
+       strcpy(uinfo->value.enumerated.name,
+              toneport_source_info[uinfo->value.enumerated.item].name);
+
+       return 0;
+}
+
+/* source get callback */
+static int snd_toneport_source_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+       struct usb_line6_toneport *toneport =
+           (struct usb_line6_toneport *)line6pcm->line6;
+       ucontrol->value.enumerated.item[0] = toneport->source;
+       return 0;
+}
+
+/* source put callback */
+static int snd_toneport_source_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+       struct usb_line6_toneport *toneport =
+           (struct usb_line6_toneport *)line6pcm->line6;
+       unsigned int source;
+
+       source = ucontrol->value.enumerated.item[0];
+       if (source >= ARRAY_SIZE(toneport_source_info))
+               return -EINVAL;
+       if (source == toneport->source)
+               return 0;
+
+       toneport->source = source;
+       toneport_send_cmd(toneport->line6.usbdev,
+                         toneport_source_info[source].code, 0x0000);
+       return 1;
+}
+
+static void toneport_start_pcm(unsigned long arg)
+{
+       struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg;
+       struct usb_line6 *line6 = &toneport->line6;
+
+       line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR);
+}
+
+/* control definition */
+static struct snd_kcontrol_new toneport_control_monitor = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Monitor Playback Volume",
+       .index = 0,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info = snd_toneport_monitor_info,
+       .get = snd_toneport_monitor_get,
+       .put = snd_toneport_monitor_put
+};
+
+/* source selector definition */
+static struct snd_kcontrol_new toneport_control_source = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "PCM Capture Source",
+       .index = 0,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info = snd_toneport_source_info,
+       .get = snd_toneport_source_get,
+       .put = snd_toneport_source_put
+};
+
+/*
+       For the led on Guitarport.
+       Brightness goes from 0x00 to 0x26. Set a value above this to have led
+       blink.
+       (void cmd_0x02(byte red, byte green)
+*/
+
+static bool toneport_has_led(struct usb_line6_toneport *toneport)
+{
+       switch (toneport->type) {
+       case LINE6_GUITARPORT:
+       case LINE6_TONEPORT_GX:
+       /* add your device here if you are missing support for the LEDs */
+               return true;
+
+       default:
+               return false;
+       }
+}
+
+static const char * const led_colors[2] = { "red", "green" };
+static const int led_init_vals[2] = { 0x00, 0x26 };
+
+static void toneport_update_led(struct usb_line6_toneport *toneport)
+{
+       toneport_send_cmd(toneport->line6.usbdev,
+                         (toneport->leds[0].dev.brightness << 8) | 0x0002,
+                         toneport->leds[1].dev.brightness);
+}
+
+static void toneport_led_brightness_set(struct led_classdev *led_cdev,
+                                       enum led_brightness brightness)
+{
+       struct toneport_led *leds =
+               container_of(led_cdev, struct toneport_led, dev);
+       toneport_update_led(leds->toneport);
+}
+
+static int toneport_init_leds(struct usb_line6_toneport *toneport)
+{
+       struct device *dev = &toneport->line6.usbdev->dev;
+       int i, err;
+
+       for (i = 0; i < 2; i++) {
+               struct toneport_led *led = &toneport->leds[i];
+               struct led_classdev *leddev = &led->dev;
+
+               led->toneport = toneport;
+               snprintf(led->name, sizeof(led->name), "%s::%s",
+                        dev_name(dev), led_colors[i]);
+               leddev->name = led->name;
+               leddev->brightness = led_init_vals[i];
+               leddev->max_brightness = 0x26;
+               leddev->brightness_set = toneport_led_brightness_set;
+               err = led_classdev_register(dev, leddev);
+               if (err)
+                       return err;
+               led->registered = true;
+       }
+
+       return 0;
+}
+
+static void toneport_remove_leds(struct usb_line6_toneport *toneport)
+{
+       struct toneport_led *led;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               led = &toneport->leds[i];
+               if (!led->registered)
+                       break;
+               led_classdev_unregister(&led->dev);
+               led->registered = false;
+       }
+}
+
+static bool toneport_has_source_select(struct usb_line6_toneport *toneport)
+{
+       switch (toneport->type) {
+       case LINE6_TONEPORT_UX1:
+       case LINE6_TONEPORT_UX2:
+       case LINE6_PODSTUDIO_UX1:
+       case LINE6_PODSTUDIO_UX2:
+               return true;
+
+       default:
+               return false;
+       }
+}
+
+/*
+       Setup Toneport device.
+*/
+static void toneport_setup(struct usb_line6_toneport *toneport)
+{
+       int ticks;
+       struct usb_line6 *line6 = &toneport->line6;
+       struct usb_device *usbdev = line6->usbdev;
+
+       /* sync time on device with host: */
+       ticks = (int)get_seconds();
+       line6_write_data(line6, 0x80c6, &ticks, 4);
+
+       /* enable device: */
+       toneport_send_cmd(usbdev, 0x0301, 0x0000);
+
+       /* initialize source select: */
+       if (toneport_has_source_select(toneport))
+               toneport_send_cmd(usbdev,
+                                 toneport_source_info[toneport->source].code,
+                                 0x0000);
+
+       if (toneport_has_led(toneport))
+               toneport_update_led(toneport);
+
+       mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ);
+}
+
+/*
+       Toneport device disconnected.
+*/
+static void line6_toneport_disconnect(struct usb_line6 *line6)
+{
+       struct usb_line6_toneport *toneport =
+               (struct usb_line6_toneport *)line6;
+
+       del_timer_sync(&toneport->timer);
+
+       if (toneport_has_led(toneport))
+               toneport_remove_leds(toneport);
+}
+
+
+/*
+        Try to init Toneport device.
+*/
+static int toneport_init(struct usb_line6 *line6,
+                        const struct usb_device_id *id)
+{
+       int err;
+       struct usb_line6_toneport *toneport =  (struct usb_line6_toneport *) line6;
+
+       toneport->type = id->driver_info;
+       setup_timer(&toneport->timer, toneport_start_pcm,
+                   (unsigned long)toneport);
+
+       line6->disconnect = line6_toneport_disconnect;
+
+       /* initialize PCM subsystem: */
+       err = line6_init_pcm(line6, &toneport_pcm_properties);
+       if (err < 0)
+               return err;
+
+       /* register monitor control: */
+       err = snd_ctl_add(line6->card,
+                         snd_ctl_new1(&toneport_control_monitor,
+                                      line6->line6pcm));
+       if (err < 0)
+               return err;
+
+       /* register source select control: */
+       if (toneport_has_source_select(toneport)) {
+               err =
+                   snd_ctl_add(line6->card,
+                               snd_ctl_new1(&toneport_control_source,
+                                            line6->line6pcm));
+               if (err < 0)
+                       return err;
+       }
+
+       line6_read_serial_number(line6, &toneport->serial_number);
+       line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1);
+
+       if (toneport_has_led(toneport)) {
+               err = toneport_init_leds(toneport);
+               if (err < 0)
+                       return err;
+       }
+
+       toneport_setup(toneport);
+
+       /* register audio system: */
+       return snd_card_register(line6->card);
+}
+
+#ifdef CONFIG_PM
+/*
+       Resume Toneport device after reset.
+*/
+static int toneport_reset_resume(struct usb_interface *interface)
+{
+       toneport_setup(usb_get_intfdata(interface));
+       return line6_resume(interface);
+}
+#endif
+
+#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
+#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
+
+/* table of devices that work with this driver */
+static const struct usb_device_id toneport_id_table[] = {
+       { LINE6_DEVICE(0x4750),    .driver_info = LINE6_GUITARPORT },
+       { LINE6_DEVICE(0x4153),    .driver_info = LINE6_PODSTUDIO_GX },
+       { LINE6_DEVICE(0x4150),    .driver_info = LINE6_PODSTUDIO_UX1 },
+       { LINE6_IF_NUM(0x4151, 0), .driver_info = LINE6_PODSTUDIO_UX2 },
+       { LINE6_DEVICE(0x4147),    .driver_info = LINE6_TONEPORT_GX },
+       { LINE6_DEVICE(0x4141),    .driver_info = LINE6_TONEPORT_UX1 },
+       { LINE6_IF_NUM(0x4142, 0), .driver_info = LINE6_TONEPORT_UX2 },
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, toneport_id_table);
+
+static const struct line6_properties toneport_properties_table[] = {
+       [LINE6_GUITARPORT] = {
+               .id = "GuitarPort",
+               .name = "GuitarPort",
+               .capabilities   = LINE6_CAP_PCM,
+               .altsetting = 2,  /* 1..4 seem to be ok */
+               /* no control channel */
+               .ep_audio_r = 0x82,
+               .ep_audio_w = 0x01,
+       },
+       [LINE6_PODSTUDIO_GX] = {
+               .id = "PODStudioGX",
+               .name = "POD Studio GX",
+               .capabilities   = LINE6_CAP_PCM,
+               .altsetting = 2,  /* 1..4 seem to be ok */
+               /* no control channel */
+               .ep_audio_r = 0x82,
+               .ep_audio_w = 0x01,
+       },
+       [LINE6_PODSTUDIO_UX1] = {
+               .id = "PODStudioUX1",
+               .name = "POD Studio UX1",
+               .capabilities   = LINE6_CAP_PCM,
+               .altsetting = 2,  /* 1..4 seem to be ok */
+               /* no control channel */
+               .ep_audio_r = 0x82,
+               .ep_audio_w = 0x01,
+       },
+       [LINE6_PODSTUDIO_UX2] = {
+               .id = "PODStudioUX2",
+               .name = "POD Studio UX2",
+               .capabilities   = LINE6_CAP_PCM,
+               .altsetting = 2,  /* defaults to 44.1kHz, 16-bit */
+               /* no control channel */
+               .ep_audio_r = 0x82,
+               .ep_audio_w = 0x01,
+       },
+       [LINE6_TONEPORT_GX] = {
+               .id = "TonePortGX",
+               .name = "TonePort GX",
+               .capabilities   = LINE6_CAP_PCM,
+               .altsetting = 2,  /* 1..4 seem to be ok */
+               /* no control channel */
+               .ep_audio_r = 0x82,
+               .ep_audio_w = 0x01,
+       },
+       [LINE6_TONEPORT_UX1] = {
+               .id = "TonePortUX1",
+               .name = "TonePort UX1",
+               .capabilities   = LINE6_CAP_PCM,
+               .altsetting = 2,  /* 1..4 seem to be ok */
+               /* no control channel */
+               .ep_audio_r = 0x82,
+               .ep_audio_w = 0x01,
+       },
+       [LINE6_TONEPORT_UX2] = {
+               .id = "TonePortUX2",
+               .name = "TonePort UX2",
+               .capabilities   = LINE6_CAP_PCM,
+               .altsetting = 2,  /* defaults to 44.1kHz, 16-bit */
+               /* no control channel */
+               .ep_audio_r = 0x82,
+               .ep_audio_w = 0x01,
+       },
+};
+
+/*
+       Probe USB device.
+*/
+static int toneport_probe(struct usb_interface *interface,
+                         const struct usb_device_id *id)
+{
+       return line6_probe(interface, id, "Line6-TonePort",
+                          &toneport_properties_table[id->driver_info],
+                          toneport_init, sizeof(struct usb_line6_toneport));
+}
+
+static struct usb_driver toneport_driver = {
+       .name = KBUILD_MODNAME,
+       .probe = toneport_probe,
+       .disconnect = line6_disconnect,
+#ifdef CONFIG_PM
+       .suspend = line6_suspend,
+       .resume = line6_resume,
+       .reset_resume = toneport_reset_resume,
+#endif
+       .id_table = toneport_id_table,
+};
+
+module_usb_driver(toneport_driver);
+
+MODULE_DESCRIPTION("TonePort USB driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/usb/line6/variax.c b/sound/usb/line6/variax.c
new file mode 100644 (file)
index 0000000..ddc23dd
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ *     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, version 2.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include <sound/core.h>
+
+#include "driver.h"
+
+#define VARIAX_STARTUP_DELAY1 1000
+#define VARIAX_STARTUP_DELAY3 100
+#define VARIAX_STARTUP_DELAY4 100
+
+/*
+       Stages of Variax startup procedure
+*/
+enum {
+       VARIAX_STARTUP_INIT = 1,
+       VARIAX_STARTUP_VERSIONREQ,
+       VARIAX_STARTUP_WAIT,
+       VARIAX_STARTUP_ACTIVATE,
+       VARIAX_STARTUP_WORKQUEUE,
+       VARIAX_STARTUP_SETUP,
+       VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1
+};
+
+enum {
+       LINE6_PODXTLIVE_VARIAX,
+       LINE6_VARIAX
+};
+
+struct usb_line6_variax {
+       /* Generic Line 6 USB data */
+       struct usb_line6 line6;
+
+       /* Buffer for activation code */
+       unsigned char *buffer_activate;
+
+       /* Handler for device initialization */
+       struct work_struct startup_work;
+
+       /* Timers for device initialization */
+       struct timer_list startup_timer1;
+       struct timer_list startup_timer2;
+
+       /* Current progress in startup procedure */
+       int startup_progress;
+};
+
+#define VARIAX_OFFSET_ACTIVATE 7
+
+/*
+       This message is sent by the device during initialization and identifies
+       the connected guitar version.
+*/
+static const char variax_init_version[] = {
+       0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
+       0x07, 0x00, 0x00, 0x00
+};
+
+/*
+       This message is the last one sent by the device during initialization.
+*/
+static const char variax_init_done[] = {
+       0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
+};
+
+static const char variax_activate[] = {
+       0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
+       0xf7
+};
+
+/* forward declarations: */
+static void variax_startup2(unsigned long data);
+static void variax_startup4(unsigned long data);
+static void variax_startup5(unsigned long data);
+
+static void variax_activate_async(struct usb_line6_variax *variax, int a)
+{
+       variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
+       line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
+                                    sizeof(variax_activate));
+}
+
+/*
+       Variax startup procedure.
+       This is a sequence of functions with special requirements (e.g., must
+       not run immediately after initialization, must not run in interrupt
+       context). After the last one has finished, the device is ready to use.
+*/
+
+static void variax_startup1(struct usb_line6_variax *variax)
+{
+       CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);
+
+       /* delay startup procedure: */
+       line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
+                         variax_startup2, (unsigned long)variax);
+}
+
+static void variax_startup2(unsigned long data)
+{
+       struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
+       struct usb_line6 *line6 = &variax->line6;
+
+       /* schedule another startup procedure until startup is complete: */
+       if (variax->startup_progress >= VARIAX_STARTUP_LAST)
+               return;
+
+       variax->startup_progress = VARIAX_STARTUP_VERSIONREQ;
+       line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
+                         variax_startup2, (unsigned long)variax);
+
+       /* request firmware version: */
+       line6_version_request_async(line6);
+}
+
+static void variax_startup3(struct usb_line6_variax *variax)
+{
+       CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);
+
+       /* delay startup procedure: */
+       line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
+                         variax_startup4, (unsigned long)variax);
+}
+
+static void variax_startup4(unsigned long data)
+{
+       struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
+
+       CHECK_STARTUP_PROGRESS(variax->startup_progress,
+                              VARIAX_STARTUP_ACTIVATE);
+
+       /* activate device: */
+       variax_activate_async(variax, 1);
+       line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
+                         variax_startup5, (unsigned long)variax);
+}
+
+static void variax_startup5(unsigned long data)
+{
+       struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
+
+       CHECK_STARTUP_PROGRESS(variax->startup_progress,
+                              VARIAX_STARTUP_WORKQUEUE);
+
+       /* schedule work for global work queue: */
+       schedule_work(&variax->startup_work);
+}
+
+static void variax_startup6(struct work_struct *work)
+{
+       struct usb_line6_variax *variax =
+           container_of(work, struct usb_line6_variax, startup_work);
+
+       CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
+
+       /* ALSA audio interface: */
+       snd_card_register(variax->line6.card);
+}
+
+/*
+       Process a completely received message.
+*/
+static void line6_variax_process_message(struct usb_line6 *line6)
+{
+       struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
+       const unsigned char *buf = variax->line6.buffer_message;
+
+       switch (buf[0]) {
+       case LINE6_RESET:
+               dev_info(variax->line6.ifcdev, "VARIAX reset\n");
+               break;
+
+       case LINE6_SYSEX_BEGIN:
+               if (memcmp(buf + 1, variax_init_version + 1,
+                          sizeof(variax_init_version) - 1) == 0) {
+                       variax_startup3(variax);
+               } else if (memcmp(buf + 1, variax_init_done + 1,
+                                 sizeof(variax_init_done) - 1) == 0) {
+                       /* notify of complete initialization: */
+                       variax_startup4((unsigned long)variax);
+               }
+               break;
+       }
+}
+
+/*
+       Variax destructor.
+*/
+static void line6_variax_disconnect(struct usb_line6 *line6)
+{
+       struct usb_line6_variax *variax = (struct usb_line6_variax *)line6;
+
+       del_timer(&variax->startup_timer1);
+       del_timer(&variax->startup_timer2);
+       cancel_work_sync(&variax->startup_work);
+
+       kfree(variax->buffer_activate);
+}
+
+/*
+        Try to init workbench device.
+*/
+static int variax_init(struct usb_line6 *line6,
+                      const struct usb_device_id *id)
+{
+       struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
+       int err;
+
+       line6->process_message = line6_variax_process_message;
+       line6->disconnect = line6_variax_disconnect;
+
+       init_timer(&variax->startup_timer1);
+       init_timer(&variax->startup_timer2);
+       INIT_WORK(&variax->startup_work, variax_startup6);
+
+       /* initialize USB buffers: */
+       variax->buffer_activate = kmemdup(variax_activate,
+                                         sizeof(variax_activate), GFP_KERNEL);
+
+       if (variax->buffer_activate == NULL)
+               return -ENOMEM;
+
+       /* initialize MIDI subsystem: */
+       err = line6_init_midi(&variax->line6);
+       if (err < 0)
+               return err;
+
+       /* initiate startup procedure: */
+       variax_startup1(variax);
+       return 0;
+}
+
+#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
+#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
+
+/* table of devices that work with this driver */
+static const struct usb_device_id variax_id_table[] = {
+       { LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX },
+       { LINE6_DEVICE(0x534d),    .driver_info = LINE6_VARIAX },
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, variax_id_table);
+
+static const struct line6_properties variax_properties_table[] = {
+       [LINE6_PODXTLIVE_VARIAX] = {
+               .id = "PODxtLive",
+               .name = "PODxt Live",
+               .capabilities   = LINE6_CAP_CONTROL,
+               .altsetting = 1,
+               .ep_ctrl_r = 0x86,
+               .ep_ctrl_w = 0x05,
+               .ep_audio_r = 0x82,
+               .ep_audio_w = 0x01,
+       },
+       [LINE6_VARIAX] = {
+               .id = "Variax",
+               .name = "Variax Workbench",
+               .capabilities   = LINE6_CAP_CONTROL,
+               .altsetting = 1,
+               .ep_ctrl_r = 0x82,
+               .ep_ctrl_w = 0x01,
+               /* no audio channel */
+       }
+};
+
+/*
+       Probe USB device.
+*/
+static int variax_probe(struct usb_interface *interface,
+                       const struct usb_device_id *id)
+{
+       return line6_probe(interface, id, "Line6-Variax",
+                          &variax_properties_table[id->driver_info],
+                          variax_init, sizeof(struct usb_line6_variax));
+}
+
+static struct usb_driver variax_driver = {
+       .name = KBUILD_MODNAME,
+       .probe = variax_probe,
+       .disconnect = line6_disconnect,
+#ifdef CONFIG_PM
+       .suspend = line6_suspend,
+       .resume = line6_resume,
+       .reset_resume = line6_resume,
+#endif
+       .id_table = variax_id_table,
+};
+
+module_usb_driver(variax_driver);
+
+MODULE_DESCRIPTION("Vairax Workbench USB driver");
+MODULE_LICENSE("GPL");
index 5bfb695547f832e22c8ad80042bf382292460e64..417ebb11cf4896b8009c0aa86c7dab71c34d61a4 100644 (file)
@@ -2292,14 +2292,13 @@ int snd_usbmidi_create(struct snd_card *card,
        umidi->iface = iface;
        umidi->quirk = quirk;
        umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;
-       init_timer(&umidi->error_timer);
        spin_lock_init(&umidi->disc_lock);
        init_rwsem(&umidi->disc_rwsem);
        mutex_init(&umidi->mutex);
        umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor),
                               le16_to_cpu(umidi->dev->descriptor.idProduct));
-       umidi->error_timer.function = snd_usbmidi_error_timer;
-       umidi->error_timer.data = (unsigned long)umidi;
+       setup_timer(&umidi->error_timer, snd_usbmidi_error_timer,
+                   (unsigned long)umidi);
 
        /* detect the endpoint(s) to use */
        memset(endpoints, 0, sizeof(endpoints));
index 0d8aba5fe1a839abdb60197edfdfc0023802bb65..b4ef410e5a982b31adc933153773b34f9ccbbc2b 100644 (file)
@@ -1464,6 +1464,14 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
        subs->last_frame_number = usb_get_current_frame_number(subs->dev);
        subs->last_frame_number &= 0xFF; /* keep 8 LSBs */
 
+       if (subs->trigger_tstamp_pending_update) {
+               /* this is the first actual URB submitted,
+                * update trigger timestamp to reflect actual start time
+                */
+               snd_pcm_gettime(runtime, &runtime->trigger_tstamp);
+               subs->trigger_tstamp_pending_update = false;
+       }
+
        spin_unlock_irqrestore(&subs->lock, flags);
        urb->transfer_buffer_length = bytes;
        if (period_elapsed)
@@ -1550,6 +1558,7 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
+               subs->trigger_tstamp_pending_update = true;
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                subs->data_endpoint->prepare_data_urb = prepare_playback_urb;
                subs->data_endpoint->retire_data_urb = retire_playback_urb;
index 0a598af9b38b81d63f0202179733dcda4db91e20..67d476548dcf9094acd61e0ff74f0f320af1556a 100644 (file)
@@ -2486,6 +2486,28 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
 
+{
+       /* Akai MPC Element */
+       USB_DEVICE(0x09e8, 0x0021),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = & (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_IGNORE_INTERFACE
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_MIDI_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
+
 /* TerraTec devices */
 {
        USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0012),
index 4dd74ab1e9cce87093631ff64a6c52d44dfed134..90369001eab6612ba4cd1a0a774387042ccfd462 100644 (file)
@@ -1,76 +1,7 @@
-/*
- * Copyright (C) 2007, 2008 Karsten Wiese <fzu@wemgehoertderstaat.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
+#ifndef __USB_STREAM_H
+#define __USB_STREAM_H
 
-#define USB_STREAM_INTERFACE_VERSION 2
-
-#define SNDRV_USB_STREAM_IOCTL_SET_PARAMS \
-       _IOW('H', 0x90, struct usb_stream_config)
-
-struct usb_stream_packet {
-       unsigned offset;
-       unsigned length;
-};
-
-
-struct usb_stream_config {
-       unsigned version;
-       unsigned sample_rate;
-       unsigned period_frames;
-       unsigned frame_size;
-};
-
-struct usb_stream {
-       struct usb_stream_config cfg;
-       unsigned read_size;
-       unsigned write_size;
-
-       int period_size;
-
-       unsigned state;
-
-       int idle_insize;
-       int idle_outsize;
-       int sync_packet;
-       unsigned insize_done;
-       unsigned periods_done;
-       unsigned periods_polled;
-
-       struct usb_stream_packet outpacket[2];
-       unsigned                 inpackets;
-       unsigned                 inpacket_head;
-       unsigned                 inpacket_split;
-       unsigned                 inpacket_split_at;
-       unsigned                 next_inpacket_split;
-       unsigned                 next_inpacket_split_at;
-       struct usb_stream_packet inpacket[0];
-};
-
-enum usb_stream_state {
-       usb_stream_invalid,
-       usb_stream_stopped,
-       usb_stream_sync0,
-       usb_stream_sync1,
-       usb_stream_ready,
-       usb_stream_running,
-       usb_stream_xrun,
-};
-
-#if __KERNEL__
+#include <uapi/sound/usb_stream.h>
 
 #define USB_STREAM_NURBS 4
 #define USB_STREAM_URBDEPTH 4
@@ -108,5 +39,4 @@ void usb_stream_free(struct usb_stream_kernel *);
 int usb_stream_start(struct usb_stream_kernel *);
 void usb_stream_stop(struct usb_stream_kernel *);
 
-
-#endif
+#endif /* __USB_STREAM_H */