]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge tag 'sound-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 8 Oct 2012 22:07:14 +0000 (07:07 +0900)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 8 Oct 2012 22:07:14 +0000 (07:07 +0900)
Pull sound updates from Takashi Iwai:
 "This contains pretty many small commits covering fairly large range of
  files in sound/ directory.  Partly because of additional API support
  and partly because of constantly developed ASoC and ARM stuff.

  Some highlights:

   - Introduced the helper function and documentation for exposing the
     channel map via control API, as discussed in Plumbers; most of PCI
     drivers are covered, will follow more drivers later

   - Most of drivers have been replaced with the new PM callbacks (if
     the bus is supported)

   - HD-audio controller got the support of runtime PM and the support
     of D3 clock-stop.  Also changing the power_save option in sysfs
     kicks off immediately to enable / disable the power-save mode.

   - Another significant code change in HD-audio is the rewrite of
     firmware loading code.  Other than that, most of changes in
     HD-audio are continued cleanups and standardization for the generic
     auto parser and bug fixes (HBR, device-specific fixups), in
     addition to the support of channel-map API.

   - Addition of ASoC bindings for the compressed API, used by the
     mid-x86 drivers.

   - Lots of cleanups and API refreshes for ASoC codec drivers and
     DaVinci.

   - Conversion of OMAP to dmaengine.

   - New machine driver for Wolfson Microelectronics Bells.

   - New CODEC driver for Wolfson Microelectronics WM0010.

   - Enhancements to the ux500 and wm2000 drivers

   - A new driver for DA9055 and the support for regulator bypass mode."

Fix up various arm soc header file reorg conflicts.

* tag 'sound-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (339 commits)
  ALSA: hda - Add new codec ALC283 ALC290 support
  ALSA: hda - avoid unneccesary indices on "Headphone Jack" controls
  ALSA: hda - fix indices on boost volume on Conexant
  ALSA: aloop - add locking to timer access
  ALSA: hda - Fix hang caused by race during suspend.
  sound: Remove unnecessary semicolon
  ALSA: hda/realtek - Fix detection of ALC271X codec
  ALSA: hda - Add inverted internal mic quirk for Lenovo IdeaPad U310
  ALSA: hda - make Realtek/Sigmatel/Conexant use the generic unsol event
  ALSA: hda - make a generic unsol event handler
  ASoC: codecs: Add DA9055 codec driver
  ASoC: eukrea-tlv320: Convert it to platform driver
  ALSA: ASoC: add DT bindings for CS4271
  ASoC: wm_hubs: Ensure volume updates are handled during class W startup
  ASoC: wm5110: Adding missing volume update bits
  ASoC: wm5110: Add OUT3R support
  ASoC: wm5110: Add AEC loopback support
  ASoC: wm5110: Rename EPOUT to HPOUT3
  ASoC: arizona: Add more clock rates
  ASoC: arizona: Add more DSP options for mixer input muxes
  ...

363 files changed:
Documentation/devicetree/bindings/sound/cs4270.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/cs4271.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/omap-mcbsp.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/omap-twl4030.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/tlv320aic3x.txt [new file with mode: 0644]
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/Channel-Mapping-API.txt [new file with mode: 0644]
Documentation/sound/alsa/HD-Audio-Models.txt
arch/arm/mach-davinci/asp.h [new file with mode: 0644]
arch/arm/mach-davinci/davinci.h
arch/arm/mach-davinci/devices-da8xx.c
arch/arm/mach-davinci/devices.c
arch/arm/mach-davinci/dm355.c
arch/arm/mach-davinci/dm365.c
arch/arm/mach-davinci/dm644x.c
arch/arm/mach-davinci/dm646x.c
arch/arm/mach-davinci/include/mach/da8xx.h
arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c
arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c
arch/arm/mach-imx/eukrea_mbimxsd51-baseboard.c
arch/arm/mach-imx/mach-imx27_visstrim_m10.c
arch/arm/mach-omap2/board-am3517evm.c
arch/arm/mach-omap2/board-cm-t35.c
arch/arm/mach-omap2/board-devkit8000.c
arch/arm/mach-omap2/board-igep0020.c
arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/board-omap3evm.c
arch/arm/mach-omap2/board-overo.c
arch/arm/mach-omap2/board-zoom-peripherals.c
arch/arm/mach-omap2/include/mach/board-zoom.h
arch/arm/mach-omap2/mcbsp.c
arch/arm/mach-omap2/omap_hwmod_44xx_data.c
arch/arm/mach-omap2/twl-common.c
arch/arm/mach-omap2/twl-common.h
arch/arm/plat-samsung/dma-ops.c
arch/blackfin/mach-bf527/boards/ezkit.c
arch/blackfin/mach-bf533/boards/stamp.c
arch/blackfin/mach-bf537/boards/stamp.c
arch/blackfin/mach-bf561/boards/ezkit.c
arch/blackfin/mach-bf609/boards/ezkit.c
drivers/dma/at_hdmac.c
drivers/dma/ep93xx_dma.c
drivers/dma/imx-dma.c
drivers/dma/imx-sdma.c
drivers/dma/mmp_tdma.c
drivers/dma/mxs-dma.c
drivers/dma/omap-dma.c
drivers/dma/pl330.c
drivers/dma/sa11x0-dma.c
drivers/dma/sirf-dma.c
drivers/dma/ste_dma40.c
drivers/dma/tegra20-apb-dma.c
include/linux/dmaengine.h
include/linux/i2c/twl.h
include/linux/mfd/wm8994/pdata.h
include/linux/platform_data/asoc-mx27vis.h [new file with mode: 0644]
include/linux/platform_data/asoc-ti-mcbsp.h
include/linux/platform_data/davinci_asp.h [moved from arch/arm/mach-davinci/include/mach/asp.h with 56% similarity]
include/linux/platform_data/omap-twl4030.h [new file with mode: 0644]
include/sound/ac97_codec.h
include/sound/ad1816a.h
include/sound/asound.h
include/sound/compress_driver.h
include/sound/compress_params.h
include/sound/da9055.h [new file with mode: 0644]
include/sound/emu10k1.h
include/sound/initval.h
include/sound/memalloc.h
include/sound/pcm.h
include/sound/soc-dai.h
include/sound/soc-dapm.h
include/sound/soc.h
include/sound/tegra_wm8903.h [moved from arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h with 89% similarity]
include/sound/tlv.h
include/sound/version.h [deleted file]
include/sound/wm0010.h [new file with mode: 0644]
include/sound/wm8960.h
include/sound/wm8993.h
sound/core/compress_offload.c
sound/core/control.c
sound/core/info.c
sound/core/info_oss.c
sound/core/oss/mixer_oss.c
sound/core/pcm.c
sound/core/pcm_lib.c
sound/core/pcm_memory.c
sound/core/seq/seq_device.c
sound/core/sgbuf.c
sound/core/sound.c
sound/drivers/aloop.c
sound/drivers/opl3/opl3_midi.c
sound/drivers/opl4/opl4_synth.c
sound/drivers/vx/vx_pcm.c
sound/isa/Kconfig
sound/isa/Makefile
sound/isa/ad1816a/ad1816a.c
sound/isa/ad1816a/ad1816a_lib.c
sound/isa/cmi8328.c [new file with mode: 0644]
sound/isa/gus/interwave.c
sound/isa/opti9xx/miro.c
sound/isa/opti9xx/opti92x-ad1848.c
sound/isa/sb/emu8000.c
sound/isa/sb/emu8000_callback.c
sound/isa/wavefront/wavefront_synth.c
sound/last.c
sound/oss/audio.c
sound/oss/opl3.c
sound/oss/pss.c
sound/oss/sb_ess.c
sound/oss/sb_mixer.c
sound/oss/sys_timer.c
sound/oss/uart6850.c
sound/pci/ac97/ac97_patch.c
sound/pci/ali5451/ali5451.c
sound/pci/als300.c
sound/pci/als4000.c
sound/pci/asihpi/asihpi.c
sound/pci/atiixp.c
sound/pci/atiixp_modem.c
sound/pci/au88x0/au88x0_game.c
sound/pci/au88x0/au88x0_pcm.c
sound/pci/azt3328.c
sound/pci/ca0106/ca0106.h
sound/pci/ca0106/ca0106_main.c
sound/pci/ca0106/ca0106_mixer.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/cs46xx_lib.h
sound/pci/cs46xx/dsp_spos.c
sound/pci/cs46xx/dsp_spos_scb_lib.c
sound/pci/cs5530.c
sound/pci/cs5535audio/Makefile
sound/pci/cs5535audio/cs5535audio.c
sound/pci/ctxfi/ctatc.c
sound/pci/ctxfi/ctatc.h
sound/pci/ctxfi/cthardware.h
sound/pci/ctxfi/cthw20k1.c
sound/pci/ctxfi/cthw20k2.c
sound/pci/ctxfi/ctmixer.c
sound/pci/ctxfi/ctmixer.h
sound/pci/ctxfi/ctpcm.c
sound/pci/ctxfi/xfi.c
sound/pci/echoaudio/echoaudio.c
sound/pci/echoaudio/echoaudio.h
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1_callback.c
sound/pci/emu10k1/emu10k1_main.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/emu10k1/emufx.c
sound/pci/emu10k1/emupcm.c
sound/pci/emu10k1/memory.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_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_hwdep.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_jack.c
sound/pci/hda/hda_jack.h
sound/pci/hda/hda_local.h
sound/pci/hda/hda_proc.c
sound/pci/hda/hda_trace.h
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/ice1712/aureon.c
sound/pci/ice1712/ice1712.h
sound/pci/ice1712/ice1724.c
sound/pci/ice1712/juli.c
sound/pci/ice1712/prodigy_hifi.c
sound/pci/intel8x0.c
sound/pci/intel8x0m.c
sound/pci/korg1212/korg1212.c
sound/pci/maestro3.c
sound/pci/mixart/mixart_hwdep.c
sound/pci/nm256/nm256.c
sound/pci/oxygen/oxygen.c
sound/pci/oxygen/oxygen.h
sound/pci/oxygen/oxygen_lib.c
sound/pci/oxygen/virtuoso.c
sound/pci/pcxhr/pcxhr.c
sound/pci/pcxhr/pcxhr_hwdep.c
sound/pci/riptide/riptide.c
sound/pci/sis7019.c
sound/pci/trident/trident.c
sound/pci/trident/trident_main.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/pci/vx222/vx222.c
sound/pci/ymfpci/ymfpci.c
sound/pci/ymfpci/ymfpci.h
sound/pci/ymfpci/ymfpci_main.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/blackfin/bf5xx-ad1836.c
sound/soc/cirrus/Kconfig [moved from sound/soc/ep93xx/Kconfig with 100% similarity]
sound/soc/cirrus/Makefile [moved from sound/soc/ep93xx/Makefile with 100% similarity]
sound/soc/cirrus/edb93xx.c [moved from sound/soc/ep93xx/edb93xx.c with 100% similarity]
sound/soc/cirrus/ep93xx-ac97.c [moved from sound/soc/ep93xx/ep93xx-ac97.c with 100% similarity]
sound/soc/cirrus/ep93xx-i2s.c [moved from sound/soc/ep93xx/ep93xx-i2s.c with 100% similarity]
sound/soc/cirrus/ep93xx-pcm.c [moved from sound/soc/ep93xx/ep93xx-pcm.c with 100% similarity]
sound/soc/cirrus/ep93xx-pcm.h [moved from sound/soc/ep93xx/ep93xx-pcm.h with 100% similarity]
sound/soc/cirrus/simone.c [moved from sound/soc/ep93xx/simone.c with 100% similarity]
sound/soc/cirrus/snappercl15.c [moved from sound/soc/ep93xx/snappercl15.c with 100% similarity]
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ab8500-codec.c
sound/soc/codecs/ad1836.c
sound/soc/codecs/ad193x.c
sound/soc/codecs/ad1980.c
sound/soc/codecs/adau1373.c
sound/soc/codecs/adau1701.c
sound/soc/codecs/ak4671.c
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/cs4270.c
sound/soc/codecs/cs4271.c
sound/soc/codecs/cs42l51.c
sound/soc/codecs/cs42l52.c
sound/soc/codecs/da9055.c [new file with mode: 0644]
sound/soc/codecs/isabelle.c
sound/soc/codecs/lm4857.c
sound/soc/codecs/max98088.c
sound/soc/codecs/max98095.c
sound/soc/codecs/max9850.c
sound/soc/codecs/max9877.c
sound/soc/codecs/mc13783.c
sound/soc/codecs/sta32x.c
sound/soc/codecs/sta529.c
sound/soc/codecs/stac9766.c
sound/soc/codecs/tlv320aic26.c
sound/soc/codecs/tlv320aic32x4.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320dac33.c
sound/soc/codecs/tpa6130a2.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/twl6040.c
sound/soc/codecs/wm0010.c [new file with mode: 0644]
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm2200.c
sound/soc/codecs/wm5100.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8510.c
sound/soc/codecs/wm8523.c
sound/soc/codecs/wm8580.c
sound/soc/codecs/wm8711.c
sound/soc/codecs/wm8728.c
sound/soc/codecs/wm8737.c
sound/soc/codecs/wm8741.c
sound/soc/codecs/wm8770.c
sound/soc/codecs/wm8776.c
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8940.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/wm8971.c
sound/soc/codecs/wm8974.c
sound/soc/codecs/wm8978.c
sound/soc/codecs/wm8983.c
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm8991.c
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8994.h
sound/soc/codecs/wm8996.c
sound/soc/codecs/wm9090.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm_hubs.c
sound/soc/codecs/wm_hubs.h
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-i2s.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/davinci-mcasp.h
sound/soc/davinci/davinci-pcm.c
sound/soc/davinci/davinci-pcm.h
sound/soc/davinci/davinci-sffsdr.c
sound/soc/davinci/davinci-vcif.c
sound/soc/fsl/Kconfig
sound/soc/fsl/eukrea-tlv320.c
sound/soc/fsl/fsl_dma.c
sound/soc/fsl/imx-audmux.c
sound/soc/fsl/imx-pcm-dma.c
sound/soc/fsl/imx-ssi.c
sound/soc/fsl/mpc5200_dma.c
sound/soc/fsl/mpc5200_dma.h
sound/soc/fsl/mpc5200_psc_ac97.c
sound/soc/fsl/mpc5200_psc_i2s.c
sound/soc/fsl/mpc8610_hpcd.c
sound/soc/fsl/mx27vis-aic32x4.c
sound/soc/fsl/p1022_ds.c
sound/soc/fsl/pcm030-audio-fabric.c
sound/soc/mid-x86/mfld_machine.c
sound/soc/mid-x86/sst_dsp.h [new file with mode: 0644]
sound/soc/mid-x86/sst_platform.c
sound/soc/mid-x86/sst_platform.h
sound/soc/mxs/mxs-saif.c
sound/soc/omap/Kconfig
sound/soc/omap/Makefile
sound/soc/omap/am3517evm.c
sound/soc/omap/igep0020.c [deleted file]
sound/soc/omap/mcbsp.c
sound/soc/omap/mcbsp.h
sound/soc/omap/omap-abe-twl6040.c
sound/soc/omap/omap-dmic.c
sound/soc/omap/omap-hdmi.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-mcbsp.h
sound/soc/omap/omap-mcpdm.c
sound/soc/omap/omap-pcm.c
sound/soc/omap/omap-pcm.h
sound/soc/omap/omap-twl4030.c [new file with mode: 0644]
sound/soc/omap/omap3beagle.c [deleted file]
sound/soc/omap/omap3evm.c [deleted file]
sound/soc/omap/overo.c [deleted file]
sound/soc/omap/zoom2.c
sound/soc/samsung/Kconfig
sound/soc/samsung/Makefile
sound/soc/samsung/bells.c [new file with mode: 0644]
sound/soc/samsung/speyside.c
sound/soc/sh/fsi.c
sound/soc/soc-compress.c [new file with mode: 0644]
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-dmaengine-pcm.c
sound/soc/soc-jack.c
sound/soc/tegra/tegra_wm8903.c
sound/soc/ux500/ux500_msp_dai.c
sound/soc/ux500/ux500_msp_i2s.c
sound/sparc/amd7930.c
sound/sparc/dbri.c
sound/usb/6fire/firmware.c
sound/usb/card.c
sound/usb/card.h
sound/usb/endpoint.c
sound/usb/endpoint.h
sound/usb/helper.c
sound/usb/mixer.c
sound/usb/pcm.c
sound/usb/quirks-table.h
sound/usb/quirks.c
sound/usb/quirks.h

diff --git a/Documentation/devicetree/bindings/sound/cs4270.txt b/Documentation/devicetree/bindings/sound/cs4270.txt
new file mode 100644 (file)
index 0000000..6b222f9
--- /dev/null
@@ -0,0 +1,21 @@
+CS4270 audio CODEC
+
+The driver for this device currently only supports I2C.
+
+Required properties:
+
+  - compatible : "cirrus,cs4270"
+
+  - reg : the I2C address of the device for I2C
+
+Optional properties:
+
+  - reset-gpio : a GPIO spec for the reset pin. If specified, it will be
+                deasserted before communication to the codec starts.
+
+Example:
+
+codec: cs4270@48 {
+       compatible = "cirrus,cs4270";
+       reg = <0x48>;
+};
diff --git a/Documentation/devicetree/bindings/sound/cs4271.txt b/Documentation/devicetree/bindings/sound/cs4271.txt
new file mode 100644 (file)
index 0000000..c81b5fd
--- /dev/null
@@ -0,0 +1,36 @@
+Cirrus Logic CS4271 DT bindings
+
+This driver supports both the I2C and the SPI bus.
+
+Required properties:
+
+ - compatible: "cirrus,cs4271"
+
+For required properties on SPI, please consult
+Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Required properties on I2C:
+
+ - reg: the i2c address
+
+
+Optional properties:
+
+ - reset-gpio:         a GPIO spec to define which pin is connected to the chip's
+               !RESET pin
+
+Examples:
+
+       codec_i2c: cs4271@10 {
+               compatible = "cirrus,cs4271";
+               reg = <0x10>;
+               reset-gpio = <&gpio 23 0>;
+       };
+
+       codec_spi: cs4271@0 {
+               compatible = "cirrus,cs4271";
+               reg = <0x0>;
+               reset-gpio = <&gpio 23 0>;
+               spi-max-frequency = <6000000>;
+       };
+
diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt
new file mode 100644 (file)
index 0000000..374e145
--- /dev/null
@@ -0,0 +1,45 @@
+Texas Instruments McASP controller
+
+Required properties:
+- compatible :
+       "ti,dm646x-mcasp-audio" : for DM646x platforms
+       "ti,da830-mcasp-audio"  : for both DA830 & DA850 platforms
+       "ti,omap2-mcasp-audio"  : for OMAP2 platforms (TI81xx, AM33xx)
+
+- reg : Should contain McASP registers offset and length
+- interrupts : Interrupt number for McASP
+- op-mode : I2S/DIT ops mode.
+- tdm-slots : Slots for TDM operation.
+- num-serializer : Serializers used by McASP.
+- serial-dir : A list of serializer pin mode. The list number should be equal
+               to "num-serializer" parameter. Each entry is a number indication
+               serializer pin direction. (0 - INACTIVE, 1 - TX, 2 - RX)
+
+
+Optional properties:
+
+- ti,hwmods : Must be "mcasp<n>", n is controller instance starting 0
+- tx-num-evt : FIFO levels.
+- rx-num-evt : FIFO levels.
+- sram-size-playback : size of sram to be allocated during playback
+- sram-size-capture  : size of sram to be allocated during capture
+
+Example:
+
+mcasp0: mcasp0@1d00000 {
+       compatible = "ti,da830-mcasp-audio";
+       #address-cells = <1>;
+       #size-cells = <0>;
+       reg = <0x100000 0x3000>;
+       interrupts = <82 83>;
+       op-mode = <0>;          /* MCASP_IIS_MODE */
+       tdm-slots = <2>;
+       num-serializer = <16>;
+       serial-dir = <
+                       0 0 0 0 /* 0: INACTIVE, 1: TX, 2: RX */
+                       0 0 0 0
+                       0 0 0 1
+                       2 0 0 0 >;
+       tx-num-evt = <1>;
+       rx-num-evt = <1>;
+};
diff --git a/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt b/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt
new file mode 100644 (file)
index 0000000..65dec87
--- /dev/null
@@ -0,0 +1,91 @@
+* Texas Instruments OMAP4+ and twl6040 based audio setups
+
+Required properties:
+- compatible: "ti,abe-twl6040"
+- ti,model: Name of the sound card ( for example "SDP4430")
+- ti,mclk-freq: MCLK frequency for HPPLL operation
+- ti,mcpdm: phandle for the McPDM node
+- ti,twl6040: phandle for the twl6040 core node
+- ti,audio-routing: List of 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.
+
+Optional properties:
+- ti,dmic: phandle for the OMAP dmic node if the machine have it connected
+- ti,jack_detection: Need to be set to <1> if the board capable to detect jack
+  insertion, removal.
+
+Available audio endpoints for the audio-routing table:
+
+Board connectors:
+ * Headset Stereophone
+ * Earphone Spk
+ * Ext Spk
+ * Line Out
+ * Vibrator
+ * Headset Mic
+ * Main Handset Mic
+ * Sub Handset Mic
+ * Line In
+ * Digital Mic
+
+twl6040 pins:
+ * HSOL
+ * HSOR
+ * EP
+ * HFL
+ * HFR
+ * AUXL
+ * AUXR
+ * VIBRAL
+ * VIBRAR
+ * HSMIC
+ * MAINMIC
+ * SUBMIC
+ * AFML
+ * AFMR
+
+ * Headset Mic Bias
+ * Main Mic Bias
+ * Digital Mic1 Bias
+ * Digital Mic2 Bias
+
+Digital mic pins:
+ * DMic
+
+Example:
+
+sound {
+       compatible = "ti,abe-twl6040";
+       ti,model = "SDP4430";
+
+       ti,jack-detection = <1>;
+       ti,mclk-freq = <38400000>;
+
+       ti,mcpdm = <&mcpdm>;
+       ti,dmic = <&dmic>;
+
+       ti,twl6040 = <&twl6040>;
+
+       /* Audio routing */
+       ti,audio-routing =
+               "Headset Stereophone", "HSOL",
+               "Headset Stereophone", "HSOR",
+               "Earphone Spk", "EP",
+               "Ext Spk", "HFL",
+               "Ext Spk", "HFR",
+               "Line Out", "AUXL",
+               "Line Out", "AUXR",
+               "Vibrator", "VIBRAL",
+               "Vibrator", "VIBRAR",
+               "HSMIC", "Headset Mic",
+               "Headset Mic", "Headset Mic Bias",
+               "MAINMIC", "Main Handset Mic",
+               "Main Handset Mic", "Main Mic Bias",
+               "SUBMIC", "Sub Handset Mic",
+               "Sub Handset Mic", "Main Mic Bias",
+               "AFML", "Line In",
+               "AFMR", "Line In",
+               "DMic", "Digital Mic",
+               "Digital Mic", "Digital Mic1 Bias";
+};
diff --git a/Documentation/devicetree/bindings/sound/omap-mcbsp.txt b/Documentation/devicetree/bindings/sound/omap-mcbsp.txt
new file mode 100644 (file)
index 0000000..17cce44
--- /dev/null
@@ -0,0 +1,37 @@
+* Texas Instruments OMAP2+ McBSP module
+
+Required properties:
+- compatible: "ti,omap2420-mcbsp" for McBSP on OMAP2420
+             "ti,omap2430-mcbsp" for McBSP on OMAP2430
+             "ti,omap3-mcbsp" for McBSP on OMAP3
+             "ti,omap4-mcbsp" for McBSP on OMAP4 and newer SoC
+- reg: Register location and size, for OMAP4+ as an array:
+       <MPU access base address, size>,
+       <L3 interconnect address, size>;
+- reg-names: Array of strings associated with the address space
+- interrupts: Interrupt numbers for the McBSP port, as an array in case the
+             McBSP IP have more interrupt lines:
+       <OCP compliant irq>,
+       <TX irq>,
+       <RX irq>;
+- interrupt-names: Array of strings associated with the interrupt numbers
+- interrupt-parent: The parent interrupt controller
+- ti,buffer-size: Size of the FIFO on the port (OMAP2430 and newer SoC)
+- ti,hwmods: Name of the hwmod associated to the McBSP port
+
+Example:
+
+mcbsp2: mcbsp@49022000 {
+       compatible = "ti,omap3-mcbsp";
+       reg = <0x49022000 0xff>,
+             <0x49028000 0xff>;
+       reg-names = "mpu", "sidetone";
+       interrupts = <0 17 0x4>, /* OCP compliant interrupt */
+                    <0 62 0x4>, /* TX interrupt */
+                    <0 63 0x4>, /* RX interrupt */
+                    <0 4 0x4>;  /* Sidetone */
+       interrupt-names = "common", "tx", "rx", "sidetone";
+       interrupt-parent = <&intc>;
+       ti,buffer-size = <1280>;
+       ti,hwmods = "mcbsp2";
+};
diff --git a/Documentation/devicetree/bindings/sound/omap-twl4030.txt b/Documentation/devicetree/bindings/sound/omap-twl4030.txt
new file mode 100644 (file)
index 0000000..6fae51c
--- /dev/null
@@ -0,0 +1,17 @@
+* Texas Instruments SoC with twl4030 based audio setups
+
+Required properties:
+- compatible: "ti,omap-twl4030"
+- ti,model: Name of the sound card (for example "omap3beagle")
+- ti,mcbsp: phandle for the McBSP node
+- ti,codec: phandle for the twl4030 audio node
+
+Example:
+
+sound {
+       compatible = "ti,omap-twl4030";
+       ti,model = "omap3beagle";
+
+       ti,mcbsp = <&mcbsp2>;
+       ti,codec = <&twl_audio>;
+};
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt
new file mode 100644 (file)
index 0000000..e7b98f4
--- /dev/null
@@ -0,0 +1,20 @@
+Texas Instruments - tlv320aic3x Codec module
+
+The tlv320aic3x serial control bus communicates through I2C protocols
+
+Required properties:
+- compatible - "string" -  "ti,tlv320aic3x"
+- reg - <int> -  I2C slave address
+
+
+Optional properties:
+
+- gpio-reset - gpio pin number used for codec reset
+- ai3x-gpio-func - <array of 2 int> - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality
+
+Example:
+
+tlv320aic3x: tlv320aic3x@1b {
+       compatible = "ti,tlv320aic3x";
+       reg = <0x1b>;
+};
index 4e4d0bc9816f9d25f1c185d795f98b476bb50a2c..d90d8ec2853df3e49e18edefc1bffd8995826403 100644 (file)
@@ -860,8 +860,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     [Multiple options for each card instance]
     model      - force the model name
-    position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF,
-                  3 = VIACOMBO, 4 = COMBO)
+    position_fix - Fix DMA pointer
+                 -1 = system default: choose appropriate one per controller
+                       hardware
+                 0 = auto: falls back to LPIB when POSBUF doesn't work
+                 1 = use LPIB
+                 2 = POSBUF: use position buffer
+                 3 = VIACOMBO: VIA-specific workaround for capture
+                 4 = COMBO: use LPIB for playback, auto for capture stream
     probe_mask  - Bitmask to probe codecs (default = -1, meaning all slots)
                  When the bit 8 (0x100) is set, the lower 8 bits are used
                  as the "fixed" codec slots; i.e. the driver probes the
diff --git a/Documentation/sound/alsa/Channel-Mapping-API.txt b/Documentation/sound/alsa/Channel-Mapping-API.txt
new file mode 100644 (file)
index 0000000..3c43d1a
--- /dev/null
@@ -0,0 +1,153 @@
+ALSA PCM channel-mapping API
+============================
+                                       Takashi Iwai <tiwai@suse.de>
+
+GENERAL
+-------
+
+The channel mapping API allows user to query the possible channel maps
+and the current channel map, also optionally to modify the channel map
+of the current stream.
+
+A channel map is an array of position for each PCM channel.
+Typically, a stereo PCM stream has a channel map of
+  { front_left, front_right }
+while a 4.0 surround PCM stream has a channel map of
+  { front left, front right, rear left, rear right }.
+
+The problem, so far, was that we had no standard channel map
+explicitly, and applications had no way to know which channel
+corresponds to which (speaker) position.  Thus, applications applied
+wrong channels for 5.1 outputs, and you hear suddenly strange sound
+from rear.  Or, some devices secretly assume that center/LFE is the
+third/fourth channels while others that C/LFE as 5th/6th channels.
+
+Also, some devices such as HDMI are configurable for different speaker
+positions even with the same number of total channels.  However, there
+was no way to specify this because of lack of channel map
+specification.  These are the main motivations for the new channel
+mapping API.
+
+
+DESIGN
+------
+
+Actually, "the channel mapping API" doesn't introduce anything new in
+the kernel/user-space ABI perspective.  It uses only the existing
+control element features.
+
+As a ground design, each PCM substream may contain a control element
+providing the channel mapping information and configuration.  This
+element is specified by:
+       iface = SNDRV_CTL_ELEM_IFACE_PCM
+       name = "Playback Channel Map" or "Capture Channel Map"
+       device = the same device number for the assigned PCM substream
+       index = the same index number for the assigned PCM substream
+
+Note the name is different depending on the PCM substream direction.
+
+Each control element provides at least the TLV read operation and the
+read operation.  Optionally, the write operation can be provided to
+allow user to change the channel map dynamically.
+
+* TLV
+
+The TLV operation gives the list of available channel
+maps.  A list item of a channel map is usually a TLV of
+       type data-bytes ch0 ch1 ch2...
+where type is the TLV type value, the second argument is the total
+bytes (not the numbers) of channel values, and the rest are the
+position value for each channel.
+
+As a TLV type, either SNDRV_CTL_TLVT_CHMAP_FIXED,
+SNDRV_CTL_TLV_CHMAP_VAR or SNDRV_CTL_TLVT_CHMAP_PAIRED can be used.
+The _FIXED type is for a channel map with the fixed channel position
+while the latter two are for flexible channel positions.  _VAR type is
+for a channel map where all channels are freely swappable and _PAIRED
+type is where pair-wise channels are swappable.  For example, when you
+have {FL/FR/RL/RR} channel map, _PAIRED type would allow you to swap
+only {RL/RR/FL/FR} while _VAR type would allow even swapping FL and
+RR.
+
+These new TLV types are defined in sound/tlv.h.
+
+The available channel position values are defined in sound/asound.h,
+here is a cut:
+
+/* channel positions */
+enum {
+       SNDRV_CHMAP_UNKNOWN = 0,
+       SNDRV_CHMAP_NA,         /* N/A, silent */
+       SNDRV_CHMAP_MONO,       /* mono stream */
+       /* this follows the alsa-lib mixer channel value + 3 */
+       SNDRV_CHMAP_FL,         /* front left */
+       SNDRV_CHMAP_FR,         /* front right */
+       SNDRV_CHMAP_RL,         /* rear left */
+       SNDRV_CHMAP_RR,         /* rear right */
+       SNDRV_CHMAP_FC,         /* front center */
+       SNDRV_CHMAP_LFE,        /* LFE */
+       SNDRV_CHMAP_SL,         /* side left */
+       SNDRV_CHMAP_SR,         /* side right */
+       SNDRV_CHMAP_RC,         /* rear center */
+       /* new definitions */
+       SNDRV_CHMAP_FLC,        /* front left center */
+       SNDRV_CHMAP_FRC,        /* front right center */
+       SNDRV_CHMAP_RLC,        /* rear left center */
+       SNDRV_CHMAP_RRC,        /* rear right center */
+       SNDRV_CHMAP_FLW,        /* front left wide */
+       SNDRV_CHMAP_FRW,        /* front right wide */
+       SNDRV_CHMAP_FLH,        /* front left high */
+       SNDRV_CHMAP_FCH,        /* front center high */
+       SNDRV_CHMAP_FRH,        /* front right high */
+       SNDRV_CHMAP_TC,         /* top center */
+       SNDRV_CHMAP_TFL,        /* top front left */
+       SNDRV_CHMAP_TFR,        /* top front right */
+       SNDRV_CHMAP_TFC,        /* top front center */
+       SNDRV_CHMAP_TRL,        /* top rear left */
+       SNDRV_CHMAP_TRR,        /* top rear right */
+       SNDRV_CHMAP_TRC,        /* top rear center */
+       SNDRV_CHMAP_LAST = SNDRV_CHMAP_TRC,
+};
+
+When a PCM stream can provide more than one channel map, you can
+provide multiple channel maps in a TLV container type.  The TLV data
+to be returned will contain such as:
+       SNDRV_CTL_TLVT_CONTAINER 96
+           SNDRV_CTL_TLVT_CHMAP_FIXED 4 SNDRV_CHMAP_FC
+           SNDRV_CTL_TLVT_CHMAP_FIXED 8 SNDRV_CHMAP_FL SNDRV_CHMAP_FR
+           SNDRV_CTL_TLVT_CHMAP_FIXED 16 NDRV_CHMAP_FL SNDRV_CHMAP_FR \
+               SNDRV_CHMAP_RL SNDRV_CHMAP_RR
+
+The channel position is provided in LSB 16bits.  The upper bits are
+used for bit flags.
+
+#define SNDRV_CHMAP_POSITION_MASK      0xffff
+#define SNDRV_CHMAP_PHASE_INVERSE      (0x01 << 16)
+#define SNDRV_CHMAP_DRIVER_SPEC                (0x02 << 16)
+
+SNDRV_CHMAP_PHASE_INVERSE indicates the channel is phase inverted,
+(thus summing left and right channels would result in almost silence).
+Some digital mic devices have this.
+
+When SNDRV_CHMAP_DRIVER_SPEC is set, all the channel position values
+don't follow the standard definition above but driver-specific.
+
+* READ OPERATION
+
+The control read operation is for providing the current channel map of
+the given stream.  The control element returns an integer array
+containing the position of each channel.
+
+When this is performed before the number of the channel is specified
+(i.e. hw_params is set), it should return all channels set to
+UNKNOWN.
+
+* WRITE OPERATION
+
+The control write operation is optional, and only for devices that can
+change the channel configuration on the fly, such as HDMI.  User needs
+to pass an integer value containing the valid channel positions for
+all channels of the assigned PCM substream.
+
+This operation is allowed only at PCM PREPARED state.  When called in
+other states, it shall return an error.
index a92bba8168435bc731ce8db34530d55639fa8def..16dfe57f173167c9df59bfdc6c1cefff9db2fa0f 100644 (file)
@@ -74,7 +74,8 @@ CMI9880
 
 AD1882 / AD1882A
 ================
-  3stack       3-stack mode (default)
+  3stack       3-stack mode
+  3stack-automute 3-stack with automute front HP (default)
   6stack       6-stack mode
 
 AD1884A / AD1883 / AD1984A / AD1984B
diff --git a/arch/arm/mach-davinci/asp.h b/arch/arm/mach-davinci/asp.h
new file mode 100644 (file)
index 0000000..d9b2acd
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * TI DaVinci Audio definitions
+ */
+#ifndef __ASM_ARCH_DAVINCI_ASP_H
+#define __ASM_ARCH_DAVINCI_ASP_H
+
+/* Bases of dm644x and dm355 register banks */
+#define DAVINCI_ASP0_BASE      0x01E02000
+#define DAVINCI_ASP1_BASE      0x01E04000
+
+/* Bases of dm365 register banks */
+#define DAVINCI_DM365_ASP0_BASE        0x01D02000
+
+/* Bases of dm646x register banks */
+#define DAVINCI_DM646X_MCASP0_REG_BASE         0x01D01000
+#define DAVINCI_DM646X_MCASP1_REG_BASE         0x01D01800
+
+/* Bases of da850/da830 McASP0  register banks */
+#define DAVINCI_DA8XX_MCASP0_REG_BASE  0x01D00000
+
+/* Bases of da830 McASP1 register banks */
+#define DAVINCI_DA830_MCASP1_REG_BASE  0x01D04000
+
+/* EDMA channels of dm644x and dm355 */
+#define DAVINCI_DMA_ASP0_TX    2
+#define DAVINCI_DMA_ASP0_RX    3
+#define DAVINCI_DMA_ASP1_TX    8
+#define DAVINCI_DMA_ASP1_RX    9
+
+/* EDMA channels of dm646x */
+#define DAVINCI_DM646X_DMA_MCASP0_AXEVT0       6
+#define DAVINCI_DM646X_DMA_MCASP0_AREVT0       9
+#define DAVINCI_DM646X_DMA_MCASP1_AXEVT1       12
+
+/* EDMA channels of da850/da830 McASP0 */
+#define DAVINCI_DA8XX_DMA_MCASP0_AREVT 0
+#define DAVINCI_DA8XX_DMA_MCASP0_AXEVT 1
+
+/* EDMA channels of da830 McASP1 */
+#define DAVINCI_DA830_DMA_MCASP1_AREVT 2
+#define DAVINCI_DA830_DMA_MCASP1_AXEVT 3
+
+/* Interrupts */
+#define DAVINCI_ASP0_RX_INT    IRQ_MBRINT
+#define DAVINCI_ASP0_TX_INT    IRQ_MBXINT
+#define DAVINCI_ASP1_RX_INT    IRQ_MBRINT
+#define DAVINCI_ASP1_TX_INT    IRQ_MBXINT
+
+#endif /* __ASM_ARCH_DAVINCI_ASP_H */
index a37fc44e29bc05b2c52d796bf4ace69cb6800601..12d544befcfa36554d70931fcf0048e01ab212bd 100644 (file)
 #include <linux/davinci_emac.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
-
-#include <mach/asp.h>
+#include <linux/platform_data/davinci_asp.h>
 #include <linux/platform_data/keyscan-davinci.h>
 #include <mach/hardware.h>
+#include <mach/edma.h>
 
 #include <media/davinci/vpfe_capture.h>
 #include <media/davinci/vpif_types.h>
index 783eab6845c4ea6d56e0a9575b9e9cb89e5eaf84..bd2f72b414bce03c87b4921e2962ff709cf815e4 100644 (file)
@@ -24,6 +24,7 @@
 #include <mach/cpuidle.h>
 
 #include "clock.h"
+#include "asp.h"
 
 #define DA8XX_TPCC_BASE                        0x01c00000
 #define DA8XX_TPTC0_BASE               0x01c08000
@@ -505,15 +506,8 @@ static struct platform_device da850_mcasp_device = {
        .resource       = da850_mcasp_resources,
 };
 
-static struct platform_device davinci_pcm_device = {
-       .name   = "davinci-pcm-audio",
-       .id     = -1,
-};
-
 void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata)
 {
-       platform_device_register(&davinci_pcm_device);
-
        /* DA830/OMAP-L137 has 3 instances of McASP */
        if (cpu_is_davinci_da830() && id == 1) {
                da830_mcasp1_device.dev.platform_data = pdata;
index 3a42b6f79aa9b7275c6dfcc27341968a4b70b1e4..4c48a36ee567d6a98b2eb5d0a56ef9b51f2121b0 100644 (file)
@@ -313,16 +313,6 @@ static void davinci_init_wdt(void)
 
 /*-------------------------------------------------------------------------*/
 
-static struct platform_device davinci_pcm_device = {
-       .name           = "davinci-pcm-audio",
-       .id             = -1,
-};
-
-static void davinci_init_pcm(void)
-{
-       platform_device_register(&davinci_pcm_device);
-}
-
 /*-------------------------------------------------------------------------*/
 
 struct davinci_timer_instance davinci_timer_instance[2] = {
@@ -345,7 +335,6 @@ static int __init davinci_init_devices(void)
        /* please keep these calls, and their implementations above,
         * in alphabetical order so they're easier to sort through.
         */
-       davinci_init_pcm();
        davinci_init_wdt();
 
        return 0;
index adbde33eca015a640217ed1335671645cd874449..a255434908dbcfebb1a1b8a3a946860db7e9f4bf 100644 (file)
 #include <mach/time.h>
 #include <mach/serial.h>
 #include <mach/common.h>
-#include <mach/asp.h>
 #include <linux/platform_data/spi-davinci.h>
 #include <mach/gpio-davinci.h>
 
 #include "davinci.h"
 #include "clock.h"
 #include "mux.h"
+#include "asp.h"
 
 #define DM355_UART2_BASE       (IO_PHYS + 0x206000)
 
index 719e22f2a37e42bd4bc11bcf28bc86f629a79adf..b680c832e0ba87758f1f29aeb502109ce2699268 100644 (file)
@@ -29,7 +29,6 @@
 #include <mach/time.h>
 #include <mach/serial.h>
 #include <mach/common.h>
-#include <mach/asp.h>
 #include <linux/platform_data/keyscan-davinci.h>
 #include <linux/platform_data/spi-davinci.h>
 #include <mach/gpio-davinci.h>
@@ -37,6 +36,7 @@
 #include "davinci.h"
 #include "clock.h"
 #include "mux.h"
+#include "asp.h"
 
 #define DM365_REF_FREQ         24000000        /* 24 MHz on the DM365 EVM */
 
index c8b866657fcbf1a2d240c3711fce4bba1093c775..0755d466221a6aad1b3c93056f5e39e314cfc034 100644 (file)
 #include <mach/time.h>
 #include <mach/serial.h>
 #include <mach/common.h>
-#include <mach/asp.h>
 #include <mach/gpio-davinci.h>
 
 #include "davinci.h"
 #include "clock.h"
 #include "mux.h"
+#include "asp.h"
 
 /*
  * Device specific clocks
index 9eb87c1d1edd1e1deacefc64d240469987e2f0d6..97c0f8e555bd454edb83c4612bf31153816fa9e0 100644 (file)
 #include <mach/time.h>
 #include <mach/serial.h>
 #include <mach/common.h>
-#include <mach/asp.h>
 #include <mach/gpio-davinci.h>
 
 #include "davinci.h"
 #include "clock.h"
 #include "mux.h"
+#include "asp.h"
 
 #define DAVINCI_VPIF_BASE       (0x01C12000)
 
index 33e78ae2a254d3106f97a42dcf68aa2cebc076c2..c9ee723c56f35a78628dc0a4a78c08bd63a4f6c3 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/davinci_emac.h>
 #include <linux/spi/spi.h>
+#include <linux/platform_data/davinci_asp.h>
 
 #include <mach/serial.h>
 #include <mach/edma.h>
-#include <mach/asp.h>
 #include <mach/pm.h>
 #include <linux/platform_data/i2c-davinci.h>
 #include <linux/platform_data/mmc-davinci.h>
index fd3177f9e79ad2be616fb4d70b1f71f48daf9fdf..98aef571b9f839de8111cb8cb19e3dfe595b5adb 100644 (file)
@@ -348,4 +348,5 @@ void __init eukrea_mbimx27_baseboard_init(void)
        imx27_add_imx_keypad(&eukrea_mbimx27_keymap_data);
 
        gpio_led_register_device(-1, &eukrea_mbimx27_gpio_led_info);
+       imx_add_platform_device("eukrea_tlv320", 0, NULL, 0, NULL, 0);
 }
index dfd2da87c2df1e3214a6fac5bfca0ec18dee3193..0b84666792f05f7192954b3a57b2256d7e341031 100644 (file)
@@ -306,4 +306,5 @@ void __init eukrea_mbimxsd25_baseboard_init(void)
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
        gpio_led_register_device(-1, &eukrea_mbimxsd_led_info);
        imx_add_gpio_keys(&eukrea_mbimxsd_button_data);
+       imx_add_platform_device("eukrea_tlv320", 0, NULL, 0, NULL, 0);
 }
index 6e9dd12a6961cf8bf7e6fc8cf8053a12ca13fd32..c6532a007d468ae68658c213d3656ee483cc2dfd 100644 (file)
@@ -315,4 +315,5 @@ void __init eukrea_mbimxsd35_baseboard_init(void)
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
        gpio_led_register_device(-1, &eukrea_mbimxsd_led_info);
        imx_add_gpio_keys(&eukrea_mbimxsd_button_data);
+       imx_add_platform_device("eukrea_tlv320", 0, NULL, 0, NULL, 0);
 }
index 96a24b73dc2309fc109c346524d22e39b84e3b67..8b0de30d7a3f3d2dba60032367b4b548657804b4 100644 (file)
@@ -228,4 +228,5 @@ void __init eukrea_mbimxsd51_baseboard_init(void)
 
        gpio_led_register_device(-1, &eukrea_mbimxsd51_led_info);
        imx_add_gpio_keys(&eukrea_mbimxsd51_button_data);
+       imx_add_platform_device("eukrea_tlv320", 0, NULL, 0, NULL, 0);
 }
index 821d6aac411cb9e5d9d56f8ffb3100b3affa1b6b..141756f00ae5c8733795855bd31b994c8609a496 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/leds.h>
+#include <linux/platform_data/asoc-mx27vis.h>
 #include <media/soc_camera.h>
 #include <sound/tlv320aic32x4.h>
 #include <asm/mach-types.h>
 #define EXPBOARD_BIT1          (GPIO_PORTD + 27)
 #define EXPBOARD_BIT0          (GPIO_PORTD + 28)
 
+#define AMP_GAIN_0             (GPIO_PORTF + 9)
+#define AMP_GAIN_1             (GPIO_PORTF + 8)
+#define AMP_MUTE_SDL           (GPIO_PORTE + 5)
+#define AMP_MUTE_SDR           (GPIO_PORTF + 7)
+
 static const int visstrim_m10_pins[] __initconst = {
        /* UART1 (console) */
        PE12_PF_UART1_TXD,
@@ -139,6 +145,11 @@ static const int visstrim_m10_pins[] __initconst = {
        EXPBOARD_BIT2 | GPIO_GPIO | GPIO_IN | GPIO_PUEN,
        EXPBOARD_BIT1 | GPIO_GPIO | GPIO_IN | GPIO_PUEN,
        EXPBOARD_BIT0 | GPIO_GPIO | GPIO_IN | GPIO_PUEN,
+       /* Audio AMP control */
+       AMP_GAIN_0 | GPIO_GPIO | GPIO_OUT,
+       AMP_GAIN_1 | GPIO_GPIO | GPIO_OUT,
+       AMP_MUTE_SDL | GPIO_GPIO | GPIO_OUT,
+       AMP_MUTE_SDR | GPIO_GPIO | GPIO_OUT,
 };
 
 static struct gpio visstrim_m10_version_gpios[] = {
@@ -166,6 +177,26 @@ static const struct gpio visstrim_m10_gpios[] __initconst = {
                .flags = GPIOF_DIR_OUT | GPIOF_INIT_LOW,
                .label = "usbotg_cs",
        },
+       {
+               .gpio = AMP_GAIN_0,
+               .flags = GPIOF_DIR_OUT,
+               .label = "amp-gain-0",
+       },
+       {
+               .gpio = AMP_GAIN_1,
+               .flags = GPIOF_DIR_OUT,
+               .label = "amp-gain-1",
+       },
+       {
+               .gpio = AMP_MUTE_SDL,
+               .flags = GPIOF_DIR_OUT,
+               .label = "amp-mute-sdl",
+       },
+       {
+               .gpio = AMP_MUTE_SDR,
+               .flags = GPIOF_DIR_OUT,
+               .label = "amp-mute-sdr",
+       },
 };
 
 /* Camera */
@@ -444,6 +475,14 @@ static void __init visstrim_deinterlace_init(void)
 }
 
 
+/* Audio */
+static const struct snd_mx27vis_platform_data snd_mx27vis_pdata __initconst = {
+       .amp_gain0_gpio = AMP_GAIN_0,
+       .amp_gain1_gpio = AMP_GAIN_1,
+       .amp_mutel_gpio = AMP_MUTE_SDL,
+       .amp_muter_gpio = AMP_MUTE_SDR,
+};
+
 static void __init visstrim_m10_revision(void)
 {
        int exp_version = 0;
@@ -502,7 +541,8 @@ static void __init visstrim_m10_board_init(void)
        imx27_add_fec(NULL);
        imx_add_gpio_keys(&visstrim_gpio_keys_platform_data);
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
-       imx_add_platform_device("mx27vis", 0, NULL, 0, NULL, 0);
+       imx_add_platform_device("mx27vis", 0, NULL, 0, &snd_mx27vis_pdata,
+                               sizeof(snd_mx27vis_pdata));
        platform_device_register_resndata(NULL, "soc-camera-pdrv", 0, NULL, 0,
                                      &iclink_tvp5150, sizeof(iclink_tvp5150));
        gpio_led_register_device(0, &visstrim_m10_led_data);
index 0d99c9110d01e6090a38e071813a33dc9bae2536..e16289755f2e39b98674f8a10654c9805950c7d3 100644 (file)
@@ -263,6 +263,16 @@ static __init void am3517_evm_musb_init(void)
        usb_musb_init(&musb_board_data);
 }
 
+static __init void am3517_evm_mcbsp1_init(void)
+{
+       u32 devconf0;
+
+       /* McBSP1 CLKR/FSR signal to be connected to CLKX/FSX pin */
+       devconf0 = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
+       devconf0 |=  OMAP2_MCBSP1_CLKR_MASK | OMAP2_MCBSP1_FSR_MASK;
+       omap_ctrl_writel(devconf0, OMAP2_CONTROL_DEVCONF0);
+}
+
 static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
        .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
 #if defined(CONFIG_PANEL_SHARP_LQ043T1DG01) || \
@@ -366,6 +376,9 @@ static void __init am3517_evm_init(void)
        /* MUSB */
        am3517_evm_musb_init();
 
+       /* McBSP1 */
+       am3517_evm_mcbsp1_init();
+
        /* MMC init function */
        omap_hsmmc_init(mmc);
 }
index 8ffd612c5e079cf3852060cf8dacdadc1687b363..376d26eb601c371b75b4c4af7a3105ebe30bf8c4 100644 (file)
@@ -723,6 +723,7 @@ static void __init cm_t3x_common_init(void)
        cm_t35_init_ethernet();
        cm_t35_init_led();
        cm_t35_init_display();
+       omap_twl4030_audio_init("cm-t3x");
 
        usb_musb_init(NULL);
        cm_t35_init_usbh();
index 7bb8056d43886dc541e2961eb2ba6f537dc5fc34..1fd161e934c7e7df2d9eec52c3c35f3e8abfc964 100644 (file)
@@ -623,6 +623,7 @@ static void __init devkit8000_init(void)
        usbhs_init(&usbhs_bdata);
        omap_nand_flash_init(NAND_BUSWIDTH_16, devkit8000_nand_partitions,
                             ARRAY_SIZE(devkit8000_nand_partitions));
+       omap_twl4030_audio_init("omap3beagle");
 
        /* Ensure SDRC pins are mux'd for self-refresh */
        omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
index fb8bd837dd137f95374751c3b045e7c4c00f18b4..48d5e41dfbfabe3da59ef00f7457f5012cf2ec1a 100644 (file)
@@ -625,6 +625,7 @@ static void __init igep_init(void)
 
        igep_flash_init();
        igep_leds_init();
+       omap_twl4030_audio_init("igep2");
 
        /*
         * WLAN-BT combo module from MuRata which has a Marvell WLAN
index 68ff8d51973c4daa01f39036a7b03923bffabcfe..a08bebc94ec59d5269acd1d5c08f40f41a9cb616 100644 (file)
@@ -514,6 +514,7 @@ static void __init omap3_beagle_init(void)
        usbhs_init(&usbhs_bdata);
        omap_nand_flash_init(NAND_BUSWIDTH_16, omap3beagle_nand_partitions,
                             ARRAY_SIZE(omap3beagle_nand_partitions));
+       omap_twl4030_audio_init("omap3beagle");
 
        /* Ensure msecure is mux'd to be able to set the RTC. */
        omap_mux_init_signal("sys_drm_msecure", OMAP_PIN_OFF_OUTPUT_HIGH);
index c64e565bdef5cd1e6fa0c5227a45c2228b8efeb4..a3959de85e0554706a20a8266edb050c16c8ef7e 100644 (file)
@@ -739,6 +739,7 @@ static void __init omap3_evm_init(void)
        omap3evm_init_smsc911x();
        omap3_evm_display_init();
        omap3_evm_wl12xx_init();
+       omap_twl4030_audio_init("omap3evm");
 }
 
 MACHINE_START(OMAP3EVM, "OMAP3 EVM")
index 2e7f24030fc9a286657260f0b092191a3c9461ac..b700685762b50b70242f823e22bf393b2ebe4943 100644 (file)
@@ -504,6 +504,7 @@ static void __init overo_init(void)
        overo_display_init();
        overo_init_led();
        overo_init_keys();
+       omap_twl4030_audio_init("overo");
 
        /* Ensure SDRC pins are mux'd for self-refresh */
        omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
index 6bcc107b9fc37facbafeac687e31f281f2a1bb57..67f8540c8e07a912a87460311afc0f3a0e5c094e 100644 (file)
@@ -35,6 +35,7 @@
 #include "common-board-devices.h"
 
 #define OMAP_ZOOM_WLAN_PMENA_GPIO      (101)
+#define ZOOM2_HEADSET_EXTMUTE_GPIO     (153)
 #define OMAP_ZOOM_WLAN_IRQ_GPIO                (162)
 
 #define LCD_PANEL_ENABLE_GPIO          (7 + OMAP_MAX_GPIO_LINES)
@@ -245,12 +246,6 @@ static int zoom_twl_gpio_setup(struct device *dev,
        return ret;
 }
 
-/* EXTMUTE callback function */
-static void zoom2_set_hs_extmute(int mute)
-{
-       gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute);
-}
-
 static struct twl4030_gpio_platform_data zoom_gpio_data = {
        .setup          = zoom_twl_gpio_setup,
 };
@@ -277,7 +272,7 @@ static int __init omap_i2c_init(void)
 
                codec_data->ramp_delay_value = 3;       /* 161 ms */
                codec_data->hs_extmute = 1;
-               codec_data->set_hs_extmute = zoom2_set_hs_extmute;
+               codec_data->hs_extmute_gpio = ZOOM2_HEADSET_EXTMUTE_GPIO;
        }
        omap_pmic_init(1, 2400, "twl5030", 7 + OMAP_INTC_START, &zoom_twldata);
        omap_register_i2c_bus(2, 400, NULL, 0);
index 775fdc3b000b686d20e09ab21d4a5c756c8c9542..2e9486940ead2c993b5b50c36d9cc18d661951d7 100644 (file)
@@ -8,5 +8,3 @@
 extern int __init zoom_debugboard_init(void);
 extern void __init zoom_peripherals_init(void);
 extern void __init zoom_display_init(void);
-
-#define ZOOM2_HEADSET_EXTMUTE_GPIO     153
index 7d47407d6d461892cf2deb57c20a5a050335ac04..37f8f948047baace501bc6ef4b09f551aa7c9cfa 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/platform_data/asoc-ti-mcbsp.h>
@@ -23,8 +24,6 @@
 #include <plat/omap_device.h>
 #include <linux/pm_runtime.h>
 
-#include "control.h"
-
 /*
  * FIXME: Find a mechanism to enable/disable runtime the McBSP ICLK autoidle.
  * Sidetone needs non-gated ICLK and sidetone autoidle is broken.
 #include "cm2xxx_3xxx.h"
 #include "cm-regbits-34xx.h"
 
-/* McBSP1 internal signal muxing function for OMAP2/3 */
-static int omap2_mcbsp1_mux_rx_clk(struct device *dev, const char *signal,
-                                  const char *src)
-{
-       u32 v;
-
-       v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
-
-       if (!strcmp(signal, "clkr")) {
-               if (!strcmp(src, "clkr"))
-                       v &= ~OMAP2_MCBSP1_CLKR_MASK;
-               else if (!strcmp(src, "clkx"))
-                       v |= OMAP2_MCBSP1_CLKR_MASK;
-               else
-                       return -EINVAL;
-       } else if (!strcmp(signal, "fsr")) {
-               if (!strcmp(src, "fsr"))
-                       v &= ~OMAP2_MCBSP1_FSR_MASK;
-               else if (!strcmp(src, "fsx"))
-                       v |= OMAP2_MCBSP1_FSR_MASK;
-               else
-                       return -EINVAL;
-       } else {
-               return -EINVAL;
-       }
-
-       omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
-
-       return 0;
-}
-
-/* McBSP4 internal signal muxing function for OMAP4 */
-#define OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_FSX    (1 << 31)
-#define OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_CLKX   (1 << 30)
-static int omap4_mcbsp4_mux_rx_clk(struct device *dev, const char *signal,
-                                  const char *src)
-{
-       u32 v;
-
-       /*
-        * In CONTROL_MCBSPLP register only bit 30 (CLKR mux), and bit 31 (FSR
-        * mux) is used */
-       v = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MCBSPLP);
-
-       if (!strcmp(signal, "clkr")) {
-               if (!strcmp(src, "clkr"))
-                       v &= ~OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_CLKX;
-               else if (!strcmp(src, "clkx"))
-                       v |= OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_CLKX;
-               else
-                       return -EINVAL;
-       } else if (!strcmp(signal, "fsr")) {
-               if (!strcmp(src, "fsr"))
-                       v &= ~OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_FSX;
-               else if (!strcmp(src, "fsx"))
-                       v |= OMAP4_CONTROL_MCBSPLP_ALBCTRLRX_FSX;
-               else
-                       return -EINVAL;
-       } else {
-               return -EINVAL;
-       }
-
-       omap4_ctrl_pad_writel(v, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MCBSPLP);
-
-       return 0;
-}
-
-/* McBSP CLKS source switching function */
-static int omap2_mcbsp_set_clk_src(struct device *dev, struct clk *clk,
-                                  const char *src)
-{
-       struct clk *fck_src;
-       char *fck_src_name;
-       int r;
-
-       if (!strcmp(src, "clks_ext"))
-               fck_src_name = "pad_fck";
-       else if (!strcmp(src, "clks_fclk"))
-               fck_src_name = "prcm_fck";
-       else
-               return -EINVAL;
-
-       fck_src = clk_get(dev, fck_src_name);
-       if (IS_ERR_OR_NULL(fck_src)) {
-               pr_err("omap-mcbsp: %s: could not clk_get() %s\n", "clks",
-                      fck_src_name);
-               return -EINVAL;
-       }
-
-       pm_runtime_put_sync(dev);
-
-       r = clk_set_parent(clk, fck_src);
-       if (IS_ERR_VALUE(r)) {
-               pr_err("omap-mcbsp: %s: could not clk_set_parent() to %s\n",
-                      "clks", fck_src_name);
-               clk_put(fck_src);
-               return -EINVAL;
-       }
-
-       pm_runtime_get_sync(dev);
-
-       clk_put(fck_src);
-
-       return 0;
-}
-
 static int omap3_enable_st_clock(unsigned int id, bool enable)
 {
        unsigned int w;
@@ -179,17 +72,11 @@ static int __init omap_init_mcbsp(struct omap_hwmod *oh, void *unused)
                pdata->reg_size = 4;
                pdata->has_ccr = true;
        }
-       pdata->set_clk_src = omap2_mcbsp_set_clk_src;
-
-       /* On OMAP2/3 the McBSP1 port has 6 pin configuration */
-       if (id == 1 && oh->class->rev < MCBSP_CONFIG_TYPE4)
-               pdata->mux_signal = omap2_mcbsp1_mux_rx_clk;
 
-       /* On OMAP4 the McBSP4 port has 6 pin configuration */
-       if (id == 4 && oh->class->rev == MCBSP_CONFIG_TYPE4)
-               pdata->mux_signal = omap4_mcbsp4_mux_rx_clk;
-
-       if (oh->class->rev == MCBSP_CONFIG_TYPE3) {
+       if (oh->class->rev == MCBSP_CONFIG_TYPE2) {
+               /* The FIFO has 128 locations */
+               pdata->buffer_size = 0x80;
+       } else if (oh->class->rev == MCBSP_CONFIG_TYPE3) {
                if (id == 2)
                        /* The FIFO has 1024 + 256 locations */
                        pdata->buffer_size = 0x500;
@@ -225,7 +112,8 @@ static int __init omap_init_mcbsp(struct omap_hwmod *oh, void *unused)
 
 static int __init omap2_mcbsp_init(void)
 {
-       omap_hwmod_for_each_by_class("mcbsp", omap_init_mcbsp, NULL);
+       if (!of_have_populated_dt())
+               omap_hwmod_for_each_by_class("mcbsp", omap_init_mcbsp, NULL);
 
        return 0;
 }
index 8d7a93525bc6f8f13a10df61964596ca0aac18e1..652d0285bd6dd7b1a445bcbab02e395e04c5e11a 100644 (file)
@@ -5269,6 +5269,7 @@ static struct omap_hwmod_ocp_if omap44xx_l4_per__mcbsp4 = {
 
 static struct omap_hwmod_addr_space omap44xx_mcpdm_addrs[] = {
        {
+               .name           = "mpu",
                .pa_start       = 0x40132000,
                .pa_end         = 0x4013207f,
                .flags          = ADDR_TYPE_RT
@@ -5287,6 +5288,7 @@ static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcpdm = {
 
 static struct omap_hwmod_addr_space omap44xx_mcpdm_dma_addrs[] = {
        {
+               .name           = "dma",
                .pa_start       = 0x49032000,
                .pa_end         = 0x4903207f,
                .flags          = ADDR_TYPE_RT
index 45f77413c21d10b70074ade36b984031eb8c05c5..18a8519594252df8b9a383373b9f5ccd0755044f 100644 (file)
@@ -519,3 +519,30 @@ void __init omap4_pmic_get_config(struct twl4030_platform_data *pmic_data,
                pmic_data->v2v1 = &omap4_v2v1_idata;
 }
 #endif /* CONFIG_ARCH_OMAP4 */
+
+#if defined(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) || \
+       defined(CONFIG_SND_OMAP_SOC_OMAP_TWL4030_MODULE)
+#include <linux/platform_data/omap-twl4030.h>
+
+static struct omap_tw4030_pdata omap_twl4030_audio_data;
+
+static struct platform_device audio_device = {
+       .name           = "omap-twl4030",
+       .id             = -1,
+       .dev = {
+               .platform_data = &omap_twl4030_audio_data,
+       },
+};
+
+void __init omap_twl4030_audio_init(char *card_name)
+{
+       omap_twl4030_audio_data.card_name = card_name;
+       platform_device_register(&audio_device);
+}
+
+#else /* SOC_OMAP_TWL4030 */
+void __init omap_twl4030_audio_init(char *card_name)
+{
+       return;
+}
+#endif /* SOC_OMAP_TWL4030 */
index 2256efe90cf1cfcc53990866cdccfcb58c2cca0c..dcfbad5ac471d211b72e1c39f22762de67aab6fc 100644 (file)
@@ -60,4 +60,6 @@ void omap3_pmic_get_config(struct twl4030_platform_data *pmic_data,
 void omap4_pmic_get_config(struct twl4030_platform_data *pmic_data,
                           u32 pdata_flags, u32 regulators_flags);
 
+void omap_twl4030_audio_init(char *card_name);
+
 #endif /* __OMAP_PMIC_COMMON__ */
index c38d75489240fc34476ef9bfd2a3caa010df2967..d088afa034e87bf2d4df760a690e1bdb33bc0281 100644 (file)
@@ -91,7 +91,8 @@ static int samsung_dmadev_prepare(unsigned ch,
                break;
        case DMA_CYCLIC:
                desc = dmaengine_prep_dma_cyclic(chan, param->buf,
-                       param->len, param->period, param->direction);
+                       param->len, param->period, param->direction,
+                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
                break;
        default:
                dev_err(&chan->dev->device, "unsupported format\n");
index fc179ca077994ea94f1e204294a892885c10ea2b..29f16e5c37b925cdbbd0447e536e77e35bc451c3 100644 (file)
@@ -587,6 +587,21 @@ static struct platform_device bfin_tdm = {
 };
 #endif
 
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
+               || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+static const char * const ad1836_link[] = {
+       "bfin-tdm.0",
+       "spi0.4",
+};
+static struct platform_device bfin_ad1836_machine = {
+       .name = "bfin-snd-ad1836",
+       .id = -1,
+       .dev = {
+               .platform_data = (void *)ad1836_link,
+       },
+};
+#endif
+
 static struct spi_board_info bfin_spi_board_info[] __initdata = {
 #if defined(CONFIG_MTD_M25P80) \
        || defined(CONFIG_MTD_M25P80_MODULE)
@@ -1269,6 +1284,11 @@ static struct platform_device *stamp_devices[] __initdata = {
 #if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
        &bfin_tdm,
 #endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) || \
+       defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+       &bfin_ad1836_machine,
+#endif
 };
 
 static int __init ezkit_init(void)
index ce88a7165b62a99dfbea8adcfbe59bc356760209..6fca8698bf3bce5c2108bef0bc86d529e5099e7b 100644 (file)
@@ -617,6 +617,21 @@ static struct platform_device bfin_ac97_pcm = {
 };
 #endif
 
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
+               || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+static const char * const ad1836_link[] = {
+       "bfin-tdm.0",
+       "spi0.4",
+};
+static struct platform_device bfin_ad1836_machine = {
+       .name = "bfin-snd-ad1836",
+       .id = -1,
+       .dev = {
+               .platform_data = (void *)ad1836_link,
+       },
+};
+#endif
+
 #if defined(CONFIG_SND_BF5XX_SOC_AD73311) || \
        defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
 static const unsigned ad73311_gpio[] = {
@@ -754,6 +769,11 @@ static struct platform_device *stamp_devices[] __initdata = {
        &bfin_ac97_pcm,
 #endif
 
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) || \
+       defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+       &bfin_ad1836_machine,
+#endif
+
 #if defined(CONFIG_SND_BF5XX_SOC_AD73311) || \
        defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
        &bfin_ad73311_machine,
index 5ed654ae66e14930399982a7b1310fa53cf58629..307bd7e62f437d0418e2a5682bc4881ae17f3b6a 100644 (file)
@@ -2641,6 +2641,21 @@ static struct platform_device bfin_ac97_pcm = {
 };
 #endif
 
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
+               || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+static const char * const ad1836_link[] = {
+       "bfin-tdm.0",
+       "spi0.4",
+};
+static struct platform_device bfin_ad1836_machine = {
+       .name = "bfin-snd-ad1836",
+       .id = -1,
+       .dev = {
+               .platform_data = (void *)ad1836_link,
+       },
+};
+#endif
+
 #if defined(CONFIG_SND_BF5XX_SOC_AD73311) || \
                                defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
 static const unsigned ad73311_gpio[] = {
@@ -2927,6 +2942,11 @@ static struct platform_device *stamp_devices[] __initdata = {
        &bfin_ac97_pcm,
 #endif
 
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) || \
+       defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+       &bfin_ad1836_machine,
+#endif
+
 #if defined(CONFIG_SND_BF5XX_SOC_AD73311) || \
                defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
        &bfin_ad73311_machine,
index 7c36777c645558315d651af24e992d0bd2f722f1..551f866172cf7ae51cd5af8e631a821c38ea5f80 100644 (file)
@@ -539,6 +539,21 @@ static struct platform_device bfin_ac97 = {
 };
 #endif
 
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
+               || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+static const char * const ad1836_link[] = {
+       "bfin-tdm.0",
+       "spi0.4",
+};
+static struct platform_device bfin_ad1836_machine = {
+       .name = "bfin-snd-ad1836",
+       .id = -1,
+       .dev = {
+               .platform_data = (void *)ad1836_link,
+       },
+};
+#endif
+
 static struct platform_device *ezkit_devices[] __initdata = {
 
        &bfin_dpmc,
@@ -603,6 +618,11 @@ static struct platform_device *ezkit_devices[] __initdata = {
 #if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
        &bfin_ac97,
 #endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) || \
+       defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+       &bfin_ad1836_machine,
+#endif
 };
 
 static int __init net2272_init(void)
index c2cf1ae31189cb2ce0be5d04e4b6450dc209bebe..61c1f47a4bf2969f38559746192e7a5a41004c8e 100644 (file)
@@ -818,6 +818,21 @@ static struct platform_device bfin_i2s = {
 };
 #endif
 
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
+               || defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+static const char * const ad1836_link[] = {
+       "bfin-tdm.0",
+       "spi0.76",
+};
+static struct platform_device bfin_ad1836_machine = {
+       .name = "bfin-snd-ad1836",
+       .id = -1,
+       .dev = {
+               .platform_data = (void *)ad1836_link,
+       },
+};
+#endif
+
 #if defined(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X61) || \
        defined(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X61_MODULE)
 static struct platform_device adau1761_device = {
@@ -1557,6 +1572,10 @@ static struct platform_device *ezkit_devices[] __initdata = {
        defined(CONFIG_SND_BF6XX_SOC_I2S_MODULE)
        &bfin_i2s,
 #endif
+#if defined(CONFIG_SND_BF5XX_SOC_AD1836) || \
+       defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
+       &bfin_ad1836_machine,
+#endif
 #if defined(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X61) || \
        defined(CONFIG_SND_SOC_BFIN_EVAL_ADAU1X61_MODULE)
        &adau1761_device,
index 17d6958342e7756dcb98aff9467461d1100e7d2e..13a02f4425b0db386c0bca43f7e019a099d26c92 100644 (file)
@@ -852,12 +852,13 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc,
  * @buf_len: total number of bytes for the entire buffer
  * @period_len: number of bytes for each period
  * @direction: transfer direction, to or from device
+ * @flags: tx descriptor status flags
  * @context: transfer context (ignored)
  */
 static struct dma_async_tx_descriptor *
 atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
                size_t period_len, enum dma_transfer_direction direction,
-               void *context)
+               unsigned long flags, void *context)
 {
        struct at_dma_chan      *atchan = to_at_dma_chan(chan);
        struct at_dma_slave     *atslave = chan->private;
index 64256f64425285748d8be20d15fad0b5492c993a..bcfde400904ff9a6dd05e957eb1159d5fc98f771 100644 (file)
@@ -1120,6 +1120,7 @@ fail:
  * @buf_len: length of the buffer (in bytes)
  * @period_len: length of a single period
  * @dir: direction of the operation
+ * @flags: tx descriptor status flags
  * @context: operation context (ignored)
  *
  * Prepares a descriptor for cyclic DMA operation. This means that once the
@@ -1133,7 +1134,8 @@ fail:
 static struct dma_async_tx_descriptor *
 ep93xx_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,
                           size_t buf_len, size_t period_len,
-                          enum dma_transfer_direction dir, void *context)
+                          enum dma_transfer_direction dir, unsigned long flags,
+                          void *context)
 {
        struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
        struct ep93xx_dma_desc *desc, *first;
index 2a3fab289db01720f74bd4f2be86a9b85b56c0dc..f11b5b2b1a1c1e41274ed7578ba197971e209f5a 100644 (file)
@@ -801,7 +801,7 @@ static struct dma_async_tx_descriptor *imxdma_prep_slave_sg(
 static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic(
                struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
                size_t period_len, enum dma_transfer_direction direction,
-               void *context)
+               unsigned long flags, void *context)
 {
        struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
        struct imxdma_engine *imxdma = imxdmac->imxdma;
index 1b781d6ac4254443dd4d03ab35318e918a93155d..c099ca0846f49dc76dcc29342940b29498ba68f9 100644 (file)
@@ -1012,7 +1012,7 @@ err_out:
 static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
                struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
                size_t period_len, enum dma_transfer_direction direction,
-               void *context)
+               unsigned long flags, void *context)
 {
        struct sdma_channel *sdmac = to_sdma_chan(chan);
        struct sdma_engine *sdma = sdmac->sdma;
index 07fa48688ba918d18f2f3dafc9f6ff181838fbbc..6d9c82e891d7c722505fe50507bd34218cb6bc2d 100644 (file)
@@ -358,7 +358,7 @@ struct mmp_tdma_desc *mmp_tdma_alloc_descriptor(struct mmp_tdma_chan *tdmac)
 static struct dma_async_tx_descriptor *mmp_tdma_prep_dma_cyclic(
                struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
                size_t period_len, enum dma_transfer_direction direction,
-               void *context)
+               unsigned long flags, void *context)
 {
        struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
        struct mmp_tdma_desc *desc;
index 7f41b25805fa071edfa9d74946c630c2a7528733..734a4eb84d6579675110033eeda6676ff40c4c91 100644 (file)
@@ -531,7 +531,7 @@ err_out:
 static struct dma_async_tx_descriptor *mxs_dma_prep_dma_cyclic(
                struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
                size_t period_len, enum dma_transfer_direction direction,
-               void *context)
+               unsigned long flags, void *context)
 {
        struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
        struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
index 2e1662777661ca59ec652860ca2a2fccb5596266..bb2d8e7029eb638c8d18f9ed3a9db01d795aef2c 100644 (file)
@@ -36,6 +36,7 @@ struct omap_chan {
        struct dma_slave_config cfg;
        unsigned dma_sig;
        bool cyclic;
+       bool paused;
 
        int dma_ch;
        struct omap_desc *desc;
@@ -367,7 +368,8 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg(
 
 static struct dma_async_tx_descriptor *omap_dma_prep_dma_cyclic(
        struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
-       size_t period_len, enum dma_transfer_direction dir, void *context)
+       size_t period_len, enum dma_transfer_direction dir, unsigned long flags,
+       void *context)
 {
        struct omap_chan *c = to_omap_dma_chan(chan);
        enum dma_slave_buswidth dev_width;
@@ -415,7 +417,10 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_cyclic(
        d->dev_addr = dev_addr;
        d->fi = burst;
        d->es = es;
-       d->sync_mode = OMAP_DMA_SYNC_PACKET;
+       if (burst)
+               d->sync_mode = OMAP_DMA_SYNC_PACKET;
+       else
+               d->sync_mode = OMAP_DMA_SYNC_ELEMENT;
        d->sync_type = sync_type;
        d->periph_port = OMAP_DMA_PORT_MPUI;
        d->sg[0].addr = buf_addr;
@@ -426,7 +431,10 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_cyclic(
        if (!c->cyclic) {
                c->cyclic = true;
                omap_dma_link_lch(c->dma_ch, c->dma_ch);
-               omap_enable_dma_irq(c->dma_ch, OMAP_DMA_FRAME_IRQ);
+
+               if (flags & DMA_PREP_INTERRUPT)
+                       omap_enable_dma_irq(c->dma_ch, OMAP_DMA_FRAME_IRQ);
+
                omap_disable_dma_irq(c->dma_ch, OMAP_DMA_BLOCK_IRQ);
        }
 
@@ -435,7 +443,7 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_cyclic(
                omap_set_dma_dest_burst_mode(c->dma_ch, OMAP_DMA_DATA_BURST_16);
        }
 
-       return vchan_tx_prep(&c->vc, &d->vd, DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
+       return vchan_tx_prep(&c->vc, &d->vd, flags);
 }
 
 static int omap_dma_slave_config(struct omap_chan *c, struct dma_slave_config *cfg)
@@ -469,11 +477,14 @@ static int omap_dma_terminate_all(struct omap_chan *c)
         */
        if (c->desc) {
                c->desc = NULL;
-               omap_stop_dma(c->dma_ch);
+               /* Avoid stopping the dma twice */
+               if (!c->paused)
+                       omap_stop_dma(c->dma_ch);
        }
 
        if (c->cyclic) {
                c->cyclic = false;
+               c->paused = false;
                omap_dma_unlink_lch(c->dma_ch, c->dma_ch);
        }
 
@@ -486,14 +497,30 @@ static int omap_dma_terminate_all(struct omap_chan *c)
 
 static int omap_dma_pause(struct omap_chan *c)
 {
-       /* FIXME: not supported by platform private API */
-       return -EINVAL;
+       /* Pause/Resume only allowed with cyclic mode */
+       if (!c->cyclic)
+               return -EINVAL;
+
+       if (!c->paused) {
+               omap_stop_dma(c->dma_ch);
+               c->paused = true;
+       }
+
+       return 0;
 }
 
 static int omap_dma_resume(struct omap_chan *c)
 {
-       /* FIXME: not supported by platform private API */
-       return -EINVAL;
+       /* Pause/Resume only allowed with cyclic mode */
+       if (!c->cyclic)
+               return -EINVAL;
+
+       if (c->paused) {
+               omap_start_dma(c->dma_ch);
+               c->paused = false;
+       }
+
+       return 0;
 }
 
 static int omap_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
index 5d3bbcd279b47361a6cf112cd760f446b615363a..169c0dbd71aef5d171ca9b5ec9af8626939366b0 100644 (file)
@@ -2685,7 +2685,7 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len)
 static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
                struct dma_chan *chan, dma_addr_t dma_addr, size_t len,
                size_t period_len, enum dma_transfer_direction direction,
-               void *context)
+               unsigned long flags, void *context)
 {
        struct dma_pl330_desc *desc;
        struct dma_pl330_chan *pch = to_pchan(chan);
index f5a73606217ee6118f9562e5f49b34338691611e..b893159c1ecb0c9f1ff68d667f8df5fc0cedeb80 100644 (file)
@@ -614,7 +614,7 @@ static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg(
 
 static struct dma_async_tx_descriptor *sa11x0_dma_prep_dma_cyclic(
        struct dma_chan *chan, dma_addr_t addr, size_t size, size_t period,
-       enum dma_transfer_direction dir, void *context)
+       enum dma_transfer_direction dir, unsigned long flags, void *context)
 {
        struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
        struct sa11x0_dma_desc *txd;
index 434ad31174f289f6a2cc14ac6121b594d2b09207..3eed8b35b0f19d51f025a5de2dc656b9fe3f211c 100644 (file)
@@ -489,7 +489,7 @@ err_dir:
 static struct dma_async_tx_descriptor *
 sirfsoc_dma_prep_cyclic(struct dma_chan *chan, dma_addr_t addr,
        size_t buf_len, size_t period_len,
-       enum dma_transfer_direction direction, void *context)
+       enum dma_transfer_direction direction, unsigned long flags, void *context)
 {
        struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
        struct sirfsoc_dma_desc *sdesc = NULL;
index 000d309602b2d76fd825d895be5ab5b91837d19f..eee8d9b9a20bcdfde84eaa75dc05617b0524dd36 100644 (file)
@@ -2347,7 +2347,8 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan,
 static struct dma_async_tx_descriptor *
 dma40_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,
                     size_t buf_len, size_t period_len,
-                    enum dma_transfer_direction direction, void *context)
+                    enum dma_transfer_direction direction, unsigned long flags,
+                    void *context)
 {
        unsigned int periods = buf_len / period_len;
        struct dma_async_tx_descriptor *txd;
index 4708467e4d83fd1cc5219a8fc24ddaf3081bd804..45fbeed1c1a5e56d621254399d4b7c63b93861df 100644 (file)
@@ -990,7 +990,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg(
 struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic(
        struct dma_chan *dc, dma_addr_t buf_addr, size_t buf_len,
        size_t period_len, enum dma_transfer_direction direction,
-       void *context)
+       unsigned long flags, void *context)
 {
        struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
        struct tegra_dma_desc *dma_desc = NULL;
index 9c02a4508b25380123ab6e2b24c6879645b2961a..d3201e438d1640ff51339514a561fc2347427220 100644 (file)
@@ -591,7 +591,7 @@ struct dma_device {
        struct dma_async_tx_descriptor *(*device_prep_dma_cyclic)(
                struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
                size_t period_len, enum dma_transfer_direction direction,
-               void *context);
+               unsigned long flags, void *context);
        struct dma_async_tx_descriptor *(*device_prep_interleaved_dma)(
                struct dma_chan *chan, struct dma_interleaved_template *xt,
                unsigned long flags);
@@ -653,10 +653,11 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_rio_sg(
 
 static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic(
                struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
-               size_t period_len, enum dma_transfer_direction dir)
+               size_t period_len, enum dma_transfer_direction dir,
+               unsigned long flags)
 {
        return chan->device->device_prep_dma_cyclic(chan, buf_addr, buf_len,
-                                               period_len, dir, NULL);
+                                               period_len, dir, flags, NULL);
 }
 
 static inline int dmaengine_terminate_all(struct dma_chan *chan)
index 1faa58f9b85edefe0d9e76c7372173baafa20f26..9a5e28462324ba422ca9d3891a2109f1db47ae04 100644 (file)
@@ -664,7 +664,7 @@ struct twl4030_codec_data {
        unsigned int check_defaults:1;
        unsigned int reset_registers:1;
        unsigned int hs_extmute:1;
-       void (*set_hs_extmute)(int mute);
+       int hs_extmute_gpio;
 };
 
 struct twl4030_vibra_data {
index f0361c031927417ee9af47ef0a2be55e718e344d..fc87be4fdc2501a8106b18664102c793ccdb588b 100644 (file)
@@ -164,6 +164,10 @@ struct wm8994_pdata {
        int num_micd_rates;
        struct wm8958_micd_rate *micd_rates;
 
+       /* Power up delays to add after microphone bias power up (ms) */
+       int micb1_delay;
+       int micb2_delay;
+
         /* LINEOUT can be differential or single ended */
         unsigned int lineout1_diff:1;
         unsigned int lineout2_diff:1;
diff --git a/include/linux/platform_data/asoc-mx27vis.h b/include/linux/platform_data/asoc-mx27vis.h
new file mode 100644 (file)
index 0000000..409adcd
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __PLATFORM_DATA_ASOC_MX27VIS_H
+#define __PLATFORM_DATA_ASOC_MX27VIS_H
+
+struct snd_mx27vis_platform_data {
+       int amp_gain0_gpio;
+       int amp_gain1_gpio;
+       int amp_mutel_gpio;
+       int amp_muter_gpio;
+};
+
+#endif /* __PLATFORM_DATA_ASOC_MX27VIS_H */
index 18814127809aa031d3d5abc1ff64c5000ba1cd49..c78d90b28b19f4646ad9ab113ec3e8ad2d0f8ef1 100644 (file)
@@ -47,8 +47,6 @@ struct omap_mcbsp_platform_data {
        bool has_wakeup; /* Wakeup capability */
        bool has_ccr; /* Transceiver has configuration control registers */
        int (*enable_st_clock)(unsigned int, bool);
-       int (*set_clk_src)(struct device *dev, struct clk *clk, const char *src);
-       int (*mux_signal)(struct device *dev, const char *signal, const char *src);
 };
 
 /**
similarity index 56%
rename from arch/arm/mach-davinci/include/mach/asp.h
rename to include/linux/platform_data/davinci_asp.h
index 9aa240909a2cf4f9dac7bc1afc560712d9020ba2..d0c5825876f8a2d1d124a3d51fac880951a63b2f 100644 (file)
@@ -1,59 +1,26 @@
 /*
- * <mach/asp.h> - DaVinci Audio Serial Port support
+ * TI DaVinci Audio Serial Port support
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
  */
-#ifndef __ASM_ARCH_DAVINCI_ASP_H
-#define __ASM_ARCH_DAVINCI_ASP_H
 
-#include <mach/irqs.h>
-#include <mach/edma.h>
-
-/* Bases of dm644x and dm355 register banks */
-#define DAVINCI_ASP0_BASE      0x01E02000
-#define DAVINCI_ASP1_BASE      0x01E04000
-
-/* Bases of dm365 register banks */
-#define DAVINCI_DM365_ASP0_BASE        0x01D02000
-
-/* Bases of dm646x register banks */
-#define        DAVINCI_DM646X_MCASP0_REG_BASE          0x01D01000
-#define DAVINCI_DM646X_MCASP1_REG_BASE         0x01D01800
-
-/* Bases of da850/da830 McASP0  register banks */
-#define DAVINCI_DA8XX_MCASP0_REG_BASE  0x01D00000
-
-/* Bases of da830 McASP1 register banks */
-#define DAVINCI_DA830_MCASP1_REG_BASE  0x01D04000
-
-/* EDMA channels of dm644x and dm355 */
-#define DAVINCI_DMA_ASP0_TX    2
-#define DAVINCI_DMA_ASP0_RX    3
-#define DAVINCI_DMA_ASP1_TX    8
-#define DAVINCI_DMA_ASP1_RX    9
-
-/* EDMA channels of dm646x */
-#define        DAVINCI_DM646X_DMA_MCASP0_AXEVT0        6
-#define        DAVINCI_DM646X_DMA_MCASP0_AREVT0        9
-#define        DAVINCI_DM646X_DMA_MCASP1_AXEVT1        12
-
-/* EDMA channels of da850/da830 McASP0 */
-#define        DAVINCI_DA8XX_DMA_MCASP0_AREVT  0
-#define        DAVINCI_DA8XX_DMA_MCASP0_AXEVT  1
-
-/* EDMA channels of da830 McASP1 */
-#define        DAVINCI_DA830_DMA_MCASP1_AREVT  2
-#define        DAVINCI_DA830_DMA_MCASP1_AXEVT  3
-
-/* Interrupts */
-#define DAVINCI_ASP0_RX_INT    IRQ_MBRINT
-#define DAVINCI_ASP0_TX_INT    IRQ_MBXINT
-#define DAVINCI_ASP1_RX_INT    IRQ_MBRINT
-#define DAVINCI_ASP1_TX_INT    IRQ_MBXINT
+#ifndef __DAVINCI_ASP_H
+#define __DAVINCI_ASP_H
 
 struct snd_platform_data {
        u32 tx_dma_offset;
        u32 rx_dma_offset;
-       enum dma_event_q asp_chan_q;    /* event queue number for ASP channel */
-       enum dma_event_q ram_chan_q;    /* event queue number for RAM channel */
+       int asp_chan_q; /* event queue number for ASP channel */
+       int ram_chan_q; /* event queue number for RAM channel */
        unsigned int codec_fmt;
        /*
         * Allowing this is more efficient and eliminates left and right swaps
@@ -70,7 +37,7 @@ struct snd_platform_data {
         * and MCBSP_CLKS.
         * Depending on different hardware connections it is possible
         * to use this setting to change the behaviour of McBSP
-        * driver. The dm365_clk_input_pin enum is available for dm365
+        * driver.
         */
        int clk_input_pin;
 
@@ -120,10 +87,11 @@ struct snd_platform_data {
 enum {
        MCASP_VERSION_1 = 0,    /* DM646x */
        MCASP_VERSION_2,        /* DA8xx/OMAPL1x */
+       MCASP_VERSION_3,        /* TI81xx/AM33xx */
 };
 
-enum dm365_clk_input_pin {
-       MCBSP_CLKR = 0,         /* DM365 */
+enum mcbsp_clk_input_pin {
+       MCBSP_CLKR = 0,         /* as in DM365 */
        MCBSP_CLKS,
 };
 
@@ -134,4 +102,4 @@ enum dm365_clk_input_pin {
 #define DAVINCI_MCASP_IIS_MODE 0
 #define DAVINCI_MCASP_DIT_MODE 1
 
-#endif /* __ASM_ARCH_DAVINCI_ASP_H */
+#endif
diff --git a/include/linux/platform_data/omap-twl4030.h b/include/linux/platform_data/omap-twl4030.h
new file mode 100644 (file)
index 0000000..c7bef78
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+ * omap-twl4030.h - ASoC machine driver for TI SoC based boards with twl4030
+ *                 codec, header.
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
+ * All rights reserved.
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef _OMAP_TWL4030_H_
+#define _OMAP_TWL4030_H_
+
+struct omap_tw4030_pdata {
+       const char *card_name;
+};
+
+#endif /* _OMAP_TWL4030_H_ */
index fdeb8dceec0f400cccf6358bd7335b4b421eb078..d315a08d6c6d4e359b550a56b6e89515d4dd5898 100644 (file)
  */
 
 struct snd_ac97;
+struct snd_pcm_chmap;
 
 struct snd_ac97_build_ops {
        int (*build_3d) (struct snd_ac97 *ac97);
@@ -528,6 +529,8 @@ struct snd_ac97 {
        struct delayed_work power_work;
 #endif
        struct device dev;
+
+       struct snd_pcm_chmap *chmaps[2]; /* channel-maps (optional) */
 };
 
 #define to_ac97_t(d) container_of(d, struct snd_ac97, dev)
index a7d8dc782e7c4b324818fea5f012edad2a24731e..abdf609c5918ab0d1baf94ee4158a3c9ada1622b 100644 (file)
@@ -147,6 +147,9 @@ struct snd_ad1816a {
        unsigned int c_dma_size;
 
        struct snd_timer *timer;
+#ifdef CONFIG_PM
+       unsigned short image[48];
+#endif
 };
 
 
@@ -165,11 +168,15 @@ struct snd_ad1816a {
 
 extern int snd_ad1816a_create(struct snd_card *card, unsigned long port,
                              int irq, int dma1, int dma2,
-                             struct snd_ad1816a **chip);
+                             struct snd_ad1816a *chip);
 
 extern int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm);
 extern int snd_ad1816a_mixer(struct snd_ad1816a *chip);
 extern int snd_ad1816a_timer(struct snd_ad1816a *chip, int device,
                             struct snd_timer **rtimer);
+#ifdef CONFIG_PM
+extern void snd_ad1816a_suspend(struct snd_ad1816a *chip);
+extern void snd_ad1816a_resume(struct snd_ad1816a *chip);
+#endif
 
 #endif /* __SOUND_AD1816A_H */
index 0876a1e76aefbd97dc66eb76d480e7e05573f68d..dfe7d441748c208501d0cc3c3806ba293da9b862 100644 (file)
@@ -472,6 +472,45 @@ enum {
        SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,
 };
 
+/* channel positions */
+enum {
+       SNDRV_CHMAP_UNKNOWN = 0,
+       SNDRV_CHMAP_NA,         /* N/A, silent */
+       SNDRV_CHMAP_MONO,       /* mono stream */
+       /* this follows the alsa-lib mixer channel value + 3 */
+       SNDRV_CHMAP_FL,         /* front left */
+       SNDRV_CHMAP_FR,         /* front right */
+       SNDRV_CHMAP_RL,         /* rear left */
+       SNDRV_CHMAP_RR,         /* rear right */
+       SNDRV_CHMAP_FC,         /* front center */
+       SNDRV_CHMAP_LFE,        /* LFE */
+       SNDRV_CHMAP_SL,         /* side left */
+       SNDRV_CHMAP_SR,         /* side right */
+       SNDRV_CHMAP_RC,         /* rear center */
+       /* new definitions */
+       SNDRV_CHMAP_FLC,        /* front left center */
+       SNDRV_CHMAP_FRC,        /* front right center */
+       SNDRV_CHMAP_RLC,        /* rear left center */
+       SNDRV_CHMAP_RRC,        /* rear right center */
+       SNDRV_CHMAP_FLW,        /* front left wide */
+       SNDRV_CHMAP_FRW,        /* front right wide */
+       SNDRV_CHMAP_FLH,        /* front left high */
+       SNDRV_CHMAP_FCH,        /* front center high */
+       SNDRV_CHMAP_FRH,        /* front right high */
+       SNDRV_CHMAP_TC,         /* top center */
+       SNDRV_CHMAP_TFL,        /* top front left */
+       SNDRV_CHMAP_TFR,        /* top front right */
+       SNDRV_CHMAP_TFC,        /* top front center */
+       SNDRV_CHMAP_TRL,        /* top rear left */
+       SNDRV_CHMAP_TRR,        /* top rear right */
+       SNDRV_CHMAP_TRC,        /* top rear center */
+       SNDRV_CHMAP_LAST = SNDRV_CHMAP_TRC,
+};
+
+#define SNDRV_CHMAP_POSITION_MASK      0xffff
+#define SNDRV_CHMAP_PHASE_INVERSE      (0x01 << 16)
+#define SNDRV_CHMAP_DRIVER_SPEC                (0x02 << 16)
+
 #define SNDRV_PCM_IOCTL_PVERSION       _IOR('A', 0x00, int)
 #define SNDRV_PCM_IOCTL_INFO           _IOR('A', 0x01, struct snd_pcm_info)
 #define SNDRV_PCM_IOCTL_TSTAMP         _IOW('A', 0x02, int)
index 48f2a1ff2bbc81036238751465d5b2fad3cc9eee..f2912abacdf33b31911e1f321dfae7595b963d27 100644 (file)
@@ -61,6 +61,7 @@ struct snd_compr_runtime {
        u64 total_bytes_available;
        u64 total_bytes_transferred;
        wait_queue_head_t sleep;
+       void *private_data;
 };
 
 /**
index da4a456de032fb24dd75132f033f8c104b1b710a..602dc6c45d1a091fb548ac586c69813f25f4f508 100644 (file)
@@ -72,6 +72,7 @@
 #define SND_AUDIOCODEC_IEC61937              ((__u32) 0x0000000B)
 #define SND_AUDIOCODEC_G723_1                ((__u32) 0x0000000C)
 #define SND_AUDIOCODEC_G729                  ((__u32) 0x0000000D)
+#define SND_AUDIOCODEC_MAX                   SND_AUDIOCODEC_G729
 
 /*
  * Profile and modes are listed with bit masks. This allows for a
diff --git a/include/sound/da9055.h b/include/sound/da9055.h
new file mode 100644 (file)
index 0000000..cf1241b
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * DA9055 ALSA Soc codec driver
+ *
+ * Copyright (c) 2012 Dialog Semiconductor
+ *
+ * Tested on (Samsung SMDK6410 board + DA9055 EVB) using I2S and I2C
+ * Written by David Chen <david.chen@diasemi.com> and
+ * Ashish Chavan <ashish.chavan@kpitcummins.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __SOUND_DA9055_H__
+#define __SOUND_DA9055_H__
+
+enum da9055_micbias_voltage {
+       DA9055_MICBIAS_1_6V = 0,
+       DA9055_MICBIAS_1_8V = 1,
+       DA9055_MICBIAS_2_1V = 2,
+       DA9055_MICBIAS_2_2V = 3,
+};
+
+struct da9055_platform_data {
+       /* Selects which of the two MicBias pins acts as the bias source */
+       bool micbias_source;
+       /* Selects the micbias voltage */
+       enum da9055_micbias_voltage micbias;
+};
+
+#endif
index 4f865df42f0f9daf2e078b6a26c1b108638454ba..1a33f48ebe7875f6ae6b6769583646a2e501dae9 100644 (file)
@@ -1788,7 +1788,7 @@ struct snd_emu10k1 {
        unsigned int efx_voices_mask[2];
        unsigned int next_free_voice;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        unsigned int *saved_ptr;
        unsigned int *saved_gpr;
        unsigned int *tram_val_saved;
@@ -1856,7 +1856,7 @@ unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg);
 void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data);
 unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 void snd_emu10k1_suspend_regs(struct snd_emu10k1 *emu);
 void snd_emu10k1_resume_init(struct snd_emu10k1 *emu);
 void snd_emu10k1_resume_regs(struct snd_emu10k1 *emu);
index f99a0d2ddfe7b9e4e099fc386161be546a08fca4..ac62c67e6f4273ce361dd8b216b2cf05a07583e0 100644 (file)
 #define SNDRV_DEFAULT_DMA_SIZE { [0 ... (SNDRV_CARDS-1)] = SNDRV_AUTO_DMA_SIZE }
 #define SNDRV_DEFAULT_PTR      SNDRV_DEFAULT_STR
 
+#ifdef SNDRV_LEGACY_FIND_FREE_IOPORT
+static long snd_legacy_find_free_ioport(long *port_table, long size)
+{
+       while (*port_table != -1) {
+               if (request_region(*port_table, size, "ALSA test")) {
+                       release_region(*port_table, size);
+                       return *port_table;
+               }
+               port_table++;
+       }
+       return -1;
+}
+#endif
+
 #ifdef SNDRV_LEGACY_FIND_FREE_IRQ
 #include <linux/interrupt.h>
 
index c42506212649938d73c3cf611e3325ed95af7e4e..844af65af6261a73ad4502ecb98188a6280a3f8d 100644 (file)
@@ -98,8 +98,10 @@ static inline unsigned int snd_sgbuf_aligned_pages(size_t size)
 /*
  * return the physical address at the corresponding offset
  */
-static inline dma_addr_t snd_sgbuf_get_addr(struct snd_sg_buf *sgbuf, size_t offset)
+static inline dma_addr_t snd_sgbuf_get_addr(struct snd_dma_buffer *dmab,
+                                          size_t offset)
 {
+       struct snd_sg_buf *sgbuf = dmab->private_data;
        dma_addr_t addr = sgbuf->table[offset >> PAGE_SHIFT].addr;
        addr &= PAGE_MASK;
        return addr + offset % PAGE_SIZE;
@@ -108,10 +110,31 @@ static inline dma_addr_t snd_sgbuf_get_addr(struct snd_sg_buf *sgbuf, size_t off
 /*
  * return the virtual address at the corresponding offset
  */
-static inline void *snd_sgbuf_get_ptr(struct snd_sg_buf *sgbuf, size_t offset)
+static inline void *snd_sgbuf_get_ptr(struct snd_dma_buffer *dmab,
+                                    size_t offset)
 {
+       struct snd_sg_buf *sgbuf = dmab->private_data;
        return sgbuf->table[offset >> PAGE_SHIFT].buf + offset % PAGE_SIZE;
 }
+
+unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
+                                     unsigned int ofs, unsigned int size);
+#else
+/* non-SG versions */
+static inline dma_addr_t snd_sgbuf_get_addr(struct snd_dma_buffer *dmab,
+                                           size_t offset)
+{
+       return dmab->addr + offset;
+}
+
+static inline void *snd_sgbuf_get_ptr(struct snd_dma_buffer *dmab,
+                                     size_t offset)
+{
+       return dmab->area + offset;
+}
+
+#define snd_sgbuf_get_chunk_size(dmab, ofs, size)      (size)
+
 #endif /* CONFIG_SND_DMA_SGBUF */
 
 /* allocate/release a buffer */
index d0711bc8c914c6d890743b6bef9bc17f51c8f539..6268a4192d5c4a3300a5792ceb08610386b9256d 100644 (file)
@@ -437,6 +437,7 @@ struct snd_pcm_str {
        struct snd_info_entry *proc_xrun_debug_entry;
 #endif
 #endif
+       struct snd_kcontrol *chmap_kctl; /* channel-mapping controls */
 };
 
 struct snd_pcm {
@@ -982,53 +983,42 @@ static int snd_pcm_lib_alloc_vmalloc_32_buffer
        _snd_pcm_lib_alloc_vmalloc_buffer \
                        (subs, size, GFP_KERNEL | GFP_DMA32 | __GFP_ZERO)
 
+#define snd_pcm_get_dma_buf(substream) ((substream)->runtime->dma_buffer_p)
+
 #ifdef CONFIG_SND_DMA_SGBUF
 /*
  * SG-buffer handling
  */
 #define snd_pcm_substream_sgbuf(substream) \
-       ((substream)->runtime->dma_buffer_p->private_data)
-
-static inline dma_addr_t
-snd_pcm_sgbuf_get_addr(struct snd_pcm_substream *substream, unsigned int ofs)
-{
-       struct snd_sg_buf *sg = snd_pcm_substream_sgbuf(substream);
-       return snd_sgbuf_get_addr(sg, ofs);
-}
-
-static inline void *
-snd_pcm_sgbuf_get_ptr(struct snd_pcm_substream *substream, unsigned int ofs)
-{
-       struct snd_sg_buf *sg = snd_pcm_substream_sgbuf(substream);
-       return snd_sgbuf_get_ptr(sg, ofs);
-}
+       snd_pcm_get_dma_buf(substream)->private_data
 
 struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream,
                                    unsigned long offset);
-unsigned int snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
-                                         unsigned int ofs, unsigned int size);
-
 #else /* !SND_DMA_SGBUF */
 /*
  * fake using a continuous buffer
  */
+#define snd_pcm_sgbuf_ops_page NULL
+#endif /* SND_DMA_SGBUF */
+
 static inline dma_addr_t
 snd_pcm_sgbuf_get_addr(struct snd_pcm_substream *substream, unsigned int ofs)
 {
-       return substream->runtime->dma_addr + ofs;
+       return snd_sgbuf_get_addr(snd_pcm_get_dma_buf(substream), ofs);
 }
 
 static inline void *
 snd_pcm_sgbuf_get_ptr(struct snd_pcm_substream *substream, unsigned int ofs)
 {
-       return substream->runtime->dma_area + ofs;
+       return snd_sgbuf_get_ptr(snd_pcm_get_dma_buf(substream), ofs);
 }
 
-#define snd_pcm_sgbuf_ops_page NULL
-
-#define snd_pcm_sgbuf_get_chunk_size(subs, ofs, size)  (size)
-
-#endif /* SND_DMA_SGBUF */
+static inline unsigned int
+snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
+                            unsigned int ofs, unsigned int size)
+{
+       return snd_sgbuf_get_chunk_size(snd_pcm_get_dma_buf(substream), ofs, size);
+}
 
 /* handle mmap counter - PCM mmap callback should handle this counter properly */
 static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area)
@@ -1086,4 +1076,51 @@ static inline const char *snd_pcm_stream_str(struct snd_pcm_substream *substream
                return "Capture";
 }
 
+/*
+ * PCM channel-mapping control API
+ */
+/* array element of channel maps */
+struct snd_pcm_chmap_elem {
+       unsigned char channels;
+       unsigned char map[15];
+};
+
+/* channel map information; retrieved via snd_kcontrol_chip() */
+struct snd_pcm_chmap {
+       struct snd_pcm *pcm;    /* assigned PCM instance */
+       int stream;             /* PLAYBACK or CAPTURE */
+       struct snd_kcontrol *kctl;
+       const struct snd_pcm_chmap_elem *chmap;
+       unsigned int max_channels;
+       unsigned int channel_mask;      /* optional: active channels bitmask */
+       void *private_data;     /* optional: private data pointer */
+};
+
+/* get the PCM substream assigned to the given chmap info */
+static inline struct snd_pcm_substream *
+snd_pcm_chmap_substream(struct snd_pcm_chmap *info, unsigned int idx)
+{
+       struct snd_pcm_substream *s;
+       for (s = info->pcm->streams[info->stream].substream; s; s = s->next)
+               if (s->number == idx)
+                       return s;
+       return NULL;
+}
+
+/* ALSA-standard channel maps (RL/RR prior to C/LFE) */
+extern const struct snd_pcm_chmap_elem snd_pcm_std_chmaps[];
+/* Other world's standard channel maps (C/LFE prior to RL/RR) */
+extern const struct snd_pcm_chmap_elem snd_pcm_alt_chmaps[];
+
+/* bit masks to be passed to snd_pcm_chmap.channel_mask field */
+#define SND_PCM_CHMAP_MASK_24  ((1U << 2) | (1U << 4))
+#define SND_PCM_CHMAP_MASK_246 (SND_PCM_CHMAP_MASK_24 | (1U << 6))
+#define SND_PCM_CHMAP_MASK_2468        (SND_PCM_CHMAP_MASK_246 | (1U << 8))
+
+int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
+                          const struct snd_pcm_chmap_elem *chmap,
+                          int max_channels,
+                          unsigned long private_value,
+                          struct snd_pcm_chmap **info_ret);
+
 #endif /* __SOUND_PCM_H */
index 1f69e0af2941803ac4452ec509baccbbd2f05f92..628db7bca4fd0a3f8186b3e80a91adb6b48fb0dd 100644 (file)
@@ -18,6 +18,7 @@
 
 struct snd_pcm_substream;
 struct snd_soc_dapm_widget;
+struct snd_compr_stream;
 
 /*
  * DAI hardware audio formats.
@@ -205,6 +206,8 @@ struct snd_soc_dai_driver {
        int (*remove)(struct snd_soc_dai *dai);
        int (*suspend)(struct snd_soc_dai *dai);
        int (*resume)(struct snd_soc_dai *dai);
+       /* compress dai */
+       bool compress_dai;
 
        /* ops */
        const struct snd_soc_dai_ops *ops;
index abe373d57adca91889784d9b1a69b27cb59b662f..e1ef63d4a5c453b17630b279d5780b32f1e722c3 100644 (file)
@@ -244,10 +244,11 @@ struct device;
 {      .id = snd_soc_dapm_supply, .name = wname, .reg = wreg,  \
        .shift = wshift, .invert = winvert, .event = wevent, \
        .event_flags = wflags}
-#define SND_SOC_DAPM_REGULATOR_SUPPLY(wname, wdelay) \
+#define SND_SOC_DAPM_REGULATOR_SUPPLY(wname, wdelay, wflags)       \
 {      .id = snd_soc_dapm_regulator_supply, .name = wname, \
        .reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \
-       .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }
+       .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \
+       .invert = wflags}
 
 
 /* dapm kcontrol types */
@@ -319,6 +320,9 @@ struct device;
 #define SND_SOC_DAPM_EVENT_OFF(e)      \
        (e & (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD))
 
+/* regulator widget flags */
+#define SND_SOC_DAPM_REGULATOR_BYPASS     0x1     /* bypass when disabled */
+
 struct snd_soc_dapm_widget;
 enum snd_soc_dapm_type;
 struct snd_soc_dapm_path;
@@ -412,6 +416,7 @@ void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec);
 
 /* Mostly internal - should not normally be used */
 void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason);
+void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm);
 
 /* dapm path query */
 int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
@@ -510,7 +515,6 @@ struct snd_soc_dapm_widget {
        /* dapm control */
        int reg;                                /* negative reg = no direct dapm */
        unsigned char shift;                    /* bits to shift */
-       unsigned int saved_value;               /* widget saved value */
        unsigned int value;                             /* widget current value */
        unsigned int mask;                      /* non-shifted mask */
        unsigned int on_val;                    /* on state value */
index e063380f63a2517f724641f5f84d7a300f95335c..91244a096c190223c17272aa23d219f47b40ab71 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/regmap.h>
+#include <linux/log2.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
+#include <sound/compress_driver.h>
 #include <sound/control.h>
 #include <sound/ac97_codec.h>
 
                 .platform_max = xmax} }
 #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmax, xtexts) \
 {      .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
-       .max = xmax, .texts = xtexts }
+       .max = xmax, .texts = xtexts, \
+       .mask = xmax ? roundup_pow_of_two(xmax) - 1 : 0}
 #define SOC_ENUM_SINGLE(xreg, xshift, xmax, xtexts) \
        SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmax, xtexts)
 #define SOC_ENUM_SINGLE_EXT(xmax, xtexts) \
@@ -399,6 +402,7 @@ int snd_soc_platform_read(struct snd_soc_platform *platform,
 int snd_soc_platform_write(struct snd_soc_platform *platform,
                                        unsigned int reg, unsigned int val);
 int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
+int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num);
 
 struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
                const char *dai_link, int stream);
@@ -632,6 +636,13 @@ struct snd_soc_ops {
        int (*trigger)(struct snd_pcm_substream *, int);
 };
 
+struct snd_soc_compr_ops {
+       int (*startup)(struct snd_compr_stream *);
+       void (*shutdown)(struct snd_compr_stream *);
+       int (*set_params)(struct snd_compr_stream *);
+       int (*trigger)(struct snd_compr_stream *);
+};
+
 /* SoC cache ops */
 struct snd_soc_cache_ops {
        const char *name;
@@ -787,9 +798,12 @@ struct snd_soc_platform_driver {
        snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
                struct snd_soc_dai *);
 
-       /* platform stream ops */
+       /* platform stream pcm ops */
        struct snd_pcm_ops *ops;
 
+       /* platform stream compress ops */
+       struct snd_compr_ops *compr_ops;
+
        /* platform stream completion event */
        int (*stream_event)(struct snd_soc_dapm_context *dapm, int event);
 
@@ -891,6 +905,7 @@ struct snd_soc_dai_link {
 
        /* machine stream operations */
        struct snd_soc_ops *ops;
+       struct snd_soc_compr_ops *compr_ops;
 };
 
 struct snd_soc_codec_conf {
@@ -1027,6 +1042,7 @@ struct snd_soc_pcm_runtime {
 
        /* runtime devices */
        struct snd_pcm *pcm;
+       struct snd_compr *compr;
        struct snd_soc_codec *codec;
        struct snd_soc_platform *platform;
        struct snd_soc_dai *codec_dai;
similarity index 89%
rename from arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h
rename to include/sound/tegra_wm8903.h
index 9d293344a7ff52b4a71d489fcbebd3ca48da0bb0..57b202ee97c39d5b88a4134aa3a02f6999146df8 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h
- *
  * Copyright 2011 NVIDIA, Inc.
  *
  * This software is licensed under the terms of the GNU General Public
@@ -14,6 +12,9 @@
  *
  */
 
+#ifndef __SOUND_TEGRA_WM38903_H
+#define __SOUND_TEGRA_WM38903_H
+
 struct tegra_wm8903_platform_data {
        int gpio_spkr_en;
        int gpio_hp_det;
@@ -21,3 +22,5 @@ struct tegra_wm8903_platform_data {
        int gpio_int_mic_en;
        int gpio_ext_mic_en;
 };
+
+#endif
index a64d8fe3f855b408e5c45ffae359d23ebb6db7eb..28c65e1ada21e8f632422055d70d66789d63a3d5 100644 (file)
 
 #define TLV_DB_GAIN_MUTE       -9999999
 
+/*
+ * channel-mapping TLV items
+ *  TLV length must match with num_channels
+ */
+#define SNDRV_CTL_TLVT_CHMAP_FIXED     0x101   /* fixed channel position */
+#define SNDRV_CTL_TLVT_CHMAP_VAR       0x102   /* channels freely swappable */
+#define SNDRV_CTL_TLVT_CHMAP_PAIRED    0x103   /* pair-wise swappable */
+
 #endif /* __SOUND_TLV_H */
diff --git a/include/sound/version.h b/include/sound/version.h
deleted file mode 100644 (file)
index cc75024..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-/* include/version.h */
-#define CONFIG_SND_VERSION "1.0.25"
-#define CONFIG_SND_DATE ""
diff --git a/include/sound/wm0010.h b/include/sound/wm0010.h
new file mode 100644 (file)
index 0000000..3261e90
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * wm0010.h -- Platform data for WM0010 DSP Driver
+ *
+ * Copyright 2012 Wolfson Microelectronics PLC.
+ *
+ * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef WM0010_PDATA_H
+#define WM0010_PDATA_H
+
+struct wm0010_pdata {
+       int gpio_reset;
+
+       /* Set if there is an inverter between the GPIO controlling
+        * the reset signal and the device.
+        */
+       int reset_active_high;
+       int irq_flags;
+};
+
+#endif
index 74e9a95529c502de158e6dd04426548135ad4b60..e8ce8ee7d62d996c0be5cd7ecb93baabefc37a57 100644 (file)
@@ -18,7 +18,7 @@
 struct wm8960_data {
        bool capless;  /* Headphone outputs configured in capless mode */
 
-       int dres;  /* Discharge resistance for headphone outputs */
+       bool shared_lrclk;  /* DAC and ADC LRCLKs are wired together */
 };
 
 #endif
index eee19f63c0d8111078be6e23fe7020440567125f..8016fd826f5aac8b599b846c189d0757b50ed033 100644 (file)
@@ -32,6 +32,10 @@ struct wm8993_platform_data {
        unsigned int lineout1fb:1;
        unsigned int lineout2fb:1;
 
+       /* Delay to add for microphones to stabalise after power up */
+       int micbias1_delay;
+       int micbias2_delay;
+
        /* Microphone biases: 0=0.9*AVDD1 1=0.65*AVVD1 */
        unsigned int micbias1_lvl:1;
        unsigned int micbias2_lvl:1;
index eb60cb8dbb8a6f12d965912e923197cdd2f4e8b5..c40ae573346dd140031af773c532dd4f32f32240 100644 (file)
@@ -425,6 +425,26 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
        return 0;
 }
 
+static int snd_compress_check_input(struct snd_compr_params *params)
+{
+       /* first let's check the buffer parameter's */
+       if (params->buffer.fragment_size == 0 ||
+                       params->buffer.fragments > SIZE_MAX / params->buffer.fragment_size)
+               return -EINVAL;
+
+       /* now codec parameters */
+       if (params->codec.id == 0 || params->codec.id > SND_AUDIOCODEC_MAX)
+               return -EINVAL;
+
+       if (params->codec.ch_in == 0 || params->codec.ch_out == 0)
+               return -EINVAL;
+
+       if (!(params->codec.sample_rate & SNDRV_PCM_RATE_8000_192000))
+               return -EINVAL;
+
+       return 0;
+}
+
 static int
 snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
 {
@@ -443,11 +463,17 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
                        retval = -EFAULT;
                        goto out;
                }
+
+               retval = snd_compress_check_input(params);
+               if (retval)
+                       goto out;
+
                retval = snd_compr_allocate_buffer(stream, params);
                if (retval) {
                        retval = -ENOMEM;
                        goto out;
                }
+
                retval = stream->ops->set_params(stream, params);
                if (retval)
                        goto out;
index 2487a6bb1c545a3338aa19fbd244c952724f1058..7e86a5b9f3b572f9c97f351027ed4e1b9b7b75b3 100644 (file)
@@ -246,6 +246,7 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
        kctl.count = ncontrol->count ? ncontrol->count : 1;
        access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
                 (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
+                                     SNDRV_CTL_ELEM_ACCESS_VOLATILE|
                                      SNDRV_CTL_ELEM_ACCESS_INACTIVE|
                                      SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE|
                                      SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND|
index c1e611c65c8fc3308cf6e005cc36688b164c1a55..6b368d25073b154d34b8258d59b509a1ffb6c6d2 100644 (file)
@@ -28,7 +28,7 @@
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/info.h>
-#include <sound/version.h>
+#include <linux/utsname.h>
 #include <linux/proc_fs.h>
 #include <linux/mutex.h>
 #include <stdarg.h>
@@ -986,9 +986,8 @@ static struct snd_info_entry *snd_info_version_entry;
 static void snd_info_version_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 {
        snd_iprintf(buffer,
-                   "Advanced Linux Sound Architecture Driver Version "
-                   CONFIG_SND_VERSION CONFIG_SND_DATE ".\n"
-                  );
+                   "Advanced Linux Sound Architecture Driver Version k%s.\n",
+                   init_utsname()->release);
 }
 
 static int __init snd_info_version_init(void)
index cf42ab5080eb59eb495fa4ae617b98085c26d057..83c29dbff9c00fda9124c5155db62fa59341f6a4 100644 (file)
@@ -26,7 +26,6 @@
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/info.h>
-#include <sound/version.h>
 #include <linux/utsname.h>
 #include <linux/mutex.h>
 
@@ -94,7 +93,7 @@ static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int d
 static void snd_sndstat_proc_read(struct snd_info_entry *entry,
                                  struct snd_info_buffer *buffer)
 {
-       snd_iprintf(buffer, "Sound Driver:3.8.1a-980706 (ALSA v" CONFIG_SND_VERSION " emulation code)\n");
+       snd_iprintf(buffer, "Sound Driver:3.8.1a-980706 (ALSA emulation code)\n");
        snd_iprintf(buffer, "Kernel: %s %s %s %s %s\n",
                    init_utsname()->sysname,
                    init_utsname()->nodename,
index 18297f7f2c55825ed8fe7737a965d271ad6f30dc..29f6ded02555568498473fb37547c9e7b0b96c2b 100644 (file)
@@ -1046,6 +1046,7 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mix
                        
                if (kctl->info(kctl, uinfo)) {
                        up_read(&mixer->card->controls_rwsem);
+                       kfree(uinfo);
                        return 0;
                }
                strcpy(str, ptr->name);
@@ -1061,6 +1062,7 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mix
                                uinfo->value.enumerated.item = slot.capture_item;
                                if (kctl->info(kctl, uinfo)) {
                                        up_read(&mixer->card->controls_rwsem);
+                                       kfree(uinfo);
                                        return 0;
                                }
                                if (!strcmp(uinfo->value.enumerated.name, str)) {
index 1a3070b4e5b5fc043d04ed734df76a51503bb65f..f2991940b271df46ef503173750a89d874fec6ad 100644 (file)
@@ -1105,6 +1105,10 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
                        break;
                }
                snd_unregister_device(devtype, pcm->card, pcm->device);
+               if (pcm->streams[cidx].chmap_kctl) {
+                       snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl);
+                       pcm->streams[cidx].chmap_kctl = NULL;
+               }
        }
  unlock:
        mutex_unlock(&register_mutex);
index 7ae6719233933b9eb904aea87da3543b2b671312..f42c10a43315afdbe3761e6ef86d4fe220387124 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/export.h>
 #include <sound/core.h>
 #include <sound/control.h>
+#include <sound/tlv.h>
 #include <sound/info.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -2302,3 +2303,216 @@ snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream,
 }
 
 EXPORT_SYMBOL(snd_pcm_lib_readv);
+
+/*
+ * standard channel mapping helpers
+ */
+
+/* default channel maps for multi-channel playbacks, up to 8 channels */
+const struct snd_pcm_chmap_elem snd_pcm_std_chmaps[] = {
+       { .channels = 1,
+         .map = { SNDRV_CHMAP_MONO } },
+       { .channels = 2,
+         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+       { .channels = 4,
+         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+                  SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+       { .channels = 6,
+         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+                  SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+                  SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } },
+       { .channels = 8,
+         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+                  SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+                  SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
+                  SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
+       { }
+};
+EXPORT_SYMBOL_GPL(snd_pcm_std_chmaps);
+
+/* alternative channel maps with CLFE <-> surround swapped for 6/8 channels */
+const struct snd_pcm_chmap_elem snd_pcm_alt_chmaps[] = {
+       { .channels = 1,
+         .map = { SNDRV_CHMAP_MONO } },
+       { .channels = 2,
+         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+       { .channels = 4,
+         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+                  SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+       { .channels = 6,
+         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+                  SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
+                  SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+       { .channels = 8,
+         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+                  SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
+                  SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+                  SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
+       { }
+};
+EXPORT_SYMBOL_GPL(snd_pcm_alt_chmaps);
+
+static bool valid_chmap_channels(const struct snd_pcm_chmap *info, int ch)
+{
+       if (ch > info->max_channels)
+               return false;
+       return !info->channel_mask || (info->channel_mask & (1U << ch));
+}
+
+static int pcm_chmap_ctl_info(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_info *uinfo)
+{
+       struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 0;
+       uinfo->count = info->max_channels;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = SNDRV_CHMAP_LAST;
+       return 0;
+}
+
+/* get callback for channel map ctl element
+ * stores the channel position firstly matching with the current channels
+ */
+static int pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+       unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+       struct snd_pcm_substream *substream;
+       const struct snd_pcm_chmap_elem *map;
+
+       if (snd_BUG_ON(!info->chmap))
+               return -EINVAL;
+       substream = snd_pcm_chmap_substream(info, idx);
+       if (!substream)
+               return -ENODEV;
+       memset(ucontrol->value.integer.value, 0,
+              sizeof(ucontrol->value.integer.value));
+       if (!substream->runtime)
+               return 0; /* no channels set */
+       for (map = info->chmap; map->channels; map++) {
+               int i;
+               if (map->channels == substream->runtime->channels &&
+                   valid_chmap_channels(info, map->channels)) {
+                       for (i = 0; i < map->channels; i++)
+                               ucontrol->value.integer.value[i] = map->map[i];
+                       return 0;
+               }
+       }
+       return -EINVAL;
+}
+
+/* tlv callback for channel map ctl element
+ * expands the pre-defined channel maps in a form of TLV
+ */
+static int pcm_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+                            unsigned int size, unsigned int __user *tlv)
+{
+       struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+       const struct snd_pcm_chmap_elem *map;
+       unsigned int __user *dst;
+       int c, count = 0;
+
+       if (snd_BUG_ON(!info->chmap))
+               return -EINVAL;
+       if (size < 8)
+               return -ENOMEM;
+       if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv))
+               return -EFAULT;
+       size -= 8;
+       dst = tlv + 2;
+       for (map = info->chmap; map->channels; map++) {
+               int chs_bytes = map->channels * 4;
+               if (!valid_chmap_channels(info, map->channels))
+                       continue;
+               if (size < 8)
+                       return -ENOMEM;
+               if (put_user(SNDRV_CTL_TLVT_CHMAP_FIXED, dst) ||
+                   put_user(chs_bytes, dst + 1))
+                       return -EFAULT;
+               dst += 2;
+               size -= 8;
+               count += 8;
+               if (size < chs_bytes)
+                       return -ENOMEM;
+               size -= chs_bytes;
+               count += chs_bytes;
+               for (c = 0; c < map->channels; c++) {
+                       if (put_user(map->map[c], dst))
+                               return -EFAULT;
+                       dst++;
+               }
+       }
+       if (put_user(count, tlv + 1))
+               return -EFAULT;
+       return 0;
+}
+
+static void pcm_chmap_ctl_private_free(struct snd_kcontrol *kcontrol)
+{
+       struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+       info->pcm->streams[info->stream].chmap_kctl = NULL;
+       kfree(info);
+}
+
+/**
+ * snd_pcm_add_chmap_ctls - create channel-mapping control elements
+ * @pcm: the assigned PCM instance
+ * @stream: stream direction
+ * @chmap: channel map elements (for query)
+ * @max_channels: the max number of channels for the stream
+ * @private_value: the value passed to each kcontrol's private_value field
+ * @info_ret: store struct snd_pcm_chmap instance if non-NULL
+ *
+ * Create channel-mapping control elements assigned to the given PCM stream(s).
+ * Returns zero if succeed, or a negative error value.
+ */
+int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
+                          const struct snd_pcm_chmap_elem *chmap,
+                          int max_channels,
+                          unsigned long private_value,
+                          struct snd_pcm_chmap **info_ret)
+{
+       struct snd_pcm_chmap *info;
+       struct snd_kcontrol_new knew = {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .access = SNDRV_CTL_ELEM_ACCESS_READ |
+                       SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+                       SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
+               .info = pcm_chmap_ctl_info,
+               .get = pcm_chmap_ctl_get,
+               .tlv.c = pcm_chmap_ctl_tlv,
+       };
+       int err;
+
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+       info->pcm = pcm;
+       info->stream = stream;
+       info->chmap = chmap;
+       info->max_channels = max_channels;
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+               knew.name = "Playback Channel Map";
+       else
+               knew.name = "Capture Channel Map";
+       knew.device = pcm->device;
+       knew.count = pcm->streams[stream].substream_count;
+       knew.private_value = private_value;
+       info->kctl = snd_ctl_new1(&knew, info);
+       if (!info->kctl) {
+               kfree(info);
+               return -ENOMEM;
+       }
+       info->kctl->private_free = pcm_chmap_ctl_private_free;
+       err = snd_ctl_add(pcm->card, info->kctl);
+       if (err < 0)
+               return err;
+       pcm->streams[stream].chmap_kctl = info->kctl;
+       if (info_ret)
+               *info_ret = info;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_pcm_add_chmap_ctls);
index 957131366dd93b47300832ec6b8c65fa821aca4f..69e01c4fc32db4ec2e1314209295c7d2b9aab33c 100644 (file)
@@ -327,32 +327,6 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne
 }
 
 EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
-
-/*
- * compute the max chunk size with continuous pages on sg-buffer
- */
-unsigned int snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
-                                         unsigned int ofs, unsigned int size)
-{
-       struct snd_sg_buf *sg = snd_pcm_substream_sgbuf(substream);
-       unsigned int start, end, pg;
-
-       start = ofs >> PAGE_SHIFT;
-       end = (ofs + size - 1) >> PAGE_SHIFT;
-       /* check page continuity */
-       pg = sg->table[start].addr >> PAGE_SHIFT;
-       for (;;) {
-               start++;
-               if (start > end)
-                       break;
-               pg++;
-               if ((sg->table[start].addr >> PAGE_SHIFT) != pg)
-                       return (start << PAGE_SHIFT) - ofs;
-       }
-       /* ok, all on continuous pages */
-       return size;
-}
-EXPORT_SYMBOL(snd_pcm_sgbuf_get_chunk_size);
 #endif /* CONFIG_SND_DMA_SGBUF */
 
 /**
index 5cf8d65ed5ef2cc9fe8cbce1d7275fc7b0745b14..60e8fc1b344041d27086d4dfde7786b8d8ac85ec 100644 (file)
@@ -569,5 +569,7 @@ EXPORT_SYMBOL(snd_seq_device_load_drivers);
 EXPORT_SYMBOL(snd_seq_device_new);
 EXPORT_SYMBOL(snd_seq_device_register_driver);
 EXPORT_SYMBOL(snd_seq_device_unregister_driver);
+#ifdef CONFIG_MODULES
 EXPORT_SYMBOL(snd_seq_autoload_lock);
 EXPORT_SYMBOL(snd_seq_autoload_unlock);
+#endif
index d0f00356fc115a32db23bc8475f08a6aad178c47..0a418503ec412c61e22da5ac31ddac96e6e436a4 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
+#include <linux/export.h>
 #include <sound/memalloc.h>
 
 
@@ -136,3 +137,29 @@ void *snd_malloc_sgbuf_pages(struct device *device,
        snd_free_sgbuf_pages(dmab); /* free the table */
        return NULL;
 }
+
+/*
+ * compute the max chunk size with continuous pages on sg-buffer
+ */
+unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
+                                     unsigned int ofs, unsigned int size)
+{
+       struct snd_sg_buf *sg = dmab->private_data;
+       unsigned int start, end, pg;
+
+       start = ofs >> PAGE_SHIFT;
+       end = (ofs + size - 1) >> PAGE_SHIFT;
+       /* check page continuity */
+       pg = sg->table[start].addr >> PAGE_SHIFT;
+       for (;;) {
+               start++;
+               if (start > end)
+                       break;
+               pg++;
+               if ((sg->table[start].addr >> PAGE_SHIFT) != pg)
+                       return (start << PAGE_SHIFT) - ofs;
+       }
+       /* ok, all on continuous pages */
+       return size;
+}
+EXPORT_SYMBOL(snd_sgbuf_get_chunk_size);
index 28f35593a750464b87306a5c4355d98333856e36..643976000ce825d1857fd3a3192fadeff0da4e5b 100644 (file)
@@ -27,7 +27,6 @@
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/info.h>
-#include <sound/version.h>
 #include <sound/control.h>
 #include <sound/initval.h>
 #include <linux/kmod.h>
@@ -468,7 +467,7 @@ static int __init alsa_sound_init(void)
        }
        snd_info_minor_register();
 #ifndef MODULE
-       printk(KERN_INFO "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n");
+       printk(KERN_INFO "Advanced Linux Sound Architecture Driver Initialized.\n");
 #endif
        return 0;
 }
index 5a34355e78e8f83295496e1feb836a99f7ff7b44..0fe6d64ff840f02cdb17df4c27721f8e9a953cb5 100644 (file)
@@ -120,6 +120,7 @@ struct loopback_pcm {
        unsigned int last_drift;
        unsigned long last_jiffies;
        struct timer_list timer;
+       spinlock_t timer_lock;
 };
 
 static struct platform_device *devices[SNDRV_CARDS];
@@ -170,6 +171,7 @@ static void loopback_timer_start(struct loopback_pcm *dpcm)
        unsigned long tick;
        unsigned int rate_shift = get_rate_shift(dpcm);
 
+       spin_lock(&dpcm->timer_lock);
        if (rate_shift != dpcm->pcm_rate_shift) {
                dpcm->pcm_rate_shift = rate_shift;
                dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size);
@@ -182,12 +184,15 @@ static void loopback_timer_start(struct loopback_pcm *dpcm)
        tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps;
        dpcm->timer.expires = jiffies + tick;
        add_timer(&dpcm->timer);
+       spin_unlock(&dpcm->timer_lock);
 }
 
 static inline void loopback_timer_stop(struct loopback_pcm *dpcm)
 {
+       spin_lock(&dpcm->timer_lock);
        del_timer(&dpcm->timer);
        dpcm->timer.expires = 0;
+       spin_unlock(&dpcm->timer_lock);
 }
 
 #define CABLE_VALID_PLAYBACK   (1 << SNDRV_PCM_STREAM_PLAYBACK)
@@ -667,6 +672,7 @@ static int loopback_open(struct snd_pcm_substream *substream)
        dpcm->substream = substream;
        setup_timer(&dpcm->timer, loopback_timer_function,
                    (unsigned long)dpcm);
+       spin_lock_init(&dpcm->timer_lock);
 
        cable = loopback->cables[substream->number][dev];
        if (!cable) {
index 2bfe4bcb7a7dd8b4b667895e9a96012197207230..0c796bcbc0a36947453b8a3632daae48d5b24abc 100644 (file)
@@ -163,7 +163,7 @@ static int opl3_get_voice(struct snd_opl3 *opl3, int instr_4op,
        struct best *bp;
 
        for (i = 0; i < END; i++) {
-               best[i].time = (unsigned int)(-1); /* XXX MAX_?INT really */;
+               best[i].time = (unsigned int)(-1); /* XXX MAX_?INT really */
                best[i].voice = -1;
        }
 
index 49b9e240915c48d1f236644de16157db03a6f0fb..4b91adc0238ca4bc855065c2a0af32ef23d9cf33 100644 (file)
@@ -504,8 +504,7 @@ void snd_opl4_note_on(void *private_data, int note, int vel, struct snd_midi_cha
        spin_lock_irqsave(&opl4->reg_lock, flags);
        for (i = 0; i < voices; i++) {
                voice[i] = snd_opl4_get_voice(opl4);
-               list_del(&voice[i]->list);
-               list_add_tail(&voice[i]->list, &opl4->on_voices);
+               list_move_tail(&voice[i]->list, &opl4->on_voices);
                voice[i]->chan = chan;
                voice[i]->note = note;
                voice[i]->velocity = vel & 0x7f;
@@ -555,8 +554,7 @@ void snd_opl4_note_on(void *private_data, int note, int vel, struct snd_midi_cha
 
 static void snd_opl4_voice_off(struct snd_opl4 *opl4, struct opl4_voice *voice)
 {
-       list_del(&voice->list);
-       list_add_tail(&voice->list, &opl4->off_voices);
+       list_move_tail(&voice->list, &opl4->off_voices);
 
        voice->reg_misc &= ~OPL4_KEY_ON_BIT;
        snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc);
@@ -571,8 +569,7 @@ void snd_opl4_note_off(void *private_data, int note, int vel, struct snd_midi_ch
 
 static void snd_opl4_terminate_voice(struct snd_opl4 *opl4, struct opl4_voice *voice)
 {
-       list_del(&voice->list);
-       list_add_tail(&voice->list, &opl4->off_voices);
+       list_move_tail(&voice->list, &opl4->off_voices);
 
        voice->reg_misc = (voice->reg_misc & ~OPL4_KEY_ON_BIT) | OPL4_DAMP_BIT;
        snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc);
index 5e897b236cec4f3b5c5371f41bb9e925bfab94f7..deed5efff33c9c57c2d462f7d05de89dc31bf2d7 100644 (file)
@@ -184,7 +184,7 @@ static int vx_set_format(struct vx_core *chip, struct vx_pipe *pipe,
        default : 
                snd_BUG();
                return -EINVAL;
-        };
+       }
 
        return vx_set_stream_format(chip, pipe, header);
 }
index 52064cfa91f3f9d1fa82612b3d6ac50dac51b2a4..a38d9643e9d8319dc38c4e3379d83d13a27e250c 100644 (file)
@@ -117,6 +117,18 @@ config SND_AZT2320
          To compile this driver as a module, choose M here: the module
          will be called snd-azt2320.
 
+config SND_CMI8328
+       tristate "C-Media CMI8328"
+       select SND_WSS_LIB
+       select SND_OPL3_LIB
+       select SND_MPU401_UART
+       help
+         Say Y here to include support for soundcards based on the
+         C-Media CMI8328 chip.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-cmi8328.
+
 config SND_CMI8330
        tristate "C-Media CMI8330"
        select SND_WSS_LIB
index 8d781e419e2ece74797733a4eea86a14ba8ba5d6..9a15f1497b1081cf1a785acd8b8ffbbd0170cd33 100644 (file)
@@ -6,6 +6,7 @@
 snd-adlib-objs := adlib.o
 snd-als100-objs := als100.o
 snd-azt2320-objs := azt2320.o
+snd-cmi8328-objs := cmi8328.o
 snd-cmi8330-objs := cmi8330.o
 snd-es18xx-objs := es18xx.o
 snd-opl3sa2-objs := opl3sa2.o
@@ -16,6 +17,7 @@ snd-sscape-objs := sscape.o
 obj-$(CONFIG_SND_ADLIB) += snd-adlib.o
 obj-$(CONFIG_SND_ALS100) += snd-als100.o
 obj-$(CONFIG_SND_AZT2320) += snd-azt2320.o
+obj-$(CONFIG_SND_CMI8328) += snd-cmi8328.o
 obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o
 obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o
 obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o
index 94b83b6e46a3a97bef06e38be481159afe9b3c4e..2c2f829c3fd7b91ca38a2323272bdfab9421d217 100644 (file)
@@ -63,11 +63,6 @@ MODULE_PARM_DESC(enable, "Enable ad1816a based soundcard.");
 module_param_array(clockfreq, int, NULL, 0444);
 MODULE_PARM_DESC(clockfreq, "Clock frequency for ad1816a driver (default = 0).");
 
-struct snd_card_ad1816a {
-       struct pnp_dev *dev;
-       struct pnp_dev *devmpu;
-};
-
 static struct pnp_card_device_id snd_ad1816a_pnpids[] = {
        /* Analog Devices AD1815 */
        { .id = "ADS7150", .devs = { { .id = "ADS7150" }, { .id = "ADS7151" } } },
@@ -99,25 +94,16 @@ MODULE_DEVICE_TABLE(pnp_card, snd_ad1816a_pnpids);
 #define        DRIVER_NAME     "snd-card-ad1816a"
 
 
-static int __devinit snd_card_ad1816a_pnp(int dev, struct snd_card_ad1816a *acard,
-                                         struct pnp_card_link *card,
+static int __devinit snd_card_ad1816a_pnp(int dev, struct pnp_card_link *card,
                                          const struct pnp_card_device_id *id)
 {
        struct pnp_dev *pdev;
        int err;
 
-       acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
-       if (acard->dev == NULL)
+       pdev = pnp_request_card_device(card, id->devs[0].id, NULL);
+       if (pdev == NULL)
                return -EBUSY;
 
-       acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL);
-       if (acard->devmpu == NULL) {
-               mpu_port[dev] = -1;
-               snd_printk(KERN_WARNING PFX "MPU401 device busy, skipping.\n");
-       }
-
-       pdev = acard->dev;
-
        err = pnp_activate_dev(pdev);
        if (err < 0) {
                printk(KERN_ERR PFX "AUDIO PnP configure failure\n");
@@ -130,16 +116,17 @@ static int __devinit snd_card_ad1816a_pnp(int dev, struct snd_card_ad1816a *acar
        dma2[dev] = pnp_dma(pdev, 1);
        irq[dev] = pnp_irq(pdev, 0);
 
-       if (acard->devmpu == NULL)
+       pdev = pnp_request_card_device(card, id->devs[1].id, NULL);
+       if (pdev == NULL) {
+               mpu_port[dev] = -1;
+               snd_printk(KERN_WARNING PFX "MPU401 device busy, skipping.\n");
                return 0;
-
-       pdev = acard->devmpu;
+       }
 
        err = pnp_activate_dev(pdev);
        if (err < 0) {
                printk(KERN_ERR PFX "MPU401 PnP configure failure\n");
                mpu_port[dev] = -1;
-               acard->devmpu = NULL;
        } else {
                mpu_port[dev] = pnp_port_start(pdev, 0);
                mpu_irq[dev] = pnp_irq(pdev, 0);
@@ -153,18 +140,17 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
 {
        int error;
        struct snd_card *card;
-       struct snd_card_ad1816a *acard;
        struct snd_ad1816a *chip;
        struct snd_opl3 *opl3;
        struct snd_timer *timer;
 
        error = snd_card_create(index[dev], id[dev], THIS_MODULE,
-                               sizeof(struct snd_card_ad1816a), &card);
+                               sizeof(struct snd_ad1816a), &card);
        if (error < 0)
                return error;
-       acard = card->private_data;
+       chip = card->private_data;
 
-       if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) {
+       if ((error = snd_card_ad1816a_pnp(dev, pcard, pid))) {
                snd_card_free(card);
                return error;
        }
@@ -174,7 +160,7 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
                                        irq[dev],
                                        dma1[dev],
                                        dma2[dev],
-                                       &chip)) < 0) {
+                                       chip)) < 0) {
                snd_card_free(card);
                return error;
        }
@@ -258,13 +244,37 @@ static void __devexit snd_ad1816a_pnp_remove(struct pnp_card_link * pcard)
        pnp_set_card_drvdata(pcard, NULL);
 }
 
+#ifdef CONFIG_PM
+static int snd_ad1816a_pnp_suspend(struct pnp_card_link *pcard,
+                                  pm_message_t state)
+{
+       struct snd_card *card = pnp_get_card_drvdata(pcard);
+
+       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+       snd_ad1816a_suspend(card->private_data);
+       return 0;
+}
+
+static int snd_ad1816a_pnp_resume(struct pnp_card_link *pcard)
+{
+       struct snd_card *card = pnp_get_card_drvdata(pcard);
+
+       snd_ad1816a_resume(card->private_data);
+       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+       return 0;
+}
+#endif
+
 static struct pnp_card_driver ad1816a_pnpc_driver = {
        .flags          = PNP_DRIVER_RES_DISABLE,
        .name           = "ad1816a",
        .id_table       = snd_ad1816a_pnpids,
        .probe          = snd_ad1816a_pnp_detect,
        .remove         = __devexit_p(snd_ad1816a_pnp_remove),
-       /* FIXME: suspend/resume */
+#ifdef CONFIG_PM
+       .suspend        = snd_ad1816a_pnp_suspend,
+       .resume         = snd_ad1816a_pnp_resume,
+#endif
 };
 
 static int __init alsa_card_ad1816a_init(void)
index 177eed3271bc4215683ffe58f6650d87af58e376..db64df6023e0fc3cf8dc53ff6f1b6e7349efb7fa 100644 (file)
@@ -491,7 +491,7 @@ static int snd_ad1816a_capture_close(struct snd_pcm_substream *substream)
 }
 
 
-static void __devinit snd_ad1816a_init(struct snd_ad1816a *chip)
+static void snd_ad1816a_init(struct snd_ad1816a *chip)
 {
        unsigned long flags;
 
@@ -511,6 +511,32 @@ static void __devinit snd_ad1816a_init(struct snd_ad1816a *chip)
        spin_unlock_irqrestore(&chip->lock, flags);
 }
 
+#ifdef CONFIG_PM
+void snd_ad1816a_suspend(struct snd_ad1816a *chip)
+{
+       int reg;
+       unsigned long flags;
+
+       snd_pcm_suspend_all(chip->pcm);
+       spin_lock_irqsave(&chip->lock, flags);
+       for (reg = 0; reg < 48; reg++)
+               chip->image[reg] = snd_ad1816a_read(chip, reg);
+       spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+void snd_ad1816a_resume(struct snd_ad1816a *chip)
+{
+       int reg;
+       unsigned long flags;
+
+       snd_ad1816a_init(chip);
+       spin_lock_irqsave(&chip->lock, flags);
+       for (reg = 0; reg < 48; reg++)
+               snd_ad1816a_write(chip, reg, chip->image[reg]);
+       spin_unlock_irqrestore(&chip->lock, flags);
+}
+#endif
+
 static int __devinit snd_ad1816a_probe(struct snd_ad1816a *chip)
 {
        unsigned long flags;
@@ -548,7 +574,6 @@ static int snd_ad1816a_free(struct snd_ad1816a *chip)
                snd_dma_disable(chip->dma2);
                free_dma(chip->dma2);
        }
-       kfree(chip);
        return 0;
 }
 
@@ -573,19 +598,13 @@ static const char __devinit *snd_ad1816a_chip_id(struct snd_ad1816a *chip)
 
 int __devinit snd_ad1816a_create(struct snd_card *card,
                                 unsigned long port, int irq, int dma1, int dma2,
-                                struct snd_ad1816a **rchip)
+                                struct snd_ad1816a *chip)
 {
         static struct snd_device_ops ops = {
                .dev_free =     snd_ad1816a_dev_free,
        };
        int error;
-       struct snd_ad1816a *chip;
-
-       *rchip = NULL;
 
-       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-       if (chip == NULL)
-               return -ENOMEM;
        chip->irq = -1;
        chip->dma1 = -1;
        chip->dma2 = -1;
@@ -631,7 +650,6 @@ int __devinit snd_ad1816a_create(struct snd_card *card,
                return error;
        }
 
-       *rchip = chip;
        return 0;
 }
 
diff --git a/sound/isa/cmi8328.c b/sound/isa/cmi8328.c
new file mode 100644 (file)
index 0000000..bde6013
--- /dev/null
@@ -0,0 +1,483 @@
+/*
+ * Driver for C-Media CMI8328-based soundcards, such as AudioExcel AV500
+ * Copyright (c) 2012 Ondrej Zary
+ *
+ * AudioExcel AV500 card consists of:
+ *  - CMI8328 - main chip (SB Pro emulation, gameport, OPL3, MPU401, CD-ROM)
+ *  - CS4231A - WSS codec
+ *  - Dream SAM9233+GMS950400+RAM+ROM: Wavetable MIDI, connected to MPU401
+ */
+
+#include <linux/init.h>
+#include <linux/isa.h>
+#include <linux/module.h>
+#include <linux/gameport.h>
+#include <asm/dma.h>
+#include <sound/core.h>
+#include <sound/wss.h>
+#include <sound/opl3.h>
+#include <sound/mpu401.h>
+#define SNDRV_LEGACY_FIND_FREE_IOPORT
+#define SNDRV_LEGACY_FIND_FREE_IRQ
+#define SNDRV_LEGACY_FIND_FREE_DMA
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Ondrej Zary <linux@rainbow-software.org>");
+MODULE_DESCRIPTION("C-Media CMI8328");
+MODULE_LICENSE("GPL");
+
+#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#define SUPPORT_JOYSTICK 1
+#endif
+
+/* I/O port is configured by jumpers on the card to one of these */
+static int cmi8328_ports[] = { 0x530, 0xe80, 0xf40, 0x604 };
+#define CMI8328_MAX    ARRAY_SIZE(cmi8328_ports)
+
+static int index[CMI8328_MAX] =     {[0 ... (CMI8328_MAX-1)] = -1};
+static char *id[CMI8328_MAX] =      {[0 ... (CMI8328_MAX-1)] = NULL};
+static long port[CMI8328_MAX] =     {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_PORT};
+static int irq[CMI8328_MAX] =       {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_IRQ};
+static int dma1[CMI8328_MAX] =      {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_DMA};
+static int dma2[CMI8328_MAX] =      {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_DMA};
+static long mpuport[CMI8328_MAX] =  {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_PORT};
+static int mpuirq[CMI8328_MAX] =    {[0 ... (CMI8328_MAX-1)] = SNDRV_AUTO_IRQ};
+#ifdef SUPPORT_JOYSTICK
+static bool gameport[CMI8328_MAX] = {[0 ... (CMI8328_MAX-1)] = true};
+#endif
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for CMI8328 soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for CMI8328 soundcard.");
+
+module_param_array(port, long, NULL, 0444);
+MODULE_PARM_DESC(port, "Port # for CMI8328 driver.");
+module_param_array(irq, int, NULL, 0444);
+MODULE_PARM_DESC(irq, "IRQ # for CMI8328 driver.");
+module_param_array(dma1, int, NULL, 0444);
+MODULE_PARM_DESC(dma1, "DMA1 for CMI8328 driver.");
+module_param_array(dma2, int, NULL, 0444);
+MODULE_PARM_DESC(dma2, "DMA2 for CMI8328 driver.");
+
+module_param_array(mpuport, long, NULL, 0444);
+MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8328 driver.");
+module_param_array(mpuirq, int, NULL, 0444);
+MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8328 MPU-401 port.");
+#ifdef SUPPORT_JOYSTICK
+module_param_array(gameport, bool, NULL, 0444);
+MODULE_PARM_DESC(gameport, "Enable gameport.");
+#endif
+
+struct snd_cmi8328 {
+       u16 port;
+       u8 cfg[3];
+       u8 wss_cfg;
+       struct snd_card *card;
+       struct snd_wss *wss;
+#ifdef SUPPORT_JOYSTICK
+       struct gameport *gameport;
+#endif
+};
+
+/* CMI8328 configuration registers */
+#define CFG1 0x61
+#define CFG1_SB_DISABLE        (1 << 0)
+#define CFG1_GAMEPORT  (1 << 1)
+/*
+ * bit 0:    SB: 0=enabled, 1=disabled
+ * bit 1:    gameport: 0=disabled, 1=enabled
+ * bits 2-4: SB IRQ: 001=3, 010=5, 011=7, 100=9, 101=10, 110=11
+ * bits 5-6: SB DMA: 00=disabled (when SB disabled), 01=DMA0, 10=DMA1, 11=DMA3
+ * bit 7:    SB port: 0=0x220, 1=0x240
+ */
+#define CFG2 0x62
+#define CFG2_MPU_ENABLE (1 << 2)
+/*
+ * bits 0-1: CD-ROM mode: 00=disabled, 01=Panasonic, 10=Sony/Mitsumi/Wearnes,
+                         11=IDE
+ * bit 2:    MPU401: 0=disabled, 1=enabled
+ * bits 3-4: MPU401 IRQ: 00=3, 01=5, 10=7, 11=9,
+ * bits 5-7: MPU401 port: 000=0x300, 001=0x310, 010=0x320, 011=0x330, 100=0x332,
+                         101=0x334, 110=0x336
+ */
+#define CFG3 0x63
+/*
+ * bits 0-2: CD-ROM IRQ: 000=disabled, 001=3, 010=5, 011=7, 100=9, 101=10,
+                        110=11
+ * bits 3-4: CD-ROM DMA: 00=disabled, 01=DMA0, 10=DMA1, 11=DMA3
+ * bits 5-7: CD-ROM port: 000=0x300, 001=0x310, 010=0x320, 011=0x330, 100=0x340,
+                         101=0x350, 110=0x360, 111=0x370
+ */
+
+static u8 snd_cmi8328_cfg_read(u16 port, u8 reg)
+{
+       outb(0x43, port + 3);
+       outb(0x21, port + 3);
+       outb(reg, port + 3);
+       return inb(port);
+}
+
+static void snd_cmi8328_cfg_write(u16 port, u8 reg, u8 val)
+{
+       outb(0x43, port + 3);
+       outb(0x21, port + 3);
+       outb(reg, port + 3);
+       outb(val, port + 3);    /* yes, value goes to the same port as index */
+}
+
+static void snd_cmi8328_cfg_save(u16 port, u8 cfg[])
+{
+       cfg[0] = snd_cmi8328_cfg_read(port, CFG1);
+       cfg[1] = snd_cmi8328_cfg_read(port, CFG2);
+       cfg[2] = snd_cmi8328_cfg_read(port, CFG3);
+}
+
+static void snd_cmi8328_cfg_restore(u16 port, u8 cfg[])
+{
+       snd_cmi8328_cfg_write(port, CFG1, cfg[0]);
+       snd_cmi8328_cfg_write(port, CFG2, cfg[1]);
+       snd_cmi8328_cfg_write(port, CFG3, cfg[2]);
+}
+
+static int __devinit snd_cmi8328_mixer(struct snd_wss *chip)
+{
+       struct snd_card *card;
+       struct snd_ctl_elem_id id1, id2;
+       int err;
+
+       card = chip->card;
+
+       memset(&id1, 0, sizeof(id1));
+       memset(&id2, 0, sizeof(id2));
+       id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+       /* rename AUX0 switch to CD */
+       strcpy(id1.name, "Aux Playback Switch");
+       strcpy(id2.name, "CD Playback Switch");
+       err = snd_ctl_rename_id(card, &id1, &id2);
+       if (err < 0) {
+               snd_printk(KERN_ERR "error renaming control\n");
+               return err;
+       }
+       /* rename AUX0 volume to CD */
+       strcpy(id1.name, "Aux Playback Volume");
+       strcpy(id2.name, "CD Playback Volume");
+       err = snd_ctl_rename_id(card, &id1, &id2);
+       if (err < 0) {
+               snd_printk(KERN_ERR "error renaming control\n");
+               return err;
+       }
+       /* rename AUX1 switch to Synth */
+       strcpy(id1.name, "Aux Playback Switch");
+       id1.index = 1;
+       strcpy(id2.name, "Synth Playback Switch");
+       err = snd_ctl_rename_id(card, &id1, &id2);
+       if (err < 0) {
+               snd_printk(KERN_ERR "error renaming control\n");
+               return err;
+       }
+       /* rename AUX1 volume to Synth */
+       strcpy(id1.name, "Aux Playback Volume");
+       id1.index = 1;
+       strcpy(id2.name, "Synth Playback Volume");
+       err = snd_ctl_rename_id(card, &id1, &id2);
+       if (err < 0) {
+               snd_printk(KERN_ERR "error renaming control\n");
+               return err;
+       }
+
+       return 0;
+}
+
+/* find index of an item in "-1"-ended array */
+int array_find(int array[], int item)
+{
+       int i;
+
+       for (i = 0; array[i] != -1; i++)
+               if (array[i] == item)
+                       return i;
+
+       return -1;
+}
+/* the same for long */
+int array_find_l(long array[], long item)
+{
+       int i;
+
+       for (i = 0; array[i] != -1; i++)
+               if (array[i] == item)
+                       return i;
+
+       return -1;
+}
+
+static int __devinit snd_cmi8328_probe(struct device *pdev, unsigned int ndev)
+{
+       struct snd_card *card;
+       struct snd_opl3 *opl3;
+       struct snd_cmi8328 *cmi;
+#ifdef SUPPORT_JOYSTICK
+       struct resource *res;
+#endif
+       int err, pos;
+       static long mpu_ports[] = { 0x330, 0x300, 0x310, 0x320, 0x332, 0x334,
+                                  0x336, -1 };
+       static u8 mpu_port_bits[] = { 3, 0, 1, 2, 4, 5, 6 };
+       static int mpu_irqs[] = { 9, 7, 5, 3, -1 };
+       static u8 mpu_irq_bits[] = { 3, 2, 1, 0 };
+       static int irqs[] = { 9, 10, 11, 7, -1 };
+       static u8 irq_bits[] = { 2, 3, 4, 1 };
+       static int dma1s[] = { 3, 1, 0, -1 };
+       static u8 dma_bits[] = { 3, 2, 1 };
+       static int dma2s[][2] = { {1, -1}, {0, -1}, {-1, -1}, {0, -1} };
+       u16 port = cmi8328_ports[ndev];
+       u8 val;
+
+       /* 0xff is invalid configuration (but settable - hope it isn't set) */
+       if (snd_cmi8328_cfg_read(port, CFG1) == 0xff)
+               return -ENODEV;
+       /* the SB disable bit must NEVER EVER be cleared or the WSS dies */
+       snd_cmi8328_cfg_write(port, CFG1, CFG1_SB_DISABLE);
+       if (snd_cmi8328_cfg_read(port, CFG1) != CFG1_SB_DISABLE)
+               return -ENODEV;
+       /* disable everything first */
+       snd_cmi8328_cfg_write(port, CFG2, 0);   /* disable CDROM and MPU401 */
+       snd_cmi8328_cfg_write(port, CFG3, 0);   /* disable CDROM IRQ and DMA */
+
+       if (irq[ndev] == SNDRV_AUTO_IRQ) {
+               irq[ndev] = snd_legacy_find_free_irq(irqs);
+               if (irq[ndev] < 0) {
+                       snd_printk(KERN_ERR "unable to find a free IRQ\n");
+                       return -EBUSY;
+               }
+       }
+       if (dma1[ndev] == SNDRV_AUTO_DMA) {
+               dma1[ndev] = snd_legacy_find_free_dma(dma1s);
+               if (dma1[ndev] < 0) {
+                       snd_printk(KERN_ERR "unable to find a free DMA1\n");
+                       return -EBUSY;
+               }
+       }
+       if (dma2[ndev] == SNDRV_AUTO_DMA) {
+               dma2[ndev] = snd_legacy_find_free_dma(dma2s[dma1[ndev] % 4]);
+               if (dma2[ndev] < 0) {
+                       snd_printk(KERN_WARNING "unable to find a free DMA2, full-duplex will not work\n");
+                       dma2[ndev] = -1;
+               }
+       }
+       /* configure WSS IRQ... */
+       pos = array_find(irqs, irq[ndev]);
+       if (pos < 0) {
+               snd_printk(KERN_ERR "invalid IRQ %d\n", irq[ndev]);
+               return -EINVAL;
+       }
+       val = irq_bits[pos] << 3;
+       /* ...and DMA... */
+       pos = array_find(dma1s, dma1[ndev]);
+       if (pos < 0) {
+               snd_printk(KERN_ERR "invalid DMA1 %d\n", dma1[ndev]);
+               return -EINVAL;
+       }
+       val |= dma_bits[pos];
+       /* ...and DMA2 */
+       if (dma2[ndev] >= 0 && dma1[ndev] != dma2[ndev]) {
+               pos = array_find(dma2s[dma1[ndev]], dma2[ndev]);
+               if (pos < 0) {
+                       snd_printk(KERN_ERR "invalid DMA2 %d\n", dma2[ndev]);
+                       return -EINVAL;
+               }
+               val |= 0x04; /* enable separate capture DMA */
+       }
+       outb(val, port);
+
+       err = snd_card_create(index[ndev], id[ndev], THIS_MODULE,
+                               sizeof(struct snd_cmi8328), &card);
+       if (err < 0)
+               return err;
+       cmi = card->private_data;
+       cmi->card = card;
+       cmi->port = port;
+       cmi->wss_cfg = val;
+       snd_card_set_dev(card, pdev);
+
+       err = snd_wss_create(card, port + 4, -1, irq[ndev], dma1[ndev],
+                       dma2[ndev], WSS_HW_DETECT, 0, &cmi->wss);
+       if (err < 0)
+               goto error;
+
+       err = snd_wss_pcm(cmi->wss, 0, NULL);
+       if (err < 0)
+               goto error;
+
+       err = snd_wss_mixer(cmi->wss);
+       if (err < 0)
+               goto error;
+       err = snd_cmi8328_mixer(cmi->wss);
+       if (err < 0)
+               goto error;
+
+       if (snd_wss_timer(cmi->wss, 0, NULL) < 0)
+               snd_printk(KERN_WARNING "error initializing WSS timer\n");
+
+       if (mpuport[ndev] == SNDRV_AUTO_PORT) {
+               mpuport[ndev] = snd_legacy_find_free_ioport(mpu_ports, 2);
+               if (mpuport[ndev] < 0)
+                       snd_printk(KERN_ERR "unable to find a free MPU401 port\n");
+       }
+       if (mpuirq[ndev] == SNDRV_AUTO_IRQ) {
+               mpuirq[ndev] = snd_legacy_find_free_irq(mpu_irqs);
+               if (mpuirq[ndev] < 0)
+                       snd_printk(KERN_ERR "unable to find a free MPU401 IRQ\n");
+       }
+       /* enable and configure MPU401 */
+       if (mpuport[ndev] > 0 && mpuirq[ndev] > 0) {
+               val = CFG2_MPU_ENABLE;
+               pos = array_find_l(mpu_ports, mpuport[ndev]);
+               if (pos < 0)
+                       snd_printk(KERN_WARNING "invalid MPU401 port 0x%lx\n",
+                                                               mpuport[ndev]);
+               else {
+                       val |= mpu_port_bits[pos] << 5;
+                       pos = array_find(mpu_irqs, mpuirq[ndev]);
+                       if (pos < 0)
+                               snd_printk(KERN_WARNING "invalid MPU401 IRQ %d\n",
+                                                               mpuirq[ndev]);
+                       else {
+                               val |= mpu_irq_bits[pos] << 3;
+                               snd_cmi8328_cfg_write(port, CFG2, val);
+                               if (snd_mpu401_uart_new(card, 0,
+                                               MPU401_HW_MPU401, mpuport[ndev],
+                                               0, mpuirq[ndev], NULL) < 0)
+                                       snd_printk(KERN_ERR "error initializing MPU401\n");
+                       }
+               }
+       }
+       /* OPL3 is hardwired to 0x388 and cannot be disabled */
+       if (snd_opl3_create(card, 0x388, 0x38a, OPL3_HW_AUTO, 0, &opl3) < 0)
+               snd_printk(KERN_ERR "error initializing OPL3\n");
+       else
+               if (snd_opl3_hwdep_new(opl3, 0, 1, NULL) < 0)
+                       snd_printk(KERN_WARNING "error initializing OPL3 hwdep\n");
+
+       strcpy(card->driver, "CMI8328");
+       strcpy(card->shortname, "C-Media CMI8328");
+       sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d,%d",
+               card->shortname, cmi->wss->port, irq[ndev], dma1[ndev],
+               (dma2[ndev] >= 0) ? dma2[ndev] : dma1[ndev]);
+
+       dev_set_drvdata(pdev, card);
+       err = snd_card_register(card);
+       if (err < 0)
+               goto error;
+#ifdef SUPPORT_JOYSTICK
+       if (!gameport[ndev])
+               return 0;
+       /* gameport is hardwired to 0x200 */
+       res = request_region(0x200, 8, "CMI8328 gameport");
+       if (!res)
+               snd_printk(KERN_WARNING "unable to allocate gameport I/O port\n");
+       else {
+               struct gameport *gp = cmi->gameport = gameport_allocate_port();
+               if (!cmi->gameport)
+                       release_and_free_resource(res);
+               else {
+                       gameport_set_name(gp, "CMI8328 Gameport");
+                       gameport_set_phys(gp, "%s/gameport0", dev_name(pdev));
+                       gameport_set_dev_parent(gp, pdev);
+                       gp->io = 0x200;
+                       gameport_set_port_data(gp, res);
+                       /* Enable gameport */
+                       snd_cmi8328_cfg_write(port, CFG1,
+                                       CFG1_SB_DISABLE | CFG1_GAMEPORT);
+                       gameport_register_port(gp);
+               }
+       }
+#endif
+       return 0;
+error:
+       snd_card_free(card);
+
+       return err;
+}
+
+static int __devexit snd_cmi8328_remove(struct device *pdev, unsigned int dev)
+{
+       struct snd_card *card = dev_get_drvdata(pdev);
+       struct snd_cmi8328 *cmi = card->private_data;
+
+#ifdef SUPPORT_JOYSTICK
+       if (cmi->gameport) {
+               struct resource *res = gameport_get_port_data(cmi->gameport);
+               gameport_unregister_port(cmi->gameport);
+               release_and_free_resource(res);
+       }
+#endif
+       /* disable everything */
+       snd_cmi8328_cfg_write(cmi->port, CFG1, CFG1_SB_DISABLE);
+       snd_cmi8328_cfg_write(cmi->port, CFG2, 0);
+       snd_cmi8328_cfg_write(cmi->port, CFG3, 0);
+       snd_card_free(card);
+       dev_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int snd_cmi8328_suspend(struct device *pdev, unsigned int n,
+                               pm_message_t state)
+{
+       struct snd_card *card = dev_get_drvdata(pdev);
+       struct snd_cmi8328 *cmi;
+
+       if (!card)      /* ignore absent devices */
+               return 0;
+       cmi = card->private_data;
+       snd_cmi8328_cfg_save(cmi->port, cmi->cfg);
+       snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+       snd_pcm_suspend_all(cmi->wss->pcm);
+       cmi->wss->suspend(cmi->wss);
+
+       return 0;
+}
+
+static int snd_cmi8328_resume(struct device *pdev, unsigned int n)
+{
+       struct snd_card *card = dev_get_drvdata(pdev);
+       struct snd_cmi8328 *cmi;
+
+       if (!card)      /* ignore absent devices */
+               return 0;
+       cmi = card->private_data;
+       snd_cmi8328_cfg_restore(cmi->port, cmi->cfg);
+       outb(cmi->wss_cfg, cmi->port);
+       cmi->wss->resume(cmi->wss);
+       snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+
+       return 0;
+}
+#endif
+
+static struct isa_driver snd_cmi8328_driver = {
+       .probe          = snd_cmi8328_probe,
+       .remove         = __devexit_p(snd_cmi8328_remove),
+#ifdef CONFIG_PM
+       .suspend        = snd_cmi8328_suspend,
+       .resume         = snd_cmi8328_resume,
+#endif
+       .driver         = {
+               .name   = "cmi8328"
+       },
+};
+
+static int __init alsa_card_cmi8328_init(void)
+{
+       return isa_register_driver(&snd_cmi8328_driver, CMI8328_MAX);
+}
+
+static void __exit alsa_card_cmi8328_exit(void)
+{
+       isa_unregister_driver(&snd_cmi8328_driver);
+}
+
+module_init(alsa_card_cmi8328_init)
+module_exit(alsa_card_cmi8328_exit)
index a76bc8d27c1d914a2dd36262ef2f1f8f1a9307bf..3fc8b66fd167fc98bbdd42c29b889920f5c104ce 100644 (file)
@@ -443,9 +443,8 @@ static void __devinit snd_interwave_detect_memory(struct snd_gus_card * gus)
                for (i = 0; i < 8; ++i)
                        iwave[i] = snd_gf1_peek(gus, bank_pos + i);
 #ifdef CONFIG_SND_DEBUG_ROM
-               printk(KERN_DEBUG "ROM at 0x%06x = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", bank_pos,
-                      iwave[0], iwave[1], iwave[2], iwave[3],
-                      iwave[4], iwave[5], iwave[6], iwave[7]);
+               printk(KERN_DEBUG "ROM at 0x%06x = %*phC\n", bank_pos,
+                                 8, iwave);
 #endif
                if (strncmp(iwave, "INTRWAVE", 8))
                        continue;       /* first check */
index c24594c866f458adbcdd155e025d4f2ba9c78ebf..3d1afb612b3548ade1db68d1b60af8f3e7e6ce4b 100644 (file)
@@ -37,6 +37,7 @@
 #include <sound/opl4.h>
 #include <sound/control.h>
 #include <sound/info.h>
+#define SNDRV_LEGACY_FIND_FREE_IOPORT
 #define SNDRV_LEGACY_FIND_FREE_IRQ
 #define SNDRV_LEGACY_FIND_FREE_DMA
 #include <sound/initval.h>
@@ -770,20 +771,6 @@ static int __devinit snd_miro_mixer(struct snd_card *card,
        return 0;
 }
 
-static long snd_legacy_find_free_ioport(long *port_table, long size)
-{
-       while (*port_table != -1) {
-               struct resource *res;
-               if ((res = request_region(*port_table, size, 
-                                         "ALSA test")) != NULL) {
-                       release_and_free_resource(res);
-                       return *port_table;
-               }
-               port_table++;
-       }
-       return -1;
-}
-
 static int __devinit snd_miro_init(struct snd_miro *chip,
                                   unsigned short hardware)
 {
index f8fbe22515c99b627885fa3c05da815514777f4e..2899c9fd1ceb4c12a34d01d714ec1bd3d4e74767 100644 (file)
@@ -39,6 +39,7 @@
 #ifndef OPTi93X
 #include <sound/opl4.h>
 #endif
+#define SNDRV_LEGACY_FIND_FREE_IOPORT
 #define SNDRV_LEGACY_FIND_FREE_IRQ
 #define SNDRV_LEGACY_FIND_FREE_DMA
 #include <sound/initval.h>
@@ -185,19 +186,6 @@ static char * snd_opti9xx_names[] = {
        "82C930",       "82C931",       "82C933"
 };
 
-
-static long __devinit snd_legacy_find_free_ioport(long *port_table, long size)
-{
-       while (*port_table != -1) {
-               if (request_region(*port_table, size, "ALSA test")) {
-                       release_region(*port_table, size);
-                       return *port_table;
-               }
-               port_table++;
-       }
-       return -1;
-}
-
 static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip,
                                      unsigned short hardware)
 {
index 71887874679c1ae7d93b436a7998e86c5717e7ba..2aae6a0efbcd3a2a05e40f896fc0374be7e3eb3b 100644 (file)
@@ -417,9 +417,6 @@ size_dram(struct snd_emu8000 *emu)
                EMU8000_SMLD_READ(emu); /* discard stale data  */
                if (EMU8000_SMLD_READ(emu) != UNIQUE_ID2)
                        break; /* no memory at this address */
-
-               detected_size = size;
-
                snd_emu8000_read_wait(emu);
 
                /*
@@ -432,6 +429,18 @@ size_dram(struct snd_emu8000 *emu)
                if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1)
                        break; /* we must have wrapped around */
                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;
        }
 
        /* wait until FULL bit in SMAxW register is false */
index 344b4355be1cd79b898227e5a39661129227f3e9..72a9ac5efb4061360d539fb1ed13300033f13d95 100644 (file)
@@ -175,7 +175,7 @@ get_voice(struct snd_emux *emu, struct snd_emux_port *port)
        hw = emu->hw;
 
        for (i = 0; i < END; i++) {
-               best[i].time = (unsigned int)(-1); /* XXX MAX_?INT really */;
+               best[i].time = (unsigned int)(-1); /* XXX MAX_?INT really */
                best[i].voice = -1;
        }
 
index 405f8b6a58b53db482376efd456c6e2ddaf6e2a3..b1bf8d4e6494f4561ea2e11a407f4663f5882f98 100644 (file)
@@ -538,7 +538,7 @@ munge_int32 (unsigned int src,
                                    /* Note: we leave the upper bits in place */ 
 
                dst++;
-       };
+       }
        return dst;
 };
 
index 7ffc182e084478fac3e7ca4cf98523d4e68867d5..43f222825038e8e69ca8d1edd87a50e3bdc93be3 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#define SNDRV_MAIN_OBJECT_FILE
 #include <linux/init.h>
 #include <sound/core.h>
 
index 4b958b1c497c86a75b3984af6d43b553b639c401..09c932f899b8158c8fde31eb9f8dbd5eac440e72 100644 (file)
@@ -354,7 +354,7 @@ int audio_read(int dev, struct file *file, char __user *buf, int count)
 
                        if(copy_to_user(&(buf)[p], fixit, l))
                                return -EFAULT;
-               };
+               }
 
                DMAbuf_rmchars(dev, buf_no, l);
 
index 407cd677950bccb68059fdcd1abec6da914b7a38..c5c24409ceb065b49d8f7bb05d010085e4588d47 100644 (file)
@@ -1190,7 +1190,7 @@ static int opl3_init(int ioaddr, struct module *owner)
 
                for (i = 0; i < 18; i++)
                        pv_map[i].ioaddr = devc->left_io;
-       };
+       }
        conf_printf2(devc->fm_info.name, ioaddr, 0, -1, -1);
 
        for (i = 0; i < SBFM_MAXINSTR; i++)
index 0f32a561f15f6a6575d75888abc733b3ceebd377..145e36b2cfd0db9ff84232047fa89e2a3e929928 100644 (file)
@@ -359,7 +359,7 @@ static int pss_download_boot(pss_confdata * devc, unsigned char *block, int size
                {
                        /*_____ Send the next byte */
                        outw (*block++, REG (PSS_DATA));
-               };
+               }
                count++;
        }
 
index 5c773dff5ac5dd702d2f463c348373e999f0ef65..c0be085e4a200e4878097138b9294fe0d4a0855c 100644 (file)
@@ -1104,15 +1104,15 @@ int ess_init(sb_devc * devc, struct address_info *hw_config)
                default:
                        printk (KERN_ERR "Invalid esstype=%d specified\n", devc->sbmo.esstype);
                        return 0;
-               };
+               }
                if (submodel != -1) {
                        devc->submodel = submodel;
                        sprintf (modelname, "ES%d", devc->sbmo.esstype);
                        chip = modelname;
-               };
+               }
                if (chip == NULL && (ess_minor & 0x0f) < 8) {
                        chip = "ES688";
-               };
+               }
 #ifdef FKS_TEST
 FKS_test (devc);
 #endif
@@ -1122,7 +1122,7 @@ FKS_test (devc);
                 */
                if (chip == NULL && devc->sbmo.esstype == ESSTYPE_LIKE20) {
                        chip = "ES1688";
-               };
+               }
 
                if (chip == NULL) {
                        int type;
@@ -1150,8 +1150,8 @@ FKS_test (devc);
                                if ((type & 0x00ff) != ((type >> 8) & 0x00ff)) {
                                        printk ("ess_init: Unrecognized %04x\n", type);
                                }
-                       };
-               };
+                       }
+               }
 #if 0
                /*
                 * this one failed:
@@ -1182,10 +1182,10 @@ FKS_test (devc);
                                chip = "ES1788";
                                devc->submodel = SUBMDL_ES1788;
                        }
-               };
+               }
                if (chip == NULL) {
                        chip = "ES1688";
-               };
+               }
 
            printk ( KERN_INFO "ESS chip %s %s%s\n"
                , chip
@@ -1293,7 +1293,7 @@ printk(KERN_INFO "ess_set_dma_hw: dma8=%d,dma16=%d,dup=%d\n"
                        default:
                                printk(KERN_ERR "ESS1887: Invalid DMA16 %d\n", dma);
                                return 0;
-                       };
+                       }
                        ess_chgmixer (devc, 0x78, 0x20, dma16_bits);
                        ess_chgmixer (devc, 0x7d, 0x07, dma_bits);
                }
@@ -1584,7 +1584,7 @@ printk(KERN_INFO "FKS: write mixer %x: %x\n", port, value);
                udelay(20);
                outb(((unsigned char) (value & 0xff)), MIXER_DATA);
                udelay(20);
-       };
+       }
        spin_unlock_irqrestore(&devc->lock, flags);
 }
 
@@ -1761,7 +1761,7 @@ int ess_mixer_reset (sb_devc * devc)
                        ess_chgmixer(devc, 0x7a, 0x18, 0x08);
                        ess_chgmixer(devc, 0x1c, 0x07, 0x07);
                        break;
-               };
+               }
                /*
                 * Call set_recmask for proper initialization
                 */
index f8f3b7a66b7377fcc25fc84b76c8b9b63af44181..acf7586aeb47de2ba6184c208e69777d45cb4c4a 100644 (file)
@@ -410,7 +410,7 @@ static int set_recmask(sb_devc * devc, int mask)
                case MDL_SMW:
                        if (devc->model == MDL_ESS && ess_set_recmask (devc, &devmask)) {
                                break;
-                       };
+                       }
                        if (devmask != SOUND_MASK_MIC &&
                                devmask != SOUND_MASK_LINE &&
                                devmask != SOUND_MASK_CD)
@@ -666,7 +666,7 @@ static void sb_mixer_reset(sb_devc * devc)
 
        if (devc->model != MDL_ESS || !ess_mixer_reset (devc)) {
                set_recmask(devc, SOUND_MASK_MIC);
-       };
+       }
 }
 
 int sb_mixer_init(sb_devc * devc, struct module *owner)
index 8db6aefe15e4043224a788c2d9bc314e1c2055a9..9f039831114c2f75e11789e061dd505933f87beb 100644 (file)
@@ -57,7 +57,7 @@ poll_def_tmr(unsigned long dummy)
                  {
                          def_tmr.expires = (1) + jiffies;
                          add_timer(&def_tmr);
-                 };
+                 }
 
                  if (tmr_running)
                    {
@@ -103,7 +103,7 @@ def_tmr_open(int dev, int mode)
        {
                def_tmr.expires = (1) + jiffies;
                add_timer(&def_tmr);
-       };
+       }
 
        return 0;
 }
index f3f914aa92ee3aaf25a81fa80f02bde9b27b3077..1079133dd6ab17fc856677a328ea54563028c555 100644 (file)
@@ -146,7 +146,7 @@ static int uart6850_open(int dev, int mode,
        {
 /*               printk("Midi6850: Midi busy\n");*/
                  return -EBUSY;
-       };
+       }
 
        uart6850_cmd(UART_RESET);
        uart6850_input_loop();
index a872d0a829767d50bbeeaa3ee7f9ba7be40de683..66a3bc95fb844c3f1b311b227622aacbb680a50c 100644 (file)
@@ -2595,6 +2595,21 @@ static void alc650_update_jacks(struct snd_ac97 *ac97)
                             shared ? 0 : 0x100);
 }
 
+static int alc650_swap_surround_put(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
+       struct snd_pcm_chmap *map = ac97->chmaps[SNDRV_PCM_STREAM_PLAYBACK];
+
+       if (map) {
+               if (ucontrol->value.integer.value[0])
+                       map->chmap = snd_pcm_std_chmaps;
+               else
+                       map->chmap = snd_pcm_alt_chmaps;
+       }
+       return snd_ac97_put_volsw(kcontrol, ucontrol);
+}
+
 static const struct snd_kcontrol_new snd_ac97_controls_alc650[] = {
        AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0),
        AC97_SINGLE("Surround Down Mix", AC97_ALC650_MULTICH, 1, 1, 0),
@@ -2608,7 +2623,14 @@ static const struct snd_kcontrol_new snd_ac97_controls_alc650[] = {
        /* 9: Line-In/Surround share */
        /* 10: Mic/CLFE share */
        /* 11-13: in IEC958 controls */
-       AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Swap Surround Slot",
+               .info = snd_ac97_info_volsw,
+               .get = snd_ac97_get_volsw,
+               .put = alc650_swap_surround_put,
+               .private_value =  AC97_SINGLE_VALUE(AC97_ALC650_MULTICH, 14, 1, 0),
+       },
 #if 0 /* always set in patch_alc650 */
        AC97_SINGLE("IEC958 Input Clock Enable", AC97_ALC650_CLOCK, 0, 1, 0),
        AC97_SINGLE("IEC958 Input Pin Enable", AC97_ALC650_CLOCK, 1, 1, 0),
index ee895f3c8605890f39032263485e9bfb99720939..c7e3c533316eeb72e0873353478354caa7594aab 100644 (file)
@@ -270,7 +270,7 @@ struct snd_ali {
        spinlock_t      reg_lock;
        spinlock_t      voice_alloc;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        struct snd_ali_image *image;
 #endif
 };
@@ -1883,7 +1883,7 @@ static int __devinit snd_ali_mixer(struct snd_ali * codec)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int ali_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -1989,7 +1989,7 @@ static SIMPLE_DEV_PM_OPS(ali_pm, ali_suspend, ali_resume);
 #define ALI_PM_OPS     &ali_pm
 #else
 #define ALI_PM_OPS     NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int snd_ali_free(struct snd_ali * codec)
 {
@@ -2000,7 +2000,7 @@ static int snd_ali_free(struct snd_ali * codec)
        if (codec->port)
                pci_release_regions(codec->pci);
        pci_disable_device(codec->pci);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        kfree(codec->image);
 #endif
        pci_dev_put(codec->pci_m1533);
@@ -2232,7 +2232,7 @@ static int __devinit snd_ali_create(struct snd_card *card,
                return err;
        }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        codec->image = kmalloc(sizeof(*codec->image), GFP_KERNEL);
        if (!codec->image)
                snd_printk(KERN_WARNING "can't allocate apm buffer\n");
index 68c4469c6d1995ed775d49212de6db204da0e668..00f157a2cf6411d8b1ad1b1ffef32f566d5e02b8 100644 (file)
@@ -765,7 +765,7 @@ static int __devinit snd_als300_create(struct snd_card *card,
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_als300_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
index 0eeca49c57541b3dc85cab82ba389214adab40e1..feb2a143683079df95f47384f0b52c9621a0a03b 100644 (file)
@@ -987,7 +987,7 @@ static void __devexit snd_card_als4000_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_als4000_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -1040,7 +1040,7 @@ static SIMPLE_DEV_PM_OPS(snd_als4000_pm, snd_als4000_suspend, snd_als4000_resume
 #define SND_ALS4000_PM_OPS     &snd_als4000_pm
 #else
 #define SND_ALS4000_PM_OPS     NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver als4000_driver = {
        .name = KBUILD_MODNAME,
index e8de831f98bc510c6cde42159bce817dad45408b..eedc017c1cd8f7f65f537ddca7c445c6e3b14111 100644 (file)
@@ -2658,7 +2658,7 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
                                        hpi_ctl.dst_node_type,
                                        hpi_ctl.dst_node_index);
                        continue;
-               };
+               }
                if (err < 0)
                        return err;
        }
@@ -2968,7 +2968,7 @@ static struct pci_driver driver = {
        .id_table = asihpi_pci_tbl,
        .probe = snd_asihpi_probe,
        .remove = __devexit_p(snd_asihpi_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*     .suspend = snd_asihpi_suspend,
        .resume = snd_asihpi_resume, */
 #endif
index 31020d2a868bd97b92d18e65ceb469214f24f7f6..368df8b0853e218ca48b92553ccd653d8b406195 100644 (file)
@@ -535,7 +535,7 @@ static int snd_atiixp_aclink_reset(struct atiixp *chip)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_atiixp_aclink_down(struct atiixp *chip)
 {
        // if (atiixp_read(chip, MODEM_MIRROR) & 0x1) /* modem running, too? */
@@ -1250,6 +1250,7 @@ static struct atiixp_dma_ops snd_atiixp_spdif_dma_ops = {
 static int __devinit snd_atiixp_pcm_new(struct atiixp *chip)
 {
        struct snd_pcm *pcm;
+       struct snd_pcm_chmap *chmap;
        struct snd_ac97_bus *pbus = chip->ac97_bus;
        int err, i, num_pcms;
 
@@ -1293,6 +1294,14 @@ static int __devinit snd_atiixp_pcm_new(struct atiixp *chip)
                                              snd_dma_pci_data(chip->pci),
                                              64*1024, 128*1024);
 
+       err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                                    snd_pcm_alt_chmaps, chip->max_channels, 0,
+                                    &chmap);
+       if (err < 0)
+               return err;
+       chmap->channel_mask = SND_PCM_CHMAP_MASK_2468;
+       chip->ac97[0]->chmaps[SNDRV_PCM_STREAM_PLAYBACK] = chmap;
+
        /* no SPDIF support on codec? */
        if (chip->pcms[ATI_PCM_SPDIF] && ! chip->pcms[ATI_PCM_SPDIF]->rates)
                return 0;
@@ -1458,7 +1467,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp *chip, int clock,
 }
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -1533,7 +1542,7 @@ static SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume);
 #define SND_ATIIXP_PM_OPS      &snd_atiixp_pm
 #else
 #define SND_ATIIXP_PM_OPS      NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 
 #ifdef CONFIG_PROC_FS
index 79e204ec623fe298859f216c85c36244ab81bf33..6fc03d9f2cff451c2b3db77a525c64cd984c6b92 100644 (file)
@@ -511,7 +511,7 @@ static int snd_atiixp_aclink_reset(struct atiixp_modem *chip)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_atiixp_aclink_down(struct atiixp_modem *chip)
 {
        // if (atiixp_read(chip, MODEM_MIRROR) & 0x1) /* modem running, too? */
@@ -1113,7 +1113,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock)
 }
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -1169,7 +1169,7 @@ static SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume);
 #define SND_ATIIXP_PM_OPS      &snd_atiixp_pm
 #else
 #define SND_ATIIXP_PM_OPS      NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_PROC_FS
 /*
index c07c792bde8d27a8ad8c6627ac0c8de784c2608e..30a456700d899bb88cbc643d3d5ea782a2f3d684 100644 (file)
@@ -100,7 +100,7 @@ static int __devinit vortex_gameport_register(vortex_t * vortex)
        if (!gp) {
                printk(KERN_ERR "vortex: cannot allocate memory for gameport\n");
                return -ENOMEM;
-       };
+       }
 
        gameport_set_name(gp, "AU88x0 Gameport");
        gameport_set_phys(gp, "pci%s/gameport0", pci_name(vortex->pci_dev));
index e59f120742a48e4140a54d80c63f6592c325c220..b2405020284c6476814b8039a27cb416d64bf668 100644 (file)
@@ -585,7 +585,7 @@ static int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol,
                                case 4:
                                        mixin = p->mixin[i];
                                        break;
-                               };
+                               }
                                vol = p->vol[i];
                                vortex_mix_setinputvolumebyte(vortex,
                                        vortex->mixplayb[i], mixin, vol);
index 4dddd871548b3de1c83bb829c4c16bee7fa1a14e..c03b66b784a377ef22135d81de415995c9c163d7 100644 (file)
@@ -365,7 +365,7 @@ struct snd_azf3328 {
         * CONFIG_PM register storage below, but that's slightly difficult. */
        u16 shadow_reg_ctrl_6AH;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        /* register value containers for power management
         * Note: not always full I/O range preserved (similar to Win driver!) */
        u32 saved_regs_ctrl[AZF_ALIGN(AZF_IO_SIZE_CTRL_PM) / 4];
@@ -2729,7 +2729,7 @@ snd_azf3328_remove(struct pci_dev *pci)
        snd_azf3328_dbgcallleave();
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static inline void
 snd_azf3328_suspend_regs(unsigned long io_addr, unsigned count, u32 *saved_regs)
 {
@@ -2866,7 +2866,7 @@ static SIMPLE_DEV_PM_OPS(snd_azf3328_pm, snd_azf3328_suspend, snd_azf3328_resume
 #define SND_AZF3328_PM_OPS     &snd_azf3328_pm
 #else
 #define SND_AZF3328_PM_OPS     NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver azf3328_driver = {
        .name = KBUILD_MODNAME,
index e8e8ccc964038c1aa29154d83c44b8c2b616b8e5..04402c14cb2392276bb23308244c626b6539fc4e 100644 (file)
@@ -710,7 +710,7 @@ struct snd_ca0106 {
 
        u16 spi_dac_reg[16];
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 #define NUM_SAVED_VOLUMES      9
        unsigned int saved_vol[NUM_SAVED_VOLUMES];
 #endif
@@ -733,7 +733,7 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu, u32 reg, u32 value);
 int snd_ca0106_spi_write(struct snd_ca0106 * emu,
                                   unsigned int data);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip);
 void snd_ca0106_mixer_resume(struct snd_ca0106 *chip);
 #else
index 83277b747b36928f96ba14ab9bb0d32dcea1de57..65c55910566b24eb5dda03445a0e50f0f848bfe5 100644 (file)
@@ -1334,10 +1334,29 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static const struct snd_pcm_chmap_elem surround_map[] = {
+       { .channels = 2,
+         .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+       { }
+};
+
+static const struct snd_pcm_chmap_elem clfe_map[] = {
+       { .channels = 2,
+         .map = { SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } },
+       { }
+};
+
+static const struct snd_pcm_chmap_elem side_map[] = {
+       { .channels = 2,
+         .map = { SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
+       { }
+};
+
 static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device)
 {
        struct snd_pcm *pcm;
        struct snd_pcm_substream *substream;
+       const struct snd_pcm_chmap_elem *map = NULL;
        int err;
   
        err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm);
@@ -1350,18 +1369,22 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device)
        case 0:
          snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_front_ops);
          snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_0_ops);
+         map = snd_pcm_std_chmaps;
           break;
        case 1:
          snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_rear_ops);
          snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_1_ops);
+         map = surround_map;
           break;
        case 2:
          snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_center_lfe_ops);
          snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_2_ops);
+         map = clfe_map;
           break;
        case 3:
          snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ca0106_playback_unknown_ops);
          snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ca0106_capture_3_ops);
+         map = side_map;
           break;
         }
 
@@ -1388,6 +1411,11 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device)
                        return err;
        }
   
+       err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2,
+                                    1 << 2, NULL);
+       if (err < 0)
+               return err;
+
        emu->pcm[device] = pcm;
   
        return 0;
@@ -1871,7 +1899,7 @@ static void __devexit snd_ca0106_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_ca0106_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
index 84f3f92436b5a34eb414158bea5405288e27e455..68eacf7002d6ee87b848818b06a6997236d00426 100644 (file)
@@ -907,7 +907,7 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
         return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 struct ca0106_vol_tbl {
        unsigned int channel_id;
        unsigned int reg;
@@ -953,4 +953,4 @@ void snd_ca0106_mixer_resume(struct snd_ca0106  *chip)
        if (chip->details->i2c_adc)
                ca0106_set_capture_mic_line_in(chip);
 }
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
index b7d6f2b886effc78de4da2caaeac53b1ff786010..22122ff26e34aacabf963c731f645aabb5678158 100644 (file)
@@ -504,7 +504,7 @@ struct cmipci {
 
        spinlock_t reg_lock;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        unsigned int saved_regs[0x20];
        unsigned char saved_mixers[0x20];
 #endif
@@ -1962,6 +1962,12 @@ static int __devinit snd_cmipci_pcm_spdif_new(struct cmipci *cm, int device)
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                              snd_dma_pci_data(cm->pci), 64*1024, 128*1024);
 
+       err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                                    snd_pcm_alt_chmaps, cm->max_channels, 0,
+                                    NULL);
+       if (err < 0)
+               return err;
+
        return 0;
 }
 
@@ -3315,7 +3321,7 @@ static void __devexit snd_cmipci_remove(struct pci_dev *pci)
 }
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -3403,7 +3409,7 @@ static SIMPLE_DEV_PM_OPS(snd_cmipci_pm, snd_cmipci_suspend, snd_cmipci_resume);
 #define SND_CMIPCI_PM_OPS      &snd_cmipci_pm
 #else
 #define SND_CMIPCI_PM_OPS      NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver cmipci_driver = {
        .name = KBUILD_MODNAME,
index 45a8317085f44961719db1b76195afb1d4d7e0ff..8e86ec0031fcce10cdec54d3bbb6d03d310daa8f 100644 (file)
@@ -486,7 +486,7 @@ struct cs4281 {
 
        struct gameport *gameport;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        u32 suspend_regs[SUSPEND_REGISTERS];
 #endif
 
@@ -1977,7 +1977,7 @@ static void __devexit snd_cs4281_remove(struct pci_dev *pci)
 /*
  * Power Management
  */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 
 static int saved_regs[SUSPEND_REGISTERS] = {
        BA0_JSCTL,
@@ -2089,7 +2089,7 @@ static SIMPLE_DEV_PM_OPS(cs4281_pm, cs4281_suspend, cs4281_resume);
 #define CS4281_PM_OPS  &cs4281_pm
 #else
 #define CS4281_PM_OPS  NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver cs4281_driver = {
        .name = KBUILD_MODNAME,
index 1e007c736a8bf6b939334fcc3ee9d5faf0ec14f7..575bed0836ffa242856ab5db73f8cbe2d80288da 100644 (file)
@@ -166,7 +166,7 @@ static struct pci_driver cs46xx_driver = {
        .id_table = snd_cs46xx_ids,
        .probe = snd_card_cs46xx_probe,
        .remove = __devexit_p(snd_card_cs46xx_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .driver = {
                .pm = &snd_cs46xx_pm,
        },
index 29d8a8da1ba73a6bf0e4ff915e7492a7745ec862..fc339ef0a0ae439a87087753a4bfaf6e28de9742 100644 (file)
@@ -1721,7 +1721,7 @@ struct snd_cs46xx {
        unsigned int play_ctl;
 #endif
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        u32 *saved_regs;
 #endif
 };
index a71d1c14a0f6b9efa06bc91d2970bb304ebaa872..a2bb8c91ebe6041c61b2789d0ef97b073ac518b1 100644 (file)
@@ -2797,7 +2797,7 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip)
        }
 #endif
        
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        kfree(chip->saved_regs);
 #endif
 
@@ -3590,7 +3590,7 @@ static struct cs_card_type __devinitdata cards[] = {
 /*
  * APM support
  */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static unsigned int saved_regs[] = {
        BA0_ACOSV,
        /*BA0_ASER_FADDR,*/
@@ -3711,7 +3711,7 @@ static int snd_cs46xx_resume(struct device *dev)
 }
 
 SIMPLE_DEV_PM_OPS(snd_cs46xx_pm, snd_cs46xx_suspend, snd_cs46xx_resume);
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 
 /*
@@ -3868,7 +3868,7 @@ int __devinit snd_cs46xx_create(struct snd_card *card,
        
        snd_cs46xx_proc_init(card, chip);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        chip->saved_regs = kmalloc(sizeof(*chip->saved_regs) *
                                   ARRAY_SIZE(saved_regs), GFP_KERNEL);
        if (!chip->saved_regs) {
index b5189495d58a412634d6be413e7cf77ac9876907..86f14620f817f70821aabe16086a20a238f0c0c3 100644 (file)
@@ -90,7 +90,7 @@ static inline unsigned int snd_cs46xx_peekBA0(struct snd_cs46xx *chip, unsigned
 struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip);
 void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip);
 int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 int cs46xx_dsp_resume(struct snd_cs46xx * chip);
 #endif
 struct dsp_symbol_entry *cs46xx_dsp_lookup_symbol (struct snd_cs46xx * chip, char * symbol_name,
index 56fec0bc0efb30cfbd04fcad3d80dd03efa81725..1686b4f4c44fb493538ada5bf14f4965ed645443 100644 (file)
@@ -287,7 +287,7 @@ void  cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip)
                if (ins->scbs[i].deleted) continue;
 
                cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
                kfree(ins->scbs[i].data);
 #endif
        }
@@ -1019,7 +1019,7 @@ cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32
 {
        struct dsp_scb_descriptor * desc;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        /* copy the data for resume */
        scb_data = kmemdup(scb_data, SCB_BYTES, GFP_KERNEL);
        if (!scb_data)
@@ -1032,7 +1032,7 @@ cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32
                _dsp_create_scb(chip,scb_data,dest);
        } else {
                snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n");
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
                kfree(scb_data);
 #endif
        }
@@ -1937,7 +1937,7 @@ int cs46xx_dsp_set_iec958_volume (struct snd_cs46xx * chip, u16 left, u16 right)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 int cs46xx_dsp_resume(struct snd_cs46xx * chip)
 {
        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
index c2c695b07f8cc0c63e1599f403ccaade2b9e52f7..409e8764fbeb2a3678b4c01446a699fc631bc2a5 100644 (file)
@@ -203,7 +203,7 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor *
        remove_symbol (chip,scb->scb_symbol);
 
        ins->scbs[scb->index].deleted = 1;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        kfree(ins->scbs[scb->index].data);
        ins->scbs[scb->index].data = NULL;
 #endif
index f1e4229993af198a23afb4f33a93f1153251e9b5..d1cca2831575973dac041b49d066afa404b89f0d 100644 (file)
@@ -142,8 +142,7 @@ static int __devinit snd_cs5530_create(struct snd_card *card,
 
        mem = pci_ioremap_bar(pci, 0);
        if (mem == NULL) {
-               kfree(chip);
-               pci_disable_device(pci);
+               snd_cs5530_free(chip);
                return -EBUSY;
        }
 
index ccc642269b9e6a71a108df9f03d39d54f5df9029..a8f75f8dfda9912229cf8b4bfd087230900c49e8 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o
-snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o
+snd-cs5535audio-$(CONFIG_PM_SLEEP) += cs5535audio_pm.o
 snd-cs5535audio-$(CONFIG_OLPC) += cs5535audio_olpc.o
 
 # Toplevel Module Dependency
index 51f64ba5facf0ace8ec14e85ef4eb6911100f9d9..4915efa551fca122434cc926adcf92721b58018f 100644 (file)
@@ -399,7 +399,7 @@ static struct pci_driver cs5535audio_driver = {
        .id_table = snd_cs5535audio_ids,
        .probe = snd_cs5535audio_probe,
        .remove = __devexit_p(snd_cs5535audio_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .driver = {
                .pm = &snd_cs5535audio_pm,
        },
index 2f6e9c762d3fd184dd995b17a9485faf050dffeb..a2f997a9977a7218e1085b9ee75857ab45f9ee44 100644 (file)
@@ -1536,7 +1536,7 @@ static void atc_connect_resources(struct ct_atc *atc)
        }
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int atc_suspend(struct ct_atc *atc)
 {
        int i;
@@ -1647,7 +1647,7 @@ static struct ct_atc atc_preset __devinitdata = {
        .output_switch_put = atc_output_switch_put,
        .mic_source_switch_get = atc_mic_source_switch_get,
        .mic_source_switch_put = atc_mic_source_switch_put,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .suspend = atc_suspend,
        .resume = atc_resume,
 #endif
index 653e813ad1422729ce69c26df8a81b721c095387..69b51f9d345eda48eff3fa2b85790b70990e188d 100644 (file)
@@ -143,7 +143,7 @@ struct ct_atc {
 
        struct ct_timer *timer;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        int (*suspend)(struct ct_atc *atc);
        int (*resume)(struct ct_atc *atc);
 #define NUM_PCMS (NUM_CTALSADEVS - 1)
index c56fe533b3f375b643988e9d1b9b40f783fa6385..5977e9a24b5ca68971e1f5f0dc17f17b03257098 100644 (file)
@@ -72,7 +72,7 @@ struct hw {
        int (*card_init)(struct hw *hw, struct card_conf *info);
        int (*card_stop)(struct hw *hw);
        int (*pll_init)(struct hw *hw, unsigned int rsr);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        int (*suspend)(struct hw *hw);
        int (*resume)(struct hw *hw, struct card_conf *info);
 #endif
index dc1969bc67d4982d187cb095ad29d6f61b132607..4507f7088b24c1b69dba253a2968d3bfdc95d7da 100644 (file)
@@ -2085,7 +2085,7 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int hw_suspend(struct hw *hw)
 {
        struct pci_dev *pci = hw->pci;
@@ -2180,7 +2180,7 @@ static struct hw ct20k1_preset __devinitdata = {
        .is_adc_source_selected = hw_is_adc_input_selected,
        .select_adc_source = hw_adc_input_select,
        .capabilities = hw_capabilities,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .suspend = hw_suspend,
        .resume = hw_resume,
 #endif
index 9d1231dc4ae22d8a5041bd3722fd406f55d95a58..b9c9349058bcc9178242fc5680849eb6f074c07c 100644 (file)
@@ -2201,7 +2201,7 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int hw_suspend(struct hw *hw)
 {
        struct pci_dev *pci = hw->pci;
@@ -2250,7 +2250,7 @@ static struct hw ct20k2_preset __devinitdata = {
        .output_switch_put = hw_output_switch_put,
        .mic_source_switch_get = hw_mic_source_switch_get,
        .mic_source_switch_put = hw_mic_source_switch_put,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .suspend = hw_suspend,
        .resume = hw_resume,
 #endif
index 0cc13eeef8da7ee04125f32005393bdbe95df821..48fe0e39c2be273a95762698999dd4cf5508b019 100644 (file)
@@ -1118,7 +1118,7 @@ mixer_set_input_right(struct ct_mixer *mixer,
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int mixer_resume(struct ct_mixer *mixer)
 {
        int i, state;
@@ -1188,7 +1188,7 @@ int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer)
        mixer->get_output_ports = mixer_get_output_ports;
        mixer->set_input_left = mixer_set_input_left;
        mixer->set_input_right = mixer_set_input_right;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        mixer->resume = mixer_resume;
 #endif
 
index b009e989e77ddcef32cc8451c8eb8b99102f67c0..be881c639fee536f46c3f605984facc37d6d0ebb 100644 (file)
@@ -56,7 +56,7 @@ struct ct_mixer {
                              enum MIXER_PORT_T type, struct rsc *rsc);
        int (*set_input_right)(struct ct_mixer *mixer,
                               enum MIXER_PORT_T type, struct rsc *rsc);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        int (*resume)(struct ct_mixer *mixer);
 #endif
 };
index 2c8622617c8c4cac7df6f01535cc97adc165c206..e8a4feb1ed86ba59396368601f1cdbfeb364ce0a 100644 (file)
@@ -395,12 +395,38 @@ static struct snd_pcm_ops ct_pcm_capture_ops = {
        .page           = snd_pcm_sgbuf_ops_page,
 };
 
+static const struct snd_pcm_chmap_elem surround_map[] = {
+       { .channels = 1,
+         .map = { SNDRV_CHMAP_MONO } },
+       { .channels = 2,
+         .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+       { }
+};
+
+static const struct snd_pcm_chmap_elem clfe_map[] = {
+       { .channels = 1,
+         .map = { SNDRV_CHMAP_MONO } },
+       { .channels = 2,
+         .map = { SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } },
+       { }
+};
+
+static const struct snd_pcm_chmap_elem side_map[] = {
+       { .channels = 1,
+         .map = { SNDRV_CHMAP_MONO } },
+       { .channels = 2,
+         .map = { SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
+       { }
+};
+
 /* Create ALSA pcm device */
 int ct_alsa_pcm_create(struct ct_atc *atc,
                       enum CTALSADEVS device,
                       const char *device_name)
 {
        struct snd_pcm *pcm;
+       const struct snd_pcm_chmap_elem *map;
+       int chs;
        int err;
        int playback_count, capture_count;
 
@@ -427,7 +453,31 @@ int ct_alsa_pcm_create(struct ct_atc *atc,
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
                        snd_dma_pci_data(atc->pci), 128*1024, 128*1024);
 
-#ifdef CONFIG_PM
+       chs = 2;
+       switch (device) {
+       case FRONT:
+               chs = 8;
+               map = snd_pcm_std_chmaps;
+               break;
+       case SURROUND:
+               map = surround_map;
+               break;
+       case CLFE:
+               map = clfe_map;
+               break;
+       case SIDE:
+               map = side_map;
+               break;
+       default:
+               map = snd_pcm_std_chmaps;
+               break;
+       }
+       err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, chs,
+                                    0, NULL);
+       if (err < 0)
+               return err;
+
+#ifdef CONFIG_PM_SLEEP
        atc->pcms[device] = pcm;
 #endif
 
index e002183ef8b2a7f0c5cd8a542d58340020299beb..07c07d752fd8978fa040363b10329078c14a0fcf 100644 (file)
@@ -125,7 +125,7 @@ static void __devexit ct_card_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int ct_card_suspend(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
index 0ff754f180d0e852e55c74b2454d1ca00dba21d6..abb0b86c41c942286c2897727e60ab466323d93f 100644 (file)
@@ -46,7 +46,7 @@ static int get_firmware(const struct firmware **fw_entry,
        int err;
        char name[30];
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        if (chip->fw_cache[fw_index]) {
                DE_ACT(("firmware requested: %s is cached\n", card_fw[fw_index].data));
                *fw_entry = chip->fw_cache[fw_index];
@@ -59,7 +59,7 @@ static int get_firmware(const struct firmware **fw_entry,
        err = request_firmware(fw_entry, name, pci_device(chip));
        if (err < 0)
                snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        else
                chip->fw_cache[fw_index] = *fw_entry;
 #endif
@@ -70,7 +70,7 @@ static int get_firmware(const struct firmware **fw_entry,
 
 static void free_firmware(const struct firmware *fw_entry)
 {
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        DE_ACT(("firmware not released (kept in cache)\n"));
 #else
        release_firmware(fw_entry);
@@ -82,7 +82,7 @@ static void free_firmware(const struct firmware *fw_entry)
 
 static void free_firmware_cache(struct echoaudio *chip)
 {
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        int i;
 
        for (i = 0; i < 8 ; i++)
@@ -2203,7 +2203,7 @@ ctl_error:
 
 
 
-#if defined(CONFIG_PM)
+#if defined(CONFIG_PM_SLEEP)
 
 static int snd_echo_suspend(struct device *dev)
 {
@@ -2313,7 +2313,7 @@ static SIMPLE_DEV_PM_OPS(snd_echo_pm, snd_echo_suspend, snd_echo_resume);
 #define SND_ECHO_PM_OPS        &snd_echo_pm
 #else
 #define SND_ECHO_PM_OPS        NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 
 static void __devexit snd_echo_remove(struct pci_dev *pci)
index 1df974dcb5f4b9b37a7e1727645a3fcbec50d0d9..e158369f5faaa117d23d71878293a27d6a428f86 100644 (file)
@@ -449,7 +449,7 @@ struct echoaudio {
        volatile u32 __iomem *dsp_registers;    /* DSP's register base */
        u32 active_mask;                        /* Chs. active mask or
                                                 * punks out */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        const struct firmware *fw_cache[8];     /* Cached firmwares */
 #endif
 
index ddac4e6d660d0116f27af2ebf4f70344b63b932d..b7c1875ba90ec2ad06518a1af310fd62d3f357cb 100644 (file)
@@ -206,7 +206,7 @@ static void __devexit snd_card_emu10k1_remove(struct pci_dev *pci)
 }
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_emu10k1_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -268,7 +268,7 @@ static SIMPLE_DEV_PM_OPS(snd_emu10k1_pm, snd_emu10k1_suspend, snd_emu10k1_resume
 #define SND_EMU10K1_PM_OPS     &snd_emu10k1_pm
 #else
 #define SND_EMU10K1_PM_OPS     NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver emu10k1_driver = {
        .name = KBUILD_MODNAME,
index a0afa5057488895b9e5710ccc57017db6d21e6d4..cae36597aa718c3fc13abe95221a2308627c2c8c 100644 (file)
@@ -228,7 +228,7 @@ lookup_voices(struct snd_emux *emu, struct snd_emu10k1 *hw,
        int  i;
 
        for (i = 0; i < V_END; i++) {
-               best[i].time = (unsigned int)-1; /* XXX MAX_?INT really */;
+               best[i].time = (unsigned int)-1; /* XXX MAX_?INT really */
                best[i].voice = -1;
        }
 
index 754924081d0ac99a4434c0e887faa1b69dc9f417..bed4485f34f61fa7b90cfaa6bc5a3da3b9e55150 100644 (file)
@@ -1241,7 +1241,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
  *  Create the EMU10K1 instance
  */
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int alloc_pm_buffer(struct snd_emu10k1 *emu);
 static void free_pm_buffer(struct snd_emu10k1 *emu);
 #endif
@@ -1275,7 +1275,7 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
                snd_dma_free_pages(&emu->ptb_pages);
        vfree(emu->page_ptr_table);
        vfree(emu->page_addr_table);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        free_pm_buffer(emu);
 #endif
        if (emu->port)
@@ -1971,7 +1971,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
        err = snd_emu10k1_init(emu, enable_ir, 0);
        if (err < 0)
                goto error;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        err = alloc_pm_buffer(emu);
        if (err < 0)
                goto error;
@@ -2000,7 +2000,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
        return err;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static unsigned char saved_regs[] = {
        CPF, PTRX, CVCF, VTFT, Z1, Z2, PSST, DSL, CCCA, CCR, CLP,
        FXRT, MAPA, MAPB, ENVVOL, ATKHLDV, DCYSUSV, LFOVAL1, ENVVAL,
index 5c8978b2c4d9b1486afb26566a40b384e48106b0..556fd6f456e36809af61c5156a062db67f3de386 100644 (file)
@@ -830,9 +830,22 @@ static irqreturn_t snd_emu10k1x_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static const struct snd_pcm_chmap_elem surround_map[] = {
+       { .channels = 2,
+         .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+       { }
+};
+
+static const struct snd_pcm_chmap_elem clfe_map[] = {
+       { .channels = 2,
+         .map = { SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } },
+       { }
+};
+
 static int __devinit snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct snd_pcm **rpcm)
 {
        struct snd_pcm *pcm;
+       const struct snd_pcm_chmap_elem *map = NULL;
        int err;
        int capture = 0;
   
@@ -861,12 +874,15 @@ static int __devinit snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct s
        switch(device) {
        case 0:
                strcpy(pcm->name, "EMU10K1X Front");
+               map = snd_pcm_std_chmaps;
                break;
        case 1:
                strcpy(pcm->name, "EMU10K1X Rear");
+               map = surround_map;
                break;
        case 2:
                strcpy(pcm->name, "EMU10K1X Center/LFE");
+               map = clfe_map;
                break;
        }
        emu->pcm = pcm;
@@ -875,6 +891,11 @@ static int __devinit snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct s
                                              snd_dma_pci_data(emu->pci), 
                                              32*1024, 32*1024);
   
+       err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2,
+                                    1 << 2, NULL);
+       if (err < 0)
+               return err;
+
        if (rpcm)
                *rpcm = pcm;
   
index dae4050ede5cc96f4dd3b070da01b4bbebfff591..52419959178c6fcad09855b67b417537b70e226a 100644 (file)
@@ -2646,7 +2646,7 @@ int __devinit snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 int __devinit snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu)
 {
        int len;
index e22b8e2bbd884099339b807045176ceb33ee37d9..0e6664fa6cd997fe7b64137bd420523beef0444e 100644 (file)
@@ -1310,7 +1310,7 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)
                        runtime->hw.channels_min =
                                runtime->hw.channels_max = 16;
                        break;
-               };
+               }
 #endif
 #if 0
                /* For 96kHz */
index 0a436626182b9cc358def5a31f7a7daabf43c484..ae709c1ab3a848e3b954d7e04747d423b30d1e55 100644 (file)
@@ -263,8 +263,8 @@ int snd_emu10k1_memblk_map(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *b
        spin_lock_irqsave(&emu->memblk_lock, flags);
        if (blk->mapped_page >= 0) {
                /* update order link */
-               list_del(&blk->mapped_order_link);
-               list_add_tail(&blk->mapped_order_link, &emu->mapped_order_link_head);
+               list_move_tail(&blk->mapped_order_link,
+                              &emu->mapped_order_link_head);
                spin_unlock_irqrestore(&emu->memblk_lock, flags);
                return 0;
        }
index a81dc44228eab97911ea0cde311014bafa4d2ee9..88cec6b7dd41244643a6df7b3b7d80e4fb5776ab 100644 (file)
@@ -893,7 +893,7 @@ int __devinit snd_p16v_mixer(struct snd_emu10k1 *emu)
         return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 
 #define NUM_CHS        1       /* up to 4, but only first channel is used */
 
index f7e6f73186e18a99a7e25b5e5d4c5639f3032af6..5674cc316530bc3ab0a1b009e7d51b22ff0e3c1f 100644 (file)
 
 #ifdef CHIP1370
 #define DRIVER_NAME "ENS1370"
+#define CHIP_NAME "ES1370" /* it can be ENS but just to keep compatibility... */
 #else
 #define DRIVER_NAME "ENS1371"
+#define CHIP_NAME "ES1371"
 #endif
 
 
@@ -1258,6 +1260,14 @@ static struct snd_pcm_ops snd_ensoniq_capture_ops = {
        .pointer =      snd_ensoniq_capture_pointer,
 };
 
+static const struct snd_pcm_chmap_elem surround_map[] = {
+       { .channels = 1,
+         .map = { SNDRV_CHMAP_MONO } },
+       { .channels = 2,
+         .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+       { }
+};
+
 static int __devinit snd_ensoniq_pcm(struct ensoniq * ensoniq, int device,
                                     struct snd_pcm ** rpcm)
 {
@@ -1266,11 +1276,7 @@ static int __devinit snd_ensoniq_pcm(struct ensoniq * ensoniq, int device,
 
        if (rpcm)
                *rpcm = NULL;
-#ifdef CHIP1370
-       err = snd_pcm_new(ensoniq->card, "ES1370/1", device, 1, 1, &pcm);
-#else
-       err = snd_pcm_new(ensoniq->card, "ES1371/1", device, 1, 1, &pcm);
-#endif
+       err = snd_pcm_new(ensoniq->card, CHIP_NAME "/1", device, 1, 1, &pcm);
        if (err < 0)
                return err;
 
@@ -1283,16 +1289,22 @@ static int __devinit snd_ensoniq_pcm(struct ensoniq * ensoniq, int device,
 
        pcm->private_data = ensoniq;
        pcm->info_flags = 0;
-#ifdef CHIP1370
-       strcpy(pcm->name, "ES1370 DAC2/ADC");
-#else
-       strcpy(pcm->name, "ES1371 DAC2/ADC");
-#endif
+       strcpy(pcm->name, CHIP_NAME " DAC2/ADC");
        ensoniq->pcm1 = pcm;
 
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                              snd_dma_pci_data(ensoniq->pci), 64*1024, 128*1024);
 
+#ifdef CHIP1370
+       err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                                    surround_map, 2, 0, NULL);
+#else
+       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;
@@ -1306,11 +1318,7 @@ static int __devinit snd_ensoniq_pcm2(struct ensoniq * ensoniq, int device,
 
        if (rpcm)
                *rpcm = NULL;
-#ifdef CHIP1370
-       err = snd_pcm_new(ensoniq->card, "ES1370/2", device, 1, 0, &pcm);
-#else
-       err = snd_pcm_new(ensoniq->card, "ES1371/2", device, 1, 0, &pcm);
-#endif
+       err = snd_pcm_new(ensoniq->card, CHIP_NAME "/2", device, 1, 0, &pcm);
        if (err < 0)
                return err;
 
@@ -1321,16 +1329,22 @@ static int __devinit snd_ensoniq_pcm2(struct ensoniq * ensoniq, int device,
 #endif
        pcm->private_data = ensoniq;
        pcm->info_flags = 0;
-#ifdef CHIP1370
-       strcpy(pcm->name, "ES1370 DAC1");
-#else
-       strcpy(pcm->name, "ES1371 DAC1");
-#endif
+       strcpy(pcm->name, CHIP_NAME " DAC1");
        ensoniq->pcm2 = pcm;
 
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
                                              snd_dma_pci_data(ensoniq->pci), 64*1024, 128*1024);
 
+#ifdef CHIP1370
+       err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                                    snd_pcm_std_chmaps, 2, 0, NULL);
+#else
+       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;
@@ -1885,11 +1899,7 @@ static void snd_ensoniq_proc_read(struct snd_info_entry *entry,
 {
        struct ensoniq *ensoniq = entry->private_data;
 
-#ifdef CHIP1370
-       snd_iprintf(buffer, "Ensoniq AudioPCI ES1370\n\n");
-#else
-       snd_iprintf(buffer, "Ensoniq AudioPCI ES1371\n\n");
-#endif
+       snd_iprintf(buffer, "Ensoniq AudioPCI " CHIP_NAME "\n\n");
        snd_iprintf(buffer, "Joystick enable  : %s\n",
                    ensoniq->ctrl & ES_JYSTK_EN ? "on" : "off");
 #ifdef CHIP1370
@@ -2032,7 +2042,7 @@ static void snd_ensoniq_chip_init(struct ensoniq *ensoniq)
        synchronize_irq(ensoniq->irq);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_ensoniq_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -2094,7 +2104,7 @@ static SIMPLE_DEV_PM_OPS(snd_ensoniq_pm, snd_ensoniq_suspend, snd_ensoniq_resume
 #define SND_ENSONIQ_PM_OPS     &snd_ensoniq_pm
 #else
 #define SND_ENSONIQ_PM_OPS     NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int __devinit snd_ensoniq_create(struct snd_card *card,
                                     struct pci_dev *pci,
@@ -2361,11 +2371,7 @@ static int __devinit snd_ensoniq_midi(struct ensoniq * ensoniq, int device,
                *rrawmidi = NULL;
        if ((err = snd_rawmidi_new(ensoniq->card, "ES1370/1", device, 1, 1, &rmidi)) < 0)
                return err;
-#ifdef CHIP1370
-       strcpy(rmidi->name, "ES1370");
-#else
-       strcpy(rmidi->name, "ES1371");
-#endif
+       strcpy(rmidi->name, CHIP_NAME);
        snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_ensoniq_midi_output);
        snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_ensoniq_midi_input);
        rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT |
index dbb81807bc1ae5cb6cba33b699dce20f97075e35..394c5d413530cd66fb5b1c1718d55f6b523ece13 100644 (file)
@@ -236,7 +236,7 @@ struct es1938 {
 #ifdef SUPPORT_JOYSTICK
        struct gameport *gameport;
 #endif
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        unsigned char saved_regs[SAVED_REG_SIZE];
 #endif
 };
@@ -1456,7 +1456,7 @@ static void snd_es1938_chip_init(struct es1938 *chip)
        outb(0, SLDM_REG(chip, DMACLEAR));
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * PM support
  */
@@ -1536,7 +1536,7 @@ static SIMPLE_DEV_PM_OPS(es1938_pm, es1938_suspend, es1938_resume);
 #define ES1938_PM_OPS  &es1938_pm
 #else
 #define ES1938_PM_OPS  NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef SUPPORT_JOYSTICK
 static int __devinit snd_es1938_create_gameport(struct es1938 *chip)
index fb4c90b99c003c4c673c00bc67c5442f058541d7..5d0e568fdea1b39e6a4c94f9c4fa360edffa5ede 100644 (file)
@@ -491,7 +491,7 @@ struct esschan {
        /* linked list */
        struct list_head list;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        u16 wc_map[4];
 #endif
 };
@@ -544,7 +544,7 @@ struct es1968 {
        struct list_head substream_list;
        spinlock_t substream_lock;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        u16 apu_map[NR_APUS][NR_APU_REGS];
 #endif
 
@@ -706,7 +706,7 @@ static void __apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 dat
 {
        if (snd_BUG_ON(channel >= NR_APUS))
                return;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        chip->apu_map[channel][reg] = data;
 #endif
        reg |= (channel << 4);
@@ -993,7 +993,7 @@ static void snd_es1968_program_wavecache(struct es1968 *chip, struct esschan *es
        /* set the wavecache control reg */
        wave_set_register(chip, es->apu[channel] << 3, tmpval);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        es->wc_map[channel] = tmpval;
 #endif
 }
@@ -2377,7 +2377,7 @@ static void snd_es1968_start_irq(struct es1968 *chip)
        outw(w, chip->io_port + ESM_PORT_HOST_IRQ);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * PM support
  */
@@ -2461,7 +2461,7 @@ static SIMPLE_DEV_PM_OPS(es1968_pm, es1968_suspend, es1968_resume);
 #define ES1968_PM_OPS  &es1968_pm
 #else
 #define ES1968_PM_OPS  NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef SUPPORT_JOYSTICK
 #define JOYSTICK_ADDR  0x200
index 522c8706f24446e5cb70f2522284d37d7ef14213..cc2e91d1553822699251c15baf950e406243df8d 100644 (file)
@@ -205,7 +205,7 @@ struct fm801 {
        struct snd_tea575x tea;
 #endif
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        u16 saved_regs[0x20];
 #endif
 };
@@ -711,6 +711,13 @@ static int __devinit snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pc
                                              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,
+                                    snd_pcm_alt_chmaps,
+                                    chip->multichannel ? 6 : 2, 0,
+                                    NULL);
+       if (err < 0)
+               return err;
+
        if (rpcm)
                *rpcm = pcm;
        return 0;
@@ -1361,7 +1368,7 @@ static void __devexit snd_card_fm801_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static unsigned char saved_regs[] = {
        FM801_PCM_VOL, FM801_I2S_VOL, FM801_FM_VOL, FM801_REC_SRC,
        FM801_PLY_CTRL, FM801_PLY_COUNT, FM801_PLY_BUF1, FM801_PLY_BUF2,
@@ -1421,7 +1428,7 @@ static SIMPLE_DEV_PM_OPS(snd_fm801_pm, snd_fm801_suspend, snd_fm801_resume);
 #define SND_FM801_PM_OPS       &snd_fm801_pm
 #else
 #define SND_FM801_PM_OPS       NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver fm801_driver = {
        .name = KBUILD_MODNAME,
index 194d625c1f83b31cf231783474c9e4f77769458b..7105c3de1bca98ff5a975d15d2ba35fc19876d98 100644 (file)
@@ -228,17 +228,9 @@ config SND_HDA_GENERIC
          Say Y here to enable the generic HD-audio codec parser
          in snd-hda-intel driver.
 
-config SND_HDA_POWER_SAVE
-       bool "Aggressive power-saving on HD-audio"
-       depends on PM
-       help
-         Say Y here to enable more aggressive power-saving mode on
-         HD-audio driver.  The power-saving timeout can be configured
-         via power_save option or over sysfs on-the-fly.
-
 config SND_HDA_POWER_SAVE_DEFAULT
        int "Default time-out for HD-audio power-save mode"
-       depends on SND_HDA_POWER_SAVE
+       depends on PM
        default 0
        help
          The default time-out value in seconds for HD-audio automatic
index 4f7d2dfcef7b16357ead4185b7b62e3463d5f1a5..4ec6dc88b7f802a27adcc46ab580630e5c37fda8 100644 (file)
@@ -141,7 +141,6 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
        memset(sequences_hp, 0, sizeof(sequences_hp));
        assoc_line_out = 0;
 
-       codec->ignore_misc_bit = true;
        end_nid = codec->start_nid + codec->num_nodes;
        for (nid = codec->start_nid; nid < end_nid; nid++) {
                unsigned int wid_caps = get_wcaps(codec, nid);
@@ -157,9 +156,6 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
                        continue;
 
                def_conf = snd_hda_codec_get_pincfg(codec, nid);
-               if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
-                     AC_DEFCFG_MISC_NO_PRESENCE))
-                       codec->ignore_misc_bit = false;
                conn = get_defcfg_connect(def_conf);
                if (conn == AC_JACK_PORT_NONE)
                        continue;
@@ -502,6 +498,38 @@ static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins,
        return channel_sfx[i];
 }
 
+static const char *check_output_pfx(struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
+       int attr = snd_hda_get_input_pin_attr(def_conf);
+
+       /* check the location */
+       switch (attr) {
+       case INPUT_PIN_ATTR_DOCK:
+               return "Dock ";
+       case INPUT_PIN_ATTR_FRONT:
+               return "Front ";
+       }
+       return "";
+}
+
+static int get_hp_label_index(struct hda_codec *codec, hda_nid_t nid,
+                             const hda_nid_t *pins, int num_pins)
+{
+       int i, j, idx = 0;
+
+       const char *pfx = check_output_pfx(codec, nid);
+
+       i = find_idx_in_nid_list(nid, pins, num_pins);
+       if (i < 0)
+               return -1;
+       for (j = 0; j < i; j++)
+               if (pfx == check_output_pfx(codec, pins[j]))
+                       idx++;
+
+       return idx;
+}
+
 static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
                               const struct auto_pin_cfg *cfg,
                               const char *name, char *label, int maxlen,
@@ -509,20 +537,13 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
 {
        unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
        int attr = snd_hda_get_input_pin_attr(def_conf);
-       const char *pfx = "", *sfx = "";
+       const char *pfx, *sfx = "";
 
        /* handle as a speaker if it's a fixed line-out */
        if (!strcmp(name, "Line Out") && attr == INPUT_PIN_ATTR_INT)
                name = "Speaker";
-       /* check the location */
-       switch (attr) {
-       case INPUT_PIN_ATTR_DOCK:
-               pfx = "Dock ";
-               break;
-       case INPUT_PIN_ATTR_FRONT:
-               pfx = "Front ";
-               break;
-       }
+       pfx = check_output_pfx(codec, nid);
+
        if (cfg) {
                /* try to give a unique suffix if needed */
                sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs,
@@ -532,8 +553,8 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
                                               indexp);
                if (!sfx) {
                        /* don't add channel suffix for Headphone controls */
-                       int idx = find_idx_in_nid_list(nid, cfg->hp_pins,
-                                                      cfg->hp_outs);
+                       int idx = get_hp_label_index(codec, nid, cfg->hp_pins,
+                                                    cfg->hp_outs);
                        if (idx >= 0)
                                *indexp = idx;
                        sfx = "";
@@ -739,7 +760,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
                for (q = quirk; q->subvendor; q++) {
                        unsigned int vendorid =
                                q->subdevice | (q->subvendor << 16);
-                       if (vendorid == codec->subsystem_id) {
+                       unsigned int mask = 0xffff0000 | q->subdevice_mask;
+                       if ((codec->subsystem_id & mask) == (vendorid & mask)) {
                                id = q->value;
 #ifdef CONFIG_SND_DEBUG_VERBOSE
                                name = q->name;
index 1c65cc5e3a31101d098d6cdb48a2772d1adc38f9..c0ab72cbeed1288da505468e27e42b3dca984b3f 100644 (file)
@@ -94,13 +94,19 @@ int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset)
 }
 EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset);
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static void hda_power_work(struct work_struct *work);
 static void hda_keep_power_on(struct hda_codec *codec);
 #define hda_codec_is_power_on(codec)   ((codec)->power_on)
+static inline void hda_call_pm_notify(struct hda_bus *bus, bool power_up)
+{
+       if (bus->ops.pm_notify)
+               bus->ops.pm_notify(bus, power_up);
+}
 #else
 static inline void hda_keep_power_on(struct hda_codec *codec) {}
 #define hda_codec_is_power_on(codec)   1
+#define hda_call_pm_notify(bus, state) {}
 #endif
 
 /**
@@ -808,7 +814,7 @@ find_codec_preset(struct hda_codec *codec)
 {
        struct hda_codec_preset_list *tbl;
        const struct hda_codec_preset *preset;
-       int mod_requested = 0;
+       unsigned int mod_requested = 0;
 
        if (is_generic_config(codec))
                return NULL; /* use the generic parser */
@@ -1186,7 +1192,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
                return;
        snd_hda_jack_tbl_clear(codec);
        restore_init_pincfgs(codec);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        cancel_delayed_work(&codec->power_work);
        flush_workqueue(codec->bus->workq);
 #endif
@@ -1199,6 +1205,10 @@ static void snd_hda_codec_free(struct hda_codec *codec)
        codec->bus->caddr_tbl[codec->addr] = NULL;
        if (codec->patch_ops.free)
                codec->patch_ops.free(codec);
+#ifdef CONFIG_PM
+       if (!codec->pm_down_notified) /* cancel leftover refcounts */
+               hda_call_pm_notify(codec->bus, false);
+#endif
        module_put(codec->owner);
        free_hda_cache(&codec->amp_cache);
        free_hda_cache(&codec->cmd_cache);
@@ -1212,7 +1222,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
 static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec,
                                hda_nid_t fg, unsigned int power_state);
 
-static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
+static unsigned int hda_set_power_state(struct hda_codec *codec,
                                unsigned int power_state);
 
 /**
@@ -1229,6 +1239,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
 {
        struct hda_codec *codec;
        char component[31];
+       hda_nid_t fg;
        int err;
 
        if (snd_BUG_ON(!bus))
@@ -1263,7 +1274,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
        snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64);
        snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16);
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        spin_lock_init(&codec->power_lock);
        INIT_DELAYED_WORK(&codec->power_work, hda_power_work);
        /* snd_hda_codec_new() marks the codec as power-up, and leave it as is.
@@ -1271,6 +1282,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
         * phase.
         */
        hda_keep_power_on(codec);
+       hda_call_pm_notify(bus, true);
 #endif
 
        if (codec->bus->modelname) {
@@ -1304,7 +1316,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
                goto error;
        }
 
-       err = read_widget_caps(codec, codec->afg ? codec->afg : codec->mfg);
+       fg = codec->afg ? codec->afg : codec->mfg;
+       err = read_widget_caps(codec, fg);
        if (err < 0) {
                snd_printk(KERN_ERR "hda_codec: cannot malloc\n");
                goto error;
@@ -1314,20 +1327,22 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
                goto error;
 
        if (!codec->subsystem_id) {
-               hda_nid_t nid = codec->afg ? codec->afg : codec->mfg;
                codec->subsystem_id =
-                       snd_hda_codec_read(codec, nid, 0,
+                       snd_hda_codec_read(codec, fg, 0,
                                           AC_VERB_GET_SUBSYSTEM_ID, 0);
        }
 
-       codec->epss = snd_hda_codec_get_supported_ps(codec,
-                                       codec->afg ? codec->afg : codec->mfg,
+#ifdef CONFIG_PM
+       codec->d3_stop_clk = snd_hda_codec_get_supported_ps(codec, fg,
+                                       AC_PWRST_CLKSTOP);
+       if (!codec->d3_stop_clk)
+               bus->power_keep_link_on = 1;
+#endif
+       codec->epss = snd_hda_codec_get_supported_ps(codec, fg,
                                        AC_PWRST_EPSS);
 
        /* power-up all before initialization */
-       hda_set_power_state(codec,
-                           codec->afg ? codec->afg : codec->mfg,
-                           AC_PWRST_D0);
+       hda_set_power_state(codec, AC_PWRST_D0);
 
        snd_hda_codec_proc_new(codec);
 
@@ -2335,7 +2350,7 @@ int snd_hda_codec_reset(struct hda_codec *codec)
 
        /* OK, let it free */
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        cancel_delayed_work_sync(&codec->power_work);
        codec->power_on = 0;
        codec->power_transition = 0;
@@ -3500,20 +3515,6 @@ void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
                snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
                                    power_state);
        }
-
-       if (power_state == AC_PWRST_D0) {
-               unsigned long end_time;
-               int state;
-               /* wait until the codec reachs to D0 */
-               end_time = jiffies + msecs_to_jiffies(500);
-               do {
-                       state = snd_hda_codec_read(codec, fg, 0,
-                                                  AC_VERB_GET_POWER_STATE, 0);
-                       if (state == power_state)
-                               break;
-                       msleep(1);
-               } while (time_after_eq(end_time, jiffies));
-       }
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all);
 
@@ -3534,18 +3535,40 @@ static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, hda_nid_t fg
 }
 
 /*
- * set power state of the codec
+ * wait until the state is reached, returns the current state
  */
-static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
-                               unsigned int power_state)
+static unsigned int hda_sync_power_state(struct hda_codec *codec,
+                                        hda_nid_t fg,
+                                        unsigned int power_state)
 {
-       int count;
-       unsigned int state;
+       unsigned long end_time = jiffies + msecs_to_jiffies(500);
+       unsigned int state, actual_state;
 
-       if (codec->patch_ops.set_power_state) {
-               codec->patch_ops.set_power_state(codec, fg, power_state);
-               return;
+       for (;;) {
+               state = snd_hda_codec_read(codec, fg, 0,
+                                          AC_VERB_GET_POWER_STATE, 0);
+               if (state & AC_PWRST_ERROR)
+                       break;
+               actual_state = (state >> 4) & 0x0f;
+               if (actual_state == power_state)
+                       break;
+               if (time_after_eq(jiffies, end_time))
+                       break;
+               /* wait until the codec reachs to the target state */
+               msleep(1);
        }
+       return state;
+}
+
+/*
+ * set power state of the codec, and return the power state
+ */
+static unsigned int hda_set_power_state(struct hda_codec *codec,
+                                       unsigned int power_state)
+{
+       hda_nid_t fg = codec->afg ? codec->afg : codec->mfg;
+       int count;
+       unsigned int state;
 
        /* this delay seems necessary to avoid click noise at power-down */
        if (power_state == AC_PWRST_D3) {
@@ -3555,14 +3578,22 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
 
        /* repeat power states setting at most 10 times*/
        for (count = 0; count < 10; count++) {
-               snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
-                                   power_state);
-               snd_hda_codec_set_power_to_all(codec, fg, power_state, true);
-               state = snd_hda_codec_read(codec, fg, 0,
-                                          AC_VERB_GET_POWER_STATE, 0);
+               if (codec->patch_ops.set_power_state)
+                       codec->patch_ops.set_power_state(codec, fg,
+                                                        power_state);
+               else {
+                       snd_hda_codec_read(codec, fg, 0,
+                                          AC_VERB_SET_POWER_STATE,
+                                          power_state);
+                       snd_hda_codec_set_power_to_all(codec, fg, power_state,
+                                                      true);
+               }
+               state = hda_sync_power_state(codec, fg, power_state);
                if (!(state & AC_PWRST_ERROR))
                        break;
        }
+
+       return state;
 }
 
 #ifdef CONFIG_SND_HDA_HWDEP
@@ -3579,17 +3610,19 @@ static inline void hda_exec_init_verbs(struct hda_codec *codec) {}
 #ifdef CONFIG_PM
 /*
  * call suspend and power-down; used both from PM and power-save
+ * this function returns the power state in the end
  */
-static void hda_call_codec_suspend(struct hda_codec *codec)
+static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq)
 {
+       unsigned int state;
+
        if (codec->patch_ops.suspend)
                codec->patch_ops.suspend(codec);
        hda_cleanup_all_streams(codec);
-       hda_set_power_state(codec,
-                           codec->afg ? codec->afg : codec->mfg,
-                           AC_PWRST_D3);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       cancel_delayed_work(&codec->power_work);
+       state = hda_set_power_state(codec, AC_PWRST_D3);
+       /* Cancel delayed work if we aren't currently running from it. */
+       if (!in_wq)
+               cancel_delayed_work_sync(&codec->power_work);
        spin_lock(&codec->power_lock);
        snd_hda_update_power_acct(codec);
        trace_hda_power_down(codec);
@@ -3597,7 +3630,7 @@ static void hda_call_codec_suspend(struct hda_codec *codec)
        codec->power_transition = 0;
        codec->power_jiffies = jiffies;
        spin_unlock(&codec->power_lock);
-#endif
+       return state;
 }
 
 /*
@@ -3609,9 +3642,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
         * in the resume / power-save sequence
         */
        hda_keep_power_on(codec);
-       hda_set_power_state(codec,
-                           codec->afg ? codec->afg : codec->mfg,
-                           AC_PWRST_D0);
+       hda_set_power_state(codec, AC_PWRST_D0);
        restore_pincfgs(codec); /* restore all current pin configs */
        restore_shutup_pins(codec);
        hda_exec_init_verbs(codec);
@@ -3624,6 +3655,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
                snd_hda_codec_resume_amp(codec);
                snd_hda_codec_resume_cache(codec);
        }
+       snd_hda_jack_report_sync(codec);
        snd_hda_power_down(codec); /* flag down before returning */
 }
 #endif /* CONFIG_PM */
@@ -3658,6 +3690,36 @@ int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus)
 }
 EXPORT_SYMBOL_HDA(snd_hda_build_controls);
 
+/*
+ * add standard channel maps if not specified
+ */
+static int add_std_chmaps(struct hda_codec *codec)
+{
+       int i, str, err;
+
+       for (i = 0; i < codec->num_pcms; i++) {
+               for (str = 0; str < 2; str++) {
+                       struct snd_pcm *pcm = codec->pcm_info[i].pcm;
+                       struct hda_pcm_stream *hinfo =
+                               &codec->pcm_info[i].stream[str];
+                       struct snd_pcm_chmap *chmap;
+
+                       if (codec->pcm_info[i].own_chmap)
+                               continue;
+                       if (!pcm || !hinfo->substreams)
+                               continue;
+                       err = snd_pcm_add_chmap_ctls(pcm, str,
+                                                    snd_pcm_std_chmaps,
+                                                    hinfo->channels_max,
+                                                    0, &chmap);
+                       if (err < 0)
+                               return err;
+                       chmap->channel_mask = SND_PCM_CHMAP_MASK_2468;
+               }
+       }
+       return 0;
+}
+
 int snd_hda_codec_build_controls(struct hda_codec *codec)
 {
        int err = 0;
@@ -3669,6 +3731,13 @@ int snd_hda_codec_build_controls(struct hda_codec *codec)
                err = codec->patch_ops.build_controls(codec);
        if (err < 0)
                return err;
+
+       /* we create chmaps here instead of build_pcms */
+       err = add_std_chmaps(codec);
+       if (err < 0)
+               return err;
+
+       snd_hda_jack_report_sync(codec); /* call at the last init point */
        return 0;
 }
 
@@ -4211,7 +4280,7 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec)
  *
  * This function returns 0 if successful, or a negative error code.
  */
-int __devinit snd_hda_build_pcms(struct hda_bus *bus)
+int snd_hda_build_pcms(struct hda_bus *bus)
 {
        struct hda_codec *codec;
 
@@ -4391,12 +4460,13 @@ int snd_hda_add_new_ctls(struct hda_codec *codec,
 }
 EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls);
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static void hda_power_work(struct work_struct *work)
 {
        struct hda_codec *codec =
                container_of(work, struct hda_codec, power_work.work);
        struct hda_bus *bus = codec->bus;
+       unsigned int state;
 
        spin_lock(&codec->power_lock);
        if (codec->power_transition > 0) { /* during power-up sequence? */
@@ -4410,9 +4480,12 @@ static void hda_power_work(struct work_struct *work)
        }
        spin_unlock(&codec->power_lock);
 
-       hda_call_codec_suspend(codec);
-       if (bus->ops.pm_notify)
-               bus->ops.pm_notify(bus);
+       state = hda_call_codec_suspend(codec, true);
+       codec->pm_down_notified = 0;
+       if (!bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) {
+               codec->pm_down_notified = 1;
+               hda_call_pm_notify(bus, false);
+       }
 }
 
 static void hda_keep_power_on(struct hda_codec *codec)
@@ -4438,19 +4511,16 @@ void snd_hda_update_power_acct(struct hda_codec *codec)
 /* Transition to powered up, if wait_power_down then wait for a pending
  * transition to D3 to complete. A pending D3 transition is indicated
  * with power_transition == -1. */
+/* call this with codec->power_lock held! */
 static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)
 {
        struct hda_bus *bus = codec->bus;
 
-       spin_lock(&codec->power_lock);
-       codec->power_count++;
        /* Return if power_on or transitioning to power_on, unless currently
         * powering down. */
        if ((codec->power_on || codec->power_transition > 0) &&
-           !(wait_power_down && codec->power_transition < 0)) {
-               spin_unlock(&codec->power_lock);
+           !(wait_power_down && codec->power_transition < 0))
                return;
-       }
        spin_unlock(&codec->power_lock);
 
        cancel_delayed_work_sync(&codec->power_work);
@@ -4462,9 +4532,9 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)
        if (codec->power_on) {
                if (codec->power_transition < 0)
                        codec->power_transition = 0;
-               spin_unlock(&codec->power_lock);
                return;
        }
+
        trace_hda_power_up(codec);
        snd_hda_update_power_acct(codec);
        codec->power_on = 1;
@@ -4472,71 +4542,54 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)
        codec->power_transition = 1; /* avoid reentrance */
        spin_unlock(&codec->power_lock);
 
-       if (bus->ops.pm_notify)
-               bus->ops.pm_notify(bus);
+       if (codec->pm_down_notified) {
+               codec->pm_down_notified = 0;
+               hda_call_pm_notify(bus, true);
+       }
+
        hda_call_codec_resume(codec);
 
        spin_lock(&codec->power_lock);
        codec->power_transition = 0;
-       spin_unlock(&codec->power_lock);
-}
-
-/**
- * snd_hda_power_up - Power-up the codec
- * @codec: HD-audio codec
- *
- * Increment the power-up counter and power up the hardware really when
- * not turned on yet.
- */
-void snd_hda_power_up(struct hda_codec *codec)
-{
-       __snd_hda_power_up(codec, false);
 }
-EXPORT_SYMBOL_HDA(snd_hda_power_up);
-
-/**
- * snd_hda_power_up_d3wait - Power-up the codec after waiting for any pending
- *   D3 transition to complete.  This differs from snd_hda_power_up() when
- *   power_transition == -1.  snd_hda_power_up sees this case as a nop,
- *   snd_hda_power_up_d3wait waits for the D3 transition to complete then powers
- *   back up.
- * @codec: HD-audio codec
- *
- * Cancel any power down operation hapenning on the work queue, then power up.
- */
-void snd_hda_power_up_d3wait(struct hda_codec *codec)
-{
-       /* This will cancel and wait for pending power_work to complete. */
-       __snd_hda_power_up(codec, true);
-}
-EXPORT_SYMBOL_HDA(snd_hda_power_up_d3wait);
 
 #define power_save(codec)      \
        ((codec)->bus->power_save ? *(codec)->bus->power_save : 0)
 
-/**
- * snd_hda_power_down - Power-down the codec
- * @codec: HD-audio codec
- *
- * Decrement the power-up counter and schedules the power-off work if
- * the counter rearches to zero.
- */
-void snd_hda_power_down(struct hda_codec *codec)
+/* Transition to powered down */
+static void __snd_hda_power_down(struct hda_codec *codec)
 {
-       spin_lock(&codec->power_lock);
-       --codec->power_count;
-       if (!codec->power_on || codec->power_count || codec->power_transition) {
-               spin_unlock(&codec->power_lock);
+       if (!codec->power_on || codec->power_count || codec->power_transition)
                return;
-       }
+
        if (power_save(codec)) {
                codec->power_transition = -1; /* avoid reentrance */
                queue_delayed_work(codec->bus->workq, &codec->power_work,
                                msecs_to_jiffies(power_save(codec) * 1000));
        }
+}
+
+/**
+ * snd_hda_power_save - Power-up/down/sync the codec
+ * @codec: HD-audio codec
+ * @delta: the counter delta to change
+ *
+ * Change the power-up counter via @delta, and power up or down the hardware
+ * appropriately.  For the power-down, queue to the delayed action.
+ * Passing zero to @delta means to synchronize the power state.
+ */
+void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait)
+{
+       spin_lock(&codec->power_lock);
+       codec->power_count += delta;
+       trace_hda_power_count(codec);
+       if (delta > 0)
+               __snd_hda_power_up(codec, d3wait);
+       else
+               __snd_hda_power_down(codec);
        spin_unlock(&codec->power_lock);
 }
-EXPORT_SYMBOL_HDA(snd_hda_power_down);
+EXPORT_SYMBOL_HDA(snd_hda_power_save);
 
 /**
  * snd_hda_check_amp_list_power - Check the amp list and update the power
@@ -5076,7 +5129,7 @@ int snd_hda_suspend(struct hda_bus *bus)
 
        list_for_each_entry(codec, &bus->codec_list, list) {
                if (hda_codec_is_power_on(codec))
-                       hda_call_codec_suspend(codec);
+                       hda_call_codec_suspend(codec, false);
        }
        return 0;
 }
@@ -5087,9 +5140,6 @@ EXPORT_SYMBOL_HDA(snd_hda_suspend);
  * @bus: the HDA bus
  *
  * Returns 0 if successful.
- *
- * This function is defined only when POWER_SAVE isn't set.
- * In the power-save mode, the codec is resumed dynamically.
  */
 int snd_hda_resume(struct hda_bus *bus)
 {
index e5a7e19a80712c0ece3ad1b41617e40512206ad3..507fe8a917b69b09993193ef460f4fbc3f3af31a 100644 (file)
@@ -386,6 +386,10 @@ enum {
 /* DIGITAL2 bits */
 #define AC_DIG2_CC                     (0x7f<<0)
 
+/* DIGITAL3 bits */
+#define AC_DIG3_ICT                    (0xf<<0)
+#define AC_DIG3_KAE                    (1<<7)
+
 /* Pin widget control - 8bit */
 #define AC_PINCTL_EPT                  (0x3<<0)
 #define AC_PINCTL_EPT_NATIVE           0
@@ -610,9 +614,9 @@ struct hda_bus_ops {
                          struct hda_pcm *pcm);
        /* reset bus for retry verb */
        void (*bus_reset)(struct hda_bus *bus);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        /* notify power-up/down from codec to controller */
-       void (*pm_notify)(struct hda_bus *bus);
+       void (*pm_notify)(struct hda_bus *bus, bool power_up);
 #endif
 };
 
@@ -708,8 +712,6 @@ struct hda_codec_ops {
 #ifdef CONFIG_PM
        int (*suspend)(struct hda_codec *codec);
        int (*resume)(struct hda_codec *codec);
-#endif
-#ifdef CONFIG_SND_HDA_POWER_SAVE
        int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid);
 #endif
        void (*reboot_notify)(struct hda_codec *codec);
@@ -774,6 +776,7 @@ struct hda_pcm {
        unsigned int pcm_type;  /* HDA_PCM_TYPE_XXX */
        int device;             /* device number to assign */
        struct snd_pcm *pcm;    /* assigned PCM instance */
+       bool own_chmap;         /* codec driver provides own channel maps */
 };
 
 /* codec information */
@@ -859,12 +862,13 @@ struct hda_codec {
        unsigned int no_sticky_stream:1; /* no sticky-PCM stream assignment */
        unsigned int pins_shutup:1;     /* pins are shut up */
        unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */
-       unsigned int ignore_misc_bit:1; /* ignore MISC_NO_PRESENCE bit */
        unsigned int no_jack_detect:1;  /* Machine has no jack-detection */
        unsigned int pcm_format_first:1; /* PCM format must be set first */
        unsigned int epss:1;            /* supporting EPSS? */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        unsigned int power_on :1;       /* current (global) power-state */
+       unsigned int d3_stop_clk:1;     /* support D3 operation without BCLK */
+       unsigned int pm_down_notified:1; /* PM notified to controller */
        int power_transition;   /* power-state in transition */
        int power_count;        /* current (global) power refcount */
        struct delayed_work power_work; /* delayed task for powerdown */
@@ -1042,7 +1046,7 @@ int snd_hda_resume(struct hda_bus *bus);
 static inline
 int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 {
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        if (codec->patch_ops.check_power_status)
                return codec->patch_ops.check_power_status(codec, nid);
 #endif
@@ -1059,22 +1063,70 @@ const char *snd_hda_get_jack_location(u32 cfg);
 /*
  * power saving
  */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-void snd_hda_power_up(struct hda_codec *codec);
-void snd_hda_power_up_d3wait(struct hda_codec *codec);
-void snd_hda_power_down(struct hda_codec *codec);
+#ifdef CONFIG_PM
+void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait);
 void snd_hda_update_power_acct(struct hda_codec *codec);
 #else
-static inline void snd_hda_power_up(struct hda_codec *codec) {}
-static inline void snd_hda_power_up_d3wait(struct hda_codec *codec) {}
-static inline void snd_hda_power_down(struct hda_codec *codec) {}
+static inline void snd_hda_power_save(struct hda_codec *codec, int delta,
+                                     bool d3wait) {}
 #endif
 
+/**
+ * snd_hda_power_up - Power-up the codec
+ * @codec: HD-audio codec
+ *
+ * Increment the power-up counter and power up the hardware really when
+ * not turned on yet.
+ */
+static inline void snd_hda_power_up(struct hda_codec *codec)
+{
+       snd_hda_power_save(codec, 1, false);
+}
+
+/**
+ * snd_hda_power_up_d3wait - Power-up the codec after waiting for any pending
+ *   D3 transition to complete.  This differs from snd_hda_power_up() when
+ *   power_transition == -1.  snd_hda_power_up sees this case as a nop,
+ *   snd_hda_power_up_d3wait waits for the D3 transition to complete then powers
+ *   back up.
+ * @codec: HD-audio codec
+ *
+ * Cancel any power down operation hapenning on the work queue, then power up.
+ */
+static inline void snd_hda_power_up_d3wait(struct hda_codec *codec)
+{
+       snd_hda_power_save(codec, 1, true);
+}
+
+/**
+ * snd_hda_power_down - Power-down the codec
+ * @codec: HD-audio codec
+ *
+ * Decrement the power-up counter and schedules the power-off work if
+ * the counter rearches to zero.
+ */
+static inline void snd_hda_power_down(struct hda_codec *codec)
+{
+       snd_hda_power_save(codec, -1, false);
+}
+
+/**
+ * snd_hda_power_sync - Synchronize the power-save status
+ * @codec: HD-audio codec
+ *
+ * Synchronize the actual power state with the power account;
+ * called when power_save parameter is changed
+ */
+static inline void snd_hda_power_sync(struct hda_codec *codec)
+{
+       snd_hda_power_save(codec, 0, false);
+}
+
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
 /*
  * patch firmware
  */
-int snd_hda_load_patch(struct hda_bus *bus, const char *patch);
+int snd_hda_load_patch(struct hda_bus *bus, size_t size, const void *buf);
 #endif
 
 /*
index 431bf868711ec1fc1749c3910d940822200b1da9..b81d3d0b952d1355cc324119c87c98a14bb3cb0e 100644 (file)
@@ -70,7 +70,7 @@ struct hda_gspec {
 
        struct list_head nid_list;      /* list of widgets */
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 #define MAX_LOOPBACK_AMPS      7
        struct hda_loopback_check loopback;
        int num_loopbacks;
@@ -654,7 +654,7 @@ static int parse_input(struct hda_codec *codec)
        return 0;
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static void add_input_loopback(struct hda_codec *codec, hda_nid_t nid,
                               int dir, int idx)
 {
@@ -1028,7 +1028,7 @@ static int build_generic_pcms(struct hda_codec *codec)
        return 0;
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static int generic_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 {
        struct hda_gspec *spec = codec->spec;
@@ -1043,7 +1043,7 @@ static struct hda_codec_ops generic_patch_ops = {
        .build_controls = build_generic_controls,
        .build_pcms = build_generic_pcms,
        .free = snd_hda_generic_free,
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        .check_power_status = generic_check_power_status,
 #endif
 };
index 6b2efb8cb1f9c6bded4e7d318467f8825be75903..1af86d40eb2396b7dde509052beb8b0180bd0f8e 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/mutex.h>
 #include <linux/ctype.h>
 #include <linux/string.h>
-#include <linux/firmware.h>
 #include <linux/export.h>
 #include <sound/core.h>
 #include "hda_codec.h"
@@ -156,7 +155,7 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec)
        return 0;
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static ssize_t power_on_acct_show(struct device *dev,
                                  struct device_attribute *attr,
                                  char *buf)
@@ -192,7 +191,7 @@ int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec)
                                          hwdep->device, &power_attrs[i]);
        return 0;
 }
-#endif /* CONFIG_SND_HDA_POWER_SAVE */
+#endif /* CONFIG_PM */
 
 #ifdef CONFIG_SND_HDA_RECONFIG
 
@@ -747,18 +746,21 @@ static int parse_line_mode(char *buf, struct hda_bus *bus)
  *
  * the spaces at the beginning and the end of the line are stripped
  */
-static int get_line_from_fw(char *buf, int size, struct firmware *fw)
+static int get_line_from_fw(char *buf, int size, size_t *fw_size_p,
+                           const void **fw_data_p)
 {
        int len;
-       const char *p = fw->data;
-       while (isspace(*p) && fw->size) {
+       size_t fw_size = *fw_size_p;
+       const char *p = *fw_data_p;
+
+       while (isspace(*p) && fw_size) {
                p++;
-               fw->size--;
+               fw_size--;
        }
-       if (!fw->size)
+       if (!fw_size)
                return 0;
 
-       for (len = 0; len < fw->size; len++) {
+       for (len = 0; len < fw_size; len++) {
                if (!*p)
                        break;
                if (*p == '\n') {
@@ -770,8 +772,8 @@ static int get_line_from_fw(char *buf, int size, struct firmware *fw)
                        *buf++ = *p++;
        }
        *buf = 0;
-       fw->size -= len;
-       fw->data = p;
+       *fw_size_p = fw_size - len;
+       *fw_data_p = p;
        remove_trail_spaces(buf);
        return 1;
 }
@@ -779,29 +781,15 @@ static int get_line_from_fw(char *buf, int size, struct firmware *fw)
 /*
  * load a "patch" firmware file and parse it
  */
-int snd_hda_load_patch(struct hda_bus *bus, const char *patch)
+int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)
 {
-       int err;
-       const struct firmware *fw;
-       struct firmware tmp;
        char buf[128];
        struct hda_codec *codec;
        int line_mode;
-       struct device *dev = bus->card->dev;
-
-       if (snd_BUG_ON(!dev))
-               return -ENODEV;
-       err = request_firmware(&fw, patch, dev);
-       if (err < 0) {
-               printk(KERN_ERR "hda-codec: Cannot load the patch '%s'\n",
-                      patch);
-               return err;
-       }
 
-       tmp = *fw;
        line_mode = LINE_MODE_NONE;
        codec = NULL;
-       while (get_line_from_fw(buf, sizeof(buf) - 1, &tmp)) {
+       while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) {
                if (!*buf || *buf == '#' || *buf == '\n')
                        continue;
                if (*buf == '[')
@@ -810,7 +798,6 @@ int snd_hda_load_patch(struct hda_bus *bus, const char *patch)
                         (codec || !patch_items[line_mode].need_codec))
                        patch_items[line_mode].parser(buf, bus, &codec);
        }
-       release_firmware(fw);
        return 0;
 }
 EXPORT_SYMBOL_HDA(snd_hda_load_patch);
index c4763c52eaf64ced9e1d520f80fd8b245507dbd6..f09ff6c14041794bbd3d56e5d59a17410dddf037 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/mutex.h>
 #include <linux/reboot.h>
 #include <linux/io.h>
+#include <linux/pm_runtime.h>
 #ifdef CONFIG_X86
 /* for snoop control */
 #include <asm/pgtable.h>
@@ -55,6 +56,7 @@
 #include <sound/initval.h>
 #include <linux/vgaarb.h>
 #include <linux/vga_switcheroo.h>
+#include <linux/firmware.h>
 #include "hda_codec.h"
 
 
@@ -62,7 +64,7 @@ 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;
 static char *model[SNDRV_CARDS];
-static int position_fix[SNDRV_CARDS];
+static int position_fix[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
 static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
 static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
 static int probe_only[SNDRV_CARDS];
@@ -86,7 +88,7 @@ module_param_array(model, charp, NULL, 0444);
 MODULE_PARM_DESC(model, "Use the given board model.");
 module_param_array(position_fix, int, NULL, 0444);
 MODULE_PARM_DESC(position_fix, "DMA pointer read method."
-                "(0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO).");
+                "(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO).");
 module_param_array(bdl_pos_adj, int, NULL, 0644);
 MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
 module_param_array(probe_mask, int, NULL, 0444);
@@ -108,9 +110,16 @@ MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode "
                            "(0=off, 1=on) (default=1).");
 #endif
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
+static int param_set_xint(const char *val, const struct kernel_param *kp);
+static struct kernel_param_ops param_ops_xint = {
+       .set = param_set_xint,
+       .get = param_get_int,
+};
+#define param_check_xint param_check_int
+
 static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
-module_param(power_save, int, 0644);
+module_param(power_save, xint, 0644);
 MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
                 "(in second, 0 = disable).");
 
@@ -121,7 +130,7 @@ MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
 static bool power_save_controller = 1;
 module_param(power_save_controller, bool, 0644);
 MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
-#endif
+#endif /* CONFIG_PM */
 
 static int align_buffer_size = -1;
 module_param(align_buffer_size, bint, 0644);
@@ -406,6 +415,7 @@ struct azx_dev {
         */
        unsigned int insufficient :1;
        unsigned int wc_marked:1;
+       unsigned int no_period_wakeup:1;
 };
 
 /* CORB/RIRB */
@@ -471,6 +481,10 @@ struct azx {
        struct snd_dma_buffer rb;
        struct snd_dma_buffer posbuf;
 
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+       const struct firmware *fw;
+#endif
+
        /* flags */
        int position_fix[2]; /* for both playback/capture streams */
        int poll_count;
@@ -498,6 +512,9 @@ struct azx {
 
        /* reboot notifier (for mysterious hangup problem at power-down) */
        struct notifier_block reboot_notifier;
+
+       /* card list (for power_save trigger) */
+       struct list_head list;
 };
 
 /* driver types */
@@ -538,6 +555,7 @@ enum {
 #define AZX_DCAPS_ALIGN_BUFSIZE        (1 << 22)       /* buffer size alignment */
 #define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23)   /* BDLE in 4k boundary */
 #define AZX_DCAPS_POSFIX_COMBO  (1 << 24)      /* Use COMBO as default */
+#define AZX_DCAPS_COUNT_LPIB_DELAY  (1 << 25)  /* Take LPIB as delay */
 
 /* quirks for ATI SB / AMD Hudson */
 #define AZX_DCAPS_PRESET_ATI_SB \
@@ -560,13 +578,17 @@ enum {
  * VGA-switcher support
  */
 #ifdef SUPPORT_VGA_SWITCHEROO
+#define use_vga_switcheroo(chip)       ((chip)->use_vga_switcheroo)
+#else
+#define use_vga_switcheroo(chip)       0
+#endif
+
+#if defined(SUPPORT_VGA_SWITCHEROO) || defined(CONFIG_SND_HDA_PATCH_LOADER)
 #define DELAYED_INIT_MARK
 #define DELAYED_INITDATA_MARK
-#define use_vga_switcheroo(chip)       ((chip)->use_vga_switcheroo)
 #else
 #define DELAYED_INIT_MARK      __devinit
 #define DELAYED_INITDATA_MARK  __devinitdata
-#define use_vga_switcheroo(chip)       0
 #endif
 
 static char *driver_short_names[] DELAYED_INITDATA_MARK = {
@@ -1012,8 +1034,8 @@ static unsigned int azx_get_response(struct hda_bus *bus,
                return azx_rirb_get_response(bus, addr);
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-static void azx_power_notify(struct hda_bus *bus);
+#ifdef CONFIG_PM
+static void azx_power_notify(struct hda_bus *bus, bool power_up);
 #endif
 
 /* reset codec link */
@@ -1269,6 +1291,11 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
        u8 sd_status;
        int i, ok;
 
+#ifdef CONFIG_PM_RUNTIME
+       if (chip->pci->dev.power.runtime_status != RPM_ACTIVE)
+               return IRQ_NONE;
+#endif
+
        spin_lock(&chip->reg_lock);
 
        if (chip->disabled) {
@@ -1394,7 +1421,7 @@ static int azx_setup_periods(struct azx *chip,
        ofs = 0;
        azx_dev->frags = 0;
        pos_adj = bdl_pos_adj[chip->dev_index];
-       if (pos_adj > 0) {
+       if (!azx_dev->no_period_wakeup && pos_adj > 0) {
                struct snd_pcm_runtime *runtime = substream->runtime;
                int pos_align = pos_adj;
                pos_adj = (pos_adj * runtime->rate + 47999) / 48000;
@@ -1410,8 +1437,7 @@ static int azx_setup_periods(struct azx *chip,
                        pos_adj = 0;
                } else {
                        ofs = setup_bdle(chip, substream, azx_dev,
-                                        &bdl, ofs, pos_adj,
-                                        !substream->runtime->no_period_wakeup);
+                                        &bdl, ofs, pos_adj, true);
                        if (ofs < 0)
                                goto error;
                }
@@ -1424,7 +1450,7 @@ static int azx_setup_periods(struct azx *chip,
                else
                        ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs,
                                         period_bytes,
-                                        !substream->runtime->no_period_wakeup);
+                                        !azx_dev->no_period_wakeup);
                if (ofs < 0)
                        goto error;
        }
@@ -1580,7 +1606,7 @@ static int DELAYED_INIT_MARK azx_codec_create(struct azx *chip, const char *mode
        bus_temp.ops.get_response = azx_get_response;
        bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
        bus_temp.ops.bus_reset = azx_bus_reset;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        bus_temp.power_save = &power_save;
        bus_temp.ops.pm_notify = azx_power_notify;
 #endif
@@ -1897,10 +1923,12 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
 
        if (bufsize != azx_dev->bufsize ||
            period_bytes != azx_dev->period_bytes ||
-           format_val != azx_dev->format_val) {
+           format_val != azx_dev->format_val ||
+           runtime->no_period_wakeup != azx_dev->no_period_wakeup) {
                azx_dev->bufsize = bufsize;
                azx_dev->period_bytes = period_bytes;
                azx_dev->format_val = format_val;
+               azx_dev->no_period_wakeup = runtime->no_period_wakeup;
                err = azx_setup_periods(chip, substream, azx_dev);
                if (err < 0)
                        return err;
@@ -1959,14 +1987,14 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        }
 
        spin_lock(&chip->reg_lock);
-       if (nsync > 1) {
-               /* first, set SYNC bits of corresponding streams */
-               if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
-                       azx_writel(chip, OLD_SSYNC,
-                                  azx_readl(chip, OLD_SSYNC) | sbits);
-               else
-                       azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) | sbits);
-       }
+
+       /* first, set SYNC bits of corresponding streams */
+       if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
+               azx_writel(chip, OLD_SSYNC,
+                       azx_readl(chip, OLD_SSYNC) | sbits);
+       else
+               azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) | sbits);
+
        snd_pcm_group_for_each_entry(s, substream) {
                if (s->pcm->card != substream->pcm->card)
                        continue;
@@ -1984,8 +2012,6 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        }
        spin_unlock(&chip->reg_lock);
        if (start) {
-               if (nsync == 1)
-                       return 0;
                /* wait until all FIFOs get ready */
                for (timeout = 5000; timeout; timeout--) {
                        nwait = 0;
@@ -2018,16 +2044,14 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                        cpu_relax();
                }
        }
-       if (nsync > 1) {
-               spin_lock(&chip->reg_lock);
-               /* reset SYNC bits */
-               if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
-                       azx_writel(chip, OLD_SSYNC,
-                                  azx_readl(chip, OLD_SSYNC) & ~sbits);
-               else
-                       azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits);
-               spin_unlock(&chip->reg_lock);
-       }
+       spin_lock(&chip->reg_lock);
+       /* reset SYNC bits */
+       if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC)
+               azx_writel(chip, OLD_SSYNC,
+                       azx_readl(chip, OLD_SSYNC) & ~sbits);
+       else
+               azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits);
+       spin_unlock(&chip->reg_lock);
        return 0;
 }
 
@@ -2120,6 +2144,27 @@ static unsigned int azx_get_position(struct azx *chip,
 
        if (pos >= azx_dev->bufsize)
                pos = 0;
+
+       /* calculate runtime delay from LPIB */
+       if (azx_dev->substream->runtime &&
+           chip->position_fix[stream] == POS_FIX_POSBUF &&
+           (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) {
+               unsigned int lpib_pos = azx_sd_readl(azx_dev, SD_LPIB);
+               int delay;
+               if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       delay = pos - lpib_pos;
+               else
+                       delay = lpib_pos - pos;
+               if (delay < 0)
+                       delay += azx_dev->bufsize;
+               if (delay >= azx_dev->period_bytes) {
+                       snd_printdd("delay %d > period_bytes %d\n",
+                               delay, azx_dev->period_bytes);
+                       delay = 0; /* something is wrong */
+               }
+               azx_dev->substream->runtime->delay =
+                       bytes_to_frames(azx_dev->substream->runtime, delay);
+       }
        return pos;
 }
 
@@ -2379,33 +2424,65 @@ static void azx_stop_chip(struct azx *chip)
        chip->initialized = 0;
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 /* power-up/down the controller */
-static void azx_power_notify(struct hda_bus *bus)
+static void azx_power_notify(struct hda_bus *bus, bool power_up)
 {
        struct azx *chip = bus->private_data;
+
+       if (power_up)
+               pm_runtime_get_sync(&chip->pci->dev);
+       else
+               pm_runtime_put_sync(&chip->pci->dev);
+}
+
+static DEFINE_MUTEX(card_list_lock);
+static LIST_HEAD(card_list);
+
+static void azx_add_card_list(struct azx *chip)
+{
+       mutex_lock(&card_list_lock);
+       list_add(&chip->list, &card_list);
+       mutex_unlock(&card_list_lock);
+}
+
+static void azx_del_card_list(struct azx *chip)
+{
+       mutex_lock(&card_list_lock);
+       list_del_init(&chip->list);
+       mutex_unlock(&card_list_lock);
+}
+
+/* trigger power-save check at writing parameter */
+static int param_set_xint(const char *val, const struct kernel_param *kp)
+{
+       struct azx *chip;
        struct hda_codec *c;
-       int power_on = 0;
+       int prev = power_save;
+       int ret = param_set_int(val, kp);
 
-       list_for_each_entry(c, &bus->codec_list, list) {
-               if (c->power_on) {
-                       power_on = 1;
-                       break;
-               }
+       if (ret || prev == power_save)
+               return ret;
+
+       mutex_lock(&card_list_lock);
+       list_for_each_entry(chip, &card_list, list) {
+               if (!chip->bus || chip->disabled)
+                       continue;
+               list_for_each_entry(c, &chip->bus->codec_list, list)
+                       snd_hda_power_sync(c);
        }
-       if (power_on)
-               azx_init_chip(chip, 1);
-       else if (chip->running && power_save_controller &&
-                !bus->power_keep_link_on)
-               azx_stop_chip(chip);
+       mutex_unlock(&card_list_lock);
+       return 0;
 }
-#endif /* CONFIG_SND_HDA_POWER_SAVE */
+#else
+#define azx_add_card_list(chip) /* NOP */
+#define azx_del_card_list(chip) /* NOP */
+#endif /* CONFIG_PM */
 
-#ifdef CONFIG_PM
+#if defined(CONFIG_PM_SLEEP) || defined(SUPPORT_VGA_SWITCHEROO)
 /*
  * power management
  */
-
 static int azx_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -2460,11 +2537,41 @@ static int azx_resume(struct device *dev)
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
        return 0;
 }
-static SIMPLE_DEV_PM_OPS(azx_pm, azx_suspend, azx_resume);
+#endif /* CONFIG_PM_SLEEP || SUPPORT_VGA_SWITCHEROO */
+
+#ifdef CONFIG_PM_RUNTIME
+static int azx_runtime_suspend(struct device *dev)
+{
+       struct snd_card *card = dev_get_drvdata(dev);
+       struct azx *chip = card->private_data;
+
+       if (!power_save_controller)
+               return -EAGAIN;
+
+       azx_stop_chip(chip);
+       azx_clear_irq_pending(chip);
+       return 0;
+}
+
+static int azx_runtime_resume(struct device *dev)
+{
+       struct snd_card *card = dev_get_drvdata(dev);
+       struct azx *chip = card->private_data;
+
+       azx_init_pci(chip);
+       azx_init_chip(chip, 1);
+       return 0;
+}
+#endif /* CONFIG_PM_RUNTIME */
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops azx_pm = {
+       SET_SYSTEM_SLEEP_PM_OPS(azx_suspend, azx_resume)
+       SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, NULL)
+};
+
 #define AZX_PM_OPS     &azx_pm
 #else
-#define azx_suspend(dev)
-#define azx_resume(dev)
 #define AZX_PM_OPS     NULL
 #endif /* CONFIG_PM */
 
@@ -2599,6 +2706,8 @@ static int azx_free(struct azx *chip)
 {
        int i;
 
+       azx_del_card_list(chip);
+
        azx_notifier_unregister(chip);
 
        if (use_vga_switcheroo(chip)) {
@@ -2640,6 +2749,10 @@ static int azx_free(struct azx *chip)
                pci_release_regions(chip->pci);
        pci_disable_device(chip->pci);
        kfree(chip->azx_dev);
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+       if (chip->fw)
+               release_firmware(chip->fw);
+#endif
        kfree(chip);
 
        return 0;
@@ -2719,6 +2832,7 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
        const struct snd_pci_quirk *q;
 
        switch (fix) {
+       case POS_FIX_AUTO:
        case POS_FIX_LPIB:
        case POS_FIX_POSBUF:
        case POS_FIX_VIACOMBO:
@@ -2904,6 +3018,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        chip->dev_index = dev;
        INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work);
        INIT_LIST_HEAD(&chip->pcm_list);
+       INIT_LIST_HEAD(&chip->list);
        init_vga_switcheroo(chip);
 
        chip->position_fix[0] = chip->position_fix[1] =
@@ -3138,7 +3253,7 @@ static int DELAYED_INIT_MARK azx_first_init(struct azx *chip)
 
 static void power_down_all_codecs(struct azx *chip)
 {
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        /* The codecs were powered up in snd_hda_codec_new().
         * Now all initialization done, so turn them down if possible
         */
@@ -3149,12 +3264,40 @@ static void power_down_all_codecs(struct azx *chip)
 #endif
 }
 
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+/* callback from request_firmware_nowait() */
+static void azx_firmware_cb(const struct firmware *fw, void *context)
+{
+       struct snd_card *card = context;
+       struct azx *chip = card->private_data;
+       struct pci_dev *pci = chip->pci;
+
+       if (!fw) {
+               snd_printk(KERN_ERR SFX "Cannot load firmware, aborting\n");
+               goto error;
+       }
+
+       chip->fw = fw;
+       if (!chip->disabled) {
+               /* continue probing */
+               if (azx_probe_continue(chip))
+                       goto error;
+       }
+       return; /* OK */
+
+ error:
+       snd_card_free(card);
+       pci_set_drvdata(pci, NULL);
+}
+#endif
+
 static int __devinit azx_probe(struct pci_dev *pci,
                               const struct pci_device_id *pci_id)
 {
        static int dev;
        struct snd_card *card;
        struct azx *chip;
+       bool probe_now;
        int err;
 
        if (dev >= SNDRV_CARDS)
@@ -3170,15 +3313,28 @@ static int __devinit azx_probe(struct pci_dev *pci,
                return err;
        }
 
-       /* set this here since it's referred in snd_hda_load_patch() */
        snd_card_set_dev(card, &pci->dev);
 
        err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
        if (err < 0)
                goto out_free;
        card->private_data = chip;
+       probe_now = !chip->disabled;
 
-       if (!chip->disabled) {
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+       if (patch[dev] && *patch[dev]) {
+               snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n",
+                          patch[dev]);
+               err = request_firmware_nowait(THIS_MODULE, true, patch[dev],
+                                             &pci->dev, GFP_KERNEL, card,
+                                             azx_firmware_cb);
+               if (err < 0)
+                       goto out_free;
+               probe_now = false; /* continued in azx_firmware_cb() */
+       }
+#endif /* CONFIG_SND_HDA_PATCH_LOADER */
+
+       if (probe_now) {
                err = azx_probe_continue(chip);
                if (err < 0)
                        goto out_free;
@@ -3186,6 +3342,9 @@ static int __devinit azx_probe(struct pci_dev *pci,
 
        pci_set_drvdata(pci, card);
 
+       if (pci_dev_run_wake(pci))
+               pm_runtime_put_noidle(&pci->dev);
+
        dev++;
        return 0;
 
@@ -3208,12 +3367,13 @@ static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip)
        if (err < 0)
                goto out_free;
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
-       if (patch[dev] && *patch[dev]) {
-               snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n",
-                          patch[dev]);
-               err = snd_hda_load_patch(chip->bus, patch[dev]);
+       if (chip->fw) {
+               err = snd_hda_load_patch(chip->bus, chip->fw->size,
+                                        chip->fw->data);
                if (err < 0)
                        goto out_free;
+               release_firmware(chip->fw); /* no longer needed */
+               chip->fw = NULL;
        }
 #endif
        if ((probe_only[dev] & 1) == 0) {
@@ -3239,6 +3399,7 @@ static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip)
        chip->running = 1;
        power_down_all_codecs(chip);
        azx_notifier_register(chip);
+       azx_add_card_list(chip);
 
        return 0;
 
@@ -3250,6 +3411,10 @@ out_free:
 static void __devexit azx_remove(struct pci_dev *pci)
 {
        struct snd_card *card = pci_get_drvdata(pci);
+
+       if (pci_dev_run_wake(pci))
+               pm_runtime_get_noresume(&pci->dev);
+
        if (card)
                snd_card_free(card);
        pci_set_drvdata(pci, NULL);
@@ -3260,7 +3425,7 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        /* CPT */
        { PCI_DEVICE(0x8086, 0x1c20),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
-         AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+         AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
        /* PBG */
        { PCI_DEVICE(0x8086, 0x1d20),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
@@ -3268,23 +3433,30 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        /* Panther Point */
        { PCI_DEVICE(0x8086, 0x1e20),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
-         AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+         AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
        /* Lynx Point */
        { PCI_DEVICE(0x8086, 0x8c20),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
-         AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+         AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
        /* Lynx Point-LP */
        { PCI_DEVICE(0x8086, 0x9c20),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
-         AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+         AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
        /* Lynx Point-LP */
        { PCI_DEVICE(0x8086, 0x9c21),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
-         AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+         AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
        /* Haswell */
        { PCI_DEVICE(0x8086, 0x0c0c),
          .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
-         AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+         AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
+       { PCI_DEVICE(0x8086, 0x0d0c),
+         .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
+         AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
+       /* 5 Series/3400 */
+       { PCI_DEVICE(0x8086, 0x3b56),
+         .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
+         AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
        /* SCH */
        { PCI_DEVICE(0x8086, 0x811b),
          .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
index aaccc0236bda86ccba98bd1f3a5cb69474c5823e..5c690cb873d469af2b419476fb790e893c2433a2 100644 (file)
@@ -26,9 +26,8 @@ bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
                return false;
        if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT))
                return false;
-       if (!codec->ignore_misc_bit &&
-           (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
-            AC_DEFCFG_MISC_NO_PRESENCE))
+       if (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
+            AC_DEFCFG_MISC_NO_PRESENCE)
                return false;
        if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
                return false;
@@ -193,8 +192,9 @@ EXPORT_SYMBOL_HDA(snd_hda_jack_detect);
 /**
  * snd_hda_jack_detect_enable - enable the jack-detection
  */
-int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
-                              unsigned char action)
+int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
+                                       unsigned char action,
+                                       hda_jack_callback cb)
 {
        struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid);
        if (!jack)
@@ -204,10 +204,19 @@ int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
        jack->jack_detect = 1;
        if (action)
                jack->action = action;
+       if (cb)
+               jack->callback = cb;
        return snd_hda_codec_write_cache(codec, nid, 0,
                                         AC_VERB_SET_UNSOLICITED_ENABLE,
                                         AC_USRSP_EN | jack->tag);
 }
+EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable_callback);
+
+int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
+                              unsigned char action)
+{
+       return snd_hda_jack_detect_enable_callback(codec, nid, action, NULL);
+}
 EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable);
 
 /**
@@ -412,3 +421,21 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec,
        return 0;
 }
 EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctls);
+
+void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+       struct hda_jack_tbl *event;
+       int tag = (res >> AC_UNSOL_RES_TAG_SHIFT) & 0x7f;
+
+       event = snd_hda_jack_tbl_get_from_tag(codec, tag);
+       if (!event)
+               return;
+       event->jack_dirty = 1;
+
+       if (event->callback)
+               event->callback(codec, event);
+
+       snd_hda_jack_report_sync(codec);
+}
+EXPORT_SYMBOL_HDA(snd_hda_jack_unsol_event);
+
index a9803da633c0c181c4dd2c12fb3beecf479af2e4..af8dd4724da544c85a2b4df431262952dbb39c4a 100644 (file)
 #define __SOUND_HDA_JACK_H
 
 struct auto_pin_cfg;
+struct hda_jack_tbl;
+
+typedef void (*hda_jack_callback) (struct hda_codec *, struct hda_jack_tbl *);
 
 struct hda_jack_tbl {
        hda_nid_t nid;
        unsigned char action;           /* event action (0 = none) */
        unsigned char tag;              /* unsol event tag */
        unsigned int private_data;      /* arbitrary data */
+       hda_jack_callback callback;
        /* jack-detection stuff */
        unsigned int pin_sense;         /* cached pin-sense value */
        unsigned int jack_detect:1;     /* capable of jack-detection? */
@@ -61,6 +65,10 @@ void snd_hda_jack_set_dirty_all(struct hda_codec *codec);
 
 int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
                               unsigned char action);
+int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
+                                       unsigned char action,
+                                       hda_jack_callback cb);
+
 
 u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
 int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid);
@@ -74,5 +82,6 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec,
 
 void snd_hda_jack_report_sync(struct hda_codec *codec);
 
+void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res);
 
 #endif /* __SOUND_HDA_JACK_H */
index 1b4c12941baa3f2f250913c556624870c1e15b48..09dbdc37f781592b45c8e8c03a80b0f133195996 100644 (file)
@@ -529,7 +529,7 @@ int snd_hda_create_hwdep(struct hda_codec *codec);
 static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; }
 #endif
 
-#if defined(CONFIG_SND_HDA_POWER_SAVE) && defined(CONFIG_SND_HDA_HWDEP)
+#if defined(CONFIG_PM) && defined(CONFIG_SND_HDA_HWDEP)
 int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec);
 #else
 static inline int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec)
index 6894ec66258c5988771b2518071e6e9a603e14f2..045e5d32f5ded3d2e5b54f3f344e99a29ab09aac 100644 (file)
@@ -402,6 +402,9 @@ static void print_digital_conv(struct snd_info_buffer *buffer,
 {
        unsigned int digi1 = snd_hda_codec_read(codec, nid, 0,
                                                AC_VERB_GET_DIGI_CONVERT_1, 0);
+       unsigned char digi2 = digi1 >> 8;
+       unsigned char digi3 = digi1 >> 16;
+
        snd_iprintf(buffer, "  Digital:");
        if (digi1 & AC_DIG1_ENABLE)
                snd_iprintf(buffer, " Enabled");
@@ -419,9 +422,13 @@ static void print_digital_conv(struct snd_info_buffer *buffer,
                snd_iprintf(buffer, " Pro");
        if (digi1 & AC_DIG1_LEVEL)
                snd_iprintf(buffer, " GenLevel");
+       if (digi3 & AC_DIG3_KAE)
+               snd_iprintf(buffer, " KAE");
        snd_iprintf(buffer, "\n");
        snd_iprintf(buffer, "  Digital category: 0x%x\n",
-                   (digi1 >> 8) & AC_DIG2_CC);
+                   digi2 & AC_DIG2_CC);
+       snd_iprintf(buffer, "  IEC Coding Type: 0x%x\n",
+                       digi3 & AC_DIG3_ICT);
 }
 
 static const char *get_pwr_state(u32 state)
index 9884871ddb0009f07dda1514e7576b076dfba446..3a1c63161eb129d71a02203ce9fe3a3b24ec6df4 100644 (file)
@@ -58,6 +58,7 @@ TRACE_EVENT(hda_bus_reset,
        TP_printk("[%d]", __entry->card)
 );
 
+#ifdef CONFIG_PM
 DECLARE_EVENT_CLASS(hda_power,
 
        TP_PROTO(struct hda_codec *codec),
@@ -87,6 +88,31 @@ DEFINE_EVENT(hda_power, hda_power_up,
        TP_ARGS(codec)
 );
 
+TRACE_EVENT(hda_power_count,
+       TP_PROTO(struct hda_codec *codec),
+       TP_ARGS(codec),
+       TP_STRUCT__entry(
+               __field( unsigned int, card )
+               __field( unsigned int, addr )
+               __field( int, power_count )
+               __field( int, power_on )
+               __field( int, power_transition )
+       ),
+
+       TP_fast_assign(
+               __entry->card = (codec)->bus->card->number;
+               __entry->addr = (codec)->addr;
+               __entry->power_count = (codec)->power_count;
+               __entry->power_on = (codec)->power_on;
+               __entry->power_transition = (codec)->power_transition;
+       ),
+
+       TP_printk("[%d:%d] power_count=%d, power_on=%d, power_transition=%d",
+                 __entry->card, __entry->addr, __entry->power_count,
+                 __entry->power_on, __entry->power_transition)
+);
+#endif /* CONFIG_PM */
+
 TRACE_EVENT(hda_unsol_event,
 
        TP_PROTO(struct hda_bus *bus, u32 res, u32 res_ex),
index 0208fa121e5aad0fa4c77f6d5a642aebb38417dd..cdd43eadbc67425e80237b7da979c778b6bd835b 100644 (file)
@@ -85,7 +85,7 @@ struct ad198x_spec {
        unsigned int analog_beep: 1;    /* analog beep input present */
        unsigned int avoid_init_slave_vol:1;
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        struct hda_loopback_check loopback;
 #endif
        /* for virtual master */
@@ -269,7 +269,7 @@ static int ad198x_build_controls(struct hda_codec *codec)
        return 0;
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 {
        struct ad198x_spec *spec = codec->spec;
@@ -654,10 +654,8 @@ static const struct hda_codec_ops ad198x_patch_ops = {
        .build_pcms = ad198x_build_pcms,
        .init = ad198x_init,
        .free = ad198x_free,
-#ifdef CONFIG_SND_HDA_POWER_SAVE
-       .check_power_status = ad198x_check_power_status,
-#endif
 #ifdef CONFIG_PM
+       .check_power_status = ad198x_check_power_status,
        .suspend = ad198x_suspend,
 #endif
        .reboot_notify = ad198x_shutup,
@@ -1231,7 +1229,7 @@ static const struct snd_pci_quirk ad1986a_cfg_tbl[] = {
        {}
 };
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static const struct hda_amp_list ad1986a_loopbacks[] = {
        { 0x13, HDA_OUTPUT, 0 }, /* Mic */
        { 0x14, HDA_OUTPUT, 0 }, /* Phone */
@@ -1278,7 +1276,7 @@ static int patch_ad1986a(struct hda_codec *codec)
        spec->mixers[0] = ad1986a_mixers;
        spec->num_init_verbs = 1;
        spec->init_verbs[0] = ad1986a_init_verbs;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        spec->loopback.amplist = ad1986a_loopbacks;
 #endif
        spec->vmaster_nid = 0x1b;
@@ -1537,7 +1535,7 @@ static const struct hda_verb ad1983_init_verbs[] = {
        { } /* end */
 };
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static const struct hda_amp_list ad1983_loopbacks[] = {
        { 0x12, HDA_OUTPUT, 0 }, /* Mic */
        { 0x13, HDA_OUTPUT, 0 }, /* Line */
@@ -1576,7 +1574,7 @@ static int patch_ad1983(struct hda_codec *codec)
        spec->num_init_verbs = 1;
        spec->init_verbs[0] = ad1983_init_verbs;
        spec->spdif_route = 0;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        spec->loopback.amplist = ad1983_loopbacks;
 #endif
        spec->vmaster_nid = 0x05;
@@ -1704,7 +1702,7 @@ static const struct hda_verb ad1981_init_verbs[] = {
        { } /* end */
 };
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static const struct hda_amp_list ad1981_loopbacks[] = {
        { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */
        { 0x13, HDA_OUTPUT, 0 }, /* Line */
@@ -1812,7 +1810,7 @@ static const struct hda_input_mux ad1981_hp_capture_source = {
        .num_items = 3,
        .items = {
                { "Mic", 0x0 },
-               { "Docking-Station", 0x1 },
+               { "Dock Mic", 0x1 },
                { "Mix", 0x2 },
        },
 };
@@ -1836,8 +1834,8 @@ static const struct snd_kcontrol_new ad1981_hp_mixers[] = {
         */
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Docking-Station Playback Volume", 0x13, 0x0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Docking-Station Playback Switch", 0x13, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
        HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
        /* FIXME: does this laptop have analog CD connection? */
@@ -1982,7 +1980,7 @@ static int patch_ad1981(struct hda_codec *codec)
        spec->num_init_verbs = 1;
        spec->init_verbs[0] = ad1981_init_verbs;
        spec->spdif_route = 0;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        spec->loopback.amplist = ad1981_loopbacks;
 #endif
        spec->vmaster_nid = 0x05;
@@ -2807,7 +2805,7 @@ static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
                snd_hda_sequence_write(codec, ad1988_laptop_hp_off);
 } 
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static const struct hda_amp_list ad1988_loopbacks[] = {
        { 0x20, HDA_INPUT, 0 }, /* Front Mic */
        { 0x20, HDA_INPUT, 1 }, /* Line */
@@ -3399,7 +3397,7 @@ static int patch_ad1988(struct hda_codec *codec)
                codec->patch_ops.unsol_event = ad1988_laptop_unsol_event;
                break;
        }
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        spec->loopback.amplist = ad1988_loopbacks;
 #endif
        spec->vmaster_nid = 0x04;
@@ -3555,7 +3553,7 @@ static const struct hda_verb ad1884_init_verbs[] = {
        { } /* end */
 };
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static const struct hda_amp_list ad1884_loopbacks[] = {
        { 0x20, HDA_INPUT, 0 }, /* Front Mic */
        { 0x20, HDA_INPUT, 1 }, /* Mic */
@@ -3567,7 +3565,7 @@ static const struct hda_amp_list ad1884_loopbacks[] = {
 
 static const char * const ad1884_slave_vols[] = {
        "PCM", "Mic", "Mono", "Front Mic", "Mic", "CD",
-       "Internal Mic", "Docking Mic", /* "Beep", */ "IEC958",
+       "Internal Mic", "Dock Mic", /* "Beep", */ "IEC958",
        NULL
 };
 
@@ -3602,7 +3600,7 @@ static int patch_ad1884(struct hda_codec *codec)
        spec->num_init_verbs = 1;
        spec->init_verbs[0] = ad1884_init_verbs;
        spec->spdif_route = 0;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        spec->loopback.amplist = ad1884_loopbacks;
 #endif
        spec->vmaster_nid = 0x04;
@@ -3628,7 +3626,7 @@ static const struct hda_input_mux ad1984_thinkpad_capture_source = {
                { "Mic", 0x0 },
                { "Internal Mic", 0x1 },
                { "Mix", 0x3 },
-               { "Docking-Station", 0x4 },
+               { "Dock Mic", 0x4 },
        },
 };
 
@@ -3657,8 +3655,8 @@ static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
        HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
        HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
        HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
-       HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
-       HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
@@ -3994,7 +3992,7 @@ static const struct hda_verb ad1884a_init_verbs[] = {
        { } /* end */
 };
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static const struct hda_amp_list ad1884a_loopbacks[] = {
        { 0x20, HDA_INPUT, 0 }, /* Front Mic */
        { 0x20, HDA_INPUT, 1 }, /* Mic */
@@ -4602,7 +4600,7 @@ static int patch_ad1884a(struct hda_codec *codec)
        spec->num_init_verbs = 1;
        spec->init_verbs[0] = ad1884a_init_verbs;
        spec->spdif_route = 0;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        spec->loopback.amplist = ad1884a_loopbacks;
 #endif
        codec->patch_ops = ad198x_patch_ops;
@@ -4814,6 +4812,32 @@ static const struct snd_kcontrol_new ad1882_3stack_mixers[] = {
        { } /* end */
 };
 
+/* simple auto-mute control for AD1882 3-stack board */
+#define AD1882_HP_EVENT        0x01
+
+static void ad1882_3stack_automute(struct hda_codec *codec)
+{
+       bool mute = snd_hda_jack_detect(codec, 0x11);
+       snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           mute ? 0 : PIN_OUT);
+}
+
+static int ad1882_3stack_automute_init(struct hda_codec *codec)
+{
+       ad198x_init(codec);
+       ad1882_3stack_automute(codec);
+       return 0;
+}
+
+static void ad1882_3stack_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+       switch (res >> 26) {
+       case AD1882_HP_EVENT:
+               ad1882_3stack_automute(codec);
+               break;
+       }
+}
+
 static const struct snd_kcontrol_new ad1882_6stack_mixers[] = {
        HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
@@ -4928,7 +4952,12 @@ static const struct hda_verb ad1882_init_verbs[] = {
        { } /* end */
 };
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+static const struct hda_verb ad1882_3stack_automute_verbs[] = {
+       {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1882_HP_EVENT},
+       { } /* end */
+};
+
+#ifdef CONFIG_PM
 static const struct hda_amp_list ad1882_loopbacks[] = {
        { 0x20, HDA_INPUT, 0 }, /* Front Mic */
        { 0x20, HDA_INPUT, 1 }, /* Mic */
@@ -4942,12 +4971,14 @@ static const struct hda_amp_list ad1882_loopbacks[] = {
 enum {
        AD1882_3STACK,
        AD1882_6STACK,
+       AD1882_3STACK_AUTOMUTE,
        AD1882_MODELS
 };
 
 static const char * const ad1882_models[AD1986A_MODELS] = {
        [AD1882_3STACK]         = "3stack",
        [AD1882_6STACK]         = "6stack",
+       [AD1882_3STACK_AUTOMUTE] = "3stack-automute",
 };
 
 
@@ -4989,7 +5020,7 @@ static int patch_ad1882(struct hda_codec *codec)
        spec->num_init_verbs = 1;
        spec->init_verbs[0] = ad1882_init_verbs;
        spec->spdif_route = 0;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        spec->loopback.amplist = ad1882_loopbacks;
 #endif
        spec->vmaster_nid = 0x04;
@@ -5002,6 +5033,7 @@ static int patch_ad1882(struct hda_codec *codec)
        switch (board_config) {
        default:
        case AD1882_3STACK:
+       case AD1882_3STACK_AUTOMUTE:
                spec->num_mixers = 3;
                spec->mixers[2] = ad1882_3stack_mixers;
                spec->channel_mode = ad1882_modes;
@@ -5009,6 +5041,12 @@ static int patch_ad1882(struct hda_codec *codec)
                spec->need_dac_fix = 1;
                spec->multiout.max_channels = 2;
                spec->multiout.num_dacs = 1;
+               if (board_config != AD1882_3STACK) {
+                       spec->init_verbs[spec->num_init_verbs++] =
+                               ad1882_3stack_automute_verbs;
+                       codec->patch_ops.unsol_event = ad1882_3stack_unsol_event;
+                       codec->patch_ops.init = ad1882_3stack_automute_init;
+               }
                break;
        case AD1882_6STACK:
                spec->num_mixers = 3;
index 0c4c1a61b3789f590d62ea6a2e8348417746cd95..fcfc9f0a056b82fcbe9b7deafbef3b2c9516f6c4 100644 (file)
@@ -34,7 +34,8 @@
  */
 
 struct cs_spec {
-       int board_config;
+       struct hda_gen_spec gen;
+
        struct auto_pin_cfg autocfg;
        struct hda_multi_out multiout;
        struct snd_kcontrol *vmaster_sw;
@@ -80,16 +81,20 @@ enum {
        CS420X_MBP53,
        CS420X_MBP55,
        CS420X_IMAC27,
-       CS420X_IMAC27_122,
-       CS420X_APPLE,
+       CS420X_GPIO_13,
+       CS420X_GPIO_23,
+       CS420X_MBP101,
+       CS420X_MBP101_COEF,
        CS420X_AUTO,
-       CS420X_MODELS
+       /* aliases */
+       CS420X_IMAC27_122 = CS420X_GPIO_23,
+       CS420X_APPLE = CS420X_GPIO_13,
 };
 
 /* CS421x boards */
 enum {
        CS421X_CDB4210,
-       CS421X_MODELS
+       CS421X_SENSE_B,
 };
 
 /* Vendor-specific processing widget */
@@ -1157,6 +1162,14 @@ static const struct hda_verb cs_errata_init_verbs[] = {
        {} /* terminator */
 };
 
+static const struct hda_verb mbp101_init_verbs[] = {
+       {0x11, AC_VERB_SET_COEF_INDEX, 0x0002},
+       {0x11, AC_VERB_SET_PROC_COEF, 0x100a},
+       {0x11, AC_VERB_SET_COEF_INDEX, 0x0004},
+       {0x11, AC_VERB_SET_PROC_COEF, 0x000f},
+       {}
+};
+
 /* SPDIF setup */
 static void init_digital(struct hda_codec *codec)
 {
@@ -1193,7 +1206,6 @@ static int cs_init(struct hda_codec *codec)
        init_output(codec);
        init_input(codec);
        init_digital(codec);
-       snd_hda_jack_report_sync(codec);
 
        return 0;
 }
@@ -1279,38 +1291,32 @@ static int cs_parse_auto_config(struct hda_codec *codec)
        return 0;
 }
 
-static const char * const cs420x_models[CS420X_MODELS] = {
-       [CS420X_MBP53] = "mbp53",
-       [CS420X_MBP55] = "mbp55",
-       [CS420X_IMAC27] = "imac27",
-       [CS420X_IMAC27_122] = "imac27_122",
-       [CS420X_APPLE] = "apple",
-       [CS420X_AUTO] = "auto",
+static const struct hda_model_fixup cs420x_models[] = {
+       { .id = CS420X_MBP53, .name = "mbp53" },
+       { .id = CS420X_MBP55, .name = "mbp55" },
+       { .id = CS420X_IMAC27, .name = "imac27" },
+       { .id = CS420X_IMAC27_122, .name = "imac27_122" },
+       { .id = CS420X_APPLE, .name = "apple" },
+       { .id = CS420X_MBP101, .name = "mbp101" },
+       {}
 };
 
-
-static const struct snd_pci_quirk cs420x_cfg_tbl[] = {
+static const struct snd_pci_quirk cs420x_fixup_tbl[] = {
        SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
        SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55),
        SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
        SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
        /* this conflicts with too many other models */
        /*SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),*/
-       {} /* terminator */
-};
 
-static const struct snd_pci_quirk cs420x_codec_cfg_tbl[] = {
+       /* codec SSID */
        SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122),
+       SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101),
        SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE),
        {} /* terminator */
 };
 
-struct cs_pincfg {
-       hda_nid_t nid;
-       u32 val;
-};
-
-static const struct cs_pincfg mbp53_pincfgs[] = {
+static const struct hda_pintbl mbp53_pincfgs[] = {
        { 0x09, 0x012b4050 },
        { 0x0a, 0x90100141 },
        { 0x0b, 0x90100140 },
@@ -1324,7 +1330,7 @@ static const struct cs_pincfg mbp53_pincfgs[] = {
        {} /* terminator */
 };
 
-static const struct cs_pincfg mbp55_pincfgs[] = {
+static const struct hda_pintbl mbp55_pincfgs[] = {
        { 0x09, 0x012b4030 },
        { 0x0a, 0x90100121 },
        { 0x0b, 0x90100120 },
@@ -1338,7 +1344,7 @@ static const struct cs_pincfg mbp55_pincfgs[] = {
        {} /* terminator */
 };
 
-static const struct cs_pincfg imac27_pincfgs[] = {
+static const struct hda_pintbl imac27_pincfgs[] = {
        { 0x09, 0x012b4050 },
        { 0x0a, 0x90100140 },
        { 0x0b, 0x90100142 },
@@ -1352,22 +1358,78 @@ static const struct cs_pincfg imac27_pincfgs[] = {
        {} /* terminator */
 };
 
-static const struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = {
-       [CS420X_MBP53] = mbp53_pincfgs,
-       [CS420X_MBP55] = mbp55_pincfgs,
-       [CS420X_IMAC27] = imac27_pincfgs,
+static const struct hda_pintbl mbp101_pincfgs[] = {
+       { 0x0d, 0x40ab90f0 },
+       { 0x0e, 0x90a600f0 },
+       { 0x12, 0x50a600f0 },
+       {} /* terminator */
 };
 
-static void fix_pincfg(struct hda_codec *codec, int model,
-                      const struct cs_pincfg **pin_configs)
+static void cs420x_fixup_gpio_13(struct hda_codec *codec,
+                                const struct hda_fixup *fix, int action)
 {
-       const struct cs_pincfg *cfg = pin_configs[model];
-       if (!cfg)
-               return;
-       for (; cfg->nid; cfg++)
-               snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               struct cs_spec *spec = codec->spec;
+               spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */
+               spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
+               spec->gpio_mask = spec->gpio_dir =
+                       spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
+       }
 }
 
+static void cs420x_fixup_gpio_23(struct hda_codec *codec,
+                                const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               struct cs_spec *spec = codec->spec;
+               spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */
+               spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
+               spec->gpio_mask = spec->gpio_dir =
+                       spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
+       }
+}
+
+static const struct hda_fixup cs420x_fixups[] = {
+       [CS420X_MBP53] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = mbp53_pincfgs,
+               .chained = true,
+               .chain_id = CS420X_APPLE,
+       },
+       [CS420X_MBP55] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = mbp55_pincfgs,
+               .chained = true,
+               .chain_id = CS420X_GPIO_13,
+       },
+       [CS420X_IMAC27] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = imac27_pincfgs,
+               .chained = true,
+               .chain_id = CS420X_GPIO_13,
+       },
+       [CS420X_GPIO_13] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs420x_fixup_gpio_13,
+       },
+       [CS420X_GPIO_23] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs420x_fixup_gpio_23,
+       },
+       [CS420X_MBP101] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = mbp101_pincfgs,
+               .chained = true,
+               .chain_id = CS420X_MBP101_COEF,
+       },
+       [CS420X_MBP101_COEF] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = mbp101_init_verbs,
+               .chained = true,
+               .chain_id = CS420X_GPIO_13,
+       },
+};
+
 static int patch_cs420x(struct hda_codec *codec)
 {
        struct cs_spec *spec;
@@ -1380,33 +1442,9 @@ static int patch_cs420x(struct hda_codec *codec)
 
        spec->vendor_nid = CS420X_VENDOR_NID;
 
-       spec->board_config =
-               snd_hda_check_board_config(codec, CS420X_MODELS,
-                                          cs420x_models, cs420x_cfg_tbl);
-       if (spec->board_config < 0)
-               spec->board_config =
-                       snd_hda_check_board_codec_sid_config(codec,
-                               CS420X_MODELS, NULL, cs420x_codec_cfg_tbl);
-       if (spec->board_config >= 0)
-               fix_pincfg(codec, spec->board_config, cs_pincfgs);
-
-       switch (spec->board_config) {
-       case CS420X_IMAC27:
-       case CS420X_MBP53:
-       case CS420X_MBP55:
-       case CS420X_APPLE:
-               spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */
-               spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
-               spec->gpio_mask = spec->gpio_dir =
-                       spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
-               break;
-       case CS420X_IMAC27_122:
-               spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */
-               spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
-               spec->gpio_mask = spec->gpio_dir =
-                       spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
-               break;
-       }
+       snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl,
+                          cs420x_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
        err = cs_parse_auto_config(codec);
        if (err < 0)
@@ -1414,6 +1452,8 @@ static int patch_cs420x(struct hda_codec *codec)
 
        codec->patch_ops = cs_patch_ops;
 
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
        return 0;
 
  error:
@@ -1431,11 +1471,12 @@ static int patch_cs420x(struct hda_codec *codec)
 */
 
 /* CS4210 board names */
-static const char *cs421x_models[CS421X_MODELS] = {
-       [CS421X_CDB4210] = "cdb4210",
+static const struct hda_model_fixup cs421x_models[] = {
+       { .id = CS421X_CDB4210, .name = "cdb4210" },
+       {}
 };
 
-static const struct snd_pci_quirk cs421x_cfg_tbl[] = {
+static const struct snd_pci_quirk cs421x_fixup_tbl[] = {
        /* Test Intel board + CDB2410  */
        SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210),
        {} /* terminator */
@@ -1443,7 +1484,7 @@ static const struct snd_pci_quirk cs421x_cfg_tbl[] = {
 
 /* CS4210 board pinconfigs */
 /* Default CS4210 (CDB4210)*/
-static const struct cs_pincfg cdb4210_pincfgs[] = {
+static const struct hda_pintbl cdb4210_pincfgs[] = {
        { 0x05, 0x0321401f },
        { 0x06, 0x90170010 },
        { 0x07, 0x03813031 },
@@ -1453,8 +1494,26 @@ static const struct cs_pincfg cdb4210_pincfgs[] = {
        {} /* terminator */
 };
 
-static const struct cs_pincfg *cs421x_pincfgs[CS421X_MODELS] = {
-       [CS421X_CDB4210] = cdb4210_pincfgs,
+/* Setup GPIO/SENSE for each board (if used) */
+static void cs421x_fixup_sense_b(struct hda_codec *codec,
+                                const struct hda_fixup *fix, int action)
+{
+       struct cs_spec *spec = codec->spec;
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               spec->sense_b = 1;
+}
+
+static const struct hda_fixup cs421x_fixups[] = {
+       [CS421X_CDB4210] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = cdb4210_pincfgs,
+               .chained = true,
+               .chain_id = CS421X_SENSE_B,
+       },
+       [CS421X_SENSE_B] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs421x_fixup_sense_b,
+       }
 };
 
 static const struct hda_verb cs421x_coef_init_verbs[] = {
@@ -1643,7 +1702,6 @@ static int cs421x_init(struct hda_codec *codec)
        init_output(codec);
        init_input(codec);
        init_cs421x_digital(codec);
-       snd_hda_jack_report_sync(codec);
 
        return 0;
 }
@@ -1937,26 +1995,9 @@ static int patch_cs4210(struct hda_codec *codec)
 
        spec->vendor_nid = CS4210_VENDOR_NID;
 
-       spec->board_config =
-               snd_hda_check_board_config(codec, CS421X_MODELS,
-                                          cs421x_models, cs421x_cfg_tbl);
-       if (spec->board_config >= 0)
-               fix_pincfg(codec, spec->board_config, cs421x_pincfgs);
-       /*
-           Setup GPIO/SENSE for each board (if used)
-       */
-       switch (spec->board_config) {
-       case CS421X_CDB4210:
-               snd_printd("CS4210 board: %s\n",
-                       cs421x_models[spec->board_config]);
-/*             spec->gpio_mask = 3;
-               spec->gpio_dir = 3;
-               spec->gpio_data = 3;
-*/
-               spec->sense_b = 1;
-
-               break;
-       }
+       snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl,
+                          cs421x_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
 
        /*
            Update the GPIO/DMIC/SENSE_B pinmux before the configuration
@@ -1971,6 +2012,8 @@ static int patch_cs4210(struct hda_codec *codec)
 
        codec->patch_ops = cs421x_patch_ops;
 
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
        return 0;
 
  error:
index 5e22a8f43d2eebc288083142b355feffb61ffedb..03b1dc317ff0341122d48a0535e41963b2834157 100644 (file)
@@ -553,7 +553,7 @@ static int conexant_build_controls(struct hda_codec *codec)
        return 0;
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static int conexant_suspend(struct hda_codec *codec)
 {
        snd_hda_shutup_pins(codec);
@@ -567,7 +567,7 @@ static const struct hda_codec_ops conexant_patch_ops = {
        .init = conexant_init,
        .free = conexant_free,
        .set_power_state = conexant_set_power,
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        .suspend = conexant_suspend,
 #endif
        .reboot_notify = snd_hda_shutup_pins,
@@ -1710,8 +1710,8 @@ static const struct snd_kcontrol_new cxt5051_capture_mixers[] = {
        HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT),
-       HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Dock Mic Volume", 0x15, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Dock Mic Switch", 0x15, 0x00, HDA_INPUT),
        {}
 };
 
@@ -3402,7 +3402,7 @@ static void cx_auto_update_speakers(struct hda_codec *codec)
        do_automute(codec, cfg->line_outs, cfg->line_out_pins, on);
 }
 
-static void cx_auto_hp_automute(struct hda_codec *codec)
+static void cx_auto_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
 {
        struct conexant_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
@@ -3413,7 +3413,7 @@ static void cx_auto_hp_automute(struct hda_codec *codec)
        cx_auto_update_speakers(codec);
 }
 
-static void cx_auto_line_automute(struct hda_codec *codec)
+static void cx_auto_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
 {
        struct conexant_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
@@ -3540,8 +3540,9 @@ static int __select_input_connection(struct hda_codec *codec, hda_nid_t mux,
                                     hda_nid_t pin, hda_nid_t *srcp,
                                     bool do_select, int depth)
 {
+       struct conexant_spec *spec = codec->spec;
        hda_nid_t conn[HDA_MAX_NUM_INPUTS];
-       int i, nums;
+       int startidx, i, nums;
 
        switch (get_wcaps_type(get_wcaps(codec, mux))) {
        case AC_WID_AUD_IN:
@@ -3565,14 +3566,25 @@ static int __select_input_connection(struct hda_codec *codec, hda_nid_t mux,
        depth++;
        if (depth == 2)
                return -1;
+
+       /* Try to rotate around connections to avoid one boost controlling
+          another input path as well */
+       startidx = 0;
+       for (i = 0; i < spec->private_imux.num_items; i++)
+               if (spec->imux_info[i].pin == pin) {
+                       startidx = i;
+                       break;
+               }
+
        for (i = 0; i < nums; i++) {
-               int ret  = __select_input_connection(codec, conn[i], pin, srcp,
+               int j = (i + startidx) % nums;
+               int ret  = __select_input_connection(codec, conn[j], pin, srcp,
                                                     do_select, depth);
                if (ret >= 0) {
                        if (do_select)
                                snd_hda_codec_write(codec, mux, 0,
-                                                   AC_VERB_SET_CONNECT_SEL, i);
-                       return i;
+                                                   AC_VERB_SET_CONNECT_SEL, j);
+                       return j;
                }
        }
        return -1;
@@ -3652,7 +3664,7 @@ static bool select_automic(struct hda_codec *codec, int idx, bool detect)
 }
 
 /* automatic switch internal and external mic */
-static void cx_auto_automic(struct hda_codec *codec)
+static void cx_auto_automic(struct hda_codec *codec, struct hda_jack_tbl *jack)
 {
        struct conexant_spec *spec = codec->spec;
 
@@ -3663,22 +3675,6 @@ static void cx_auto_automic(struct hda_codec *codec)
                        select_automic(codec, spec->auto_mic_int, false);
 }
 
-static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       switch (snd_hda_jack_get_action(codec, res >> 26)) {
-       case CONEXANT_HP_EVENT:
-               cx_auto_hp_automute(codec);
-               break;
-       case CONEXANT_LINE_EVENT:
-               cx_auto_line_automute(codec);
-               break;
-       case CONEXANT_MIC_EVENT:
-               cx_auto_automic(codec);
-               break;
-       }
-       snd_hda_jack_report_sync(codec);
-}
-
 /* check whether the pin config is suitable for auto-mic switching;
  * auto-mic is enabled only when one int-mic and one ext- and/or
  * one dock-mic exist
@@ -3888,11 +3884,12 @@ static void mute_outputs(struct hda_codec *codec, int num_nids,
 }
 
 static void enable_unsol_pins(struct hda_codec *codec, int num_pins,
-                             hda_nid_t *pins, unsigned int action)
+                             hda_nid_t *pins, unsigned int action,
+                             hda_jack_callback cb)
 {
        int i;
        for (i = 0; i < num_pins; i++)
-               snd_hda_jack_detect_enable(codec, pins[i], action);
+               snd_hda_jack_detect_enable_callback(codec, pins[i], action, cb);
 }
 
 static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
@@ -3980,13 +3977,14 @@ static void cx_auto_init_output(struct hda_codec *codec)
        }
        if (spec->auto_mute) {
                enable_unsol_pins(codec, cfg->hp_outs, cfg->hp_pins,
-                                 CONEXANT_HP_EVENT);
+                                 CONEXANT_HP_EVENT, cx_auto_hp_automute);
                spec->hp_present = detect_jacks(codec, cfg->hp_outs,
                                                cfg->hp_pins);
                if (spec->detect_line) {
                        enable_unsol_pins(codec, cfg->line_outs,
                                          cfg->line_out_pins,
-                                         CONEXANT_LINE_EVENT);
+                                         CONEXANT_LINE_EVENT,
+                                         cx_auto_line_automute);
                        spec->line_present =
                                detect_jacks(codec, cfg->line_outs,
                                             cfg->line_out_pins);
@@ -4027,16 +4025,16 @@ static void cx_auto_init_input(struct hda_codec *codec)
 
        if (spec->auto_mic) {
                if (spec->auto_mic_ext >= 0) {
-                       snd_hda_jack_detect_enable(codec,
+                       snd_hda_jack_detect_enable_callback(codec,
                                cfg->inputs[spec->auto_mic_ext].pin,
-                               CONEXANT_MIC_EVENT);
+                               CONEXANT_MIC_EVENT, cx_auto_automic);
                }
                if (spec->auto_mic_dock >= 0) {
-                       snd_hda_jack_detect_enable(codec,
+                       snd_hda_jack_detect_enable_callback(codec,
                                cfg->inputs[spec->auto_mic_dock].pin,
-                               CONEXANT_MIC_EVENT);
+                               CONEXANT_MIC_EVENT, cx_auto_automic);
                }
-               cx_auto_automic(codec);
+               cx_auto_automic(codec, NULL);
        } else {
                select_input_connection(codec, spec->imux_info[0].adc,
                                        spec->imux_info[0].pin);
@@ -4061,7 +4059,6 @@ static int cx_auto_init(struct hda_codec *codec)
        cx_auto_init_output(codec);
        cx_auto_init_input(codec);
        cx_auto_init_digital(codec);
-       snd_hda_jack_report_sync(codec);
        snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
        return 0;
 }
@@ -4262,7 +4259,7 @@ static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx,
 
        if (get_wcaps(codec, mux) & AC_WCAP_OUT_AMP) {
                spec->imux_info[idx].boost = mux;
-               return cx_auto_add_volume(codec, label, " Boost", 0,
+               return cx_auto_add_volume(codec, label, " Boost", cidx,
                                          mux, HDA_OUTPUT);
        }
        return 0;
@@ -4395,8 +4392,8 @@ static const struct hda_codec_ops cx_auto_patch_ops = {
        .build_pcms = conexant_build_pcms,
        .init = cx_auto_init,
        .free = conexant_free,
-       .unsol_event = cx_auto_unsol_event,
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+       .unsol_event = snd_hda_jack_unsol_event,
+#ifdef CONFIG_PM
        .suspend = conexant_suspend,
 #endif
        .reboot_notify = snd_hda_shutup_pins,
@@ -4462,6 +4459,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410),
        SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
        {}
 };
index 8f23374fa6427198735f91b987656986052a8773..71555cc54db1686519b8bd20f168d4fe5babbcad 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/jack.h>
+#include <sound/asoundef.h>
+#include <sound/tlv.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 #include "hda_jack.h"
@@ -71,6 +73,9 @@ struct hdmi_spec_per_pin {
        struct hdmi_eld sink_eld;
        struct delayed_work work;
        int repoll_count;
+       bool non_pcm;
+       bool chmap_set;         /* channel-map override by ALSA API? */
+       unsigned char chmap[8]; /* ALSA API channel-map */
 };
 
 struct hdmi_spec {
@@ -80,6 +85,7 @@ struct hdmi_spec {
        int num_pins;
        struct hdmi_spec_per_pin pins[MAX_HDMI_PINS];
        struct hda_pcm pcm_rec[MAX_HDMI_PINS];
+       unsigned int channels_max; /* max over all cvts */
 
        /*
         * Non-generic ATI/NVIDIA specific
@@ -469,6 +475,17 @@ static void init_channel_allocations(void)
        }
 }
 
+static int get_channel_allocation_order(int ca)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+               if (channel_allocations[i].ca_index == ca)
+                       break;
+       }
+       return i;
+}
+
 /*
  * The transformation takes two steps:
  *
@@ -535,24 +552,36 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec,
 }
 
 
-static void hdmi_setup_channel_mapping(struct hda_codec *codec,
+static void hdmi_std_setup_channel_mapping(struct hda_codec *codec,
                                       hda_nid_t pin_nid,
+                                      bool non_pcm,
                                       int ca)
 {
        int i;
        int err;
+       int order;
+       int non_pcm_mapping[8];
+
+       order = get_channel_allocation_order(ca);
 
        if (hdmi_channel_mapping[ca][1] == 0) {
-               for (i = 0; i < channel_allocations[ca].channels; i++)
+               for (i = 0; i < channel_allocations[order].channels; i++)
                        hdmi_channel_mapping[ca][i] = i | (i << 4);
                for (; i < 8; i++)
                        hdmi_channel_mapping[ca][i] = 0xf | (i << 4);
        }
 
+       if (non_pcm) {
+               for (i = 0; i < channel_allocations[order].channels; i++)
+                       non_pcm_mapping[i] = i | (i << 4);
+               for (; i < 8; i++)
+                       non_pcm_mapping[i] = 0xf | (i << 4);
+       }
+
        for (i = 0; i < 8; i++) {
                err = snd_hda_codec_write(codec, pin_nid, 0,
                                          AC_VERB_SET_HDMI_CHAN_SLOT,
-                                         hdmi_channel_mapping[ca][i]);
+                                         non_pcm ? non_pcm_mapping[i] : hdmi_channel_mapping[ca][i]);
                if (err) {
                        snd_printdd(KERN_NOTICE
                                    "HDMI: channel mapping failed\n");
@@ -563,6 +592,136 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec,
        hdmi_debug_channel_mapping(codec, pin_nid);
 }
 
+struct channel_map_table {
+       unsigned char map;              /* ALSA API channel map position */
+       unsigned char cea_slot;         /* CEA slot value */
+       int spk_mask;                   /* speaker position bit mask */
+};
+
+static struct channel_map_table map_tables[] = {
+       { SNDRV_CHMAP_FL,       0x00,   FL },
+       { SNDRV_CHMAP_FR,       0x01,   FR },
+       { SNDRV_CHMAP_RL,       0x04,   RL },
+       { SNDRV_CHMAP_RR,       0x05,   RR },
+       { SNDRV_CHMAP_LFE,      0x02,   LFE },
+       { SNDRV_CHMAP_FC,       0x03,   FC },
+       { SNDRV_CHMAP_RLC,      0x06,   RLC },
+       { SNDRV_CHMAP_RRC,      0x07,   RRC },
+       {} /* terminator */
+};
+
+/* from ALSA API channel position to speaker bit mask */
+static int to_spk_mask(unsigned char c)
+{
+       struct channel_map_table *t = map_tables;
+       for (; t->map; t++) {
+               if (t->map == c)
+                       return t->spk_mask;
+       }
+       return 0;
+}
+
+/* from ALSA API channel position to CEA slot */
+static int to_cea_slot(unsigned char c)
+{
+       struct channel_map_table *t = map_tables;
+       for (; t->map; t++) {
+               if (t->map == c)
+                       return t->cea_slot;
+       }
+       return 0x0f;
+}
+
+/* from CEA slot to ALSA API channel position */
+static int from_cea_slot(unsigned char c)
+{
+       struct channel_map_table *t = map_tables;
+       for (; t->map; t++) {
+               if (t->cea_slot == c)
+                       return t->map;
+       }
+       return 0;
+}
+
+/* from speaker bit mask to ALSA API channel position */
+static int spk_to_chmap(int spk)
+{
+       struct channel_map_table *t = map_tables;
+       for (; t->map; t++) {
+               if (t->spk_mask == spk)
+                       return t->map;
+       }
+       return 0;
+}
+
+/* get the CA index corresponding to the given ALSA API channel map */
+static int hdmi_manual_channel_allocation(int chs, unsigned char *map)
+{
+       int i, spks = 0, spk_mask = 0;
+
+       for (i = 0; i < chs; i++) {
+               int mask = to_spk_mask(map[i]);
+               if (mask) {
+                       spk_mask |= mask;
+                       spks++;
+               }
+       }
+
+       for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+               if ((chs == channel_allocations[i].channels ||
+                    spks == channel_allocations[i].channels) &&
+                   (spk_mask & channel_allocations[i].spk_mask) ==
+                               channel_allocations[i].spk_mask)
+                       return channel_allocations[i].ca_index;
+       }
+       return -1;
+}
+
+/* set up the channel slots for the given ALSA API channel map */
+static int hdmi_manual_setup_channel_mapping(struct hda_codec *codec,
+                                            hda_nid_t pin_nid,
+                                            int chs, unsigned char *map)
+{
+       int i;
+       for (i = 0; i < 8; i++) {
+               int val, err;
+               if (i < chs)
+                       val = to_cea_slot(map[i]);
+               else
+                       val = 0xf;
+               val |= (i << 4);
+               err = snd_hda_codec_write(codec, pin_nid, 0,
+                                         AC_VERB_SET_HDMI_CHAN_SLOT, val);
+               if (err)
+                       return -EINVAL;
+       }
+       return 0;
+}
+
+/* store ALSA API channel map from the current default map */
+static void hdmi_setup_fake_chmap(unsigned char *map, int ca)
+{
+       int i;
+       for (i = 0; i < 8; i++) {
+               if (i < channel_allocations[ca].channels)
+                       map[i] = from_cea_slot((hdmi_channel_mapping[ca][i] >> 4) & 0x0f);
+               else
+                       map[i] = 0;
+       }
+}
+
+static void hdmi_setup_channel_mapping(struct hda_codec *codec,
+                                      hda_nid_t pin_nid, bool non_pcm, int ca,
+                                      int channels, unsigned char *map)
+{
+       if (!non_pcm && map) {
+               hdmi_manual_setup_channel_mapping(codec, pin_nid,
+                                                 channels, map);
+       } else {
+               hdmi_std_setup_channel_mapping(codec, pin_nid, non_pcm, ca);
+               hdmi_setup_fake_chmap(map, ca);
+       }
+}
 
 /*
  * Audio InfoFrame routines
@@ -686,7 +845,8 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
 }
 
 static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
-                                       struct snd_pcm_substream *substream)
+                                      bool non_pcm,
+                                      struct snd_pcm_substream *substream)
 {
        struct hdmi_spec *spec = codec->spec;
        struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
@@ -700,7 +860,12 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
        if (!eld->monitor_present)
                return;
 
-       ca = hdmi_channel_allocation(eld, channels);
+       if (!non_pcm && per_pin->chmap_set)
+               ca = hdmi_manual_channel_allocation(channels, per_pin->chmap);
+       else
+               ca = hdmi_channel_allocation(eld, channels);
+       if (ca < 0)
+               ca = 0;
 
        memset(&ai, 0, sizeof(ai));
        if (eld->conn_type == 0) { /* HDMI */
@@ -737,12 +902,21 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
                            "pin=%d channels=%d\n",
                            pin_nid,
                            channels);
-               hdmi_setup_channel_mapping(codec, pin_nid, ca);
+               hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
+                                          channels, per_pin->chmap);
                hdmi_stop_infoframe_trans(codec, pin_nid);
                hdmi_fill_audio_infoframe(codec, pin_nid,
                                            ai.bytes, sizeof(ai));
                hdmi_start_infoframe_trans(codec, pin_nid);
+       } else {
+               /* For non-pcm audio switch, setup new channel mapping
+                * accordingly */
+               if (per_pin->non_pcm != non_pcm)
+                       hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
+                                                  channels, per_pin->chmap);
        }
+
+       per_pin->non_pcm = non_pcm;
 }
 
 
@@ -1035,6 +1209,7 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
        per_pin = &spec->pins[pin_idx];
 
        per_pin->pin_nid = pin_nid;
+       per_pin->non_pcm = false;
 
        err = hdmi_read_pin_conn(codec, pin_idx);
        if (err < 0)
@@ -1064,8 +1239,11 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
 
        per_cvt->cvt_nid = cvt_nid;
        per_cvt->channels_min = 2;
-       if (chans <= 16)
+       if (chans <= 16) {
                per_cvt->channels_max = chans;
+               if (chans > spec->channels_max)
+                       spec->channels_max = chans;
+       }
 
        err = snd_hda_query_supported_pcm(codec, cvt_nid,
                                          &per_cvt->rates,
@@ -1115,7 +1293,7 @@ static int hdmi_parse_codec(struct hda_codec *codec)
         * can be lost and presence sense verb will become inaccurate if the
         * HDA link is powered off at hot plug or hw initialization time.
         */
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        if (!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) &
              AC_PWRST_EPSS))
                codec->bus->power_keep_link_on = 1;
@@ -1133,6 +1311,19 @@ static char *get_hdmi_pcm_name(int idx)
        return &names[idx][0];
 }
 
+static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
+{
+       struct hda_spdif_out *spdif;
+       bool non_pcm;
+
+       mutex_lock(&codec->spdif_mutex);
+       spdif = snd_hda_spdif_out_of_nid(codec, cvt_nid);
+       non_pcm = !!(spdif->status & IEC958_AES0_NONAUDIO);
+       mutex_unlock(&codec->spdif_mutex);
+       return non_pcm;
+}
+
+
 /*
  * HDMI callbacks
  */
@@ -1148,10 +1339,13 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
        int pin_idx = hinfo_to_pin_index(spec, hinfo);
        hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid;
        int pinctl;
+       bool non_pcm;
+
+       non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
 
        hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels);
 
-       hdmi_setup_audio_infoframe(codec, pin_idx, substream);
+       hdmi_setup_audio_infoframe(codec, pin_idx, non_pcm, substream);
 
        pinctl = snd_hda_codec_read(codec, pin_nid, 0,
                                    AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
@@ -1200,7 +1394,10 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
                                    AC_VERB_SET_PIN_WIDGET_CONTROL,
                                    pinctl & ~PIN_OUT);
                snd_hda_spdif_ctls_unassign(codec, pin_idx);
+               per_pin->chmap_set = false;
+               memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
        }
+
        return 0;
 }
 
@@ -1211,6 +1408,135 @@ static const struct hda_pcm_ops generic_ops = {
        .cleanup = generic_hdmi_playback_pcm_cleanup,
 };
 
+/*
+ * ALSA API channel-map control callbacks
+ */
+static int hdmi_chmap_ctl_info(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_info *uinfo)
+{
+       struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+       struct hda_codec *codec = info->private_data;
+       struct hdmi_spec *spec = codec->spec;
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = spec->channels_max;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = SNDRV_CHMAP_LAST;
+       return 0;
+}
+
+static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+                             unsigned int size, unsigned int __user *tlv)
+{
+       struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+       struct hda_codec *codec = info->private_data;
+       struct hdmi_spec *spec = codec->spec;
+       const unsigned int valid_mask =
+               FL | FR | RL | RR | LFE | FC | RLC | RRC;
+       unsigned int __user *dst;
+       int chs, count = 0;
+
+       if (size < 8)
+               return -ENOMEM;
+       if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv))
+               return -EFAULT;
+       size -= 8;
+       dst = tlv + 2;
+       for (chs = 2; chs <= spec->channels_max; chs++) {
+               int i, c;
+               struct cea_channel_speaker_allocation *cap;
+               cap = channel_allocations;
+               for (i = 0; i < ARRAY_SIZE(channel_allocations); i++, cap++) {
+                       int chs_bytes = chs * 4;
+                       if (cap->channels != chs)
+                               continue;
+                       if (cap->spk_mask & ~valid_mask)
+                               continue;
+                       if (size < 8)
+                               return -ENOMEM;
+                       if (put_user(SNDRV_CTL_TLVT_CHMAP_VAR, dst) ||
+                           put_user(chs_bytes, dst + 1))
+                               return -EFAULT;
+                       dst += 2;
+                       size -= 8;
+                       count += 8;
+                       if (size < chs_bytes)
+                               return -ENOMEM;
+                       size -= chs_bytes;
+                       count += chs_bytes;
+                       for (c = 7; c >= 0; c--) {
+                               int spk = cap->speakers[c];
+                               if (!spk)
+                                       continue;
+                               if (put_user(spk_to_chmap(spk), dst))
+                                       return -EFAULT;
+                               dst++;
+                       }
+               }
+       }
+       if (put_user(count, tlv + 1))
+               return -EFAULT;
+       return 0;
+}
+
+static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+       struct hda_codec *codec = info->private_data;
+       struct hdmi_spec *spec = codec->spec;
+       int pin_idx = kcontrol->private_value;
+       struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(per_pin->chmap); i++)
+               ucontrol->value.integer.value[i] = per_pin->chmap[i];
+       return 0;
+}
+
+static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+       struct hda_codec *codec = info->private_data;
+       struct hdmi_spec *spec = codec->spec;
+       int pin_idx = kcontrol->private_value;
+       struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
+       unsigned int ctl_idx;
+       struct snd_pcm_substream *substream;
+       unsigned char chmap[8];
+       int i, ca, prepared = 0;
+
+       ctl_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+       substream = snd_pcm_chmap_substream(info, ctl_idx);
+       if (!substream || !substream->runtime)
+               return -EBADFD;
+       switch (substream->runtime->status->state) {
+       case SNDRV_PCM_STATE_OPEN:
+       case SNDRV_PCM_STATE_SETUP:
+               break;
+       case SNDRV_PCM_STATE_PREPARED:
+               prepared = 1;
+               break;
+       default:
+               return -EBUSY;
+       }
+       memset(chmap, 0, sizeof(chmap));
+       for (i = 0; i < ARRAY_SIZE(chmap); i++)
+               chmap[i] = ucontrol->value.integer.value[i];
+       if (!memcmp(chmap, per_pin->chmap, sizeof(chmap)))
+               return 0;
+       ca = hdmi_manual_channel_allocation(ARRAY_SIZE(chmap), chmap);
+       if (ca < 0)
+               return -EINVAL;
+       per_pin->chmap_set = true;
+       memcpy(per_pin->chmap, chmap, sizeof(chmap));
+       if (prepared)
+               hdmi_setup_audio_infoframe(codec, pin_idx, per_pin->non_pcm,
+                                          substream);
+
+       return 0;
+}
+
 static int generic_hdmi_build_pcms(struct hda_codec *codec)
 {
        struct hdmi_spec *spec = codec->spec;
@@ -1223,6 +1549,7 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
                info = &spec->pcm_rec[pin_idx];
                info->name = get_hdmi_pcm_name(pin_idx);
                info->pcm_type = HDA_PCM_TYPE_HDMI;
+               info->own_chmap = true;
 
                pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
                pstr->substreams = 1;
@@ -1280,6 +1607,27 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
                hdmi_present_sense(per_pin, 0);
        }
 
+       /* add channel maps */
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               struct snd_pcm_chmap *chmap;
+               struct snd_kcontrol *kctl;
+               int i;
+               err = snd_pcm_add_chmap_ctls(codec->pcm_info[pin_idx].pcm,
+                                            SNDRV_PCM_STREAM_PLAYBACK,
+                                            NULL, 0, pin_idx, &chmap);
+               if (err < 0)
+                       return err;
+               /* override handlers */
+               chmap->private_data = codec;
+               kctl = chmap->kctl;
+               for (i = 0; i < kctl->count; i++)
+                       kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
+               kctl->info = hdmi_chmap_ctl_info;
+               kctl->get = hdmi_chmap_ctl_get;
+               kctl->put = hdmi_chmap_ctl_put;
+               kctl->tlv.c = hdmi_chmap_ctl_tlv;
+       }
+
        return 0;
 }
 
@@ -1311,7 +1659,6 @@ static int generic_hdmi_init(struct hda_codec *codec)
                hdmi_init_pin(codec, pin_nid);
                snd_hda_jack_detect_enable(codec, pin_nid, pin_nid);
        }
-       snd_hda_jack_report_sync(codec);
        return 0;
 }
 
@@ -1428,7 +1775,6 @@ static int simple_playback_init(struct hda_codec *codec)
                snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE,
                                    AMP_OUT_UNMUTE);
        snd_hda_jack_detect_enable(codec, pin, pin);
-       snd_hda_jack_report_sync(codec);
        return 0;
 }
 
@@ -1809,6 +2155,43 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec)
        return 0;
 }
 
+static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int err = simple_playback_build_pcms(codec);
+       spec->pcm_rec[0].own_chmap = true;
+       return err;
+}
+
+static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct snd_pcm_chmap *chmap;
+       int err;
+
+       err = simple_playback_build_controls(codec);
+       if (err < 0)
+               return err;
+
+       /* add channel maps */
+       err = snd_pcm_add_chmap_ctls(spec->pcm_rec[0].pcm,
+                                    SNDRV_PCM_STREAM_PLAYBACK,
+                                    snd_pcm_alt_chmaps, 8, 0, &chmap);
+       if (err < 0)
+               return err;
+       switch (codec->preset->id) {
+       case 0x10de0002:
+       case 0x10de0003:
+       case 0x10de0005:
+       case 0x10de0006:
+               chmap->channel_mask = (1U << 2) | (1U << 8);
+               break;
+       case 0x10de0007:
+               chmap->channel_mask = (1U << 2) | (1U << 6) | (1U << 8);
+       }
+       return 0;
+}
+
 static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
 {
        struct hdmi_spec *spec;
@@ -1819,6 +2202,8 @@ static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
        spec->multiout.max_channels = 8;
        spec->pcm_playback = nvhdmi_pcm_playback_8ch_7x;
        codec->patch_ops.init = nvhdmi_7x_init_8ch;
+       codec->patch_ops.build_pcms = nvhdmi_7x_8ch_build_pcms;
+       codec->patch_ops.build_controls = nvhdmi_7x_8ch_build_controls;
 
        /* Initialize the audio infoframe channel mask and checksum to something
         * valid */
index 4f81dd44c837e1de6b1de327f457bcb0fcc8f16f..8568aee56e2daaef1c77a8d19df4227af57eccc3 100644 (file)
@@ -174,7 +174,7 @@ struct alc_spec {
 
        /* hooks */
        void (*init_hook)(struct hda_codec *codec);
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        void (*power_hook)(struct hda_codec *codec);
 #endif
        void (*shutup)(struct hda_codec *codec);
@@ -215,7 +215,7 @@ struct alc_spec {
        /* for virtual master */
        hda_nid_t vmaster_nid;
        struct hda_vmaster_mute_hook vmaster_mute;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        struct hda_loopback_check loopback;
        int num_loopbacks;
        struct hda_amp_list loopback_list[8];
@@ -594,7 +594,7 @@ static void call_update_outputs(struct hda_codec *codec)
 }
 
 /* standard HP-automute helper */
-static void alc_hp_automute(struct hda_codec *codec)
+static void alc_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
 {
        struct alc_spec *spec = codec->spec;
 
@@ -607,7 +607,7 @@ static void alc_hp_automute(struct hda_codec *codec)
 }
 
 /* standard line-out-automute helper */
-static void alc_line_automute(struct hda_codec *codec)
+static void alc_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
 {
        struct alc_spec *spec = codec->spec;
 
@@ -627,7 +627,7 @@ static void alc_line_automute(struct hda_codec *codec)
        snd_hda_get_conn_index(codec, mux, nid, 0)
 
 /* standard mic auto-switch helper */
-static void alc_mic_automute(struct hda_codec *codec)
+static void alc_mic_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
 {
        struct alc_spec *spec = codec->spec;
        hda_nid_t *pins = spec->imux_pins;
@@ -648,25 +648,8 @@ static void alc_mic_automute(struct hda_codec *codec)
                alc_mux_select(codec, 0, spec->int_mic_idx, false);
 }
 
-/* handle the specified unsol action (ALC_XXX_EVENT) */
-static void alc_exec_unsol_event(struct hda_codec *codec, int action)
-{
-       switch (action) {
-       case ALC_HP_EVENT:
-               alc_hp_automute(codec);
-               break;
-       case ALC_FRONT_EVENT:
-               alc_line_automute(codec);
-               break;
-       case ALC_MIC_EVENT:
-               alc_mic_automute(codec);
-               break;
-       }
-       snd_hda_jack_report_sync(codec);
-}
-
 /* update the master volume per volume-knob's unsol event */
-static void alc_update_knob_master(struct hda_codec *codec, hda_nid_t nid)
+static void alc_update_knob_master(struct hda_codec *codec, struct hda_jack_tbl *jack)
 {
        unsigned int val;
        struct snd_kcontrol *kctl;
@@ -678,7 +661,7 @@ static void alc_update_knob_master(struct hda_codec *codec, hda_nid_t nid)
        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
        if (!uctl)
                return;
-       val = snd_hda_codec_read(codec, nid, 0,
+       val = snd_hda_codec_read(codec, jack->nid, 0,
                                 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
        val &= HDA_AMP_VOLMASK;
        uctl->value.integer.value[0] = val;
@@ -687,37 +670,19 @@ static void alc_update_knob_master(struct hda_codec *codec, hda_nid_t nid)
        kfree(uctl);
 }
 
-/* unsolicited event for HP jack sensing */
-static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
+static void alc880_unsol_event(struct hda_codec *codec, unsigned int res)
 {
-       int action;
-
-       if (codec->vendor_id == 0x10ec0880)
-               res >>= 28;
-       else
-               res >>= 26;
-       action = snd_hda_jack_get_action(codec, res);
-       if (action == ALC_DCVOL_EVENT) {
-               /* Execute the dc-vol event here as it requires the NID
-                * but we don't pass NID to alc_exec_unsol_event().
-                * Once when we convert all static quirks to the auto-parser,
-                * this can be integerated into there.
-                */
-               struct hda_jack_tbl *jack;
-               jack = snd_hda_jack_tbl_get_from_tag(codec, res);
-               if (jack)
-                       alc_update_knob_master(codec, jack->nid);
-               return;
-       }
-       alc_exec_unsol_event(codec, action);
+       /* For some reason, the res given from ALC880 is broken.
+          Here we adjust it properly. */
+       snd_hda_jack_unsol_event(codec, res >> 2);
 }
 
 /* call init functions of standard auto-mute helpers */
 static void alc_inithook(struct hda_codec *codec)
 {
-       alc_hp_automute(codec);
-       alc_line_automute(codec);
-       alc_mic_automute(codec);
+       alc_hp_automute(codec, NULL);
+       alc_line_automute(codec, NULL);
+       alc_mic_automute(codec, NULL);
 }
 
 /* additional initialization for ALC888 variants */
@@ -999,7 +964,8 @@ static void alc_init_automute(struct hda_codec *codec)
                        continue;
                snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
                            nid);
-               snd_hda_jack_detect_enable(codec, nid, ALC_HP_EVENT);
+               snd_hda_jack_detect_enable_callback(codec, nid, ALC_HP_EVENT,
+                                                   alc_hp_automute);
                spec->detect_hp = 1;
        }
 
@@ -1011,10 +977,10 @@ static void alc_init_automute(struct hda_codec *codec)
                                        continue;
                                snd_printdd("realtek: Enable Line-Out "
                                            "auto-muting on NID 0x%x\n", nid);
-                               snd_hda_jack_detect_enable(codec, nid,
-                                                          ALC_FRONT_EVENT);
+                               snd_hda_jack_detect_enable_callback(codec, nid, ALC_FRONT_EVENT,
+                                                                   alc_line_automute);
                                spec->detect_lo = 1;
-               }
+                       }
                spec->automute_lo_possible = spec->detect_hp;
        }
 
@@ -1110,10 +1076,12 @@ static bool alc_auto_mic_check_imux(struct hda_codec *codec)
                return false; /* no corresponding imux */
        }
 
-       snd_hda_jack_detect_enable(codec, spec->ext_mic_pin, ALC_MIC_EVENT);
+       snd_hda_jack_detect_enable_callback(codec, spec->ext_mic_pin,
+                                           ALC_MIC_EVENT, alc_mic_automute);
        if (spec->dock_mic_pin)
-               snd_hda_jack_detect_enable(codec, spec->dock_mic_pin,
-                                          ALC_MIC_EVENT);
+               snd_hda_jack_detect_enable_callback(codec, spec->dock_mic_pin,
+                                                   ALC_MIC_EVENT,
+                                                   alc_mic_automute);
 
        spec->auto_mic_valid_imux = 1;
        spec->auto_mic = 1;
@@ -2053,13 +2021,11 @@ static int alc_init(struct hda_codec *codec)
 
        alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
 
-       snd_hda_jack_report_sync(codec);
-
        hda_call_check_power_status(codec, 0x01);
        return 0;
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 {
        struct alc_spec *spec = codec->spec;
@@ -2289,6 +2255,8 @@ static int alc_build_pcms(struct hda_codec *codec)
                        p = &alc_pcm_analog_playback;
                info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
                info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
+                       spec->multiout.max_channels;
        }
        if (spec->adc_nids) {
                p = spec->stream_analog_capture;
@@ -2437,7 +2405,7 @@ static void alc_free(struct hda_codec *codec)
        snd_hda_detach_beep_device(codec);
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static void alc_power_eapd(struct hda_codec *codec)
 {
        alc_auto_setup_eapd(codec, false);
@@ -2473,17 +2441,18 @@ static const struct hda_codec_ops alc_patch_ops = {
        .build_pcms = alc_build_pcms,
        .init = alc_init,
        .free = alc_free,
-       .unsol_event = alc_unsol_event,
+       .unsol_event = snd_hda_jack_unsol_event,
 #ifdef CONFIG_PM
        .resume = alc_resume,
 #endif
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        .suspend = alc_suspend,
        .check_power_status = alc_check_power_status,
 #endif
        .reboot_notify = alc_shutup,
 };
 
+
 /* replace the codec chip_name with the given string */
 static int alc_codec_rename(struct hda_codec *codec, const char *name)
 {
@@ -2633,7 +2602,7 @@ static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch,
        return channel_name[ch];
 }
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 /* add the powersave loopback-list entry */
 static void add_loopback_list(struct alc_spec *spec, hda_nid_t mix, int idx)
 {
@@ -4447,7 +4416,7 @@ static void alc880_fixup_vol_knob(struct hda_codec *codec,
                                  const struct alc_fixup *fix, int action)
 {
        if (action == ALC_FIXUP_ACT_PROBE)
-               snd_hda_jack_detect_enable(codec, 0x21, ALC_DCVOL_EVENT);
+               snd_hda_jack_detect_enable_callback(codec, 0x21, ALC_DCVOL_EVENT, alc_update_knob_master);
 }
 
 static const struct alc_fixup alc880_fixups[] = {
@@ -4812,6 +4781,8 @@ static int patch_alc880(struct hda_codec *codec)
        }
 
        codec->patch_ops = alc_patch_ops;
+       codec->patch_ops.unsol_event = alc880_unsol_event;
+
 
        alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
 
@@ -4866,7 +4837,8 @@ static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
                spec->detect_hp = 1;
                spec->automute_speaker = 1;
                spec->autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
-               snd_hda_jack_detect_enable(codec, 0x0f, ALC_HP_EVENT);
+               snd_hda_jack_detect_enable_callback(codec, 0x0f, ALC_HP_EVENT,
+                                                   alc_hp_automute);
                snd_hda_gen_add_verbs(&spec->gen, alc_gpio1_init_verbs);
        }
 }
@@ -6189,6 +6161,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_MIC2_MUTE_LED),
        SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_DMIC),
        SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
        SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
@@ -6334,6 +6307,12 @@ static int patch_alc269(struct hda_codec *codec)
 
        spec = codec->spec;
 
+       alc_pick_fixup(codec, alc269_fixup_models,
+                      alc269_fixup_tbl, alc269_fixups);
+       alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+
+       alc_auto_parse_customize_define(codec);
+
        if (codec->vendor_id == 0x10ec0269) {
                spec->codec_variant = ALC269_TYPE_ALC269VA;
                switch (alc_get_coef0(codec) & 0x00f0) {
@@ -6361,12 +6340,6 @@ static int patch_alc269(struct hda_codec *codec)
                alc269_fill_coef(codec);
        }
 
-       alc_pick_fixup(codec, alc269_fixup_models,
-                      alc269_fixup_tbl, alc269_fixups);
-       alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
-
-       alc_auto_parse_customize_define(codec);
-
        /* automatic parse from the BIOS config */
        err = alc269_parse_auto_config(codec);
        if (err < 0)
@@ -6503,7 +6476,7 @@ static int patch_alc861(struct hda_codec *codec)
        }
 
        codec->patch_ops = alc_patch_ops;
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
        spec->power_hook = alc_power_eapd;
 #endif
 
@@ -7068,6 +7041,8 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
        { .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 },
        { .id = 0x10ec0280, .name = "ALC280", .patch = patch_alc269 },
        { .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 },
+       { .id = 0x10ec0283, .name = "ALC283", .patch = patch_alc269 },
+       { .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 },
        { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
          .patch = patch_alc861 },
        { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
index 3d4722f0a1cacba8fc9a923f22dbf767433dbd6c..fe163547f906cae4f6d1d1ea88ee7a7a1b599951 100644 (file)
@@ -103,6 +103,7 @@ enum {
        STAC_HP_ZEPHYR,
        STAC_92HD83XXX_HP_LED,
        STAC_92HD83XXX_HP_INV_LED,
+       STAC_92HD83XXX_HP_MIC_LED,
        STAC_92HD83XXX_MODELS
 };
 
@@ -215,6 +216,9 @@ struct sigmatel_spec {
        unsigned int vref_mute_led_nid; /* pin NID for mute-LED vref control */
        unsigned int vref_led;
 
+       unsigned int mic_mute_led_gpio; /* capture mute LED GPIO */
+       bool mic_mute_led_on; /* current mic mute state */
+
        /* stream */
        unsigned int stream_delay;
 
@@ -1679,6 +1683,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
        [STAC_HP_ZEPHYR] = "hp-zephyr",
        [STAC_92HD83XXX_HP_LED] = "hp-led",
        [STAC_92HD83XXX_HP_INV_LED] = "hp-inv-led",
+       [STAC_92HD83XXX_HP_MIC_LED] = "hp-mic-led",
 };
 
 static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
@@ -1703,6 +1708,8 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
                          "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B,
                          "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18df,
+                         "HP Folio", STAC_92HD83XXX_HP_MIC_LED),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388,
                          "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389,
@@ -2791,18 +2798,27 @@ stac_control_new(struct sigmatel_spec *spec,
        return knew;
 }
 
-static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
-                                    const struct snd_kcontrol_new *ktemp,
-                                    int idx, const char *name,
-                                    unsigned long val)
+static struct snd_kcontrol_new *
+add_control_temp(struct sigmatel_spec *spec,
+                const struct snd_kcontrol_new *ktemp,
+                int idx, const char *name,
+                unsigned long val)
 {
        struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name,
                                                         HDA_SUBDEV_AMP_FLAG);
        if (!knew)
-               return -ENOMEM;
+               return NULL;
        knew->index = idx;
        knew->private_value = val;
-       return 0;
+       return knew;
+}
+
+static int stac92xx_add_control_temp(struct sigmatel_spec *spec,
+                                    const struct snd_kcontrol_new *ktemp,
+                                    int idx, const char *name,
+                                    unsigned long val)
+{
+       return add_control_temp(spec, ktemp, idx, name, val) ? 0 : -ENOMEM;
 }
 
 static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec,
@@ -3226,9 +3242,12 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
                                idx = i;
                                break;
                        case AUTO_PIN_SPEAKER_OUT:
-                               name = "Speaker";
-                               idx = i;
-                               break;
+                               if (num_outs <= 1) {
+                                       name = "Speaker";
+                                       idx = i;
+                                       break;
+                               }
+                               /* Fall through in case of multi speaker outs */
                        default:
                                name = chname[i];
                                idx = 0;
@@ -3242,18 +3261,56 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
        return 0;
 }
 
+static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
+                         unsigned int dir_mask, unsigned int data);
+
+/* hook for controlling mic-mute LED GPIO */
+static int stac92xx_capture_sw_put_led(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       int err;
+       bool mute;
+
+       err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+       if (err <= 0)
+               return err;
+       mute = !(ucontrol->value.integer.value[0] &&
+                ucontrol->value.integer.value[1]);
+       if (spec->mic_mute_led_on != mute) {
+               spec->mic_mute_led_on = mute;
+               if (mute)
+                       spec->gpio_data |= spec->mic_mute_led_gpio;
+               else
+                       spec->gpio_data &= ~spec->mic_mute_led_gpio;
+               stac_gpio_set(codec, spec->gpio_mask,
+                             spec->gpio_dir, spec->gpio_data);
+       }
+       return err;
+}
+
 static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol,
                                    unsigned long sw, int idx)
 {
+       struct sigmatel_spec *spec = codec->spec;
+       struct snd_kcontrol_new *knew;
        int err;
+
        err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx,
                                       "Capture Volume", vol);
        if (err < 0)
                return err;
-       err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_MUTE, idx,
-                                      "Capture Switch", sw);
-       if (err < 0)
-               return err;
+
+       knew = add_control_temp(spec,
+                               &stac92xx_control_templates[STAC_CTL_WIDGET_MUTE],
+                               idx, "Capture Switch", sw);
+       if (!knew)
+               return -ENOMEM;
+       /* add a LED hook for some HP laptops */
+       if (spec->mic_mute_led_gpio)
+               knew->put = stac92xx_capture_sw_put_led;
+
        return 0;
 }
 
@@ -4155,6 +4212,9 @@ static int stac_add_event(struct hda_codec *codec, hda_nid_t nid,
        return 0;
 }
 
+static void handle_unsol_event(struct hda_codec *codec,
+                              struct hda_jack_tbl *event);
+
 /* check if given nid is a valid pin and no other events are assigned
  * to it.  If OK, assign the event, set the unsol flag, and returns 1.
  * Otherwise, returns zero.
@@ -4172,6 +4232,7 @@ static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
        if (event->action && event->action != type)
                return 0;
        event->action = type;
+       event->callback = handle_unsol_event;
        snd_hda_jack_detect_enable(codec, nid, 0);
        return 1;
 }
@@ -4418,8 +4479,6 @@ static int stac92xx_init(struct hda_codec *codec)
                stac_toggle_power_map(codec, nid, 0);
        }
 
-       snd_hda_jack_report_sync(codec);
-
        /* sync mute LED */
        if (spec->gpio_led) {
                if (spec->vmaster_mute.hook)
@@ -4812,20 +4871,6 @@ static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid)
        handle_unsol_event(codec, event);
 }
 
-static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       struct hda_jack_tbl *event;
-       int tag;
-
-       tag = (res >> 26) & 0x7f;
-       event = snd_hda_jack_tbl_get_from_tag(codec, tag);
-       if (!event)
-               return;
-       event->jack_dirty = 1;
-       handle_unsol_event(codec, event);
-       snd_hda_jack_report_sync(codec);
-}
-
 static int hp_blike_system(u32 subsystem_id);
 
 static void set_hp_led_gpio(struct hda_codec *codec)
@@ -5076,7 +5121,7 @@ static const struct hda_codec_ops stac92xx_patch_ops = {
        .build_pcms = stac92xx_build_pcms,
        .init = stac92xx_init,
        .free = stac92xx_free,
-       .unsol_event = stac92xx_unsol_event,
+       .unsol_event = snd_hda_jack_unsol_event,
 #ifdef CONFIG_PM
        .suspend = stac92xx_suspend,
        .resume = stac92xx_resume,
@@ -5578,6 +5623,9 @@ again:
        case STAC_92HD83XXX_HP_INV_LED:
                default_polarity = 1;
                break;
+       case STAC_92HD83XXX_HP_MIC_LED:
+               spec->mic_mute_led_gpio = 0x08; /* GPIO3 */
+               break;
        }
 
        if (find_mute_led_cfg(codec, default_polarity))
@@ -5596,6 +5644,13 @@ again:
                }
        }
 
+       if (spec->mic_mute_led_gpio) {
+               spec->gpio_mask |= spec->mic_mute_led_gpio;
+               spec->gpio_dir |= spec->mic_mute_led_gpio;
+               spec->mic_mute_led_on = true;
+               spec->gpio_data |= spec->mic_mute_led_gpio;
+       }
+
        err = stac92xx_parse_auto_config(codec);
        if (!err) {
                if (spec->board_config < 0) {
index 43077177691588ab03590cd0576369c54b55d266..5a45a912aedcc22ef543a57229fcfa26880c51b7 100644 (file)
@@ -1672,7 +1672,8 @@ static void via_hp_automute(struct hda_codec *codec)
        struct via_spec *spec = codec->spec;
 
        if (!spec->hp_independent_mode && spec->autocfg.hp_pins[0] &&
-           (spec->codec_type != VT1708 || spec->vt1708_jack_detect))
+           (spec->codec_type != VT1708 || spec->vt1708_jack_detect) &&
+           is_jack_detectable(codec, spec->autocfg.hp_pins[0]))
                present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]);
 
        if (spec->smart51_enabled)
@@ -1764,7 +1765,7 @@ static int via_suspend(struct hda_codec *codec)
 }
 #endif
 
-#ifdef CONFIG_SND_HDA_POWER_SAVE
+#ifdef CONFIG_PM
 static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
 {
        struct via_spec *spec = codec->spec;
@@ -1785,8 +1786,6 @@ static const struct hda_codec_ops via_patch_ops = {
        .unsol_event = via_unsol_event,
 #ifdef CONFIG_PM
        .suspend = via_suspend,
-#endif
-#ifdef CONFIG_SND_HDA_POWER_SAVE
        .check_power_status = via_check_power_status,
 #endif
 };
@@ -2815,7 +2814,6 @@ static int via_init(struct hda_codec *codec)
 
        via_hp_automute(codec);
        vt1708_update_hp_work(spec);
-       snd_hda_jack_report_sync(codec);
 
        return 0;
 }
@@ -3669,6 +3667,32 @@ static void set_widgets_power_state_vt2002P(struct hda_codec *codec)
                update_power_state(codec, 0x21, AC_PWRST_D3);
 }
 
+/*
+ * pin fix-up
+ */
+enum {
+       VIA_FIXUP_INTMIC_BOOST,
+};
+
+static void via_fixup_intmic_boost(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               override_mic_boost(codec, 0x30, 0, 2, 40);
+}
+
+static const struct hda_fixup via_fixups[] = {
+       [VIA_FIXUP_INTMIC_BOOST] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = via_fixup_intmic_boost,
+       },
+};
+
+static const struct snd_pci_quirk vt2002p_fixups[] = {
+       SND_PCI_QUIRK(0x1043, 0x8532, "Asus X202E", VIA_FIXUP_INTMIC_BOOST),
+       {}
+};
+
 /* patch for vt2002P */
 static int patch_vt2002P(struct hda_codec *codec)
 {
@@ -3685,6 +3709,9 @@ static int patch_vt2002P(struct hda_codec *codec)
        override_mic_boost(codec, 0x29, 0, 3, 40);
        add_secret_dac_path(codec);
 
+       snd_hda_pick_fixup(codec, NULL, vt2002p_fixups, via_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
        /* automatic parse from the BIOS config */
        err = via_parse_auto_config(codec);
        if (err < 0) {
index 3e4f8c12ffceeb7d48b117c50ebce743d408e243..20bcddea2eab19320d25299180368a815bc4f90f 100644 (file)
@@ -2103,7 +2103,7 @@ static int aureon_reset(struct snd_ice1712 *ice)
 /*
  * suspend/resume
  */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int aureon_resume(struct snd_ice1712 *ice)
 {
        struct aureon_spec *spec = ice->spec;
@@ -2160,7 +2160,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
                wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
        }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        ice->pm_resume = aureon_resume;
        ice->pm_suspend_enabled = 1;
 #endif
index 0da778a69ef8b47d9bc1af83791561e04b6d1069..d0e7d87f09f0ed4947462630906ec02249e583c6 100644 (file)
@@ -384,7 +384,7 @@ struct snd_ice1712 {
        char **ext_clock_names;
        int ext_clock_count;
        void (*pro_open)(struct snd_ice1712 *, struct snd_pcm_substream *);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        int (*pm_suspend)(struct snd_ice1712 *);
        int (*pm_resume)(struct snd_ice1712 *);
        unsigned int pm_suspend_enabled:1;
index bed9f34f4efee6b9556dbe23cf675242cbf7c0b4..3050a52792532ad3a58303f54a800dcc7c0ab883 100644 (file)
@@ -2792,7 +2792,7 @@ static void __devexit snd_vt1724_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_vt1724_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -2878,7 +2878,7 @@ static SIMPLE_DEV_PM_OPS(snd_vt1724_pm, snd_vt1724_suspend, snd_vt1724_resume);
 #define SND_VT1724_PM_OPS      &snd_vt1724_pm
 #else
 #define SND_VT1724_PM_OPS      NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver vt1724_driver = {
        .name = KBUILD_MODNAME,
index 98bc3b7681b5615f97d8e55f0a6fc947951382f0..14fd536b6452d6e5dda1ec01f12929a89c4cd7c0 100644 (file)
@@ -486,7 +486,7 @@ static int __devinit juli_add_controls(struct snd_ice1712 *ice)
  * suspend/resume
  * */
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int juli_resume(struct snd_ice1712 *ice)
 {
        struct snd_akm4xxx *ak = ice->akm;
@@ -652,7 +652,7 @@ static int __devinit juli_init(struct snd_ice1712 *ice)
 
        ice->spdif.ops.open = juli_spdif_in_open;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        ice->pm_resume = juli_resume;
        ice->pm_suspend = juli_suspend;
        ice->pm_suspend_enabled = 1;
index 075d5aa1fee003bef0dfaa4177ac21d010247277..7bf093c51ce5a5569f6cec1a1f9e53a88763236f 100644 (file)
@@ -1100,7 +1100,7 @@ static void ak4396_init(struct snd_ice1712 *ice)
                ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int prodigy_hd2_resume(struct snd_ice1712 *ice)
 {
        /* initialize ak4396 codec and restore previous mixer volumes */
@@ -1141,7 +1141,7 @@ static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice)
                return -ENOMEM;
        ice->spec = spec;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        ice->pm_resume = &prodigy_hd2_resume;
        ice->pm_suspend_enabled = 1;
 #endif
index cd553f592e2d12643558958b14693ccd87a6ac07..ea4b706c8d635925c248bfb497a021361d990a27 100644 (file)
@@ -1541,6 +1541,26 @@ static int __devinit snd_intel8x0_pcm1(struct intel8x0 *chip, int device,
                                              snd_dma_pci_data(chip->pci),
                                              rec->prealloc_size, rec->prealloc_max_size);
 
+       if (rec->ac97_idx == ICHD_PCMOUT && rec->playback_ops) {
+               struct snd_pcm_chmap *chmap;
+               int chs = 2;
+               if (rec->ac97_idx == ICHD_PCMOUT) {
+                       if (chip->multi8)
+                               chs = 8;
+                       else if (chip->multi6)
+                               chs = 6;
+                       else if (chip->multi4)
+                               chs = 4;
+               }
+               err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                                            snd_pcm_alt_chmaps, chs, 0,
+                                            &chmap);
+               if (err < 0)
+                       return err;
+               chmap->channel_mask = SND_PCM_CHMAP_MASK_2468;
+               chip->ac97[0]->chmaps[SNDRV_PCM_STREAM_PLAYBACK] = chmap;
+       }
+
        return 0;
 }
 
@@ -2206,7 +2226,7 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock,
                case DEVICE_INTEL_ICH4:
                        chip->spdif_idx = ICHD_SPBAR;
                        break;
-               };
+               }
        }
 
        chip->in_ac97_init = 1;
@@ -2620,7 +2640,7 @@ static int snd_intel8x0_free(struct intel8x0 *chip)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -2741,7 +2761,7 @@ static SIMPLE_DEV_PM_OPS(intel8x0_pm, intel8x0_suspend, intel8x0_resume);
 #define INTEL8X0_PM_OPS        &intel8x0_pm
 #else
 #define INTEL8X0_PM_OPS        NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #define INTEL8X0_TESTBUF_SIZE  32768   /* enough large for one shot */
 
index da44bb3f8e7aaf1c8c7ca35278d27c275010365c..4d551736531eebe546e4620768907e6775840ab2 100644 (file)
@@ -1008,7 +1008,7 @@ static int snd_intel8x0m_free(struct intel8x0m *chip)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -1067,7 +1067,7 @@ static SIMPLE_DEV_PM_OPS(intel8x0m_pm, intel8x0m_suspend, intel8x0m_resume);
 #define INTEL8X0M_PM_OPS       &intel8x0m_pm
 #else
 #define INTEL8X0M_PM_OPS       NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_PROC_FS
 static void snd_intel8x0m_proc_read(struct snd_info_entry * entry,
index e69ce5f9c31e036a9f4229d76fe9d8c21d9cefe8..8a67ce95f2468395a65474f8a7de194241570c35 100644 (file)
@@ -196,8 +196,8 @@ enum MonitorModeSelector {
 #define K1212_ADAT_BUF_SIZE    (K1212_ADAT_CHANNELS * 2 * kPlayBufferFrames * kNumBuffers)
 #define K1212_MAX_BUF_SIZE     (K1212_ANALOG_BUF_SIZE + K1212_ADAT_BUF_SIZE)
 
-#define k1212MinADCSens     0x7f
-#define k1212MaxADCSens     0x00
+#define k1212MinADCSens     0x00
+#define k1212MaxADCSens     0x7f
 #define k1212MaxVolume      0x7fff
 #define k1212MaxWaveVolume  0xffff
 #define k1212MinVolume      0x0000
index c85d1ffcc9558b5f64ed4e9aaea1963b7c8597c2..eb3cd3a4315eff8990b7f2d7162a6aaa640d35e6 100644 (file)
@@ -789,7 +789,7 @@ struct snd_m3 {
 
        unsigned int in_suspend;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        u16 *suspend_mem;
 #endif
 
@@ -2368,7 +2368,7 @@ static int snd_m3_free(struct snd_m3 *chip)
                outw(0, chip->iobase + HOST_INT_CTRL); /* disable ints */
        }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        vfree(chip->suspend_mem);
 #endif
 
@@ -2390,7 +2390,7 @@ static int snd_m3_free(struct snd_m3 *chip)
 /*
  * APM support
  */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int m3_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -2485,7 +2485,7 @@ static SIMPLE_DEV_PM_OPS(m3_pm, m3_suspend, m3_resume);
 #define M3_PM_OPS      &m3_pm
 #else
 #define M3_PM_OPS      NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_SND_MAESTRO3_INPUT
 static int __devinit snd_m3_input_register(struct snd_m3 *chip)
@@ -2656,7 +2656,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
        }
        chip->irq = pci->irq;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        chip->suspend_mem = vmalloc(sizeof(u16) * (REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH));
        if (chip->suspend_mem == NULL)
                snd_printk(KERN_WARNING "can't allocate apm buffer\n");
index bfbdc91e4cb30cc89ad028a8627a6204d2b12919..e0f4d87555a04ace24920b66fe96bf8994d6e111 100644 (file)
@@ -538,7 +538,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
 
                if ((err = snd_card_register(chip->card)) < 0)
                        return err;
-       };
+       }
 
        snd_printdd("miXart firmware downloaded and successfully set up\n");
 
index 465cff25b14622738f1e16d423fc6b579c32d0ad..e80e9a1e84aa4b8cd6ccfaf12abe49de0b063343 100644 (file)
@@ -1377,7 +1377,7 @@ snd_nm256_peek_for_sig(struct nm256 *chip)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * APM event handler, so the card is properly reinitialized after a power
  * event.
@@ -1441,7 +1441,7 @@ static SIMPLE_DEV_PM_OPS(nm256_pm, nm256_suspend, nm256_resume);
 #define NM256_PM_OPS   &nm256_pm
 #else
 #define NM256_PM_OPS   NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int snd_nm256_free(struct nm256 *chip)
 {
index 37520a2b4dcf29c8f7cf7e869d74aed2ad74b36c..2becae155a48d2f0c49bcb999194bc61a469e139 100644 (file)
@@ -872,7 +872,7 @@ static struct pci_driver oxygen_driver = {
        .id_table = oxygen_ids,
        .probe = generic_oxygen_probe,
        .remove = __devexit_p(oxygen_pci_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .driver = {
                .pm = &oxygen_pci_pm,
        },
index 7112a89fb8bd0ba32319dc4fc458248605455d31..09a24b24958bedfa8797f52680e977c289dfb117 100644 (file)
@@ -161,7 +161,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
                                     )
                    );
 void oxygen_pci_remove(struct pci_dev *pci);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 extern const struct dev_pm_ops oxygen_pci_pm;
 #endif
 void oxygen_pci_shutdown(struct pci_dev *pci);
index e9fa2d07951d8e2059f3c0a233dd5258e954eb50..9562dc63ba607c70db84443a961b57fad9e20927 100644 (file)
@@ -726,7 +726,7 @@ void oxygen_pci_remove(struct pci_dev *pci)
 }
 EXPORT_SYMBOL(oxygen_pci_remove);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int oxygen_pci_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -824,7 +824,7 @@ static int oxygen_pci_resume(struct device *dev)
 
 SIMPLE_DEV_PM_OPS(oxygen_pci_pm, oxygen_pci_suspend, oxygen_pci_resume);
 EXPORT_SYMBOL(oxygen_pci_pm);
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 void oxygen_pci_shutdown(struct pci_dev *pci)
 {
index d3b606b69f3bf38864a16e6a1d77c5813d844d59..3d71423b23bcf5450b2926c5b900fa76a91a8559 100644 (file)
@@ -93,7 +93,7 @@ static struct pci_driver xonar_driver = {
        .id_table = xonar_ids,
        .probe = xonar_probe,
        .remove = __devexit_p(oxygen_pci_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .driver = {
                .pm = &oxygen_pci_pm,
        },
index e3ac1f768ff6c6065768d3d62dd628f5b041aac6..be4f1456009a55ea33d5c8597da0607fc4b203a3 100644 (file)
@@ -91,6 +91,14 @@ enum {
        PCI_ID_PCX924E,
        PCI_ID_PCX924HRMIC,
        PCI_ID_PCX924E_MIC,
+       PCI_ID_VX442HR,
+       PCI_ID_PCX442HR,
+       PCI_ID_VX442E,
+       PCI_ID_PCX442E,
+       PCI_ID_VX822HR,
+       PCI_ID_PCX822HR,
+       PCI_ID_VX822E,
+       PCI_ID_PCX822E,
        PCI_ID_LAST
 };
 
@@ -121,6 +129,14 @@ static DEFINE_PCI_DEVICE_TABLE(pcxhr_ids) = {
        { 0x10b5, 0x9056, 0x1369, 0xbb21, 0, 0, PCI_ID_PCX924E, },
        { 0x10b5, 0x9056, 0x1369, 0xbf01, 0, 0, PCI_ID_PCX924HRMIC, },
        { 0x10b5, 0x9056, 0x1369, 0xbf21, 0, 0, PCI_ID_PCX924E_MIC, },
+       { 0x10b5, 0x9656, 0x1369, 0xd001, 0, 0, PCI_ID_VX442HR, },
+       { 0x10b5, 0x9656, 0x1369, 0xd101, 0, 0, PCI_ID_PCX442HR, },
+       { 0x10b5, 0x9056, 0x1369, 0xd021, 0, 0, PCI_ID_VX442E, },
+       { 0x10b5, 0x9056, 0x1369, 0xd121, 0, 0, PCI_ID_PCX442E, },
+       { 0x10b5, 0x9656, 0x1369, 0xd201, 0, 0, PCI_ID_VX822HR, },
+       { 0x10b5, 0x9656, 0x1369, 0xd301, 0, 0, PCI_ID_PCX822HR, },
+       { 0x10b5, 0x9056, 0x1369, 0xd221, 0, 0, PCI_ID_VX822E, },
+       { 0x10b5, 0x9056, 0x1369, 0xd321, 0, 0, PCI_ID_PCX822E, },
        { 0, }
 };
 
@@ -160,6 +176,14 @@ static struct board_parameters pcxhr_board_params[] = {
 [PCI_ID_PCX924E] =      { "PCX924e",      1, 1, 5, 44 },
 [PCI_ID_PCX924HRMIC] =  { "PCX924HR-Mic", 1, 1, 5, 44 },
 [PCI_ID_PCX924E_MIC] =  { "PCX924e-Mic",  1, 1, 5, 44 },
+[PCI_ID_VX442HR] =      { "VX442HR",      2, 2, 0, 41 },
+[PCI_ID_PCX442HR] =     { "PCX442HR",     2, 2, 0, 41 },
+[PCI_ID_VX442E] =       { "VX442e",       2, 2, 1, 41 },
+[PCI_ID_PCX442E] =      { "PCX442e",      2, 2, 1, 41 },
+[PCI_ID_VX822HR] =      { "VX822HR",      4, 1, 2, 42 },
+[PCI_ID_PCX822HR] =     { "PCX822HR",     4, 1, 2, 42 },
+[PCI_ID_VX822E] =       { "VX822e",       4, 1, 3, 42 },
+[PCI_ID_PCX822E] =      { "PCX822e",      4, 1, 3, 42 },
 };
 
 /* boards without hw AES1 and SRC onboard are all using fw_file_set==4 */
index ec1587cddb0cc150e7ac2e66563a69ae54f5aab9..bf207e317f71864ad2dc35b4003be764b81f5c39 100644 (file)
@@ -66,10 +66,10 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr)
        err = pcxhr_send_msg(mgr, &rmh);
        if (err)
                return err;
-       /* test 8 or 12 phys out */
-       if ((rmh.stat[0] & MASK_FIRST_FIELD) != mgr->playback_chips * 2)
+       /* test 4, 8 or 12 phys out */
+       if ((rmh.stat[0] & MASK_FIRST_FIELD) < mgr->playback_chips * 2)
                return -EINVAL;
-       /* test 8 or 2 phys in */
+       /* test 4, 8 or 2 phys in */
        if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) <
            mgr->capture_chips * 2)
                return -EINVAL;
index 760ee467cd9aac9e8969d6c8cb2f03a94c6f1d3d..7d291542c5baba8803cbc3fddae2d33121e2f3d0 100644 (file)
@@ -464,7 +464,7 @@ struct snd_riptide {
 
        unsigned long received_irqs;
        unsigned long handled_irqs;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        int in_suspend;
 #endif
 };
@@ -1150,7 +1150,7 @@ static void riptide_handleirq(unsigned long dev_id)
        }
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int riptide_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -1193,7 +1193,7 @@ static SIMPLE_DEV_PM_OPS(riptide_pm, riptide_suspend, riptide_resume);
 #define RIPTIDE_PM_OPS &riptide_pm
 #else
 #define RIPTIDE_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip)
 {
index 805ab6e9a78fbb0879c111140deda257c083d30c..51e43407ebc539f657b6d7da9ab3647917f2e8af 100644 (file)
@@ -103,7 +103,7 @@ struct voice {
  * we're not doing power management, we still need to allocate a page
  * for the silence buffer.
  */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 #define SIS_SUSPEND_PAGES      4
 #else
 #define SIS_SUSPEND_PAGES      1
@@ -1208,7 +1208,7 @@ static int sis_chip_init(struct sis7019 *sis)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int sis_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -1305,7 +1305,7 @@ static SIMPLE_DEV_PM_OPS(sis_pm, sis_suspend, sis_resume);
 #define SIS_PM_OPS     &sis_pm
 #else
 #define SIS_PM_OPS     NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int sis_alloc_suspend(struct sis7019 *sis)
 {
index d36e6ca147e18932fd63afbe1c273e936234ecc3..8a6f1f76e8709508cb186a4957ad2776e2865392 100644 (file)
@@ -177,7 +177,7 @@ static struct pci_driver trident_driver = {
        .id_table = snd_trident_ids,
        .probe = snd_trident_probe,
        .remove = __devexit_p(snd_trident_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .driver = {
                .pm = &snd_trident_pm,
        },
index 94011dcae7312e4e48f6e75a0b8d59f73e92b572..06b10d1a76e56c3593e09f704ba5efb3b6688577 100644 (file)
@@ -3919,7 +3919,7 @@ static void snd_trident_clear_voices(struct snd_trident * trident, unsigned shor
        }
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_trident_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -3983,4 +3983,4 @@ static int snd_trident_resume(struct device *dev)
 }
 
 SIMPLE_DEV_PM_OPS(snd_trident_pm, snd_trident_suspend, snd_trident_resume);
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
index 0eb7245dd362de2445d383f343d904ac3f04edb1..f0b4efdb483c3ea627cb8a544b9a8b9c6ff2bc58 100644 (file)
@@ -362,7 +362,7 @@ struct via82xx {
 
        unsigned char old_legacy;
        unsigned char old_legacy_cfg;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        unsigned char legacy_saved;
        unsigned char legacy_cfg_saved;
        unsigned char spdif_ctrl_saved;
@@ -1440,6 +1440,7 @@ static void init_viadev(struct via82xx *chip, int idx, unsigned int reg_offset,
 static int __devinit snd_via8233_pcm_new(struct via82xx *chip)
 {
        struct snd_pcm *pcm;
+       struct snd_pcm_chmap *chmap;
        int i, err;
 
        chip->playback_devno = 0;       /* x 4 */
@@ -1467,6 +1468,12 @@ static int __devinit snd_via8233_pcm_new(struct via82xx *chip)
                                              snd_dma_pci_data(chip->pci),
                                              64*1024, VIA_MAX_BUFSIZE);
 
+       err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                                    snd_pcm_std_chmaps, 2, 0,
+                                    &chmap);
+       if (err < 0)
+               return err;
+
        /* PCM #1:  multi-channel playback and 2nd capture */
        err = snd_pcm_new(chip->card, chip->card->shortname, 1, 1, 1, &pcm);
        if (err < 0)
@@ -1484,6 +1491,14 @@ static int __devinit snd_via8233_pcm_new(struct via82xx *chip)
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
                                              snd_dma_pci_data(chip->pci),
                                              64*1024, VIA_MAX_BUFSIZE);
+
+       err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                                    snd_pcm_alt_chmaps, 6, 0,
+                                    &chmap);
+       if (err < 0)
+               return err;
+       chip->ac97->chmaps[SNDRV_PCM_STREAM_PLAYBACK] = chmap;
+
        return 0;
 }
 
@@ -1493,6 +1508,7 @@ static int __devinit snd_via8233_pcm_new(struct via82xx *chip)
 static int __devinit snd_via8233a_pcm_new(struct via82xx *chip)
 {
        struct snd_pcm *pcm;
+       struct snd_pcm_chmap *chmap;
        int err;
 
        chip->multi_devno = 0;
@@ -1519,6 +1535,13 @@ static int __devinit snd_via8233a_pcm_new(struct via82xx *chip)
                                              snd_dma_pci_data(chip->pci),
                                              64*1024, VIA_MAX_BUFSIZE);
 
+       err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                                    snd_pcm_alt_chmaps, 6, 0,
+                                    &chmap);
+       if (err < 0)
+               return err;
+       chip->ac97->chmaps[SNDRV_PCM_STREAM_PLAYBACK] = chmap;
+
        /* SPDIF supported? */
        if (! ac97_can_spdif(chip->ac97))
                return 0;
@@ -2038,7 +2061,7 @@ static int __devinit snd_via686_init_misc(struct via82xx *chip)
                if (mpu_port >= 0x200) {        /* force MIDI */
                        mpu_port &= 0xfffc;
                        pci_write_config_dword(chip->pci, 0x18, mpu_port | 0x01);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
                        chip->mpu_port_saved = mpu_port;
 #endif
                } else {
@@ -2090,7 +2113,7 @@ static int __devinit snd_via686_init_misc(struct via82xx *chip)
 
        snd_via686_create_gameport(chip, &legacy);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        chip->legacy_saved = legacy;
        chip->legacy_cfg_saved = legacy_cfg;
 #endif
@@ -2238,7 +2261,7 @@ static int snd_via82xx_chip_init(struct via82xx *chip)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -2313,7 +2336,7 @@ static SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume
 #define SND_VIA82XX_PM_OPS     &snd_via82xx_pm
 #else
 #define SND_VIA82XX_PM_OPS     NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int snd_via82xx_free(struct via82xx *chip)
 {
index e886bc16999db91d6882d82cdc0b96580a36d9c3..8e0efc416f22f74bd68ba1f1fa89565073ee2bb0 100644 (file)
@@ -1019,7 +1019,7 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -1076,7 +1076,7 @@ static SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume
 #define SND_VIA82XX_PM_OPS     &snd_via82xx_pm
 #else
 #define SND_VIA82XX_PM_OPS     NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int snd_via82xx_free(struct via82xx_modem *chip)
 {
index b89e7a86e9d8f809bdee1306b7fb92ac0d2bcffd..fdfbaf8572336ddd31648a127d668701d60b0a28 100644 (file)
@@ -257,7 +257,7 @@ static void __devexit snd_vx222_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_vx222_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
index 4810356b97ba0997379aa2a45711087d789f5cf9..e01fe34db9eca55ec0feb02082b5f25b87917b62 100644 (file)
@@ -355,7 +355,7 @@ static struct pci_driver ymfpci_driver = {
        .id_table = snd_ymfpci_ids,
        .probe = snd_card_ymfpci_probe,
        .remove = __devexit_p(snd_card_ymfpci_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .driver = {
                .pm = &snd_ymfpci_pm,
        },
index bddc4052286be3e7c9433b5195765a43bcf27669..4631a23489151f8631e878e4a98fe31b51ab066b 100644 (file)
@@ -363,7 +363,7 @@ struct snd_ymfpci {
        const struct firmware *dsp_microcode;
        const struct firmware *controller_microcode;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        u32 *saved_regs;
        u32 saved_ydsxgr_mode;
        u16 saved_dsxg_legacy;
index 62b23635b7543b651e979e5628c1ec631b53df6d..3a6f03f9b02f6bf9645dd3f473396881e3fed1ad 100644 (file)
@@ -1166,6 +1166,11 @@ int __devinit snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm
        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,
+                                    snd_pcm_std_chmaps, 2, 0, NULL);
+       if (err < 0)
+               return err;
+
        if (rpcm)
                *rpcm = pcm;
        return 0;
@@ -1257,6 +1262,14 @@ static struct snd_pcm_ops snd_ymfpci_playback_4ch_ops = {
        .pointer =              snd_ymfpci_playback_pointer,
 };
 
+static const struct snd_pcm_chmap_elem surround_map[] = {
+       { .channels = 1,
+         .map = { SNDRV_CHMAP_MONO } },
+       { .channels = 2,
+         .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+       { }
+};
+
 int __devinit snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, struct snd_pcm ** rpcm)
 {
        struct snd_pcm *pcm;
@@ -1278,6 +1291,11 @@ int __devinit snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, struct snd
        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,
+                                    surround_map, 2, 0, NULL);
+       if (err < 0)
+               return err;
+
        if (rpcm)
                *rpcm = pcm;
        return 0;
@@ -2242,7 +2260,7 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip)
        pci_set_power_state(chip->pci, 3);
 #endif
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        vfree(chip->saved_regs);
 #endif
        if (chip->irq >= 0)
@@ -2272,7 +2290,7 @@ static int snd_ymfpci_dev_free(struct snd_device *device)
        return snd_ymfpci_free(chip);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int saved_regs_index[] = {
        /* spdif */
        YDSXGR_SPDIFOUTCTRL,
@@ -2374,7 +2392,7 @@ static int snd_ymfpci_resume(struct device *dev)
 }
 
 SIMPLE_DEV_PM_OPS(snd_ymfpci_pm, snd_ymfpci_suspend, snd_ymfpci_resume);
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 int __devinit snd_ymfpci_create(struct snd_card *card,
                                struct pci_dev * pci,
@@ -2452,7 +2470,7 @@ int __devinit snd_ymfpci_create(struct snd_card *card,
                return err;
        }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        chip->saved_regs = vmalloc(YDSXGR_NUM_SAVED_REGS * sizeof(u32));
        if (chip->saved_regs == NULL) {
                snd_ymfpci_free(chip);
index c5de0a84566f14ae2a3da251d25441c546640f74..5da8ca7aee05c9680827d7ae7478ceb0532812fb 100644 (file)
@@ -9,6 +9,7 @@ menuconfig SND_SOC
        select SND_JACK if INPUT=y || INPUT=SND
        select REGMAP_I2C if I2C
        select REGMAP_SPI if SPI_MASTER
+       select SND_COMPRESS_OFFLOAD
        ---help---
 
          If you want ASoC support, you should say Y here and also to the
@@ -32,9 +33,9 @@ config SND_SOC_DMAENGINE_PCM
 source "sound/soc/atmel/Kconfig"
 source "sound/soc/au1x/Kconfig"
 source "sound/soc/blackfin/Kconfig"
+source "sound/soc/cirrus/Kconfig"
 source "sound/soc/davinci/Kconfig"
 source "sound/soc/dwc/Kconfig"
-source "sound/soc/ep93xx/Kconfig"
 source "sound/soc/fsl/Kconfig"
 source "sound/soc/jz4740/Kconfig"
 source "sound/soc/nuc900/Kconfig"
index 00a555a743b6a0f013de0a57737b49c880244bf0..bcbf1d00aa858ef62fc11d4767c0cb3b4f270eb3 100644 (file)
@@ -1,5 +1,5 @@
 snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
-snd-soc-core-objs += soc-pcm.o soc-io.o
+snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o
 
 snd-soc-dmaengine-pcm-objs := soc-dmaengine-pcm.o
 obj-$(CONFIG_SND_SOC_DMAENGINE_PCM) += snd-soc-dmaengine-pcm.o
@@ -10,9 +10,9 @@ obj-$(CONFIG_SND_SOC) += generic/
 obj-$(CONFIG_SND_SOC)  += atmel/
 obj-$(CONFIG_SND_SOC)  += au1x/
 obj-$(CONFIG_SND_SOC)  += blackfin/
+obj-$(CONFIG_SND_SOC)  += cirrus/
 obj-$(CONFIG_SND_SOC)  += davinci/
 obj-$(CONFIG_SND_SOC)  += dwc/
-obj-$(CONFIG_SND_SOC)  += ep93xx/
 obj-$(CONFIG_SND_SOC)  += fsl/
 obj-$(CONFIG_SND_SOC)  += jz4740/
 obj-$(CONFIG_SND_SOC)  += mid-x86/
index d542d4063771a4daaec9048ad0b6aa0e4d640afb..16b9c9efd19a79aba78c8e01ec9e4095300501d6 100644 (file)
@@ -59,62 +59,63 @@ static struct snd_soc_ops bf5xx_ad1836_ops = {
 #define BF5XX_AD1836_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \
                                SND_SOC_DAIFMT_CBM_CFM)
 
-static struct snd_soc_dai_link bf5xx_ad1836_dai[] = {
-       {
-               .name = "ad1836",
-               .stream_name = "AD1836",
-               .cpu_dai_name = "bfin-tdm.0",
-               .codec_dai_name = "ad1836-hifi",
-               .platform_name = "bfin-tdm-pcm-audio",
-               .codec_name = "spi0.4",
-               .ops = &bf5xx_ad1836_ops,
-               .dai_fmt = BF5XX_AD1836_DAIFMT,
-       },
-       {
-               .name = "ad1836",
-               .stream_name = "AD1836",
-               .cpu_dai_name = "bfin-tdm.1",
-               .codec_dai_name = "ad1836-hifi",
-               .platform_name = "bfin-tdm-pcm-audio",
-               .codec_name = "spi0.4",
-               .ops = &bf5xx_ad1836_ops,
-               .dai_fmt = BF5XX_AD1836_DAIFMT,
-       },
+static struct snd_soc_dai_link bf5xx_ad1836_dai = {
+       .name = "ad1836",
+       .stream_name = "AD1836",
+       .codec_dai_name = "ad1836-hifi",
+       .platform_name = "bfin-tdm-pcm-audio",
+       .ops = &bf5xx_ad1836_ops,
+       .dai_fmt = BF5XX_AD1836_DAIFMT,
 };
 
 static struct snd_soc_card bf5xx_ad1836 = {
        .name = "bfin-ad1836",
        .owner = THIS_MODULE,
-       .dai_link = &bf5xx_ad1836_dai[CONFIG_SND_BF5XX_SPORT_NUM],
+       .dai_link = &bf5xx_ad1836_dai,
        .num_links = 1,
 };
 
-static struct platform_device *bfxx_ad1836_snd_device;
-
-static int __init bf5xx_ad1836_init(void)
+static __devinit int bf5xx_ad1836_driver_probe(struct platform_device *pdev)
 {
+       struct snd_soc_card *card = &bf5xx_ad1836;
+       const char **link_name;
        int ret;
 
-       bfxx_ad1836_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!bfxx_ad1836_snd_device)
-               return -ENOMEM;
+       link_name = pdev->dev.platform_data;
+       if (!link_name) {
+               dev_err(&pdev->dev, "No platform data supplied\n");
+               return -EINVAL;
+       }
+       bf5xx_ad1836_dai.cpu_dai_name = link_name[0];
+       bf5xx_ad1836_dai.codec_name = link_name[1];
 
-       platform_set_drvdata(bfxx_ad1836_snd_device, &bf5xx_ad1836);
-       ret = platform_device_add(bfxx_ad1836_snd_device);
+       card->dev = &pdev->dev;
+       platform_set_drvdata(pdev, card);
 
+       ret = snd_soc_register_card(card);
        if (ret)
-               platform_device_put(bfxx_ad1836_snd_device);
-
+               dev_err(&pdev->dev, "Failed to register card\n");
        return ret;
 }
 
-static void __exit bf5xx_ad1836_exit(void)
+static int __devexit bf5xx_ad1836_driver_remove(struct platform_device *pdev)
 {
-       platform_device_unregister(bfxx_ad1836_snd_device);
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_card(card);
+       return 0;
 }
 
-module_init(bf5xx_ad1836_init);
-module_exit(bf5xx_ad1836_exit);
+static struct platform_driver bf5xx_ad1836_driver = {
+       .driver = {
+               .name = "bfin-snd-ad1836",
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+       },
+       .probe = bf5xx_ad1836_driver_probe,
+       .remove = __devexit_p(bf5xx_ad1836_driver_remove),
+};
+module_platform_driver(bf5xx_ad1836_driver);
 
 /* Module information */
 MODULE_AUTHOR("Barry Song");
index 9f8e8594aeb9044bfd42e9e72be73219f9f8b504..b92759a3936157e0884b98f752935ccbef7b8945 100644 (file)
@@ -37,6 +37,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_CX20442
        select SND_SOC_DA7210 if I2C
        select SND_SOC_DA732X if I2C
+       select SND_SOC_DA9055 if I2C
        select SND_SOC_DFBMCS320
        select SND_SOC_ISABELLE if I2C
        select SND_SOC_JZ4740_CODEC
@@ -70,6 +71,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_UDA134X
        select SND_SOC_UDA1380 if I2C
        select SND_SOC_WL1273 if MFD_WL1273_CORE
+       select SND_SOC_WM0010 if SPI_MASTER
        select SND_SOC_WM1250_EV1 if I2C
        select SND_SOC_WM2000 if I2C
        select SND_SOC_WM2200 if I2C
@@ -238,6 +240,9 @@ config SND_SOC_DA7210
 config SND_SOC_DA732X
         tristate
 
+config SND_SOC_DA9055
+       tristate
+
 config SND_SOC_DFBMCS320
        tristate
 
@@ -326,6 +331,9 @@ config SND_SOC_UDA1380
 config SND_SOC_WL1273
        tristate
 
+config SND_SOC_WM0010
+       tristate
+
 config SND_SOC_WM1250_EV1
        tristate
 
index 34148bb59c68dcba49debbf7813a278c3539b45e..9bd4d95aab4ffcecb9abf5bff4e0c94d7203adee 100644 (file)
@@ -24,6 +24,7 @@ snd-soc-cs4271-objs := cs4271.o
 snd-soc-cx20442-objs := cx20442.o
 snd-soc-da7210-objs := da7210.o
 snd-soc-da732x-objs := da732x.o
+snd-soc-da9055-objs := da9055.o
 snd-soc-dfbmcs320-objs := dfbmcs320.o
 snd-soc-dmic-objs := dmic.o
 snd-soc-isabelle-objs := isabelle.o
@@ -61,6 +62,7 @@ snd-soc-twl6040-objs := twl6040.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wl1273-objs := wl1273.o
+snd-soc-wm0010-objs := wm0010.o
 snd-soc-wm1250-ev1-objs := wm1250-ev1.o
 snd-soc-wm2000-objs := wm2000.o
 snd-soc-wm2200-objs := wm2200.o
@@ -143,6 +145,7 @@ obj-$(CONFIG_SND_SOC_CS4271)        += snd-soc-cs4271.o
 obj-$(CONFIG_SND_SOC_CX20442)  += snd-soc-cx20442.o
 obj-$(CONFIG_SND_SOC_DA7210)   += snd-soc-da7210.o
 obj-$(CONFIG_SND_SOC_DA732X)   += snd-soc-da732x.o
+obj-$(CONFIG_SND_SOC_DA9055)   += snd-soc-da9055.o
 obj-$(CONFIG_SND_SOC_DFBMCS320)        += snd-soc-dfbmcs320.o
 obj-$(CONFIG_SND_SOC_DMIC)     += snd-soc-dmic.o
 obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
@@ -177,6 +180,7 @@ obj-$(CONFIG_SND_SOC_TWL6040)       += snd-soc-twl6040.o
 obj-$(CONFIG_SND_SOC_UDA134X)  += snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)  += snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WL1273)   += snd-soc-wl1273.o
+obj-$(CONFIG_SND_SOC_WM0010)   += snd-soc-wm0010.o
 obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
 obj-$(CONFIG_SND_SOC_WM2000)   += snd-soc-wm2000.o
 obj-$(CONFIG_SND_SOC_WM2200)   += snd-soc-wm2200.o
index 07abd09e0b1d83f6a9eb347a6bef37187ad34fe4..af547490b4f7f6e0b1dbada793259c64a513a203 100644 (file)
@@ -391,10 +391,10 @@ static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = {
        SND_SOC_DAPM_CLOCK_SUPPLY("audioclk"),
 
        /* Regulators */
-       SND_SOC_DAPM_REGULATOR_SUPPLY("V-AUD", 0),
-       SND_SOC_DAPM_REGULATOR_SUPPLY("V-AMIC1", 0),
-       SND_SOC_DAPM_REGULATOR_SUPPLY("V-AMIC2", 0),
-       SND_SOC_DAPM_REGULATOR_SUPPLY("V-DMIC", 0),
+       SND_SOC_DAPM_REGULATOR_SUPPLY("V-AUD", 0, 0),
+       SND_SOC_DAPM_REGULATOR_SUPPLY("V-AMIC1", 0, 0),
+       SND_SOC_DAPM_REGULATOR_SUPPLY("V-AMIC2", 0, 0),
+       SND_SOC_DAPM_REGULATOR_SUPPLY("V-DMIC", 0, 0),
 
        /* Power */
        SND_SOC_DAPM_SUPPLY("Audio Power",
@@ -2462,10 +2462,7 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
        dev_dbg(dev, "%s: Enter.\n", __func__);
 
        /* Setup AB8500 according to board-settings */
-       pdata = (struct ab8500_platform_data *)dev_get_platdata(dev->parent);
-
-       /* Inform SoC Core that we have our own I/O arrangements. */
-       codec->control_data = (void *)true;
+       pdata = dev_get_platdata(dev->parent);
 
        if (np) {
                if (!pdata)
index c67b50d8b3170cd388a1279516a186c9a23e9a99..dce6ebeef4527cfb176063e91c90a9a741ee3f89 100644 (file)
@@ -19,6 +19,8 @@
 #include <sound/soc.h>
 #include <sound/tlv.h>
 #include <linux/spi/spi.h>
+#include <linux/regmap.h>
+
 #include "ad1836.h"
 
 enum ad1836_type {
@@ -30,6 +32,7 @@ enum ad1836_type {
 /* codec private data */
 struct ad1836_priv {
        enum ad1836_type type;
+       struct regmap *regmap;
 };
 
 /*
@@ -161,8 +164,8 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
                struct snd_pcm_hw_params *params,
                struct snd_soc_dai *dai)
 {
+       struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(dai->codec);
        int word_len = 0;
-       struct snd_soc_codec *codec = dai->codec;
 
        /* bit size */
        switch (params_format(params)) {
@@ -178,10 +181,12 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
-       snd_soc_update_bits(codec, AD1836_DAC_CTRL1, AD1836_DAC_WORD_LEN_MASK,
+       regmap_update_bits(ad1836->regmap, AD1836_DAC_CTRL1,
+               AD1836_DAC_WORD_LEN_MASK,
                word_len << AD1836_DAC_WORD_LEN_OFFSET);
 
-       snd_soc_update_bits(codec, AD1836_ADC_CTRL2, AD1836_ADC_WORD_LEN_MASK,
+       regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,
+               AD1836_ADC_WORD_LEN_MASK,
                word_len << AD1836_ADC_WORD_OFFSET);
 
        return 0;
@@ -223,15 +228,17 @@ static struct snd_soc_dai_driver ad183x_dais[] = {
 #ifdef CONFIG_PM
 static int ad1836_suspend(struct snd_soc_codec *codec)
 {
+       struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
        /* reset clock control mode */
-       return snd_soc_update_bits(codec, AD1836_ADC_CTRL2,
+       return regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,
                AD1836_ADC_SERFMT_MASK, 0);
 }
 
 static int ad1836_resume(struct snd_soc_codec *codec)
 {
+       struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
        /* restore clock control mode */
-       return snd_soc_update_bits(codec, AD1836_ADC_CTRL2,
+       return regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,
                AD1836_ADC_SERFMT_MASK, AD1836_ADC_AUX);
 }
 #else
@@ -250,37 +257,30 @@ static int ad1836_probe(struct snd_soc_codec *codec)
        num_dacs = ad183x_dais[ad1836->type].playback.channels_max / 2;
        num_adcs = ad183x_dais[ad1836->type].capture.channels_max / 2;
 
-       ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI);
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to set cache I/O: %d\n",
-                               ret);
-               return ret;
-       }
-
        /* default setting for ad1836 */
        /* de-emphasis: 48kHz, power-on dac */
-       snd_soc_write(codec, AD1836_DAC_CTRL1, 0x300);
+       regmap_write(ad1836->regmap, AD1836_DAC_CTRL1, 0x300);
        /* unmute dac channels */
-       snd_soc_write(codec, AD1836_DAC_CTRL2, 0x0);
+       regmap_write(ad1836->regmap, AD1836_DAC_CTRL2, 0x0);
        /* high-pass filter enable, power-on adc */
-       snd_soc_write(codec, AD1836_ADC_CTRL1, 0x100);
+       regmap_write(ad1836->regmap, AD1836_ADC_CTRL1, 0x100);
        /* unmute adc channles, adc aux mode */
-       snd_soc_write(codec, AD1836_ADC_CTRL2, 0x180);
+       regmap_write(ad1836->regmap, AD1836_ADC_CTRL2, 0x180);
        /* volume */
        for (i = 1; i <= num_dacs; ++i) {
-               snd_soc_write(codec, AD1836_DAC_L_VOL(i), 0x3FF);
-               snd_soc_write(codec, AD1836_DAC_R_VOL(i), 0x3FF);
+               regmap_write(ad1836->regmap, AD1836_DAC_L_VOL(i), 0x3FF);
+               regmap_write(ad1836->regmap, AD1836_DAC_R_VOL(i), 0x3FF);
        }
 
        if (ad1836->type == AD1836) {
                /* left/right diff:PGA/MUX */
-               snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A);
+               regmap_write(ad1836->regmap, AD1836_ADC_CTRL3, 0x3A);
                ret = snd_soc_add_codec_controls(codec, ad1836_controls,
                                ARRAY_SIZE(ad1836_controls));
                if (ret)
                        return ret;
        } else {
-               snd_soc_write(codec, AD1836_ADC_CTRL3, 0x00);
+               regmap_write(ad1836->regmap, AD1836_ADC_CTRL3, 0x00);
        }
 
        ret = snd_soc_add_codec_controls(codec, ad183x_dac_controls, num_dacs * 2);
@@ -313,8 +313,9 @@ static int ad1836_probe(struct snd_soc_codec *codec)
 /* power down chip */
 static int ad1836_remove(struct snd_soc_codec *codec)
 {
+       struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
        /* reset clock control mode */
-       return snd_soc_update_bits(codec, AD1836_ADC_CTRL2,
+       return regmap_update_bits(ad1836->regmap, AD1836_ADC_CTRL2,
                AD1836_ADC_SERFMT_MASK, 0);
 }
 
@@ -323,8 +324,6 @@ static struct snd_soc_codec_driver soc_codec_dev_ad1836 = {
        .remove = ad1836_remove,
        .suspend = ad1836_suspend,
        .resume = ad1836_resume,
-       .reg_cache_size = AD1836_NUM_REGS,
-       .reg_word_size = sizeof(u16),
 
        .controls = ad183x_controls,
        .num_controls = ARRAY_SIZE(ad183x_controls),
@@ -334,6 +333,33 @@ static struct snd_soc_codec_driver soc_codec_dev_ad1836 = {
        .num_dapm_routes = ARRAY_SIZE(ad183x_dapm_routes),
 };
 
+static const struct reg_default ad1836_reg_defaults[] = {
+       { AD1836_DAC_CTRL1, 0x0000 },
+       { AD1836_DAC_CTRL2, 0x0000 },
+       { AD1836_DAC_L_VOL(0), 0x0000 },
+       { AD1836_DAC_R_VOL(0), 0x0000 },
+       { AD1836_DAC_L_VOL(1), 0x0000 },
+       { AD1836_DAC_R_VOL(1), 0x0000 },
+       { AD1836_DAC_L_VOL(2), 0x0000 },
+       { AD1836_DAC_R_VOL(2), 0x0000 },
+       { AD1836_DAC_L_VOL(3), 0x0000 },
+       { AD1836_DAC_R_VOL(3), 0x0000 },
+       { AD1836_ADC_CTRL1, 0x0000 },
+       { AD1836_ADC_CTRL2, 0x0000 },
+       { AD1836_ADC_CTRL3, 0x0000 },
+};
+
+static const struct regmap_config ad1836_regmap_config = {
+       .val_bits = 12,
+       .reg_bits = 4,
+       .read_flag_mask = 0x08,
+
+       .max_register = AD1836_ADC_CTRL3,
+       .reg_defaults = ad1836_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(ad1836_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+};
+
 static int __devinit ad1836_spi_probe(struct spi_device *spi)
 {
        struct ad1836_priv *ad1836;
@@ -344,6 +370,10 @@ static int __devinit ad1836_spi_probe(struct spi_device *spi)
        if (ad1836 == NULL)
                return -ENOMEM;
 
+       ad1836->regmap = devm_regmap_init_spi(spi, &ad1836_regmap_config);
+       if (IS_ERR(ad1836->regmap))
+               return PTR_ERR(ad1836->regmap);
+
        ad1836->type = spi_get_device_id(spi)->driver_data;
 
        spi_set_drvdata(spi, ad1836);
@@ -379,17 +409,7 @@ static struct spi_driver ad1836_spi_driver = {
        .id_table       = ad1836_ids,
 };
 
-static int __init ad1836_init(void)
-{
-       return spi_register_driver(&ad1836_spi_driver);
-}
-module_init(ad1836_init);
-
-static void __exit ad1836_exit(void)
-{
-       spi_unregister_driver(&ad1836_spi_driver);
-}
-module_exit(ad1836_exit);
+module_spi_driver(ad1836_spi_driver);
 
 MODULE_DESCRIPTION("ASoC ad1836 driver");
 MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
index 13e62be4f9903eac8560819d751b0edbcf9e4555..2f752660f6789760381aaec5f0391aac94b33bde 100644 (file)
@@ -381,40 +381,25 @@ static const struct regmap_config ad193x_spi_regmap_config = {
 static int __devinit ad193x_spi_probe(struct spi_device *spi)
 {
        struct ad193x_priv *ad193x;
-       int ret;
 
        ad193x = devm_kzalloc(&spi->dev, sizeof(struct ad193x_priv),
                              GFP_KERNEL);
        if (ad193x == NULL)
                return -ENOMEM;
 
-       ad193x->regmap = regmap_init_spi(spi, &ad193x_spi_regmap_config);
-       if (IS_ERR(ad193x->regmap)) {
-               ret = PTR_ERR(ad193x->regmap);
-               goto err_out;
-       }
+       ad193x->regmap = devm_regmap_init_spi(spi, &ad193x_spi_regmap_config);
+       if (IS_ERR(ad193x->regmap))
+               return PTR_ERR(ad193x->regmap);
 
        spi_set_drvdata(spi, ad193x);
 
-       ret = snd_soc_register_codec(&spi->dev,
-                       &soc_codec_dev_ad193x, &ad193x_dai, 1);
-       if (ret < 0)
-               goto err_regmap_exit;
-
-       return 0;
-
-err_regmap_exit:
-       regmap_exit(ad193x->regmap);
-err_out:
-       return ret;
+       return snd_soc_register_codec(&spi->dev, &soc_codec_dev_ad193x,
+                       &ad193x_dai, 1);
 }
 
 static int __devexit ad193x_spi_remove(struct spi_device *spi)
 {
-       struct ad193x_priv *ad193x = spi_get_drvdata(spi);
-
        snd_soc_unregister_codec(&spi->dev);
-       regmap_exit(ad193x->regmap);
        return 0;
 }
 
@@ -449,40 +434,25 @@ static int __devinit ad193x_i2c_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
        struct ad193x_priv *ad193x;
-       int ret;
 
        ad193x = devm_kzalloc(&client->dev, sizeof(struct ad193x_priv),
                              GFP_KERNEL);
        if (ad193x == NULL)
                return -ENOMEM;
 
-       ad193x->regmap = regmap_init_i2c(client, &ad193x_i2c_regmap_config);
-       if (IS_ERR(ad193x->regmap)) {
-               ret = PTR_ERR(ad193x->regmap);
-               goto err_out;
-       }
+       ad193x->regmap = devm_regmap_init_i2c(client, &ad193x_i2c_regmap_config);
+       if (IS_ERR(ad193x->regmap))
+               return PTR_ERR(ad193x->regmap);
 
        i2c_set_clientdata(client, ad193x);
 
-       ret =  snd_soc_register_codec(&client->dev,
-                       &soc_codec_dev_ad193x, &ad193x_dai, 1);
-       if (ret < 0)
-               goto err_regmap_exit;
-
-       return 0;
-
-err_regmap_exit:
-       regmap_exit(ad193x->regmap);
-err_out:
-       return ret;
+       return snd_soc_register_codec(&client->dev, &soc_codec_dev_ad193x,
+                       &ad193x_dai, 1);
 }
 
 static int __devexit ad193x_i2c_remove(struct i2c_client *client)
 {
-       struct ad193x_priv *ad193x = i2c_get_clientdata(client);
-
        snd_soc_unregister_codec(&client->dev);
-       regmap_exit(ad193x->regmap);
        return 0;
 }
 
index 11b1b714b8b5e106ad7784258ca4caa4a4939e9e..8c39dddd7d0063d90adcf587c5e6dc19c37f73ad 100644 (file)
@@ -186,7 +186,6 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec)
 
        printk(KERN_INFO "AD1980 SoC Audio Codec\n");
 
-       codec->control_data = codec;    /* we don't use regmap! */
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0) {
                printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
index 44f59064d8de11247187a8d124661361e7913e65..704544bfc90dc564c774593ee7d0300098c47d6c 100644 (file)
@@ -1392,17 +1392,7 @@ static struct i2c_driver adau1373_i2c_driver = {
        .id_table = adau1373_i2c_id,
 };
 
-static int __init adau1373_init(void)
-{
-       return i2c_add_driver(&adau1373_i2c_driver);
-}
-module_init(adau1373_init);
-
-static void __exit adau1373_exit(void)
-{
-       i2c_del_driver(&adau1373_i2c_driver);
-}
-module_exit(adau1373_exit);
+module_i2c_driver(adau1373_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC ADAU1373 driver");
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
index 3d50fc8646b672fd87eb82c21abb72b4699ec368..51f2f3cd81364658d0b78d48c7baddb7cac5abd2 100644 (file)
@@ -527,17 +527,7 @@ static struct i2c_driver adau1701_i2c_driver = {
        .id_table       = adau1701_i2c_id,
 };
 
-static int __init adau1701_init(void)
-{
-       return i2c_add_driver(&adau1701_i2c_driver);
-}
-module_init(adau1701_init);
-
-static void __exit adau1701_exit(void)
-{
-       i2c_del_driver(&adau1701_i2c_driver);
-}
-module_exit(adau1701_exit);
+module_i2c_driver(adau1701_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC ADAU1701 SigmaDSP driver");
 MODULE_AUTHOR("Cliff Cai <cliff.cai@analog.com>");
index 5fb7c2a80e6daa5e8e68948a09b95a852fba778e..2b457976a7bff0f18ada9248acdc0c25b4bd82cd 100644 (file)
@@ -696,17 +696,7 @@ static struct i2c_driver ak4671_i2c_driver = {
        .id_table = ak4671_i2c_id,
 };
 
-static int __init ak4671_modinit(void)
-{
-       return i2c_add_driver(&ak4671_i2c_driver);
-}
-module_init(ak4671_modinit);
-
-static void __exit ak4671_exit(void)
-{
-       i2c_del_driver(&ak4671_i2c_driver);
-}
-module_exit(ak4671_exit);
+module_i2c_driver(ak4671_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC AK4671 codec driver");
 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
index 1cf7a32d1b211e779cb7705746c32b07c11afa82..c03b65af30598f8f03dfba2d7353913a33a0bfe9 100644 (file)
@@ -119,6 +119,24 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
        "DSP1.4",
        "DSP1.5",
        "DSP1.6",
+       "DSP2.1",
+       "DSP2.2",
+       "DSP2.3",
+       "DSP2.4",
+       "DSP2.5",
+       "DSP2.6",
+       "DSP3.1",
+       "DSP3.2",
+       "DSP3.3",
+       "DSP3.4",
+       "DSP3.5",
+       "DSP3.6",
+       "DSP4.1",
+       "DSP4.2",
+       "DSP4.3",
+       "DSP4.4",
+       "DSP4.5",
+       "DSP4.6",
        "ASRC1L",
        "ASRC1R",
        "ASRC2L",
@@ -180,6 +198,24 @@ int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
        0x6b,
        0x6c,
        0x6d,
+       0x70,  /* DSP2.1 */
+       0x71,
+       0x72,
+       0x73,
+       0x74,
+       0x75,
+       0x78,  /* DSP3.1 */
+       0x79,
+       0x7a,
+       0x7b,
+       0x7c,
+       0x7d,
+       0x80,  /* DSP4.1 */
+       0x81,
+       0x82,
+       0x83,
+       0x84,
+       0x85,
        0x90,  /* ASRC1L */
        0x91,
        0x92,
@@ -229,6 +265,75 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
 }
 EXPORT_SYMBOL_GPL(arizona_out_ev);
 
+static unsigned int arizona_sysclk_48k_rates[] = {
+       6144000,
+       12288000,
+       22579200,
+       49152000,
+       73728000,
+       98304000,
+       147456000,
+};
+
+static unsigned int arizona_sysclk_44k1_rates[] = {
+       5644800,
+       11289600,
+       24576000,
+       45158400,
+       67737600,
+       90316800,
+       135475200,
+};
+
+static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
+                            unsigned int freq)
+{
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       unsigned int reg;
+       unsigned int *rates;
+       int ref, div, refclk;
+
+       switch (clk) {
+       case ARIZONA_CLK_OPCLK:
+               reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
+               refclk = priv->sysclk;
+               break;
+       case ARIZONA_CLK_ASYNC_OPCLK:
+               reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
+               refclk = priv->asyncclk;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (refclk % 8000)
+               rates = arizona_sysclk_44k1_rates;
+       else
+               rates = arizona_sysclk_48k_rates;
+
+       for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
+                    rates[ref] <= refclk; ref++) {
+               div = 1;
+               while (rates[ref] / div >= freq && div < 32) {
+                       if (rates[ref] / div == freq) {
+                               dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
+                                       freq);
+                               snd_soc_update_bits(codec, reg,
+                                                   ARIZONA_OPCLK_DIV_MASK |
+                                                   ARIZONA_OPCLK_SEL_MASK,
+                                                   (div <<
+                                                    ARIZONA_OPCLK_DIV_SHIFT) |
+                                                   ref);
+                               return 0;
+                       }
+                       div++;
+               }
+       }
+
+       dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
+       return -EINVAL;
+}
+
 int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
                       int source, unsigned int freq, int dir)
 {
@@ -252,6 +357,9 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
                reg = ARIZONA_ASYNC_CLOCK_1;
                clk = &priv->asyncclk;
                break;
+       case ARIZONA_CLK_OPCLK:
+       case ARIZONA_CLK_ASYNC_OPCLK:
+               return arizona_set_opclk(codec, clk_id, freq);
        default:
                return -EINVAL;
        }
@@ -666,7 +774,7 @@ static irqreturn_t arizona_fll_lock(int irq, void *data)
 {
        struct arizona_fll *fll = data;
 
-       arizona_fll_dbg(fll, "Locked\n");
+       arizona_fll_dbg(fll, "Lock status changed\n");
 
        complete(&fll->lock);
 
index 59caca8865e8aa355c279dd257cf836d667627aa..36ec64946120077455ab218c85aef34eaa29ef9a 100644 (file)
 
 #include <sound/soc.h>
 
-#define ARIZONA_CLK_SYSCLK   1
-#define ARIZONA_CLK_ASYNCCLK 2
+#define ARIZONA_CLK_SYSCLK         1
+#define ARIZONA_CLK_ASYNCCLK       2
+#define ARIZONA_CLK_OPCLK          3
+#define ARIZONA_CLK_ASYNC_OPCLK    4
 
 #define ARIZONA_CLK_SRC_MCLK1    0x0
 #define ARIZONA_CLK_SRC_MCLK2    0x1
@@ -59,7 +61,7 @@ struct arizona_priv {
        struct arizona_dai_priv dai[ARIZONA_MAX_DAI];
 };
 
-#define ARIZONA_NUM_MIXER_INPUTS 57
+#define ARIZONA_NUM_MIXER_INPUTS 75
 
 extern const unsigned int arizona_mixer_tlv[];
 extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS];
index 047917f0b8aef6c54d82f618db30b706fe72636f..8e4779812b96c03d11f07ca6a4c47ca628b3295b 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/i2c.h>
 #include <linux/delay.h>
 #include <linux/regulator/consumer.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 
 /*
  * The codec isn't really big-endian or little-endian, since the I2S
  * This array contains the power-on default values of the registers, with the
  * exception of the "CHIPID" register (01h).  The lower four bits of that
  * register contain the hardware revision, so it is treated as volatile.
- *
- * Also note that on the CS4270, the first readable register is 1, but ASoC
- * assumes the first register is 0.  Therfore, the array must have an entry for
- * register 0, but we use cs4270_reg_is_readable() to tell ASoC that it can't
- * be read.
  */
-static const u8 cs4270_default_reg_cache[CS4270_LASTREG + 1] = {
-       0x00, 0x00, 0x00, 0x30, 0x00, 0x60, 0x20, 0x00, 0x00
+static const struct reg_default cs4270_reg_defaults[] = {
+       { 2, 0x00 },
+       { 3, 0x30 },
+       { 4, 0x00 },
+       { 5, 0x60 },
+       { 6, 0x20 },
+       { 7, 0x00 },
+       { 8, 0x00 },
 };
 
 static const char *supply_names[] = {
@@ -126,7 +129,7 @@ static const char *supply_names[] = {
 
 /* Private data for the CS4270 */
 struct cs4270_private {
-       enum snd_soc_control_type control_type;
+       struct regmap *regmap;
        unsigned int mclk; /* Input frequency of the MCLK pin */
        unsigned int mode; /* The mode (I2S or left-justified) */
        unsigned int slave_mode;
@@ -191,12 +194,12 @@ static struct cs4270_mode_ratios cs4270_mode_ratios[] = {
 /* The number of MCLK/LRCK ratios supported by the CS4270 */
 #define NUM_MCLK_RATIOS                ARRAY_SIZE(cs4270_mode_ratios)
 
-static int cs4270_reg_is_readable(struct snd_soc_codec *codec, unsigned int reg)
+static bool cs4270_reg_is_readable(struct device *dev, unsigned int reg)
 {
        return (reg >= CS4270_FIRSTREG) && (reg <= CS4270_LASTREG);
 }
 
-static int cs4270_reg_is_volatile(struct snd_soc_codec *codec, unsigned int reg)
+static bool cs4270_reg_is_volatile(struct device *dev, unsigned int reg)
 {
        /* Unreadable registers are considered volatile */
        if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG))
@@ -456,7 +459,7 @@ static struct snd_soc_dai_driver cs4270_dai = {
        .name = "cs4270-hifi",
        .playback = {
                .stream_name = "Playback",
-               .channels_min = 1,
+               .channels_min = 2,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_CONTINUOUS,
                .rate_min = 4000,
@@ -465,7 +468,7 @@ static struct snd_soc_dai_driver cs4270_dai = {
        },
        .capture = {
                .stream_name = "Capture",
-               .channels_min = 1,
+               .channels_min = 2,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_CONTINUOUS,
                .rate_min = 4000,
@@ -485,12 +488,12 @@ static struct snd_soc_dai_driver cs4270_dai = {
 static int cs4270_probe(struct snd_soc_codec *codec)
 {
        struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
-       int i, ret;
+       int ret;
 
        /* Tell ASoC what kind of I/O to use to read the registers.  ASoC will
         * then do the I2C transactions itself.
         */
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, cs4270->control_type);
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
        if (ret < 0) {
                dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret);
                return ret;
@@ -519,33 +522,8 @@ static int cs4270_probe(struct snd_soc_codec *codec)
                return ret;
        }
 
-       /* Add the non-DAPM controls */
-       ret = snd_soc_add_codec_controls(codec, cs4270_snd_controls,
-                               ARRAY_SIZE(cs4270_snd_controls));
-       if (ret < 0) {
-               dev_err(codec->dev, "failed to add controls\n");
-               return ret;
-       }
-
-       /* get the power supply regulators */
-       for (i = 0; i < ARRAY_SIZE(supply_names); i++)
-               cs4270->supplies[i].supply = supply_names[i];
-
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(cs4270->supplies),
-                                cs4270->supplies);
-       if (ret < 0)
-               return ret;
-
        ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
                                    cs4270->supplies);
-       if (ret < 0)
-               goto error_free_regulators;
-
-       return 0;
-
-error_free_regulators:
-       regulator_bulk_free(ARRAY_SIZE(cs4270->supplies),
-                           cs4270->supplies);
 
        return ret;
 }
@@ -561,7 +539,6 @@ static int cs4270_remove(struct snd_soc_codec *codec)
        struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
 
        regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
-       regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
 
        return 0;
 };
@@ -611,7 +588,7 @@ static int cs4270_soc_resume(struct snd_soc_codec *codec)
        ndelay(500);
 
        /* first restore the entire register cache ... */
-       snd_soc_cache_sync(codec);
+       regcache_sync(cs4270->regmap);
 
        /* ... then disable the power-down bits */
        reg = snd_soc_read(codec, CS4270_PWRCTL);
@@ -632,11 +609,30 @@ static const struct snd_soc_codec_driver soc_codec_device_cs4270 = {
        .remove =               cs4270_remove,
        .suspend =              cs4270_soc_suspend,
        .resume =               cs4270_soc_resume,
-       .volatile_register =    cs4270_reg_is_volatile,
-       .readable_register =    cs4270_reg_is_readable,
-       .reg_cache_size =       CS4270_LASTREG + 1,
-       .reg_word_size =        sizeof(u8),
-       .reg_cache_default =    cs4270_default_reg_cache,
+
+       .controls =             cs4270_snd_controls,
+       .num_controls =         ARRAY_SIZE(cs4270_snd_controls),
+};
+
+/*
+ * cs4270_of_match - the device tree bindings
+ */
+static const struct of_device_id cs4270_of_match[] = {
+       { .compatible = "cirrus,cs4270", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, cs4270_of_match);
+
+static const struct regmap_config cs4270_regmap = {
+       .reg_bits =             8,
+       .val_bits =             8,
+       .max_register =         CS4270_LASTREG,
+       .reg_defaults =         cs4270_reg_defaults,
+       .num_reg_defaults =     ARRAY_SIZE(cs4270_reg_defaults),
+       .cache_type =           REGCACHE_RBTREE,
+
+       .readable_reg =         cs4270_reg_is_readable,
+       .volatile_reg =         cs4270_reg_is_volatile,
 };
 
 /**
@@ -650,19 +646,56 @@ static const struct snd_soc_codec_driver soc_codec_device_cs4270 = {
 static int cs4270_i2c_probe(struct i2c_client *i2c_client,
        const struct i2c_device_id *id)
 {
+       struct device_node *np = i2c_client->dev.of_node;
        struct cs4270_private *cs4270;
-       int ret;
+       unsigned int val;
+       int ret, i;
 
-       /* Verify that we have a CS4270 */
+       cs4270 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs4270_private),
+                             GFP_KERNEL);
+       if (!cs4270) {
+               dev_err(&i2c_client->dev, "could not allocate codec\n");
+               return -ENOMEM;
+       }
+
+       /* get the power supply regulators */
+       for (i = 0; i < ARRAY_SIZE(supply_names); i++)
+               cs4270->supplies[i].supply = supply_names[i];
+
+       ret = devm_regulator_bulk_get(&i2c_client->dev,
+                                     ARRAY_SIZE(cs4270->supplies),
+                                     cs4270->supplies);
+       if (ret < 0)
+               return ret;
+
+       /* See if we have a way to bring the codec out of reset */
+       if (np) {
+               enum of_gpio_flags flags;
+               int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
+
+               if (gpio_is_valid(gpio)) {
+                       ret = devm_gpio_request_one(&i2c_client->dev, gpio,
+                                    flags & OF_GPIO_ACTIVE_LOW ?
+                                       GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
+                                    "cs4270 reset");
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
+       cs4270->regmap = devm_regmap_init_i2c(i2c_client, &cs4270_regmap);
+       if (IS_ERR(cs4270->regmap))
+               return PTR_ERR(cs4270->regmap);
 
-       ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);
+       /* Verify that we have a CS4270 */
+       ret = regmap_read(cs4270->regmap, CS4270_CHIPID, &val);
        if (ret < 0) {
                dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n",
                       i2c_client->addr);
                return ret;
        }
        /* The top four bits of the chip ID should be 1100. */
-       if ((ret & 0xF0) != 0xC0) {
+       if ((val & 0xF0) != 0xC0) {
                dev_err(&i2c_client->dev, "device at addr %X is not a CS4270\n",
                       i2c_client->addr);
                return -ENODEV;
@@ -670,17 +703,9 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
 
        dev_info(&i2c_client->dev, "found device at i2c address %X\n",
                i2c_client->addr);
-       dev_info(&i2c_client->dev, "hardware revision %X\n", ret & 0xF);
-
-       cs4270 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs4270_private),
-                             GFP_KERNEL);
-       if (!cs4270) {
-               dev_err(&i2c_client->dev, "could not allocate codec\n");
-               return -ENOMEM;
-       }
+       dev_info(&i2c_client->dev, "hardware revision %X\n", val & 0xF);
 
        i2c_set_clientdata(i2c_client, cs4270);
-       cs4270->control_type = SND_SOC_I2C;
 
        ret = snd_soc_register_codec(&i2c_client->dev,
                        &soc_codec_device_cs4270, &cs4270_dai, 1);
@@ -718,23 +743,14 @@ static struct i2c_driver cs4270_i2c_driver = {
        .driver = {
                .name = "cs4270",
                .owner = THIS_MODULE,
+               .of_match_table = cs4270_of_match,
        },
        .id_table = cs4270_id,
        .probe = cs4270_i2c_probe,
        .remove = cs4270_i2c_remove,
 };
 
-static int __init cs4270_init(void)
-{
-       return i2c_add_driver(&cs4270_i2c_driver);
-}
-module_init(cs4270_init);
-
-static void __exit cs4270_exit(void)
-{
-       i2c_del_driver(&cs4270_i2c_driver);
-}
-module_exit(cs4270_exit);
+module_i2c_driver(cs4270_i2c_driver);
 
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
 MODULE_DESCRIPTION("Cirrus Logic CS4270 ALSA SoC Codec Driver");
index 9eb01d7d58a36f44c001b88556a466758c0eba49..f994af34f552f4b08c4e01880c3410a4890afb7c 100644 (file)
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/tlv.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/spi/spi.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
 #include <sound/cs4271.h>
 
 #define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
@@ -458,6 +460,14 @@ static int cs4271_soc_resume(struct snd_soc_codec *codec)
 #define cs4271_soc_resume      NULL
 #endif /* CONFIG_PM */
 
+#ifdef CONFIG_OF
+static const struct of_device_id cs4271_dt_ids[] = {
+       { .compatible = "cirrus,cs4271", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, cs4271_dt_ids);
+#endif
+
 static int cs4271_probe(struct snd_soc_codec *codec)
 {
        struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
@@ -465,6 +475,12 @@ static int cs4271_probe(struct snd_soc_codec *codec)
        int ret;
        int gpio_nreset = -EINVAL;
 
+#ifdef CONFIG_OF
+       if (of_match_device(cs4271_dt_ids, codec->dev))
+               gpio_nreset = of_get_named_gpio(codec->dev->of_node,
+                                               "reset-gpio", 0);
+#endif
+
        if (cs4271plat && gpio_is_valid(cs4271plat->gpio_nreset))
                gpio_nreset = cs4271plat->gpio_nreset;
 
@@ -569,6 +585,7 @@ static struct spi_driver cs4271_spi_driver = {
        .driver = {
                .name   = "cs4271",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(cs4271_dt_ids),
        },
        .probe          = cs4271_spi_probe,
        .remove         = __devexit_p(cs4271_spi_remove),
@@ -608,6 +625,7 @@ static struct i2c_driver cs4271_i2c_driver = {
        .driver = {
                .name   = "cs4271",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(cs4271_dt_ids),
        },
        .id_table       = cs4271_i2c_id,
        .probe          = cs4271_i2c_probe,
index 091d0193f507df21553be5515efc5f6836cd88d9..1e0fa3b5f79a5e5659ec76acf5c4a70457fad328 100644 (file)
@@ -614,24 +614,7 @@ static struct i2c_driver cs42l51_i2c_driver = {
        .remove = cs42l51_i2c_remove,
 };
 
-static int __init cs42l51_init(void)
-{
-       int ret;
-
-       ret = i2c_add_driver(&cs42l51_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "%s: can't add i2c driver\n", __func__);
-               return ret;
-       }
-       return 0;
-}
-module_init(cs42l51_init);
-
-static void __exit cs42l51_exit(void)
-{
-       i2c_del_driver(&cs42l51_i2c_driver);
-}
-module_exit(cs42l51_exit);
+module_i2c_driver(cs42l51_i2c_driver);
 
 MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
 MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
index 628daf6a1d97e8fee699f8d87ea92ec6dbf5fdaf..61599298fb26c32bdb193e1be0ccb33d2490a0af 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
-#include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c
new file mode 100644 (file)
index 0000000..185d8dd
--- /dev/null
@@ -0,0 +1,1510 @@
+/*
+ * DA9055 ALSA Soc codec driver
+ *
+ * Copyright (c) 2012 Dialog Semiconductor
+ *
+ * Tested on (Samsung SMDK6410 board + DA9055 EVB) using I2S and I2C
+ * Written by David Chen <david.chen@diasemi.com> and
+ * Ashish Chavan <ashish.chavan@kpitcummins.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/delay.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/da9055.h>
+
+/* DA9055 register space */
+
+/* Status Registers */
+#define DA9055_STATUS1                 0x02
+#define DA9055_PLL_STATUS              0x03
+#define DA9055_AUX_L_GAIN_STATUS       0x04
+#define DA9055_AUX_R_GAIN_STATUS       0x05
+#define DA9055_MIC_L_GAIN_STATUS       0x06
+#define DA9055_MIC_R_GAIN_STATUS       0x07
+#define DA9055_MIXIN_L_GAIN_STATUS     0x08
+#define DA9055_MIXIN_R_GAIN_STATUS     0x09
+#define DA9055_ADC_L_GAIN_STATUS       0x0A
+#define DA9055_ADC_R_GAIN_STATUS       0x0B
+#define DA9055_DAC_L_GAIN_STATUS       0x0C
+#define DA9055_DAC_R_GAIN_STATUS       0x0D
+#define DA9055_HP_L_GAIN_STATUS                0x0E
+#define DA9055_HP_R_GAIN_STATUS                0x0F
+#define DA9055_LINE_GAIN_STATUS                0x10
+
+/* System Initialisation Registers */
+#define DA9055_CIF_CTRL                        0x20
+#define DA9055_DIG_ROUTING_AIF         0X21
+#define DA9055_SR                      0x22
+#define DA9055_REFERENCES              0x23
+#define DA9055_PLL_FRAC_TOP            0x24
+#define DA9055_PLL_FRAC_BOT            0x25
+#define DA9055_PLL_INTEGER             0x26
+#define DA9055_PLL_CTRL                        0x27
+#define DA9055_AIF_CLK_MODE            0x28
+#define DA9055_AIF_CTRL                        0x29
+#define DA9055_DIG_ROUTING_DAC         0x2A
+#define DA9055_ALC_CTRL1               0x2B
+
+/* Input - Gain, Select and Filter Registers */
+#define DA9055_AUX_L_GAIN              0x30
+#define DA9055_AUX_R_GAIN              0x31
+#define DA9055_MIXIN_L_SELECT          0x32
+#define DA9055_MIXIN_R_SELECT          0x33
+#define DA9055_MIXIN_L_GAIN            0x34
+#define DA9055_MIXIN_R_GAIN            0x35
+#define DA9055_ADC_L_GAIN              0x36
+#define DA9055_ADC_R_GAIN              0x37
+#define DA9055_ADC_FILTERS1            0x38
+#define DA9055_MIC_L_GAIN              0x39
+#define DA9055_MIC_R_GAIN              0x3A
+
+/* Output - Gain, Select and Filter Registers */
+#define DA9055_DAC_FILTERS5            0x40
+#define DA9055_DAC_FILTERS2            0x41
+#define DA9055_DAC_FILTERS3            0x42
+#define DA9055_DAC_FILTERS4            0x43
+#define DA9055_DAC_FILTERS1            0x44
+#define DA9055_DAC_L_GAIN              0x45
+#define DA9055_DAC_R_GAIN              0x46
+#define DA9055_CP_CTRL                 0x47
+#define DA9055_HP_L_GAIN               0x48
+#define DA9055_HP_R_GAIN               0x49
+#define DA9055_LINE_GAIN               0x4A
+#define DA9055_MIXOUT_L_SELECT         0x4B
+#define DA9055_MIXOUT_R_SELECT         0x4C
+
+/* System Controller Registers */
+#define DA9055_SYSTEM_MODES_INPUT      0x50
+#define DA9055_SYSTEM_MODES_OUTPUT     0x51
+
+/* Control Registers */
+#define DA9055_AUX_L_CTRL              0x60
+#define DA9055_AUX_R_CTRL              0x61
+#define DA9055_MIC_BIAS_CTRL           0x62
+#define DA9055_MIC_L_CTRL              0x63
+#define DA9055_MIC_R_CTRL              0x64
+#define DA9055_MIXIN_L_CTRL            0x65
+#define DA9055_MIXIN_R_CTRL            0x66
+#define DA9055_ADC_L_CTRL              0x67
+#define DA9055_ADC_R_CTRL              0x68
+#define DA9055_DAC_L_CTRL              0x69
+#define DA9055_DAC_R_CTRL              0x6A
+#define DA9055_HP_L_CTRL               0x6B
+#define DA9055_HP_R_CTRL               0x6C
+#define DA9055_LINE_CTRL               0x6D
+#define DA9055_MIXOUT_L_CTRL           0x6E
+#define DA9055_MIXOUT_R_CTRL           0x6F
+
+/* Configuration Registers */
+#define DA9055_LDO_CTRL                        0x90
+#define DA9055_IO_CTRL                 0x91
+#define DA9055_GAIN_RAMP_CTRL          0x92
+#define DA9055_MIC_CONFIG              0x93
+#define DA9055_PC_COUNT                        0x94
+#define DA9055_CP_VOL_THRESHOLD1       0x95
+#define DA9055_CP_DELAY                        0x96
+#define DA9055_CP_DETECTOR             0x97
+#define DA9055_AIF_OFFSET              0x98
+#define DA9055_DIG_CTRL                        0x99
+#define DA9055_ALC_CTRL2               0x9A
+#define DA9055_ALC_CTRL3               0x9B
+#define DA9055_ALC_NOISE               0x9C
+#define DA9055_ALC_TARGET_MIN          0x9D
+#define DA9055_ALC_TARGET_MAX          0x9E
+#define DA9055_ALC_GAIN_LIMITS         0x9F
+#define DA9055_ALC_ANA_GAIN_LIMITS     0xA0
+#define DA9055_ALC_ANTICLIP_CTRL       0xA1
+#define DA9055_ALC_ANTICLIP_LEVEL      0xA2
+#define DA9055_ALC_OFFSET_OP2M_L       0xA6
+#define DA9055_ALC_OFFSET_OP2U_L       0xA7
+#define DA9055_ALC_OFFSET_OP2M_R       0xAB
+#define DA9055_ALC_OFFSET_OP2U_R       0xAC
+#define DA9055_ALC_CIC_OP_LVL_CTRL     0xAD
+#define DA9055_ALC_CIC_OP_LVL_DATA     0xAE
+#define DA9055_DAC_NG_SETUP_TIME       0xAF
+#define DA9055_DAC_NG_OFF_THRESHOLD    0xB0
+#define DA9055_DAC_NG_ON_THRESHOLD     0xB1
+#define DA9055_DAC_NG_CTRL             0xB2
+
+/* SR bit fields */
+#define DA9055_SR_8000                 (0x1 << 0)
+#define DA9055_SR_11025                        (0x2 << 0)
+#define DA9055_SR_12000                        (0x3 << 0)
+#define DA9055_SR_16000                        (0x5 << 0)
+#define DA9055_SR_22050                        (0x6 << 0)
+#define DA9055_SR_24000                        (0x7 << 0)
+#define DA9055_SR_32000                        (0x9 << 0)
+#define DA9055_SR_44100                        (0xA << 0)
+#define DA9055_SR_48000                        (0xB << 0)
+#define DA9055_SR_88200                        (0xE << 0)
+#define DA9055_SR_96000                        (0xF << 0)
+
+/* REFERENCES bit fields */
+#define DA9055_BIAS_EN                 (1 << 3)
+#define DA9055_VMID_EN                 (1 << 7)
+
+/* PLL_CTRL bit fields */
+#define DA9055_PLL_INDIV_10_20_MHZ     (1 << 2)
+#define DA9055_PLL_SRM_EN              (1 << 6)
+#define DA9055_PLL_EN                  (1 << 7)
+
+/* AIF_CLK_MODE bit fields */
+#define DA9055_AIF_BCLKS_PER_WCLK_32   (0 << 0)
+#define DA9055_AIF_BCLKS_PER_WCLK_64   (1 << 0)
+#define DA9055_AIF_BCLKS_PER_WCLK_128  (2 << 0)
+#define DA9055_AIF_BCLKS_PER_WCLK_256  (3 << 0)
+#define DA9055_AIF_CLK_EN_SLAVE_MODE   (0 << 7)
+#define DA9055_AIF_CLK_EN_MASTER_MODE  (1 << 7)
+
+/* AIF_CTRL bit fields */
+#define DA9055_AIF_FORMAT_I2S_MODE     (0 << 0)
+#define DA9055_AIF_FORMAT_LEFT_J       (1 << 0)
+#define DA9055_AIF_FORMAT_RIGHT_J      (2 << 0)
+#define DA9055_AIF_WORD_S16_LE         (0 << 2)
+#define DA9055_AIF_WORD_S20_3LE                (1 << 2)
+#define DA9055_AIF_WORD_S24_LE         (2 << 2)
+#define DA9055_AIF_WORD_S32_LE         (3 << 2)
+
+/* MIXIN_L_CTRL bit fields */
+#define DA9055_MIXIN_L_MIX_EN          (1 << 3)
+
+/* MIXIN_R_CTRL bit fields */
+#define DA9055_MIXIN_R_MIX_EN          (1 << 3)
+
+/* ADC_L_CTRL bit fields */
+#define DA9055_ADC_L_EN                        (1 << 7)
+
+/* ADC_R_CTRL bit fields */
+#define DA9055_ADC_R_EN                        (1 << 7)
+
+/* DAC_L_CTRL bit fields */
+#define DA9055_DAC_L_MUTE_EN           (1 << 6)
+
+/* DAC_R_CTRL bit fields */
+#define DA9055_DAC_R_MUTE_EN           (1 << 6)
+
+/* HP_L_CTRL bit fields */
+#define DA9055_HP_L_AMP_OE             (1 << 3)
+
+/* HP_R_CTRL bit fields */
+#define DA9055_HP_R_AMP_OE             (1 << 3)
+
+/* LINE_CTRL bit fields */
+#define DA9055_LINE_AMP_OE             (1 << 3)
+
+/* MIXOUT_L_CTRL bit fields */
+#define DA9055_MIXOUT_L_MIX_EN         (1 << 3)
+
+/* MIXOUT_R_CTRL bit fields */
+#define DA9055_MIXOUT_R_MIX_EN         (1 << 3)
+
+/* MIC bias select bit fields */
+#define DA9055_MICBIAS2_EN             (1 << 6)
+
+/* ALC_CIC_OP_LEVEL_CTRL bit fields */
+#define DA9055_ALC_DATA_MIDDLE         (2 << 0)
+#define DA9055_ALC_DATA_TOP            (3 << 0)
+#define DA9055_ALC_CIC_OP_CHANNEL_LEFT (0 << 7)
+#define DA9055_ALC_CIC_OP_CHANNEL_RIGHT        (1 << 7)
+
+#define DA9055_AIF_BCLK_MASK           (3 << 0)
+#define DA9055_AIF_CLK_MODE_MASK       (1 << 7)
+#define DA9055_AIF_FORMAT_MASK         (3 << 0)
+#define DA9055_AIF_WORD_LENGTH_MASK    (3 << 2)
+#define DA9055_GAIN_RAMPING_EN         (1 << 5)
+#define DA9055_MICBIAS_LEVEL_MASK      (3 << 4)
+
+#define DA9055_ALC_OFFSET_15_8         0x00FF00
+#define DA9055_ALC_OFFSET_17_16                0x030000
+#define DA9055_ALC_AVG_ITERATIONS      5
+
+struct pll_div {
+       int fref;
+       int fout;
+       u8 frac_top;
+       u8 frac_bot;
+       u8 integer;
+       u8 mode;        /* 0 = slave, 1 = master */
+};
+
+/* PLL divisor table */
+static const struct pll_div da9055_pll_div[] = {
+       /* for MASTER mode, fs = 44.1Khz and its harmonics */
+       {11289600, 2822400, 0x00, 0x00, 0x20, 1},       /* MCLK=11.2896Mhz */
+       {12000000, 2822400, 0x03, 0x61, 0x1E, 1},       /* MCLK=12Mhz */
+       {12288000, 2822400, 0x0C, 0xCC, 0x1D, 1},       /* MCLK=12.288Mhz */
+       {13000000, 2822400, 0x19, 0x45, 0x1B, 1},       /* MCLK=13Mhz */
+       {13500000, 2822400, 0x18, 0x56, 0x1A, 1},       /* MCLK=13.5Mhz */
+       {14400000, 2822400, 0x02, 0xD0, 0x19, 1},       /* MCLK=14.4Mhz */
+       {19200000, 2822400, 0x1A, 0x1C, 0x12, 1},       /* MCLK=19.2Mhz */
+       {19680000, 2822400, 0x0B, 0x6D, 0x12, 1},       /* MCLK=19.68Mhz */
+       {19800000, 2822400, 0x07, 0xDD, 0x12, 1},       /* MCLK=19.8Mhz */
+       /* for MASTER mode, fs = 48Khz and its harmonics */
+       {11289600, 3072000, 0x1A, 0x8E, 0x22, 1},       /* MCLK=11.2896Mhz */
+       {12000000, 3072000, 0x18, 0x93, 0x20, 1},       /* MCLK=12Mhz */
+       {12288000, 3072000, 0x00, 0x00, 0x20, 1},       /* MCLK=12.288Mhz */
+       {13000000, 3072000, 0x07, 0xEA, 0x1E, 1},       /* MCLK=13Mhz */
+       {13500000, 3072000, 0x04, 0x11, 0x1D, 1},       /* MCLK=13.5Mhz */
+       {14400000, 3072000, 0x09, 0xD0, 0x1B, 1},       /* MCLK=14.4Mhz */
+       {19200000, 3072000, 0x0F, 0x5C, 0x14, 1},       /* MCLK=19.2Mhz */
+       {19680000, 3072000, 0x1F, 0x60, 0x13, 1},       /* MCLK=19.68Mhz */
+       {19800000, 3072000, 0x1B, 0x80, 0x13, 1},       /* MCLK=19.8Mhz */
+       /* for SLAVE mode with SRM */
+       {11289600, 2822400, 0x0D, 0x47, 0x21, 0},       /* MCLK=11.2896Mhz */
+       {12000000, 2822400, 0x0D, 0xFA, 0x1F, 0},       /* MCLK=12Mhz */
+       {12288000, 2822400, 0x16, 0x66, 0x1E, 0},       /* MCLK=12.288Mhz */
+       {13000000, 2822400, 0x00, 0x98, 0x1D, 0},       /* MCLK=13Mhz */
+       {13500000, 2822400, 0x1E, 0x33, 0x1B, 0},       /* MCLK=13.5Mhz */
+       {14400000, 2822400, 0x06, 0x50, 0x1A, 0},       /* MCLK=14.4Mhz */
+       {19200000, 2822400, 0x14, 0xBC, 0x13, 0},       /* MCLK=19.2Mhz */
+       {19680000, 2822400, 0x05, 0x66, 0x13, 0},       /* MCLK=19.68Mhz */
+       {19800000, 2822400, 0x01, 0xAE, 0x13, 0},       /* MCLK=19.8Mhz  */
+};
+
+enum clk_src {
+       DA9055_CLKSRC_MCLK
+};
+
+/* Gain and Volume */
+
+static const unsigned int aux_vol_tlv[] = {
+       TLV_DB_RANGE_HEAD(2),
+       0x0, 0x10, TLV_DB_SCALE_ITEM(-5400, 0, 0),
+       /* -54dB to 15dB */
+       0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0)
+};
+
+static const unsigned int digital_gain_tlv[] = {
+       TLV_DB_RANGE_HEAD(2),
+       0x0, 0x07, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
+       /* -78dB to 12dB */
+       0x08, 0x7f, TLV_DB_SCALE_ITEM(-7800, 75, 0)
+};
+
+static const unsigned int alc_analog_gain_tlv[] = {
+       TLV_DB_RANGE_HEAD(2),
+       0x0, 0x0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
+       /* 0dB to 36dB */
+       0x01, 0x07, TLV_DB_SCALE_ITEM(0, 600, 0)
+};
+
+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(mixin_gain_tlv, -450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(eq_gain_tlv, -1050, 150, 0);
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -5700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(lineout_vol_tlv, -4800, 100, 0);
+static const DECLARE_TLV_DB_SCALE(alc_threshold_tlv, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(alc_gain_tlv, 0, 600, 0);
+
+/* ADC and DAC high pass filter cutoff value */
+static const char * const da9055_hpf_cutoff_txt[] = {
+       "Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000"
+};
+
+static const struct soc_enum da9055_dac_hpf_cutoff =
+       SOC_ENUM_SINGLE(DA9055_DAC_FILTERS1, 4, 4, da9055_hpf_cutoff_txt);
+
+static const struct soc_enum da9055_adc_hpf_cutoff =
+       SOC_ENUM_SINGLE(DA9055_ADC_FILTERS1, 4, 4, da9055_hpf_cutoff_txt);
+
+/* ADC and DAC voice mode (8kHz) high pass cutoff value */
+static const char * const da9055_vf_cutoff_txt[] = {
+       "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
+};
+
+static const struct soc_enum da9055_dac_vf_cutoff =
+       SOC_ENUM_SINGLE(DA9055_DAC_FILTERS1, 0, 8, da9055_vf_cutoff_txt);
+
+static const struct soc_enum da9055_adc_vf_cutoff =
+       SOC_ENUM_SINGLE(DA9055_ADC_FILTERS1, 0, 8, da9055_vf_cutoff_txt);
+
+/* Gain ramping rate value */
+static const char * const da9055_gain_ramping_txt[] = {
+       "nominal rate", "nominal rate * 4", "nominal rate * 8",
+       "nominal rate / 8"
+};
+
+static const struct soc_enum da9055_gain_ramping_rate =
+       SOC_ENUM_SINGLE(DA9055_GAIN_RAMP_CTRL, 0, 4, da9055_gain_ramping_txt);
+
+/* DAC noise gate setup time value */
+static const char * const da9055_dac_ng_setup_time_txt[] = {
+       "256 samples", "512 samples", "1024 samples", "2048 samples"
+};
+
+static const struct soc_enum da9055_dac_ng_setup_time =
+       SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 0, 4,
+                       da9055_dac_ng_setup_time_txt);
+
+/* DAC noise gate rampup rate value */
+static const char * const da9055_dac_ng_rampup_txt[] = {
+       "0.02 ms/dB", "0.16 ms/dB"
+};
+
+static const struct soc_enum da9055_dac_ng_rampup_rate =
+       SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 2, 2,
+                       da9055_dac_ng_rampup_txt);
+
+/* DAC noise gate rampdown rate value */
+static const char * const da9055_dac_ng_rampdown_txt[] = {
+       "0.64 ms/dB", "20.48 ms/dB"
+};
+
+static const struct soc_enum da9055_dac_ng_rampdown_rate =
+       SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 3, 2,
+                       da9055_dac_ng_rampdown_txt);
+
+/* DAC soft mute rate value */
+static const char * const da9055_dac_soft_mute_rate_txt[] = {
+       "1", "2", "4", "8", "16", "32", "64"
+};
+
+static const struct soc_enum da9055_dac_soft_mute_rate =
+       SOC_ENUM_SINGLE(DA9055_DAC_FILTERS5, 4, 7,
+                       da9055_dac_soft_mute_rate_txt);
+
+/* DAC routing select */
+static const char * const da9055_dac_src_txt[] = {
+       "ADC output left", "ADC output right", "AIF input left",
+       "AIF input right"
+};
+
+static const struct soc_enum da9055_dac_l_src =
+       SOC_ENUM_SINGLE(DA9055_DIG_ROUTING_DAC, 0, 4, da9055_dac_src_txt);
+
+static const struct soc_enum da9055_dac_r_src =
+       SOC_ENUM_SINGLE(DA9055_DIG_ROUTING_DAC, 4, 4, da9055_dac_src_txt);
+
+/* MIC PGA Left source select */
+static const char * const da9055_mic_l_src_txt[] = {
+       "MIC1_P_N", "MIC1_P", "MIC1_N", "MIC2_L"
+};
+
+static const struct soc_enum da9055_mic_l_src =
+       SOC_ENUM_SINGLE(DA9055_MIXIN_L_SELECT, 4, 4, da9055_mic_l_src_txt);
+
+/* MIC PGA Right source select */
+static const char * const da9055_mic_r_src_txt[] = {
+       "MIC2_R_L", "MIC2_R", "MIC2_L"
+};
+
+static const struct soc_enum da9055_mic_r_src =
+       SOC_ENUM_SINGLE(DA9055_MIXIN_R_SELECT, 4, 3, da9055_mic_r_src_txt);
+
+/* ALC Input Signal Tracking rate select */
+static const char * const da9055_signal_tracking_rate_txt[] = {
+       "1/4", "1/16", "1/256", "1/65536"
+};
+
+static const struct soc_enum da9055_integ_attack_rate =
+       SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 4, 4,
+                       da9055_signal_tracking_rate_txt);
+
+static const struct soc_enum da9055_integ_release_rate =
+       SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 6, 4,
+                       da9055_signal_tracking_rate_txt);
+
+/* ALC Attack Rate select */
+static const char * const da9055_attack_rate_txt[] = {
+       "44/fs", "88/fs", "176/fs", "352/fs", "704/fs", "1408/fs", "2816/fs",
+       "5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs"
+};
+
+static const struct soc_enum da9055_attack_rate =
+       SOC_ENUM_SINGLE(DA9055_ALC_CTRL2, 0, 13, da9055_attack_rate_txt);
+
+/* ALC Release Rate select */
+static const char * const da9055_release_rate_txt[] = {
+       "176/fs", "352/fs", "704/fs", "1408/fs", "2816/fs", "5632/fs",
+       "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs"
+};
+
+static const struct soc_enum da9055_release_rate =
+       SOC_ENUM_SINGLE(DA9055_ALC_CTRL2, 4, 11, da9055_release_rate_txt);
+
+/* ALC Hold Time select */
+static const char * const da9055_hold_time_txt[] = {
+       "62/fs", "124/fs", "248/fs", "496/fs", "992/fs", "1984/fs", "3968/fs",
+       "7936/fs", "15872/fs", "31744/fs", "63488/fs", "126976/fs",
+       "253952/fs", "507904/fs", "1015808/fs", "2031616/fs"
+};
+
+static const struct soc_enum da9055_hold_time =
+       SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 0, 16, da9055_hold_time_txt);
+
+static int da9055_get_alc_data(struct snd_soc_codec *codec, u8 reg_val)
+{
+       int mid_data, top_data;
+       int sum = 0;
+       u8 iteration;
+
+       for (iteration = 0; iteration < DA9055_ALC_AVG_ITERATIONS;
+            iteration++) {
+               /* Select the left or right channel and capture data */
+               snd_soc_write(codec, DA9055_ALC_CIC_OP_LVL_CTRL, reg_val);
+
+               /* Select middle 8 bits for read back from data register */
+               snd_soc_write(codec, DA9055_ALC_CIC_OP_LVL_CTRL,
+                             reg_val | DA9055_ALC_DATA_MIDDLE);
+               mid_data = snd_soc_read(codec, DA9055_ALC_CIC_OP_LVL_DATA);
+
+               /* Select top 8 bits for read back from data register */
+               snd_soc_write(codec, DA9055_ALC_CIC_OP_LVL_CTRL,
+                             reg_val | DA9055_ALC_DATA_TOP);
+               top_data = snd_soc_read(codec, DA9055_ALC_CIC_OP_LVL_DATA);
+
+               sum += ((mid_data << 8) | (top_data << 16));
+       }
+
+       return sum / DA9055_ALC_AVG_ITERATIONS;
+}
+
+static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       u8 reg_val, adc_left, adc_right;
+       int avg_left_data, avg_right_data, offset_l, offset_r;
+
+       if (ucontrol->value.integer.value[0]) {
+               /*
+                * While enabling ALC (or ALC sync mode), calibration of the DC
+                * offsets must be done first
+                */
+
+               /* Save current values from ADC control registers */
+               adc_left = snd_soc_read(codec, DA9055_ADC_L_CTRL);
+               adc_right = snd_soc_read(codec, DA9055_ADC_R_CTRL);
+
+               /* Enable ADC Left and Right */
+               snd_soc_update_bits(codec, DA9055_ADC_L_CTRL,
+                                   DA9055_ADC_L_EN, DA9055_ADC_L_EN);
+               snd_soc_update_bits(codec, DA9055_ADC_R_CTRL,
+                                   DA9055_ADC_R_EN, DA9055_ADC_R_EN);
+
+               /* Calculate average for Left and Right data */
+               /* Left Data */
+               avg_left_data = da9055_get_alc_data(codec,
+                               DA9055_ALC_CIC_OP_CHANNEL_LEFT);
+               /* Right Data */
+               avg_right_data = da9055_get_alc_data(codec,
+                                DA9055_ALC_CIC_OP_CHANNEL_RIGHT);
+
+               /* Calculate DC offset */
+               offset_l = -avg_left_data;
+               offset_r = -avg_right_data;
+
+               reg_val = (offset_l & DA9055_ALC_OFFSET_15_8) >> 8;
+               snd_soc_write(codec, DA9055_ALC_OFFSET_OP2M_L, reg_val);
+               reg_val = (offset_l & DA9055_ALC_OFFSET_17_16) >> 16;
+               snd_soc_write(codec, DA9055_ALC_OFFSET_OP2U_L, reg_val);
+
+               reg_val = (offset_r & DA9055_ALC_OFFSET_15_8) >> 8;
+               snd_soc_write(codec, DA9055_ALC_OFFSET_OP2M_R, reg_val);
+               reg_val = (offset_r & DA9055_ALC_OFFSET_17_16) >> 16;
+               snd_soc_write(codec, DA9055_ALC_OFFSET_OP2U_R, reg_val);
+
+               /* Restore original values of ADC control registers */
+               snd_soc_write(codec, DA9055_ADC_L_CTRL, adc_left);
+               snd_soc_write(codec, DA9055_ADC_R_CTRL, adc_right);
+       }
+
+       return snd_soc_put_volsw(kcontrol, ucontrol);
+}
+
+static const struct snd_kcontrol_new da9055_snd_controls[] = {
+
+       /* Volume controls */
+       SOC_DOUBLE_R_TLV("Mic Volume",
+                        DA9055_MIC_L_GAIN, DA9055_MIC_R_GAIN,
+                        0, 0x7, 0, mic_vol_tlv),
+       SOC_DOUBLE_R_TLV("Aux Volume",
+                        DA9055_AUX_L_GAIN, DA9055_AUX_R_GAIN,
+                        0, 0x3f, 0, aux_vol_tlv),
+       SOC_DOUBLE_R_TLV("Mixin PGA Volume",
+                        DA9055_MIXIN_L_GAIN, DA9055_MIXIN_R_GAIN,
+                        0, 0xf, 0, mixin_gain_tlv),
+       SOC_DOUBLE_R_TLV("ADC Volume",
+                        DA9055_ADC_L_GAIN, DA9055_ADC_R_GAIN,
+                        0, 0x7f, 0, digital_gain_tlv),
+
+       SOC_DOUBLE_R_TLV("DAC Volume",
+                        DA9055_DAC_L_GAIN, DA9055_DAC_R_GAIN,
+                        0, 0x7f, 0, digital_gain_tlv),
+       SOC_DOUBLE_R_TLV("Headphone Volume",
+                        DA9055_HP_L_GAIN, DA9055_HP_R_GAIN,
+                        0, 0x3f, 0, hp_vol_tlv),
+       SOC_SINGLE_TLV("Lineout Volume", DA9055_LINE_GAIN, 0, 0x3f, 0,
+                      lineout_vol_tlv),
+
+       /* DAC Equalizer controls */
+       SOC_SINGLE("DAC EQ Switch", DA9055_DAC_FILTERS4, 7, 1, 0),
+       SOC_SINGLE_TLV("DAC EQ1 Volume", DA9055_DAC_FILTERS2, 0, 0xf, 0,
+                      eq_gain_tlv),
+       SOC_SINGLE_TLV("DAC EQ2 Volume", DA9055_DAC_FILTERS2, 4, 0xf, 0,
+                      eq_gain_tlv),
+       SOC_SINGLE_TLV("DAC EQ3 Volume", DA9055_DAC_FILTERS3, 0, 0xf, 0,
+                      eq_gain_tlv),
+       SOC_SINGLE_TLV("DAC EQ4 Volume", DA9055_DAC_FILTERS3, 4, 0xf, 0,
+                      eq_gain_tlv),
+       SOC_SINGLE_TLV("DAC EQ5 Volume", DA9055_DAC_FILTERS4, 0, 0xf, 0,
+                      eq_gain_tlv),
+
+       /* High Pass Filter and Voice Mode controls */
+       SOC_SINGLE("ADC HPF Switch", DA9055_ADC_FILTERS1, 7, 1, 0),
+       SOC_ENUM("ADC HPF Cutoff", da9055_adc_hpf_cutoff),
+       SOC_SINGLE("ADC Voice Mode Switch", DA9055_ADC_FILTERS1, 3, 1, 0),
+       SOC_ENUM("ADC Voice Cutoff", da9055_adc_vf_cutoff),
+
+       SOC_SINGLE("DAC HPF Switch", DA9055_DAC_FILTERS1, 7, 1, 0),
+       SOC_ENUM("DAC HPF Cutoff", da9055_dac_hpf_cutoff),
+       SOC_SINGLE("DAC Voice Mode Switch", DA9055_DAC_FILTERS1, 3, 1, 0),
+       SOC_ENUM("DAC Voice Cutoff", da9055_dac_vf_cutoff),
+
+       /* Mute controls */
+       SOC_DOUBLE_R("Mic Switch", DA9055_MIC_L_CTRL,
+                    DA9055_MIC_R_CTRL, 6, 1, 0),
+       SOC_DOUBLE_R("Aux Switch", DA9055_AUX_L_CTRL,
+                    DA9055_AUX_R_CTRL, 6, 1, 0),
+       SOC_DOUBLE_R("Mixin PGA Switch", DA9055_MIXIN_L_CTRL,
+                    DA9055_MIXIN_R_CTRL, 6, 1, 0),
+       SOC_DOUBLE_R("ADC Switch", DA9055_ADC_L_CTRL,
+                    DA9055_ADC_R_CTRL, 6, 1, 0),
+       SOC_DOUBLE_R("Headphone Switch", DA9055_HP_L_CTRL,
+                    DA9055_HP_R_CTRL, 6, 1, 0),
+       SOC_SINGLE("Lineout Switch", DA9055_LINE_CTRL, 6, 1, 0),
+       SOC_SINGLE("DAC Soft Mute Switch", DA9055_DAC_FILTERS5, 7, 1, 0),
+       SOC_ENUM("DAC Soft Mute Rate", da9055_dac_soft_mute_rate),
+
+       /* Zero Cross controls */
+       SOC_DOUBLE_R("Aux ZC Switch", DA9055_AUX_L_CTRL,
+                    DA9055_AUX_R_CTRL, 4, 1, 0),
+       SOC_DOUBLE_R("Mixin PGA ZC Switch", DA9055_MIXIN_L_CTRL,
+                    DA9055_MIXIN_R_CTRL, 4, 1, 0),
+       SOC_DOUBLE_R("Headphone ZC Switch", DA9055_HP_L_CTRL,
+                    DA9055_HP_R_CTRL, 4, 1, 0),
+       SOC_SINGLE("Lineout ZC Switch", DA9055_LINE_CTRL, 4, 1, 0),
+
+       /* Gain Ramping controls */
+       SOC_DOUBLE_R("Aux Gain Ramping Switch", DA9055_AUX_L_CTRL,
+                    DA9055_AUX_R_CTRL, 5, 1, 0),
+       SOC_DOUBLE_R("Mixin Gain Ramping Switch", DA9055_MIXIN_L_CTRL,
+                    DA9055_MIXIN_R_CTRL, 5, 1, 0),
+       SOC_DOUBLE_R("ADC Gain Ramping Switch", DA9055_ADC_L_CTRL,
+                    DA9055_ADC_R_CTRL, 5, 1, 0),
+       SOC_DOUBLE_R("DAC Gain Ramping Switch", DA9055_DAC_L_CTRL,
+                    DA9055_DAC_R_CTRL, 5, 1, 0),
+       SOC_DOUBLE_R("Headphone Gain Ramping Switch", DA9055_HP_L_CTRL,
+                    DA9055_HP_R_CTRL, 5, 1, 0),
+       SOC_SINGLE("Lineout Gain Ramping Switch", DA9055_LINE_CTRL, 5, 1, 0),
+       SOC_ENUM("Gain Ramping Rate", da9055_gain_ramping_rate),
+
+       /* DAC Noise Gate controls */
+       SOC_SINGLE("DAC NG Switch", DA9055_DAC_NG_CTRL, 7, 1, 0),
+       SOC_SINGLE("DAC NG ON Threshold", DA9055_DAC_NG_ON_THRESHOLD,
+                  0, 0x7, 0),
+       SOC_SINGLE("DAC NG OFF Threshold", DA9055_DAC_NG_OFF_THRESHOLD,
+                  0, 0x7, 0),
+       SOC_ENUM("DAC NG Setup Time", da9055_dac_ng_setup_time),
+       SOC_ENUM("DAC NG Rampup Rate", da9055_dac_ng_rampup_rate),
+       SOC_ENUM("DAC NG Rampdown Rate", da9055_dac_ng_rampdown_rate),
+
+       /* DAC Invertion control */
+       SOC_SINGLE("DAC Left Invert", DA9055_DIG_CTRL, 3, 1, 0),
+       SOC_SINGLE("DAC Right Invert", DA9055_DIG_CTRL, 7, 1, 0),
+
+       /* DMIC controls */
+       SOC_DOUBLE_R("DMIC Switch", DA9055_MIXIN_L_SELECT,
+                    DA9055_MIXIN_R_SELECT, 7, 1, 0),
+
+       /* ALC Controls */
+       SOC_DOUBLE_EXT("ALC Switch", DA9055_ALC_CTRL1, 3, 7, 1, 0,
+                      snd_soc_get_volsw, da9055_put_alc_sw),
+       SOC_SINGLE_EXT("ALC Sync Mode Switch", DA9055_ALC_CTRL1, 1, 1, 0,
+                      snd_soc_get_volsw, da9055_put_alc_sw),
+       SOC_SINGLE("ALC Offset Switch", DA9055_ALC_CTRL1, 0, 1, 0),
+       SOC_SINGLE("ALC Anticlip Mode Switch", DA9055_ALC_ANTICLIP_CTRL,
+                  7, 1, 0),
+       SOC_SINGLE("ALC Anticlip Level", DA9055_ALC_ANTICLIP_LEVEL,
+                  0, 0x7f, 0),
+       SOC_SINGLE_TLV("ALC Min Threshold Volume", DA9055_ALC_TARGET_MIN,
+                      0, 0x3f, 1, alc_threshold_tlv),
+       SOC_SINGLE_TLV("ALC Max Threshold Volume", DA9055_ALC_TARGET_MAX,
+                      0, 0x3f, 1, alc_threshold_tlv),
+       SOC_SINGLE_TLV("ALC Noise Threshold Volume", DA9055_ALC_NOISE,
+                      0, 0x3f, 1, alc_threshold_tlv),
+       SOC_SINGLE_TLV("ALC Max Gain Volume", DA9055_ALC_GAIN_LIMITS,
+                      4, 0xf, 0, alc_gain_tlv),
+       SOC_SINGLE_TLV("ALC Max Attenuation Volume", DA9055_ALC_GAIN_LIMITS,
+                      0, 0xf, 0, alc_gain_tlv),
+       SOC_SINGLE_TLV("ALC Min Analog Gain Volume",
+                      DA9055_ALC_ANA_GAIN_LIMITS,
+                      0, 0x7, 0, alc_analog_gain_tlv),
+       SOC_SINGLE_TLV("ALC Max Analog Gain Volume",
+                      DA9055_ALC_ANA_GAIN_LIMITS,
+                      4, 0x7, 0, alc_analog_gain_tlv),
+       SOC_ENUM("ALC Attack Rate", da9055_attack_rate),
+       SOC_ENUM("ALC Release Rate", da9055_release_rate),
+       SOC_ENUM("ALC Hold Time", da9055_hold_time),
+       /*
+        * Rate at which input signal envelope is tracked as the signal gets
+        * larger
+        */
+       SOC_ENUM("ALC Integ Attack Rate", da9055_integ_attack_rate),
+       /*
+        * Rate at which input signal envelope is tracked as the signal gets
+        * smaller
+        */
+       SOC_ENUM("ALC Integ Release Rate", da9055_integ_release_rate),
+};
+
+/* DAPM Controls */
+
+/* Mic PGA Left Source */
+static const struct snd_kcontrol_new da9055_mic_l_mux_controls =
+SOC_DAPM_ENUM("Route", da9055_mic_l_src);
+
+/* Mic PGA Right Source */
+static const struct snd_kcontrol_new da9055_mic_r_mux_controls =
+SOC_DAPM_ENUM("Route", da9055_mic_r_src);
+
+/* In Mixer Left */
+static const struct snd_kcontrol_new da9055_dapm_mixinl_controls[] = {
+       SOC_DAPM_SINGLE("Aux Left Switch", DA9055_MIXIN_L_SELECT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Mic Left Switch", DA9055_MIXIN_L_SELECT, 1, 1, 0),
+       SOC_DAPM_SINGLE("Mic Right Switch", DA9055_MIXIN_L_SELECT, 2, 1, 0),
+};
+
+/* In Mixer Right */
+static const struct snd_kcontrol_new da9055_dapm_mixinr_controls[] = {
+       SOC_DAPM_SINGLE("Aux Right Switch", DA9055_MIXIN_R_SELECT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Mic Right Switch", DA9055_MIXIN_R_SELECT, 1, 1, 0),
+       SOC_DAPM_SINGLE("Mic Left Switch", DA9055_MIXIN_R_SELECT, 2, 1, 0),
+       SOC_DAPM_SINGLE("Mixin Left Switch", DA9055_MIXIN_R_SELECT, 3, 1, 0),
+};
+
+/* DAC Left Source */
+static const struct snd_kcontrol_new da9055_dac_l_mux_controls =
+SOC_DAPM_ENUM("Route", da9055_dac_l_src);
+
+/* DAC Right Source */
+static const struct snd_kcontrol_new da9055_dac_r_mux_controls =
+SOC_DAPM_ENUM("Route", da9055_dac_r_src);
+
+/* Out Mixer Left */
+static const struct snd_kcontrol_new da9055_dapm_mixoutl_controls[] = {
+       SOC_DAPM_SINGLE("Aux Left Switch", DA9055_MIXOUT_L_SELECT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Mixin Left Switch", DA9055_MIXOUT_L_SELECT, 1, 1, 0),
+       SOC_DAPM_SINGLE("Mixin Right Switch", DA9055_MIXOUT_L_SELECT, 2, 1, 0),
+       SOC_DAPM_SINGLE("DAC Left Switch", DA9055_MIXOUT_L_SELECT, 3, 1, 0),
+       SOC_DAPM_SINGLE("Aux Left Invert Switch", DA9055_MIXOUT_L_SELECT,
+                       4, 1, 0),
+       SOC_DAPM_SINGLE("Mixin Left Invert Switch", DA9055_MIXOUT_L_SELECT,
+                       5, 1, 0),
+       SOC_DAPM_SINGLE("Mixin Right Invert Switch", DA9055_MIXOUT_L_SELECT,
+                       6, 1, 0),
+};
+
+/* Out Mixer Right */
+static const struct snd_kcontrol_new da9055_dapm_mixoutr_controls[] = {
+       SOC_DAPM_SINGLE("Aux Right Switch", DA9055_MIXOUT_R_SELECT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Mixin Right Switch", DA9055_MIXOUT_R_SELECT, 1, 1, 0),
+       SOC_DAPM_SINGLE("Mixin Left Switch", DA9055_MIXOUT_R_SELECT, 2, 1, 0),
+       SOC_DAPM_SINGLE("DAC Right Switch", DA9055_MIXOUT_R_SELECT, 3, 1, 0),
+       SOC_DAPM_SINGLE("Aux Right Invert Switch", DA9055_MIXOUT_R_SELECT,
+                       4, 1, 0),
+       SOC_DAPM_SINGLE("Mixin Right Invert Switch", DA9055_MIXOUT_R_SELECT,
+                       5, 1, 0),
+       SOC_DAPM_SINGLE("Mixin Left Invert Switch", DA9055_MIXOUT_R_SELECT,
+                       6, 1, 0),
+};
+
+/* DAPM widgets */
+static const struct snd_soc_dapm_widget da9055_dapm_widgets[] = {
+       /* Input Side */
+
+       /* Input Lines */
+       SND_SOC_DAPM_INPUT("MIC1"),
+       SND_SOC_DAPM_INPUT("MIC2"),
+       SND_SOC_DAPM_INPUT("AUXL"),
+       SND_SOC_DAPM_INPUT("AUXR"),
+
+       /* MUXs for Mic PGA source selection */
+       SND_SOC_DAPM_MUX("Mic Left Source", SND_SOC_NOPM, 0, 0,
+                        &da9055_mic_l_mux_controls),
+       SND_SOC_DAPM_MUX("Mic Right Source", SND_SOC_NOPM, 0, 0,
+                        &da9055_mic_r_mux_controls),
+
+       /* Input PGAs */
+       SND_SOC_DAPM_PGA("Mic Left", DA9055_MIC_L_CTRL, 7, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Mic Right", DA9055_MIC_R_CTRL, 7, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Aux Left", DA9055_AUX_L_CTRL, 7, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Aux Right", DA9055_AUX_R_CTRL, 7, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("MIXIN Left", DA9055_MIXIN_L_CTRL, 7, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("MIXIN Right", DA9055_MIXIN_R_CTRL, 7, 0, NULL, 0),
+
+       SND_SOC_DAPM_SUPPLY("Mic Bias", DA9055_MIC_BIAS_CTRL, 7, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("AIF", DA9055_AIF_CTRL, 7, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("Charge Pump", DA9055_CP_CTRL, 7, 0, NULL, 0),
+
+       /* Input Mixers */
+       SND_SOC_DAPM_MIXER("In Mixer Left", SND_SOC_NOPM, 0, 0,
+                          &da9055_dapm_mixinl_controls[0],
+                          ARRAY_SIZE(da9055_dapm_mixinl_controls)),
+       SND_SOC_DAPM_MIXER("In Mixer Right", SND_SOC_NOPM, 0, 0,
+                          &da9055_dapm_mixinr_controls[0],
+                          ARRAY_SIZE(da9055_dapm_mixinr_controls)),
+
+       /* ADCs */
+       SND_SOC_DAPM_ADC("ADC Left", "Capture", DA9055_ADC_L_CTRL, 7, 0),
+       SND_SOC_DAPM_ADC("ADC Right", "Capture", DA9055_ADC_R_CTRL, 7, 0),
+
+       /* Output Side */
+
+       /* MUXs for DAC source selection */
+       SND_SOC_DAPM_MUX("DAC Left Source", SND_SOC_NOPM, 0, 0,
+                        &da9055_dac_l_mux_controls),
+       SND_SOC_DAPM_MUX("DAC Right Source", SND_SOC_NOPM, 0, 0,
+                        &da9055_dac_r_mux_controls),
+
+       /* AIF input */
+       SND_SOC_DAPM_AIF_IN("AIFIN Left", "Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("AIFIN Right", "Playback", 0, SND_SOC_NOPM, 0, 0),
+
+       /* DACs */
+       SND_SOC_DAPM_DAC("DAC Left", "Playback", DA9055_DAC_L_CTRL, 7, 0),
+       SND_SOC_DAPM_DAC("DAC Right", "Playback", DA9055_DAC_R_CTRL, 7, 0),
+
+       /* Output Mixers */
+       SND_SOC_DAPM_MIXER("Out Mixer Left", SND_SOC_NOPM, 0, 0,
+                          &da9055_dapm_mixoutl_controls[0],
+                          ARRAY_SIZE(da9055_dapm_mixoutl_controls)),
+       SND_SOC_DAPM_MIXER("Out Mixer Right", SND_SOC_NOPM, 0, 0,
+                          &da9055_dapm_mixoutr_controls[0],
+                          ARRAY_SIZE(da9055_dapm_mixoutr_controls)),
+
+       /* Output PGAs */
+       SND_SOC_DAPM_PGA("MIXOUT Left", DA9055_MIXOUT_L_CTRL, 7, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("MIXOUT Right", DA9055_MIXOUT_R_CTRL, 7, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Lineout", DA9055_LINE_CTRL, 7, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Headphone Left", DA9055_HP_L_CTRL, 7, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("Headphone Right", DA9055_HP_R_CTRL, 7, 0, NULL, 0),
+
+       /* Output Lines */
+       SND_SOC_DAPM_OUTPUT("HPL"),
+       SND_SOC_DAPM_OUTPUT("HPR"),
+       SND_SOC_DAPM_OUTPUT("LINE"),
+};
+
+/* DAPM audio route definition */
+static const struct snd_soc_dapm_route da9055_audio_map[] = {
+       /* Dest       Connecting Widget    source */
+
+       /* Input path */
+       {"Mic Left Source", "MIC1_P_N", "MIC1"},
+       {"Mic Left Source", "MIC1_P", "MIC1"},
+       {"Mic Left Source", "MIC1_N", "MIC1"},
+       {"Mic Left Source", "MIC2_L", "MIC2"},
+
+       {"Mic Right Source", "MIC2_R_L", "MIC2"},
+       {"Mic Right Source", "MIC2_R", "MIC2"},
+       {"Mic Right Source", "MIC2_L", "MIC2"},
+
+       {"Mic Left", NULL, "Mic Left Source"},
+       {"Mic Right", NULL, "Mic Right Source"},
+
+       {"Aux Left", NULL, "AUXL"},
+       {"Aux Right", NULL, "AUXR"},
+
+       {"In Mixer Left", "Mic Left Switch", "Mic Left"},
+       {"In Mixer Left", "Mic Right Switch", "Mic Right"},
+       {"In Mixer Left", "Aux Left Switch", "Aux Left"},
+
+       {"In Mixer Right", "Mic Right Switch", "Mic Right"},
+       {"In Mixer Right", "Mic Left Switch", "Mic Left"},
+       {"In Mixer Right", "Aux Right Switch", "Aux Right"},
+       {"In Mixer Right", "Mixin Left Switch", "MIXIN Left"},
+
+       {"MIXIN Left", NULL, "In Mixer Left"},
+       {"ADC Left", NULL, "MIXIN Left"},
+
+       {"MIXIN Right", NULL, "In Mixer Right"},
+       {"ADC Right", NULL, "MIXIN Right"},
+
+       {"ADC Left", NULL, "AIF"},
+       {"ADC Right", NULL, "AIF"},
+
+       /* Output path */
+       {"AIFIN Left", NULL, "AIF"},
+       {"AIFIN Right", NULL, "AIF"},
+
+       {"DAC Left Source", "ADC output left", "ADC Left"},
+       {"DAC Left Source", "ADC output right", "ADC Right"},
+       {"DAC Left Source", "AIF input left", "AIFIN Left"},
+       {"DAC Left Source", "AIF input right", "AIFIN Right"},
+
+       {"DAC Right Source", "ADC output left", "ADC Left"},
+       {"DAC Right Source", "ADC output right", "ADC Right"},
+       {"DAC Right Source", "AIF input left", "AIFIN Left"},
+       {"DAC Right Source", "AIF input right", "AIFIN Right"},
+
+       {"DAC Left", NULL, "DAC Left Source"},
+       {"DAC Right", NULL, "DAC Right Source"},
+
+       {"Out Mixer Left", "Aux Left Switch", "Aux Left"},
+       {"Out Mixer Left", "Mixin Left Switch", "MIXIN Left"},
+       {"Out Mixer Left", "Mixin Right Switch", "MIXIN Right"},
+       {"Out Mixer Left", "Aux Left Invert Switch", "Aux Left"},
+       {"Out Mixer Left", "Mixin Left Invert Switch", "MIXIN Left"},
+       {"Out Mixer Left", "Mixin Right Invert Switch", "MIXIN Right"},
+       {"Out Mixer Left", "DAC Left Switch", "DAC Left"},
+
+       {"Out Mixer Right", "Aux Right Switch", "Aux Right"},
+       {"Out Mixer Right", "Mixin Right Switch", "MIXIN Right"},
+       {"Out Mixer Right", "Mixin Left Switch", "MIXIN Left"},
+       {"Out Mixer Right", "Aux Right Invert Switch", "Aux Right"},
+       {"Out Mixer Right", "Mixin Right Invert Switch", "MIXIN Right"},
+       {"Out Mixer Right", "Mixin Left Invert Switch", "MIXIN Left"},
+       {"Out Mixer Right", "DAC Right Switch", "DAC Right"},
+
+       {"MIXOUT Left", NULL, "Out Mixer Left"},
+       {"Headphone Left", NULL, "MIXOUT Left"},
+       {"Headphone Left", NULL, "Charge Pump"},
+       {"HPL", NULL, "Headphone Left"},
+
+       {"MIXOUT Right", NULL, "Out Mixer Right"},
+       {"Headphone Right", NULL, "MIXOUT Right"},
+       {"Headphone Right", NULL, "Charge Pump"},
+       {"HPR", NULL, "Headphone Right"},
+
+       {"MIXOUT Right", NULL, "Out Mixer Right"},
+       {"Lineout", NULL, "MIXOUT Right"},
+       {"LINE", NULL, "Lineout"},
+};
+
+/* Codec private data */
+struct da9055_priv {
+       struct regmap *regmap;
+       unsigned int mclk_rate;
+       int master;
+       struct da9055_platform_data *pdata;
+};
+
+static struct reg_default da9055_reg_defaults[] = {
+       { 0x21, 0x10 },
+       { 0x22, 0x0A },
+       { 0x23, 0x00 },
+       { 0x24, 0x00 },
+       { 0x25, 0x00 },
+       { 0x26, 0x00 },
+       { 0x27, 0x0C },
+       { 0x28, 0x01 },
+       { 0x29, 0x08 },
+       { 0x2A, 0x32 },
+       { 0x2B, 0x00 },
+       { 0x30, 0x35 },
+       { 0x31, 0x35 },
+       { 0x32, 0x00 },
+       { 0x33, 0x00 },
+       { 0x34, 0x03 },
+       { 0x35, 0x03 },
+       { 0x36, 0x6F },
+       { 0x37, 0x6F },
+       { 0x38, 0x80 },
+       { 0x39, 0x01 },
+       { 0x3A, 0x01 },
+       { 0x40, 0x00 },
+       { 0x41, 0x88 },
+       { 0x42, 0x88 },
+       { 0x43, 0x08 },
+       { 0x44, 0x80 },
+       { 0x45, 0x6F },
+       { 0x46, 0x6F },
+       { 0x47, 0x61 },
+       { 0x48, 0x35 },
+       { 0x49, 0x35 },
+       { 0x4A, 0x35 },
+       { 0x4B, 0x00 },
+       { 0x4C, 0x00 },
+       { 0x60, 0x44 },
+       { 0x61, 0x44 },
+       { 0x62, 0x00 },
+       { 0x63, 0x40 },
+       { 0x64, 0x40 },
+       { 0x65, 0x40 },
+       { 0x66, 0x40 },
+       { 0x67, 0x40 },
+       { 0x68, 0x40 },
+       { 0x69, 0x48 },
+       { 0x6A, 0x40 },
+       { 0x6B, 0x41 },
+       { 0x6C, 0x40 },
+       { 0x6D, 0x40 },
+       { 0x6E, 0x10 },
+       { 0x6F, 0x10 },
+       { 0x90, 0x80 },
+       { 0x92, 0x02 },
+       { 0x93, 0x00 },
+       { 0x99, 0x00 },
+       { 0x9A, 0x00 },
+       { 0x9B, 0x00 },
+       { 0x9C, 0x3F },
+       { 0x9D, 0x00 },
+       { 0x9E, 0x3F },
+       { 0x9F, 0xFF },
+       { 0xA0, 0x71 },
+       { 0xA1, 0x00 },
+       { 0xA2, 0x00 },
+       { 0xA6, 0x00 },
+       { 0xA7, 0x00 },
+       { 0xAB, 0x00 },
+       { 0xAC, 0x00 },
+       { 0xAD, 0x00 },
+       { 0xAF, 0x08 },
+       { 0xB0, 0x00 },
+       { 0xB1, 0x00 },
+       { 0xB2, 0x00 },
+};
+
+static bool da9055_volatile_register(struct device *dev,
+                                    unsigned int reg)
+{
+       switch (reg) {
+       case DA9055_STATUS1:
+       case DA9055_PLL_STATUS:
+       case DA9055_AUX_L_GAIN_STATUS:
+       case DA9055_AUX_R_GAIN_STATUS:
+       case DA9055_MIC_L_GAIN_STATUS:
+       case DA9055_MIC_R_GAIN_STATUS:
+       case DA9055_MIXIN_L_GAIN_STATUS:
+       case DA9055_MIXIN_R_GAIN_STATUS:
+       case DA9055_ADC_L_GAIN_STATUS:
+       case DA9055_ADC_R_GAIN_STATUS:
+       case DA9055_DAC_L_GAIN_STATUS:
+       case DA9055_DAC_R_GAIN_STATUS:
+       case DA9055_HP_L_GAIN_STATUS:
+       case DA9055_HP_R_GAIN_STATUS:
+       case DA9055_LINE_GAIN_STATUS:
+       case DA9055_ALC_CIC_OP_LVL_DATA:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+/* Set DAI word length */
+static int da9055_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 da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec);
+       u8 aif_ctrl, fs;
+       u32 sysclk;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               aif_ctrl = DA9055_AIF_WORD_S16_LE;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               aif_ctrl = DA9055_AIF_WORD_S20_3LE;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               aif_ctrl = DA9055_AIF_WORD_S24_LE;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               aif_ctrl = DA9055_AIF_WORD_S32_LE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Set AIF format */
+       snd_soc_update_bits(codec, DA9055_AIF_CTRL, DA9055_AIF_WORD_LENGTH_MASK,
+                           aif_ctrl);
+
+       switch (params_rate(params)) {
+       case 8000:
+               fs              = DA9055_SR_8000;
+               sysclk          = 3072000;
+               break;
+       case 11025:
+               fs              = DA9055_SR_11025;
+               sysclk          = 2822400;
+               break;
+       case 12000:
+               fs              = DA9055_SR_12000;
+               sysclk          = 3072000;
+               break;
+       case 16000:
+               fs              = DA9055_SR_16000;
+               sysclk          = 3072000;
+               break;
+       case 22050:
+               fs              = DA9055_SR_22050;
+               sysclk          = 2822400;
+               break;
+       case 32000:
+               fs              = DA9055_SR_32000;
+               sysclk          = 3072000;
+               break;
+       case 44100:
+               fs              = DA9055_SR_44100;
+               sysclk          = 2822400;
+               break;
+       case 48000:
+               fs              = DA9055_SR_48000;
+               sysclk          = 3072000;
+               break;
+       case 88200:
+               fs              = DA9055_SR_88200;
+               sysclk          = 2822400;
+               break;
+       case 96000:
+               fs              = DA9055_SR_96000;
+               sysclk          = 3072000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (da9055->mclk_rate) {
+               /* PLL Mode, Write actual FS */
+               snd_soc_write(codec, DA9055_SR, fs);
+       } else {
+               /*
+                * Non-PLL Mode
+                * When PLL is bypassed, chip assumes constant MCLK of
+                * 12.288MHz and uses sample rate value to divide this MCLK
+                * to derive its sys clk. As sys clk has to be 256 * Fs, we
+                * need to write constant sample rate i.e. 48KHz.
+                */
+               snd_soc_write(codec, DA9055_SR, DA9055_SR_48000);
+       }
+
+       if (da9055->mclk_rate && (da9055->mclk_rate != sysclk)) {
+               /* PLL Mode */
+               if (!da9055->master) {
+                       /* PLL slave mode, enable PLL and also SRM */
+                       snd_soc_update_bits(codec, DA9055_PLL_CTRL,
+                                           DA9055_PLL_EN | DA9055_PLL_SRM_EN,
+                                           DA9055_PLL_EN | DA9055_PLL_SRM_EN);
+               } else {
+                       /* PLL master mode, only enable PLL */
+                       snd_soc_update_bits(codec, DA9055_PLL_CTRL,
+                                           DA9055_PLL_EN, DA9055_PLL_EN);
+               }
+       } else {
+               /* Non PLL Mode, disable PLL */
+               snd_soc_update_bits(codec, DA9055_PLL_CTRL, DA9055_PLL_EN, 0);
+       }
+
+       return 0;
+}
+
+/* Set DAI mode and Format */
+static int da9055_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec);
+       u8 aif_clk_mode, aif_ctrl, mode;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               /* DA9055 in I2S Master Mode */
+               mode = 1;
+               aif_clk_mode = DA9055_AIF_CLK_EN_MASTER_MODE;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               /* DA9055 in I2S Slave Mode */
+               mode = 0;
+               aif_clk_mode = DA9055_AIF_CLK_EN_SLAVE_MODE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Don't allow change of mode if PLL is enabled */
+       if ((snd_soc_read(codec, DA9055_PLL_CTRL) & DA9055_PLL_EN) &&
+           (da9055->master != mode))
+               return -EINVAL;
+
+       da9055->master = mode;
+
+       /* Only I2S is supported */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               aif_ctrl = DA9055_AIF_FORMAT_I2S_MODE;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               aif_ctrl = DA9055_AIF_FORMAT_LEFT_J;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               aif_ctrl = DA9055_AIF_FORMAT_RIGHT_J;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* By default only 32 BCLK per WCLK is supported */
+       aif_clk_mode |= DA9055_AIF_BCLKS_PER_WCLK_32;
+
+       snd_soc_update_bits(codec, DA9055_AIF_CLK_MODE,
+                           (DA9055_AIF_CLK_MODE_MASK | DA9055_AIF_BCLK_MASK),
+                           aif_clk_mode);
+       snd_soc_update_bits(codec, DA9055_AIF_CTRL, DA9055_AIF_FORMAT_MASK,
+                           aif_ctrl);
+       return 0;
+}
+
+static int da9055_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+
+       if (mute) {
+               snd_soc_update_bits(codec, DA9055_DAC_L_CTRL,
+                                   DA9055_DAC_L_MUTE_EN, DA9055_DAC_L_MUTE_EN);
+               snd_soc_update_bits(codec, DA9055_DAC_R_CTRL,
+                                   DA9055_DAC_R_MUTE_EN, DA9055_DAC_R_MUTE_EN);
+       } else {
+               snd_soc_update_bits(codec, DA9055_DAC_L_CTRL,
+                                   DA9055_DAC_L_MUTE_EN, 0);
+               snd_soc_update_bits(codec, DA9055_DAC_R_CTRL,
+                                   DA9055_DAC_R_MUTE_EN, 0);
+       }
+
+       return 0;
+}
+
+#define DA9055_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static int da9055_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+                                int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec);
+
+       switch (clk_id) {
+       case DA9055_CLKSRC_MCLK:
+               switch (freq) {
+               case 11289600:
+               case 12000000:
+               case 12288000:
+               case 13000000:
+               case 13500000:
+               case 14400000:
+               case 19200000:
+               case 19680000:
+               case 19800000:
+                       da9055->mclk_rate = freq;
+                       return 0;
+               default:
+                       dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
+                               freq);
+                       return -EINVAL;
+               }
+               break;
+       default:
+               dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
+               return -EINVAL;
+       }
+}
+
+/*
+ * da9055_set_dai_pll  : Configure the codec PLL
+ * @param codec_dai    : Pointer to codec DAI
+ * @param pll_id       : da9055 has only one pll, so pll_id is always zero
+ * @param fref         : Input MCLK frequency
+ * @param fout         : FsDM value
+ * @return int         : Zero for success, negative error code for error
+ *
+ * Note: Supported PLL input frequencies are 11.2896MHz, 12MHz, 12.288MHz,
+ *      13MHz, 13.5MHz, 14.4MHz, 19.2MHz, 19.6MHz and 19.8MHz
+ */
+static int da9055_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+                             int source, unsigned int fref, unsigned int fout)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec);
+
+       u8 pll_frac_top, pll_frac_bot, pll_integer, cnt;
+
+       /* Disable PLL before setting the divisors */
+       snd_soc_update_bits(codec, DA9055_PLL_CTRL, DA9055_PLL_EN, 0);
+
+       /* In slave mode, there is only one set of divisors */
+       if (!da9055->master && (fout != 2822400))
+               goto pll_err;
+
+       /* Search pll div array for correct divisors */
+       for (cnt = 0; cnt < ARRAY_SIZE(da9055_pll_div); cnt++) {
+               /* Check fref, mode  and fout */
+               if ((fref == da9055_pll_div[cnt].fref) &&
+                   (da9055->master ==  da9055_pll_div[cnt].mode) &&
+                   (fout == da9055_pll_div[cnt].fout)) {
+                       /* All match, pick up divisors */
+                       pll_frac_top = da9055_pll_div[cnt].frac_top;
+                       pll_frac_bot = da9055_pll_div[cnt].frac_bot;
+                       pll_integer = da9055_pll_div[cnt].integer;
+                       break;
+               }
+       }
+       if (cnt >= ARRAY_SIZE(da9055_pll_div))
+               goto pll_err;
+
+       /* Write PLL dividers */
+       snd_soc_write(codec, DA9055_PLL_FRAC_TOP, pll_frac_top);
+       snd_soc_write(codec, DA9055_PLL_FRAC_BOT, pll_frac_bot);
+       snd_soc_write(codec, DA9055_PLL_INTEGER, pll_integer);
+
+       return 0;
+pll_err:
+       dev_err(codec_dai->dev, "Error in setting up PLL\n");
+       return -EINVAL;
+}
+
+/* DAI operations */
+static const struct snd_soc_dai_ops da9055_dai_ops = {
+       .hw_params      = da9055_hw_params,
+       .set_fmt        = da9055_set_dai_fmt,
+       .set_sysclk     = da9055_set_dai_sysclk,
+       .set_pll        = da9055_set_dai_pll,
+       .digital_mute   = da9055_mute,
+};
+
+static struct snd_soc_dai_driver da9055_dai = {
+       .name = "da9055-hifi",
+       /* Playback Capabilities */
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = DA9055_FORMATS,
+       },
+       /* Capture Capabilities */
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 1,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = DA9055_FORMATS,
+       },
+       .ops = &da9055_dai_ops,
+       .symmetric_rates = 1,
+};
+
+static int da9055_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       /* Enable VMID reference & master bias */
+                       snd_soc_update_bits(codec, DA9055_REFERENCES,
+                                           DA9055_VMID_EN | DA9055_BIAS_EN,
+                                           DA9055_VMID_EN | DA9055_BIAS_EN);
+               }
+               break;
+       case SND_SOC_BIAS_OFF:
+               /* Disable VMID reference & master bias */
+               snd_soc_update_bits(codec, DA9055_REFERENCES,
+                                   DA9055_VMID_EN | DA9055_BIAS_EN, 0);
+               break;
+       }
+       codec->dapm.bias_level = level;
+       return 0;
+}
+
+static int da9055_probe(struct snd_soc_codec *codec)
+{
+       int ret;
+       struct da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec);
+
+       codec->control_data = da9055->regmap;
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
+       }
+
+       /* Enable all Gain Ramps */
+       snd_soc_update_bits(codec, DA9055_AUX_L_CTRL,
+                           DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+       snd_soc_update_bits(codec, DA9055_AUX_R_CTRL,
+                           DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+       snd_soc_update_bits(codec, DA9055_MIXIN_L_CTRL,
+                           DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+       snd_soc_update_bits(codec, DA9055_MIXIN_R_CTRL,
+                           DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+       snd_soc_update_bits(codec, DA9055_ADC_L_CTRL,
+                           DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+       snd_soc_update_bits(codec, DA9055_ADC_R_CTRL,
+                           DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+       snd_soc_update_bits(codec, DA9055_DAC_L_CTRL,
+                           DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+       snd_soc_update_bits(codec, DA9055_DAC_R_CTRL,
+                           DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+       snd_soc_update_bits(codec, DA9055_HP_L_CTRL,
+                           DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+       snd_soc_update_bits(codec, DA9055_HP_R_CTRL,
+                           DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+       snd_soc_update_bits(codec, DA9055_LINE_CTRL,
+                           DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+
+       /*
+        * There are two separate control bits for input and output mixers as
+        * well as headphone and line outs.
+        * One to enable corresponding amplifier and other to enable its
+        * output. As amplifier bits are related to power control, they are
+        * being managed by DAPM while other (non power related) bits are
+        * enabled here
+        */
+       snd_soc_update_bits(codec, DA9055_MIXIN_L_CTRL,
+                           DA9055_MIXIN_L_MIX_EN, DA9055_MIXIN_L_MIX_EN);
+       snd_soc_update_bits(codec, DA9055_MIXIN_R_CTRL,
+                           DA9055_MIXIN_R_MIX_EN, DA9055_MIXIN_R_MIX_EN);
+
+       snd_soc_update_bits(codec, DA9055_MIXOUT_L_CTRL,
+                           DA9055_MIXOUT_L_MIX_EN, DA9055_MIXOUT_L_MIX_EN);
+       snd_soc_update_bits(codec, DA9055_MIXOUT_R_CTRL,
+                           DA9055_MIXOUT_R_MIX_EN, DA9055_MIXOUT_R_MIX_EN);
+
+       snd_soc_update_bits(codec, DA9055_HP_L_CTRL,
+                           DA9055_HP_L_AMP_OE, DA9055_HP_L_AMP_OE);
+       snd_soc_update_bits(codec, DA9055_HP_R_CTRL,
+                           DA9055_HP_R_AMP_OE, DA9055_HP_R_AMP_OE);
+
+       snd_soc_update_bits(codec, DA9055_LINE_CTRL,
+                           DA9055_LINE_AMP_OE, DA9055_LINE_AMP_OE);
+
+       /* Set this as per your system configuration */
+       snd_soc_write(codec, DA9055_PLL_CTRL, DA9055_PLL_INDIV_10_20_MHZ);
+
+       /* Set platform data values */
+       if (da9055->pdata) {
+               /* set mic bias source */
+               if (da9055->pdata->micbias_source) {
+                       snd_soc_update_bits(codec, DA9055_MIXIN_R_SELECT,
+                                           DA9055_MICBIAS2_EN,
+                                           DA9055_MICBIAS2_EN);
+               } else {
+                       snd_soc_update_bits(codec, DA9055_MIXIN_R_SELECT,
+                                           DA9055_MICBIAS2_EN, 0);
+               }
+               /* set mic bias voltage */
+               switch (da9055->pdata->micbias) {
+               case DA9055_MICBIAS_2_2V:
+               case DA9055_MICBIAS_2_1V:
+               case DA9055_MICBIAS_1_8V:
+               case DA9055_MICBIAS_1_6V:
+                       snd_soc_update_bits(codec, DA9055_MIC_CONFIG,
+                                           DA9055_MICBIAS_LEVEL_MASK,
+                                           (da9055->pdata->micbias) << 4);
+                       break;
+               }
+       }
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_da9055 = {
+       .probe                  = da9055_probe,
+       .set_bias_level         = da9055_set_bias_level,
+
+       .controls               = da9055_snd_controls,
+       .num_controls           = ARRAY_SIZE(da9055_snd_controls),
+
+       .dapm_widgets           = da9055_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(da9055_dapm_widgets),
+       .dapm_routes            = da9055_audio_map,
+       .num_dapm_routes        = ARRAY_SIZE(da9055_audio_map),
+};
+
+static const struct regmap_config da9055_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .reg_defaults = da9055_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(da9055_reg_defaults),
+       .volatile_reg = da9055_volatile_register,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit da9055_i2c_probe(struct i2c_client *i2c,
+                                     const struct i2c_device_id *id)
+{
+       struct da9055_priv *da9055;
+       struct da9055_platform_data *pdata = dev_get_platdata(&i2c->dev);
+       int ret;
+
+       da9055 = devm_kzalloc(&i2c->dev, sizeof(struct da9055_priv),
+                             GFP_KERNEL);
+       if (!da9055)
+               return -ENOMEM;
+
+       if (pdata)
+               da9055->pdata = pdata;
+
+       i2c_set_clientdata(i2c, da9055);
+
+       da9055->regmap = devm_regmap_init_i2c(i2c, &da9055_regmap_config);
+       if (IS_ERR(da9055->regmap)) {
+               ret = PTR_ERR(da9055->regmap);
+               dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_da9055, &da9055_dai, 1);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to register da9055 codec: %d\n",
+                       ret);
+       }
+       return ret;
+}
+
+static int __devexit da9055_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       return 0;
+}
+
+static const struct i2c_device_id da9055_i2c_id[] = {
+       { "da9055", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
+
+/* I2C codec control layer */
+static struct i2c_driver da9055_i2c_driver = {
+       .driver = {
+               .name = "da9055",
+               .owner = THIS_MODULE,
+       },
+       .probe          = da9055_i2c_probe,
+       .remove         = __devexit_p(da9055_remove),
+       .id_table       = da9055_i2c_id,
+};
+
+module_i2c_driver(da9055_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC DA9055 Codec driver");
+MODULE_AUTHOR("David Chen, Ashish Chavan");
+MODULE_LICENSE("GPL");
index 5d8f39e329788b10fdcf47f8166e03e1911b7d10..1bf55602c9ebf2ecf97ca2912a99815a5e707493 100644 (file)
@@ -13,7 +13,6 @@
  */
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
index ba4fafb93e5624d2aff10f6e20cf81ad34066ea9..81a328c78838250c952609275af6888e875e6057 100644 (file)
@@ -250,17 +250,7 @@ static struct i2c_driver lm4857_i2c_driver = {
        .id_table = lm4857_i2c_id,
 };
 
-static int __init lm4857_init(void)
-{
-       return i2c_add_driver(&lm4857_i2c_driver);
-}
-module_init(lm4857_init);
-
-static void __exit lm4857_exit(void)
-{
-       i2c_del_driver(&lm4857_i2c_driver);
-}
-module_exit(lm4857_exit);
+module_i2c_driver(lm4857_i2c_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 MODULE_DESCRIPTION("LM4857 amplifier driver");
index af7324b79dd0a8c8ae900277a7bf4abf2a98995a..3264a5169306fc3f8d769912173f803fae3d17a4 100644 (file)
@@ -2107,23 +2107,7 @@ static struct i2c_driver max98088_i2c_driver = {
        .id_table = max98088_i2c_id,
 };
 
-static int __init max98088_init(void)
-{
-       int ret;
-
-       ret = i2c_add_driver(&max98088_i2c_driver);
-       if (ret)
-               pr_err("Failed to register max98088 I2C driver: %d\n", ret);
-
-       return ret;
-}
-module_init(max98088_init);
-
-static void __exit max98088_exit(void)
-{
-       i2c_del_driver(&max98088_i2c_driver);
-}
-module_exit(max98088_exit);
+module_i2c_driver(max98088_i2c_driver);
 
 MODULE_DESCRIPTION("ALSA SoC MAX98088 driver");
 MODULE_AUTHOR("Peter Hsiang, Jesse Marroquin");
index 7cd508e16a5ca3cd0bfe7dcef88941d7c6ab5c90..38d43c59d3f4cfbc67cc11f2d86af73f8ae910b9 100644 (file)
@@ -2533,23 +2533,7 @@ static struct i2c_driver max98095_i2c_driver = {
        .id_table = max98095_i2c_id,
 };
 
-static int __init max98095_init(void)
-{
-       int ret;
-
-       ret = i2c_add_driver(&max98095_i2c_driver);
-       if (ret)
-               pr_err("Failed to register max98095 I2C driver: %d\n", ret);
-
-       return ret;
-}
-module_init(max98095_init);
-
-static void __exit max98095_exit(void)
-{
-       i2c_del_driver(&max98095_i2c_driver);
-}
-module_exit(max98095_exit);
+module_i2c_driver(max98095_i2c_driver);
 
 MODULE_DESCRIPTION("ALSA SoC MAX98095 driver");
 MODULE_AUTHOR("Peter Hsiang");
index a1913091f56ca5641fd58a4066890065deb0d5d6..efe535c37b39eb82f110e76328f3345fb3fdd10e 100644 (file)
@@ -369,17 +369,7 @@ static struct i2c_driver max9850_i2c_driver = {
        .id_table = max9850_i2c_id,
 };
 
-static int __init max9850_init(void)
-{
-       return i2c_add_driver(&max9850_i2c_driver);
-}
-module_init(max9850_init);
-
-static void __exit max9850_exit(void)
-{
-       i2c_del_driver(&max9850_i2c_driver);
-}
-module_exit(max9850_exit);
+module_i2c_driver(max9850_i2c_driver);
 
 MODULE_AUTHOR("Christian Glindkamp <christian.glindkamp@taskit.de>");
 MODULE_DESCRIPTION("ASoC MAX9850 codec driver");
index 3a2ba3d8fd6de13ec21f8e5b6ed67df85af77256..d15e5943c85e931bc0ffd5472b27768bbadaeb79 100644 (file)
@@ -291,17 +291,7 @@ static struct i2c_driver max9877_i2c_driver = {
        .id_table = max9877_i2c_id,
 };
 
-static int __init max9877_init(void)
-{
-       return i2c_add_driver(&max9877_i2c_driver);
-}
-module_init(max9877_init);
-
-static void __exit max9877_exit(void)
-{
-       i2c_del_driver(&max9877_i2c_driver);
-}
-module_exit(max9877_exit);
+module_i2c_driver(max9877_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC MAX9877 amp driver");
 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
index 115a403018105b0eaa2fb64abee56a47b5d32cc4..bc955999c8aa56c15fb30e99bbc8a7eecb930a67 100644 (file)
@@ -426,16 +426,16 @@ static int mc13783_set_tdm_slot_sync(struct snd_soc_dai *dai,
 }
 
 static const struct snd_kcontrol_new mc1l_amp_ctl =
-       SOC_DAPM_SINGLE("Switch", 38, 7, 1, 0);
+       SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_TX, 7, 1, 0);
 
 static const struct snd_kcontrol_new mc1r_amp_ctl =
-       SOC_DAPM_SINGLE("Switch", 38, 5, 1, 0);
+       SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_TX, 5, 1, 0);
 
 static const struct snd_kcontrol_new mc2_amp_ctl =
-       SOC_DAPM_SINGLE("Switch", 38, 9, 1, 0);
+       SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_TX, 9, 1, 0);
 
 static const struct snd_kcontrol_new atx_amp_ctl =
-       SOC_DAPM_SINGLE("Switch", 38, 11, 1, 0);
+       SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_TX, 11, 1, 0);
 
 
 /* Virtual mux. The chip does the input selection automatically
@@ -461,22 +461,22 @@ static const struct snd_kcontrol_new right_input_mux =
        SOC_DAPM_ENUM_VIRT("Route", adcr_enum);
 
 static const struct snd_kcontrol_new samp_ctl =
-       SOC_DAPM_SINGLE("Switch", 36, 3, 1, 0);
+       SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 3, 1, 0);
 
 static const struct snd_kcontrol_new lamp_ctl =
-       SOC_DAPM_SINGLE("Switch", 36, 5, 1, 0);
+       SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 5, 1, 0);
 
 static const struct snd_kcontrol_new hlamp_ctl =
-       SOC_DAPM_SINGLE("Switch", 36, 10, 1, 0);
+       SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 10, 1, 0);
 
 static const struct snd_kcontrol_new hramp_ctl =
-       SOC_DAPM_SINGLE("Switch", 36, 9, 1, 0);
+       SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 9, 1, 0);
 
 static const struct snd_kcontrol_new llamp_ctl =
-       SOC_DAPM_SINGLE("Switch", 36, 16, 1, 0);
+       SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 16, 1, 0);
 
 static const struct snd_kcontrol_new lramp_ctl =
-       SOC_DAPM_SINGLE("Switch", 36, 15, 1, 0);
+       SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 15, 1, 0);
 
 static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {
 /* Input */
@@ -487,13 +487,13 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("RXINL"),
        SND_SOC_DAPM_INPUT("TXIN"),
 
-       SND_SOC_DAPM_SUPPLY("MC1 Bias", 38, 0, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("MC2 Bias", 38, 1, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("MC1 Bias", MC13783_AUDIO_TX, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("MC2 Bias", MC13783_AUDIO_TX, 1, 0, NULL, 0),
 
-       SND_SOC_DAPM_SWITCH("MC1L Amp", 38, 7, 0, &mc1l_amp_ctl),
-       SND_SOC_DAPM_SWITCH("MC1R Amp", 38, 5, 0, &mc1r_amp_ctl),
-       SND_SOC_DAPM_SWITCH("MC2 Amp", 38, 9, 0, &mc2_amp_ctl),
-       SND_SOC_DAPM_SWITCH("TXIN Amp", 38, 11, 0, &atx_amp_ctl),
+       SND_SOC_DAPM_SWITCH("MC1L Amp", MC13783_AUDIO_TX, 7, 0, &mc1l_amp_ctl),
+       SND_SOC_DAPM_SWITCH("MC1R Amp", MC13783_AUDIO_TX, 5, 0, &mc1r_amp_ctl),
+       SND_SOC_DAPM_SWITCH("MC2 Amp", MC13783_AUDIO_TX, 9, 0, &mc2_amp_ctl),
+       SND_SOC_DAPM_SWITCH("TXIN Amp", MC13783_AUDIO_TX, 11, 0, &atx_amp_ctl),
 
        SND_SOC_DAPM_VIRT_MUX("PGA Left Input Mux", SND_SOC_NOPM, 0, 0,
                              &left_input_mux),
@@ -503,12 +503,12 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {
        SND_SOC_DAPM_PGA("PGA Left Input", SND_SOC_NOPM, 0, 0, NULL, 0),
        SND_SOC_DAPM_PGA("PGA Right Input", SND_SOC_NOPM, 0, 0, NULL, 0),
 
-       SND_SOC_DAPM_ADC("ADC", "Capture", 40, 11, 0),
-       SND_SOC_DAPM_SUPPLY("ADC_Reset", 40, 15, 0, NULL, 0),
+       SND_SOC_DAPM_ADC("ADC", "Capture", MC13783_AUDIO_CODEC, 11, 0),
+       SND_SOC_DAPM_SUPPLY("ADC_Reset", MC13783_AUDIO_CODEC, 15, 0, NULL, 0),
 
 /* Output */
-       SND_SOC_DAPM_SUPPLY("DAC_E", 41, 11, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("DAC_Reset", 41, 15, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DAC_E", MC13783_AUDIO_DAC, 11, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("DAC_Reset", MC13783_AUDIO_DAC, 15, 0, NULL, 0),
        SND_SOC_DAPM_OUTPUT("RXOUTL"),
        SND_SOC_DAPM_OUTPUT("RXOUTR"),
        SND_SOC_DAPM_OUTPUT("HSL"),
@@ -516,14 +516,18 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {
        SND_SOC_DAPM_OUTPUT("LSP"),
        SND_SOC_DAPM_OUTPUT("SP"),
 
-       SND_SOC_DAPM_SWITCH("Speaker Amp", 36, 3, 0, &samp_ctl),
+       SND_SOC_DAPM_SWITCH("Speaker Amp", MC13783_AUDIO_RX0, 3, 0, &samp_ctl),
        SND_SOC_DAPM_SWITCH("Loudspeaker Amp", SND_SOC_NOPM, 0, 0, &lamp_ctl),
-       SND_SOC_DAPM_SWITCH("Headset Amp Left", 36, 10, 0, &hlamp_ctl),
-       SND_SOC_DAPM_SWITCH("Headset Amp Right", 36, 9, 0, &hramp_ctl),
-       SND_SOC_DAPM_SWITCH("Line out Amp Left", 36, 16, 0, &llamp_ctl),
-       SND_SOC_DAPM_SWITCH("Line out Amp Right", 36, 15, 0, &lramp_ctl),
-       SND_SOC_DAPM_DAC("DAC", "Playback", 36, 22, 0),
-       SND_SOC_DAPM_PGA("DAC PGA", 37, 5, 0, NULL, 0),
+       SND_SOC_DAPM_SWITCH("Headset Amp Left", MC13783_AUDIO_RX0, 10, 0,
+                       &hlamp_ctl),
+       SND_SOC_DAPM_SWITCH("Headset Amp Right", MC13783_AUDIO_RX0, 9, 0,
+                       &hramp_ctl),
+       SND_SOC_DAPM_SWITCH("Line out Amp Left", MC13783_AUDIO_RX0, 16, 0,
+                       &llamp_ctl),
+       SND_SOC_DAPM_SWITCH("Line out Amp Right", MC13783_AUDIO_RX0, 15, 0,
+                       &lramp_ctl),
+       SND_SOC_DAPM_DAC("DAC", "Playback", MC13783_AUDIO_RX0, 22, 0),
+       SND_SOC_DAPM_PGA("DAC PGA", MC13783_AUDIO_RX1, 5, 0, NULL, 0),
 };
 
 static struct snd_soc_dapm_route mc13783_routes[] = {
@@ -581,8 +585,6 @@ static int mc13783_probe(struct snd_soc_codec *codec)
 {
        struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
 
-       codec->control_data = priv->mc13xxx;
-
        mc13xxx_lock(priv->mc13xxx);
 
        /* these are the reset values */
index 8d717f4b5a875d5efb4bcdf283f3604366a07dea..0935bfe624711646e622b0637ccd56484dfd115d 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
         SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_S32_BE)
 
 /* Power-up register defaults */
-static const u8 sta32x_regs[STA32X_REGISTER_COUNT] = {
-       0x63, 0x80, 0xc2, 0x40, 0xc2, 0x5c, 0x10, 0xff, 0x60, 0x60,
-       0x60, 0x80, 0x00, 0x00, 0x00, 0x40, 0x80, 0x77, 0x6a, 0x69,
-       0x6a, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d,
-       0xc0, 0xf3, 0x33, 0x00, 0x0c,
+static const struct reg_default sta32x_regs[] = {
+       {  0x0, 0x63 },
+       {  0x1, 0x80 },
+       {  0x2, 0xc2 },
+       {  0x3, 0x40 },
+       {  0x4, 0xc2 },
+       {  0x5, 0x5c },
+       {  0x6, 0x10 },
+       {  0x7, 0xff },
+       {  0x8, 0x60 },
+       {  0x9, 0x60 },
+       {  0xa, 0x60 },
+       {  0xb, 0x80 },
+       {  0xc, 0x00 },
+       {  0xd, 0x00 },
+       {  0xe, 0x00 },
+       {  0xf, 0x40 },
+       { 0x10, 0x80 },
+       { 0x11, 0x77 },
+       { 0x12, 0x6a },
+       { 0x13, 0x69 },
+       { 0x14, 0x6a },
+       { 0x15, 0x69 },
+       { 0x16, 0x00 },
+       { 0x17, 0x00 },
+       { 0x18, 0x00 },
+       { 0x19, 0x00 },
+       { 0x1a, 0x00 },
+       { 0x1b, 0x00 },
+       { 0x1c, 0x00 },
+       { 0x1d, 0x00 },
+       { 0x1e, 0x00 },
+       { 0x1f, 0x00 },
+       { 0x20, 0x00 },
+       { 0x21, 0x00 },
+       { 0x22, 0x00 },
+       { 0x23, 0x00 },
+       { 0x24, 0x00 },
+       { 0x25, 0x00 },
+       { 0x26, 0x00 },
+       { 0x27, 0x2d },
+       { 0x28, 0xc0 },
+       { 0x2b, 0x00 },
+       { 0x2c, 0x0c },
 };
 
 /* regulator power supply names */
@@ -72,6 +111,7 @@ static const char *sta32x_supply_names[] = {
 
 /* codec private data */
 struct sta32x_priv {
+       struct regmap *regmap;
        struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)];
        struct snd_soc_codec *codec;
        struct sta32x_platform_data *pdata;
@@ -291,17 +331,15 @@ static int sta32x_sync_coef_shadow(struct snd_soc_codec *codec)
 
 static int sta32x_cache_sync(struct snd_soc_codec *codec)
 {
+       struct sta32x_priv *sta32x = codec->control_data;
        unsigned int mute;
        int rc;
 
-       if (!codec->cache_sync)
-               return 0;
-
        /* mute during register sync */
        mute = snd_soc_read(codec, STA32X_MMUTE);
        snd_soc_write(codec, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE);
        sta32x_sync_coef_shadow(codec);
-       rc = snd_soc_cache_sync(codec);
+       rc = regcache_sync(sta32x->regmap);
        snd_soc_write(codec, STA32X_MMUTE, mute);
        return rc;
 }
@@ -316,11 +354,11 @@ static void sta32x_watchdog(struct work_struct *work)
 
        /* check if sta32x has reset itself */
        confa_cached = snd_soc_read(codec, STA32X_CONFA);
-       codec->cache_bypass = 1;
+       regcache_cache_bypass(sta32x->regmap, true);
        confa = snd_soc_read(codec, STA32X_CONFA);
-       codec->cache_bypass = 0;
+       regcache_cache_bypass(sta32x->regmap, false);
        if (confa != confa_cached) {
-               codec->cache_sync = 1;
+               regcache_mark_dirty(sta32x->regmap);
                sta32x_cache_sync(codec);
        }
 
@@ -825,31 +863,21 @@ static int sta32x_probe(struct snd_soc_codec *codec)
        sta32x->codec = codec;
        sta32x->pdata = dev_get_platdata(codec->dev);
 
-       /* regulators */
-       for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++)
-               sta32x->supplies[i].supply = sta32x_supply_names[i];
-
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sta32x->supplies),
-                                sta32x->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               goto err;
-       }
-
        ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
                                    sta32x->supplies);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
-               goto err_get;
+               return ret;
        }
 
        /* Tell ASoC what kind of I/O to use to read the registers.  ASoC will
         * then do the I2C transactions itself.
         */
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+       codec->control_data = sta32x->regmap;
+       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
        if (ret < 0) {
                dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret);
-               return ret;
+               goto err;
        }
 
        /* Chip documentation explicitly requires that the reset values
@@ -858,13 +886,15 @@ static int sta32x_probe(struct snd_soc_codec *codec)
         * so the write to the these registers are suppressed by the cache
         * restore code when it skips writes of default registers.
         */
-       snd_soc_cache_write(codec, STA32X_CONFC, 0xc2);
-       snd_soc_cache_write(codec, STA32X_CONFE, 0xc2);
-       snd_soc_cache_write(codec, STA32X_CONFF, 0x5c);
-       snd_soc_cache_write(codec, STA32X_MMUTE, 0x10);
-       snd_soc_cache_write(codec, STA32X_AUTO1, 0x60);
-       snd_soc_cache_write(codec, STA32X_AUTO3, 0x00);
-       snd_soc_cache_write(codec, STA32X_C3CFG, 0x40);
+       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))
@@ -915,9 +945,8 @@ static int sta32x_probe(struct snd_soc_codec *codec)
 
        return 0;
 
-err_get:
-       regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
 err:
+       regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
        return ret;
 }
 
@@ -928,13 +957,11 @@ static int sta32x_remove(struct snd_soc_codec *codec)
        sta32x_watchdog_stop(sta32x);
        sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF);
        regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
-       regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
 
        return 0;
 }
 
-static int sta32x_reg_is_volatile(struct snd_soc_codec *codec,
-                                 unsigned int reg)
+static bool sta32x_reg_is_volatile(struct device *dev, unsigned int reg)
 {
        switch (reg) {
        case STA32X_CONFA ... STA32X_L2ATRT:
@@ -949,10 +976,6 @@ static const struct snd_soc_codec_driver sta32x_codec = {
        .remove =               sta32x_remove,
        .suspend =              sta32x_suspend,
        .resume =               sta32x_resume,
-       .reg_cache_size =       STA32X_REGISTER_COUNT,
-       .reg_word_size =        sizeof(u8),
-       .reg_cache_default =    sta32x_regs,
-       .volatile_register =    sta32x_reg_is_volatile,
        .set_bias_level =       sta32x_set_bias_level,
        .controls =             sta32x_snd_controls,
        .num_controls =         ARRAY_SIZE(sta32x_snd_controls),
@@ -962,17 +985,45 @@ static const struct snd_soc_codec_driver sta32x_codec = {
        .num_dapm_routes =      ARRAY_SIZE(sta32x_dapm_routes),
 };
 
+static const struct regmap_config sta32x_regmap = {
+       .reg_bits =             8,
+       .val_bits =             8,
+       .max_register =         STA32X_FDRC2,
+       .reg_defaults =         sta32x_regs,
+       .num_reg_defaults =     ARRAY_SIZE(sta32x_regs),
+       .cache_type =           REGCACHE_RBTREE,
+       .volatile_reg =         sta32x_reg_is_volatile,
+};
+
 static __devinit int sta32x_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct sta32x_priv *sta32x;
-       int ret;
+       int ret, i;
 
        sta32x = devm_kzalloc(&i2c->dev, sizeof(struct sta32x_priv),
                              GFP_KERNEL);
        if (!sta32x)
                return -ENOMEM;
 
+       /* regulators */
+       for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++)
+               sta32x->supplies[i].supply = sta32x_supply_names[i];
+
+       ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(sta32x->supplies),
+                                     sta32x->supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       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);
+               return ret;
+       }
+
        i2c_set_clientdata(i2c, sta32x);
 
        ret = snd_soc_register_codec(&i2c->dev, &sta32x_codec, &sta32x_dai, 1);
@@ -1006,17 +1057,7 @@ static struct i2c_driver sta32x_i2c_driver = {
        .id_table = sta32x_i2c_id,
 };
 
-static int __init sta32x_init(void)
-{
-       return i2c_add_driver(&sta32x_i2c_driver);
-}
-module_init(sta32x_init);
-
-static void __exit sta32x_exit(void)
-{
-       i2c_del_driver(&sta32x_i2c_driver);
-}
-module_exit(sta32x_exit);
+module_i2c_driver(sta32x_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC STA32X driver");
 MODULE_AUTHOR("Johannes Stezenbach <js@sig21.net>");
index 0c225cd569d231007b92c51bc7c8cf4baf02b9dc..9e31448623866e9e7665b289bdca1665b4924db2 100644 (file)
@@ -358,7 +358,7 @@ static int sta529_resume(struct snd_soc_codec *codec)
        return 0;
 }
 
-struct snd_soc_codec_driver sta529_codec_driver = {
+static const struct snd_soc_codec_driver sta529_codec_driver = {
        .probe = sta529_probe,
        .remove = sta529_remove,
        .set_bias_level = sta529_set_bias_level,
index 33c0f3d39c87ea0ea6c99ea1752f30e663914766..982e437799a8e62aa8085a9d5b509fa4d8f8a387 100644 (file)
@@ -340,7 +340,6 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec)
 
        printk(KERN_INFO "STAC9766 SoC Audio Codec %s\n", STAC9766_VERSION);
 
-       codec->control_data = codec;    /* we don't use regmap! */
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0)
                goto codec_err;
index 85944e95357834c5e7c5584c9998d1947a42e905..b1f6982c7c9c2615cc187649501f231098d1696c 100644 (file)
@@ -444,14 +444,4 @@ static struct spi_driver aic26_spi = {
        .remove = aic26_spi_remove,
 };
 
-static int __init aic26_init(void)
-{
-       return spi_register_driver(&aic26_spi);
-}
-module_init(aic26_init);
-
-static void __exit aic26_exit(void)
-{
-       spi_unregister_driver(&aic26_spi);
-}
-module_exit(aic26_exit);
+module_spi_driver(aic26_spi);
index b0a73d37ed52b4dfb52fb97a367e03f37a6df291..f230292ba96bbfc0c5cf7c7264dd4435de3d7590 100644 (file)
@@ -746,24 +746,7 @@ static struct i2c_driver aic32x4_i2c_driver = {
        .id_table = aic32x4_i2c_id,
 };
 
-static int __init aic32x4_modinit(void)
-{
-       int ret = 0;
-
-       ret = i2c_add_driver(&aic32x4_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register aic32x4 I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(aic32x4_modinit);
-
-static void __exit aic32x4_exit(void)
-{
-       i2c_del_driver(&aic32x4_i2c_driver);
-}
-module_exit(aic32x4_exit);
+module_i2c_driver(aic32x4_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC tlv320aic32x4 codec driver");
 MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
index dc78f5a4bcbf8922bb9690452f4e4e99c0a3ec18..5708a973a77627a21c71143ff7e7622ab47314ee 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/i2c.h>
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -1457,6 +1458,8 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
 {
        struct aic3x_pdata *pdata = i2c->dev.platform_data;
        struct aic3x_priv *aic3x;
+       struct aic3x_setup_data *ai3x_setup;
+       struct device_node *np = i2c->dev.of_node;
        int ret;
 
        aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL);
@@ -1471,6 +1474,25 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
        if (pdata) {
                aic3x->gpio_reset = pdata->gpio_reset;
                aic3x->setup = pdata->setup;
+       } else if (np) {
+               ai3x_setup = devm_kzalloc(&i2c->dev, sizeof(*ai3x_setup),
+                                                               GFP_KERNEL);
+               if (ai3x_setup == NULL) {
+                       dev_err(&i2c->dev, "failed to create private data\n");
+                       return -ENOMEM;
+               }
+
+               ret = of_get_named_gpio(np, "gpio-reset", 0);
+               if (ret >= 0)
+                       aic3x->gpio_reset = ret;
+               else
+                       aic3x->gpio_reset = -1;
+
+               if (of_property_read_u32_array(np, "ai3x-gpio-func",
+                                       ai3x_setup->gpio_func, 2) >= 0) {
+                       aic3x->setup = ai3x_setup;
+               }
+
        } else {
                aic3x->gpio_reset = -1;
        }
@@ -1488,34 +1510,27 @@ static int aic3x_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
+#if defined(CONFIG_OF)
+static const struct of_device_id tlv320aic3x_of_match[] = {
+       { .compatible = "ti,tlv320aic3x", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match);
+#endif
+
 /* machine i2c codec control layer */
 static struct i2c_driver aic3x_i2c_driver = {
        .driver = {
                .name = "tlv320aic3x-codec",
                .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(tlv320aic3x_of_match),
        },
        .probe  = aic3x_i2c_probe,
        .remove = aic3x_i2c_remove,
        .id_table = aic3x_i2c_id,
 };
 
-static int __init aic3x_modinit(void)
-{
-       int ret = 0;
-       ret = i2c_add_driver(&aic3x_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register TLV320AIC3x I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(aic3x_modinit);
-
-static void __exit aic3x_exit(void)
-{
-       i2c_del_driver(&aic3x_i2c_driver);
-}
-module_exit(aic3x_exit);
+module_i2c_driver(aic3x_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver");
 MODULE_AUTHOR("Vladimir Barinov");
index 0dd41077ab79eab0daf001111a5248ac17ee98f2..d2e16c5d7d1f71ca5d4425e7c6d8a83dc7bcb7ec 100644 (file)
@@ -1621,24 +1621,7 @@ static struct i2c_driver tlv320dac33_i2c_driver = {
        .id_table       = tlv320dac33_i2c_id,
 };
 
-static int __init dac33_module_init(void)
-{
-       int r;
-       r = i2c_add_driver(&tlv320dac33_i2c_driver);
-       if (r < 0) {
-               printk(KERN_ERR "DAC33: driver registration failed\n");
-               return r;
-       }
-       return 0;
-}
-module_init(dac33_module_init);
-
-static void __exit dac33_module_exit(void)
-{
-       i2c_del_driver(&tlv320dac33_i2c_driver);
-}
-module_exit(dac33_module_exit);
-
+module_i2c_driver(tlv320dac33_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC TLV320DAC33 codec driver");
 MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
index 6fe4aa3ac54401da4210df65ead54e0a1fe537b2..565ff39ad3a35ced5598c9532bc33b85f1d8983a 100644 (file)
@@ -487,19 +487,8 @@ static struct i2c_driver tpa6130a2_i2c_driver = {
        .id_table = tpa6130a2_id,
 };
 
-static int __init tpa6130a2_init(void)
-{
-       return i2c_add_driver(&tpa6130a2_i2c_driver);
-}
-
-static void __exit tpa6130a2_exit(void)
-{
-       i2c_del_driver(&tpa6130a2_i2c_driver);
-}
+module_i2c_driver(tpa6130a2_i2c_driver);
 
 MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
 MODULE_DESCRIPTION("TPA6130A2 Headphone amplifier driver");
 MODULE_LICENSE("GPL");
-
-module_init(tpa6130a2_init);
-module_exit(tpa6130a2_exit);
index 391fcfc7b63b16838257c43326362621f61a3368..e7f608996c41e1292c6a00efc56935b9acab75af 100644 (file)
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 #include <linux/i2c/twl.h>
 #include <linux/slab.h>
+#include <linux/gpio.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -152,8 +155,7 @@ struct twl4030_priv {
        u8 predrivel_enabled, predriver_enabled;
        u8 carkitl_enabled, carkitr_enabled;
 
-       /* Delay needed after enabling the digimic interface */
-       unsigned int digimic_delay;
+       struct twl4030_codec_data *pdata;
 };
 
 /*
@@ -295,13 +297,73 @@ static inline void twl4030_reset_registers(struct snd_soc_codec *codec)
 
 }
 
-static void twl4030_init_chip(struct snd_soc_codec *codec)
+static void twl4030_setup_pdata_of(struct twl4030_codec_data *pdata,
+                                  struct device_node *node)
+{
+       int value;
+
+       of_property_read_u32(node, "ti,digimic_delay",
+                            &pdata->digimic_delay);
+       of_property_read_u32(node, "ti,ramp_delay_value",
+                            &pdata->ramp_delay_value);
+       of_property_read_u32(node, "ti,offset_cncl_path",
+                            &pdata->offset_cncl_path);
+       if (!of_property_read_u32(node, "ti,hs_extmute", &value))
+               pdata->hs_extmute = value;
+
+       pdata->hs_extmute_gpio = of_get_named_gpio(node,
+                                                  "ti,hs_extmute_gpio", 0);
+       if (gpio_is_valid(pdata->hs_extmute_gpio))
+               pdata->hs_extmute = 1;
+}
+
+static struct twl4030_codec_data *twl4030_get_pdata(struct snd_soc_codec *codec)
 {
        struct twl4030_codec_data *pdata = dev_get_platdata(codec->dev);
+       struct device_node *twl4030_codec_node = NULL;
+
+       twl4030_codec_node = of_find_node_by_name(codec->dev->parent->of_node,
+                                                 "codec");
+
+       if (!pdata && twl4030_codec_node) {
+               pdata = devm_kzalloc(codec->dev,
+                                    sizeof(struct twl4030_codec_data),
+                                    GFP_KERNEL);
+               if (!pdata) {
+                       dev_err(codec->dev, "Can not allocate memory\n");
+                       return NULL;
+               }
+               twl4030_setup_pdata_of(pdata, twl4030_codec_node);
+       }
+
+       return pdata;
+}
+
+static void twl4030_init_chip(struct snd_soc_codec *codec)
+{
+       struct twl4030_codec_data *pdata;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        u8 reg, byte;
        int i = 0;
 
+       pdata = twl4030_get_pdata(codec);
+
+       if (pdata && pdata->hs_extmute &&
+           gpio_is_valid(pdata->hs_extmute_gpio)) {
+               int ret;
+
+               if (!pdata->hs_extmute_gpio)
+                       dev_warn(codec->dev,
+                                "Extmute GPIO is 0 is this correct?\n");
+
+               ret = gpio_request_one(pdata->hs_extmute_gpio,
+                                      GPIOF_OUT_INIT_LOW, "hs_extmute");
+               if (ret) {
+                       dev_err(codec->dev, "Failed to get hs_extmute GPIO\n");
+                       pdata->hs_extmute_gpio = -1;
+               }
+       }
+
        /* Check defaults, if instructed before anything else */
        if (pdata && pdata->check_defaults)
                twl4030_check_defaults(codec);
@@ -331,7 +393,7 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
        if (!pdata)
                return;
 
-       twl4030->digimic_delay = pdata->digimic_delay;
+       twl4030->pdata = pdata;
 
        reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
        reg &= ~TWL4030_RAMP_DELAY;
@@ -732,9 +794,9 @@ static int aif_event(struct snd_soc_dapm_widget *w,
 
 static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 {
-       struct twl4030_codec_data *pdata = codec->dev->platform_data;
        unsigned char hs_gain, hs_pop;
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+       struct twl4030_codec_data *pdata = twl4030->pdata;
        /* Base values for ramp delay calculation: 2^19 - 2^26 */
        unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304,
                                    8388608, 16777216, 33554432, 67108864};
@@ -748,8 +810,8 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
        /* Enable external mute control, this dramatically reduces
         * the pop-noise */
        if (pdata && pdata->hs_extmute) {
-               if (pdata->set_hs_extmute) {
-                       pdata->set_hs_extmute(1);
+               if (gpio_is_valid(pdata->hs_extmute_gpio)) {
+                       gpio_set_value(pdata->hs_extmute_gpio, 1);
                } else {
                        hs_pop |= TWL4030_EXTMUTE;
                        twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
@@ -786,8 +848,8 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 
        /* Disable external mute */
        if (pdata && pdata->hs_extmute) {
-               if (pdata->set_hs_extmute) {
-                       pdata->set_hs_extmute(0);
+               if (gpio_is_valid(pdata->hs_extmute_gpio)) {
+                       gpio_set_value(pdata->hs_extmute_gpio, 0);
                } else {
                        hs_pop &= ~TWL4030_EXTMUTE;
                        twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
@@ -847,9 +909,10 @@ 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 twl4030_codec_data *pdata = twl4030->pdata;
 
-       if (twl4030->digimic_delay)
-               twl4030_wait_ms(twl4030->digimic_delay);
+       if (pdata && pdata->digimic_delay)
+               twl4030_wait_ms(pdata->digimic_delay);
        return 0;
 }
 
@@ -999,7 +1062,7 @@ static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned short val;
-       unsigned short mask, bitmask;
+       unsigned short mask;
 
        if (twl4030->configured) {
                dev_err(codec->dev,
@@ -1007,18 +1070,16 @@ static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,
                return -EBUSY;
        }
 
-       for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
-               ;
        if (ucontrol->value.enumerated.item[0] > e->max - 1)
                return -EINVAL;
 
        val = ucontrol->value.enumerated.item[0] << e->shift_l;
-       mask = (bitmask - 1) << e->shift_l;
+       mask = e->mask << e->shift_l;
        if (e->shift_l != e->shift_r) {
                if (ucontrol->value.enumerated.item[1] > e->max - 1)
                        return -EINVAL;
                val |= ucontrol->value.enumerated.item[1] << e->shift_r;
-               mask |= (bitmask - 1) << e->shift_r;
+               mask |= e->mask << e->shift_r;
        }
 
        return snd_soc_update_bits(codec, e->reg, mask, val);
@@ -1239,16 +1300,11 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
        SND_SOC_DAPM_OUTPUT("Virtual Voice OUT"),
 
        /* DACs */
-       SND_SOC_DAPM_DAC("DAC Right1", "Right Front HiFi Playback",
-                       SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_DAC("DAC Left1", "Left Front HiFi Playback",
-                       SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_DAC("DAC Right2", "Right Rear HiFi Playback",
-                       SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_DAC("DAC Left2", "Left Rear HiFi Playback",
-                       SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_DAC("DAC Voice", "Voice Playback",
-                       SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("DAC Right1", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("DAC Left1", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("DAC Right2", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("DAC Left2", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("DAC Voice", NULL, SND_SOC_NOPM, 0, 0),
 
        /* Analog bypasses */
        SND_SOC_DAPM_SWITCH("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0,
@@ -1377,14 +1433,10 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
 
        /* Introducing four virtual ADC, since TWL4030 have four channel for
           capture */
-       SND_SOC_DAPM_ADC("ADC Virtual Left1", "Left Front Capture",
-               SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_ADC("ADC Virtual Right1", "Right Front Capture",
-               SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_ADC("ADC Virtual Left2", "Left Rear Capture",
-               SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_ADC("ADC Virtual Right2", "Right Rear Capture",
-               SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_ADC("ADC Virtual Left1", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_ADC("ADC Virtual Right1", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_ADC("ADC Virtual Left2", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_ADC("ADC Virtual Right2", NULL, SND_SOC_NOPM, 0, 0),
 
        /* Analog/Digital mic path selection.
           TX1 Left/Right: either analog Left/Right or Digimic0
@@ -1428,6 +1480,23 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
 };
 
 static const struct snd_soc_dapm_route intercon[] = {
+       /* Stream -> DAC mapping */
+       {"DAC Right1", NULL, "HiFi Playback"},
+       {"DAC Left1", NULL, "HiFi Playback"},
+       {"DAC Right2", NULL, "HiFi Playback"},
+       {"DAC Left2", NULL, "HiFi Playback"},
+       {"DAC Voice", NULL, "Voice Playback"},
+
+       /* ADC -> Stream mapping */
+       {"HiFi Capture", NULL, "ADC Virtual Left1"},
+       {"HiFi Capture", NULL, "ADC Virtual Right1"},
+       {"HiFi Capture", NULL, "ADC Virtual Left2"},
+       {"HiFi Capture", NULL, "ADC Virtual Right2"},
+       {"Voice Capture", NULL, "ADC Virtual Left1"},
+       {"Voice Capture", NULL, "ADC Virtual Right1"},
+       {"Voice Capture", NULL, "ADC Virtual Left2"},
+       {"Voice Capture", NULL, "ADC Virtual Right2"},
+
        {"Digital L1 Playback Mixer", NULL, "DAC Left1"},
        {"Digital R1 Playback Mixer", NULL, "DAC Right1"},
        {"Digital L2 Playback Mixer", NULL, "DAC Left2"},
@@ -2172,7 +2241,7 @@ static struct snd_soc_dai_driver twl4030_dai[] = {
                .formats = TWL4030_FORMATS,
                .sig_bits = 24,},
        .capture = {
-               .stream_name = "Capture",
+               .stream_name = "HiFi Capture",
                .channels_min = 2,
                .channels_max = 4,
                .rates = TWL4030_RATES,
@@ -2189,7 +2258,7 @@ static struct snd_soc_dai_driver twl4030_dai[] = {
                .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
        .capture = {
-               .stream_name = "Capture",
+               .stream_name = "Voice Capture",
                .channels_min = 1,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
@@ -2214,7 +2283,8 @@ static int twl4030_soc_probe(struct snd_soc_codec *codec)
 {
        struct twl4030_priv *twl4030;
 
-       twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL);
+       twl4030 = devm_kzalloc(codec->dev, sizeof(struct twl4030_priv),
+                              GFP_KERNEL);
        if (twl4030 == NULL) {
                dev_err(codec->dev, "Can not allocate memory\n");
                return -ENOMEM;
@@ -2231,11 +2301,15 @@ static int twl4030_soc_probe(struct snd_soc_codec *codec)
 static int twl4030_soc_remove(struct snd_soc_codec *codec)
 {
        struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+       struct twl4030_codec_data *pdata = twl4030->pdata;
 
        /* Reset registers to their chip default before leaving */
        twl4030_reset_registers(codec);
        twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       kfree(twl4030);
+
+       if (pdata && pdata->hs_extmute && gpio_is_valid(pdata->hs_extmute_gpio))
+               gpio_free(pdata->hs_extmute_gpio);
+
        return 0;
 }
 
@@ -2262,13 +2336,6 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
 
 static int __devinit twl4030_codec_probe(struct platform_device *pdev)
 {
-       struct twl4030_codec_data *pdata = pdev->dev.platform_data;
-
-       if (!pdata) {
-               dev_err(&pdev->dev, "platform_data is missing\n");
-               return -EINVAL;
-       }
-
        return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl4030,
                        twl4030_dai, ARRAY_SIZE(twl4030_dai));
 }
index c084c549942ecef39ffa52788524125b2c8ef1b6..e8f97af75928ea3548c0d389f9e70d7f676ba2c3 100644 (file)
@@ -727,10 +727,8 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
                        TWL6040_REG_MICRCTL, 1, 0, NULL, 0),
 
        /* ADCs */
-       SND_SOC_DAPM_ADC("ADC Left", "Left Front Capture",
-                       TWL6040_REG_MICLCTL, 2, 0),
-       SND_SOC_DAPM_ADC("ADC Right", "Right Front Capture",
-                       TWL6040_REG_MICRCTL, 2, 0),
+       SND_SOC_DAPM_ADC("ADC Left", NULL, TWL6040_REG_MICLCTL, 2, 0),
+       SND_SOC_DAPM_ADC("ADC Right", NULL, TWL6040_REG_MICRCTL, 2, 0),
 
        /* Microphone bias */
        SND_SOC_DAPM_SUPPLY("Headset Mic Bias",
@@ -743,15 +741,12 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
                            TWL6040_REG_DMICBCTL, 4, 0, NULL, 0),
 
        /* DACs */
-       SND_SOC_DAPM_DAC("HSDAC Left", "Headset Playback", SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_DAC("HSDAC Right", "Headset Playback", SND_SOC_NOPM, 0, 0),
-       SND_SOC_DAPM_DAC("HFDAC Left", "Handsfree Playback",
-                        TWL6040_REG_HFLCTL, 0, 0),
-       SND_SOC_DAPM_DAC("HFDAC Right", "Handsfree Playback",
-                        TWL6040_REG_HFRCTL, 0, 0),
+       SND_SOC_DAPM_DAC("HSDAC Left", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("HSDAC Right", NULL, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("HFDAC Left", NULL, TWL6040_REG_HFLCTL, 0, 0),
+       SND_SOC_DAPM_DAC("HFDAC Right", NULL, TWL6040_REG_HFRCTL, 0, 0),
        /* Virtual DAC for vibra path (DL4 channel) */
-       SND_SOC_DAPM_DAC("VIBRA DAC", "Vibra Playback",
-                       SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("VIBRA DAC", NULL, SND_SOC_NOPM, 0, 0),
 
        SND_SOC_DAPM_MUX("Handsfree Left Playback",
                        SND_SOC_NOPM, 0, 0, &hfl_mux_controls),
@@ -810,6 +805,26 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
 };
 
 static const struct snd_soc_dapm_route intercon[] = {
+       /* Stream -> DAC mapping */
+       {"HSDAC Left", NULL, "Legacy Playback"},
+       {"HSDAC Left", NULL, "Headset Playback"},
+       {"HSDAC Right", NULL, "Legacy Playback"},
+       {"HSDAC Right", NULL, "Headset Playback"},
+
+       {"HFDAC Left", NULL, "Legacy Playback"},
+       {"HFDAC Left", NULL, "Handsfree Playback"},
+       {"HFDAC Right", NULL, "Legacy Playback"},
+       {"HFDAC Right", NULL, "Handsfree Playback"},
+
+       {"VIBRA DAC", NULL, "Legacy Playback"},
+       {"VIBRA DAC", NULL, "Vibra Playback"},
+
+       /* ADC -> Stream mapping */
+       {"ADC Left", NULL, "Legacy Capture"},
+       {"ADC Left", NULL, "Capture"},
+       {"ADC Right", NULL, "Legacy Capture"},
+       {"ADC Right", NULL, "Capture"},
+
        /* Capture path */
        {"Analog Left Capture Route", "Headset Mic", "HSMIC"},
        {"Analog Left Capture Route", "Main Mic", "MAINMIC"},
@@ -1028,14 +1043,14 @@ static struct snd_soc_dai_driver twl6040_dai[] = {
 {
        .name = "twl6040-legacy",
        .playback = {
-               .stream_name = "Playback",
+               .stream_name = "Legacy Playback",
                .channels_min = 1,
                .channels_max = 5,
                .rates = TWL6040_RATES,
                .formats = TWL6040_FORMATS,
        },
        .capture = {
-               .stream_name = "Capture",
+               .stream_name = "Legacy Capture",
                .channels_min = 1,
                .channels_max = 2,
                .rates = TWL6040_RATES,
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c
new file mode 100644 (file)
index 0000000..99afc00
--- /dev/null
@@ -0,0 +1,940 @@
+/*
+ * wm0010.c  --  WM0010 DSP Driver
+ *
+ * Copyright 2012 Wolfson Microelectronics PLC.
+ *
+ * Authors: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *          Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
+ *          Scott Ling <sl@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/irqreturn.h>
+#include <linux/init.h>
+#include <linux/spi/spi.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+#include <sound/soc.h>
+#include <sound/wm0010.h>
+
+#define DEVICE_ID_WM0010       10
+
+enum dfw_cmd {
+       DFW_CMD_FUSE = 0x01,
+       DFW_CMD_CODE_HDR,
+       DFW_CMD_CODE_DATA,
+       DFW_CMD_PLL,
+       DFW_CMD_INFO = 0xff
+};
+
+struct dfw_binrec {
+       u8 command;
+       u32 length:24;
+       u32 address;
+       uint8_t data[0];
+} __packed;
+
+struct dfw_pllrec {
+       u8 command;
+       u32 length:24;
+       u32 address;
+       u32 clkctrl1;
+       u32 clkctrl2;
+       u32 clkctrl3;
+       u32 ldetctrl;
+       u32 uart_div;
+       u32 spi_div;
+} __packed;
+
+static struct pll_clock_map {
+       int max_sysclk;
+       int max_pll_spi_speed;
+       u32 pll_clkctrl1;
+} pll_clock_map[] = {                     /* Dividers */
+       { 22000000, 26000000, 0x00201f11 }, /* 2,32,2  */
+       { 18000000, 26000000, 0x00203f21 }, /* 2,64,4  */
+       { 14000000, 26000000, 0x00202620 }, /* 1,39,4  */
+       { 10000000, 22000000, 0x00203120 }, /* 1,50,4  */
+       {  6500000, 22000000, 0x00204520 }, /* 1,70,4  */
+       {  5500000, 22000000, 0x00103f10 }, /* 1,64,2  */
+};
+
+enum wm0010_state {
+       WM0010_POWER_OFF,
+       WM0010_OUT_OF_RESET,
+       WM0010_BOOTROM,
+       WM0010_STAGE2,
+       WM0010_FIRMWARE,
+};
+
+struct wm0010_priv {
+       struct snd_soc_codec *codec;
+
+       struct mutex lock;
+       struct device *dev;
+
+       struct wm0010_pdata pdata;
+
+       int gpio_reset;
+       int gpio_reset_value;
+
+       struct regulator_bulk_data core_supplies[2];
+       struct regulator *dbvdd;
+
+       int sysclk;
+
+       enum wm0010_state state;
+       bool boot_failed;
+       int boot_done;
+       bool ready;
+       bool pll_running;
+       int max_spi_freq;
+       int board_max_spi_speed;
+       u32 pll_clkctrl1;
+
+       spinlock_t irq_lock;
+       int irq;
+
+       struct completion boot_completion;
+};
+
+struct wm0010_spi_msg {
+       struct spi_message m;
+       struct spi_transfer t;
+       u8 *tx_buf;
+       u8 *rx_buf;
+       size_t len;
+};
+
+static const struct snd_soc_dapm_widget wm0010_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("CLKIN",  SND_SOC_NOPM, 0, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route wm0010_dapm_routes[] = {
+       { "SDI2 Capture", NULL, "SDI1 Playback" },
+       { "SDI1 Capture", NULL, "SDI2 Playback" },
+
+       { "SDI1 Capture", NULL, "CLKIN" },
+       { "SDI2 Capture", NULL, "CLKIN" },
+       { "SDI1 Playback", NULL, "CLKIN" },
+       { "SDI2 Playback", NULL, "CLKIN" },
+};
+
+static const char *wm0010_state_to_str(enum wm0010_state state)
+{
+       const char *state_to_str[] = {
+               "Power off",
+               "Out of reset",
+               "Boot ROM",
+               "Stage2",
+               "Firmware"
+       };
+
+       if (state < 0 || state >= ARRAY_SIZE(state_to_str))
+               return "null";
+       return state_to_str[state];
+}
+
+/* Called with wm0010->lock held */
+static void wm0010_halt(struct snd_soc_codec *codec)
+{
+       struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+       unsigned long flags;
+       enum wm0010_state state;
+
+       /* Fetch the wm0010 state */
+       spin_lock_irqsave(&wm0010->irq_lock, flags);
+       state = wm0010->state;
+       spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+       switch (state) {
+       case WM0010_POWER_OFF:
+               /* If there's nothing to do, bail out */
+               return;
+       case WM0010_OUT_OF_RESET:
+       case WM0010_BOOTROM:
+       case WM0010_STAGE2:
+       case WM0010_FIRMWARE:
+               /* Remember to put chip back into reset */
+               gpio_set_value_cansleep(wm0010->gpio_reset,
+                                       wm0010->gpio_reset_value);
+               /* Disable the regulators */
+               regulator_disable(wm0010->dbvdd);
+               regulator_bulk_disable(ARRAY_SIZE(wm0010->core_supplies),
+                                      wm0010->core_supplies);
+               break;
+       }
+
+       spin_lock_irqsave(&wm0010->irq_lock, flags);
+       wm0010->state = WM0010_POWER_OFF;
+       spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+}
+
+struct wm0010_boot_xfer {
+       struct list_head list;
+       struct snd_soc_codec *codec;
+       struct completion *done;
+       struct spi_message m;
+       struct spi_transfer t;
+};
+
+/* Called with wm0010->lock held */
+static void wm0010_mark_boot_failure(struct wm0010_priv *wm0010)
+{
+       enum wm0010_state state;
+       unsigned long flags;
+
+       spin_lock_irqsave(&wm0010->irq_lock, flags);
+       state = wm0010->state;
+       spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+       dev_err(wm0010->dev, "Failed to transition from `%s' state to `%s' state\n",
+               wm0010_state_to_str(state), wm0010_state_to_str(state + 1));
+
+       wm0010->boot_failed = true;
+}
+
+static void wm0010_boot_xfer_complete(void *data)
+{
+       struct wm0010_boot_xfer *xfer = data;
+       struct snd_soc_codec *codec = xfer->codec;
+       struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+       u32 *out32 = xfer->t.rx_buf;
+       int i;
+
+       if (xfer->m.status != 0) {
+               dev_err(codec->dev, "SPI transfer failed: %d\n",
+                       xfer->m.status);
+               wm0010_mark_boot_failure(wm0010);
+               if (xfer->done)
+                       complete(xfer->done);
+               return;
+       }
+
+       for (i = 0; i < xfer->t.len / 4; i++) {
+               dev_dbg(codec->dev, "%d: %04x\n", i, out32[i]);
+
+               switch (be32_to_cpu(out32[i])) {
+               case 0xe0e0e0e0:
+                       dev_err(codec->dev,
+                               "%d: ROM error reported in stage 2\n", i);
+                       wm0010_mark_boot_failure(wm0010);
+                       break;
+
+               case 0x55555555:
+                       if (wm0010->boot_done == 0)
+                               break;
+                       dev_err(codec->dev,
+                               "%d: ROM bootloader running in stage 2\n", i);
+                       wm0010_mark_boot_failure(wm0010);
+                       break;
+
+               case 0x0fed0000:
+                       dev_dbg(codec->dev, "Stage2 loader running\n");
+                       break;
+
+               case 0x0fed0007:
+                       dev_dbg(codec->dev, "CODE_HDR packet received\n");
+                       break;
+
+               case 0x0fed0008:
+                       dev_dbg(codec->dev, "CODE_DATA packet received\n");
+                       break;
+
+               case 0x0fed0009:
+                       dev_dbg(codec->dev, "Download complete\n");
+                       break;
+
+               case 0x0fed000c:
+                       dev_dbg(codec->dev, "Application start\n");
+                       break;
+
+               case 0x0fed000e:
+                       dev_dbg(codec->dev, "PLL packet received\n");
+                       wm0010->pll_running = true;
+                       break;
+
+               case 0x0fed0025:
+                       dev_err(codec->dev, "Device reports image too long\n");
+                       wm0010_mark_boot_failure(wm0010);
+                       break;
+
+               case 0x0fed002c:
+                       dev_err(codec->dev, "Device reports bad SPI packet\n");
+                       wm0010_mark_boot_failure(wm0010);
+                       break;
+
+               case 0x0fed0031:
+                       dev_err(codec->dev, "Device reports SPI read overflow\n");
+                       wm0010_mark_boot_failure(wm0010);
+                       break;
+
+               case 0x0fed0032:
+                       dev_err(codec->dev, "Device reports SPI underclock\n");
+                       wm0010_mark_boot_failure(wm0010);
+                       break;
+
+               case 0x0fed0033:
+                       dev_err(codec->dev, "Device reports bad header packet\n");
+                       wm0010_mark_boot_failure(wm0010);
+                       break;
+
+               case 0x0fed0034:
+                       dev_err(codec->dev, "Device reports invalid packet type\n");
+                       wm0010_mark_boot_failure(wm0010);
+                       break;
+
+               case 0x0fed0035:
+                       dev_err(codec->dev, "Device reports data before header error\n");
+                       wm0010_mark_boot_failure(wm0010);
+                       break;
+
+               case 0x0fed0038:
+                       dev_err(codec->dev, "Device reports invalid PLL packet\n");
+                       break;
+
+               case 0x0fed003a:
+                       dev_err(codec->dev, "Device reports packet alignment error\n");
+                       wm0010_mark_boot_failure(wm0010);
+                       break;
+
+               default:
+                       dev_err(codec->dev, "Unrecognised return 0x%x\n",
+                           be32_to_cpu(out32[i]));
+                       wm0010_mark_boot_failure(wm0010);
+                       break;
+               }
+
+               if (wm0010->boot_failed)
+                       break;
+       }
+
+       wm0010->boot_done++;
+       if (xfer->done)
+               complete(xfer->done);
+}
+
+static void byte_swap_64(u64 *data_in, u64 *data_out, u32 len)
+{
+       int i;
+
+       for (i = 0; i < len / 8; i++)
+               data_out[i] = cpu_to_be64(le64_to_cpu(data_in[i]));
+}
+
+static int wm0010_boot(struct snd_soc_codec *codec)
+{
+       struct spi_device *spi = to_spi_device(codec->dev);
+       struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+       unsigned long flags;
+       struct list_head xfer_list;
+       struct wm0010_boot_xfer *xfer;
+       int ret;
+       struct completion done;
+       const struct firmware *fw;
+       const struct dfw_binrec *rec;
+       struct spi_message m;
+       struct spi_transfer t;
+       struct dfw_pllrec pll_rec;
+       u32 *img, *p;
+       u64 *img_swap;
+       u8 *out;
+       u32 len, offset;
+       int i;
+
+       spin_lock_irqsave(&wm0010->irq_lock, flags);
+       if (wm0010->state != WM0010_POWER_OFF)
+               dev_warn(wm0010->dev, "DSP already powered up!\n");
+       spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+       if (wm0010->sysclk > 26000000) {
+               dev_err(codec->dev, "Max DSP clock frequency is 26MHz\n");
+               ret = -ECANCELED;
+               goto err;
+       }
+
+       INIT_LIST_HEAD(&xfer_list);
+
+       mutex_lock(&wm0010->lock);
+       wm0010->pll_running = false;
+
+       dev_dbg(codec->dev, "max_spi_freq: %d\n", wm0010->max_spi_freq);
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm0010->core_supplies),
+                                   wm0010->core_supplies);
+       if (ret != 0) {
+               dev_err(&spi->dev, "Failed to enable core supplies: %d\n",
+                       ret);
+               mutex_unlock(&wm0010->lock);
+               goto err;
+       }
+
+       ret = regulator_enable(wm0010->dbvdd);
+       if (ret != 0) {
+               dev_err(&spi->dev, "Failed to enable DBVDD: %d\n", ret);
+               goto err_core;
+       }
+
+       /* Release reset */
+       gpio_set_value_cansleep(wm0010->gpio_reset, !wm0010->gpio_reset_value);
+       spin_lock_irqsave(&wm0010->irq_lock, flags);
+       wm0010->state = WM0010_OUT_OF_RESET;
+       spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+       /* First the bootloader */
+       ret = request_firmware(&fw, "wm0010_stage2.bin", codec->dev);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request stage2 loader: %d\n",
+                       ret);
+               goto abort;
+       }
+
+       if (!wait_for_completion_timeout(&wm0010->boot_completion,
+                                        msecs_to_jiffies(10)))
+               dev_err(codec->dev, "Failed to get interrupt from DSP\n");
+
+       spin_lock_irqsave(&wm0010->irq_lock, flags);
+       wm0010->state = WM0010_BOOTROM;
+       spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+       dev_dbg(codec->dev, "Downloading %zu byte stage 2 loader\n", fw->size);
+
+       /* Copy to local buffer first as vmalloc causes problems for dma */
+       img = kzalloc(fw->size, GFP_KERNEL);
+       if (!img) {
+               dev_err(codec->dev, "Failed to allocate image buffer\n");
+               goto abort;
+       }
+
+       out = kzalloc(fw->size, GFP_KERNEL);
+       if (!out) {
+               dev_err(codec->dev, "Failed to allocate output buffer\n");
+               goto abort;
+       }
+
+       memcpy(img, &fw->data[0], fw->size);
+
+       spi_message_init(&m);
+       memset(&t, 0, sizeof(t));
+       t.rx_buf = out;
+       t.tx_buf = img;
+       t.len = fw->size;
+       t.bits_per_word = 8;
+       t.speed_hz = wm0010->sysclk / 10;
+       spi_message_add_tail(&t, &m);
+
+       dev_dbg(codec->dev, "Starting initial download at %dHz\n",
+               t.speed_hz);
+
+       ret = spi_sync(spi, &m);
+       if (ret != 0) {
+               dev_err(codec->dev, "Initial download failed: %d\n", ret);
+               goto abort;
+       }
+
+       /* Look for errors from the boot ROM */
+       for (i = 0; i < fw->size; i++) {
+               if (out[i] != 0x55) {
+                       ret = -EBUSY;
+                       dev_err(codec->dev, "Boot ROM error: %x in %d\n",
+                               out[i], i);
+                       wm0010_mark_boot_failure(wm0010);
+                       goto abort;
+               }
+       }
+
+       release_firmware(fw);
+       kfree(img);
+       kfree(out);
+
+       if (!wait_for_completion_timeout(&wm0010->boot_completion,
+                                        msecs_to_jiffies(10)))
+               dev_err(codec->dev, "Failed to get interrupt from DSP loader.\n");
+
+       spin_lock_irqsave(&wm0010->irq_lock, flags);
+       wm0010->state = WM0010_STAGE2;
+       spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+       /* Only initialise PLL if max_spi_freq initialised */
+       if (wm0010->max_spi_freq) {
+
+               /* Initialise a PLL record */
+               memset(&pll_rec, 0, sizeof(pll_rec));
+               pll_rec.command = DFW_CMD_PLL;
+               pll_rec.length = (sizeof(pll_rec) - 8);
+
+               /* On wm0010 only the CLKCTRL1 value is used */
+               pll_rec.clkctrl1 = wm0010->pll_clkctrl1;
+
+               len = pll_rec.length + 8;
+               out = kzalloc(len, GFP_KERNEL);
+               if (!out) {
+                       dev_err(codec->dev,
+                               "Failed to allocate RX buffer\n");
+                       goto abort;
+               }
+
+               img_swap = kzalloc(len, GFP_KERNEL);
+               if (!img_swap) {
+                       dev_err(codec->dev,
+                               "Failed to allocate image buffer\n");
+                       goto abort;
+               }
+
+               /* We need to re-order for 0010 */
+               byte_swap_64((u64 *)&pll_rec, img_swap, len);
+
+               spi_message_init(&m);
+               memset(&t, 0, sizeof(t));
+               t.rx_buf = out;
+               t.tx_buf = img_swap;
+               t.len = len;
+               t.bits_per_word = 8;
+               t.speed_hz = wm0010->sysclk / 6;
+               spi_message_add_tail(&t, &m);
+
+               ret = spi_sync(spi, &m);
+               if (ret != 0) {
+                       dev_err(codec->dev, "First PLL write failed: %d\n", ret);
+                       goto abort;
+               }
+
+               /* Use a second send of the message to get the return status */
+               ret = spi_sync(spi, &m);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Second PLL write failed: %d\n", ret);
+                       goto abort;
+               }
+
+               p = (u32 *)out;
+
+               /* Look for PLL active code from the DSP */
+               for (i = 0; i < len / 4; i++) {
+                       if (*p == 0x0e00ed0f) {
+                               dev_dbg(codec->dev, "PLL packet received\n");
+                               wm0010->pll_running = true;
+                               break;
+                       }
+                       p++;
+               }
+
+               kfree(img_swap);
+               kfree(out);
+       } else
+               dev_dbg(codec->dev, "Not enabling DSP PLL.");
+
+       ret = request_firmware(&fw, "wm0010.dfw", codec->dev);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to request application: %d\n",
+                       ret);
+               goto abort;
+       }
+
+       rec = (const struct dfw_binrec *)fw->data;
+       offset = 0;
+       wm0010->boot_done = 0;
+       wm0010->boot_failed = false;
+       BUG_ON(!list_empty(&xfer_list));
+       init_completion(&done);
+
+       /* First record should be INFO */
+       if (rec->command != DFW_CMD_INFO) {
+               dev_err(codec->dev, "First record not INFO\r\n");
+               goto abort;
+       }
+
+       /* Check it's a 0010 file */
+       if (rec->data[0] != DEVICE_ID_WM0010) {
+               dev_err(codec->dev, "Not a WM0010 firmware file.\r\n");
+               goto abort;
+       }
+
+       /* Skip the info record as we don't need to send it */
+       offset += ((rec->length) + 8);
+       rec = (void *)&rec->data[rec->length];
+
+       while (offset < fw->size) {
+               dev_dbg(codec->dev,
+                       "Packet: command %d, data length = 0x%x\r\n",
+                       rec->command, rec->length);
+               len = rec->length + 8;
+
+               out = kzalloc(len, GFP_KERNEL);
+               if (!out) {
+                       dev_err(codec->dev,
+                               "Failed to allocate RX buffer\n");
+                       goto abort;
+               }
+
+               img_swap = kzalloc(len, GFP_KERNEL);
+               if (!img_swap) {
+                       dev_err(codec->dev,
+                               "Failed to allocate image buffer\n");
+                       goto abort;
+               }
+
+               /* We need to re-order for 0010 */
+               byte_swap_64((u64 *)&rec->command, img_swap, len);
+
+               xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
+               if (!xfer) {
+                       dev_err(codec->dev, "Failed to allocate xfer\n");
+                       goto abort;
+               }
+
+               xfer->codec = codec;
+               list_add_tail(&xfer->list, &xfer_list);
+
+               spi_message_init(&xfer->m);
+               xfer->m.complete = wm0010_boot_xfer_complete;
+               xfer->m.context = xfer;
+               xfer->t.tx_buf = img_swap;
+               xfer->t.rx_buf = out;
+               xfer->t.len = len;
+               xfer->t.bits_per_word = 8;
+
+               if (!wm0010->pll_running) {
+                       xfer->t.speed_hz = wm0010->sysclk / 6;
+               } else {
+                       xfer->t.speed_hz = wm0010->max_spi_freq;
+
+                       if (wm0010->board_max_spi_speed &&
+                          (wm0010->board_max_spi_speed < wm0010->max_spi_freq))
+                                       xfer->t.speed_hz = wm0010->board_max_spi_speed;
+               }
+
+               /* Store max usable spi frequency for later use */
+               wm0010->max_spi_freq = xfer->t.speed_hz;
+
+               spi_message_add_tail(&xfer->t, &xfer->m);
+
+               offset += ((rec->length) + 8);
+               rec = (void *)&rec->data[rec->length];
+
+               if (offset >= fw->size) {
+                       dev_dbg(codec->dev, "All transfers scheduled\n");
+                       xfer->done = &done;
+               }
+
+               ret = spi_async(spi, &xfer->m);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Write failed: %d\n", ret);
+                       goto abort;
+               }
+
+               if (wm0010->boot_failed)
+                       goto abort;
+       }
+
+       wait_for_completion(&done);
+
+       spin_lock_irqsave(&wm0010->irq_lock, flags);
+       wm0010->state = WM0010_FIRMWARE;
+       spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+
+       mutex_unlock(&wm0010->lock);
+
+       release_firmware(fw);
+
+       while (!list_empty(&xfer_list)) {
+               xfer = list_first_entry(&xfer_list, struct wm0010_boot_xfer,
+                                       list);
+               kfree(xfer->t.rx_buf);
+               kfree(xfer->t.tx_buf);
+               list_del(&xfer->list);
+               kfree(xfer);
+       }
+
+       return 0;
+
+abort:
+       /* Put the chip back into reset */
+       wm0010_halt(codec);
+       mutex_unlock(&wm0010->lock);
+       return ret;
+
+err_core:
+       mutex_unlock(&wm0010->lock);
+       regulator_bulk_disable(ARRAY_SIZE(wm0010->core_supplies),
+                              wm0010->core_supplies);
+err:
+       return ret;
+}
+
+static int wm0010_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE)
+                       wm0010_boot(codec);
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) {
+                       mutex_lock(&wm0010->lock);
+                       wm0010_halt(codec);
+                       mutex_unlock(&wm0010->lock);
+               }
+               break;
+       case SND_SOC_BIAS_OFF:
+               break;
+       }
+
+       codec->dapm.bias_level = level;
+
+       return 0;
+}
+
+static int wm0010_set_sysclk(struct snd_soc_codec *codec, int source,
+                            int clk_id, unsigned int freq, int dir)
+{
+       struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+       unsigned int i;
+
+       wm0010->sysclk = freq;
+
+       if (freq < pll_clock_map[ARRAY_SIZE(pll_clock_map)-1].max_sysclk) {
+               wm0010->max_spi_freq = 0;
+       } else {
+               for (i = 0; i < ARRAY_SIZE(pll_clock_map); i++)
+                       if (freq >= pll_clock_map[i].max_sysclk)
+                               break;
+
+               wm0010->max_spi_freq = pll_clock_map[i].max_pll_spi_speed;
+               wm0010->pll_clkctrl1 = pll_clock_map[i].pll_clkctrl1;
+       }
+
+       return 0;
+}
+
+static int wm0010_probe(struct snd_soc_codec *codec);
+
+static struct snd_soc_codec_driver soc_codec_dev_wm0010 = {
+       .probe = wm0010_probe,
+       .set_bias_level = wm0010_set_bias_level,
+       .set_sysclk = wm0010_set_sysclk,
+       .idle_bias_off = true,
+
+       .dapm_widgets = wm0010_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm0010_dapm_widgets),
+       .dapm_routes = wm0010_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(wm0010_dapm_routes),
+};
+
+#define WM0010_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+#define WM0010_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
+                       SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE |\
+                       SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm0010_dai[] = {
+       {
+               .name = "wm0010-sdi1",
+               .playback = {
+                       .stream_name = "SDI1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM0010_RATES,
+                       .formats = WM0010_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "SDI1 Capture",
+                        .channels_min = 1,
+                        .channels_max = 2,
+                        .rates = WM0010_RATES,
+                        .formats = WM0010_FORMATS,
+                },
+       },
+       {
+               .name = "wm0010-sdi2",
+               .playback = {
+                       .stream_name = "SDI2 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM0010_RATES,
+                       .formats = WM0010_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "SDI2 Capture",
+                        .channels_min = 1,
+                        .channels_max = 2,
+                        .rates = WM0010_RATES,
+                        .formats = WM0010_FORMATS,
+                },
+       },
+};
+
+static irqreturn_t wm0010_irq(int irq, void *data)
+{
+       struct wm0010_priv *wm0010 = data;
+
+       switch (wm0010->state) {
+       case WM0010_POWER_OFF:
+       case WM0010_OUT_OF_RESET:
+       case WM0010_BOOTROM:
+       case WM0010_STAGE2:
+               spin_lock(&wm0010->irq_lock);
+               complete(&wm0010->boot_completion);
+               spin_unlock(&wm0010->irq_lock);
+               return IRQ_HANDLED;
+       default:
+               return IRQ_NONE;
+       }
+
+       return IRQ_NONE;
+}
+
+static int wm0010_probe(struct snd_soc_codec *codec)
+{
+       struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
+
+       wm0010->codec = codec;
+
+       return 0;
+}
+
+static int __devinit wm0010_spi_probe(struct spi_device *spi)
+{
+       unsigned long gpio_flags;
+       int ret;
+       int trigger;
+       int irq;
+       struct wm0010_priv *wm0010;
+
+       wm0010 = devm_kzalloc(&spi->dev, sizeof(*wm0010),
+                             GFP_KERNEL);
+       if (!wm0010)
+               return -ENOMEM;
+
+       mutex_init(&wm0010->lock);
+       spin_lock_init(&wm0010->irq_lock);
+
+       spi_set_drvdata(spi, wm0010);
+       wm0010->dev = &spi->dev;
+
+       if (dev_get_platdata(&spi->dev))
+               memcpy(&wm0010->pdata, dev_get_platdata(&spi->dev),
+                      sizeof(wm0010->pdata));
+
+       init_completion(&wm0010->boot_completion);
+
+       wm0010->core_supplies[0].supply = "AVDD";
+       wm0010->core_supplies[1].supply = "DCVDD";
+       ret = devm_regulator_bulk_get(wm0010->dev, ARRAY_SIZE(wm0010->core_supplies),
+                                     wm0010->core_supplies);
+       if (ret != 0) {
+               dev_err(wm0010->dev, "Failed to obtain core supplies: %d\n",
+                       ret);
+               return ret;
+       }
+
+       wm0010->dbvdd = devm_regulator_get(wm0010->dev, "DBVDD");
+       if (IS_ERR(wm0010->dbvdd)) {
+               ret = PTR_ERR(wm0010->dbvdd);
+               dev_err(wm0010->dev, "Failed to obtain DBVDD: %d\n", ret);
+               return ret;
+       }
+
+       if (wm0010->pdata.gpio_reset) {
+               wm0010->gpio_reset = wm0010->pdata.gpio_reset;
+
+               if (wm0010->pdata.reset_active_high)
+                       wm0010->gpio_reset_value = 1;
+               else
+                       wm0010->gpio_reset_value = 0;
+
+               if (wm0010->gpio_reset_value)
+                       gpio_flags = GPIOF_OUT_INIT_HIGH;
+               else
+                       gpio_flags = GPIOF_OUT_INIT_LOW;
+
+               ret = devm_gpio_request_one(wm0010->dev, wm0010->gpio_reset,
+                                           gpio_flags, "wm0010 reset");
+               if (ret < 0) {
+                       dev_err(wm0010->dev,
+                               "Failed to request GPIO for DSP reset: %d\n",
+                               ret);
+                       return ret;
+               }
+       } else {
+               dev_err(wm0010->dev, "No reset GPIO configured\n");
+               return -EINVAL;
+       }
+
+       wm0010->state = WM0010_POWER_OFF;
+
+       irq = spi->irq;
+       if (wm0010->pdata.irq_flags)
+               trigger = wm0010->pdata.irq_flags;
+       else
+               trigger = IRQF_TRIGGER_FALLING;
+       trigger |= IRQF_ONESHOT;
+
+       ret = request_threaded_irq(irq, NULL, wm0010_irq, trigger | IRQF_ONESHOT,
+                                  "wm0010", wm0010);
+       if (ret) {
+               dev_err(wm0010->dev, "Failed to request IRQ %d: %d\n",
+                       irq, ret);
+               return ret;
+       }
+       wm0010->irq = irq;
+
+       if (spi->max_speed_hz)
+               wm0010->board_max_spi_speed = spi->max_speed_hz;
+       else
+               wm0010->board_max_spi_speed = 0;
+
+       ret = snd_soc_register_codec(&spi->dev,
+                                    &soc_codec_dev_wm0010, wm0010_dai,
+                                    ARRAY_SIZE(wm0010_dai));
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int __devexit wm0010_spi_remove(struct spi_device *spi)
+{
+       struct wm0010_priv *wm0010 = spi_get_drvdata(spi);
+
+       snd_soc_unregister_codec(&spi->dev);
+
+       gpio_set_value_cansleep(wm0010->gpio_reset,
+                               wm0010->gpio_reset_value);
+
+       if (wm0010->irq)
+               free_irq(wm0010->irq, wm0010);
+
+       return 0;
+}
+
+static struct spi_driver wm0010_spi_driver = {
+       .driver = {
+               .name   = "wm0010",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = wm0010_spi_probe,
+       .remove         = __devexit_p(wm0010_spi_remove),
+};
+
+module_spi_driver(wm0010_spi_driver);
+
+MODULE_DESCRIPTION("ASoC WM0010 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
index a3acb7a85f6ab26f62e92489e75e0f6b4822f831..683dc43b1d87898508b011e7ca4aee7087049f7e 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/i2c.h>
 #include <linux/regmap.h>
 #include <linux/debugfs.h>
+#include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 
 #include "wm2000.h"
 
+#define WM2000_NUM_SUPPLIES 3
+
+static const char *wm2000_supplies[WM2000_NUM_SUPPLIES] = {
+       "SPKVDD",
+       "DBVDD",
+       "DCVDD",
+};
+
 enum wm2000_anc_mode {
        ANC_ACTIVE = 0,
        ANC_BYPASS = 1,
@@ -54,6 +63,8 @@ struct wm2000_priv {
        struct i2c_client *i2c;
        struct regmap *regmap;
 
+       struct regulator_bulk_data supplies[WM2000_NUM_SUPPLIES];
+
        enum wm2000_anc_mode anc_mode;
 
        unsigned int anc_active:1;
@@ -126,6 +137,12 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
 
        dev_dbg(&i2c->dev, "Beginning power up\n");
 
+       ret = regulator_bulk_enable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+               return ret;
+       }
+
        if (!wm2000->mclk_div) {
                dev_dbg(&i2c->dev, "Disabling MCLK divider\n");
                wm2000_write(i2c, WM2000_REG_SYS_CTL2,
@@ -143,12 +160,14 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
        if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT,
                             WM2000_ANC_ENG_IDLE)) {
                dev_err(&i2c->dev, "ANC engine failed to reset\n");
+               regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
                return -ETIMEDOUT;
        }
 
        if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
                             WM2000_STATUS_BOOT_COMPLETE)) {
                dev_err(&i2c->dev, "ANC engine failed to initialise\n");
+               regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
                return -ETIMEDOUT;
        }
 
@@ -163,11 +182,13 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
                              wm2000->anc_download_size);
        if (ret < 0) {
                dev_err(&i2c->dev, "i2c_transfer() failed: %d\n", ret);
+               regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
                return ret;
        }
        if (ret != wm2000->anc_download_size) {
                dev_err(&i2c->dev, "i2c_transfer() failed, %d != %d\n",
                        ret, wm2000->anc_download_size);
+               regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
                return -EIO;
        }
 
@@ -201,6 +222,7 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
        if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
                             WM2000_STATUS_MOUSE_ACTIVE)) {
                dev_err(&i2c->dev, "Timed out waiting for device\n");
+               regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
                return -ETIMEDOUT;
        }
 
@@ -238,6 +260,8 @@ static int wm2000_power_down(struct i2c_client *i2c, int analogue)
                return -ETIMEDOUT;
        }
 
+       regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+
        dev_dbg(&i2c->dev, "powered off\n");
        wm2000->anc_mode = ANC_OFF;
 
@@ -747,7 +771,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
        struct wm2000_platform_data *pdata;
        const char *filename;
        const struct firmware *fw = NULL;
-       int ret;
+       int ret, i;
        int reg;
        u16 id;
 
@@ -760,7 +784,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
 
        dev_set_drvdata(&i2c->dev, wm2000);
 
-       wm2000->regmap = regmap_init_i2c(i2c, &wm2000_regmap);
+       wm2000->regmap = devm_regmap_init_i2c(i2c, &wm2000_regmap);
        if (IS_ERR(wm2000->regmap)) {
                ret = PTR_ERR(wm2000->regmap);
                dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@@ -768,6 +792,22 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
                goto out;
        }
 
+       for (i = 0; i < WM2000_NUM_SUPPLIES; i++)
+               wm2000->supplies[i].supply = wm2000_supplies[i];
+
+       ret = devm_regulator_bulk_get(&i2c->dev, WM2000_NUM_SUPPLIES,
+                                     wm2000->supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to get supplies: %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_bulk_enable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+               return ret;
+       }
+
        /* Verify that this is a WM2000 */
        reg = wm2000_read(i2c, WM2000_REG_ID1);
        id = reg << 8;
@@ -777,7 +817,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
        if (id != 0x2000) {
                dev_err(&i2c->dev, "Device is not a WM2000 - ID %x\n", id);
                ret = -ENODEV;
-               goto out_regmap_exit;
+               goto err_supplies;
        }
 
        reg = wm2000_read(i2c, WM2000_REG_REVISON);
@@ -796,7 +836,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
        ret = request_firmware(&fw, filename, &i2c->dev);
        if (ret != 0) {
                dev_err(&i2c->dev, "Failed to acquire ANC data: %d\n", ret);
-               goto out_regmap_exit;
+               goto err_supplies;
        }
 
        /* Pre-cook the concatenation of the register address onto the image */
@@ -807,7 +847,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
        if (wm2000->anc_download == NULL) {
                dev_err(&i2c->dev, "Out of memory\n");
                ret = -ENOMEM;
-               goto out_regmap_exit;
+               goto err_supplies;
        }
 
        wm2000->anc_download[0] = 0x80;
@@ -822,11 +862,10 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
        wm2000_reset(wm2000);
 
        ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm2000, NULL, 0);
-       if (!ret)
-               goto out;
 
-out_regmap_exit:
-       regmap_exit(wm2000->regmap);
+err_supplies:
+       regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+
 out:
        release_firmware(fw);
        return ret;
@@ -834,10 +873,7 @@ out:
 
 static __devexit int wm2000_i2c_remove(struct i2c_client *i2c)
 {
-       struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
-
        snd_soc_unregister_codec(&i2c->dev);
-       regmap_exit(wm2000->regmap);
 
        return 0;
 }
@@ -858,17 +894,7 @@ static struct i2c_driver wm2000_i2c_driver = {
        .id_table = wm2000_i2c_id,
 };
 
-static int __init wm2000_init(void)
-{
-       return i2c_add_driver(&wm2000_i2c_driver);
-}
-module_init(wm2000_init);
-
-static void __exit wm2000_exit(void)
-{
-       i2c_del_driver(&wm2000_i2c_driver);
-}
-module_exit(wm2000_exit);
+module_i2c_driver(wm2000_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM2000 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>");
index 32682c1b7cdece413693db6f6487ae4df640da09..efa93dbb01915a2112582e2c0a4f939bb96ff643 100644 (file)
@@ -1117,8 +1117,8 @@ SND_SOC_DAPM_SUPPLY("MICBIAS1", WM2200_MIC_BIAS_CTRL_1, WM2200_MICB1_ENA_SHIFT,
                    0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("MICBIAS2", WM2200_MIC_BIAS_CTRL_2, WM2200_MICB2_ENA_SHIFT,
                    0, NULL, 0),
-SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20),
-SND_SOC_DAPM_REGULATOR_SUPPLY("AVDD", 20),
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("AVDD", 20, 0),
 
 SND_SOC_DAPM_INPUT("IN1L"),
 SND_SOC_DAPM_INPUT("IN1R"),
@@ -2270,17 +2270,7 @@ static struct i2c_driver wm2200_i2c_driver = {
        .id_table = wm2200_i2c_id,
 };
 
-static int __init wm2200_modinit(void)
-{
-       return i2c_add_driver(&wm2200_i2c_driver);
-}
-module_init(wm2200_modinit);
-
-static void __exit wm2200_exit(void)
-{
-       i2c_del_driver(&wm2200_i2c_driver);
-}
-module_exit(wm2200_exit);
+module_i2c_driver(wm2200_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM2200 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
index aa62c0e44cb61eb2d68b3d99b69544e1cfc85802..7f567585832eae40c9ff03b33a49f0612427c877 100644 (file)
@@ -848,9 +848,9 @@ SND_SOC_DAPM_SUPPLY("SYSCLK", WM5100_CLOCKING_3, WM5100_SYSCLK_ENA_SHIFT, 0,
 SND_SOC_DAPM_SUPPLY("ASYNCCLK", WM5100_CLOCKING_6, WM5100_ASYNC_CLK_ENA_SHIFT,
                    0, NULL, 0),
 
-SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20),
-SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0),
-SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0, 0),
 
 SND_SOC_DAPM_SUPPLY("CP1", WM5100_HP_CHARGE_PUMP_1, WM5100_CP1_ENA_SHIFT, 0,
                    NULL, 0),
index e33d327396ad4fe7a0cb72ffd6ddc6d6caabf3f2..1722b586bdba65bde94d9d3cb5cc1ca51cd44aee 100644 (file)
@@ -274,18 +274,43 @@ ARIZONA_MIXER_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE);
 
+
+static const char *wm5102_aec_loopback_texts[] = {
+       "HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "EPOUT",
+       "SPKOUTL", "SPKOUTR", "SPKDAT1L", "SPKDAT1R",
+};
+
+static const unsigned int wm5102_aec_loopback_values[] = {
+       0, 1, 2, 3, 4, 6, 7, 8, 9,
+};
+
+static const struct soc_enum wm5102_aec_loopback =
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1,
+                             ARIZONA_AEC_LOOPBACK_SRC_SHIFT,
+                             ARIZONA_AEC_LOOPBACK_SRC_MASK,
+                             ARRAY_SIZE(wm5102_aec_loopback_texts),
+                             wm5102_aec_loopback_texts,
+                             wm5102_aec_loopback_values);
+
+static const struct snd_kcontrol_new wm5102_aec_loopback_mux =
+       SOC_DAPM_VALUE_ENUM("AEC Loopback", wm5102_aec_loopback);
+
 static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = {
 SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
                    0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
                    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
-
-SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0),
-SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0),
-SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20),
-SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0),
-SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0),
-SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0),
+SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
+                   ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
+                   ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0, 0),
 
 SND_SOC_DAPM_SIGGEN("TONE"),
 SND_SOC_DAPM_SIGGEN("NOISE"),
@@ -421,6 +446,9 @@ SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,
 SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
                    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
 
+SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+                      ARIZONA_AEC_LOOPBACK_ENA, 0, &wm5102_aec_loopback_mux),
+
 SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
@@ -516,6 +544,7 @@ SND_SOC_DAPM_OUTPUT("SPKDAT1R"),
        { name, "Noise Generator", "Noise Generator" }, \
        { name, "Tone Generator 1", "Tone Generator 1" }, \
        { name, "Tone Generator 2", "Tone Generator 2" }, \
+       { name, "AEC", "AEC Loopback" }, \
        { name, "IN1L", "IN1L PGA" }, \
        { name, "IN1R", "IN1R PGA" }, \
        { name, "IN2L", "IN2L PGA" }, \
@@ -681,21 +710,30 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
        ARIZONA_MIXER_ROUTES("ASRC2L", "ASRC2L"),
        ARIZONA_MIXER_ROUTES("ASRC2R", "ASRC2R"),
 
+       { "AEC Loopback", "HPOUT1L", "OUT1L" },
+       { "AEC Loopback", "HPOUT1R", "OUT1R" },
        { "HPOUT1L", NULL, "OUT1L" },
        { "HPOUT1R", NULL, "OUT1R" },
 
+       { "AEC Loopback", "HPOUT2L", "OUT2L" },
+       { "AEC Loopback", "HPOUT2R", "OUT2R" },
        { "HPOUT2L", NULL, "OUT2L" },
        { "HPOUT2R", NULL, "OUT2R" },
 
+       { "AEC Loopback", "EPOUT", "OUT3L" },
        { "EPOUTN", NULL, "OUT3L" },
        { "EPOUTP", NULL, "OUT3L" },
 
+       { "AEC Loopback", "SPKOUTL", "OUT4L" },
        { "SPKOUTLN", NULL, "OUT4L" },
        { "SPKOUTLP", NULL, "OUT4L" },
 
+       { "AEC Loopback", "SPKOUTR", "OUT4R" },
        { "SPKOUTRN", NULL, "OUT4R" },
        { "SPKOUTRP", NULL, "OUT4R" },
 
+       { "AEC Loopback", "SPKDAT1L", "OUT5L" },
+       { "AEC Loopback", "SPKDAT1R", "OUT5R" },
        { "SPKDAT1L", NULL, "OUT5L" },
        { "SPKDAT1R", NULL, "OUT5R" },
 };
index 01ebbcc5c6a4a55f31b6448c6ede5e92a1f3f2e8..9211e4192f710b305ca46420e0be64037a0f6967 100644 (file)
@@ -153,6 +153,15 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
 SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
 SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
 
+ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP2R", ARIZONA_DSP2RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP3L", ARIZONA_DSP3LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP3R", ARIZONA_DSP3RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP4L", ARIZONA_DSP4LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP5R", ARIZONA_DSP4RMIX_INPUT_1_SOURCE),
+
 ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE),
 
@@ -163,7 +172,8 @@ ARIZONA_MIXER_CONTROLS("HPOUT1L", ARIZONA_OUT1LMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("HPOUT1R", ARIZONA_OUT1RMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("HPOUT2L", ARIZONA_OUT2LMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("HPOUT2R", ARIZONA_OUT2RMIX_INPUT_1_SOURCE),
-ARIZONA_MIXER_CONTROLS("EPOUT", ARIZONA_OUT3LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT3L", ARIZONA_OUT3LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT3R", ARIZONA_OUT3RMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("SPKOUTL", ARIZONA_OUT4LMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE),
@@ -175,7 +185,7 @@ SOC_SINGLE("HPOUT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_1L,
           ARIZONA_OUT1_OSR_SHIFT, 1, 0),
 SOC_SINGLE("OUT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_2L,
           ARIZONA_OUT2_OSR_SHIFT, 1, 0),
-SOC_SINGLE("EPOUT High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_3L,
+SOC_SINGLE("OUT3 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_3L,
           ARIZONA_OUT3_OSR_SHIFT, 1, 0),
 SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L,
           ARIZONA_OUT4_OSR_SHIFT, 1, 0),
@@ -188,8 +198,8 @@ SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
             ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),
 SOC_DOUBLE_R("OUT2 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_2L,
             ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_MUTE_SHIFT, 1, 1),
-SOC_SINGLE("EPOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_3L,
-          ARIZONA_OUT3L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("OUT3 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_3L,
+            ARIZONA_DAC_DIGITAL_VOLUME_3R, ARIZONA_OUT3L_MUTE_SHIFT, 1, 1),
 SOC_DOUBLE_R("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L,
             ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_MUTE_SHIFT, 1, 1),
 SOC_DOUBLE_R("SPKDAT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_5L,
@@ -203,8 +213,9 @@ SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L,
 SOC_DOUBLE_R_TLV("OUT2 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_2L,
                 ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_VOL_SHIFT,
                 0xbf, 0, digital_tlv),
-SOC_SINGLE_TLV("EPOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_3L,
-              ARIZONA_OUT3L_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("OUT3 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_3L,
+                ARIZONA_DAC_DIGITAL_VOLUME_3R, ARIZONA_OUT3L_VOL_SHIFT,
+                0xbf, 0, digital_tlv),
 SOC_DOUBLE_R_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L,
                 ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_VOL_SHIFT,
                 0xbf, 0, digital_tlv),
@@ -223,8 +234,9 @@ SOC_DOUBLE_R_RANGE_TLV("OUT2 Volume", ARIZONA_OUTPUT_PATH_CONFIG_2L,
                       ARIZONA_OUTPUT_PATH_CONFIG_2R,
                       ARIZONA_OUT2L_PGA_VOL_SHIFT,
                       0x34, 0x40, 0, ana_tlv),
-SOC_SINGLE_RANGE_TLV("EPOUT Volume", ARIZONA_OUTPUT_PATH_CONFIG_3L,
-                    ARIZONA_OUT3L_PGA_VOL_SHIFT, 0x34, 0x40, 0, ana_tlv),
+SOC_DOUBLE_R_RANGE_TLV("OUT3 Volume", ARIZONA_OUTPUT_PATH_CONFIG_3L,
+                      ARIZONA_OUTPUT_PATH_CONFIG_3R,
+                      ARIZONA_OUT3L_PGA_VOL_SHIFT, 0x34, 0x40, 0, ana_tlv),
 
 SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,
           ARIZONA_SPK1R_MUTE_SHIFT, 1, 1),
@@ -272,7 +284,8 @@ ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(OUT2L, ARIZONA_OUT2LMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(OUT2R, ARIZONA_OUT2RMIX_INPUT_1_SOURCE);
-ARIZONA_MIXER_ENUMS(OUT3, ARIZONA_OUT3LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT3L, ARIZONA_OUT3LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT3R, ARIZONA_OUT3RMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(SPKOUTL, ARIZONA_OUT4LMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(SPKOUTR, ARIZONA_OUT4RMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(SPKDAT1L, ARIZONA_OUT5LMIX_INPUT_1_SOURCE);
@@ -300,18 +313,42 @@ ARIZONA_MIXER_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE);
 
+static const char *wm5110_aec_loopback_texts[] = {
+       "HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "HPOUT3L", "HPOUT3R",
+       "SPKOUTL", "SPKOUTR", "SPKDAT1L", "SPKDAT1R", "SPKDAT2L", "SPKDAT2R",
+};
+
+static const unsigned int wm5110_aec_loopback_values[] = {
+       0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+};
+
+static const struct soc_enum wm5110_aec_loopback =
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1,
+                             ARIZONA_AEC_LOOPBACK_SRC_SHIFT,
+                             ARIZONA_AEC_LOOPBACK_SRC_MASK,
+                             ARRAY_SIZE(wm5110_aec_loopback_texts),
+                             wm5110_aec_loopback_texts,
+                             wm5110_aec_loopback_values);
+
+static const struct snd_kcontrol_new wm5110_aec_loopback_mux =
+       SOC_DAPM_VALUE_ENUM("AEC Loopback", wm5110_aec_loopback);
+
 static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = {
 SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
                    0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
                    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
-
-SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0),
-SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0),
-SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20),
-SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0),
-SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0),
-SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0),
+SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
+                   ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
+                   ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0, 0),
 
 SND_SOC_DAPM_SIGGEN("TONE"),
 SND_SOC_DAPM_SIGGEN("NOISE"),
@@ -405,6 +442,9 @@ SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,
 SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,
                 NULL, 0),
 
+SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+                      ARIZONA_AEC_LOOPBACK_ENA, 0, &wm5110_aec_loopback_mux),
+
 SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
                     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
 SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
@@ -474,6 +514,9 @@ SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1,
 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_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_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
@@ -518,7 +561,8 @@ ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUT1L"),
 ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUT1R"),
 ARIZONA_MIXER_WIDGETS(OUT2L, "HPOUT2L"),
 ARIZONA_MIXER_WIDGETS(OUT2R, "HPOUT2R"),
-ARIZONA_MIXER_WIDGETS(OUT3, "EPOUT"),
+ARIZONA_MIXER_WIDGETS(OUT3L, "HPOUT3L"),
+ARIZONA_MIXER_WIDGETS(OUT3R, "HPOUT3R"),
 ARIZONA_MIXER_WIDGETS(SPKOUTL, "SPKOUTL"),
 ARIZONA_MIXER_WIDGETS(SPKOUTR, "SPKOUTR"),
 ARIZONA_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"),
@@ -550,8 +594,8 @@ SND_SOC_DAPM_OUTPUT("HPOUT1L"),
 SND_SOC_DAPM_OUTPUT("HPOUT1R"),
 SND_SOC_DAPM_OUTPUT("HPOUT2L"),
 SND_SOC_DAPM_OUTPUT("HPOUT2R"),
-SND_SOC_DAPM_OUTPUT("EPOUTN"),
-SND_SOC_DAPM_OUTPUT("EPOUTP"),
+SND_SOC_DAPM_OUTPUT("HPOUT3L"),
+SND_SOC_DAPM_OUTPUT("HPOUT3R"),
 SND_SOC_DAPM_OUTPUT("SPKOUTLN"),
 SND_SOC_DAPM_OUTPUT("SPKOUTLP"),
 SND_SOC_DAPM_OUTPUT("SPKOUTRN"),
@@ -566,6 +610,7 @@ SND_SOC_DAPM_OUTPUT("SPKDAT2R"),
        { name, "Noise Generator", "Noise Generator" }, \
        { name, "Tone Generator 1", "Tone Generator 1" }, \
        { name, "Tone Generator 2", "Tone Generator 2" }, \
+       { name, "AEC", "AEC Loopback" }, \
        { name, "IN1L", "IN1L PGA" }, \
        { name, "IN1R", "IN1R PGA" }, \
        { name, "IN2L", "IN2L PGA" }, \
@@ -616,6 +661,7 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
        { "OUT2L", NULL, "CPVDD" },
        { "OUT2R", NULL, "CPVDD" },
        { "OUT3L", NULL, "CPVDD" },
+       { "OUT3R", NULL, "CPVDD" },
 
        { "OUT4L", NULL, "SPKVDDL" },
        { "OUT4R", NULL, "SPKVDDR" },
@@ -697,7 +743,8 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
        ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
        ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"),
        ARIZONA_MIXER_ROUTES("OUT2R", "HPOUT2R"),
-       ARIZONA_MIXER_ROUTES("OUT3L", "EPOUT"),
+       ARIZONA_MIXER_ROUTES("OUT3L", "HPOUT3L"),
+       ARIZONA_MIXER_ROUTES("OUT3R", "HPOUT3R"),
 
        ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUTL"),
        ARIZONA_MIXER_ROUTES("OUT4R", "SPKOUTR"),
@@ -750,8 +797,8 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
        { "HPOUT2L", NULL, "OUT2L" },
        { "HPOUT2R", NULL, "OUT2R" },
 
-       { "EPOUTN", NULL, "OUT3L" },
-       { "EPOUTP", NULL, "OUT3L" },
+       { "HPOUT3L", NULL, "OUT3L" },
+       { "HPOUT3R", NULL, "OUT3L" },
 
        { "SPKOUTLN", NULL, "OUT4L" },
        { "SPKOUTLP", NULL, "OUT4L" },
@@ -869,6 +916,8 @@ static unsigned int wm5110_digital_vu[] = {
        ARIZONA_ADC_DIGITAL_VOLUME_2R,
        ARIZONA_ADC_DIGITAL_VOLUME_3L,
        ARIZONA_ADC_DIGITAL_VOLUME_3R,
+       ARIZONA_ADC_DIGITAL_VOLUME_4L,
+       ARIZONA_ADC_DIGITAL_VOLUME_4R,
 
        ARIZONA_DAC_DIGITAL_VOLUME_1L,
        ARIZONA_DAC_DIGITAL_VOLUME_1R,
@@ -880,6 +929,8 @@ static unsigned int wm5110_digital_vu[] = {
        ARIZONA_DAC_DIGITAL_VOLUME_4R,
        ARIZONA_DAC_DIGITAL_VOLUME_5L,
        ARIZONA_DAC_DIGITAL_VOLUME_5R,
+       ARIZONA_DAC_DIGITAL_VOLUME_6L,
+       ARIZONA_DAC_DIGITAL_VOLUME_6R,
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_wm5110 = {
index 56a049555e2c1de782b82b2fc7e947539076c1a3..c12a54e72e891d071a51e2c4d069c006c6a9ff18 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 #include <linux/of_device.h>
+#include <linux/regmap.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
  * We can't read the WM8510 register space when we are
  * using 2 wire for device control, so we cache them instead.
  */
-static const u16 wm8510_reg[WM8510_CACHEREGNUM] = {
-       0x0000, 0x0000, 0x0000, 0x0000,
-       0x0050, 0x0000, 0x0140, 0x0000,
-       0x0000, 0x0000, 0x0000, 0x00ff,
-       0x0000, 0x0000, 0x0100, 0x00ff,
-       0x0000, 0x0000, 0x012c, 0x002c,
-       0x002c, 0x002c, 0x002c, 0x0000,
-       0x0032, 0x0000, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000, 0x0000,
-       0x0038, 0x000b, 0x0032, 0x0000,
-       0x0008, 0x000c, 0x0093, 0x00e9,
-       0x0000, 0x0000, 0x0000, 0x0000,
-       0x0003, 0x0010, 0x0000, 0x0000,
-       0x0000, 0x0002, 0x0001, 0x0000,
-       0x0000, 0x0000, 0x0039, 0x0000,
-       0x0001,
+static const struct reg_default wm8510_reg_defaults[] = {
+       {  1, 0x0000 },
+       {  2, 0x0000 },
+       {  3, 0x0000 },
+       {  4, 0x0050 },
+       {  5, 0x0000 },
+       {  6, 0x0140 },
+       {  7, 0x0000 },
+       {  8, 0x0000 },
+       {  9, 0x0000 },
+       { 10, 0x0000 },
+       { 11, 0x00ff },
+       { 12, 0x0000 },
+       { 13, 0x0000 },
+       { 14, 0x0100 },
+       { 15, 0x00ff },
+       { 16, 0x0000 },
+       { 17, 0x0000 },
+       { 18, 0x012c },
+       { 19, 0x002c },
+       { 20, 0x002c },
+       { 21, 0x002c },
+       { 22, 0x002c },
+       { 23, 0x0000 },
+       { 24, 0x0032 },
+       { 25, 0x0000 },
+       { 26, 0x0000 },
+       { 27, 0x0000 },
+       { 28, 0x0000 },
+       { 29, 0x0000 },
+       { 30, 0x0000 },
+       { 31, 0x0000 },
+       { 32, 0x0038 },
+       { 33, 0x000b },
+       { 34, 0x0032 },
+       { 35, 0x0000 },
+       { 36, 0x0008 },
+       { 37, 0x000c },
+       { 38, 0x0093 },
+       { 39, 0x00e9 },
+       { 40, 0x0000 },
+       { 41, 0x0000 },
+       { 42, 0x0000 },
+       { 43, 0x0000 },
+       { 44, 0x0003 },
+       { 45, 0x0010 },
+       { 46, 0x0000 },
+       { 47, 0x0000 },
+       { 48, 0x0000 },
+       { 49, 0x0002 },
+       { 50, 0x0001 },
+       { 51, 0x0000 },
+       { 52, 0x0000 },
+       { 53, 0x0000 },
+       { 54, 0x0039 },
+       { 55, 0x0000 },
+       { 56, 0x0001 },
 };
 
+static bool wm8510_volatile(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case WM8510_RESET:
+               return true;
+       default:
+               return false;
+       }
+}
+
 #define WM8510_POWER1_BIASEN  0x08
 #define WM8510_POWER1_BUFIOEN 0x10
 
@@ -58,7 +110,7 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = {
 
 /* codec private data */
 struct wm8510_priv {
-       enum snd_soc_control_type control_type;
+       struct regmap *regmap;
 };
 
 static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" };
@@ -454,6 +506,7 @@ static int wm8510_mute(struct snd_soc_dai *dai, int mute)
 static int wm8510_set_bias_level(struct snd_soc_codec *codec,
        enum snd_soc_bias_level level)
 {
+       struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec);
        u16 power1 = snd_soc_read(codec, WM8510_POWER1) & ~0x3;
 
        switch (level) {
@@ -467,7 +520,7 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec,
                power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;
 
                if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
-                       snd_soc_cache_sync(codec);
+                       regcache_sync(wm8510->regmap);
 
                        /* Initial cap charge at VMID 5k */
                        snd_soc_write(codec, WM8510_POWER1, power1 | 0x3);
@@ -536,10 +589,9 @@ static int wm8510_resume(struct snd_soc_codec *codec)
 
 static int wm8510_probe(struct snd_soc_codec *codec)
 {
-       struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9,  wm8510->control_type);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
        if (ret < 0) {
                printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n", ret);
                return ret;
@@ -569,9 +621,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8510 = {
        .suspend =      wm8510_suspend,
        .resume =       wm8510_resume,
        .set_bias_level = wm8510_set_bias_level,
-       .reg_cache_size = ARRAY_SIZE(wm8510_reg),
-       .reg_word_size = sizeof(u16),
-       .reg_cache_default =wm8510_reg,
 
        .controls = wm8510_snd_controls,
        .num_controls = ARRAY_SIZE(wm8510_snd_controls),
@@ -586,23 +635,38 @@ static const struct of_device_id wm8510_of_match[] = {
        { },
 };
 
+static const struct regmap_config wm8510_regmap = {
+       .reg_bits = 7,
+       .val_bits = 9,
+       .max_register = WM8510_MONOMIX,
+
+       .reg_defaults = wm8510_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wm8510_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+
+       .volatile_reg = wm8510_volatile,
+};
+
 #if defined(CONFIG_SPI_MASTER)
 static int __devinit wm8510_spi_probe(struct spi_device *spi)
 {
        struct wm8510_priv *wm8510;
        int ret;
 
-       wm8510 = kzalloc(sizeof(struct wm8510_priv), GFP_KERNEL);
+       wm8510 = devm_kzalloc(&spi->dev, sizeof(struct wm8510_priv),
+                             GFP_KERNEL);
        if (wm8510 == NULL)
                return -ENOMEM;
 
-       wm8510->control_type = SND_SOC_SPI;
+       wm8510->regmap = devm_regmap_init_spi(spi, &wm8510_regmap);
+       if (IS_ERR(wm8510->regmap))
+               return PTR_ERR(wm8510->regmap);
+
        spi_set_drvdata(spi, wm8510);
 
        ret = snd_soc_register_codec(&spi->dev,
                        &soc_codec_dev_wm8510, &wm8510_dai, 1);
-       if (ret < 0)
-               kfree(wm8510);
+
        return ret;
 }
 
@@ -630,17 +694,20 @@ static __devinit int wm8510_i2c_probe(struct i2c_client *i2c,
        struct wm8510_priv *wm8510;
        int ret;
 
-       wm8510 = kzalloc(sizeof(struct wm8510_priv), GFP_KERNEL);
+       wm8510 = devm_kzalloc(&i2c->dev, sizeof(struct wm8510_priv),
+                             GFP_KERNEL);
        if (wm8510 == NULL)
                return -ENOMEM;
 
+       wm8510->regmap = devm_regmap_init_i2c(i2c, &wm8510_regmap);
+       if (IS_ERR(wm8510->regmap))
+               return PTR_ERR(wm8510->regmap);
+
        i2c_set_clientdata(i2c, wm8510);
-       wm8510->control_type = SND_SOC_I2C;
 
        ret =  snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_wm8510, &wm8510_dai, 1);
-       if (ret < 0)
-               kfree(wm8510);
+
        return ret;
 }
 
index 1c3ffb290cdcdb00651ef5c31db835394ae35421..8d5c276735012361cebb34f24dd123f0564354a3 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/of_device.h>
@@ -39,41 +40,34 @@ static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = {
 
 /* codec private data */
 struct wm8523_priv {
-       enum snd_soc_control_type control_type;
+       struct regmap *regmap;
        struct regulator_bulk_data supplies[WM8523_NUM_SUPPLIES];
        unsigned int sysclk;
        unsigned int rate_constraint_list[WM8523_NUM_RATES];
        struct snd_pcm_hw_constraint_list rate_constraint;
 };
 
-static const u16 wm8523_reg[WM8523_REGISTER_COUNT] = {
-       0x8523,     /* R0 - DEVICE_ID */
-       0x0001,     /* R1 - REVISION */
-       0x0000,     /* R2 - PSCTRL1 */
-       0x1812,     /* R3 - AIF_CTRL1 */
-       0x0000,     /* R4 - AIF_CTRL2 */
-       0x0001,     /* R5 - DAC_CTRL3 */
-       0x0190,     /* R6 - DAC_GAINL */
-       0x0190,     /* R7 - DAC_GAINR */
-       0x0000,     /* R8 - ZERO_DETECT */
+static const struct reg_default wm8523_reg_defaults[] = {
+       { 2, 0x0000 },     /* R2 - PSCTRL1 */
+       { 3, 0x1812 },     /* R3 - AIF_CTRL1 */
+       { 4, 0x0000 },     /* R4 - AIF_CTRL2 */
+       { 5, 0x0001 },     /* R5 - DAC_CTRL3 */
+       { 6, 0x0190 },     /* R6 - DAC_GAINL */
+       { 7, 0x0190 },     /* R7 - DAC_GAINR */
+       { 8, 0x0000 },     /* R8 - ZERO_DETECT */
 };
 
-static int wm8523_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
+static bool wm8523_volatile_register(struct device *dev, unsigned int reg)
 {
        switch (reg) {
        case WM8523_DEVICE_ID:
        case WM8523_REVISION:
-               return 1;
+               return true;
        default:
-               return 0;
+               return false;
        }
 }
 
-static int wm8523_reset(struct snd_soc_codec *codec)
-{
-       return snd_soc_write(codec, WM8523_DEVICE_ID, 0);
-}
-
 static const DECLARE_TLV_DB_SCALE(dac_tlv, -10000, 25, 0);
 
 static const char *wm8523_zd_count_text[] = {
@@ -301,8 +295,7 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
        struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
-       u16 *reg_cache = codec->reg_cache;
-       int ret, i;
+       int ret;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
@@ -325,16 +318,13 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec,
                                return ret;
                        }
 
+                       /* Sync back default/cached values */
+                       regcache_sync(wm8523->regmap);
+
                        /* Initial power up */
                        snd_soc_update_bits(codec, WM8523_PSCTRL1,
                                            WM8523_SYS_ENA_MASK, 1);
 
-                       /* Sync back default/cached values */
-                       for (i = WM8523_AIF_CTRL1;
-                            i < WM8523_MAX_REGISTER; i++)
-                               snd_soc_write(codec, i, reg_cache[i]);
-
-
                        msleep(100);
                }
 
@@ -402,60 +392,18 @@ static int wm8523_resume(struct snd_soc_codec *codec)
 static int wm8523_probe(struct snd_soc_codec *codec)
 {
        struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
-       int ret, i;
+       int ret;
 
        wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0];
        wm8523->rate_constraint.count =
                ARRAY_SIZE(wm8523->rate_constraint_list);
 
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8523->control_type);
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
        }
 
-       for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++)
-               wm8523->supplies[i].supply = wm8523_supply_names[i];
-
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8523->supplies),
-                                wm8523->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               return ret;
-       }
-
-       ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies),
-                                   wm8523->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
-               goto err_get;
-       }
-
-       ret = snd_soc_read(codec, WM8523_DEVICE_ID);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to read ID register\n");
-               goto err_enable;
-       }
-       if (ret != wm8523_reg[WM8523_DEVICE_ID]) {
-               dev_err(codec->dev, "Device is not a WM8523, ID is %x\n", ret);
-               ret = -EINVAL;
-               goto err_enable;
-       }
-
-       ret = snd_soc_read(codec, WM8523_REVISION);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to read revision register\n");
-               goto err_enable;
-       }
-       dev_info(codec->dev, "revision %c\n",
-                (ret & WM8523_CHIP_REV_MASK) + 'A');
-
-       ret = wm8523_reset(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset\n");
-               goto err_enable;
-       }
-
        /* Change some default settings - latch VU and enable ZC */
        snd_soc_update_bits(codec, WM8523_DAC_GAINR,
                            WM8523_DACR_VU, WM8523_DACR_VU);
@@ -463,25 +411,12 @@ static int wm8523_probe(struct snd_soc_codec *codec)
 
        wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       /* Bias level configuration will have done an extra enable */
-       regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
-
        return 0;
-
-err_enable:
-       regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
-err_get:
-       regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
-
-       return ret;
 }
 
 static int wm8523_remove(struct snd_soc_codec *codec)
 {
-       struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
-
        wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
        return 0;
 }
 
@@ -491,10 +426,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8523 = {
        .suspend =      wm8523_suspend,
        .resume =       wm8523_resume,
        .set_bias_level = wm8523_set_bias_level,
-       .reg_cache_size = WM8523_REGISTER_COUNT,
-       .reg_word_size = sizeof(u16),
-       .reg_cache_default = wm8523_reg,
-       .volatile_register = wm8523_volatile_register,
 
        .controls = wm8523_controls,
        .num_controls = ARRAY_SIZE(wm8523_controls),
@@ -509,32 +440,97 @@ static const struct of_device_id wm8523_of_match[] = {
        { },
 };
 
+static const struct regmap_config wm8523_regmap = {
+       .reg_bits = 8,
+       .val_bits = 16,
+       .max_register = WM8523_ZERO_DETECT,
+
+       .reg_defaults = wm8523_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wm8523_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+
+       .volatile_reg = wm8523_volatile_register,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8523_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8523_priv *wm8523;
-       int ret;
+       unsigned int val;
+       int ret, i;
 
-       wm8523 = kzalloc(sizeof(struct wm8523_priv), GFP_KERNEL);
+       wm8523 = devm_kzalloc(&i2c->dev, sizeof(struct wm8523_priv),
+                             GFP_KERNEL);
        if (wm8523 == NULL)
                return -ENOMEM;
 
+       wm8523->regmap = devm_regmap_init_i2c(i2c, &wm8523_regmap);
+       if (IS_ERR(wm8523->regmap)) {
+               ret = PTR_ERR(wm8523->regmap);
+               dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret);
+               return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++)
+               wm8523->supplies[i].supply = wm8523_supply_names[i];
+
+       ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8523->supplies),
+                                     wm8523->supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies),
+                                   wm8523->supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_read(wm8523->regmap, WM8523_DEVICE_ID, &val);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to read ID register\n");
+               goto err_enable;
+       }
+       if (val != 0x8523) {
+               dev_err(&i2c->dev, "Device is not a WM8523, ID is %x\n", ret);
+               ret = -EINVAL;
+               goto err_enable;
+       }
+
+       ret = regmap_read(wm8523->regmap, WM8523_REVISION, &val);
+       if (ret < 0) {
+               dev_err(&i2c->dev, "Failed to read revision register\n");
+               goto err_enable;
+       }
+       dev_info(&i2c->dev, "revision %c\n",
+                (val & WM8523_CHIP_REV_MASK) + 'A');
+
+       ret = regmap_write(wm8523->regmap, WM8523_DEVICE_ID, 0x8523);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to reset device: %d\n", ret);
+               goto err_enable;
+       }
+
+       regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
+
        i2c_set_clientdata(i2c, wm8523);
-       wm8523->control_type = SND_SOC_I2C;
 
        ret =  snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_wm8523, &wm8523_dai, 1);
-       if (ret < 0)
-               kfree(wm8523);
+
        return ret;
 
+err_enable:
+       regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
+       return ret;
 }
 
 static __devexit int wm8523_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
index 7c68226376e415a5e058bb10153531b68d49c990..5e9c40fa7eb2ae7587527ec79774cca0a2ca195a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * wm8580.c  --  WM8580 ALSA Soc Audio driver
  *
- * Copyright 2008-11 Wolfson Microelectronics PLC.
+ * Copyright 2008-12 Wolfson Microelectronics PLC.
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -23,6 +23,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/of_device.h>
  * We can't read the WM8580 register space when we
  * are using 2 wire for device control, so we cache them instead.
  */
-static const u16 wm8580_reg[] = {
-       0x0121, 0x017e, 0x007d, 0x0014, /*R3*/
-       0x0121, 0x017e, 0x007d, 0x0194, /*R7*/
-       0x0010, 0x0002, 0x0002, 0x00c2, /*R11*/
-       0x0182, 0x0082, 0x000a, 0x0024, /*R15*/
-       0x0009, 0x0000, 0x00ff, 0x0000, /*R19*/
-       0x00ff, 0x00ff, 0x00ff, 0x00ff, /*R23*/
-       0x00ff, 0x00ff, 0x00ff, 0x00ff, /*R27*/
-       0x01f0, 0x0040, 0x0000, 0x0000, /*R31(0x1F)*/
-       0x0000, 0x0000, 0x0031, 0x000b, /*R35*/
-       0x0039, 0x0000, 0x0010, 0x0032, /*R39*/
-       0x0054, 0x0076, 0x0098, 0x0000, /*R43(0x2B)*/
-       0x0000, 0x0000, 0x0000, 0x0000, /*R47*/
-       0x0000, 0x0000, 0x005e, 0x003e, /*R51(0x33)*/
-       0x0000, 0x0000 /*R53*/
+static const struct reg_default wm8580_reg_defaults[] = {
+       {  0, 0x0121 },
+       {  1, 0x017e },
+       {  2, 0x007d },
+       {  3, 0x0014 },
+       {  4, 0x0121 },
+       {  5, 0x017e },
+       {  6, 0x007d },
+       {  7, 0x0194 },
+       {  8, 0x0010 },
+       {  9, 0x0002 },
+       { 10, 0x0002 },
+       { 11, 0x00c2 },
+       { 12, 0x0182 },
+       { 13, 0x0082 },
+       { 14, 0x000a },
+       { 15, 0x0024 },
+       { 16, 0x0009 },
+       { 17, 0x0000 },
+       { 18, 0x00ff },
+       { 19, 0x0000 },
+       { 20, 0x00ff },
+       { 21, 0x00ff },
+       { 22, 0x00ff },
+       { 23, 0x00ff },
+       { 24, 0x00ff },
+       { 25, 0x00ff },
+       { 26, 0x00ff },
+       { 27, 0x00ff },
+       { 28, 0x01f0 },
+       { 29, 0x0040 },
+       { 30, 0x0000 },
+       { 31, 0x0000 },
+       { 32, 0x0000 },
+       { 33, 0x0000 },
+       { 34, 0x0031 },
+       { 35, 0x000b },
+       { 36, 0x0039 },
+       { 37, 0x0000 },
+       { 38, 0x0010 },
+       { 39, 0x0032 },
+       { 40, 0x0054 },
+       { 41, 0x0076 },
+       { 42, 0x0098 },
+       { 43, 0x0000 },
+       { 44, 0x0000 },
+       { 45, 0x0000 },
+       { 46, 0x0000 },
+       { 47, 0x0000 },
+       { 48, 0x0000 },
+       { 49, 0x0000 },
+       { 50, 0x005e },
+       { 51, 0x003e },
+       { 52, 0x0000 },
 };
 
+static bool wm8580_volatile(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case WM8580_RESET:
+               return true;
+       default:
+               return false;
+       }
+}
+
 struct pll_state {
        unsigned int in;
        unsigned int out;
@@ -188,7 +238,7 @@ static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = {
 
 /* codec private data */
 struct wm8580_priv {
-       enum snd_soc_control_type control_type;
+       struct regmap *regmap;
        struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES];
        struct pll_state a;
        struct pll_state b;
@@ -203,14 +253,16 @@ static int wm8580_out_vu(struct snd_kcontrol *kcontrol,
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       u16 *reg_cache = codec->reg_cache;
+       struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
        unsigned int reg = mc->reg;
        unsigned int reg2 = mc->rreg;
        int ret;
 
-       /* Clear the register cache so we write without VU set */
-       reg_cache[reg] = 0;
-       reg_cache[reg2] = 0;
+       /* Clear the register cache VU so we write without VU set */
+       regcache_cache_only(wm8580->regmap, true);
+       regmap_update_bits(wm8580->regmap, reg, 0x100, 0x000);
+       regmap_update_bits(wm8580->regmap, reg2, 0x100, 0x000);
+       regcache_cache_only(wm8580->regmap, false);
 
        ret = snd_soc_put_volsw(kcontrol, ucontrol);
        if (ret < 0)
@@ -815,24 +867,14 @@ static struct snd_soc_dai_driver wm8580_dai[] = {
 static int wm8580_probe(struct snd_soc_codec *codec)
 {
        struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
-       int ret = 0,i;
+       int ret = 0;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8580->control_type);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
        }
 
-       for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++)
-               wm8580->supplies[i].supply = wm8580_supply_names[i];
-
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8580->supplies),
-                                wm8580->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               return ret;
-       }
-
        ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies),
                                    wm8580->supplies);
        if (ret != 0) {
@@ -854,7 +896,6 @@ static int wm8580_probe(struct snd_soc_codec *codec)
 err_regulator_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
 err_regulator_get:
-       regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
        return ret;
 }
 
@@ -866,7 +907,6 @@ static int wm8580_remove(struct snd_soc_codec *codec)
        wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
-       regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
 
        return 0;
 }
@@ -875,9 +915,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8580 = {
        .probe =        wm8580_probe,
        .remove =       wm8580_remove,
        .set_bias_level = wm8580_set_bias_level,
-       .reg_cache_size = ARRAY_SIZE(wm8580_reg),
-       .reg_word_size = sizeof(u16),
-       .reg_cache_default = wm8580_reg,
 
        .controls = wm8580_snd_controls,
        .num_controls = ARRAY_SIZE(wm8580_snd_controls),
@@ -892,31 +929,55 @@ static const struct of_device_id wm8580_of_match[] = {
        { },
 };
 
+static const struct regmap_config wm8580_regmap = {
+       .reg_bits = 7,
+       .val_bits = 9,
+       .max_register = WM8580_MAX_REGISTER,
+
+       .reg_defaults = wm8580_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wm8580_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+
+       .volatile_reg = wm8580_volatile,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static int wm8580_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct wm8580_priv *wm8580;
-       int ret;
+       int ret, i;
 
-       wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL);
+       wm8580 = devm_kzalloc(&i2c->dev, sizeof(struct wm8580_priv),
+                             GFP_KERNEL);
        if (wm8580 == NULL)
                return -ENOMEM;
 
+       wm8580->regmap = devm_regmap_init_i2c(i2c, &wm8580_regmap);
+       if (IS_ERR(wm8580->regmap))
+               return PTR_ERR(wm8580->regmap);
+
+       for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++)
+               wm8580->supplies[i].supply = wm8580_supply_names[i];
+
+       ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8580->supplies),
+                                     wm8580->supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
        i2c_set_clientdata(i2c, wm8580);
-       wm8580->control_type = SND_SOC_I2C;
 
        ret =  snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_wm8580, wm8580_dai, ARRAY_SIZE(wm8580_dai));
-       if (ret < 0)
-               kfree(wm8580);
+
        return ret;
 }
 
 static int wm8580_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
index 0b76d1dca5eade12cfd3bfd640a665e1f0626b97..8b8bb70f1eb959e5ef3a762e88ffce716f75107d 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 #include <linux/of_device.h>
@@ -32,7 +33,7 @@
 
 /* codec private data */
 struct wm8711_priv {
-       enum snd_soc_control_type bus_type;
+       struct regmap *regmap;
        unsigned int sysclk;
 };
 
@@ -42,11 +43,21 @@ struct wm8711_priv {
  * using 2 wire for device control, so we cache them instead.
  * There is no point in caching the reset register
  */
-static const u16 wm8711_reg[WM8711_CACHEREGNUM] = {
-       0x0079, 0x0079, 0x000a, 0x0008,
-       0x009f, 0x000a, 0x0000, 0x0000
+static const struct reg_default wm8711_reg_defaults[] = {
+       { 0, 0x0079 }, { 1, 0x0079 }, { 2, 0x000a }, { 3, 0x0008 },
+       { 4, 0x009f }, { 5, 0x000a }, { 6, 0x0000 }, { 7, 0x0000 },
 };
 
+static bool wm8711_volatile(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case WM8711_RESET:
+               return true;
+       default:
+               return false;
+       }
+}
+
 #define wm8711_reset(c)        snd_soc_write(c, WM8711_RESET, 0)
 
 static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
@@ -289,6 +300,7 @@ static int wm8711_set_dai_fmt(struct snd_soc_dai *codec_dai,
 static int wm8711_set_bias_level(struct snd_soc_codec *codec,
        enum snd_soc_bias_level level)
 {
+       struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
        u16 reg = snd_soc_read(codec, WM8711_PWR) & 0xff7f;
 
        switch (level) {
@@ -299,7 +311,7 @@ static int wm8711_set_bias_level(struct snd_soc_codec *codec,
                break;
        case SND_SOC_BIAS_STANDBY:
                if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
-                       snd_soc_cache_sync(codec);
+                       regcache_sync(wm8711->regmap);
 
                snd_soc_write(codec, WM8711_PWR, reg | 0x0040);
                break;
@@ -353,10 +365,9 @@ static int wm8711_resume(struct snd_soc_codec *codec)
 
 static int wm8711_probe(struct snd_soc_codec *codec)
 {
-       struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8711->bus_type);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
@@ -391,9 +402,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8711 = {
        .suspend =      wm8711_suspend,
        .resume =       wm8711_resume,
        .set_bias_level = wm8711_set_bias_level,
-       .reg_cache_size = ARRAY_SIZE(wm8711_reg),
-       .reg_word_size = sizeof(u16),
-       .reg_cache_default = wm8711_reg,
        .controls = wm8711_snd_controls,
        .num_controls = ARRAY_SIZE(wm8711_snd_controls),
        .dapm_widgets = wm8711_dapm_widgets,
@@ -408,30 +416,45 @@ static const struct of_device_id wm8711_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, wm8711_of_match);
 
+static const struct regmap_config wm8711_regmap = {
+       .reg_bits = 7,
+       .val_bits = 9,
+       .max_register = WM8711_RESET,
+
+       .reg_defaults = wm8711_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wm8711_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+
+       .volatile_reg = wm8711_volatile,
+};
+
 #if defined(CONFIG_SPI_MASTER)
 static int __devinit wm8711_spi_probe(struct spi_device *spi)
 {
        struct wm8711_priv *wm8711;
        int ret;
 
-       wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL);
+       wm8711 = devm_kzalloc(&spi->dev, sizeof(struct wm8711_priv),
+                             GFP_KERNEL);
        if (wm8711 == NULL)
                return -ENOMEM;
 
+       wm8711->regmap = devm_regmap_init_spi(spi, &wm8711_regmap);
+       if (IS_ERR(wm8711->regmap))
+               return PTR_ERR(wm8711->regmap);
+
        spi_set_drvdata(spi, wm8711);
-       wm8711->bus_type = SND_SOC_SPI;
 
        ret = snd_soc_register_codec(&spi->dev,
                        &soc_codec_dev_wm8711, &wm8711_dai, 1);
-       if (ret < 0)
-               kfree(wm8711);
+
        return ret;
 }
 
 static int __devexit wm8711_spi_remove(struct spi_device *spi)
 {
        snd_soc_unregister_codec(&spi->dev);
-       kfree(spi_get_drvdata(spi));
+
        return 0;
 }
 
@@ -453,24 +476,26 @@ static __devinit int wm8711_i2c_probe(struct i2c_client *client,
        struct wm8711_priv *wm8711;
        int ret;
 
-       wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL);
+       wm8711 = devm_kzalloc(&client->dev, sizeof(struct wm8711_priv),
+                             GFP_KERNEL);
        if (wm8711 == NULL)
                return -ENOMEM;
 
+       wm8711->regmap = devm_regmap_init_i2c(client, &wm8711_regmap);
+       if (IS_ERR(wm8711->regmap))
+               return PTR_ERR(wm8711->regmap);
+
        i2c_set_clientdata(client, wm8711);
-       wm8711->bus_type = SND_SOC_I2C;
 
        ret =  snd_soc_register_codec(&client->dev,
                        &soc_codec_dev_wm8711, &wm8711_dai, 1);
-       if (ret < 0)
-               kfree(wm8711);
+
        return ret;
 }
 
 static __devexit int wm8711_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
index 1467f97dce21efa668b005a531faf3a64bfd78c2..00a12a0c3919b12e1cf325a84d82bec1031e9b04 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 #include <linux/of_device.h>
  * the volume update bits, mute the output and enable infinite zero
  * detect.
  */
-static const u16 wm8728_reg_defaults[] = {
-       0x1ff,
-       0x1ff,
-       0x001,
-       0x100,
+static const struct reg_default wm8728_reg_defaults[] = {
+       { 0, 0x1ff },
+       { 1, 0x1ff },
+       { 2, 0x001 },
+       { 3, 0x100 },
 };
 
 /* codec private data */
 struct wm8728_priv {
-       enum snd_soc_control_type control_type;
+       struct regmap *regmap;
 };
 
 static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1);
@@ -162,8 +163,8 @@ static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai,
 static int wm8728_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
+       struct wm8728_priv *wm8728 = snd_soc_codec_get_drvdata(codec);
        u16 reg;
-       int i;
 
        switch (level) {
        case SND_SOC_BIAS_ON:
@@ -175,9 +176,7 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec,
                        snd_soc_write(codec, WM8728_DACCTL, reg & ~0x4);
 
                        /* ..then sync in the register cache. */
-                       for (i = 0; i < ARRAY_SIZE(wm8728_reg_defaults); i++)
-                               snd_soc_write(codec, i,
-                                            snd_soc_read(codec, i));
+                       regcache_sync(wm8728->regmap);
                }
                break;
 
@@ -229,10 +228,9 @@ static int wm8728_resume(struct snd_soc_codec *codec)
 
 static int wm8728_probe(struct snd_soc_codec *codec)
 {
-       struct wm8728_priv *wm8728 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8728->control_type);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
        if (ret < 0) {
                printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n",
                       ret);
@@ -257,9 +255,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8728 = {
        .suspend =      wm8728_suspend,
        .resume =       wm8728_resume,
        .set_bias_level = wm8728_set_bias_level,
-       .reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults),
-       .reg_word_size = sizeof(u16),
-       .reg_cache_default = wm8728_reg_defaults,
        .controls = wm8728_snd_controls,
        .num_controls = ARRAY_SIZE(wm8728_snd_controls),
        .dapm_widgets = wm8728_dapm_widgets,
@@ -274,30 +269,43 @@ static const struct of_device_id wm8728_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, wm8728_of_match);
 
+static const struct regmap_config wm8728_regmap = {
+       .reg_bits = 7,
+       .val_bits = 9,
+       .max_register = WM8728_IFCTL,
+
+       .reg_defaults = wm8728_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wm8728_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+};
+
 #if defined(CONFIG_SPI_MASTER)
 static int __devinit wm8728_spi_probe(struct spi_device *spi)
 {
        struct wm8728_priv *wm8728;
        int ret;
 
-       wm8728 = kzalloc(sizeof(struct wm8728_priv), GFP_KERNEL);
+       wm8728 = devm_kzalloc(&spi->dev, sizeof(struct wm8728_priv),
+                             GFP_KERNEL);
        if (wm8728 == NULL)
                return -ENOMEM;
 
-       wm8728->control_type = SND_SOC_SPI;
+       wm8728->regmap = devm_regmap_init_spi(spi, &wm8728_regmap);
+       if (IS_ERR(wm8728->regmap))
+               return PTR_ERR(wm8728->regmap);
+
        spi_set_drvdata(spi, wm8728);
 
        ret = snd_soc_register_codec(&spi->dev,
                        &soc_codec_dev_wm8728, &wm8728_dai, 1);
-       if (ret < 0)
-               kfree(wm8728);
+
        return ret;
 }
 
 static int __devexit wm8728_spi_remove(struct spi_device *spi)
 {
        snd_soc_unregister_codec(&spi->dev);
-       kfree(spi_get_drvdata(spi));
+
        return 0;
 }
 
@@ -319,24 +327,26 @@ static __devinit int wm8728_i2c_probe(struct i2c_client *i2c,
        struct wm8728_priv *wm8728;
        int ret;
 
-       wm8728 = kzalloc(sizeof(struct wm8728_priv), GFP_KERNEL);
+       wm8728 = devm_kzalloc(&i2c->dev, sizeof(struct wm8728_priv),
+                             GFP_KERNEL);
        if (wm8728 == NULL)
                return -ENOMEM;
 
+       wm8728->regmap = devm_regmap_init_i2c(i2c, &wm8728_regmap);
+       if (IS_ERR(wm8728->regmap))
+               return PTR_ERR(wm8728->regmap);
+
        i2c_set_clientdata(i2c, wm8728);
-       wm8728->control_type = SND_SOC_I2C;
 
        ret =  snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_wm8728, &wm8728_dai, 1);
-       if (ret < 0)
-               kfree(wm8728);
+
        return ret;
 }
 
 static __devexit int wm8728_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
index d0520124616d1831d2d4cf419a9d11ecbd23c40a..5c9634f4c1f054c00d7e69f3d1e1c67041be6b99 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
@@ -40,29 +41,39 @@ static const char *wm8737_supply_names[WM8737_NUM_SUPPLIES] = {
 
 /* codec private data */
 struct wm8737_priv {
-       enum snd_soc_control_type control_type;
+       struct regmap *regmap;
        struct regulator_bulk_data supplies[WM8737_NUM_SUPPLIES];
        unsigned int mclk;
 };
 
-static const u16 wm8737_reg[WM8737_REGISTER_COUNT] = {
-       0x00C3,     /* R0  - Left PGA volume */
-       0x00C3,     /* R1  - Right PGA volume */
-       0x0007,     /* R2  - AUDIO path L */
-       0x0007,     /* R3  - AUDIO path R */
-       0x0000,     /* R4  - 3D Enhance */
-       0x0000,     /* R5  - ADC Control */
-       0x0000,     /* R6  - Power Management */
-       0x000A,     /* R7  - Audio Format */
-       0x0000,     /* R8  - Clocking */
-       0x000F,     /* R9  - MIC Preamp Control */
-       0x0003,     /* R10 - Misc Bias Control */
-       0x0000,     /* R11 - Noise Gate */
-       0x007C,     /* R12 - ALC1 */
-       0x0000,     /* R13 - ALC2 */
-       0x0032,     /* R14 - ALC3 */
+static const struct reg_default wm8737_reg_defaults[] = {
+       {  0, 0x00C3 },     /* R0  - Left PGA volume */
+       {  1, 0x00C3 },     /* R1  - Right PGA volume */
+       {  2, 0x0007 },     /* R2  - AUDIO path L */
+       {  3, 0x0007 },     /* R3  - AUDIO path R */
+       {  4, 0x0000 },     /* R4  - 3D Enhance */
+       {  5, 0x0000 },     /* R5  - ADC Control */
+       {  6, 0x0000 },     /* R6  - Power Management */
+       {  7, 0x000A },     /* R7  - Audio Format */
+       {  8, 0x0000 },     /* R8  - Clocking */
+       {  9, 0x000F },     /* R9  - MIC Preamp Control */
+       { 10, 0x0003 },     /* R10 - Misc Bias Control */
+       { 11, 0x0000 },     /* R11 - Noise Gate */
+       { 12, 0x007C },     /* R12 - ALC1 */
+       { 13, 0x0000 },     /* R13 - ALC2 */
+       { 14, 0x0032 },     /* R14 - ALC3 */
 };
 
+static bool wm8737_volatile(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case WM8737_RESET:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static int wm8737_reset(struct snd_soc_codec *codec)
 {
        return snd_soc_write(codec, WM8737_RESET, 0);
@@ -479,7 +490,7 @@ static int wm8737_set_bias_level(struct snd_soc_codec *codec,
                                return ret;
                        }
 
-                       snd_soc_cache_sync(codec);
+                       regcache_sync(wm8737->regmap);
 
                        /* Fast VMID ramp at 2*2.5k */
                        snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL,
@@ -557,24 +568,14 @@ static int wm8737_resume(struct snd_soc_codec *codec)
 static int wm8737_probe(struct snd_soc_codec *codec)
 {
        struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
-       int ret, i;
+       int ret;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8737->control_type);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
        }
 
-       for (i = 0; i < ARRAY_SIZE(wm8737->supplies); i++)
-               wm8737->supplies[i].supply = wm8737_supply_names[i];
-
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8737->supplies),
-                                wm8737->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               return ret;
-       }
-
        ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies),
                                    wm8737->supplies);
        if (ret != 0) {
@@ -607,17 +608,12 @@ static int wm8737_probe(struct snd_soc_codec *codec)
 err_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
 err_get:
-       regulator_bulk_free(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
-
        return ret;
 }
 
 static int wm8737_remove(struct snd_soc_codec *codec)
 {
-       struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
-
        wm8737_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       regulator_bulk_free(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
        return 0;
 }
 
@@ -627,10 +623,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8737 = {
        .suspend        = wm8737_suspend,
        .resume         = wm8737_resume,
        .set_bias_level = wm8737_set_bias_level,
-
-       .reg_cache_size = WM8737_REGISTER_COUNT - 1, /* Skip reset */
-       .reg_word_size  = sizeof(u16),
-       .reg_cache_default = wm8737_reg,
 };
 
 static const struct of_device_id wm8737_of_match[] = {
@@ -640,24 +632,49 @@ static const struct of_device_id wm8737_of_match[] = {
 
 MODULE_DEVICE_TABLE(of, wm8737_of_match);
 
+static const struct regmap_config wm8737_regmap = {
+       .reg_bits = 7,
+       .val_bits = 9,
+       .max_register = WM8737_MAX_REGISTER,
+
+       .reg_defaults = wm8737_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wm8737_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+
+       .volatile_reg = wm8737_volatile,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static __devinit int wm8737_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8737_priv *wm8737;
-       int ret;
+       int ret, i;
 
-       wm8737 = kzalloc(sizeof(struct wm8737_priv), GFP_KERNEL);
+       wm8737 = devm_kzalloc(&i2c->dev, sizeof(struct wm8737_priv),
+                             GFP_KERNEL);
        if (wm8737 == NULL)
                return -ENOMEM;
 
+       for (i = 0; i < ARRAY_SIZE(wm8737->supplies); i++)
+               wm8737->supplies[i].supply = wm8737_supply_names[i];
+
+       ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8737->supplies),
+                                     wm8737->supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       wm8737->regmap = devm_regmap_init_i2c(i2c, &wm8737_regmap);
+       if (IS_ERR(wm8737->regmap))
+               return PTR_ERR(wm8737->regmap);
+
        i2c_set_clientdata(i2c, wm8737);
-       wm8737->control_type = SND_SOC_I2C;
 
        ret =  snd_soc_register_codec(&i2c->dev,
                                      &soc_codec_dev_wm8737, &wm8737_dai, 1);
-       if (ret < 0)
-               kfree(wm8737);
+
        return ret;
 
 }
@@ -665,7 +682,7 @@ static __devinit int wm8737_i2c_probe(struct i2c_client *i2c,
 static __devexit int wm8737_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
+
        return 0;
 }
 
@@ -691,26 +708,39 @@ static struct i2c_driver wm8737_i2c_driver = {
 static int __devinit wm8737_spi_probe(struct spi_device *spi)
 {
        struct wm8737_priv *wm8737;
-       int ret;
+       int ret, i;
 
-       wm8737 = kzalloc(sizeof(struct wm8737_priv), GFP_KERNEL);
+       wm8737 = devm_kzalloc(&spi->dev, sizeof(struct wm8737_priv),
+                             GFP_KERNEL);
        if (wm8737 == NULL)
                return -ENOMEM;
 
-       wm8737->control_type = SND_SOC_SPI;
+       for (i = 0; i < ARRAY_SIZE(wm8737->supplies); i++)
+               wm8737->supplies[i].supply = wm8737_supply_names[i];
+
+       ret = devm_regulator_bulk_get(&spi->dev, ARRAY_SIZE(wm8737->supplies),
+                                     wm8737->supplies);
+       if (ret != 0) {
+               dev_err(&spi->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       wm8737->regmap = devm_regmap_init_spi(spi, &wm8737_regmap);
+       if (IS_ERR(wm8737->regmap))
+               return PTR_ERR(wm8737->regmap);
+
        spi_set_drvdata(spi, wm8737);
 
        ret = snd_soc_register_codec(&spi->dev,
                                     &soc_codec_dev_wm8737, &wm8737_dai, 1);
-       if (ret < 0)
-               kfree(wm8737);
+
        return ret;
 }
 
 static int __devexit wm8737_spi_remove(struct spi_device *spi)
 {
        snd_soc_unregister_codec(&spi->dev);
-       kfree(spi_get_drvdata(spi));
+
        return 0;
 }
 
index 35f3d23200e048ed8a358861b28888d3cf20678c..4281a08021384d30f0eb4673e9298f5e862f7d86 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/spi/spi.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/of_device.h>
@@ -40,26 +41,43 @@ static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = {
 
 /* codec private data */
 struct wm8741_priv {
-       enum snd_soc_control_type control_type;
+       struct regmap *regmap;
        struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
        unsigned int sysclk;
        struct snd_pcm_hw_constraint_list *sysclk_constraints;
 };
 
-static const u16 wm8741_reg_defaults[WM8741_REGISTER_COUNT] = {
-       0x0000,     /* R0  - DACLLSB Attenuation */
-       0x0000,     /* R1  - DACLMSB Attenuation */
-       0x0000,     /* R2  - DACRLSB Attenuation */
-       0x0000,     /* R3  - DACRMSB Attenuation */
-       0x0000,     /* R4  - Volume Control */
-       0x000A,     /* R5  - Format Control */
-       0x0000,     /* R6  - Filter Control */
-       0x0000,     /* R7  - Mode Control 1 */
-       0x0002,     /* R8  - Mode Control 2 */
-       0x0000,     /* R9  - Reset */
-       0x0002,     /* R32 - ADDITONAL_CONTROL_1 */
+static const struct reg_default wm8741_reg_defaults[] = {
+       {  0, 0x0000 },     /* R0  - DACLLSB Attenuation */
+       {  1, 0x0000 },     /* R1  - DACLMSB Attenuation */
+       {  2, 0x0000 },     /* R2  - DACRLSB Attenuation */
+       {  3, 0x0000 },     /* R3  - DACRMSB Attenuation */
+       {  4, 0x0000 },     /* R4  - Volume Control */
+       {  5, 0x000A },     /* R5  - Format Control */
+       {  6, 0x0000 },     /* R6  - Filter Control */
+       {  7, 0x0000 },     /* R7  - Mode Control 1 */
+       {  8, 0x0002 },     /* R8  - Mode Control 2 */
+       { 32, 0x0002 },     /* R32 - ADDITONAL_CONTROL_1 */
 };
 
+static bool wm8741_readable(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case WM8741_DACLLSB_ATTENUATION:
+       case WM8741_DACLMSB_ATTENUATION:
+       case WM8741_DACRLSB_ATTENUATION:
+       case WM8741_DACRMSB_ATTENUATION:
+       case WM8741_VOLUME_CONTROL:
+       case WM8741_FORMAT_CONTROL:
+       case WM8741_FILTER_CONTROL:
+       case WM8741_MODE_CONTROL_1:
+       case WM8741_MODE_CONTROL_2:
+       case WM8741_ADDITIONAL_CONTROL_1:
+               return true;
+       default:
+               return false;
+       }
+}
 
 static int wm8741_reset(struct snd_soc_codec *codec)
 {
@@ -403,17 +421,6 @@ static int wm8741_probe(struct snd_soc_codec *codec)
 {
        struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
-               wm8741->supplies[i].supply = wm8741_supply_names[i];
-
-       ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8741->supplies),
-                                wm8741->supplies);
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
-               goto err;
-       }
 
        ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies),
                                    wm8741->supplies);
@@ -422,7 +429,7 @@ static int wm8741_probe(struct snd_soc_codec *codec)
                goto err_get;
        }
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8741->control_type);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                goto err_enable;
@@ -450,8 +457,6 @@ static int wm8741_probe(struct snd_soc_codec *codec)
 err_enable:
        regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
 err_get:
-       regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
-err:
        return ret;
 }
 
@@ -460,7 +465,6 @@ static int wm8741_remove(struct snd_soc_codec *codec)
        struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
 
        regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
-       regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
 
        return 0;
 }
@@ -469,9 +473,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8741 = {
        .probe =        wm8741_probe,
        .remove =       wm8741_remove,
        .resume =       wm8741_resume,
-       .reg_cache_size = ARRAY_SIZE(wm8741_reg_defaults),
-       .reg_word_size = sizeof(u16),
-       .reg_cache_default = wm8741_reg_defaults,
 
        .controls = wm8741_snd_controls,
        .num_controls = ARRAY_SIZE(wm8741_snd_controls),
@@ -487,20 +488,48 @@ static const struct of_device_id wm8741_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, wm8741_of_match);
 
+static const struct regmap_config wm8741_regmap = {
+       .reg_bits = 7,
+       .val_bits = 9,
+       .max_register = WM8741_MAX_REGISTER,
+
+       .reg_defaults = wm8741_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wm8741_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+
+       .readable_reg = wm8741_readable,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 static int wm8741_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct wm8741_priv *wm8741;
-       int ret;
+       int ret, i;
 
        wm8741 = devm_kzalloc(&i2c->dev, sizeof(struct wm8741_priv),
                              GFP_KERNEL);
        if (wm8741 == NULL)
                return -ENOMEM;
 
+       for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
+               wm8741->supplies[i].supply = wm8741_supply_names[i];
+
+       ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8741->supplies),
+                                     wm8741->supplies);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       wm8741->regmap = regmap_init_i2c(i2c, &wm8741_regmap);
+       if (IS_ERR(wm8741->regmap)) {
+               ret = PTR_ERR(wm8741->regmap);
+               dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
+               return ret;
+       }
+
        i2c_set_clientdata(i2c, wm8741);
-       wm8741->control_type = SND_SOC_I2C;
 
        ret = snd_soc_register_codec(&i2c->dev,
                                     &soc_codec_dev_wm8741, &wm8741_dai, 1);
@@ -536,14 +565,30 @@ static struct i2c_driver wm8741_i2c_driver = {
 static int __devinit wm8741_spi_probe(struct spi_device *spi)
 {
        struct wm8741_priv *wm8741;
-       int ret;
+       int ret, i;
 
        wm8741 = devm_kzalloc(&spi->dev, sizeof(struct wm8741_priv),
                             GFP_KERNEL);
        if (wm8741 == NULL)
                return -ENOMEM;
 
-       wm8741->control_type = SND_SOC_SPI;
+       for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
+               wm8741->supplies[i].supply = wm8741_supply_names[i];
+
+       ret = devm_regulator_bulk_get(&spi->dev, ARRAY_SIZE(wm8741->supplies),
+                                     wm8741->supplies);
+       if (ret != 0) {
+               dev_err(&spi->dev, "Failed to request supplies: %d\n", ret);
+               return ret;
+       }
+
+       wm8741->regmap = regmap_init_spi(spi, &wm8741_regmap);
+       if (IS_ERR(wm8741->regmap)) {
+               ret = PTR_ERR(wm8741->regmap);
+               dev_err(&spi->dev, "Failed to init regmap: %d\n", ret);
+               return ret;
+       }
+
        spi_set_drvdata(spi, wm8741);
 
        ret = snd_soc_register_codec(&spi->dev,
index a5127b4ff9e1881dd49b5d588d3cd354d33cc746..c7c0034d39669a5e4b548bd7a46f40eb716f00cd 100644 (file)
@@ -724,24 +724,7 @@ static struct spi_driver wm8770_spi_driver = {
        .remove = __devexit_p(wm8770_spi_remove)
 };
 
-static int __init wm8770_modinit(void)
-{
-       int ret = 0;
-
-       ret = spi_register_driver(&wm8770_spi_driver);
-       if (ret) {
-               printk(KERN_ERR "Failed to register wm8770 SPI driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(wm8770_modinit);
-
-static void __exit wm8770_exit(void)
-{
-       spi_unregister_driver(&wm8770_spi_driver);
-}
-module_exit(wm8770_exit);
+module_spi_driver(wm8770_spi_driver);
 
 MODULE_DESCRIPTION("ASoC WM8770 driver");
 MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
index 879c356a9045941408932557db6bb5f42608fd91..c32249ddb2e025c4cb457095f47524b4e334424e 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/of_device.h>
+#include <linux/regmap.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 #include <sound/core.h>
@@ -37,18 +38,46 @@ enum wm8776_chip_type {
 
 /* codec private data */
 struct wm8776_priv {
-       enum snd_soc_control_type control_type;
+       struct regmap *regmap;
        int sysclk[2];
 };
 
-static const u16 wm8776_reg[WM8776_CACHEREGNUM] = {
-       0x79, 0x79, 0x79, 0xff, 0xff,  /* 4 */
-       0xff, 0x00, 0x90, 0x00, 0x00,  /* 9 */
-       0x22, 0x22, 0x22, 0x08, 0xcf,  /* 14 */
-       0xcf, 0x7b, 0x00, 0x32, 0x00,  /* 19 */
-       0xa6, 0x01, 0x01
+static const struct reg_default wm8776_reg_defaults[] = {
+       {  0, 0x79 },
+       {  1, 0x79 },
+       {  2, 0x79 },
+       {  3, 0xff },
+       {  4, 0xff },
+       {  5, 0xff },
+       {  6, 0x00 },
+       {  7, 0x90 },
+       {  8, 0x00 },
+       {  9, 0x00 },
+       { 10, 0x22 },
+       { 11, 0x22 },
+       { 12, 0x22 },
+       { 13, 0x08 },
+       { 14, 0xcf },
+       { 15, 0xcf },
+       { 16, 0x7b },
+       { 17, 0x00 },
+       { 18, 0x32 },
+       { 19, 0x00 },
+       { 20, 0xa6 },
+       { 21, 0x01 },
+       { 22, 0x01 },
 };
 
+static bool wm8776_volatile(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case WM8776_RESET:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static int wm8776_reset(struct snd_soc_codec *codec)
 {
        return snd_soc_write(codec, WM8776_RESET, 0);
@@ -306,6 +335,8 @@ static int wm8776_set_sysclk(struct snd_soc_dai *dai,
 static int wm8776_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
+       struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
+
        switch (level) {
        case SND_SOC_BIAS_ON:
                break;
@@ -313,7 +344,7 @@ static int wm8776_set_bias_level(struct snd_soc_codec *codec,
                break;
        case SND_SOC_BIAS_STANDBY:
                if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
-                       snd_soc_cache_sync(codec);
+                       regcache_sync(wm8776->regmap);
 
                        /* Disable the global powerdown; DAPM does the rest */
                        snd_soc_update_bits(codec, WM8776_PWRDOWN, 1, 0);
@@ -396,10 +427,9 @@ static int wm8776_resume(struct snd_soc_codec *codec)
 
 static int wm8776_probe(struct snd_soc_codec *codec)
 {
-       struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8776->control_type);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
@@ -434,9 +464,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8776 = {
        .suspend =      wm8776_suspend,
        .resume =       wm8776_resume,
        .set_bias_level = wm8776_set_bias_level,
-       .reg_cache_size = ARRAY_SIZE(wm8776_reg),
-       .reg_word_size = sizeof(u16),
-       .reg_cache_default = wm8776_reg,
 
        .controls = wm8776_snd_controls,
        .num_controls = ARRAY_SIZE(wm8776_snd_controls),
@@ -452,6 +479,18 @@ static const struct of_device_id wm8776_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, wm8776_of_match);
 
+static const struct regmap_config wm8776_regmap = {
+       .reg_bits = 7,
+       .val_bits = 9,
+       .max_register = WM8776_RESET,
+
+       .reg_defaults = wm8776_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wm8776_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+
+       .volatile_reg = wm8776_volatile,
+};
+
 #if defined(CONFIG_SPI_MASTER)
 static int __devinit wm8776_spi_probe(struct spi_device *spi)
 {
@@ -463,7 +502,10 @@ static int __devinit wm8776_spi_probe(struct spi_device *spi)
        if (wm8776 == NULL)
                return -ENOMEM;
 
-       wm8776->control_type = SND_SOC_SPI;
+       wm8776->regmap = devm_regmap_init_spi(spi, &wm8776_regmap);
+       if (IS_ERR(wm8776->regmap))
+               return PTR_ERR(wm8776->regmap);
+
        spi_set_drvdata(spi, wm8776);
 
        ret = snd_soc_register_codec(&spi->dev,
@@ -501,8 +543,11 @@ static __devinit int wm8776_i2c_probe(struct i2c_client *i2c,
        if (wm8776 == NULL)
                return -ENOMEM;
 
+       wm8776->regmap = devm_regmap_init_i2c(i2c, &wm8776_regmap);
+       if (IS_ERR(wm8776->regmap))
+               return PTR_ERR(wm8776->regmap);
+
        i2c_set_clientdata(i2c, wm8776);
-       wm8776->control_type = SND_SOC_I2C;
 
        ret =  snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
index 077c9628c70d7870f0a29a517f20cd92c6bce66d..e781f865e5d7673d3fd2caae65a6e69d201e9ae6 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #define WM8900_LRC_MASK 0x03ff
 
 struct wm8900_priv {
-       enum snd_soc_control_type control_type;
+       struct regmap *regmap;
 
        u32 fll_in; /* FLL input frequency */
        u32 fll_out; /* FLL output frequency */
@@ -147,54 +148,77 @@ struct wm8900_priv {
  * wm8900 register cache.  We can't read the entire register space and we
  * have slow control buses so we cache the registers.
  */
-static const u16 wm8900_reg_defaults[WM8900_MAXREG] = {
-       0x8900, 0x0000,
-       0xc000, 0x0000,
-       0x4050, 0x4000,
-       0x0008, 0x0000,
-       0x0040, 0x0040,
-       0x1004, 0x00c0,
-       0x00c0, 0x0000,
-       0x0100, 0x00c0,
-       0x00c0, 0x0000,
-       0xb001, 0x0000,
-       0x0000, 0x0044,
-       0x004c, 0x004c,
-       0x0044, 0x0044,
-       0x0000, 0x0044,
-       0x0000, 0x0000,
-       0x0002, 0x0000,
-       0x0000, 0x0000,
-       0x0000, 0x0000,
-       0x0008, 0x0000,
-       0x0000, 0x0008,
-       0x0097, 0x0100,
-       0x0000, 0x0000,
-       0x0050, 0x0050,
-       0x0055, 0x0055,
-       0x0055, 0x0000,
-       0x0000, 0x0079,
-       0x0079, 0x0079,
-       0x0079, 0x0000,
-       /* Remaining registers all zero */
+static const struct reg_default wm8900_reg_defaults[] = {
+       {  1, 0x0000 },
+       {  2, 0xc000 },
+       {  3, 0x0000 },
+       {  4, 0x4050 },
+       {  5, 0x4000 },
+       {  6, 0x0008 },
+       {  7, 0x0000 },
+       {  8, 0x0040 },
+       {  9, 0x0040 },
+       { 10, 0x1004 },
+       { 11, 0x00c0 },
+       { 12, 0x00c0 },
+       { 13, 0x0000 },
+       { 14, 0x0100 },
+       { 15, 0x00c0 },
+       { 16, 0x00c0 },
+       { 17, 0x0000 },
+       { 18, 0xb001 },
+       { 19, 0x0000 },
+       { 20, 0x0000 },
+       { 21, 0x0044 },
+       { 22, 0x004c },
+       { 23, 0x004c },
+       { 24, 0x0044 },
+       { 25, 0x0044 },
+       { 26, 0x0000 },
+       { 27, 0x0044 },
+       { 28, 0x0000 },
+       { 29, 0x0000 },
+       { 30, 0x0002 },
+       { 31, 0x0000 },
+       { 32, 0x0000 },
+       { 33, 0x0000 },
+       { 34, 0x0000 },
+       { 35, 0x0000 },
+       { 36, 0x0008 },
+       { 37, 0x0000 },
+       { 38, 0x0000 },
+       { 39, 0x0008 },
+       { 40, 0x0097 },
+       { 41, 0x0100 },
+       { 42, 0x0000 },
+       { 43, 0x0000 },
+       { 44, 0x0050 },
+       { 45, 0x0050 },
+       { 46, 0x0055 },
+       { 47, 0x0055 },
+       { 48, 0x0055 },
+       { 49, 0x0000 },
+       { 50, 0x0000 },
+       { 51, 0x0079 },
+       { 52, 0x0079 },
+       { 53, 0x0079 },
+       { 54, 0x0079 },
+       { 55, 0x0000 },
 };
 
-static int wm8900_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
+static bool wm8900_volatile_register(struct device *dev, unsigned int reg)
 {
        switch (reg) {
        case WM8900_REG_ID:
-               return 1;
+               return true;
        default:
-               return 0;
+               return false;
        }
 }
 
 static void wm8900_reset(struct snd_soc_codec *codec)
 {
        snd_soc_write(codec, WM8900_REG_RESET, 0);
-
-       memcpy(codec->reg_cache, wm8900_reg_defaults,
-              sizeof(wm8900_reg_defaults));
 }
 
 static int wm8900_hp_event(struct snd_soc_dapm_widget *w,
@@ -469,10 +493,10 @@ SOC_DAPM_SINGLE("RINPUT2 Switch", WM8900_REG_INCTL, 1, 1, 0),
 SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INCTL, 0, 1, 0),
 };
 
-static const char *wm9700_lp_mux[] = { "Disabled", "Enabled" };
+static const char *wm8900_lp_mux[] = { "Disabled", "Enabled" };
 
 static const struct soc_enum wm8900_lineout2_lp_mux =
-SOC_ENUM_SINGLE(WM8900_REG_LOUTMIXCTL1, 1, 2, wm9700_lp_mux);
+SOC_ENUM_SINGLE(WM8900_REG_LOUTMIXCTL1, 1, 2, wm8900_lp_mux);
 
 static const struct snd_kcontrol_new wm8900_lineout2_lp =
 SOC_DAPM_ENUM("Route", wm8900_lineout2_lp_mux);
@@ -1119,13 +1143,16 @@ static int wm8900_suspend(struct snd_soc_codec *codec)
 static int wm8900_resume(struct snd_soc_codec *codec)
 {
        struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
-       u16 *cache;
-       int i, ret;
-
-       cache = kmemdup(codec->reg_cache, sizeof(wm8900_reg_defaults),
-                       GFP_KERNEL);
+       int ret;
 
        wm8900_reset(codec);
+
+       ret = regcache_sync(wm8900->regmap);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to restore cache: %d\n", ret);
+               return ret;
+       }
+
        wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        /* Restart the FLL? */
@@ -1139,27 +1166,18 @@ static int wm8900_resume(struct snd_soc_codec *codec)
                ret = wm8900_set_fll(codec, 0, fll_in, fll_out);
                if (ret != 0) {
                        dev_err(codec->dev, "Failed to restart FLL\n");
-                       kfree(cache);
                        return ret;
                }
        }
 
-       if (cache) {
-               for (i = 0; i < WM8900_MAXREG; i++)
-                       snd_soc_write(codec, i, cache[i]);
-               kfree(cache);
-       } else
-               dev_err(codec->dev, "Unable to allocate register cache\n");
-
        return 0;
 }
 
 static int wm8900_probe(struct snd_soc_codec *codec)
 {
-       struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
        int ret = 0, reg;
 
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8900->control_type);
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
@@ -1207,10 +1225,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8900 = {
        .suspend =      wm8900_suspend,
        .resume =       wm8900_resume,
        .set_bias_level = wm8900_set_bias_level,
-       .volatile_register = wm8900_volatile_register,
-       .reg_cache_size = ARRAY_SIZE(wm8900_reg_defaults),
-       .reg_word_size = sizeof(u16),
-       .reg_cache_default = wm8900_reg_defaults,
 
        .controls = wm8900_snd_controls,
        .num_controls = ARRAY_SIZE(wm8900_snd_controls),
@@ -1220,30 +1234,44 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8900 = {
        .num_dapm_routes = ARRAY_SIZE(wm8900_dapm_routes),
 };
 
+static const struct regmap_config wm8900_regmap = {
+       .reg_bits = 8,
+       .val_bits = 16,
+       .max_register = WM8900_MAXREG,
+
+       .reg_defaults = wm8900_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wm8900_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+
+       .volatile_reg = wm8900_volatile_register,
+};
+
 #if defined(CONFIG_SPI_MASTER)
 static int __devinit wm8900_spi_probe(struct spi_device *spi)
 {
        struct wm8900_priv *wm8900;
        int ret;
 
-       wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
+       wm8900 = devm_kzalloc(&spi->dev, sizeof(struct wm8900_priv),
+                             GFP_KERNEL);
        if (wm8900 == NULL)
                return -ENOMEM;
 
-       wm8900->control_type = SND_SOC_SPI;
+       wm8900->regmap = devm_regmap_init_spi(spi, &wm8900_regmap);
+       if (IS_ERR(wm8900->regmap))
+               return PTR_ERR(wm8900->regmap);
+
        spi_set_drvdata(spi, wm8900);
 
        ret = snd_soc_register_codec(&spi->dev,
                        &soc_codec_dev_wm8900, &wm8900_dai, 1);
-       if (ret < 0)
-               kfree(wm8900);
+
        return ret;
 }
 
 static int __devexit wm8900_spi_remove(struct spi_device *spi)
 {
        snd_soc_unregister_codec(&spi->dev);
-       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
@@ -1264,24 +1292,26 @@ static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
        struct wm8900_priv *wm8900;
        int ret;
 
-       wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL);
+       wm8900 = devm_kzalloc(&i2c->dev, sizeof(struct wm8900_priv),
+                             GFP_KERNEL);
        if (wm8900 == NULL)
                return -ENOMEM;
 
+       wm8900->regmap = devm_regmap_init_i2c(i2c, &wm8900_regmap);
+       if (IS_ERR(wm8900->regmap))
+               return PTR_ERR(wm8900->regmap);
+
        i2c_set_clientdata(i2c, wm8900);
-       wm8900->control_type = SND_SOC_I2C;
 
        ret =  snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_wm8900, &wm8900_dai, 1);
-       if (ret < 0)
-               kfree(wm8900);
+
        return ret;
 }
 
 static __devexit int wm8900_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
index 73f1c8d7bafbdc591e990f2dc2fd678a61ff1f8a..839414f9e2ed3866d41f09c96cd3d50ec9dcc045 100644 (file)
@@ -2241,23 +2241,7 @@ static struct i2c_driver wm8903_i2c_driver = {
        .id_table = wm8903_i2c_id,
 };
 
-static int __init wm8903_modinit(void)
-{
-       int ret = 0;
-       ret = i2c_add_driver(&wm8903_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register wm8903 I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(wm8903_modinit);
-
-static void __exit wm8903_exit(void)
-{
-       i2c_del_driver(&wm8903_i2c_driver);
-}
-module_exit(wm8903_exit);
+module_i2c_driver(wm8903_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8903 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.cm>");
index dc4262eea4b711990c71e602fe1a0fba7928250b..7c8df52a8d9d3710e11d87d352bed367a81c4920 100644 (file)
@@ -1185,8 +1185,6 @@ static int wm8904_add_widgets(struct snd_soc_codec *codec)
                snd_soc_dapm_new_controls(dapm, wm8904_dapm_widgets,
                                          ARRAY_SIZE(wm8904_dapm_widgets));
 
-               snd_soc_dapm_add_routes(dapm, core_intercon,
-                                       ARRAY_SIZE(core_intercon));
                snd_soc_dapm_add_routes(dapm, adc_intercon,
                                        ARRAY_SIZE(adc_intercon));
                snd_soc_dapm_add_routes(dapm, dac_intercon,
index 481a3d9cfe4852958047cec3f83be88cd17a365d..b20aa4e7c3f9c2f85f84deaddc06aee763061987 100644 (file)
@@ -785,23 +785,7 @@ static struct i2c_driver wm8940_i2c_driver = {
        .id_table = wm8940_i2c_id,
 };
 
-static int __init wm8940_modinit(void)
-{
-       int ret = 0;
-       ret = i2c_add_driver(&wm8940_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register wm8940 I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(wm8940_modinit);
-
-static void __exit wm8940_exit(void)
-{
-       i2c_del_driver(&wm8940_i2c_driver);
-}
-module_exit(wm8940_exit);
+module_i2c_driver(wm8940_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8940 driver");
 MODULE_AUTHOR("Jonathan Cameron");
index 61fe97433e738eb43c486115a985fc1bd0ad68f5..2f1c075755b1fc7dd4827fbcd547da0556e9e2a9 100644 (file)
@@ -1071,23 +1071,7 @@ static struct i2c_driver wm8955_i2c_driver = {
        .id_table = wm8955_i2c_id,
 };
 
-static int __init wm8955_modinit(void)
-{
-       int ret = 0;
-       ret = i2c_add_driver(&wm8955_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8955 I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(wm8955_modinit);
-
-static void __exit wm8955_exit(void)
-{
-       i2c_del_driver(&wm8955_i2c_driver);
-}
-module_exit(wm8955_exit);
+module_i2c_driver(wm8955_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8955 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
index 1332692ef81bc9628e8cad04ccf65cd972c7fb8c..00121ba3659718ab4c4af6ff5135373762de4765 100644 (file)
@@ -946,7 +946,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
                wm8994->mbc_texts = kmalloc(sizeof(char *)
                                            * pdata->num_mbc_cfgs, GFP_KERNEL);
                if (!wm8994->mbc_texts) {
-                       dev_err(wm8994->codec->dev,
+                       dev_err(wm8994->hubs.codec->dev,
                                "Failed to allocate %d MBC config texts\n",
                                pdata->num_mbc_cfgs);
                        return;
@@ -958,9 +958,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
                wm8994->mbc_enum.max = pdata->num_mbc_cfgs;
                wm8994->mbc_enum.texts = wm8994->mbc_texts;
 
-               ret = snd_soc_add_codec_controls(wm8994->codec, control, 1);
+               ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
+                                                control, 1);
                if (ret != 0)
-                       dev_err(wm8994->codec->dev,
+                       dev_err(wm8994->hubs.codec->dev,
                                "Failed to add MBC mode controls: %d\n", ret);
        }
 
@@ -974,7 +975,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
                wm8994->vss_texts = kmalloc(sizeof(char *)
                                            * pdata->num_vss_cfgs, GFP_KERNEL);
                if (!wm8994->vss_texts) {
-                       dev_err(wm8994->codec->dev,
+                       dev_err(wm8994->hubs.codec->dev,
                                "Failed to allocate %d VSS config texts\n",
                                pdata->num_vss_cfgs);
                        return;
@@ -986,9 +987,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
                wm8994->vss_enum.max = pdata->num_vss_cfgs;
                wm8994->vss_enum.texts = wm8994->vss_texts;
 
-               ret = snd_soc_add_codec_controls(wm8994->codec, control, 1);
+               ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
+                                                control, 1);
                if (ret != 0)
-                       dev_err(wm8994->codec->dev,
+                       dev_err(wm8994->hubs.codec->dev,
                                "Failed to add VSS mode controls: %d\n", ret);
        }
 
@@ -1003,7 +1005,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
                wm8994->vss_hpf_texts = kmalloc(sizeof(char *)
                                                * pdata->num_vss_hpf_cfgs, GFP_KERNEL);
                if (!wm8994->vss_hpf_texts) {
-                       dev_err(wm8994->codec->dev,
+                       dev_err(wm8994->hubs.codec->dev,
                                "Failed to allocate %d VSS HPF config texts\n",
                                pdata->num_vss_hpf_cfgs);
                        return;
@@ -1015,9 +1017,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
                wm8994->vss_hpf_enum.max = pdata->num_vss_hpf_cfgs;
                wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts;
 
-               ret = snd_soc_add_codec_controls(wm8994->codec, control, 1);
+               ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
+                                                control, 1);
                if (ret != 0)
-                       dev_err(wm8994->codec->dev,
+                       dev_err(wm8994->hubs.codec->dev,
                                "Failed to add VSS HPFmode controls: %d\n",
                                ret);
        }
@@ -1033,7 +1036,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
                wm8994->enh_eq_texts = kmalloc(sizeof(char *)
                                                * pdata->num_enh_eq_cfgs, GFP_KERNEL);
                if (!wm8994->enh_eq_texts) {
-                       dev_err(wm8994->codec->dev,
+                       dev_err(wm8994->hubs.codec->dev,
                                "Failed to allocate %d enhanced EQ config texts\n",
                                pdata->num_enh_eq_cfgs);
                        return;
@@ -1045,9 +1048,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
                wm8994->enh_eq_enum.max = pdata->num_enh_eq_cfgs;
                wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts;
 
-               ret = snd_soc_add_codec_controls(wm8994->codec, control, 1);
+               ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
+                                                control, 1);
                if (ret != 0)
-                       dev_err(wm8994->codec->dev,
+                       dev_err(wm8994->hubs.codec->dev,
                                "Failed to add enhanced EQ controls: %d\n",
                                ret);
        }
index 96518ac8e24ce9660f6fde240cc951570af6a61c..f0f6f66017859c7e8b5fcab1f470565d8a6cdd88 100644 (file)
  * We can't read the WM8960 register space when we are
  * using 2 wire for device control, so we cache them instead.
  */
-static const u16 wm8960_reg[WM8960_CACHEREGNUM] = {
-       0x0097, 0x0097, 0x0000, 0x0000,
-       0x0000, 0x0008, 0x0000, 0x000a,
-       0x01c0, 0x0000, 0x00ff, 0x00ff,
-       0x0000, 0x0000, 0x0000, 0x0000,
-       0x0000, 0x007b, 0x0100, 0x0032,
-       0x0000, 0x00c3, 0x00c3, 0x01c0,
-       0x0000, 0x0000, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0000, 0x0000,
-       0x0100, 0x0100, 0x0050, 0x0050,
-       0x0050, 0x0050, 0x0000, 0x0000,
-       0x0000, 0x0000, 0x0040, 0x0000,
-       0x0000, 0x0050, 0x0050, 0x0000,
-       0x0002, 0x0037, 0x004d, 0x0080,
-       0x0008, 0x0031, 0x0026, 0x00e9,
+static const struct reg_default wm8960_reg_defaults[] = {
+       {  0x0, 0x0097 },
+       {  0x1, 0x0097 },
+       {  0x2, 0x0000 },
+       {  0x3, 0x0000 },
+       {  0x4, 0x0000 },
+       {  0x5, 0x0008 },
+       {  0x6, 0x0000 },
+       {  0x7, 0x000a },
+       {  0x8, 0x01c0 },
+       {  0x9, 0x0000 },
+       {  0xa, 0x00ff },
+       {  0xb, 0x00ff },
+
+       { 0x10, 0x0000 },
+       { 0x11, 0x007b },
+       { 0x12, 0x0100 },
+       { 0x13, 0x0032 },
+       { 0x14, 0x0000 },
+       { 0x15, 0x00c3 },
+       { 0x16, 0x00c3 },
+       { 0x17, 0x01c0 },
+       { 0x18, 0x0000 },
+       { 0x19, 0x0000 },
+       { 0x1a, 0x0000 },
+       { 0x1b, 0x0000 },
+       { 0x1c, 0x0000 },
+       { 0x1d, 0x0000 },
+
+       { 0x20, 0x0100 },
+       { 0x21, 0x0100 },
+       { 0x22, 0x0050 },
+
+       { 0x25, 0x0050 },
+       { 0x26, 0x0000 },
+       { 0x27, 0x0000 },
+       { 0x28, 0x0000 },
+       { 0x29, 0x0000 },
+       { 0x2a, 0x0040 },
+       { 0x2b, 0x0000 },
+       { 0x2c, 0x0000 },
+       { 0x2d, 0x0050 },
+       { 0x2e, 0x0050 },
+       { 0x2f, 0x0000 },
+       { 0x30, 0x0002 },
+       { 0x31, 0x0037 },
+
+       { 0x33, 0x0080 },
+       { 0x34, 0x0008 },
+       { 0x35, 0x0031 },
+       { 0x36, 0x0026 },
+       { 0x37, 0x00e9 },
 };
 
+static bool wm8960_volatile(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case WM8960_RESET:
+               return true;
+       default:
+               return false;
+       }
+}
+
 struct wm8960_priv {
-       enum snd_soc_control_type control_type;
+       struct regmap *regmap;
        int (*set_bias_level)(struct snd_soc_codec *,
                              enum snd_soc_bias_level level);
        struct snd_soc_dapm_widget *lout1;
@@ -510,18 +557,25 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = dai->codec;
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
        u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3;
+       snd_pcm_format_t format = params_format(params);
        int i;
 
        /* bit size */
-       switch (params_format(params)) {
+       switch (format) {
        case SNDRV_PCM_FORMAT_S16_LE:
+       case SNDRV_PCM_FORMAT_S16_BE:
                break;
        case SNDRV_PCM_FORMAT_S20_3LE:
+       case SNDRV_PCM_FORMAT_S20_3BE:
                iface |= 0x0004;
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
+       case SNDRV_PCM_FORMAT_S24_BE:
                iface |= 0x0008;
                break;
+       default:
+               dev_err(codec->dev, "unsupported format %i\n", format);
+               return -EINVAL;
        }
 
        /* Update filters for the new rate */
@@ -555,6 +609,8 @@ static int wm8960_mute(struct snd_soc_dai *dai, int mute)
 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);
+
        switch (level) {
        case SND_SOC_BIAS_ON:
                break;
@@ -566,7 +622,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
 
        case SND_SOC_BIAS_STANDBY:
                if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
-                       snd_soc_cache_sync(codec);
+                       regcache_sync(wm8960->regmap);
 
                        /* Enable anti-pop features */
                        snd_soc_write(codec, WM8960_APOP1,
@@ -667,7 +723,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
                        break;
 
                case SND_SOC_BIAS_OFF:
-                       snd_soc_cache_sync(codec);
+                       regcache_sync(wm8960->regmap);
                        break;
                default:
                        break;
@@ -906,16 +962,11 @@ static int wm8960_probe(struct snd_soc_codec *codec)
        if (!pdata) {
                dev_warn(codec->dev, "No platform data supplied\n");
        } else {
-               if (pdata->dres > WM8960_DRES_MAX) {
-                       dev_err(codec->dev, "Invalid DRES: %d\n", pdata->dres);
-                       pdata->dres = 0;
-               }
-
                if (pdata->capless)
                        wm8960->set_bias_level = wm8960_set_bias_level_capless;
        }
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8960->control_type);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
@@ -963,14 +1014,24 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8960 = {
        .suspend =      wm8960_suspend,
        .resume =       wm8960_resume,
        .set_bias_level = wm8960_set_bias_level,
-       .reg_cache_size = ARRAY_SIZE(wm8960_reg),
-       .reg_word_size = sizeof(u16),
-       .reg_cache_default = wm8960_reg,
+};
+
+static const struct regmap_config wm8960_regmap = {
+       .reg_bits = 7,
+       .val_bits = 9,
+       .max_register = WM8960_PLL4,
+
+       .reg_defaults = wm8960_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wm8960_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+
+       .volatile_reg = wm8960_volatile,
 };
 
 static __devinit int wm8960_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
+       struct wm8960_data *pdata = dev_get_platdata(&i2c->dev);
        struct wm8960_priv *wm8960;
        int ret;
 
@@ -979,8 +1040,21 @@ static __devinit int wm8960_i2c_probe(struct i2c_client *i2c,
        if (wm8960 == NULL)
                return -ENOMEM;
 
+       wm8960->regmap = regmap_init_i2c(i2c, &wm8960_regmap);
+       if (IS_ERR(wm8960->regmap))
+               return PTR_ERR(wm8960->regmap);
+
+       if (pdata && pdata->shared_lrclk) {
+               ret = regmap_update_bits(wm8960->regmap, WM8960_ADDCTL2,
+                                        0x4, 0x4);
+               if (ret != 0) {
+                       dev_err(&i2c->dev, "Failed to enable LRCM: %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
        i2c_set_clientdata(i2c, wm8960);
-       wm8960->control_type = SND_SOC_I2C;
 
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_wm8960, &wm8960_dai, 1);
@@ -1010,23 +1084,7 @@ static struct i2c_driver wm8960_i2c_driver = {
        .id_table = wm8960_i2c_id,
 };
 
-static int __init wm8960_modinit(void)
-{
-       int ret = 0;
-       ret = i2c_add_driver(&wm8960_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8960 I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(wm8960_modinit);
-
-static void __exit wm8960_exit(void)
-{
-       i2c_del_driver(&wm8960_i2c_driver);
-}
-module_exit(wm8960_exit);
+module_i2c_driver(wm8960_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8960 driver");
 MODULE_AUTHOR("Liam Girdwood");
index 01edbcc754d2cb7ef10124963a701583cf75f762..f387670d0d7591c1860c071087c81736974e9fc5 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 
 #define WM8961_MAX_REGISTER                     0xFC
 
-static u16 wm8961_reg_defaults[] = {
-       0x009F,     /* R0   - Left Input volume */
-       0x009F,     /* R1   - Right Input volume */
-       0x0000,     /* R2   - LOUT1 volume */
-       0x0000,     /* R3   - ROUT1 volume */
-       0x0020,     /* R4   - Clocking1 */
-       0x0008,     /* R5   - ADC & DAC Control 1 */
-       0x0000,     /* R6   - ADC & DAC Control 2 */
-       0x000A,     /* R7   - Audio Interface 0 */
-       0x01F4,     /* R8   - Clocking2 */
-       0x0000,     /* R9   - Audio Interface 1 */
-       0x00FF,     /* R10  - Left DAC volume */
-       0x00FF,     /* R11  - Right DAC volume */
-       0x0000,     /* R12 */
-       0x0000,     /* R13 */
-       0x0040,     /* R14  - Audio Interface 2 */
-       0x0000,     /* R15  - Software Reset */
-       0x0000,     /* R16 */
-       0x007B,     /* R17  - ALC1 */
-       0x0000,     /* R18  - ALC2 */
-       0x0032,     /* R19  - ALC3 */
-       0x0000,     /* R20  - Noise Gate */
-       0x00C0,     /* R21  - Left ADC volume */
-       0x00C0,     /* R22  - Right ADC volume */
-       0x0120,     /* R23  - Additional control(1) */
-       0x0000,     /* R24  - Additional control(2) */
-       0x0000,     /* R25  - Pwr Mgmt (1) */
-       0x0000,     /* R26  - Pwr Mgmt (2) */
-       0x0000,     /* R27  - Additional Control (3) */
-       0x0000,     /* R28  - Anti-pop */
-       0x0000,     /* R29 */
-       0x005F,     /* R30  - Clocking 3 */
-       0x0000,     /* R31 */
-       0x0000,     /* R32  - ADCL signal path */
-       0x0000,     /* R33  - ADCR signal path */
-       0x0000,     /* R34 */
-       0x0000,     /* R35 */
-       0x0000,     /* R36 */
-       0x0000,     /* R37 */
-       0x0000,     /* R38 */
-       0x0000,     /* R39 */
-       0x0000,     /* R40  - LOUT2 volume */
-       0x0000,     /* R41  - ROUT2 volume */
-       0x0000,     /* R42 */
-       0x0000,     /* R43 */
-       0x0000,     /* R44 */
-       0x0000,     /* R45 */
-       0x0000,     /* R46 */
-       0x0000,     /* R47  - Pwr Mgmt (3) */
-       0x0023,     /* R48  - Additional Control (4) */
-       0x0000,     /* R49  - Class D Control 1 */
-       0x0000,     /* R50 */
-       0x0003,     /* R51  - Class D Control 2 */
-       0x0000,     /* R52 */
-       0x0000,     /* R53 */
-       0x0000,     /* R54 */
-       0x0000,     /* R55 */
-       0x0106,     /* R56  - Clocking 4 */
-       0x0000,     /* R57  - DSP Sidetone 0 */
-       0x0000,     /* R58  - DSP Sidetone 1 */
-       0x0000,     /* R59 */
-       0x0000,     /* R60  - DC Servo 0 */
-       0x0000,     /* R61  - DC Servo 1 */
-       0x0000,     /* R62 */
-       0x015E,     /* R63  - DC Servo 3 */
-       0x0010,     /* R64 */
-       0x0010,     /* R65  - DC Servo 5 */
-       0x0000,     /* R66 */
-       0x0001,     /* R67 */
-       0x0003,     /* R68  - Analogue PGA Bias */
-       0x0000,     /* R69  - Analogue HP 0 */
-       0x0060,     /* R70 */
-       0x01FB,     /* R71  - Analogue HP 2 */
-       0x0000,     /* R72  - Charge Pump 1 */
-       0x0065,     /* R73 */
-       0x005F,     /* R74 */
-       0x0059,     /* R75 */
-       0x006B,     /* R76 */
-       0x0038,     /* R77 */
-       0x000C,     /* R78 */
-       0x000A,     /* R79 */
-       0x006B,     /* R80 */
-       0x0000,     /* R81 */
-       0x0000,     /* R82  - Charge Pump B */
-       0x0087,     /* R83 */
-       0x0000,     /* R84 */
-       0x005C,     /* R85 */
-       0x0000,     /* R86 */
-       0x0000,     /* R87  - Write Sequencer 1 */
-       0x0000,     /* R88  - Write Sequencer 2 */
-       0x0000,     /* R89  - Write Sequencer 3 */
-       0x0000,     /* R90  - Write Sequencer 4 */
-       0x0000,     /* R91  - Write Sequencer 5 */
-       0x0000,     /* R92  - Write Sequencer 6 */
-       0x0000,     /* R93  - Write Sequencer 7 */
-       0x0000,     /* R94 */
-       0x0000,     /* R95 */
-       0x0000,     /* R96 */
-       0x0000,     /* R97 */
-       0x0000,     /* R98 */
-       0x0000,     /* R99 */
-       0x0000,     /* R100 */
-       0x0000,     /* R101 */
-       0x0000,     /* R102 */
-       0x0000,     /* R103 */
-       0x0000,     /* R104 */
-       0x0000,     /* R105 */
-       0x0000,     /* R106 */
-       0x0000,     /* R107 */
-       0x0000,     /* R108 */
-       0x0000,     /* R109 */
-       0x0000,     /* R110 */
-       0x0000,     /* R111 */
-       0x0000,     /* R112 */
-       0x0000,     /* R113 */
-       0x0000,     /* R114 */
-       0x0000,     /* R115 */
-       0x0000,     /* R116 */
-       0x0000,     /* R117 */
-       0x0000,     /* R118 */
-       0x0000,     /* R119 */
-       0x0000,     /* R120 */
-       0x0000,     /* R121 */
-       0x0000,     /* R122 */
-       0x0000,     /* R123 */
-       0x0000,     /* R124 */
-       0x0000,     /* R125 */
-       0x0000,     /* R126 */
-       0x0000,     /* R127 */
-       0x0000,     /* R128 */
-       0x0000,     /* R129 */
-       0x0000,     /* R130 */
-       0x0000,     /* R131 */
-       0x0000,     /* R132 */
-       0x0000,     /* R133 */
-       0x0000,     /* R134 */
-       0x0000,     /* R135 */
-       0x0000,     /* R136 */
-       0x0000,     /* R137 */
-       0x0000,     /* R138 */
-       0x0000,     /* R139 */
-       0x0000,     /* R140 */
-       0x0000,     /* R141 */
-       0x0000,     /* R142 */
-       0x0000,     /* R143 */
-       0x0000,     /* R144 */
-       0x0000,     /* R145 */
-       0x0000,     /* R146 */
-       0x0000,     /* R147 */
-       0x0000,     /* R148 */
-       0x0000,     /* R149 */
-       0x0000,     /* R150 */
-       0x0000,     /* R151 */
-       0x0000,     /* R152 */
-       0x0000,     /* R153 */
-       0x0000,     /* R154 */
-       0x0000,     /* R155 */
-       0x0000,     /* R156 */
-       0x0000,     /* R157 */
-       0x0000,     /* R158 */
-       0x0000,     /* R159 */
-       0x0000,     /* R160 */
-       0x0000,     /* R161 */
-       0x0000,     /* R162 */
-       0x0000,     /* R163 */
-       0x0000,     /* R164 */
-       0x0000,     /* R165 */
-       0x0000,     /* R166 */
-       0x0000,     /* R167 */
-       0x0000,     /* R168 */
-       0x0000,     /* R169 */
-       0x0000,     /* R170 */
-       0x0000,     /* R171 */
-       0x0000,     /* R172 */
-       0x0000,     /* R173 */
-       0x0000,     /* R174 */
-       0x0000,     /* R175 */
-       0x0000,     /* R176 */
-       0x0000,     /* R177 */
-       0x0000,     /* R178 */
-       0x0000,     /* R179 */
-       0x0000,     /* R180 */
-       0x0000,     /* R181 */
-       0x0000,     /* R182 */
-       0x0000,     /* R183 */
-       0x0000,     /* R184 */
-       0x0000,     /* R185 */
-       0x0000,     /* R186 */
-       0x0000,     /* R187 */
-       0x0000,     /* R188 */
-       0x0000,     /* R189 */
-       0x0000,     /* R190 */
-       0x0000,     /* R191 */
-       0x0000,     /* R192 */
-       0x0000,     /* R193 */
-       0x0000,     /* R194 */
-       0x0000,     /* R195 */
-       0x0030,     /* R196 */
-       0x0006,     /* R197 */
-       0x0000,     /* R198 */
-       0x0060,     /* R199 */
-       0x0000,     /* R200 */
-       0x003F,     /* R201 */
-       0x0000,     /* R202 */
-       0x0000,     /* R203 */
-       0x0000,     /* R204 */
-       0x0001,     /* R205 */
-       0x0000,     /* R206 */
-       0x0181,     /* R207 */
-       0x0005,     /* R208 */
-       0x0008,     /* R209 */
-       0x0008,     /* R210 */
-       0x0000,     /* R211 */
-       0x013B,     /* R212 */
-       0x0000,     /* R213 */
-       0x0000,     /* R214 */
-       0x0000,     /* R215 */
-       0x0000,     /* R216 */
-       0x0070,     /* R217 */
-       0x0000,     /* R218 */
-       0x0000,     /* R219 */
-       0x0000,     /* R220 */
-       0x0000,     /* R221 */
-       0x0000,     /* R222 */
-       0x0003,     /* R223 */
-       0x0000,     /* R224 */
-       0x0000,     /* R225 */
-       0x0001,     /* R226 */
-       0x0008,     /* R227 */
-       0x0000,     /* R228 */
-       0x0000,     /* R229 */
-       0x0000,     /* R230 */
-       0x0000,     /* R231 */
-       0x0004,     /* R232 */
-       0x0000,     /* R233 */
-       0x0000,     /* R234 */
-       0x0000,     /* R235 */
-       0x0000,     /* R236 */
-       0x0000,     /* R237 */
-       0x0080,     /* R238 */
-       0x0000,     /* R239 */
-       0x0000,     /* R240 */
-       0x0000,     /* R241 */
-       0x0000,     /* R242 */
-       0x0000,     /* R243 */
-       0x0000,     /* R244 */
-       0x0052,     /* R245 */
-       0x0110,     /* R246 */
-       0x0040,     /* R247 */
-       0x0000,     /* R248 */
-       0x0030,     /* R249 */
-       0x0000,     /* R250 */
-       0x0000,     /* R251 */
-       0x0001,     /* R252 - General test 1 */
+static const struct reg_default wm8961_reg_defaults[] = {
+       {  0, 0x009F },     /* R0   - Left Input volume */
+       {  1, 0x009F },     /* R1   - Right Input volume */
+       {  2, 0x0000 },     /* R2   - LOUT1 volume */
+       {  3, 0x0000 },     /* R3   - ROUT1 volume */
+       {  4, 0x0020 },     /* R4   - Clocking1 */
+       {  5, 0x0008 },     /* R5   - ADC & DAC Control 1 */
+       {  6, 0x0000 },     /* R6   - ADC & DAC Control 2 */
+       {  7, 0x000A },     /* R7   - Audio Interface 0 */
+       {  8, 0x01F4 },     /* R8   - Clocking2 */
+       {  9, 0x0000 },     /* R9   - Audio Interface 1 */
+       { 10, 0x00FF },     /* R10  - Left DAC volume */
+       { 11, 0x00FF },     /* R11  - Right DAC volume */
+
+       { 14, 0x0040 },     /* R14  - Audio Interface 2 */
+
+       { 17, 0x007B },     /* R17  - ALC1 */
+       { 18, 0x0000 },     /* R18  - ALC2 */
+       { 19, 0x0032 },     /* R19  - ALC3 */
+       { 20, 0x0000 },     /* R20  - Noise Gate */
+       { 21, 0x00C0 },     /* R21  - Left ADC volume */
+       { 22, 0x00C0 },     /* R22  - Right ADC volume */
+       { 23, 0x0120 },     /* R23  - Additional control(1) */
+       { 24, 0x0000 },     /* R24  - Additional control(2) */
+       { 25, 0x0000 },     /* R25  - Pwr Mgmt (1) */
+       { 26, 0x0000 },     /* R26  - Pwr Mgmt (2) */
+       { 27, 0x0000 },     /* R27  - Additional Control (3) */
+       { 28, 0x0000 },     /* R28  - Anti-pop */
+
+       { 30, 0x005F },     /* R30  - Clocking 3 */
+
+       { 32, 0x0000 },     /* R32  - ADCL signal path */
+       { 33, 0x0000 },     /* R33  - ADCR signal path */
+
+       { 40, 0x0000 },     /* R40  - LOUT2 volume */
+       { 41, 0x0000 },     /* R41  - ROUT2 volume */
+
+       { 47, 0x0000 },     /* R47  - Pwr Mgmt (3) */
+       { 48, 0x0023 },     /* R48  - Additional Control (4) */
+       { 49, 0x0000 },     /* R49  - Class D Control 1 */
+
+       { 51, 0x0003 },     /* R51  - Class D Control 2 */
+
+       { 56, 0x0106 },     /* R56  - Clocking 4 */
+       { 57, 0x0000 },     /* R57  - DSP Sidetone 0 */
+       { 58, 0x0000 },     /* R58  - DSP Sidetone 1 */
+
+       { 60, 0x0000 },     /* R60  - DC Servo 0 */
+       { 61, 0x0000 },     /* R61  - DC Servo 1 */
+
+       { 63, 0x015E },     /* R63  - DC Servo 3 */
+
+       { 65, 0x0010 },     /* R65  - DC Servo 5 */
+
+       { 68, 0x0003 },     /* R68  - Analogue PGA Bias */
+       { 69, 0x0000 },     /* R69  - Analogue HP 0 */
+
+       { 71, 0x01FB },     /* R71  - Analogue HP 2 */
+       { 72, 0x0000 },     /* R72  - Charge Pump 1 */
+
+       { 82, 0x0000 },     /* R82  - Charge Pump B */
+
+       { 87, 0x0000 },     /* R87  - Write Sequencer 1 */
+       { 88, 0x0000 },     /* R88  - Write Sequencer 2 */
+       { 89, 0x0000 },     /* R89  - Write Sequencer 3 */
+       { 90, 0x0000 },     /* R90  - Write Sequencer 4 */
+       { 91, 0x0000 },     /* R91  - Write Sequencer 5 */
+       { 92, 0x0000 },     /* R92  - Write Sequencer 6 */
+       { 93, 0x0000 },     /* R93  - Write Sequencer 7 */
+
+       { 252, 0x0001 },     /* R252 - General test 1 */
 };
 
 struct wm8961_priv {
-       enum snd_soc_control_type control_type;
+       struct regmap *regmap;
        int sysclk;
 };
 
-static int wm8961_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
+static bool wm8961_volatile(struct device *dev, unsigned int reg)
 {
        switch (reg) {
        case WM8961_SOFTWARE_RESET:
        case WM8961_WRITE_SEQUENCER_7:
        case WM8961_DC_SERVO_1:
-               return 1;
+               return true;
 
        default:
-               return 0;
+               return false;
        }
 }
 
-static int wm8961_reset(struct snd_soc_codec *codec)
+static bool wm8961_readable(struct device *dev, unsigned int reg)
 {
-       return snd_soc_write(codec, WM8961_SOFTWARE_RESET, 0);
+       switch (reg) {
+       case WM8961_LEFT_INPUT_VOLUME:
+       case WM8961_RIGHT_INPUT_VOLUME:
+       case WM8961_LOUT1_VOLUME:
+       case WM8961_ROUT1_VOLUME:
+       case WM8961_CLOCKING1:
+       case WM8961_ADC_DAC_CONTROL_1:
+       case WM8961_ADC_DAC_CONTROL_2:
+       case WM8961_AUDIO_INTERFACE_0:
+       case WM8961_CLOCKING2:
+       case WM8961_AUDIO_INTERFACE_1:
+       case WM8961_LEFT_DAC_VOLUME:
+       case WM8961_RIGHT_DAC_VOLUME:
+       case WM8961_AUDIO_INTERFACE_2:
+       case WM8961_SOFTWARE_RESET:
+       case WM8961_ALC1:
+       case WM8961_ALC2:
+       case WM8961_ALC3:
+       case WM8961_NOISE_GATE:
+       case WM8961_LEFT_ADC_VOLUME:
+       case WM8961_RIGHT_ADC_VOLUME:
+       case WM8961_ADDITIONAL_CONTROL_1:
+       case WM8961_ADDITIONAL_CONTROL_2:
+       case WM8961_PWR_MGMT_1:
+       case WM8961_PWR_MGMT_2:
+       case WM8961_ADDITIONAL_CONTROL_3:
+       case WM8961_ANTI_POP:
+       case WM8961_CLOCKING_3:
+       case WM8961_ADCL_SIGNAL_PATH:
+       case WM8961_ADCR_SIGNAL_PATH:
+       case WM8961_LOUT2_VOLUME:
+       case WM8961_ROUT2_VOLUME:
+       case WM8961_PWR_MGMT_3:
+       case WM8961_ADDITIONAL_CONTROL_4:
+       case WM8961_CLASS_D_CONTROL_1:
+       case WM8961_CLASS_D_CONTROL_2:
+       case WM8961_CLOCKING_4:
+       case WM8961_DSP_SIDETONE_0:
+       case WM8961_DSP_SIDETONE_1:
+       case WM8961_DC_SERVO_0:
+       case WM8961_DC_SERVO_1:
+       case WM8961_DC_SERVO_3:
+       case WM8961_DC_SERVO_5:
+       case WM8961_ANALOGUE_PGA_BIAS:
+       case WM8961_ANALOGUE_HP_0:
+       case WM8961_ANALOGUE_HP_2:
+       case WM8961_CHARGE_PUMP_1:
+       case WM8961_CHARGE_PUMP_B:
+       case WM8961_WRITE_SEQUENCER_1:
+       case WM8961_WRITE_SEQUENCER_2:
+       case WM8961_WRITE_SEQUENCER_3:
+       case WM8961_WRITE_SEQUENCER_4:
+       case WM8961_WRITE_SEQUENCER_5:
+       case WM8961_WRITE_SEQUENCER_6:
+       case WM8961_WRITE_SEQUENCER_7:
+       case WM8961_GENERAL_TEST_1:
+               return true;
+       default:
+               return false;
+       }
 }
 
 /*
@@ -962,33 +839,12 @@ static int wm8961_probe(struct snd_soc_codec *codec)
        int ret = 0;
        u16 reg;
 
-       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
                return ret;
        }
 
-       reg = snd_soc_read(codec, WM8961_SOFTWARE_RESET);
-       if (reg != 0x1801) {
-               dev_err(codec->dev, "Device is not a WM8961: ID=0x%x\n", reg);
-               return -EINVAL;
-       }
-
-       /* This isn't volatile - readback doesn't correspond to write */
-       codec->cache_bypass = 1;
-       reg = snd_soc_read(codec, WM8961_RIGHT_INPUT_VOLUME);
-       codec->cache_bypass = 0;
-       dev_info(codec->dev, "WM8961 family %d revision %c\n",
-                (reg & WM8961_DEVICE_ID_MASK) >> WM8961_DEVICE_ID_SHIFT,
-                ((reg & WM8961_CHIP_REV_MASK) >> WM8961_CHIP_REV_SHIFT)
-                + 'A');
-
-       ret = wm8961_reset(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset\n");
-               return ret;
-       }
-
        /* Enable class W */
        reg = snd_soc_read(codec, WM8961_CHARGE_PUMP_B);
        reg |= WM8961_CP_DYN_PWR_MASK;
@@ -1066,16 +922,26 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8961 = {
        .suspend =      wm8961_suspend,
        .resume =       wm8961_resume,
        .set_bias_level = wm8961_set_bias_level,
-       .reg_cache_size = ARRAY_SIZE(wm8961_reg_defaults),
-       .reg_word_size = sizeof(u16),
-       .reg_cache_default = wm8961_reg_defaults,
-       .volatile_register = wm8961_volatile_register,
+};
+
+static const struct regmap_config wm8961_regmap = {
+       .reg_bits = 8,
+       .val_bits = 16,
+       .max_register = WM8961_MAX_REGISTER,
+
+       .reg_defaults = wm8961_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wm8961_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+
+       .volatile_reg = wm8961_volatile,
+       .readable_reg = wm8961_readable,
 };
 
 static __devinit int wm8961_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8961_priv *wm8961;
+       unsigned int val;
        int ret;
 
        wm8961 = devm_kzalloc(&i2c->dev, sizeof(struct wm8961_priv),
@@ -1083,6 +949,42 @@ static __devinit int wm8961_i2c_probe(struct i2c_client *i2c,
        if (wm8961 == NULL)
                return -ENOMEM;
 
+       wm8961->regmap = devm_regmap_init_i2c(i2c, &wm8961_regmap);
+       if (IS_ERR(wm8961->regmap))
+               return PTR_ERR(wm8961->regmap);
+
+       ret = regmap_read(wm8961->regmap, WM8961_SOFTWARE_RESET, &val);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret);
+               return ret;
+       }
+
+       if (val != 0x1801) {
+               dev_err(&i2c->dev, "Device is not a WM8961: ID=0x%x\n", val);
+               return -EINVAL;
+       }
+
+       /* This isn't volatile - readback doesn't correspond to write */
+       regcache_cache_bypass(wm8961->regmap, true);
+       ret = regmap_read(wm8961->regmap, WM8961_RIGHT_INPUT_VOLUME, &val);
+       regcache_cache_bypass(wm8961->regmap, false);
+
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to read chip revision: %d\n", ret);
+               return ret;
+       }
+
+       dev_info(&i2c->dev, "WM8961 family %d revision %c\n",
+                (val & WM8961_DEVICE_ID_MASK) >> WM8961_DEVICE_ID_SHIFT,
+                ((val & WM8961_CHIP_REV_MASK) >> WM8961_CHIP_REV_SHIFT)
+                + 'A');
+
+       ret = regmap_write(wm8961->regmap, WM8961_SOFTWARE_RESET, 0x1801);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret);
+               return ret;
+       }
+
        i2c_set_clientdata(i2c, wm8961);
 
        ret = snd_soc_register_codec(&i2c->dev,
@@ -1114,23 +1016,7 @@ static struct i2c_driver wm8961_i2c_driver = {
        .id_table = wm8961_i2c_id,
 };
 
-static int __init wm8961_modinit(void)
-{
-       int ret = 0;
-       ret = i2c_add_driver(&wm8961_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register wm8961 I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(wm8961_modinit);
-
-static void __exit wm8961_exit(void)
-{
-       i2c_del_driver(&wm8961_i2c_driver);
-}
-module_exit(wm8961_exit);
+module_i2c_driver(wm8961_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8961 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
index eef783f6b6d6849aa014296a9afea6b5743adfca..5ce6477584438b3a8555bada53f8e17c1dd7cc5e 100644 (file)
@@ -721,23 +721,7 @@ static struct i2c_driver wm8971_i2c_driver = {
        .id_table = wm8971_i2c_id,
 };
 
-static int __init wm8971_modinit(void)
-{
-       int ret = 0;
-       ret = i2c_add_driver(&wm8971_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8971 I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(wm8971_modinit);
-
-static void __exit wm8971_exit(void)
-{
-       i2c_del_driver(&wm8971_i2c_driver);
-}
-module_exit(wm8971_exit);
+module_i2c_driver(wm8971_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8971 driver");
 MODULE_AUTHOR("Lab126");
index d93c03f820c9e802f87d2cfcd0fb7357d7b9fa15..9a39511af52ad180bda356d210a7594de1c3f80f 100644 (file)
@@ -659,23 +659,7 @@ static struct i2c_driver wm8974_i2c_driver = {
        .id_table = wm8974_i2c_id,
 };
 
-static int __init wm8974_modinit(void)
-{
-       int ret = 0;
-       ret = i2c_add_driver(&wm8974_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register wm8974 I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(wm8974_modinit);
-
-static void __exit wm8974_exit(void)
-{
-       i2c_del_driver(&wm8974_i2c_driver);
-}
-module_exit(wm8974_exit);
+module_i2c_driver(wm8974_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8974 driver");
 MODULE_AUTHOR("Liam Girdwood");
index a5be3adecf7572bed47d4ed99b59f6fbf87fbed8..5421fd9fbcb5d37954e77f88962c31e9d953e2dc 100644 (file)
@@ -1105,23 +1105,7 @@ static struct i2c_driver wm8978_i2c_driver = {
        .id_table = wm8978_i2c_id,
 };
 
-static int __init wm8978_modinit(void)
-{
-       int ret = 0;
-       ret = i2c_add_driver(&wm8978_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8978 I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(wm8978_modinit);
-
-static void __exit wm8978_exit(void)
-{
-       i2c_del_driver(&wm8978_i2c_driver);
-}
-module_exit(wm8978_exit);
+module_i2c_driver(wm8978_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8978 codec driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
index 367388fdc486484202e4bb550420bdcda31a8fdf..d8879f262d2762dcf860db46388961ed84063f33 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 
 #include "wm8983.h"
 
-static const u16 wm8983_reg_defs[WM8983_MAX_REGISTER + 1] = {
-       [0x00] = 0x0000,     /* R0  - Software Reset */
-       [0x01] = 0x0000,     /* R1  - Power management 1 */
-       [0x02] = 0x0000,     /* R2  - Power management 2 */
-       [0x03] = 0x0000,     /* R3  - Power management 3 */
-       [0x04] = 0x0050,     /* R4  - Audio Interface */
-       [0x05] = 0x0000,     /* R5  - Companding control */
-       [0x06] = 0x0140,     /* R6  - Clock Gen control */
-       [0x07] = 0x0000,     /* R7  - Additional control */
-       [0x08] = 0x0000,     /* R8  - GPIO Control */
-       [0x09] = 0x0000,     /* R9  - Jack Detect Control 1 */
-       [0x0A] = 0x0000,     /* R10 - DAC Control */
-       [0x0B] = 0x00FF,     /* R11 - Left DAC digital Vol */
-       [0x0C] = 0x00FF,     /* R12 - Right DAC digital vol */
-       [0x0D] = 0x0000,     /* R13 - Jack Detect Control 2 */
-       [0x0E] = 0x0100,     /* R14 - ADC Control */
-       [0x0F] = 0x00FF,     /* R15 - Left ADC Digital Vol */
-       [0x10] = 0x00FF,     /* R16 - Right ADC Digital Vol */
-       [0x12] = 0x012C,     /* R18 - EQ1 - low shelf */
-       [0x13] = 0x002C,     /* R19 - EQ2 - peak 1 */
-       [0x14] = 0x002C,     /* R20 - EQ3 - peak 2 */
-       [0x15] = 0x002C,     /* R21 - EQ4 - peak 3 */
-       [0x16] = 0x002C,     /* R22 - EQ5 - high shelf */
-       [0x18] = 0x0032,     /* R24 - DAC Limiter 1 */
-       [0x19] = 0x0000,     /* R25 - DAC Limiter 2 */
-       [0x1B] = 0x0000,     /* R27 - Notch Filter 1 */
-       [0x1C] = 0x0000,     /* R28 - Notch Filter 2 */
-       [0x1D] = 0x0000,     /* R29 - Notch Filter 3 */
-       [0x1E] = 0x0000,     /* R30 - Notch Filter 4 */
-       [0x20] = 0x0038,     /* R32 - ALC control 1 */
-       [0x21] = 0x000B,     /* R33 - ALC control 2 */
-       [0x22] = 0x0032,     /* R34 - ALC control 3 */
-       [0x23] = 0x0000,     /* R35 - Noise Gate */
-       [0x24] = 0x0008,     /* R36 - PLL N */
-       [0x25] = 0x000C,     /* R37 - PLL K 1 */
-       [0x26] = 0x0093,     /* R38 - PLL K 2 */
-       [0x27] = 0x00E9,     /* R39 - PLL K 3 */
-       [0x29] = 0x0000,     /* R41 - 3D control */
-       [0x2A] = 0x0000,     /* R42 - OUT4 to ADC */
-       [0x2B] = 0x0000,     /* R43 - Beep control */
-       [0x2C] = 0x0033,     /* R44 - Input ctrl */
-       [0x2D] = 0x0010,     /* R45 - Left INP PGA gain ctrl */
-       [0x2E] = 0x0010,     /* R46 - Right INP PGA gain ctrl */
-       [0x2F] = 0x0100,     /* R47 - Left ADC BOOST ctrl */
-       [0x30] = 0x0100,     /* R48 - Right ADC BOOST ctrl */
-       [0x31] = 0x0002,     /* R49 - Output ctrl */
-       [0x32] = 0x0001,     /* R50 - Left mixer ctrl */
-       [0x33] = 0x0001,     /* R51 - Right mixer ctrl */
-       [0x34] = 0x0039,     /* R52 - LOUT1 (HP) volume ctrl */
-       [0x35] = 0x0039,     /* R53 - ROUT1 (HP) volume ctrl */
-       [0x36] = 0x0039,     /* R54 - LOUT2 (SPK) volume ctrl */
-       [0x37] = 0x0039,     /* R55 - ROUT2 (SPK) volume ctrl */
-       [0x38] = 0x0001,     /* R56 - OUT3 mixer ctrl */
-       [0x39] = 0x0001,     /* R57 - OUT4 (MONO) mix ctrl */
-       [0x3D] = 0x0000      /* R61 - BIAS CTRL */
+static const struct reg_default wm8983_defaults[] = {
+       { 0x01, 0x0000 },     /* R1  - Power management 1 */
+       { 0x02, 0x0000 },     /* R2  - Power management 2 */
+       { 0x03, 0x0000 },     /* R3  - Power management 3 */
+       { 0x04, 0x0050 },     /* R4  - Audio Interface */
+       { 0x05, 0x0000 },     /* R5  - Companding control */
+       { 0x06, 0x0140 },     /* R6  - Clock Gen control */
+       { 0x07, 0x0000 },     /* R7  - Additional control */
+       { 0x08, 0x0000 },     /* R8  - GPIO Control */
+       { 0x09, 0x0000 },     /* R9  - Jack Detect Control 1 */
+       { 0x0A, 0x0000 },     /* R10 - DAC Control */
+       { 0x0B, 0x00FF },     /* R11 - Left DAC digital Vol */
+       { 0x0C, 0x00FF },     /* R12 - Right DAC digital vol */
+       { 0x0D, 0x0000 },     /* R13 - Jack Detect Control 2 */
+       { 0x0E, 0x0100 },     /* R14 - ADC Control */
+       { 0x0F, 0x00FF },     /* R15 - Left ADC Digital Vol */
+       { 0x10, 0x00FF },     /* R16 - Right ADC Digital Vol */
+       { 0x12, 0x012C },     /* R18 - EQ1 - low shelf */
+       { 0x13, 0x002C },     /* R19 - EQ2 - peak 1 */
+       { 0x14, 0x002C },     /* R20 - EQ3 - peak 2 */
+       { 0x15, 0x002C },     /* R21 - EQ4 - peak 3 */
+       { 0x16, 0x002C },     /* R22 - EQ5 - high shelf */
+       { 0x18, 0x0032 },     /* R24 - DAC Limiter 1 */
+       { 0x19, 0x0000 },     /* R25 - DAC Limiter 2 */
+       { 0x1B, 0x0000 },     /* R27 - Notch Filter 1 */
+       { 0x1C, 0x0000 },     /* R28 - Notch Filter 2 */
+       { 0x1D, 0x0000 },     /* R29 - Notch Filter 3 */
+       { 0x1E, 0x0000 },     /* R30 - Notch Filter 4 */
+       { 0x20, 0x0038 },     /* R32 - ALC control 1 */
+       { 0x21, 0x000B },     /* R33 - ALC control 2 */
+       { 0x22, 0x0032 },     /* R34 - ALC control 3 */
+       { 0x23, 0x0000 },     /* R35 - Noise Gate */
+       { 0x24, 0x0008 },     /* R36 - PLL N */
+       { 0x25, 0x000C },     /* R37 - PLL K 1 */
+       { 0x26, 0x0093 },     /* R38 - PLL K 2 */
+       { 0x27, 0x00E9 },     /* R39 - PLL K 3 */
+       { 0x29, 0x0000 },     /* R41 - 3D control */
+       { 0x2A, 0x0000 },     /* R42 - OUT4 to ADC */
+       { 0x2B, 0x0000 },     /* R43 - Beep control */
+       { 0x2C, 0x0033 },     /* R44 - Input ctrl */
+       { 0x2D, 0x0010 },     /* R45 - Left INP PGA gain ctrl */
+       { 0x2E, 0x0010 },     /* R46 - Right INP PGA gain ctrl */
+       { 0x2F, 0x0100 },     /* R47 - Left ADC BOOST ctrl */
+       { 0x30, 0x0100 },     /* R48 - Right ADC BOOST ctrl */
+       { 0x31, 0x0002 },     /* R49 - Output ctrl */
+       { 0x32, 0x0001 },     /* R50 - Left mixer ctrl */
+       { 0x33, 0x0001 },     /* R51 - Right mixer ctrl */
+       { 0x34, 0x0039 },     /* R52 - LOUT1 (HP) volume ctrl */
+       { 0x35, 0x0039 },     /* R53 - ROUT1 (HP) volume ctrl */
+       { 0x36, 0x0039 },     /* R54 - LOUT2 (SPK) volume ctrl */
+       { 0x37, 0x0039 },     /* R55 - ROUT2 (SPK) volume ctrl */
+       { 0x38, 0x0001 },     /* R56 - OUT3 mixer ctrl */
+       { 0x39, 0x0001 },     /* R57 - OUT4 (MONO) mix ctrl */
+       { 0x3D, 0x0000 },      /* R61 - BIAS CTRL */
 };
 
 static const struct wm8983_reg_access {
@@ -159,7 +159,7 @@ static const int vol_update_regs[] = {
 };
 
 struct wm8983_priv {
-       enum snd_soc_control_type control_type;
+       struct regmap *regmap;
        u32 sysclk;
        u32 bclk;
 };
@@ -610,7 +610,7 @@ static int eqmode_put(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static int wm8983_readable(struct snd_soc_codec *codec, unsigned int reg)
+static bool wm8983_readable(struct device *dev, unsigned int reg)
 {
        if (reg > WM8983_MAX_REGISTER)
                return 0;
@@ -905,6 +905,7 @@ static int wm8983_set_sysclk(struct snd_soc_dai *dai,
 static int wm8983_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
+       struct wm8983_priv *wm8983 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
        switch (level) {
@@ -917,7 +918,7 @@ static int wm8983_set_bias_level(struct snd_soc_codec *codec,
                break;
        case SND_SOC_BIAS_STANDBY:
                if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
-                       ret = snd_soc_cache_sync(codec);
+                       ret = regcache_sync(wm8983->regmap);
                        if (ret < 0) {
                                dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
                                return ret;
@@ -994,10 +995,9 @@ static int wm8983_remove(struct snd_soc_codec *codec)
 static int wm8983_probe(struct snd_soc_codec *codec)
 {
        int ret;
-       struct wm8983_priv *wm8983 = snd_soc_codec_get_drvdata(codec);
        int i;
 
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8983->control_type);
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
                return ret;
@@ -1067,16 +1067,23 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8983 = {
        .suspend = wm8983_suspend,
        .resume = wm8983_resume,
        .set_bias_level = wm8983_set_bias_level,
-       .reg_cache_size = ARRAY_SIZE(wm8983_reg_defs),
-       .reg_word_size = sizeof(u16),
-       .reg_cache_default = wm8983_reg_defs,
        .controls = wm8983_snd_controls,
        .num_controls = ARRAY_SIZE(wm8983_snd_controls),
        .dapm_widgets = wm8983_dapm_widgets,
        .num_dapm_widgets = ARRAY_SIZE(wm8983_dapm_widgets),
        .dapm_routes = wm8983_audio_map,
        .num_dapm_routes = ARRAY_SIZE(wm8983_audio_map),
-       .readable_register = wm8983_readable
+};
+
+static const struct regmap_config wm8983_regmap = {
+       .reg_bits = 7,
+       .val_bits = 9,
+
+       .reg_defaults = wm8983_defaults,
+       .num_reg_defaults = ARRAY_SIZE(wm8983_defaults),
+       .cache_type = REGCACHE_RBTREE,
+
+       .readable_reg = wm8983_readable,
 };
 
 #if defined(CONFIG_SPI_MASTER)
@@ -1085,24 +1092,27 @@ static int __devinit wm8983_spi_probe(struct spi_device *spi)
        struct wm8983_priv *wm8983;
        int ret;
 
-       wm8983 = kzalloc(sizeof *wm8983, GFP_KERNEL);
+       wm8983 = devm_kzalloc(&spi->dev, sizeof *wm8983, GFP_KERNEL);
        if (!wm8983)
                return -ENOMEM;
 
-       wm8983->control_type = SND_SOC_SPI;
+       wm8983->regmap = devm_regmap_init_spi(spi, &wm8983_regmap);
+       if (IS_ERR(wm8983->regmap)) {
+               ret = PTR_ERR(wm8983->regmap);
+               dev_err(&spi->dev, "Failed to init regmap: %d\n", ret);
+               return ret;
+       }
+
        spi_set_drvdata(spi, wm8983);
 
        ret = snd_soc_register_codec(&spi->dev,
                                     &soc_codec_dev_wm8983, &wm8983_dai, 1);
-       if (ret < 0)
-               kfree(wm8983);
        return ret;
 }
 
 static int __devexit wm8983_spi_remove(struct spi_device *spi)
 {
        snd_soc_unregister_codec(&spi->dev);
-       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
@@ -1123,24 +1133,28 @@ static __devinit int wm8983_i2c_probe(struct i2c_client *i2c,
        struct wm8983_priv *wm8983;
        int ret;
 
-       wm8983 = kzalloc(sizeof *wm8983, GFP_KERNEL);
+       wm8983 = devm_kzalloc(&i2c->dev, sizeof *wm8983, GFP_KERNEL);
        if (!wm8983)
                return -ENOMEM;
 
-       wm8983->control_type = SND_SOC_I2C;
+       wm8983->regmap = devm_regmap_init_i2c(i2c, &wm8983_regmap);
+       if (IS_ERR(wm8983->regmap)) {
+               ret = PTR_ERR(wm8983->regmap);
+               dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
+               return ret;
+       }
+
        i2c_set_clientdata(i2c, wm8983);
 
        ret = snd_soc_register_codec(&i2c->dev,
                                     &soc_codec_dev_wm8983, &wm8983_dai, 1);
-       if (ret < 0)
-               kfree(wm8983);
+
        return ret;
 }
 
 static __devexit int wm8983_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
index db63c97ddf5160afe74c8b2bcd9f9f1d28c27273..c28c83e5395d93d76288bebd356df1abdf791f49 100644 (file)
@@ -1388,7 +1388,8 @@ static __devinit int wm8990_i2c_probe(struct i2c_client *i2c,
        struct wm8990_priv *wm8990;
        int ret;
 
-       wm8990 = kzalloc(sizeof(struct wm8990_priv), GFP_KERNEL);
+       wm8990 = devm_kzalloc(&i2c->dev, sizeof(struct wm8990_priv),
+                             GFP_KERNEL);
        if (wm8990 == NULL)
                return -ENOMEM;
 
@@ -1396,15 +1397,14 @@ static __devinit int wm8990_i2c_probe(struct i2c_client *i2c,
 
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_wm8990, &wm8990_dai, 1);
-       if (ret < 0)
-               kfree(wm8990);
+
        return ret;
 }
 
 static __devexit int wm8990_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
+
        return 0;
 }
 
index 9ac31ba9b82e1ad635167baa38563da16d1e6ee2..fe439f027e102b9274883a9a879dc5cf320bb6a1 100644 (file)
@@ -1363,7 +1363,7 @@ static __devinit int wm8991_i2c_probe(struct i2c_client *i2c,
        struct wm8991_priv *wm8991;
        int ret;
 
-       wm8991 = kzalloc(sizeof *wm8991, GFP_KERNEL);
+       wm8991 = devm_kzalloc(&i2c->dev, sizeof(*wm8991), GFP_KERNEL);
        if (!wm8991)
                return -ENOMEM;
 
@@ -1372,15 +1372,14 @@ static __devinit int wm8991_i2c_probe(struct i2c_client *i2c,
 
        ret = snd_soc_register_codec(&i2c->dev,
                                     &soc_codec_dev_wm8991, &wm8991_dai, 1);
-       if (ret < 0)
-               kfree(wm8991);
+
        return ret;
 }
 
 static __devexit int wm8991_i2c_remove(struct i2c_client *client)
 {
        snd_soc_unregister_codec(&client->dev);
-       kfree(i2c_get_clientdata(client));
+
        return 0;
 }
 
@@ -1400,23 +1399,7 @@ static struct i2c_driver wm8991_i2c_driver = {
        .id_table = wm8991_i2c_id,
 };
 
-static int __init wm8991_modinit(void)
-{
-       int ret;
-       ret = i2c_add_driver(&wm8991_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8991 I2C driver: %d\n",
-                      ret);
-       }
-       return 0;
-}
-module_init(wm8991_modinit);
-
-static void __exit wm8991_exit(void)
-{
-       i2c_del_driver(&wm8991_i2c_driver);
-}
-module_exit(wm8991_exit);
+module_i2c_driver(wm8991_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8991 driver");
 MODULE_AUTHOR("Graeme Gregory");
index 9fd80d688979c2043326b03a40f3da1c4e220189..94737a30716b7acf9fd47382b09f461c6a5ffec0 100644 (file)
@@ -1520,6 +1520,8 @@ static int wm8993_probe(struct snd_soc_codec *codec)
                                      wm8993->pdata.lineout2fb,
                                      wm8993->pdata.jd_scthr,
                                      wm8993->pdata.jd_thr,
+                                     wm8993->pdata.micbias1_delay,
+                                     wm8993->pdata.micbias2_delay,
                                      wm8993->pdata.micbias1_lvl,
                                      wm8993->pdata.micbias2_lvl);
 
index 6c9eeca85b952278f375ff9bb21faee1e33ec06a..2b2dadc54dac5cfe729ddc2fd402e748195a6882 100644 (file)
@@ -671,6 +671,18 @@ SOC_SINGLE_TLV("AIF2 EQ5 Volume", WM8994_AIF2_EQ_GAINS_2, 6, 31, 0,
               eq_tlv),
 };
 
+static const struct snd_kcontrol_new wm8994_drc_controls[] = {
+SND_SOC_BYTES_MASK("AIF1.1 DRC", WM8994_AIF1_DRC1_1, 5,
+                  WM8994_AIF1DAC1_DRC_ENA | WM8994_AIF1ADC1L_DRC_ENA |
+                  WM8994_AIF1ADC1R_DRC_ENA),
+SND_SOC_BYTES_MASK("AIF1.2 DRC", WM8994_AIF1_DRC2_1, 5,
+                  WM8994_AIF1DAC2_DRC_ENA | WM8994_AIF1ADC2L_DRC_ENA |
+                  WM8994_AIF1ADC2R_DRC_ENA),
+SND_SOC_BYTES_MASK("AIF2 DRC", WM8994_AIF2_DRC_1, 5,
+                  WM8994_AIF2DAC_DRC_ENA | WM8994_AIF2ADCL_DRC_ENA |
+                  WM8994_AIF2ADCR_DRC_ENA),
+};
+
 static const char *wm8958_ng_text[] = {
        "30ms", "125ms", "250ms", "500ms",
 };
@@ -789,11 +801,27 @@ 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 wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
                return configure_clock(codec);
 
+       case SND_SOC_DAPM_POST_PMU:
+               /*
+                * JACKDET won't run until we start the clock and it
+                * only reports deltas, make sure we notify the state
+                * up the stack on startup.  Use a *very* generous
+                * timeout for paranoia, there's no urgency and we
+                * don't want false reports.
+                */
+               if (wm8994->jackdet && !wm8994->clk_has_run) {
+                       schedule_delayed_work(&wm8994->jackdet_bootstrap,
+                                             msecs_to_jiffies(1000));
+                       wm8994->clk_has_run = true;
+               }
+               break;
+
        case SND_SOC_DAPM_POST_PMD:
                configure_clock(codec);
                break;
@@ -1632,7 +1660,8 @@ SND_SOC_DAPM_SUPPLY("VMID", SND_SOC_NOPM, 0, 0, vmid_event,
                    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
 SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event,
-                   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                   SND_SOC_DAPM_PRE_PMD),
 
 SND_SOC_DAPM_SUPPLY("DSP1CLK", SND_SOC_NOPM, 3, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("DSP2CLK", SND_SOC_NOPM, 2, 0, NULL, 0),
@@ -2102,6 +2131,10 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
        case WM8994_FLL_SRC_LRCLK:
        case WM8994_FLL_SRC_BCLK:
                break;
+       case WM8994_FLL_SRC_INTERNAL:
+               freq_in = 12000000;
+               freq_out = 12000000;
+               break;
        default:
                return -EINVAL;
        }
@@ -2161,12 +2194,14 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
 
        snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_4 + reg_offset,
                            WM8994_FLL1_N_MASK,
-                                   fll.n << WM8994_FLL1_N_SHIFT);
+                           fll.n << WM8994_FLL1_N_SHIFT);
 
        snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
-                           WM8958_FLL1_BYP |
+                           WM8994_FLL1_FRC_NCO | WM8958_FLL1_BYP |
                            WM8994_FLL1_REFCLK_DIV_MASK |
                            WM8994_FLL1_REFCLK_SRC_MASK,
+                           ((src == WM8994_FLL_SRC_INTERNAL)
+                            << WM8994_FLL1_FRC_NCO_SHIFT) |
                            (fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) |
                            (src - 1));
 
@@ -2192,13 +2227,16 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                        }
                }
 
+               reg = WM8994_FLL1_ENA;
+
                if (fll.k)
-                       reg = WM8994_FLL1_ENA | WM8994_FLL1_FRAC;
-               else
-                       reg = WM8994_FLL1_ENA;
+                       reg |= WM8994_FLL1_FRAC;
+               if (src == WM8994_FLL_SRC_INTERNAL)
+                       reg |= WM8994_FLL1_OSC_ENA;
+
                snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset,
-                                   WM8994_FLL1_ENA | WM8994_FLL1_FRAC,
-                                   reg);
+                                   WM8994_FLL1_ENA | WM8994_FLL1_OSC_ENA |
+                                   WM8994_FLL1_FRAC, reg);
 
                if (wm8994->fll_locked_irq) {
                        timeout = wait_for_completion_timeout(&wm8994->fll_locked[id],
@@ -3027,7 +3065,7 @@ static int wm8994_codec_resume(struct snd_soc_codec *codec)
 
 static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
 {
-       struct snd_soc_codec *codec = wm8994->codec;
+       struct snd_soc_codec *codec = wm8994->hubs.codec;
        struct wm8994_pdata *pdata = wm8994->pdata;
        struct snd_kcontrol_new controls[] = {
                SOC_ENUM_EXT("AIF1.1 EQ Mode",
@@ -3085,16 +3123,16 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
        wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts;
        wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts;
 
-       ret = snd_soc_add_codec_controls(wm8994->codec, controls,
+       ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls,
                                   ARRAY_SIZE(controls));
        if (ret != 0)
-               dev_err(wm8994->codec->dev,
+               dev_err(wm8994->hubs.codec->dev,
                        "Failed to add ReTune Mobile controls: %d\n", ret);
 }
 
 static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
 {
-       struct snd_soc_codec *codec = wm8994->codec;
+       struct snd_soc_codec *codec = wm8994->hubs.codec;
        struct wm8994_pdata *pdata = wm8994->pdata;
        int ret, i;
 
@@ -3107,6 +3145,8 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
                                      pdata->lineout2fb,
                                      pdata->jd_scthr,
                                      pdata->jd_thr,
+                                     pdata->micb1_delay,
+                                     pdata->micb2_delay,
                                      pdata->micbias1_lvl,
                                      pdata->micbias2_lvl);
 
@@ -3123,10 +3163,10 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
                };
 
                /* We need an array of texts for the enum API */
-               wm8994->drc_texts = devm_kzalloc(wm8994->codec->dev,
+               wm8994->drc_texts = devm_kzalloc(wm8994->hubs.codec->dev,
                            sizeof(char *) * pdata->num_drc_cfgs, GFP_KERNEL);
                if (!wm8994->drc_texts) {
-                       dev_err(wm8994->codec->dev,
+                       dev_err(wm8994->hubs.codec->dev,
                                "Failed to allocate %d DRC config texts\n",
                                pdata->num_drc_cfgs);
                        return;
@@ -3138,23 +3178,28 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
                wm8994->drc_enum.max = pdata->num_drc_cfgs;
                wm8994->drc_enum.texts = wm8994->drc_texts;
 
-               ret = snd_soc_add_codec_controls(wm8994->codec, controls,
+               ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls,
                                           ARRAY_SIZE(controls));
-               if (ret != 0)
-                       dev_err(wm8994->codec->dev,
-                               "Failed to add DRC mode controls: %d\n", ret);
-
                for (i = 0; i < WM8994_NUM_DRC; i++)
                        wm8994_set_drc(codec, i);
+       } else {
+               ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
+                                                wm8994_drc_controls,
+                                                ARRAY_SIZE(wm8994_drc_controls));
        }
 
+       if (ret != 0)
+               dev_err(wm8994->hubs.codec->dev,
+                       "Failed to add DRC mode controls: %d\n", ret);
+
+
        dev_dbg(codec->dev, "%d ReTune Mobile configurations\n",
                pdata->num_retune_mobile_cfgs);
 
        if (pdata->num_retune_mobile_cfgs)
                wm8994_handle_retune_mobile_pdata(wm8994);
        else
-               snd_soc_add_codec_controls(wm8994->codec, wm8994_eq_controls,
+               snd_soc_add_codec_controls(wm8994->hubs.codec, wm8994_eq_controls,
                                     ARRAY_SIZE(wm8994_eq_controls));
 
        for (i = 0; i < ARRAY_SIZE(pdata->micbias); i++) {
@@ -3236,6 +3281,12 @@ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
 
        snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, reg);
 
+       /* enable MICDET and MICSHRT deboune */
+       snd_soc_update_bits(codec, WM8994_IRQ_DEBOUNCE,
+                           WM8994_MIC1_DET_DB_MASK | WM8994_MIC1_SHRT_DB_MASK |
+                           WM8994_MIC2_DET_DB_MASK | WM8994_MIC2_SHRT_DB_MASK,
+                           WM8994_MIC1_DET_DB | WM8994_MIC1_SHRT_DB);
+
        snd_soc_dapm_sync(&codec->dapm);
 
        return 0;
@@ -3309,7 +3360,7 @@ static void wm8994_mic_work(struct work_struct *work)
 static irqreturn_t wm8994_mic_irq(int irq, void *data)
 {
        struct wm8994_priv *priv = data;
-       struct snd_soc_codec *codec = priv->codec;
+       struct snd_soc_codec *codec = priv->hubs.codec;
 
 #ifndef CONFIG_SND_SOC_WM8994_MODULE
        trace_snd_soc_jack_irq(dev_name(codec->dev));
@@ -3345,7 +3396,7 @@ static void wm8958_default_micdet(u16 status, void *data)
 
                        snd_soc_jack_report(wm8994->micdet[0].jack, 0,
                                            wm8994->btn_mask |
-                                            SND_JACK_HEADSET);
+                                           SND_JACK_HEADSET);
                }
                return;
        }
@@ -3422,7 +3473,7 @@ static void wm8958_default_micdet(u16 status, void *data)
 static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
 {
        struct wm8994_priv *wm8994 = data;
-       struct snd_soc_codec *codec = wm8994->codec;
+       struct snd_soc_codec *codec = wm8994->hubs.codec;
        int reg;
        bool present;
 
@@ -3499,10 +3550,22 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
                                    SND_JACK_MECHANICAL | SND_JACK_HEADSET |
                                    wm8994->btn_mask);
 
+       /* Since we only report deltas force an update, ensures we
+        * avoid bootstrapping issues with the core. */
+       snd_soc_jack_report(wm8994->micdet[0].jack, 0, 0);
+
        pm_runtime_put(codec->dev);
        return IRQ_HANDLED;
 }
 
+static void wm1811_jackdet_bootstrap(struct work_struct *work)
+{
+       struct wm8994_priv *wm8994 = container_of(work,
+                                               struct wm8994_priv,
+                                               jackdet_bootstrap.work);
+       wm1811_jackdet_irq(0, wm8994);
+}
+
 /**
  * wm8958_mic_detect - Enable microphone detection via the WM8958 IRQ
  *
@@ -3573,6 +3636,10 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
                 * otherwise jump straight to microphone detection.
                 */
                if (wm8994->jackdet) {
+                       /* Disable debounce for the initial detect */
+                       snd_soc_update_bits(codec, WM1811_JACKDET_CTRL,
+                                           WM1811_JACKDET_DB, 0);
+
                        snd_soc_update_bits(codec, WM8958_MICBIAS2,
                                            WM8958_MICB2_DISCH,
                                            WM8958_MICB2_DISCH);
@@ -3600,7 +3667,7 @@ EXPORT_SYMBOL_GPL(wm8958_mic_detect);
 static irqreturn_t wm8958_mic_irq(int irq, void *data)
 {
        struct wm8994_priv *wm8994 = data;
-       struct snd_soc_codec *codec = wm8994->codec;
+       struct snd_soc_codec *codec = wm8994->hubs.codec;
        int reg, count;
 
        /*
@@ -3690,15 +3757,15 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        unsigned int reg;
        int ret, i;
 
-       wm8994->codec = codec;
+       wm8994->hubs.codec = codec;
        codec->control_data = control->regmap;
 
        snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
 
-       wm8994->codec = codec;
-
        mutex_init(&wm8994->accdet_lock);
        INIT_DELAYED_WORK(&wm8994->mic_work, wm8994_mic_work);
+       INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap,
+                         wm1811_jackdet_bootstrap);
 
        for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
                init_completion(&wm8994->fll_locked[i]);
@@ -3756,14 +3823,17 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                wm8994->hubs.no_cache_dac_hp_direct = true;
                wm8994->fll_byp = true;
 
-               switch (wm8994->revision) {
+               switch (control->cust_id) {
                case 0:
-               case 1:
                case 2:
-               case 3:
                        wm8994->hubs.dcs_codes_l = -9;
                        wm8994->hubs.dcs_codes_r = -7;
                        break;
+               case 1:
+               case 3:
+                       wm8994->hubs.dcs_codes_l = -8;
+                       wm8994->hubs.dcs_codes_r = -7;
+                       break;
                default:
                        break;
                }
@@ -3852,7 +3922,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 
        switch (control->type) {
        case WM1811:
-               if (wm8994->revision > 1) {
+               if (control->cust_id > 1 || wm8994->revision > 1) {
                        ret = wm8994_request_irq(wm8994->wm8994,
                                                 WM8994_IRQ_GPIO(6),
                                                 wm1811_jackdet_irq, "JACKDET",
index d77e06f0a6751f7a1d4394b90324916b6085a34d..f142ec198db3dabfcfc5d1e20a51cdfd5e42874b 100644 (file)
 #define WM8994_FLL1 1
 #define WM8994_FLL2 2
 
-#define WM8994_FLL_SRC_MCLK1  1
-#define WM8994_FLL_SRC_MCLK2  2
-#define WM8994_FLL_SRC_LRCLK  3
-#define WM8994_FLL_SRC_BCLK   4
+#define WM8994_FLL_SRC_MCLK1    1
+#define WM8994_FLL_SRC_MCLK2    2
+#define WM8994_FLL_SRC_LRCLK    3
+#define WM8994_FLL_SRC_BCLK     4
+#define WM8994_FLL_SRC_INTERNAL 5
 
 enum wm8994_vmid_mode {
        WM8994_VMID_NORMAL,
@@ -72,7 +73,6 @@ struct wm8994;
 struct wm8994_priv {
        struct wm_hubs_data hubs;
        struct wm8994 *wm8994;
-       struct snd_soc_codec *codec;
        int sysclk[2];
        int sysclk_rate[2];
        int mclk[2];
@@ -81,6 +81,7 @@ struct wm8994_priv {
        struct completion fll_locked[2];
        bool fll_locked_irq;
        bool fll_byp;
+       bool clk_has_run;
 
        int vmid_refcount;
        int active_refcount;
@@ -134,6 +135,7 @@ struct wm8994_priv {
        int btn_mask;
        bool jackdet;
        int jackdet_mode;
+       struct delayed_work jackdet_bootstrap;
 
        wm8958_micdet_cb jack_cb;
        void *jack_cb_data;
index 00f183dfa454809f3e81a6e00fcfd3b17fc01d52..6dcb02c3666fc4e37f6763aa977dec746c15cbe0 100644 (file)
@@ -931,7 +931,7 @@ SND_SOC_DAPM_INPUT("IN2RP"),
 SND_SOC_DAPM_INPUT("DMIC1DAT"),
 SND_SOC_DAPM_INPUT("DMIC2DAT"),
 
-SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20),
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
 SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, WM8996_AIF_CLOCKING_1, 0, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY_S("SYSDSPCLK", 2, WM8996_CLOCKING_1, 1, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY_S("AIFCLK", 2, WM8996_CLOCKING_1, 2, 0, NULL, 0),
index 2c2346fdd6370a3e307bd75a2815c6fcb89379eb..c7ddc56175d12ad799f449a814db1432d341305f 100644 (file)
@@ -695,17 +695,7 @@ static struct i2c_driver wm9090_i2c_driver = {
        .id_table = wm9090_id,
 };
 
-static int __init wm9090_init(void)
-{
-       return i2c_add_driver(&wm9090_i2c_driver);
-}
-module_init(wm9090_init);
-
-static void __exit wm9090_exit(void)
-{
-       i2c_del_driver(&wm9090_i2c_driver);
-}
-module_exit(wm9090_exit);
+module_i2c_driver(wm9090_i2c_driver);
 
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 MODULE_DESCRIPTION("WM9090 ASoC driver");
index c6d2076a796bd9aecf510636a0339e76abed2dde..4dd73ea08d0b51287c8a394dd269798fc5dc8b06 100644 (file)
@@ -132,8 +132,9 @@ SOC_SINGLE("Aux Playback Phone Volume", AC97_CD, 4, 7, 1),
 SOC_SINGLE("Phone Volume", AC97_PHONE, 0, 15, 1),
 SOC_DOUBLE("Line Capture Volume", AC97_LINE, 8, 0, 31, 1),
 
-SOC_SINGLE("Capture 20dB Boost Switch", AC97_REC_SEL, 14, 1, 0),
-SOC_SINGLE("Capture to Phone 20dB Boost Switch", AC97_REC_SEL, 11, 1, 1),
+SOC_SINGLE_TLV("Capture Boost Switch", AC97_REC_SEL, 14, 1, 0, boost_tlv),
+SOC_SINGLE_TLV("Capture to Phone Boost Switch", AC97_REC_SEL, 11, 1, 1,
+              boost_tlv),
 
 SOC_SINGLE("3D Upper Cut-off Switch", AC97_3D_CONTROL, 5, 1, 1),
 SOC_SINGLE("3D Lower Cut-off Switch", AC97_3D_CONTROL, 4, 1, 1),
@@ -146,7 +147,7 @@ SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0),
 SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 1),
 SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 1),
 
-SOC_SINGLE("Capture ADC Switch", AC97_REC_GAIN, 15, 1, 1),
+SOC_SINGLE("Capture Switch", AC97_REC_GAIN, 15, 1, 1),
 SOC_ENUM("Capture Volume Steps", wm9712_enum[6]),
 SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 0),
 SOC_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0),
@@ -634,7 +635,6 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec)
 {
        int ret = 0;
 
-       codec->control_data = codec;    /* we don't use regmap! */
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0) {
                printk(KERN_ERR "wm9712: failed to register AC97 codec\n");
@@ -699,8 +699,8 @@ static int __devexit wm9712_remove(struct platform_device *pdev)
 
 static struct platform_driver wm9712_codec_driver = {
        .driver = {
-                       .name = "wm9712-codec",
-                       .owner = THIS_MODULE,
+               .name = "wm9712-codec",
+               .owner = THIS_MODULE,
        },
 
        .probe = wm9712_probe,
index d0b8a3287a8592af98dad706861fcb3b87460bbc..3eb19fb71d17209e0bccc071ed3f481471201276 100644 (file)
@@ -1196,7 +1196,6 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)
        if (wm9713 == NULL)
                return -ENOMEM;
        snd_soc_codec_set_drvdata(codec, wm9713);
-       codec->control_data = wm9713;   /* we don't use regmap! */
 
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0)
index 61baa48823cba20a7b8696824f333cb82bad2a1e..867ae97ddcec1b495ec061cd373410bc80272d0b 100644 (file)
@@ -199,15 +199,56 @@ static void wm_hubs_dcs_cache_set(struct snd_soc_codec *codec, u16 dcs_cfg)
        list_add_tail(&cache->list, &hubs->dcs_cache);
 }
 
+static void wm_hubs_read_dc_servo(struct snd_soc_codec *codec,
+                                 u16 *reg_l, u16 *reg_r)
+{
+       struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+       u16 dcs_reg, reg;
+
+       switch (hubs->dcs_readback_mode) {
+       case 2:
+               dcs_reg = WM8994_DC_SERVO_4E;
+               break;
+       case 1:
+               dcs_reg = WM8994_DC_SERVO_READBACK;
+               break;
+       default:
+               dcs_reg = WM8993_DC_SERVO_3;
+               break;
+       }
+
+       /* Different chips in the family support different readback
+        * methods.
+        */
+       switch (hubs->dcs_readback_mode) {
+       case 0:
+               *reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1)
+                       & WM8993_DCS_INTEG_CHAN_0_MASK;
+               *reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
+                       & WM8993_DCS_INTEG_CHAN_1_MASK;
+               break;
+       case 2:
+       case 1:
+               reg = snd_soc_read(codec, dcs_reg);
+               *reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
+                       >> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
+               *reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
+               break;
+       default:
+               WARN(1, "Unknown DCS readback method\n");
+               return;
+       }
+}
+
 /*
  * Startup calibration of the DC servo
  */
-static void calibrate_dc_servo(struct snd_soc_codec *codec)
+static void enable_dc_servo(struct snd_soc_codec *codec)
 {
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
        struct wm_hubs_dcs_cache *cache;
        s8 offset;
-       u16 reg, reg_l, reg_r, dcs_cfg, dcs_reg;
+       u16 reg_l, reg_r, dcs_cfg, dcs_reg;
 
        switch (hubs->dcs_readback_mode) {
        case 2:
@@ -245,27 +286,7 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
                                  WM8993_DCS_TRIG_STARTUP_1);
        }
 
-       /* Different chips in the family support different readback
-        * methods.
-        */
-       switch (hubs->dcs_readback_mode) {
-       case 0:
-               reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1)
-                       & WM8993_DCS_INTEG_CHAN_0_MASK;
-               reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
-                       & WM8993_DCS_INTEG_CHAN_1_MASK;
-               break;
-       case 2:
-       case 1:
-               reg = snd_soc_read(codec, dcs_reg);
-               reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
-                       >> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
-               reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
-               break;
-       default:
-               WARN(1, "Unknown DCS readback method\n");
-               return;
-       }
+       wm_hubs_read_dc_servo(codec, &reg_l, &reg_r);
 
        dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
 
@@ -276,12 +297,16 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
                        hubs->dcs_codes_l, hubs->dcs_codes_r);
 
                /* HPOUT1R */
-               offset = reg_r;
+               offset = (s8)reg_r;
+               dev_dbg(codec->dev, "DCS right %d->%d\n", offset,
+                       offset + hubs->dcs_codes_r);
                offset += hubs->dcs_codes_r;
                dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
 
                /* HPOUT1L */
-               offset = reg_l;
+               offset = (s8)reg_l;
+               dev_dbg(codec->dev, "DCS left %d->%d\n", offset,
+                       offset + hubs->dcs_codes_l);
                offset += hubs->dcs_codes_l;
                dcs_cfg |= (u8)offset;
 
@@ -535,7 +560,7 @@ static int hp_event(struct snd_soc_dapm_widget *w,
                snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
                                    WM8993_DCS_TIMER_PERIOD_01_MASK, 0);
 
-               calibrate_dc_servo(codec);
+               enable_dc_servo(codec);
 
                reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT |
                        WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT;
@@ -619,6 +644,28 @@ static int lineout_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
+static int micbias_event(struct snd_soc_dapm_widget *w,
+                        struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+
+       switch (w->shift) {
+       case WM8993_MICB1_ENA_SHIFT:
+               if (hubs->micb1_delay)
+                       msleep(hubs->micb1_delay);
+               break;
+       case WM8993_MICB2_ENA_SHIFT:
+               if (hubs->micb2_delay)
+                       msleep(hubs->micb2_delay);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 void wm_hubs_update_class_w(struct snd_soc_codec *codec)
 {
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
@@ -634,6 +681,11 @@ void wm_hubs_update_class_w(struct snd_soc_codec *codec)
 
        snd_soc_update_bits(codec, WM8993_CLASS_W_0,
                            WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ, enable);
+
+       snd_soc_write(codec, WM8993_LEFT_OUTPUT_VOLUME,
+                     snd_soc_read(codec, WM8993_LEFT_OUTPUT_VOLUME));
+       snd_soc_write(codec, WM8993_RIGHT_OUTPUT_VOLUME,
+                     snd_soc_read(codec, WM8993_RIGHT_OUTPUT_VOLUME));
 }
 EXPORT_SYMBOL_GPL(wm_hubs_update_class_w);
 
@@ -809,8 +861,10 @@ SND_SOC_DAPM_INPUT("IN1RP"),
 SND_SOC_DAPM_INPUT("IN2RN"),
 SND_SOC_DAPM_INPUT("IN2RP:VXRP"),
 
-SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0, NULL, 0),
-SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0,
+                   micbias_event, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0,
+                   micbias_event, SND_SOC_DAPM_POST_PMU),
 
 SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0,
                   in1l_pga, ARRAY_SIZE(in1l_pga)),
@@ -1112,6 +1166,8 @@ int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec,
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
        struct snd_soc_dapm_context *dapm = &codec->dapm;
 
+       hubs->codec = codec;
+
        INIT_LIST_HEAD(&hubs->dcs_cache);
        init_completion(&hubs->dcs_done);
 
@@ -1143,13 +1199,16 @@ EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_routes);
 int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec,
                                  int lineout1_diff, int lineout2_diff,
                                  int lineout1fb, int lineout2fb,
-                                 int jd_scthr, int jd_thr, int micbias1_lvl,
-                                 int micbias2_lvl)
+                                 int jd_scthr, int jd_thr,
+                                 int micbias1_delay, int micbias2_delay,
+                                 int micbias1_lvl, int micbias2_lvl)
 {
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
 
        hubs->lineout1_se = !lineout1_diff;
        hubs->lineout2_se = !lineout2_diff;
+       hubs->micb1_delay = micbias1_delay;
+       hubs->micb2_delay = micbias2_delay;
 
        if (!lineout1_diff)
                snd_soc_update_bits(codec, WM8993_LINE_MIXER1,
index da2dc899ce6d58df7a4f34bd6f589ead6e4b2f3f..24c763df21f970344f43c99c720b5c69865a625c 100644 (file)
@@ -36,6 +36,9 @@ struct wm_hubs_data {
        struct list_head dcs_cache;
        bool (*check_class_w_digital)(struct snd_soc_codec *);
 
+       int micb1_delay;
+       int micb2_delay;
+
        bool lineout1_se;
        bool lineout1n_ena;
        bool lineout1p_ena;
@@ -46,6 +49,8 @@ struct wm_hubs_data {
 
        bool dcs_done_irq;
        struct completion dcs_done;
+
+       struct snd_soc_codec *codec;
 };
 
 extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *);
@@ -54,6 +59,7 @@ extern int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *,
                                         int lineout1_diff, int lineout2_diff,
                                         int lineout1fb, int lineout2fb,
                                         int jd_scthr, int jd_thr,
+                                        int micbias1_dly, int micbias2_dly,
                                         int micbias1_lvl, int micbias2_lvl);
 
 extern irqreturn_t wm_hubs_dcs_done(int irq, void *data);
index 10a2d8c788b73a434af2de950fdf3a3ad3652091..6fac5af13298ffa2c64ebf5bad1b5fde6a0ac6f6 100644 (file)
 #include <asm/dma.h>
 #include <asm/mach-types.h>
 
-#include <mach/asp.h>
-#include <mach/edma.h>
-#include <mach/mux.h>
-
 #include "davinci-pcm.h"
 #include "davinci-i2s.h"
 #include "davinci-mcasp.h"
@@ -160,7 +156,7 @@ static struct snd_soc_dai_link dm6446_evm_dai = {
        .cpu_dai_name = "davinci-mcbsp",
        .codec_dai_name = "tlv320aic3x-hifi",
        .codec_name = "tlv320aic3x-codec.1-001b",
-       .platform_name = "davinci-pcm-audio",
+       .platform_name = "davinci-mcbsp",
        .init = evm_aic3x_init,
        .ops = &evm_ops,
 };
@@ -171,7 +167,7 @@ static struct snd_soc_dai_link dm355_evm_dai = {
        .cpu_dai_name = "davinci-mcbsp.1",
        .codec_dai_name = "tlv320aic3x-hifi",
        .codec_name = "tlv320aic3x-codec.1-001b",
-       .platform_name = "davinci-pcm-audio",
+       .platform_name = "davinci-mcbsp.1",
        .init = evm_aic3x_init,
        .ops = &evm_ops,
 };
@@ -185,14 +181,15 @@ static struct snd_soc_dai_link dm365_evm_dai = {
        .init = evm_aic3x_init,
        .codec_name = "tlv320aic3x-codec.1-0018",
        .ops = &evm_ops,
+       .platform_name = "davinci-mcbsp",
 #elif defined(CONFIG_SND_DM365_VOICE_CODEC)
        .name = "Voice Codec - CQ93VC",
        .stream_name = "CQ93",
        .cpu_dai_name = "davinci-vcif",
        .codec_dai_name = "cq93vc-hifi",
        .codec_name = "cq93vc-codec",
+       .platform_name = "davinci-vcif",
 #endif
-       .platform_name = "davinci-pcm-audio",
 };
 
 static struct snd_soc_dai_link dm6467_evm_dai[] = {
@@ -201,7 +198,7 @@ static struct snd_soc_dai_link dm6467_evm_dai[] = {
                .stream_name = "AIC3X",
                .cpu_dai_name= "davinci-mcasp.0",
                .codec_dai_name = "tlv320aic3x-hifi",
-               .platform_name ="davinci-pcm-audio",
+               .platform_name = "davinci-mcasp.0",
                .codec_name = "tlv320aic3x-codec.0-001a",
                .init = evm_aic3x_init,
                .ops = &evm_ops,
@@ -212,7 +209,7 @@ static struct snd_soc_dai_link dm6467_evm_dai[] = {
                .cpu_dai_name= "davinci-mcasp.1",
                .codec_dai_name = "dit-hifi",
                .codec_name = "spdif_dit",
-               .platform_name = "davinci-pcm-audio",
+               .platform_name = "davinci-mcasp.1",
                .ops = &evm_spdif_ops,
        },
 };
@@ -223,7 +220,7 @@ static struct snd_soc_dai_link da830_evm_dai = {
        .cpu_dai_name = "davinci-mcasp.1",
        .codec_dai_name = "tlv320aic3x-hifi",
        .codec_name = "tlv320aic3x-codec.1-0018",
-       .platform_name = "davinci-pcm-audio",
+       .platform_name = "davinci-mcasp.1",
        .init = evm_aic3x_init,
        .ops = &evm_ops,
 };
@@ -234,7 +231,7 @@ static struct snd_soc_dai_link da850_evm_dai = {
        .cpu_dai_name= "davinci-mcasp.0",
        .codec_dai_name = "tlv320aic3x-hifi",
        .codec_name = "tlv320aic3x-codec.1-0018",
-       .platform_name = "davinci-pcm-audio",
+       .platform_name = "davinci-mcasp.0",
        .init = evm_aic3x_init,
        .ops = &evm_ops,
 };
index 0a74b9587a2c089796f2e4f9f1ca933f15e1f12a..8218312071801bcafe3031fd308d70edd3bbd870 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/clk.h>
+#include <linux/platform_data/davinci_asp.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -23,8 +24,6 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 
-#include <mach/asp.h>
-
 #include "davinci-pcm.h"
 #include "davinci-i2s.h"
 
@@ -732,8 +731,16 @@ static int davinci_i2s_probe(struct platform_device *pdev)
        if (ret != 0)
                goto err_release_clk;
 
+       ret = davinci_soc_platform_register(&pdev->dev);
+       if (ret) {
+               dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
+               goto err_unregister_dai;
+       }
+
        return 0;
 
+err_unregister_dai:
+       snd_soc_unregister_dai(&pdev->dev);
 err_release_clk:
        clk_disable(dev->clk);
        clk_put(dev->clk);
@@ -745,6 +752,8 @@ static int davinci_i2s_remove(struct platform_device *pdev)
        struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev);
 
        snd_soc_unregister_dai(&pdev->dev);
+       davinci_soc_platform_unregister(&pdev->dev);
+
        clk_disable(dev->clk);
        clk_put(dev->clk);
        dev->clk = NULL;
index ce5e5cd254ddc395c6d08e8767228b4a6822668d..714e51e5be5bd2c7038f1965a74545a01c5a268c 100644 (file)
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/io.h>
-#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
 #define DAVINCI_MCASP_WFIFOSTS         (0x1014)
 #define DAVINCI_MCASP_RFIFOCTL         (0x1018)
 #define DAVINCI_MCASP_RFIFOSTS         (0x101C)
+#define MCASP_VER3_WFIFOCTL            (0x1000)
+#define MCASP_VER3_WFIFOSTS            (0x1004)
+#define MCASP_VER3_RFIFOCTL            (0x1008)
+#define MCASP_VER3_RFIFOSTS            (0x100C)
 
 /*
  * DAVINCI_MCASP_PWREMUMGT_REG - Power Down and Emulation Management
@@ -381,18 +388,36 @@ static void davinci_mcasp_start(struct davinci_audio_dev *dev, int stream)
 {
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
                if (dev->txnumevt) {    /* enable FIFO */
-                       mcasp_clr_bits(dev->base + DAVINCI_MCASP_WFIFOCTL,
+                       switch (dev->version) {
+                       case MCASP_VERSION_3:
+                               mcasp_clr_bits(dev->base + MCASP_VER3_WFIFOCTL,
                                                                FIFO_ENABLE);
-                       mcasp_set_bits(dev->base + DAVINCI_MCASP_WFIFOCTL,
+                               mcasp_set_bits(dev->base + MCASP_VER3_WFIFOCTL,
                                                                FIFO_ENABLE);
+                               break;
+                       default:
+                               mcasp_clr_bits(dev->base +
+                                       DAVINCI_MCASP_WFIFOCTL, FIFO_ENABLE);
+                               mcasp_set_bits(dev->base +
+                                       DAVINCI_MCASP_WFIFOCTL, FIFO_ENABLE);
+                       }
                }
                mcasp_start_tx(dev);
        } else {
                if (dev->rxnumevt) {    /* enable FIFO */
-                       mcasp_clr_bits(dev->base + DAVINCI_MCASP_RFIFOCTL,
+                       switch (dev->version) {
+                       case MCASP_VERSION_3:
+                               mcasp_clr_bits(dev->base + MCASP_VER3_RFIFOCTL,
                                                                FIFO_ENABLE);
-                       mcasp_set_bits(dev->base + DAVINCI_MCASP_RFIFOCTL,
+                               mcasp_set_bits(dev->base + MCASP_VER3_RFIFOCTL,
                                                                FIFO_ENABLE);
+                               break;
+                       default:
+                               mcasp_clr_bits(dev->base +
+                                       DAVINCI_MCASP_RFIFOCTL, FIFO_ENABLE);
+                               mcasp_set_bits(dev->base +
+                                       DAVINCI_MCASP_RFIFOCTL, FIFO_ENABLE);
+                       }
                }
                mcasp_start_rx(dev);
        }
@@ -413,14 +438,31 @@ static void mcasp_stop_tx(struct davinci_audio_dev *dev)
 static void davinci_mcasp_stop(struct davinci_audio_dev *dev, int stream)
 {
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               if (dev->txnumevt)      /* disable FIFO */
-                       mcasp_clr_bits(dev->base + DAVINCI_MCASP_WFIFOCTL,
+               if (dev->txnumevt) {    /* disable FIFO */
+                       switch (dev->version) {
+                       case MCASP_VERSION_3:
+                               mcasp_clr_bits(dev->base + MCASP_VER3_WFIFOCTL,
                                                                FIFO_ENABLE);
+                               break;
+                       default:
+                               mcasp_clr_bits(dev->base +
+                                       DAVINCI_MCASP_WFIFOCTL, FIFO_ENABLE);
+                       }
+               }
                mcasp_stop_tx(dev);
        } else {
-               if (dev->rxnumevt)      /* disable FIFO */
-                       mcasp_clr_bits(dev->base + DAVINCI_MCASP_RFIFOCTL,
+               if (dev->rxnumevt) {    /* disable FIFO */
+                       switch (dev->version) {
+                       case MCASP_VERSION_3:
+                               mcasp_clr_bits(dev->base + MCASP_VER3_RFIFOCTL,
                                                                FIFO_ENABLE);
+                       break;
+
+                       default:
+                               mcasp_clr_bits(dev->base +
+                                       DAVINCI_MCASP_RFIFOCTL, FIFO_ENABLE);
+                       }
+               }
                mcasp_stop_rx(dev);
        }
 }
@@ -619,20 +661,37 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)
                if (dev->txnumevt * tx_ser > 64)
                        dev->txnumevt = 1;
 
-               mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, tx_ser,
+               switch (dev->version) {
+               case MCASP_VERSION_3:
+                       mcasp_mod_bits(dev->base + MCASP_VER3_WFIFOCTL, tx_ser,
                                                                NUMDMA_MASK);
-               mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL,
+                       mcasp_mod_bits(dev->base + MCASP_VER3_WFIFOCTL,
                                ((dev->txnumevt * tx_ser) << 8), NUMEVT_MASK);
+                       break;
+               default:
+                       mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL,
+                                                       tx_ser, NUMDMA_MASK);
+                       mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL,
+                               ((dev->txnumevt * tx_ser) << 8), NUMEVT_MASK);
+               }
        }
 
        if (dev->rxnumevt && stream == SNDRV_PCM_STREAM_CAPTURE) {
                if (dev->rxnumevt * rx_ser > 64)
                        dev->rxnumevt = 1;
-
-               mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, rx_ser,
+               switch (dev->version) {
+               case MCASP_VERSION_3:
+                       mcasp_mod_bits(dev->base + MCASP_VER3_RFIFOCTL, rx_ser,
                                                                NUMDMA_MASK);
-               mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL,
+                       mcasp_mod_bits(dev->base + MCASP_VER3_RFIFOCTL,
                                ((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK);
+                       break;
+               default:
+                       mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL,
+                                                       rx_ser, NUMDMA_MASK);
+                       mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL,
+                               ((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK);
+               }
        }
 }
 
@@ -782,20 +841,17 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               if (!dev->clk_active) {
-                       clk_enable(dev->clk);
-                       dev->clk_active = 1;
-               }
+               ret = pm_runtime_get_sync(dev->dev);
+               if (IS_ERR_VALUE(ret))
+                       dev_err(dev->dev, "pm_runtime_get_sync() failed\n");
                davinci_mcasp_start(dev, substream->stream);
                break;
 
        case SNDRV_PCM_TRIGGER_SUSPEND:
                davinci_mcasp_stop(dev, substream->stream);
-               if (dev->clk_active) {
-                       clk_disable(dev->clk);
-                       dev->clk_active = 0;
-               }
-
+               ret = pm_runtime_put_sync(dev->dev);
+               if (IS_ERR_VALUE(ret))
+                       dev_err(dev->dev, "pm_runtime_put_sync() failed\n");
                break;
 
        case SNDRV_PCM_TRIGGER_STOP:
@@ -865,6 +921,118 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
 
 };
 
+static const struct of_device_id mcasp_dt_ids[] = {
+       {
+               .compatible = "ti,dm646x-mcasp-audio",
+               .data = (void *)MCASP_VERSION_1,
+       },
+       {
+               .compatible = "ti,da830-mcasp-audio",
+               .data = (void *)MCASP_VERSION_2,
+       },
+       {
+               .compatible = "ti,omap2-mcasp-audio",
+               .data = (void *)MCASP_VERSION_3,
+       },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mcasp_dt_ids);
+
+static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
+                                               struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct snd_platform_data *pdata = NULL;
+       const struct of_device_id *match =
+                       of_match_device(of_match_ptr(mcasp_dt_ids), &pdev->dev);
+
+       const u32 *of_serial_dir32;
+       u8 *of_serial_dir;
+       u32 val;
+       int i, ret = 0;
+
+       if (pdev->dev.platform_data) {
+               pdata = pdev->dev.platform_data;
+               return pdata;
+       } else if (match) {
+               pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+               if (!pdata) {
+                       ret = -ENOMEM;
+                       goto nodata;
+               }
+       } else {
+               /* control shouldn't reach here. something is wrong */
+               ret = -EINVAL;
+               goto nodata;
+       }
+
+       if (match->data)
+               pdata->version = (u8)((int)match->data);
+
+       ret = of_property_read_u32(np, "op-mode", &val);
+       if (ret >= 0)
+               pdata->op_mode = val;
+
+       ret = of_property_read_u32(np, "tdm-slots", &val);
+       if (ret >= 0)
+               pdata->tdm_slots = val;
+
+       ret = of_property_read_u32(np, "num-serializer", &val);
+       if (ret >= 0)
+               pdata->num_serializer = val;
+
+       of_serial_dir32 = of_get_property(np, "serial-dir", &val);
+       val /= sizeof(u32);
+       if (val != pdata->num_serializer) {
+               dev_err(&pdev->dev,
+                               "num-serializer(%d) != serial-dir size(%d)\n",
+                               pdata->num_serializer, val);
+               ret = -EINVAL;
+               goto nodata;
+       }
+
+       if (of_serial_dir32) {
+               of_serial_dir = devm_kzalloc(&pdev->dev,
+                                               (sizeof(*of_serial_dir) * val),
+                                               GFP_KERNEL);
+               if (!of_serial_dir) {
+                       ret = -ENOMEM;
+                       goto nodata;
+               }
+
+               for (i = 0; i < pdata->num_serializer; i++)
+                       of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]);
+
+               pdata->serial_dir = of_serial_dir;
+       }
+
+       ret = of_property_read_u32(np, "tx-num-evt", &val);
+       if (ret >= 0)
+               pdata->txnumevt = val;
+
+       ret = of_property_read_u32(np, "rx-num-evt", &val);
+       if (ret >= 0)
+               pdata->rxnumevt = val;
+
+       ret = of_property_read_u32(np, "sram-size-playback", &val);
+       if (ret >= 0)
+               pdata->sram_size_playback = val;
+
+       ret = of_property_read_u32(np, "sram-size-capture", &val);
+       if (ret >= 0)
+               pdata->sram_size_capture = val;
+
+       return  pdata;
+
+nodata:
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Error populating platform data, err %d\n",
+                       ret);
+               pdata = NULL;
+       }
+       return  pdata;
+}
+
 static int davinci_mcasp_probe(struct platform_device *pdev)
 {
        struct davinci_pcm_dma_params *dma_data;
@@ -873,11 +1041,22 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        struct davinci_audio_dev *dev;
        int ret;
 
+       if (!pdev->dev.platform_data && !pdev->dev.of_node) {
+               dev_err(&pdev->dev, "No platform data supplied\n");
+               return -EINVAL;
+       }
+
        dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_audio_dev),
                           GFP_KERNEL);
        if (!dev)
                return  -ENOMEM;
 
+       pdata = davinci_mcasp_set_pdata_from_of(pdev);
+       if (!pdata) {
+               dev_err(&pdev->dev, "no platform data\n");
+               return -EINVAL;
+       }
+
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!mem) {
                dev_err(&pdev->dev, "no mem resource?\n");
@@ -891,13 +1070,13 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
                return -EBUSY;
        }
 
-       pdata = pdev->dev.platform_data;
-       dev->clk = clk_get(&pdev->dev, NULL);
-       if (IS_ERR(dev->clk))
-               return -ENODEV;
+       pm_runtime_enable(&pdev->dev);
 
-       clk_enable(dev->clk);
-       dev->clk_active = 1;
+       ret = pm_runtime_get_sync(&pdev->dev);
+       if (IS_ERR_VALUE(ret)) {
+               dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n");
+               return ret;
+       }
 
        dev->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
        if (!dev->base) {
@@ -914,6 +1093,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        dev->version = pdata->version;
        dev->txnumevt = pdata->txnumevt;
        dev->rxnumevt = pdata->rxnumevt;
+       dev->dev = &pdev->dev;
 
        dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
        dma_data->asp_chan_q = pdata->asp_chan_q;
@@ -952,22 +1132,31 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 
        if (ret != 0)
                goto err_release_clk;
+
+       ret = davinci_soc_platform_register(&pdev->dev);
+       if (ret) {
+               dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
+               goto err_unregister_dai;
+       }
+
        return 0;
 
+err_unregister_dai:
+       snd_soc_unregister_dai(&pdev->dev);
 err_release_clk:
-       clk_disable(dev->clk);
-       clk_put(dev->clk);
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
        return ret;
 }
 
 static int davinci_mcasp_remove(struct platform_device *pdev)
 {
-       struct davinci_audio_dev *dev = dev_get_drvdata(&pdev->dev);
 
        snd_soc_unregister_dai(&pdev->dev);
-       clk_disable(dev->clk);
-       clk_put(dev->clk);
-       dev->clk = NULL;
+       davinci_soc_platform_unregister(&pdev->dev);
+
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
 
        return 0;
 }
@@ -978,6 +1167,7 @@ static struct platform_driver davinci_mcasp_driver = {
        .driver         = {
                .name   = "davinci-mcasp",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(mcasp_dt_ids),
        },
 };
 
index 4681acc636061300efe053f56e214fc0eff1b98b..0de9ed6ce038a8472aeb762d403fbf26d579bc24 100644 (file)
@@ -19,7 +19,8 @@
 #define DAVINCI_MCASP_H
 
 #include <linux/io.h>
-#include <mach/asp.h>
+#include <linux/platform_data/davinci_asp.h>
+
 #include "davinci-pcm.h"
 
 #define DAVINCI_MCASP_RATES    SNDRV_PCM_RATE_8000_96000
@@ -40,9 +41,8 @@ struct davinci_audio_dev {
        struct davinci_pcm_dma_params dma_params[2];
        void __iomem *base;
        int sample_rate;
-       struct clk *clk;
+       struct device *dev;
        unsigned int codec_fmt;
-       u8 clk_active;
 
        /* McASP specific data */
        int     tdm_slots;
index 97d77b298968fc714c4125fb48392afcd4bc60fe..93ea3bf567e1fd1835ff643ff4e73d67fecdce12 100644 (file)
@@ -23,7 +23,6 @@
 #include <sound/soc.h>
 
 #include <asm/dma.h>
-#include <mach/edma.h>
 #include <mach/sram.h>
 
 #include "davinci-pcm.h"
@@ -864,28 +863,17 @@ static struct snd_soc_platform_driver davinci_soc_platform = {
        .pcm_free =     davinci_pcm_free,
 };
 
-static int __devinit davinci_soc_platform_probe(struct platform_device *pdev)
+int davinci_soc_platform_register(struct device *dev)
 {
-       return snd_soc_register_platform(&pdev->dev, &davinci_soc_platform);
+       return snd_soc_register_platform(dev, &davinci_soc_platform);
 }
+EXPORT_SYMBOL_GPL(davinci_soc_platform_register);
 
-static int __devexit davinci_soc_platform_remove(struct platform_device *pdev)
+void davinci_soc_platform_unregister(struct device *dev)
 {
-       snd_soc_unregister_platform(&pdev->dev);
-       return 0;
+       snd_soc_unregister_platform(dev);
 }
-
-static struct platform_driver davinci_pcm_driver = {
-       .driver = {
-                       .name = "davinci-pcm-audio",
-                       .owner = THIS_MODULE,
-       },
-
-       .probe = davinci_soc_platform_probe,
-       .remove = __devexit_p(davinci_soc_platform_remove),
-};
-
-module_platform_driver(davinci_pcm_driver);
+EXPORT_SYMBOL_GPL(davinci_soc_platform_unregister);
 
 MODULE_AUTHOR("Vladimir Barinov");
 MODULE_DESCRIPTION("TI DAVINCI PCM DMA module");
index c0d6c9be4b4d605b12bdf6145a8fde5319cd2bf6..fc4d01cdd8c95c92b11694faece56d77fc648bd9 100644 (file)
@@ -12,9 +12,8 @@
 #ifndef _DAVINCI_PCM_H
 #define _DAVINCI_PCM_H
 
+#include <linux/platform_data/davinci_asp.h>
 #include <mach/edma.h>
-#include <mach/asp.h>
-
 
 struct davinci_pcm_dma_params {
        int channel;                    /* sync dma channel ID */
@@ -28,4 +27,7 @@ struct davinci_pcm_dma_params {
        unsigned int fifo_level;
 };
 
+int davinci_soc_platform_register(struct device *dev);
+void davinci_soc_platform_unregister(struct device *dev);
+
 #endif
index f71175b29e38fb26aeeb8d6c6e4a1a45af789db2..5be65aae7e0e538b552f9f4bf2bb99c9ed0ad3f8 100644 (file)
@@ -86,7 +86,7 @@ static struct snd_soc_dai_link sffsdr_dai = {
        .cpu_dai_name = "davinci-mcbsp",
        .codec_dai_name = "pcm3008-hifi",
        .codec_name = "pcm3008-codec",
-       .platform_name = "davinci-pcm-audio",
+       .platform_name = "davinci-mcbsp",
        .ops = &sffsdr_ops,
 };
 
index da030ff883d570683603ca041a636b634a42181c..07bde2e6f84ef1e789e9a5eefa0cd0d6ee222783 100644 (file)
@@ -240,12 +240,20 @@ static int davinci_vcif_probe(struct platform_device *pdev)
                return ret;
        }
 
+       ret = davinci_soc_platform_register(&pdev->dev);
+       if (ret) {
+               dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
+               snd_soc_unregister_dai(&pdev->dev);
+               return ret;
+       }
+
        return 0;
 }
 
 static int davinci_vcif_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_dai(&pdev->dev);
+       davinci_soc_platform_unregister(&pdev->dev);
 
        return 0;
 }
index d70133086ac330456ec931b74afce38dd36a3b54..4563b28bd6254ddbeda6f0cd8229f22b10159ef7 100644 (file)
@@ -6,7 +6,7 @@ config SND_SOC_FSL_UTILS
 
 menuconfig SND_POWERPC_SOC
        tristate "SoC Audio for Freescale PowerPC CPUs"
-       depends on FSL_SOC
+       depends on FSL_SOC || PPC_MPC52xx
        help
          Say Y or M if you want to add support for codecs attached to
          the PowerPC CPUs.
index efb9ede01208f8cbe6f66b597f1253ecd780e96f..267d5b4b63ceb8392c9bd1433e2f1f6c288b92cf 100644 (file)
@@ -93,9 +93,7 @@ static struct snd_soc_card eukrea_tlv320 = {
        .num_links      = 1,
 };
 
-static struct platform_device *eukrea_tlv320_snd_device;
-
-static int __init eukrea_tlv320_init(void)
+static int __devinit eukrea_tlv320_probe(struct platform_device *pdev)
 {
        int ret;
        int int_port = 0, ext_port;
@@ -136,29 +134,32 @@ static int __init eukrea_tlv320_init(void)
                return 0;
        }
 
-       eukrea_tlv320_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!eukrea_tlv320_snd_device)
-               return -ENOMEM;
-
-       platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320);
-       ret = platform_device_add(eukrea_tlv320_snd_device);
-
-       if (ret) {
-               printk(KERN_ERR "ASoC: Platform device allocation failed\n");
-               platform_device_put(eukrea_tlv320_snd_device);
-       }
+       eukrea_tlv320.dev = &pdev->dev;
+       ret = snd_soc_register_card(&eukrea_tlv320);
+       if (ret)
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
 
        return ret;
 }
 
-static void __exit eukrea_tlv320_exit(void)
+static int __devexit eukrea_tlv320_remove(struct platform_device *pdev)
 {
-       platform_device_unregister(eukrea_tlv320_snd_device);
+       snd_soc_unregister_card(&eukrea_tlv320);
+
+       return 0;
 }
 
-module_init(eukrea_tlv320_init);
-module_exit(eukrea_tlv320_exit);
+static struct platform_driver eukrea_tlv320_driver = {
+       .driver = {
+               .name = "eukrea_tlv320",
+               .owner = THIS_MODULE,
+       },
+       .probe = eukrea_tlv320_probe,
+       .remove = __devexit_p(eukrea_tlv320_remove),};
+
+module_platform_driver(eukrea_tlv320_driver);
 
 MODULE_AUTHOR("Eric Bénard <eric@eukrea.com>");
 MODULE_DESCRIPTION("CPUIMX ALSA SoC driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:eukrea_tlv320");
index 96bb92dd174c0ae14c0b262ae4f55fd6df2d3f70..6feb26500580749fc4b19b18368fdcd2d73175d0 100644 (file)
@@ -823,12 +823,6 @@ static int fsl_dma_close(struct snd_pcm_substream *substream)
                if (dma_private->irq)
                        free_irq(dma_private->irq, dma_private);
 
-               if (dma_private->ld_buf_phys) {
-                       dma_unmap_single(dev, dma_private->ld_buf_phys,
-                                        sizeof(dma_private->link),
-                                        DMA_TO_DEVICE);
-               }
-
                /* Deallocate the fsl_dma_private structure */
                dma_free_coherent(dev, sizeof(struct fsl_dma_private),
                                  dma_private, dma_private->ld_buf_phys);
index e7c800ebbd7559e53a24ba2488e8b5eb5981826f..524ce6210ceea8588594664064d7e4283e02d59e 100644 (file)
@@ -74,9 +74,6 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf,
        if (!buf)
                return -ENOMEM;
 
-       if (!audmux_base)
-               return -ENOSYS;
-
        if (audmux_clk)
                clk_prepare_enable(audmux_clk);
 
index 89a7755b6f56b9d99c98bd6c77f8fbd4e274eda6..d85929b79c350cad32be2ad46e2963cdc93249da 100644 (file)
@@ -109,6 +109,9 @@ static int snd_imx_open(struct snd_pcm_substream *substream)
        dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        dma_data = kzalloc(sizeof(*dma_data), GFP_KERNEL);
+       if (!dma_data)
+               return -ENOMEM;
+
        dma_data->peripheral_type = dma_params->shared_peripheral ?
                                        IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI;
        dma_data->priority = DMA_PRIO_HIGH;
@@ -117,7 +120,7 @@ static int snd_imx_open(struct snd_pcm_substream *substream)
        ret = snd_dmaengine_pcm_open(substream, filter, dma_data);
        if (ret) {
                kfree(dma_data);
-               return 0;
+               return ret;
        }
 
        snd_dmaengine_pcm_set_data(substream, dma_data);
index e6a17baca1eeebd05a6dc1b64c7288c384e17aeb..006f7d465ed2dda2f3122b307cb40820aef37a5d 100644 (file)
@@ -380,14 +380,13 @@ static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
 static struct snd_soc_dai_driver imx_ssi_dai = {
        .probe = imx_ssi_dai_probe,
        .playback = {
-               /* The SSI does not support monaural audio. */
-               .channels_min = 2,
+               .channels_min = 1,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000_96000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
        .capture = {
-               .channels_min = 2,
+               .channels_min = 1,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000_96000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
@@ -524,7 +523,7 @@ static int imx_ssi_probe(struct platform_device *pdev)
        int ret = 0;
        struct snd_soc_dai_driver *dai;
 
-       ssi = kzalloc(sizeof(*ssi), GFP_KERNEL);
+       ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL);
        if (!ssi)
                return -ENOMEM;
        dev_set_drvdata(&pdev->dev, ssi);
@@ -537,7 +536,7 @@ static int imx_ssi_probe(struct platform_device *pdev)
 
        ssi->irq = platform_get_irq(pdev, 0);
 
-       ssi->clk = clk_get(&pdev->dev, NULL);
+       ssi->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(ssi->clk)) {
                ret = PTR_ERR(ssi->clk);
                dev_err(&pdev->dev, "Cannot get the clock: %d\n",
@@ -552,23 +551,18 @@ static int imx_ssi_probe(struct platform_device *pdev)
                goto failed_get_resource;
        }
 
-       if (!request_mem_region(res->start, resource_size(res), DRV_NAME)) {
-               dev_err(&pdev->dev, "request_mem_region failed\n");
-               ret = -EBUSY;
-               goto failed_get_resource;
-       }
-
-       ssi->base = ioremap(res->start, resource_size(res));
+       ssi->base = devm_request_and_ioremap(&pdev->dev, res);
        if (!ssi->base) {
                dev_err(&pdev->dev, "ioremap failed\n");
                ret = -ENODEV;
-               goto failed_ioremap;
+               goto failed_register;
        }
 
        if (ssi->flags & IMX_SSI_USE_AC97) {
                if (ac97_ssi) {
+                       dev_err(&pdev->dev, "AC'97 SSI already registered\n");
                        ret = -EBUSY;
-                       goto failed_ac97;
+                       goto failed_register;
                }
                ac97_ssi = ssi;
                setup_channel_to_ac97(ssi);
@@ -637,15 +631,10 @@ failed_pdev_fiq_add:
 failed_pdev_fiq_alloc:
        snd_soc_unregister_dai(&pdev->dev);
 failed_register:
-failed_ac97:
-       iounmap(ssi->base);
-failed_ioremap:
        release_mem_region(res->start, resource_size(res));
 failed_get_resource:
        clk_disable_unprepare(ssi->clk);
-       clk_put(ssi->clk);
 failed_clk:
-       kfree(ssi);
 
        return ret;
 }
@@ -663,11 +652,8 @@ static int __devexit imx_ssi_remove(struct platform_device *pdev)
        if (ssi->flags & IMX_SSI_USE_AC97)
                ac97_ssi = NULL;
 
-       iounmap(ssi->base);
        release_mem_region(res->start, resource_size(res));
        clk_disable_unprepare(ssi->clk);
-       clk_put(ssi->clk);
-       kfree(ssi);
 
        return 0;
 }
index 9a3f7c5ab68748c5c05916d831defac13e0e7edb..9997c039bb245a7b891bbade0b436346fb5c5d3f 100644 (file)
@@ -370,7 +370,7 @@ static struct snd_soc_platform_driver mpc5200_audio_dma_platform = {
        .pcm_free       = &psc_dma_free,
 };
 
-static int mpc5200_hpcd_probe(struct platform_device *op)
+int mpc5200_audio_dma_create(struct platform_device *op)
 {
        phys_addr_t fifo;
        struct psc_dma *psc_dma;
@@ -487,8 +487,9 @@ out_unmap:
        iounmap(regs);
        return ret;
 }
+EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create);
 
-static int mpc5200_hpcd_remove(struct platform_device *op)
+int mpc5200_audio_dma_destroy(struct platform_device *op)
 {
        struct psc_dma *psc_dma = dev_get_drvdata(&op->dev);
 
@@ -510,24 +511,7 @@ static int mpc5200_hpcd_remove(struct platform_device *op)
 
        return 0;
 }
-
-static struct of_device_id mpc5200_hpcd_match[] = {
-       { .compatible = "fsl,mpc5200-pcm", },
-       {}
-};
-MODULE_DEVICE_TABLE(of, mpc5200_hpcd_match);
-
-static struct platform_driver mpc5200_hpcd_of_driver = {
-       .probe          = mpc5200_hpcd_probe,
-       .remove         = mpc5200_hpcd_remove,
-       .driver = {
-               .owner          = THIS_MODULE,
-               .name           = "mpc5200-pcm-audio",
-               .of_match_table    = mpc5200_hpcd_match,
-       }
-};
-
-module_platform_driver(mpc5200_hpcd_of_driver);
+EXPORT_SYMBOL_GPL(mpc5200_audio_dma_destroy);
 
 MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
 MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver");
index a3c0cd5382fbbfdb74a52b93ceaef444e87f011f..dff253fde29a98268185e715b2425134099eb296 100644 (file)
@@ -81,4 +81,7 @@ to_psc_dma_stream(struct snd_pcm_substream *substream, struct psc_dma *psc_dma)
        return &psc_dma->playback;
 }
 
+int mpc5200_audio_dma_create(struct platform_device *op);
+int mpc5200_audio_dma_destroy(struct platform_device *op);
+
 #endif /* __SOUND_SOC_FSL_MPC5200_DMA_H__ */
index ffa00a2eb7704439341debdcf7cafe2310e4ce94..a313c0ae36dba38f5bd0abbb002f5072c72ec259 100644 (file)
@@ -237,15 +237,18 @@ static const struct snd_soc_dai_ops psc_ac97_digital_ops = {
 
 static struct snd_soc_dai_driver psc_ac97_dai[] = {
 {
+       .name = "mpc5200-psc-ac97.0",
        .ac97_control = 1,
        .probe  = psc_ac97_probe,
        .playback = {
+               .stream_name    = "AC97 Playback",
                .channels_min   = 1,
                .channels_max   = 6,
                .rates          = SNDRV_PCM_RATE_8000_48000,
                .formats = SNDRV_PCM_FMTBIT_S32_BE,
        },
        .capture = {
+               .stream_name    = "AC97 Capture",
                .channels_min   = 1,
                .channels_max   = 2,
                .rates          = SNDRV_PCM_RATE_8000_48000,
@@ -254,8 +257,10 @@ static struct snd_soc_dai_driver psc_ac97_dai[] = {
        .ops = &psc_ac97_analog_ops,
 },
 {
+       .name = "mpc5200-psc-ac97.1",
        .ac97_control = 1,
        .playback = {
+               .stream_name    = "AC97 SPDIF",
                .channels_min   = 1,
                .channels_max   = 2,
                .rates          = SNDRV_PCM_RATE_32000 | \
@@ -278,6 +283,10 @@ static int __devinit psc_ac97_of_probe(struct platform_device *op)
        struct snd_ac97 ac97;
        struct mpc52xx_psc __iomem *regs;
 
+       rc = mpc5200_audio_dma_create(op);
+       if (rc != 0)
+               return rc;
+
        rc = snd_soc_register_dais(&op->dev, psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
        if (rc != 0) {
                dev_err(&op->dev, "Failed to register DAI\n");
@@ -303,6 +312,7 @@ static int __devinit psc_ac97_of_probe(struct platform_device *op)
 
 static int __devexit psc_ac97_of_remove(struct platform_device *op)
 {
+       mpc5200_audio_dma_destroy(op);
        snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_ac97_dai));
        return 0;
 }
index 7b530327553ad998f0cdf81635e3af218418e414..ba1f0a66358f30288c6de2bf4fcba4e7468dd952 100644 (file)
@@ -130,13 +130,16 @@ static const struct snd_soc_dai_ops psc_i2s_dai_ops = {
 };
 
 static struct snd_soc_dai_driver psc_i2s_dai[] = {{
+       .name = "mpc5200-psc-i2s.0",
        .playback = {
+               .stream_name = "I2S Playback",
                .channels_min = 2,
                .channels_max = 2,
                .rates = PSC_I2S_RATES,
                .formats = PSC_I2S_FORMATS,
        },
        .capture = {
+               .stream_name = "I2S Capture",
                .channels_min = 2,
                .channels_max = 2,
                .rates = PSC_I2S_RATES,
@@ -156,6 +159,10 @@ static int __devinit psc_i2s_of_probe(struct platform_device *op)
        struct psc_dma *psc_dma;
        struct mpc52xx_psc __iomem *regs;
 
+       rc = mpc5200_audio_dma_create(op);
+       if (rc != 0)
+               return rc;
+
        rc = snd_soc_register_dais(&op->dev, psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
        if (rc != 0) {
                pr_err("Failed to register DAI\n");
@@ -200,6 +207,7 @@ static int __devinit psc_i2s_of_probe(struct platform_device *op)
 
 static int __devexit psc_i2s_of_remove(struct platform_device *op)
 {
+       mpc5200_audio_dma_destroy(op);
        snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_i2s_dai));
        return 0;
 }
index 60bcba1bc30e550d34fc97500efb31b1a890e259..9ff9318c52b9df42e7c8f61fb3aac2c3bba56983 100644 (file)
@@ -192,7 +192,6 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
                container_of(dev, struct platform_device, dev);
        struct device_node *np = ssi_pdev->dev.of_node;
        struct device_node *codec_np = NULL;
-       struct platform_device *sound_device = NULL;
        struct mpc8610_hpcd_data *machine_data;
        int ret = -ENODEV;
        const char *sprop;
@@ -341,34 +340,22 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
        machine_data->card.probe = mpc8610_hpcd_machine_probe;
        machine_data->card.remove = mpc8610_hpcd_machine_remove;
        machine_data->card.name = pdev->name; /* The platform driver name */
+       machine_data->card.owner = THIS_MODULE;
+       machine_data->card.dev = &pdev->dev;
        machine_data->card.num_links = 2;
        machine_data->card.dai_link = machine_data->dai;
 
-       /* Allocate a new audio platform device structure */
-       sound_device = platform_device_alloc("soc-audio", -1);
-       if (!sound_device) {
-               dev_err(&pdev->dev, "platform device alloc failed\n");
-               ret = -ENOMEM;
-               goto error;
-       }
-
-       /* Associate the card data with the sound device */
-       platform_set_drvdata(sound_device, &machine_data->card);
-
        /* Register with ASoC */
-       ret = platform_device_add(sound_device);
+       ret = snd_soc_register_card(&machine_data->card);
        if (ret) {
-               dev_err(&pdev->dev, "platform device add failed\n");
-               goto error_sound;
+               dev_err(&pdev->dev, "could not register card\n");
+               goto error;
        }
-       dev_set_drvdata(&pdev->dev, sound_device);
 
        of_node_put(codec_np);
 
        return 0;
 
-error_sound:
-       platform_device_put(sound_device);
 error:
        kfree(machine_data);
 error_alloc:
@@ -383,17 +370,12 @@ error_alloc:
  */
 static int __devexit mpc8610_hpcd_remove(struct platform_device *pdev)
 {
-       struct platform_device *sound_device = dev_get_drvdata(&pdev->dev);
-       struct snd_soc_card *card = platform_get_drvdata(sound_device);
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
        struct mpc8610_hpcd_data *machine_data =
                container_of(card, struct mpc8610_hpcd_data, card);
 
-       platform_device_unregister(sound_device);
-
+       snd_soc_unregister_card(card);
        kfree(machine_data);
-       sound_device->dev.platform_data = NULL;
-
-       dev_set_drvdata(&pdev->dev, NULL);
 
        return 0;
 }
index f6d04ad4bb39f99e83752e06c9e253d3c8bff8cd..2b76877b1789479b0e7bfd1bd2a69640e298c77f 100644 (file)
 #include <linux/device.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
+#include <linux/platform_data/asoc-mx27vis.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 #include <sound/tlv.h>
 #include <asm/mach-types.h>
-#include <mach/iomux-mx27.h>
 
 #include "../codecs/tlv320aic32x4.h"
 #include "imx-ssi.h"
 #define MX27VIS_AMP_GAIN       0
 #define MX27VIS_AMP_MUTE       1
 
-#define MX27VIS_PIN_G0         (GPIO_PORTF + 9)
-#define MX27VIS_PIN_G1         (GPIO_PORTF + 8)
-#define MX27VIS_PIN_SDL                (GPIO_PORTE + 5)
-#define MX27VIS_PIN_SDR                (GPIO_PORTF + 7)
-
 static int mx27vis_amp_gain;
 static int mx27vis_amp_mute;
-
-static const int mx27vis_amp_pins[] = {
-       MX27VIS_PIN_G0 | GPIO_GPIO | GPIO_OUT,
-       MX27VIS_PIN_G1 | GPIO_GPIO | GPIO_OUT,
-       MX27VIS_PIN_SDL | GPIO_GPIO | GPIO_OUT,
-       MX27VIS_PIN_SDR | GPIO_GPIO | GPIO_OUT,
-};
+static int mx27vis_amp_gain0_gpio;
+static int mx27vis_amp_gain1_gpio;
+static int mx27vis_amp_mutel_gpio;
+static int mx27vis_amp_muter_gpio;
 
 static int mx27vis_aic32x4_hw_params(struct snd_pcm_substream *substream,
                            struct snd_pcm_hw_params *params)
@@ -109,13 +101,13 @@ static int mx27vis_amp_set(struct snd_kcontrol *kcontrol,
 
        switch (reg) {
        case MX27VIS_AMP_GAIN:
-               gpio_set_value(MX27VIS_PIN_G0, value & 1);
-               gpio_set_value(MX27VIS_PIN_G1, value >> 1);
+               gpio_set_value(mx27vis_amp_gain0_gpio, value & 1);
+               gpio_set_value(mx27vis_amp_gain1_gpio, value >> 1);
                mx27vis_amp_gain = value;
                break;
        case MX27VIS_AMP_MUTE:
-               gpio_set_value(MX27VIS_PIN_SDL, value & 1);
-               gpio_set_value(MX27VIS_PIN_SDR, value >> 1);
+               gpio_set_value(mx27vis_amp_mutel_gpio, value & 1);
+               gpio_set_value(mx27vis_amp_muter_gpio, value >> 1);
                mx27vis_amp_mute = value;
                break;
        }
@@ -190,8 +182,19 @@ static struct snd_soc_card mx27vis_aic32x4 = {
 
 static int __devinit mx27vis_aic32x4_probe(struct platform_device *pdev)
 {
+       struct snd_mx27vis_platform_data *pdata = pdev->dev.platform_data;
        int ret;
 
+       if (!pdata) {
+               dev_err(&pdev->dev, "No platform data supplied\n");
+               return -EINVAL;
+       }
+
+       mx27vis_amp_gain0_gpio = pdata->amp_gain0_gpio;
+       mx27vis_amp_gain1_gpio = pdata->amp_gain1_gpio;
+       mx27vis_amp_mutel_gpio = pdata->amp_mutel_gpio;
+       mx27vis_amp_muter_gpio = pdata->amp_muter_gpio;
+
        mx27vis_aic32x4.dev = &pdev->dev;
        ret = snd_soc_register_card(&mx27vis_aic32x4);
        if (ret) {
@@ -213,11 +216,6 @@ static int __devinit mx27vis_aic32x4_probe(struct platform_device *pdev)
                        IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0)
        );
 
-       ret = mxc_gpio_setup_multiple_pins(mx27vis_amp_pins,
-                       ARRAY_SIZE(mx27vis_amp_pins), "MX27VIS_AMP");
-       if (ret)
-               printk(KERN_ERR "ASoC: unable to setup gpios\n");
-
        return ret;
 }
 
index 50adf4032bcceee4a1ac4085baed835b46c27c6f..144d496036370e84d888d71d33703e39370eff41 100644 (file)
@@ -202,7 +202,6 @@ static int p1022_ds_probe(struct platform_device *pdev)
                container_of(dev, struct platform_device, dev);
        struct device_node *np = ssi_pdev->dev.of_node;
        struct device_node *codec_np = NULL;
-       struct platform_device *sound_device = NULL;
        struct machine_data *mdata;
        int ret = -ENODEV;
        const char *sprop;
@@ -349,36 +348,23 @@ static int p1022_ds_probe(struct platform_device *pdev)
        mdata->card.probe = p1022_ds_machine_probe;
        mdata->card.remove = p1022_ds_machine_remove;
        mdata->card.name = pdev->name; /* The platform driver name */
+       mdata->card.owner = THIS_MODULE;
+       mdata->card.dev = &pdev->dev;
        mdata->card.num_links = 2;
        mdata->card.dai_link = mdata->dai;
 
-       /* Allocate a new audio platform device structure */
-       sound_device = platform_device_alloc("soc-audio", -1);
-       if (!sound_device) {
-               dev_err(&pdev->dev, "platform device alloc failed\n");
-               ret = -ENOMEM;
-               goto error;
-       }
-
-       /* Associate the card data with the sound device */
-       platform_set_drvdata(sound_device, &mdata->card);
-
        /* Register with ASoC */
-       ret = platform_device_add(sound_device);
+       ret = snd_soc_register_card(&mdata->card);
        if (ret) {
-               dev_err(&pdev->dev, "platform device add failed\n");
+               dev_err(&pdev->dev, "could not register card\n");
                goto error;
        }
-       dev_set_drvdata(&pdev->dev, sound_device);
 
        of_node_put(codec_np);
 
        return 0;
 
 error:
-       if (sound_device)
-               platform_device_put(sound_device);
-
        kfree(mdata);
 error_put:
        of_node_put(codec_np);
@@ -392,17 +378,12 @@ error_put:
  */
 static int __devexit p1022_ds_remove(struct platform_device *pdev)
 {
-       struct platform_device *sound_device = dev_get_drvdata(&pdev->dev);
-       struct snd_soc_card *card = platform_get_drvdata(sound_device);
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
        struct machine_data *mdata =
                container_of(card, struct machine_data, card);
 
-       platform_device_unregister(sound_device);
-
+       snd_soc_unregister_card(card);
        kfree(mdata);
-       sound_device->dev.platform_data = NULL;
-
-       dev_set_drvdata(&pdev->dev, NULL);
 
        return 0;
 }
index b3af55dcde9de54bbe2547e0ef16dcc2ce9288df..4b63ec8eb372ee917a06c314764a2d7f6804a892 100644 (file)
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/interrupt.h>
 #include <linux/device.h>
-#include <linux/delay.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
-#include <linux/dma-mapping.h>
 
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
 #include <sound/soc.h>
 
 #include "mpc5200_dma.h"
-#include "mpc5200_psc_ac97.h"
-#include "../codecs/wm9712.h"
 
 #define DRV_NAME "pcm030-audio-fabric"
 
+struct pcm030_audio_data {
+       struct snd_soc_card *card;
+       struct platform_device *codec_device;
+};
+
 static struct snd_soc_dai_link pcm030_fabric_dai[] = {
 {
        .name = "AC97",
        .stream_name = "AC97 Analog",
        .codec_dai_name = "wm9712-hifi",
        .cpu_dai_name = "mpc5200-psc-ac97.0",
-       .platform_name = "mpc5200-pcm-audio",
        .codec_name = "wm9712-codec",
 },
 {
@@ -45,44 +40,95 @@ static struct snd_soc_dai_link pcm030_fabric_dai[] = {
        .stream_name = "AC97 IEC958",
        .codec_dai_name = "wm9712-aux",
        .cpu_dai_name = "mpc5200-psc-ac97.1",
-       .platform_name = "mpc5200-pcm-audio",
        .codec_name = "wm9712-codec",
 },
 };
 
-static struct snd_soc_card card = {
+static struct snd_soc_card pcm030_card = {
        .name = "pcm030",
        .owner = THIS_MODULE,
        .dai_link = pcm030_fabric_dai,
        .num_links = ARRAY_SIZE(pcm030_fabric_dai),
 };
 
-static __init int pcm030_fabric_init(void)
+static int __init pcm030_fabric_probe(struct platform_device *op)
 {
-       struct platform_device *pdev;
-       int rc;
+       struct device_node *np = op->dev.of_node;
+       struct device_node *platform_np;
+       struct snd_soc_card *card = &pcm030_card;
+       struct pcm030_audio_data *pdata;
+       int ret;
+       int i;
 
        if (!of_machine_is_compatible("phytec,pcm030"))
                return -ENODEV;
 
-       pdev = platform_device_alloc("soc-audio", 1);
-       if (!pdev) {
-               pr_err("pcm030_fabric_init: platform_device_alloc() failed\n");
-               return -ENODEV;
-       }
+       pdata = devm_kzalloc(&op->dev, sizeof(struct pcm030_audio_data),
+                            GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+
+       card->dev = &op->dev;
+       platform_set_drvdata(op, pdata);
 
-       platform_set_drvdata(pdev, &card);
+       pdata->card = card;
 
-       rc = platform_device_add(pdev);
-       if (rc) {
-               pr_err("pcm030_fabric_init: platform_device_add() failed\n");
-               platform_device_put(pdev);
+       platform_np = of_parse_phandle(np, "asoc-platform", 0);
+       if (!platform_np) {
+               dev_err(&op->dev, "ac97 not registered\n");
                return -ENODEV;
        }
-       return 0;
+
+       for (i = 0; i < card->num_links; i++)
+               card->dai_link[i].platform_of_node = platform_np;
+
+       ret = request_module("snd-soc-wm9712");
+       if (ret)
+               dev_err(&op->dev, "request_module returned: %d\n", ret);
+
+       pdata->codec_device = platform_device_alloc("wm9712-codec", -1);
+       if (!pdata->codec_device)
+               dev_err(&op->dev, "platform_device_alloc() failed\n");
+
+       ret = platform_device_add(pdata->codec_device);
+       if (ret)
+               dev_err(&op->dev, "platform_device_add() failed: %d\n", ret);
+
+       ret = snd_soc_register_card(card);
+       if (ret)
+               dev_err(&op->dev, "snd_soc_register_card() failed: %d\n", ret);
+
+       return ret;
+}
+
+static int __devexit pcm030_fabric_remove(struct platform_device *op)
+{
+       struct pcm030_audio_data *pdata = platform_get_drvdata(op);
+       int ret;
+
+       ret = snd_soc_unregister_card(pdata->card);
+       platform_device_unregister(pdata->codec_device);
+
+       return ret;
 }
 
-module_init(pcm030_fabric_init);
+static struct of_device_id pcm030_audio_match[] = {
+       { .compatible = "phytec,pcm030-audio-fabric", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, pcm030_audio_match);
+
+static struct platform_driver pcm030_fabric_driver = {
+       .probe          = pcm030_fabric_probe,
+       .remove         = __devexit_p(pcm030_fabric_remove),
+       .driver         = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+               .of_match_table    = pcm030_audio_match,
+       },
+};
+
+module_platform_driver(pcm030_fabric_driver);
 
 
 MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
index 2937e54da49ef596f52243cbce586a4cbba8712b..2cc7782714b53830716fe74cea0c94c3527bc705 100644 (file)
@@ -318,6 +318,15 @@ static struct snd_soc_dai_link mfld_msic_dailink[] = {
                .platform_name = "sst-platform",
                .init = NULL,
        },
+       {
+               .name = "Medfield Compress",
+               .stream_name = "Speaker",
+               .cpu_dai_name = "Compress-cpu-dai",
+               .codec_dai_name = "SN95031 Speaker",
+               .codec_name = "sn95031",
+               .platform_name = "sst-platform",
+               .init = NULL,
+       },
 };
 
 /* SoC card */
diff --git a/sound/soc/mid-x86/sst_dsp.h b/sound/soc/mid-x86/sst_dsp.h
new file mode 100644 (file)
index 0000000..0fce1de
--- /dev/null
@@ -0,0 +1,134 @@
+#ifndef __SST_DSP_H__
+#define __SST_DSP_H__
+/*
+ *  sst_dsp.h - Intel SST Driver for audio engine
+ *
+ *  Copyright (C) 2008-12 Intel Corporation
+ *  Authors:   Vinod Koul <vinod.koul@linux.intel.com>
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; 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.
+ *
+ *  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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+enum sst_codec_types {
+       /*  AUDIO/MUSIC CODEC Type Definitions */
+       SST_CODEC_TYPE_UNKNOWN = 0,
+       SST_CODEC_TYPE_PCM,     /* Pass through Audio codec */
+       SST_CODEC_TYPE_MP3,
+       SST_CODEC_TYPE_MP24,
+       SST_CODEC_TYPE_AAC,
+       SST_CODEC_TYPE_AACP,
+       SST_CODEC_TYPE_eAACP,
+};
+
+enum stream_type {
+       SST_STREAM_TYPE_NONE = 0,
+       SST_STREAM_TYPE_MUSIC = 1,
+};
+
+struct snd_pcm_params {
+       u16 codec;      /* codec type */
+       u8 num_chan;    /* 1=Mono, 2=Stereo */
+       u8 pcm_wd_sz;   /* 16/24 - bit*/
+       u32 reserved;   /* Bitrate in bits per second */
+       u32 sfreq;      /* Sampling rate in Hz */
+       u8 use_offload_path;
+       u8 reserved2;
+       u16 reserved3;
+       u8 channel_map[8];
+} __packed;
+
+/* MP3 Music Parameters Message */
+struct snd_mp3_params {
+       u16 codec;
+       u8  num_chan;   /* 1=Mono, 2=Stereo     */
+       u8  pcm_wd_sz; /* 16/24 - bit*/
+       u8  crc_check; /* crc_check - disable (0) or enable (1) */
+       u8  reserved1; /* unused*/
+       u16 reserved2;  /* Unused */
+} __packed;
+
+#define AAC_BIT_STREAM_ADTS            0
+#define AAC_BIT_STREAM_ADIF            1
+#define AAC_BIT_STREAM_RAW             2
+
+/* AAC Music Parameters Message */
+struct snd_aac_params {
+       u16 codec;
+       u8 num_chan; /* 1=Mono, 2=Stereo*/
+       u8 pcm_wd_sz; /* 16/24 - bit*/
+       u8 bdownsample; /*SBR downsampling 0 - disable 1 -enabled AAC+ only */
+       u8 bs_format; /* input bit stream format adts=0, adif=1, raw=2 */
+       u16  reser2;
+       u32 externalsr; /*sampling rate of basic AAC raw bit stream*/
+       u8 sbr_signalling;/*disable/enable/set automode the SBR tool.AAC+*/
+       u8 reser1;
+       u16  reser3;
+} __packed;
+
+/* WMA Music Parameters Message */
+struct snd_wma_params {
+       u16 codec;
+       u8  num_chan;   /* 1=Mono, 2=Stereo */
+       u8  pcm_wd_sz;  /* 16/24 - bit*/
+       u32 brate;      /* Use the hard coded value. */
+       u32 sfreq;      /* Sampling freq eg. 8000, 441000, 48000 */
+       u32 channel_mask;  /* Channel Mask */
+       u16 format_tag; /* Format Tag */
+       u16 block_align;        /* packet size */
+       u16 wma_encode_opt;/* Encoder option */
+       u8 op_align;    /* op align 0- 16 bit, 1- MSB, 2 LSB */
+       u8 reserved;    /* reserved */
+} __packed;
+
+/* Codec params struture */
+union  snd_sst_codec_params {
+       struct snd_pcm_params pcm_params;
+       struct snd_mp3_params mp3_params;
+       struct snd_aac_params aac_params;
+       struct snd_wma_params wma_params;
+} __packed;
+
+/* Address and size info of a frame buffer */
+struct sst_address_info {
+       u32 addr; /* Address at IA */
+       u32 size; /* Size of the buffer */
+};
+
+struct snd_sst_alloc_params_ext {
+       struct sst_address_info  ring_buf_info[8];
+       u8 sg_count;
+       u8 reserved;
+       u16 reserved2;
+       u32 frag_size;  /*Number of samples after which period elapsed
+                                 message is sent valid only if path  = 0*/
+} __packed;
+
+struct snd_sst_stream_params {
+       union snd_sst_codec_params uc;
+} __packed;
+
+struct snd_sst_params {
+       u32 stream_id;
+       u8 codec;
+       u8 ops;
+       u8 stream_type;
+       u8 device_type;
+       struct snd_sst_stream_params sparams;
+       struct snd_sst_alloc_params_ext aparams;
+};
+
+#endif /* __SST_DSP_H__ */
index d34563b12c3b4e4579a33aa57df16e1738409a66..a263cbed8624527e5b09f19b01da08ecff3e7292 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  sst_platform.c - Intel MID Platform driver
  *
- *  Copyright (C) 2010 Intel Corp
+ *  Copyright (C) 2010-2012 Intel Corp
  *  Author: Vinod Koul <vinod.koul@intel.com>
  *  Author: Harsha Priya <priya.harsha@intel.com>
  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -32,6 +32,7 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/compress_driver.h>
 #include "sst_platform.h"
 
 static struct sst_device *sst;
@@ -152,6 +153,16 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
                .formats = SNDRV_PCM_FMTBIT_S24_LE,
        },
 },
+{
+       .name = "Compress-cpu-dai",
+       .compress_dai = 1,
+       .playback = {
+               .channels_min = SST_STEREO,
+               .channels_max = SST_STEREO,
+               .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+},
 };
 
 /* helper functions */
@@ -463,8 +474,199 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
        }
        return retval;
 }
+
+/* compress stream operations */
+static void sst_compr_fragment_elapsed(void *arg)
+{
+       struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg;
+
+       pr_debug("fragment elapsed by driver\n");
+       if (cstream)
+               snd_compr_fragment_elapsed(cstream);
+}
+
+static int sst_platform_compr_open(struct snd_compr_stream *cstream)
+{
+
+       int ret_val = 0;
+       struct snd_compr_runtime *runtime = cstream->runtime;
+       struct sst_runtime_stream *stream;
+
+       stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+       if (!stream)
+               return -ENOMEM;
+
+       spin_lock_init(&stream->status_lock);
+
+       /* get the sst ops */
+       if (!sst || !try_module_get(sst->dev->driver->owner)) {
+               pr_err("no device available to run\n");
+               ret_val = -ENODEV;
+               goto out_ops;
+       }
+       stream->compr_ops = sst->compr_ops;
+
+       stream->id = 0;
+       sst_set_stream_status(stream, SST_PLATFORM_INIT);
+       runtime->private_data = stream;
+       return 0;
+out_ops:
+       kfree(stream);
+       return ret_val;
+}
+
+static int sst_platform_compr_free(struct snd_compr_stream *cstream)
+{
+       struct sst_runtime_stream *stream;
+       int ret_val = 0, str_id;
+
+       stream = cstream->runtime->private_data;
+       /*need to check*/
+       str_id = stream->id;
+       if (str_id)
+               ret_val = stream->compr_ops->close(str_id);
+       module_put(sst->dev->driver->owner);
+       kfree(stream);
+       pr_debug("%s: %d\n", __func__, ret_val);
+       return 0;
+}
+
+static int sst_platform_compr_set_params(struct snd_compr_stream *cstream,
+                                       struct snd_compr_params *params)
+{
+       struct sst_runtime_stream *stream;
+       int retval;
+       struct snd_sst_params str_params;
+       struct sst_compress_cb cb;
+
+       stream = cstream->runtime->private_data;
+       /* construct fw structure for this*/
+       memset(&str_params, 0, sizeof(str_params));
+
+       str_params.ops = STREAM_OPS_PLAYBACK;
+       str_params.stream_type = SST_STREAM_TYPE_MUSIC;
+       str_params.device_type = SND_SST_DEVICE_COMPRESS;
+
+       switch (params->codec.id) {
+       case SND_AUDIOCODEC_MP3: {
+               str_params.codec = SST_CODEC_TYPE_MP3;
+               str_params.sparams.uc.mp3_params.codec = SST_CODEC_TYPE_MP3;
+               str_params.sparams.uc.mp3_params.num_chan = params->codec.ch_in;
+               str_params.sparams.uc.mp3_params.pcm_wd_sz = 16;
+               break;
+       }
+
+       case SND_AUDIOCODEC_AAC: {
+               str_params.codec = SST_CODEC_TYPE_AAC;
+               str_params.sparams.uc.aac_params.codec = SST_CODEC_TYPE_AAC;
+               str_params.sparams.uc.aac_params.num_chan = params->codec.ch_in;
+               str_params.sparams.uc.aac_params.pcm_wd_sz = 16;
+               if (params->codec.format == SND_AUDIOSTREAMFORMAT_MP4ADTS)
+                       str_params.sparams.uc.aac_params.bs_format =
+                                                       AAC_BIT_STREAM_ADTS;
+               else if (params->codec.format == SND_AUDIOSTREAMFORMAT_RAW)
+                       str_params.sparams.uc.aac_params.bs_format =
+                                                       AAC_BIT_STREAM_RAW;
+               else {
+                       pr_err("Undefined format%d\n", params->codec.format);
+                       return -EINVAL;
+               }
+               str_params.sparams.uc.aac_params.externalsr =
+                                               params->codec.sample_rate;
+               break;
+       }
+
+       default:
+               pr_err("codec not supported, id =%d\n", params->codec.id);
+               return -EINVAL;
+       }
+
+       str_params.aparams.ring_buf_info[0].addr  =
+                                       virt_to_phys(cstream->runtime->buffer);
+       str_params.aparams.ring_buf_info[0].size =
+                                       cstream->runtime->buffer_size;
+       str_params.aparams.sg_count = 1;
+       str_params.aparams.frag_size = cstream->runtime->fragment_size;
+
+       cb.param = cstream;
+       cb.compr_cb = sst_compr_fragment_elapsed;
+
+       retval = stream->compr_ops->open(&str_params, &cb);
+       if (retval < 0) {
+               pr_err("stream allocation failed %d\n", retval);
+               return retval;
+       }
+
+       stream->id = retval;
+       return 0;
+}
+
+static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd)
+{
+       struct sst_runtime_stream *stream =
+               cstream->runtime->private_data;
+
+       return stream->compr_ops->control(cmd, stream->id);
+}
+
+static int sst_platform_compr_pointer(struct snd_compr_stream *cstream,
+                                       struct snd_compr_tstamp *tstamp)
+{
+       struct sst_runtime_stream *stream;
+
+       stream  = cstream->runtime->private_data;
+       stream->compr_ops->tstamp(stream->id, tstamp);
+       tstamp->byte_offset = tstamp->copied_total %
+                                (u32)cstream->runtime->buffer_size;
+       pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset);
+       return 0;
+}
+
+static int sst_platform_compr_ack(struct snd_compr_stream *cstream,
+                                       size_t bytes)
+{
+       struct sst_runtime_stream *stream;
+
+       stream  = cstream->runtime->private_data;
+       stream->compr_ops->ack(stream->id, (unsigned long)bytes);
+       stream->bytes_written += bytes;
+
+       return 0;
+}
+
+static int sst_platform_compr_get_caps(struct snd_compr_stream *cstream,
+                                       struct snd_compr_caps *caps)
+{
+       struct sst_runtime_stream *stream =
+               cstream->runtime->private_data;
+
+       return stream->compr_ops->get_caps(caps);
+}
+
+static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
+                                       struct snd_compr_codec_caps *codec)
+{
+       struct sst_runtime_stream *stream =
+               cstream->runtime->private_data;
+
+       return stream->compr_ops->get_codec_caps(codec);
+}
+
+static struct snd_compr_ops sst_platform_compr_ops = {
+
+       .open = sst_platform_compr_open,
+       .free = sst_platform_compr_free,
+       .set_params = sst_platform_compr_set_params,
+       .trigger = sst_platform_compr_trigger,
+       .pointer = sst_platform_compr_pointer,
+       .ack = sst_platform_compr_ack,
+       .get_caps = sst_platform_compr_get_caps,
+       .get_codec_caps = sst_platform_compr_get_codec_caps,
+};
+
 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,
 };
index f04f4f72daa0548f9f8e158c9cc96129cf4951fc..d61c5d514ffabf43a29cb09e62024e7d17045471 100644 (file)
@@ -27,6 +27,8 @@
 #ifndef __SST_PLATFORMDRV_H__
 #define __SST_PLATFORMDRV_H__
 
+#include "sst_dsp.h"
+
 #define SST_MONO               1
 #define SST_STEREO             2
 #define SST_MAX_CAP            5
@@ -42,7 +44,6 @@
 #define SST_MIN_PERIODS                2
 #define SST_MAX_PERIODS                (1024*2)
 #define SST_FIFO_SIZE          0
-#define SST_CODEC_TYPE_PCM     1
 
 struct pcm_stream_info {
        int str_id;
@@ -83,6 +84,7 @@ enum sst_audio_device_type {
        SND_SST_DEVICE_VIBRA,
        SND_SST_DEVICE_HAPTIC,
        SND_SST_DEVICE_CAPTURE,
+       SND_SST_DEVICE_COMPRESS,
 };
 
 /* PCM Parameters */
@@ -107,6 +109,24 @@ struct sst_stream_params {
        struct sst_pcm_params sparams;
 };
 
+struct sst_compress_cb {
+       void *param;
+       void (*compr_cb)(void *param);
+};
+
+struct compress_sst_ops {
+       const char *name;
+       int (*open) (struct snd_sst_params *str_params,
+                       struct sst_compress_cb *cb);
+       int (*control) (unsigned int cmd, unsigned int str_id);
+       int (*tstamp) (unsigned int str_id, struct snd_compr_tstamp *tstamp);
+       int (*ack) (unsigned int str_id, unsigned long bytes);
+       int (*close) (unsigned int str_id);
+       int (*get_caps) (struct snd_compr_caps *caps);
+       int (*get_codec_caps) (struct snd_compr_codec_caps *codec);
+
+};
+
 struct sst_ops {
        int (*open) (struct sst_stream_params *str_param);
        int (*device_control) (int cmd, void *arg);
@@ -115,8 +135,11 @@ struct sst_ops {
 
 struct sst_runtime_stream {
        int     stream_status;
+       unsigned int id;
+       size_t bytes_written;
        struct pcm_stream_info stream_info;
        struct sst_ops *ops;
+       struct compress_sst_ops *compr_ops;
        spinlock_t      status_lock;
 };
 
@@ -124,6 +147,7 @@ struct sst_device {
        char *name;
        struct device *dev;
        struct sst_ops *ops;
+       struct compress_sst_ops *compr_ops;
 };
 
 int sst_register_dsp(struct sst_device *sst);
index b3030718c2288b9942628c9f087694b0568cbbb3..aa037b292f3dc05a9b6300c3cc4890988c0c2faf 100644 (file)
@@ -704,7 +704,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)
                return ret;
        }
 
-       saif->clk = clk_get(&pdev->dev, NULL);
+       saif->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(saif->clk)) {
                ret = PTR_ERR(saif->clk);
                dev_err(&pdev->dev, "Cannot get the clock: %d\n",
@@ -717,8 +717,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)
        saif->base = devm_request_and_ioremap(&pdev->dev, iores);
        if (!saif->base) {
                dev_err(&pdev->dev, "ioremap failed\n");
-               ret = -ENODEV;
-               goto failed_get_resource;
+               return -ENODEV;
        }
 
        dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
@@ -731,7 +730,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)
                                           &saif->dma_param.chan_num);
                if (ret) {
                        dev_err(&pdev->dev, "failed to get dma channel\n");
-                       goto failed_get_resource;
+                       return ret;
                }
        } else {
                saif->dma_param.chan_num = dmares->start;
@@ -742,7 +741,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)
                ret = saif->irq;
                dev_err(&pdev->dev, "failed to get irq resource: %d\n",
                        ret);
-               goto failed_get_resource;
+               return ret;
        }
 
        saif->dev = &pdev->dev;
@@ -750,7 +749,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)
                               "mxs-saif", saif);
        if (ret) {
                dev_err(&pdev->dev, "failed to request irq\n");
-               goto failed_get_resource;
+               return ret;
        }
 
        saif->dma_param.chan_irq = platform_get_irq(pdev, 1);
@@ -758,7 +757,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)
                ret = saif->dma_param.chan_irq;
                dev_err(&pdev->dev, "failed to get dma irq resource: %d\n",
                        ret);
-               goto failed_get_resource;
+               return ret;
        }
 
        platform_set_drvdata(pdev, saif);
@@ -766,7 +765,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)
        ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai);
        if (ret) {
                dev_err(&pdev->dev, "register DAI failed\n");
-               goto failed_get_resource;
+               return ret;
        }
 
        ret = mxs_pcm_platform_register(&pdev->dev);
@@ -779,19 +778,14 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)
 
 failed_pdev_alloc:
        snd_soc_unregister_dai(&pdev->dev);
-failed_get_resource:
-       clk_put(saif->clk);
 
        return ret;
 }
 
 static int __devexit mxs_saif_remove(struct platform_device *pdev)
 {
-       struct mxs_saif *saif = platform_get_drvdata(pdev);
-
        mxs_pcm_platform_unregister(&pdev->dev);
        snd_soc_unregister_dai(&pdev->dev);
-       clk_put(saif->clk);
 
        return 0;
 }
index 57a2fa751085cc025abe5490deb2e8513b0a7d6b..7048137f9a337340e0e0a78a7a55859220718538 100644 (file)
@@ -1,6 +1,7 @@
 config SND_OMAP_SOC
        tristate "SoC Audio for the Texas Instruments OMAP chips"
-       depends on ARCH_OMAP
+       depends on ARCH_OMAP && DMA_OMAP
+       select SND_SOC_DMAENGINE_PCM
 
 config SND_OMAP_SOC_DMIC
        tristate
@@ -60,23 +61,6 @@ config SND_OMAP_SOC_OSK5912
        help
          Say Y if you want to add support for SoC audio on osk5912.
 
-config SND_OMAP_SOC_OVERO
-       tristate "SoC Audio support for Gumstix Overo and CompuLab CM-T35"
-       depends on TWL4030_CORE && SND_OMAP_SOC && (MACH_OVERO || MACH_CM_T35)
-       select SND_OMAP_SOC_MCBSP
-       select SND_SOC_TWL4030
-       help
-         Say Y if you want to add support for SoC audio on the
-         Gumstix Overo or CompuLab CM-T35
-
-config SND_OMAP_SOC_OMAP3EVM
-       tristate "SoC Audio support for OMAP3EVM board"
-       depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3EVM
-       select SND_OMAP_SOC_MCBSP
-       select SND_SOC_TWL4030
-       help
-         Say Y if you want to add support for SoC audio on the omap3evm board.
-
 config SND_OMAP_SOC_AM3517EVM
        tristate "SoC Audio support for OMAP3517 / AM3517 EVM"
        depends on SND_OMAP_SOC && MACH_OMAP3517EVM && I2C
@@ -95,6 +79,19 @@ config SND_OMAP_SOC_SDP3430
          Say Y if you want to add support for SoC audio on Texas Instruments
          SDP3430.
 
+config SND_OMAP_SOC_OMAP_TWL4030
+       tristate "SoC Audio support for TI SoC based boards with twl4030 codec"
+       depends on TWL4030_CORE && SND_OMAP_SOC
+       select SND_OMAP_SOC_MCBSP
+       select SND_SOC_TWL4030
+       help
+         Say Y if you want to add support for SoC audio on TI SoC based boards
+         using twl4030 as c codec. This driver currently supports:
+         - Beagleboard or Devkit8000
+         - Gumstix Overo or CompuLab CM-T35/CM-T3730
+         - IGEP v2
+         - OMAP3EVM
+
 config SND_OMAP_SOC_OMAP_ABE_TWL6040
        tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"
        depends on TWL6040_CORE && SND_OMAP_SOC && ARCH_OMAP4
@@ -127,16 +124,6 @@ config SND_OMAP_SOC_OMAP3_PANDORA
        help
          Say Y if you want to add support for SoC audio on the OMAP3 Pandora.
 
-config SND_OMAP_SOC_OMAP3_BEAGLE
-       tristate "SoC Audio support for OMAP3 Beagle and Devkit8000"
-       depends on TWL4030_CORE && SND_OMAP_SOC
-       depends on (MACH_OMAP3_BEAGLE || MACH_DEVKIT8000)
-       select SND_OMAP_SOC_MCBSP
-       select SND_SOC_TWL4030
-       help
-         Say Y if you want to add support for SoC audio on the Beagleboard or
-         the clone Devkit8000.
-
 config SND_OMAP_SOC_ZOOM2
        tristate "SoC Audio support for Zoom2"
        depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_ZOOM2
@@ -144,11 +131,3 @@ config SND_OMAP_SOC_ZOOM2
        select SND_SOC_TWL4030
        help
          Say Y if you want to add support for Soc audio on Zoom2 board.
-
-config SND_OMAP_SOC_IGEP0020
-       tristate "SoC Audio support for IGEP v2"
-       depends on TWL4030_CORE && SND_OMAP_SOC && MACH_IGEP0020
-       select SND_OMAP_SOC_MCBSP
-       select SND_SOC_TWL4030
-       help
-         Say Y if you want to add support for Soc audio on IGEP v2 board.
index 0e14dd3225650b0e6988f8ad1ec90d70788de3e5..19637e55ea48c7ac78e5fa90cef1916b0f1f7d3d 100644 (file)
@@ -16,29 +16,23 @@ snd-soc-n810-objs := n810.o
 snd-soc-rx51-objs := rx51.o
 snd-soc-ams-delta-objs := ams-delta.o
 snd-soc-osk5912-objs := osk5912.o
-snd-soc-overo-objs := overo.o
-snd-soc-omap3evm-objs := omap3evm.o
 snd-soc-am3517evm-objs := am3517evm.o
 snd-soc-sdp3430-objs := sdp3430.o
 snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o
+snd-soc-omap-twl4030-objs := omap-twl4030.o
 snd-soc-omap3pandora-objs := omap3pandora.o
-snd-soc-omap3beagle-objs := omap3beagle.o
 snd-soc-zoom2-objs := zoom2.o
-snd-soc-igep0020-objs := igep0020.o
 snd-soc-omap-hdmi-card-objs := omap-hdmi-card.o
 
 obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
 obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o
 obj-$(CONFIG_SND_OMAP_SOC_AMS_DELTA) += snd-soc-ams-delta.o
 obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
-obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP2EVM) += snd-soc-omap2evm.o
-obj-$(CONFIG_SND_OMAP_SOC_OMAP3EVM) += snd-soc-omap3evm.o
 obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o
 obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o
+obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
-obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o
 obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o
-obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o
 obj-$(CONFIG_SND_OMAP_SOC_OMAP_HDMI) += snd-soc-omap-hdmi-card.o
index a52e87d28b6ebe7f66e2a3fa239873a70470b961..fad350682ca2ea1a7c2e68a5afe58932c3a36a53 100644 (file)
@@ -41,32 +41,15 @@ static int am3517evm_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;
        int ret;
 
        /* Set the codec system clock for DAC and ADC */
        ret = snd_soc_dai_set_sysclk(codec_dai, 0,
                        CODEC_CLOCK, SND_SOC_CLOCK_IN);
-       if (ret < 0) {
+       if (ret < 0)
                printk(KERN_ERR "can't set codec system clock\n");
-               return ret;
-       }
-
-       ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_CLKR_SRC_CLKX, 0,
-                               SND_SOC_CLOCK_IN);
-       if (ret < 0) {
-               printk(KERN_ERR "can't set CPU system clock OMAP_MCBSP_CLKR_SRC_CLKX\n");
-               return ret;
-       }
 
-       ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_FSR_SRC_FSX, 0,
-                               SND_SOC_CLOCK_IN);
-       if (ret < 0) {
-               printk(KERN_ERR "can't set CPU system clock OMAP_MCBSP_FSR_SRC_FSX\n");
-               return ret;
-       }
-
-       return 0;
+       return ret;
 }
 
 static struct snd_soc_ops am3517evm_ops = {
diff --git a/sound/soc/omap/igep0020.c b/sound/soc/omap/igep0020.c
deleted file mode 100644 (file)
index 5ed8716..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * igep0020.c  --  SoC audio for IGEP v2
- *
- * Based on sound/soc/omap/overo.c by Steve Sakoman
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-
-#include "omap-mcbsp.h"
-#include "omap-pcm.h"
-
-static int igep2_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       int ret;
-
-       /* Set the codec system clock for DAC and ADC */
-       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
-                                           SND_SOC_CLOCK_IN);
-       if (ret < 0) {
-               printk(KERN_ERR "can't set codec system clock\n");
-               return ret;
-       }
-
-       return 0;
-}
-
-static struct snd_soc_ops igep2_ops = {
-       .hw_params = igep2_hw_params,
-};
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link igep2_dai = {
-       .name = "TWL4030",
-       .stream_name = "TWL4030",
-       .cpu_dai_name = "omap-mcbsp.2",
-       .codec_dai_name = "twl4030-hifi",
-       .platform_name = "omap-pcm-audio",
-       .codec_name = "twl4030-codec",
-       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-                  SND_SOC_DAIFMT_CBM_CFM,
-       .ops = &igep2_ops,
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_card_igep2 = {
-       .name = "igep2",
-       .owner = THIS_MODULE,
-       .dai_link = &igep2_dai,
-       .num_links = 1,
-};
-
-static struct platform_device *igep2_snd_device;
-
-static int __init igep2_soc_init(void)
-{
-       int ret;
-
-       if (!machine_is_igep0020())
-               return -ENODEV;
-       printk(KERN_INFO "IGEP v2 SoC init\n");
-
-       igep2_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!igep2_snd_device) {
-               printk(KERN_ERR "Platform device allocation failed\n");
-               return -ENOMEM;
-       }
-
-       platform_set_drvdata(igep2_snd_device, &snd_soc_card_igep2);
-
-       ret = platform_device_add(igep2_snd_device);
-       if (ret)
-               goto err1;
-
-       return 0;
-
-err1:
-       printk(KERN_ERR "Unable to add platform device\n");
-       platform_device_put(igep2_snd_device);
-
-       return ret;
-}
-module_init(igep2_soc_init);
-
-static void __exit igep2_soc_exit(void)
-{
-       platform_device_unregister(igep2_snd_device);
-}
-module_exit(igep2_soc_exit);
-
-MODULE_AUTHOR("Enric Balletbo i Serra <eballetbo@iseebcn.com>");
-MODULE_DESCRIPTION("ALSA SoC IGEP v2");
-MODULE_LICENSE("GPL");
index a681a9a8b8463824618a8c671d7cd12d6501006f..afb8d4f1bedfac70eb98492ce5b4c023bb9d0752 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/platform_data/asoc-ti-mcbsp.h>
 
@@ -728,50 +729,39 @@ void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int tx, int rx)
 
 int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id)
 {
+       struct clk *fck_src;
        const char *src;
+       int r;
 
        if (fck_src_id == MCBSP_CLKS_PAD_SRC)
-               src = "clks_ext";
+               src = "pad_fck";
        else if (fck_src_id == MCBSP_CLKS_PRCM_SRC)
-               src = "clks_fclk";
+               src = "prcm_fck";
        else
                return -EINVAL;
 
-       if (mcbsp->pdata->set_clk_src)
-               return mcbsp->pdata->set_clk_src(mcbsp->dev, mcbsp->fclk, src);
-       else
+       fck_src = clk_get(mcbsp->dev, src);
+       if (IS_ERR(fck_src)) {
+               dev_err(mcbsp->dev, "CLKS: could not clk_get() %s\n", src);
                return -EINVAL;
-}
-
-int omap_mcbsp_6pin_src_mux(struct omap_mcbsp *mcbsp, u8 mux)
-{
-       const char *signal, *src;
+       }
 
-       if (!mcbsp->pdata->mux_signal)
-               return -EINVAL;
+       pm_runtime_put_sync(mcbsp->dev);
 
-       switch (mux) {
-       case CLKR_SRC_CLKR:
-               signal = "clkr";
-               src = "clkr";
-               break;
-       case CLKR_SRC_CLKX:
-               signal = "clkr";
-               src = "clkx";
-               break;
-       case FSR_SRC_FSR:
-               signal = "fsr";
-               src = "fsr";
-               break;
-       case FSR_SRC_FSX:
-               signal = "fsr";
-               src = "fsx";
-               break;
-       default:
-               return -EINVAL;
+       r = clk_set_parent(mcbsp->fclk, fck_src);
+       if (r) {
+               dev_err(mcbsp->dev, "CLKS: could not clk_set_parent() to %s\n",
+                       src);
+               clk_put(fck_src);
+               return r;
        }
 
-       return mcbsp->pdata->mux_signal(mcbsp->dev, signal, src);
+       pm_runtime_get_sync(mcbsp->dev);
+
+       clk_put(fck_src);
+
+       return 0;
+
 }
 
 #define max_thres(m)                   (mcbsp->pdata->buffer_size)
index 262a6152111fe67badda011198c875974e76d377..49a67259ce5a1d115de8bce006e2d6d99b48a633 100644 (file)
@@ -334,9 +334,6 @@ void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int tx, int rx);
 /* McBSP functional clock source changing function */
 int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id);
 
-/* McBSP signal muxing API */
-int omap_mcbsp_6pin_src_mux(struct omap_mcbsp *mcbsp, u8 mux);
-
 /* Sidetone specific API */
 int omap_st_set_chgain(struct omap_mcbsp *mcbsp, int channel, s16 chgain);
 int omap_st_get_chgain(struct omap_mcbsp *mcbsp, int channel, s16 *chgain);
index 45909ca889fa17c56ecf9493cc5a3a31a4986a75..4a73ef3ae12fdb35bced35e444f45b2eb144275c 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/mfd/twl6040.h>
 #include <linux/platform_data/omap-abe-twl6040.h>
 #include <linux/module.h>
+#include <linux/of.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -39,6 +40,8 @@
 struct abe_twl6040 {
        int     jack_detection; /* board can detect jack events */
        int     mclk_freq;      /* MCLK frequency speed for twl6040 */
+
+       struct platform_device *dmic_codec_dev;
 };
 
 static int omap_abe_hw_params(struct snd_pcm_substream *substream,
@@ -181,17 +184,6 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
        int hs_trim;
        int ret = 0;
 
-       /* Disable not connected paths if not used */
-       twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone");
-       twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk");
-       twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk");
-       twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out");
-       twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator");
-       twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic");
-       twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic");
-       twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic");
-       twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In");
-
        /*
         * Configure McPDM offset cancellation based on the HSOTRIM value from
         * twl6040.
@@ -212,6 +204,24 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
                twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
        }
 
+       /*
+        * NULL pdata means we booted with DT. In this case the routing is
+        * provided and the card is fully routed, no need to mark pins.
+        */
+       if (!pdata)
+               return ret;
+
+       /* Disable not connected paths if not used */
+       twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone");
+       twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk");
+       twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk");
+       twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out");
+       twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator");
+       twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic");
+       twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic");
+       twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic");
+       twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In");
+
        return ret;
 }
 
@@ -266,52 +276,116 @@ static struct snd_soc_card omap_abe_card = {
 static __devinit int omap_abe_probe(struct platform_device *pdev)
 {
        struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev);
+       struct device_node *node = pdev->dev.of_node;
        struct snd_soc_card *card = &omap_abe_card;
        struct abe_twl6040 *priv;
        int num_links = 0;
-       int ret;
+       int ret = 0;
 
        card->dev = &pdev->dev;
 
-       if (!pdata) {
-               dev_err(&pdev->dev, "Missing pdata\n");
-               return -ENODEV;
-       }
-
        priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL);
        if (priv == NULL)
                return -ENOMEM;
 
-       if (pdata->card_name) {
-               card->name = pdata->card_name;
+       priv->dmic_codec_dev = ERR_PTR(-EINVAL);
+
+       if (node) {
+               struct device_node *dai_node;
+
+               if (snd_soc_of_parse_card_name(card, "ti,model")) {
+                       dev_err(&pdev->dev, "Card name is not provided\n");
+                       return -ENODEV;
+               }
+
+               ret = snd_soc_of_parse_audio_routing(card,
+                                               "ti,audio-routing");
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "Error while parsing DAPM routing\n");
+                       return ret;
+               }
+
+               dai_node = of_parse_phandle(node, "ti,mcpdm", 0);
+               if (!dai_node) {
+                       dev_err(&pdev->dev, "McPDM node is not provided\n");
+                       return -EINVAL;
+               }
+               abe_twl6040_dai_links[0].cpu_dai_name  = NULL;
+               abe_twl6040_dai_links[0].cpu_of_node = dai_node;
+
+               dai_node = of_parse_phandle(node, "ti,dmic", 0);
+               if (dai_node) {
+                       num_links = 2;
+                       abe_twl6040_dai_links[1].cpu_dai_name  = NULL;
+                       abe_twl6040_dai_links[1].cpu_of_node = dai_node;
+
+                       priv->dmic_codec_dev = platform_device_register_simple(
+                                               "dmic-codec", -1, NULL, 0);
+                       if (IS_ERR(priv->dmic_codec_dev)) {
+                               dev_err(&pdev->dev,
+                                       "Can't instantiate dmic-codec\n");
+                               return PTR_ERR(priv->dmic_codec_dev);
+                       }
+               } else {
+                       num_links = 1;
+               }
+
+               of_property_read_u32(node, "ti,jack-detection",
+                                    &priv->jack_detection);
+               of_property_read_u32(node, "ti,mclk-freq",
+                                    &priv->mclk_freq);
+               if (!priv->mclk_freq) {
+                       dev_err(&pdev->dev, "MCLK frequency not provided\n");
+                       ret = -EINVAL;
+                       goto err_unregister;
+               }
+
+               omap_abe_card.fully_routed = 1;
+       } else if (pdata) {
+               if (pdata->card_name) {
+                       card->name = pdata->card_name;
+               } else {
+                       dev_err(&pdev->dev, "Card name is not provided\n");
+                       return -ENODEV;
+               }
+
+               if (pdata->has_dmic)
+                       num_links = 2;
+               else
+                       num_links = 1;
+
+               priv->jack_detection = pdata->jack_detection;
+               priv->mclk_freq = pdata->mclk_freq;
        } else {
-               dev_err(&pdev->dev, "Card name is not provided\n");
+               dev_err(&pdev->dev, "Missing pdata\n");
                return -ENODEV;
        }
 
-       priv->jack_detection = pdata->jack_detection;
-       priv->mclk_freq = pdata->mclk_freq;
-
 
        if (!priv->mclk_freq) {
                dev_err(&pdev->dev, "MCLK frequency missing\n");
-               return -ENODEV;
+               ret = -ENODEV;
+               goto err_unregister;
        }
 
-       if (pdata->has_dmic)
-               num_links = 2;
-       else
-               num_links = 1;
-
        card->dai_link = abe_twl6040_dai_links;
        card->num_links = num_links;
 
        snd_soc_card_set_drvdata(card, priv);
 
        ret = snd_soc_register_card(card);
-       if (ret)
+       if (ret) {
                dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
                        ret);
+               goto err_unregister;
+       }
+
+       return 0;
+
+err_unregister:
+       if (!IS_ERR(priv->dmic_codec_dev))
+               platform_device_unregister(priv->dmic_codec_dev);
 
        return ret;
 }
@@ -319,17 +393,28 @@ static __devinit int omap_abe_probe(struct platform_device *pdev)
 static int __devexit omap_abe_remove(struct platform_device *pdev)
 {
        struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
 
        snd_soc_unregister_card(card);
 
+       if (!IS_ERR(priv->dmic_codec_dev))
+               platform_device_unregister(priv->dmic_codec_dev);
+
        return 0;
 }
 
+static const struct of_device_id omap_abe_of_match[] = {
+       {.compatible = "ti,abe-twl6040", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, omap_abe_of_match);
+
 static struct platform_driver omap_abe_driver = {
        .driver = {
                .name = "omap-abe-twl6040",
                .owner = THIS_MODULE,
                .pm = &snd_soc_pm_ops,
+               .of_match_table = omap_abe_of_match,
        },
        .probe = omap_abe_probe,
        .remove = __devexit_p(omap_abe_remove),
index 75f5dca0e8d2c0a1dd4d107ece0cd2023c9ad583..68f2cd1a92061504bd332c683d286c8ffe8414eb 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
 #include <linux/of_device.h>
-#include <plat/dma.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -63,8 +62,6 @@ struct omap_dmic {
  */
 static struct omap_pcm_dma_data omap_dmic_dai_dma_params = {
        .name           = "DMIC capture",
-       .data_type      = OMAP_DMA_DATA_TYPE_S32,
-       .sync_mode      = OMAP_DMA_SYNC_PACKET,
 };
 
 static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val)
@@ -121,6 +118,7 @@ static int omap_dmic_dai_startup(struct snd_pcm_substream *substream,
 
        mutex_unlock(&dmic->mutex);
 
+       snd_soc_dai_set_dma_data(dai, substream, &omap_dmic_dai_dma_params);
        return ret;
 }
 
@@ -205,6 +203,7 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
                                    struct snd_soc_dai *dai)
 {
        struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
+       struct omap_pcm_dma_data *dma_data;
        int channels;
 
        dmic->clk_div = omap_dmic_select_divider(dmic, params_rate(params));
@@ -230,8 +229,8 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
        }
 
        /* packet size is threshold * channels */
-       omap_dmic_dai_dma_params.packet_size = dmic->threshold * channels;
-       snd_soc_dai_set_dma_data(dai, substream, &omap_dmic_dai_dma_params);
+       dma_data = snd_soc_dai_get_dma_data(dai, substream);
+       dma_data->packet_size = dmic->threshold * channels;
 
        return 0;
 }
index a08245d9203cddfd20e38254d02104c25c18f9a8..f59c69fb400ee60861bf334067aa1ee29df00d12 100644 (file)
@@ -34,7 +34,6 @@
 #include <sound/asoundef.h>
 #include <video/omapdss.h>
 
-#include <plat/dma.h>
 #include "omap-pcm.h"
 #include "omap-hdmi.h"
 
@@ -68,6 +67,9 @@ static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream,
                dev_err(dai->dev, "audio not supported\n");
                return -ENODEV;
        }
+
+       snd_soc_dai_set_dma_data(dai, substream, &priv->dma_params);
+
        return 0;
 }
 
@@ -86,24 +88,24 @@ static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
        struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
        struct snd_aes_iec958 *iec = &priv->iec;
        struct snd_cea_861_aud_if *cea = &priv->cea;
+       struct omap_pcm_dma_data *dma_data;
        int err = 0;
 
+       dma_data = snd_soc_dai_get_dma_data(dai, substream);
+
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
-               priv->dma_params.packet_size = 16;
+               dma_data->packet_size = 16;
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
-               priv->dma_params.packet_size = 32;
+               dma_data->packet_size = 32;
                break;
        default:
                dev_err(dai->dev, "format not supported!\n");
                return -EINVAL;
        }
 
-       priv->dma_params.data_type = OMAP_DMA_DATA_TYPE_S32;
-
-       snd_soc_dai_set_dma_data(dai, substream,
-                                &priv->dma_params);
+       dma_data->data_type = 32;
 
        /*
         * fill the IEC-60958 channel status word
@@ -290,7 +292,6 @@ static __devinit int omap_hdmi_probe(struct platform_device *pdev)
 
        hdmi_data->dma_params.dma_req =  hdmi_rsrc->start;
        hdmi_data->dma_params.name = "HDMI playback";
-       hdmi_data->dma_params.sync_mode = OMAP_DMA_SYNC_PACKET;
 
        /*
         * TODO: We assume that there is only one DSS HDMI device. Future
index 1b18627763cede8ba823b90d93fc127f105758dd..a6ee157478593f1e5eb338e51597df176308a953 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -33,7 +35,6 @@
 #include <sound/soc.h>
 
 #include <plat/cpu.h>
-#include <plat/dma.h>
 #include <linux/platform_data/asoc-ti-mcbsp.h>
 #include "mcbsp.h"
 #include "omap-mcbsp.h"
@@ -80,9 +81,6 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
         */
        if (dma_data->packet_size)
                words = dma_data->packet_size;
-       else if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
-               words = snd_pcm_lib_period_bytes(substream) /
-                                               (mcbsp->wlen / 8);
        else
                words = 1;
 
@@ -154,6 +152,9 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
                                           SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
        }
 
+       snd_soc_dai_set_dma_data(cpu_dai, substream,
+                                &mcbsp->dma_data[substream->stream]);
+
        return err;
 }
 
@@ -227,20 +228,18 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
        struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
        struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
        struct omap_pcm_dma_data *dma_data;
-       int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT;
+       int wlen, channels, wpf;
        int pkt_size = 0;
        unsigned int format, div, framesize, master;
 
-       dma_data = &mcbsp->dma_data[substream->stream];
+       dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
        channels = params_channels(params);
 
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
-               dma_data->data_type = OMAP_DMA_DATA_TYPE_S16;
                wlen = 16;
                break;
        case SNDRV_PCM_FORMAT_S32_LE:
-               dma_data->data_type = OMAP_DMA_DATA_TYPE_S32;
                wlen = 32;
                break;
        default:
@@ -250,6 +249,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
                dma_data->set_threshold = omap_mcbsp_set_threshold;
                if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
                        int period_words, max_thrsh;
+                       int divider = 0;
 
                        period_words = params_period_bytes(params) / (wlen / 8);
                        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -257,46 +257,30 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
                        else
                                max_thrsh = mcbsp->max_rx_thres;
                        /*
-                        * If the period contains less or equal number of words,
-                        * we are using the original threshold mode setup:
-                        * McBSP threshold = sDMA frame size = period_size
-                        * Otherwise we switch to sDMA packet mode:
-                        * McBSP threshold = sDMA packet size
-                        * sDMA frame size = period size
+                        * Use sDMA packet mode if McBSP is in threshold mode:
+                        * If period words less than the FIFO size the packet
+                        * size is set to the number of period words, otherwise
+                        * Look for the biggest threshold value which divides
+                        * the period size evenly.
                         */
-                       if (period_words > max_thrsh) {
-                               int divider = 0;
-
-                               /*
-                                * Look for the biggest threshold value, which
-                                * divides the period size evenly.
-                                */
-                               divider = period_words / max_thrsh;
-                               if (period_words % max_thrsh)
-                                       divider++;
-                               while (period_words % divider &&
-                                       divider < period_words)
-                                       divider++;
-                               if (divider == period_words)
-                                       return -EINVAL;
-
-                               pkt_size = period_words / divider;
-                               sync_mode = OMAP_DMA_SYNC_PACKET;
-                       } else {
-                               sync_mode = OMAP_DMA_SYNC_FRAME;
-                       }
+                       divider = period_words / max_thrsh;
+                       if (period_words % max_thrsh)
+                               divider++;
+                       while (period_words % divider &&
+                               divider < period_words)
+                               divider++;
+                       if (divider == period_words)
+                               return -EINVAL;
+
+                       pkt_size = period_words / divider;
                } else if (channels > 1) {
                        /* Use packet mode for non mono streams */
                        pkt_size = channels;
-                       sync_mode = OMAP_DMA_SYNC_PACKET;
                }
        }
 
-       dma_data->sync_mode = sync_mode;
        dma_data->packet_size = pkt_size;
 
-       snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
-
        if (mcbsp->configured) {
                /* McBSP already configured by another stream */
                return 0;
@@ -399,12 +383,14 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        /* Generic McBSP register settings */
        regs->spcr2     |= XINTM(3) | FREE;
        regs->spcr1     |= RINTM(3);
-       /* RFIG and XFIG are not defined in 34xx */
-       if (!cpu_is_omap34xx() && !cpu_is_omap44xx()) {
+       /* RFIG and XFIG are not defined in 2430 and on OMAP3+ */
+       if (!mcbsp->pdata->has_ccr) {
                regs->rcr2      |= RFIG;
                regs->xcr2      |= XFIG;
        }
-       if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) {
+
+       /* Configure XCCR/RCCR only for revisions which have ccr registers */
+       if (mcbsp->pdata->has_ccr) {
                regs->xccr = DXENDLY(1) | XDMAEN | XDISABLE;
                regs->rccr = RFULL_CYCLE | RDMAEN | RDISABLE;
        }
@@ -517,21 +503,9 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                        return -EBUSY;
        }
 
-       if (clk_id == OMAP_MCBSP_SYSCLK_CLK ||
-           clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK ||
-           clk_id == OMAP_MCBSP_SYSCLK_CLKS_EXT ||
-           clk_id == OMAP_MCBSP_SYSCLK_CLKX_EXT ||
-           clk_id == OMAP_MCBSP_SYSCLK_CLKR_EXT) {
-               mcbsp->in_freq = freq;
-               regs->srgr2     &= ~CLKSM;
-               regs->pcr0      &= ~SCLKME;
-       } else if (cpu_class_is_omap1()) {
-               /*
-                * McBSP CLKR/FSR signal muxing functions are only available on
-                * OMAP2 or newer versions
-                */
-               return -EINVAL;
-       }
+       mcbsp->in_freq = freq;
+       regs->srgr2 &= ~CLKSM;
+       regs->pcr0 &= ~SCLKME;
 
        switch (clk_id) {
        case OMAP_MCBSP_SYSCLK_CLK:
@@ -559,20 +533,6 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        case OMAP_MCBSP_SYSCLK_CLKR_EXT:
                regs->pcr0      |= SCLKME;
                break;
-
-
-       case OMAP_MCBSP_CLKR_SRC_CLKR:
-               err = omap_mcbsp_6pin_src_mux(mcbsp, CLKR_SRC_CLKR);
-               break;
-       case OMAP_MCBSP_CLKR_SRC_CLKX:
-               err = omap_mcbsp_6pin_src_mux(mcbsp, CLKR_SRC_CLKX);
-               break;
-       case OMAP_MCBSP_FSR_SRC_FSR:
-               err = omap_mcbsp_6pin_src_mux(mcbsp, FSR_SRC_FSR);
-               break;
-       case OMAP_MCBSP_FSR_SRC_FSX:
-               err = omap_mcbsp_6pin_src_mux(mcbsp, FSR_SRC_FSX);
-               break;
        default:
                err = -ENODEV;
        }
@@ -642,9 +602,9 @@ static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-#define OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(channel)                      \
+#define OMAP_MCBSP_ST_CHANNEL_VOLUME(channel)                          \
 static int                                                             \
-omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc,        \
+omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc,                \
                                        struct snd_ctl_elem_value *uc)  \
 {                                                                      \
        struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc);            \
@@ -660,11 +620,10 @@ omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc,   \
                                                                        \
        /* OMAP McBSP implementation uses index values 0..4 */          \
        return omap_st_set_chgain(mcbsp, channel, val);                 \
-}
-
-#define OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(channel)                      \
+}                                                                      \
+                                                                       \
 static int                                                             \
-omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc,        \
+omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc,                \
                                        struct snd_ctl_elem_value *uc)  \
 {                                                                      \
        struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc);            \
@@ -678,10 +637,8 @@ omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc,    \
        return 0;                                                       \
 }
 
-OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(0)
-OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(1)
-OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(0)
-OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(1)
+OMAP_MCBSP_ST_CHANNEL_VOLUME(0)
+OMAP_MCBSP_ST_CHANNEL_VOLUME(1)
 
 static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
@@ -711,41 +668,34 @@ static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static const struct snd_kcontrol_new omap_mcbsp2_st_controls[] = {
-       SOC_SINGLE_EXT("McBSP2 Sidetone Switch", 1, 0, 1, 0,
-                       omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),
-       OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 0 Volume",
-                                     -32768, 32767,
-                                     omap_mcbsp_get_st_ch0_volume,
-                                     omap_mcbsp_set_st_ch0_volume),
-       OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 1 Volume",
-                                     -32768, 32767,
-                                     omap_mcbsp_get_st_ch1_volume,
-                                     omap_mcbsp_set_st_ch1_volume),
-};
+#define OMAP_MCBSP_ST_CONTROLS(port)                                     \
+static const struct snd_kcontrol_new omap_mcbsp##port##_st_controls[] = { \
+SOC_SINGLE_EXT("McBSP" #port " Sidetone Switch", 1, 0, 1, 0,             \
+              omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),           \
+OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 0 Volume", \
+                             -32768, 32767,                              \
+                             omap_mcbsp_get_st_ch0_volume,               \
+                             omap_mcbsp_set_st_ch0_volume),              \
+OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP" #port " Sidetone Channel 1 Volume", \
+                             -32768, 32767,                              \
+                             omap_mcbsp_get_st_ch1_volume,               \
+                             omap_mcbsp_set_st_ch1_volume),              \
+}
 
-static const struct snd_kcontrol_new omap_mcbsp3_st_controls[] = {
-       SOC_SINGLE_EXT("McBSP3 Sidetone Switch", 2, 0, 1, 0,
-                       omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),
-       OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 0 Volume",
-                                     -32768, 32767,
-                                     omap_mcbsp_get_st_ch0_volume,
-                                     omap_mcbsp_set_st_ch0_volume),
-       OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 1 Volume",
-                                     -32768, 32767,
-                                     omap_mcbsp_get_st_ch1_volume,
-                                     omap_mcbsp_set_st_ch1_volume),
-};
+OMAP_MCBSP_ST_CONTROLS(2);
+OMAP_MCBSP_ST_CONTROLS(3);
 
 int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
 
-       if (!mcbsp->st_data)
-               return -ENODEV;
+       if (!mcbsp->st_data) {
+               dev_warn(mcbsp->dev, "No sidetone data for port\n");
+               return 0;
+       }
 
-       switch (cpu_dai->id) {
+       switch (mcbsp->id) {
        case 2: /* McBSP 2 */
                return snd_soc_add_dai_controls(cpu_dai,
                                        omap_mcbsp2_st_controls,
@@ -762,13 +712,74 @@ int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd)
 }
 EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);
 
+static struct omap_mcbsp_platform_data omap2420_pdata = {
+       .reg_step = 4,
+       .reg_size = 2,
+};
+
+static struct omap_mcbsp_platform_data omap2430_pdata = {
+       .reg_step = 4,
+       .reg_size = 4,
+       .has_ccr = true,
+};
+
+static struct omap_mcbsp_platform_data omap3_pdata = {
+       .reg_step = 4,
+       .reg_size = 4,
+       .has_ccr = true,
+       .has_wakeup = true,
+};
+
+static struct omap_mcbsp_platform_data omap4_pdata = {
+       .reg_step = 4,
+       .reg_size = 4,
+       .has_ccr = true,
+       .has_wakeup = true,
+};
+
+static const struct of_device_id omap_mcbsp_of_match[] = {
+       {
+               .compatible = "ti,omap2420-mcbsp",
+               .data = &omap2420_pdata,
+       },
+       {
+               .compatible = "ti,omap2430-mcbsp",
+               .data = &omap2430_pdata,
+       },
+       {
+               .compatible = "ti,omap3-mcbsp",
+               .data = &omap3_pdata,
+       },
+       {
+               .compatible = "ti,omap4-mcbsp",
+               .data = &omap4_pdata,
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, omap_mcbsp_of_match);
+
 static __devinit int asoc_mcbsp_probe(struct platform_device *pdev)
 {
        struct omap_mcbsp_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct omap_mcbsp *mcbsp;
+       const struct of_device_id *match;
        int ret;
 
-       if (!pdata) {
+       match = of_match_device(omap_mcbsp_of_match, &pdev->dev);
+       if (match) {
+               struct device_node *node = pdev->dev.of_node;
+               int buffer_size;
+
+               pdata = devm_kzalloc(&pdev->dev,
+                                    sizeof(struct omap_mcbsp_platform_data),
+                                    GFP_KERNEL);
+               if (!pdata)
+                       return -ENOMEM;
+
+               memcpy(pdata, match->data, sizeof(*pdata));
+               if (!of_property_read_u32(node, "ti,buffer-size", &buffer_size))
+                       pdata->buffer_size = buffer_size;
+       } else if (!pdata) {
                dev_err(&pdev->dev, "missing platform data.\n");
                return -EINVAL;
        }
@@ -810,6 +821,7 @@ static struct platform_driver asoc_mcbsp_driver = {
        .driver = {
                        .name = "omap-mcbsp",
                        .owner = THIS_MODULE,
+                       .of_match_table = omap_mcbsp_of_match,
        },
 
        .probe = asoc_mcbsp_probe,
index f877b16f19c94d08fe3f6bf71052d576f1cede24..ba8386a0d8dc511c9f9b14febf9714bfa9488a30 100644 (file)
@@ -32,10 +32,6 @@ enum omap_mcbsp_clksrg_clk {
        OMAP_MCBSP_SYSCLK_CLK,          /* Internal ICLK */
        OMAP_MCBSP_SYSCLK_CLKX_EXT,     /* External CLKX pin */
        OMAP_MCBSP_SYSCLK_CLKR_EXT,     /* External CLKR pin */
-       OMAP_MCBSP_CLKR_SRC_CLKR,       /* CLKR from CLKR pin */
-       OMAP_MCBSP_CLKR_SRC_CLKX,       /* CLKR from CLKX pin */
-       OMAP_MCBSP_FSR_SRC_FSR,         /* FSR from FSR pin */
-       OMAP_MCBSP_FSR_SRC_FSX,         /* FSR from FSX pin */
 };
 
 /* McBSP dividers */
@@ -43,22 +39,6 @@ enum omap_mcbsp_div {
        OMAP_MCBSP_CLKGDV,              /* Sample rate generator divider */
 };
 
-#if defined(CONFIG_SOC_OMAP2420)
-#define NUM_LINKS      2
-#endif
-#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
-#undef  NUM_LINKS
-#define NUM_LINKS      3
-#endif
-#if defined(CONFIG_ARCH_OMAP4)
-#undef  NUM_LINKS
-#define NUM_LINKS      4
-#endif
-#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_OMAP2430)
-#undef  NUM_LINKS
-#define NUM_LINKS      5
-#endif
-
 int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd);
 
 #endif
index ea053c3d2ab1f8455a9d9e238895c390a0e0fe99..c02b001ee4b51816235147ddb420186c525ecd43 100644 (file)
@@ -40,7 +40,6 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 
-#include <plat/dma.h>
 #include <plat/omap_hwmod.h>
 #include "omap-mcpdm.h"
 #include "omap-pcm.h"
@@ -73,17 +72,9 @@ struct omap_mcpdm {
 static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
        {
                .name = "Audio playback",
-               .dma_req = OMAP44XX_DMA_MCPDM_DL,
-               .data_type = OMAP_DMA_DATA_TYPE_S32,
-               .sync_mode = OMAP_DMA_SYNC_PACKET,
-               .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_REG_DN_DATA,
        },
        {
                .name = "Audio capture",
-               .dma_req = OMAP44XX_DMA_MCPDM_UP,
-               .data_type = OMAP_DMA_DATA_TYPE_S32,
-               .sync_mode = OMAP_DMA_SYNC_PACKET,
-               .port_addr = OMAP44XX_MCPDM_L3_BASE + MCPDM_REG_UP_DATA,
        },
 };
 
@@ -278,9 +269,11 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
                }
                omap_mcpdm_open_streams(mcpdm);
        }
-
        mutex_unlock(&mcpdm->mutex);
 
+       snd_soc_dai_set_dma_data(dai, substream,
+                                &omap_mcpdm_dai_dma_params[substream->stream]);
+
        return 0;
 }
 
@@ -335,7 +328,7 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       dma_data = &omap_mcpdm_dai_dma_params[stream];
+       dma_data = snd_soc_dai_get_dma_data(dai, substream);
 
        /* Configure McPDM channels, and DMA packet size */
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -347,8 +340,6 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
                dma_data->packet_size = mcpdm->up_threshold * channels;
        }
 
-       snd_soc_dai_set_dma_data(dai, substream, dma_data);
-
        return 0;
 }
 
@@ -447,9 +438,8 @@ static __devinit int asoc_mcpdm_probe(struct platform_device *pdev)
 {
        struct omap_mcpdm *mcpdm;
        struct resource *res;
-       int ret = 0;
 
-       mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL);
+       mcpdm = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcpdm), GFP_KERNEL);
        if (!mcpdm)
                return -ENOMEM;
 
@@ -457,56 +447,54 @@ static __devinit int asoc_mcpdm_probe(struct platform_device *pdev)
 
        mutex_init(&mcpdm->mutex);
 
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
+       if (res == NULL)
+               return -ENOMEM;
+
+       omap_mcpdm_dai_dma_params[0].port_addr = res->start + MCPDM_REG_DN_DATA;
+       omap_mcpdm_dai_dma_params[1].port_addr = res->start + MCPDM_REG_UP_DATA;
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res == NULL) {
-               dev_err(&pdev->dev, "no resource\n");
-               goto err_res;
-       }
+       if (res == NULL)
+               return -ENOMEM;
 
-       if (!request_mem_region(res->start, resource_size(res), "McPDM")) {
-               ret = -EBUSY;
-               goto err_res;
-       }
+       res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "dn_link");
+       if (!res)
+               return -ENODEV;
 
-       mcpdm->io_base = ioremap(res->start, resource_size(res));
-       if (!mcpdm->io_base) {
-               ret = -ENOMEM;
-               goto err_iomap;
-       }
+       omap_mcpdm_dai_dma_params[0].dma_req = res->start;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "up_link");
+       if (!res)
+               return -ENODEV;
+
+       omap_mcpdm_dai_dma_params[1].dma_req = res->start;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
+       if (res == NULL)
+               return -ENOMEM;
+
+       if (!devm_request_mem_region(&pdev->dev, res->start,
+                                    resource_size(res), "McPDM"))
+               return -EBUSY;
+
+       mcpdm->io_base = devm_ioremap(&pdev->dev, res->start,
+                                     resource_size(res));
+       if (!mcpdm->io_base)
+               return -ENOMEM;
 
        mcpdm->irq = platform_get_irq(pdev, 0);
-       if (mcpdm->irq < 0) {
-               ret = mcpdm->irq;
-               goto err_irq;
-       }
+       if (mcpdm->irq < 0)
+               return mcpdm->irq;
 
        mcpdm->dev = &pdev->dev;
 
-       ret = snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
-       if (!ret)
-               return 0;
-
-err_irq:
-       iounmap(mcpdm->io_base);
-err_iomap:
-       release_mem_region(res->start, resource_size(res));
-err_res:
-       kfree(mcpdm);
-       return ret;
+       return snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
 }
 
 static int __devexit asoc_mcpdm_remove(struct platform_device *pdev)
 {
-       struct omap_mcpdm *mcpdm = platform_get_drvdata(pdev);
-       struct resource *res;
-
        snd_soc_unregister_dai(&pdev->dev);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       iounmap(mcpdm->io_base);
-       release_mem_region(res->start, resource_size(res));
-
-       kfree(mcpdm);
        return 0;
 }
 
index b309941798850d1143aaf5c4bfdf8c67a5967e09..340874ebf9ae79cb550cbfe54e81850802448e16 100644 (file)
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/omap-dma.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
 #include <sound/soc.h>
 
 #include <plat/cpu.h>
-#include <plat/dma.h>
 #include "omap-pcm.h"
 
 static const struct snd_pcm_hardware omap_pcm_hardware = {
@@ -50,61 +51,34 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
        .buffer_bytes_max       = 128 * 1024,
 };
 
-struct omap_runtime_data {
-       spinlock_t                      lock;
-       struct omap_pcm_dma_data        *dma_data;
-       int                             dma_ch;
-       int                             period_index;
-};
-
-static void omap_pcm_dma_irq(int ch, u16 stat, void *data)
+static int omap_pcm_get_dma_buswidth(int num_bits)
 {
-       struct snd_pcm_substream *substream = data;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct omap_runtime_data *prtd = runtime->private_data;
-       unsigned long flags;
-
-       if ((cpu_is_omap1510())) {
-               /*
-                * OMAP1510 doesn't fully support DMA progress counter
-                * and there is no software emulation implemented yet,
-                * so have to maintain our own progress counters
-                * that can be used by omap_pcm_pointer() instead.
-                */
-               spin_lock_irqsave(&prtd->lock, flags);
-               if ((stat == OMAP_DMA_LAST_IRQ) &&
-                               (prtd->period_index == runtime->periods - 1)) {
-                       /* we are in sync, do nothing */
-                       spin_unlock_irqrestore(&prtd->lock, flags);
-                       return;
-               }
-               if (prtd->period_index >= 0) {
-                       if (stat & OMAP_DMA_BLOCK_IRQ) {
-                               /* end of buffer reached, loop back */
-                               prtd->period_index = 0;
-                       } else if (stat & OMAP_DMA_LAST_IRQ) {
-                               /* update the counter for the last period */
-                               prtd->period_index = runtime->periods - 1;
-                       } else if (++prtd->period_index >= runtime->periods) {
-                               /* end of buffer missed? loop back */
-                               prtd->period_index = 0;
-                       }
-               }
-               spin_unlock_irqrestore(&prtd->lock, flags);
-       }
+       int buswidth;
 
-       snd_pcm_period_elapsed(substream);
+       switch (num_bits) {
+       case 16:
+               buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
+               break;
+       case 32:
+               buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
+               break;
+       default:
+               buswidth = -EINVAL;
+               break;
+       }
+       return buswidth;
 }
 
+
 /* this may get called several times by oss emulation */
 static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
                              struct snd_pcm_hw_params *params)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct omap_runtime_data *prtd = runtime->private_data;
        struct omap_pcm_dma_data *dma_data;
-
+       struct dma_slave_config config;
+       struct dma_chan *chan;
        int err = 0;
 
        dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
@@ -117,162 +91,78 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
        snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
        runtime->dma_bytes = params_buffer_bytes(params);
 
-       if (prtd->dma_data)
-               return 0;
-       prtd->dma_data = dma_data;
-       err = omap_request_dma(dma_data->dma_req, dma_data->name,
-                              omap_pcm_dma_irq, substream, &prtd->dma_ch);
-       if (!err) {
-               /*
-                * Link channel with itself so DMA doesn't need any
-                * reprogramming while looping the buffer
-                */
-               omap_dma_link_lch(prtd->dma_ch, prtd->dma_ch);
-       }
+       chan = snd_dmaengine_pcm_get_chan(substream);
+       if (!chan)
+               return -EINVAL;
 
-       return err;
-}
+       /* fills in addr_width and direction */
+       err = snd_hwparams_to_dma_slave_config(substream, params, &config);
+       if (err)
+               return err;
 
-static int omap_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct omap_runtime_data *prtd = runtime->private_data;
+       /* Override the *_dma addr_width if requested by the DAI driver */
+       if (dma_data->data_type) {
+               int buswidth = omap_pcm_get_dma_buswidth(dma_data->data_type);
 
-       if (prtd->dma_data == NULL)
-               return 0;
-
-       omap_dma_unlink_lch(prtd->dma_ch, prtd->dma_ch);
-       omap_free_dma(prtd->dma_ch);
-       prtd->dma_data = NULL;
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       config.dst_addr_width = buswidth;
+               else
+                       config.src_addr_width = buswidth;
+       }
 
-       snd_pcm_set_runtime_buffer(substream, NULL);
+       config.src_addr = dma_data->port_addr;
+       config.dst_addr = dma_data->port_addr;
+       config.src_maxburst = dma_data->packet_size;
+       config.dst_maxburst = dma_data->packet_size;
 
-       return 0;
+       return dmaengine_slave_config(chan, &config);
 }
 
-static int omap_pcm_prepare(struct snd_pcm_substream *substream)
+static int omap_pcm_hw_free(struct snd_pcm_substream *substream)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct omap_runtime_data *prtd = runtime->private_data;
-       struct omap_pcm_dma_data *dma_data = prtd->dma_data;
-       struct omap_dma_channel_params dma_params;
-       int bytes;
-
-       /* return if this is a bufferless transfer e.g.
-        * codec <--> BT codec or GSM modem -- lg FIXME */
-       if (!prtd->dma_data)
-               return 0;
-
-       memset(&dma_params, 0, sizeof(dma_params));
-       dma_params.data_type                    = dma_data->data_type;
-       dma_params.trigger                      = dma_data->dma_req;
-       dma_params.sync_mode                    = dma_data->sync_mode;
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               dma_params.src_amode            = OMAP_DMA_AMODE_POST_INC;
-               dma_params.dst_amode            = OMAP_DMA_AMODE_CONSTANT;
-               dma_params.src_or_dst_synch     = OMAP_DMA_DST_SYNC;
-               dma_params.src_start            = runtime->dma_addr;
-               dma_params.dst_start            = dma_data->port_addr;
-               dma_params.dst_port             = OMAP_DMA_PORT_MPUI;
-               dma_params.dst_fi               = dma_data->packet_size;
-       } else {
-               dma_params.src_amode            = OMAP_DMA_AMODE_CONSTANT;
-               dma_params.dst_amode            = OMAP_DMA_AMODE_POST_INC;
-               dma_params.src_or_dst_synch     = OMAP_DMA_SRC_SYNC;
-               dma_params.src_start            = dma_data->port_addr;
-               dma_params.dst_start            = runtime->dma_addr;
-               dma_params.src_port             = OMAP_DMA_PORT_MPUI;
-               dma_params.src_fi               = dma_data->packet_size;
-       }
-       /*
-        * Set DMA transfer frame size equal to ALSA period size and frame
-        * count as no. of ALSA periods. Then with DMA frame interrupt enabled,
-        * we can transfer the whole ALSA buffer with single DMA transfer but
-        * still can get an interrupt at each period bounary
-        */
-       bytes = snd_pcm_lib_period_bytes(substream);
-       dma_params.elem_count   = bytes >> dma_data->data_type;
-       dma_params.frame_count  = runtime->periods;
-       omap_set_dma_params(prtd->dma_ch, &dma_params);
-
-       if ((cpu_is_omap1510()))
-               omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ |
-                             OMAP_DMA_LAST_IRQ | OMAP_DMA_BLOCK_IRQ);
-       else if (!substream->runtime->no_period_wakeup)
-               omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ);
-       else {
-               /*
-                * No period wakeup:
-                * we need to disable BLOCK_IRQ, which is enabled by the omap
-                * dma core at request dma time.
-                */
-               omap_disable_dma_irq(prtd->dma_ch, OMAP_DMA_BLOCK_IRQ);
-       }
-
-       if (!(cpu_class_is_omap1())) {
-               omap_set_dma_src_burst_mode(prtd->dma_ch,
-                                               OMAP_DMA_DATA_BURST_16);
-               omap_set_dma_dest_burst_mode(prtd->dma_ch,
-                                               OMAP_DMA_DATA_BURST_16);
-       }
-
+       snd_pcm_set_runtime_buffer(substream, NULL);
        return 0;
 }
 
 static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct omap_runtime_data *prtd = runtime->private_data;
-       struct omap_pcm_dma_data *dma_data = prtd->dma_data;
-       unsigned long flags;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct omap_pcm_dma_data *dma_data;
        int ret = 0;
 
-       spin_lock_irqsave(&prtd->lock, flags);
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               prtd->period_index = 0;
                /* Configure McBSP internal buffer usage */
                if (dma_data->set_threshold)
                        dma_data->set_threshold(substream);
-
-               omap_start_dma(prtd->dma_ch);
                break;
 
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               prtd->period_index = -1;
-               omap_stop_dma(prtd->dma_ch);
                break;
        default:
                ret = -EINVAL;
        }
-       spin_unlock_irqrestore(&prtd->lock, flags);
+
+       if (ret == 0)
+               ret = snd_dmaengine_pcm_trigger(substream, cmd);
 
        return ret;
 }
 
 static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct omap_runtime_data *prtd = runtime->private_data;
-       dma_addr_t ptr;
        snd_pcm_uframes_t offset;
 
-       if (cpu_is_omap1510()) {
-               offset = prtd->period_index * runtime->period_size;
-       } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-               ptr = omap_get_dma_dst_pos(prtd->dma_ch);
-               offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
-       } else {
-               ptr = omap_get_dma_src_pos(prtd->dma_ch);
-               offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
-       }
-
-       if (offset >= runtime->buffer_size)
-               offset = 0;
+       if (cpu_is_omap1510())
+               offset = snd_dmaengine_pcm_pointer_no_residue(substream);
+       else
+               offset = snd_dmaengine_pcm_pointer(substream);
 
        return offset;
 }
@@ -280,7 +170,8 @@ static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
 static int omap_pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
-       struct omap_runtime_data *prtd;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct omap_pcm_dma_data *dma_data;
        int ret;
 
        snd_soc_set_runtime_hwparams(substream, &omap_pcm_hardware);
@@ -289,25 +180,17 @@ static int omap_pcm_open(struct snd_pcm_substream *substream)
        ret = snd_pcm_hw_constraint_integer(runtime,
                                            SNDRV_PCM_HW_PARAM_PERIODS);
        if (ret < 0)
-               goto out;
+               return ret;
 
-       prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
-       if (prtd == NULL) {
-               ret = -ENOMEM;
-               goto out;
-       }
-       spin_lock_init(&prtd->lock);
-       runtime->private_data = prtd;
-
-out:
+       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+       ret = snd_dmaengine_pcm_open(substream, omap_dma_filter_fn,
+                                    &dma_data->dma_req);
        return ret;
 }
 
 static int omap_pcm_close(struct snd_pcm_substream *substream)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
-
-       kfree(runtime->private_data);
+       snd_dmaengine_pcm_close(substream);
        return 0;
 }
 
@@ -328,7 +211,6 @@ static struct snd_pcm_ops omap_pcm_ops = {
        .ioctl          = snd_pcm_lib_ioctl,
        .hw_params      = omap_pcm_hw_params,
        .hw_free        = omap_pcm_hw_free,
-       .prepare        = omap_pcm_prepare,
        .trigger        = omap_pcm_trigger,
        .pointer        = omap_pcm_pointer,
        .mmap           = omap_pcm_mmap,
index b92248cbd47a86fe60aa0a2db505a4d976d400d5..cabe74c4068b88da547c45736bcda36490402ae9 100644 (file)
@@ -32,8 +32,8 @@ struct omap_pcm_dma_data {
        int             dma_req;        /* DMA request line */
        unsigned long   port_addr;      /* transmit/receive register */
        void (*set_threshold)(struct snd_pcm_substream *substream);
-       int             data_type;      /* data type 8,16,32 */
-       int             sync_mode;      /* DMA sync mode */
+       int             data_type;      /* 8, 16, 32 (bits) or 0 to let omap-pcm
+                                        * to decide the sDMA data type */
        int             packet_size;    /* packet size only in PACKET mode */
 };
 
diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c
new file mode 100644 (file)
index 0000000..3b97b87
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * omap-twl4030.c  --  SoC audio for TI SoC based boards with twl4030 codec
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
+ * All rights reserved.
+ *
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * This driver replaces the following machine drivers:
+ * omap3beagle (Author: Steve Sakoman <steve@sakoman.com>)
+ * omap3evm (Author: Anuj Aggarwal <anuj.aggarwal@ti.com>)
+ * overo (Author: Steve Sakoman <steve@sakoman.com>)
+ * igep0020 (Author: Enric Balletbo i Serra <eballetbo@iseebcn.com>)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/platform_data/omap-twl4030.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include "omap-mcbsp.h"
+#include "omap-pcm.h"
+
+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_codec *codec = rtd->codec;
+       struct snd_soc_card *card = codec->card;
+       unsigned int fmt;
+       int ret;
+
+       switch (params_channels(params)) {
+       case 2: /* Stereo I2S mode */
+               fmt =   SND_SOC_DAIFMT_I2S |
+                       SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBM_CFM;
+               break;
+       case 4: /* Four channel TDM mode */
+               fmt =   SND_SOC_DAIFMT_DSP_A |
+                       SND_SOC_DAIFMT_IB_NF |
+                       SND_SOC_DAIFMT_CBM_CFM;
+               break;
+       default:
+               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;
+}
+
+static struct snd_soc_ops omap_twl4030_ops = {
+       .hw_params = omap_twl4030_hw_params,
+};
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link omap_twl4030_dai_links[] = {
+       {
+               .name = "TWL4030",
+               .stream_name = "TWL4030",
+               .cpu_dai_name = "omap-mcbsp.2",
+               .codec_dai_name = "twl4030-hifi",
+               .platform_name = "omap-pcm-audio",
+               .codec_name = "twl4030-codec",
+               .ops = &omap_twl4030_ops,
+       },
+};
+
+/* Audio machine driver */
+static struct snd_soc_card omap_twl4030_card = {
+       .owner = THIS_MODULE,
+       .dai_link = omap_twl4030_dai_links,
+       .num_links = ARRAY_SIZE(omap_twl4030_dai_links),
+};
+
+static __devinit int omap_twl4030_probe(struct platform_device *pdev)
+{
+       struct omap_tw4030_pdata *pdata = dev_get_platdata(&pdev->dev);
+       struct device_node *node = pdev->dev.of_node;
+       struct snd_soc_card *card = &omap_twl4030_card;
+       int ret = 0;
+
+       card->dev = &pdev->dev;
+
+       if (node) {
+               struct device_node *dai_node;
+
+               if (snd_soc_of_parse_card_name(card, "ti,model")) {
+                       dev_err(&pdev->dev, "Card name is not provided\n");
+                       return -ENODEV;
+               }
+
+               dai_node = of_parse_phandle(node, "ti,mcbsp", 0);
+               if (!dai_node) {
+                       dev_err(&pdev->dev, "McBSP node is not provided\n");
+                       return -EINVAL;
+               }
+               omap_twl4030_dai_links[0].cpu_dai_name  = NULL;
+               omap_twl4030_dai_links[0].cpu_of_node = dai_node;
+
+       } else if (pdata) {
+               if (pdata->card_name) {
+                       card->name = pdata->card_name;
+               } else {
+                       dev_err(&pdev->dev, "Card name is not provided\n");
+                       return -ENODEV;
+               }
+       } else {
+               dev_err(&pdev->dev, "Missing pdata\n");
+               return -ENODEV;
+       }
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+                       ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __devexit omap_twl4030_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+       snd_soc_unregister_card(card);
+
+       return 0;
+}
+
+static const struct of_device_id omap_twl4030_of_match[] = {
+       {.compatible = "ti,omap-twl4030", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, omap_twl4030_of_match);
+
+static struct platform_driver omap_twl4030_driver = {
+       .driver = {
+               .name = "omap-twl4030",
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+               .of_match_table = omap_twl4030_of_match,
+       },
+       .probe = omap_twl4030_probe,
+       .remove = __devexit_p(omap_twl4030_remove),
+};
+
+module_platform_driver(omap_twl4030_driver);
+
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_DESCRIPTION("ALSA SoC for TI SoC based boards with twl4030 codec");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:omap-twl4030");
diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c
deleted file mode 100644 (file)
index e263188..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * omap3beagle.c  --  SoC audio for OMAP3 Beagle
- *
- * Author: Steve Sakoman <steve@sakoman.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-
-#include "omap-mcbsp.h"
-#include "omap-pcm.h"
-
-static int omap3beagle_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       unsigned int fmt;
-       int ret;
-
-       switch (params_channels(params)) {
-       case 2: /* Stereo I2S mode */
-               fmt =   SND_SOC_DAIFMT_I2S |
-                       SND_SOC_DAIFMT_NB_NF |
-                       SND_SOC_DAIFMT_CBM_CFM;
-               break;
-       case 4: /* Four channel TDM mode */
-               fmt =   SND_SOC_DAIFMT_DSP_A |
-                       SND_SOC_DAIFMT_IB_NF |
-                       SND_SOC_DAIFMT_CBM_CFM;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* Set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, fmt);
-       if (ret < 0) {
-               printk(KERN_ERR "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) {
-               printk(KERN_ERR "can't set cpu DAI configuration\n");
-               return ret;
-       }
-
-       /* Set the codec system clock for DAC and ADC */
-       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
-                                    SND_SOC_CLOCK_IN);
-       if (ret < 0) {
-               printk(KERN_ERR "can't set codec system clock\n");
-               return ret;
-       }
-
-       return 0;
-}
-
-static struct snd_soc_ops omap3beagle_ops = {
-       .hw_params = omap3beagle_hw_params,
-};
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link omap3beagle_dai = {
-       .name = "TWL4030",
-       .stream_name = "TWL4030",
-       .cpu_dai_name = "omap-mcbsp.2",
-       .platform_name = "omap-pcm-audio",
-       .codec_dai_name = "twl4030-hifi",
-       .codec_name = "twl4030-codec",
-       .ops = &omap3beagle_ops,
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_omap3beagle = {
-       .name = "omap3beagle",
-       .owner = THIS_MODULE,
-       .dai_link = &omap3beagle_dai,
-       .num_links = 1,
-};
-
-static struct platform_device *omap3beagle_snd_device;
-
-static int __init omap3beagle_soc_init(void)
-{
-       int ret;
-
-       if (!(machine_is_omap3_beagle() || machine_is_devkit8000()))
-               return -ENODEV;
-       pr_info("OMAP3 Beagle/Devkit8000 SoC init\n");
-
-       omap3beagle_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!omap3beagle_snd_device) {
-               printk(KERN_ERR "Platform device allocation failed\n");
-               return -ENOMEM;
-       }
-
-       platform_set_drvdata(omap3beagle_snd_device, &snd_soc_omap3beagle);
-
-       ret = platform_device_add(omap3beagle_snd_device);
-       if (ret)
-               goto err1;
-
-       return 0;
-
-err1:
-       printk(KERN_ERR "Unable to add platform device\n");
-       platform_device_put(omap3beagle_snd_device);
-
-       return ret;
-}
-
-static void __exit omap3beagle_soc_exit(void)
-{
-       platform_device_unregister(omap3beagle_snd_device);
-}
-
-module_init(omap3beagle_soc_init);
-module_exit(omap3beagle_soc_exit);
-
-MODULE_AUTHOR("Steve Sakoman <steve@sakoman.com>");
-MODULE_DESCRIPTION("ALSA SoC OMAP3 Beagle");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c
deleted file mode 100644 (file)
index d632bfb..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * omap3evm.c  -- ALSA SoC support for OMAP3 EVM
- *
- * Author: Anuj Aggarwal <anuj.aggarwal@ti.com>
- *
- * Based on sound/soc/omap/beagle.c by Steve Sakoman
- *
- * Copyright (C) 2008 Texas Instruments, Incorporated
- *
- * 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.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
- * whether express or implied; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
-
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-
-#include "omap-mcbsp.h"
-#include "omap-pcm.h"
-
-static int omap3evm_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       int ret;
-
-       /* Set the codec system clock for DAC and ADC */
-       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
-                                    SND_SOC_CLOCK_IN);
-       if (ret < 0) {
-               printk(KERN_ERR "Can't set codec system clock\n");
-               return ret;
-       }
-
-       return 0;
-}
-
-static struct snd_soc_ops omap3evm_ops = {
-       .hw_params = omap3evm_hw_params,
-};
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link omap3evm_dai = {
-       .name           = "TWL4030",
-       .stream_name    = "TWL4030",
-       .cpu_dai_name = "omap-mcbsp.2",
-       .codec_dai_name = "twl4030-hifi",
-       .platform_name = "omap-pcm-audio",
-       .codec_name = "twl4030-codec",
-       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-                  SND_SOC_DAIFMT_CBM_CFM,
-       .ops            = &omap3evm_ops,
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_omap3evm = {
-       .name = "omap3evm",
-       .owner = THIS_MODULE,
-       .dai_link = &omap3evm_dai,
-       .num_links = 1,
-};
-
-static struct platform_device *omap3evm_snd_device;
-
-static int __init omap3evm_soc_init(void)
-{
-       int ret;
-
-       if (!machine_is_omap3evm())
-               return -ENODEV;
-       pr_info("OMAP3 EVM SoC init\n");
-
-       omap3evm_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!omap3evm_snd_device) {
-               printk(KERN_ERR "Platform device allocation failed\n");
-               return -ENOMEM;
-       }
-
-       platform_set_drvdata(omap3evm_snd_device, &snd_soc_omap3evm);
-       ret = platform_device_add(omap3evm_snd_device);
-       if (ret)
-               goto err1;
-
-       return 0;
-
-err1:
-       printk(KERN_ERR "Unable to add platform device\n");
-       platform_device_put(omap3evm_snd_device);
-
-       return ret;
-}
-
-static void __exit omap3evm_soc_exit(void)
-{
-       platform_device_unregister(omap3evm_snd_device);
-}
-
-module_init(omap3evm_soc_init);
-module_exit(omap3evm_soc_exit);
-
-MODULE_AUTHOR("Anuj Aggarwal <anuj.aggarwal@ti.com>");
-MODULE_DESCRIPTION("ALSA SoC OMAP3 EVM");
-MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c
deleted file mode 100644 (file)
index 502bce2..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * overo.c  --  SoC audio for Gumstix Overo
- *
- * Author: Steve Sakoman <steve@sakoman.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-#include <linux/platform_data/asoc-ti-mcbsp.h>
-
-#include "omap-mcbsp.h"
-#include "omap-pcm.h"
-
-static int overo_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       int ret;
-
-       /* Set the codec system clock for DAC and ADC */
-       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
-                                           SND_SOC_CLOCK_IN);
-       if (ret < 0) {
-               printk(KERN_ERR "can't set codec system clock\n");
-               return ret;
-       }
-
-       return 0;
-}
-
-static struct snd_soc_ops overo_ops = {
-       .hw_params = overo_hw_params,
-};
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link overo_dai = {
-       .name = "TWL4030",
-       .stream_name = "TWL4030",
-       .cpu_dai_name = "omap-mcbsp.2",
-       .codec_dai_name = "twl4030-hifi",
-       .platform_name = "omap-pcm-audio",
-       .codec_name = "twl4030-codec",
-       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-                  SND_SOC_DAIFMT_CBM_CFM,
-       .ops = &overo_ops,
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_card_overo = {
-       .name = "overo",
-       .owner = THIS_MODULE,
-       .dai_link = &overo_dai,
-       .num_links = 1,
-};
-
-static struct platform_device *overo_snd_device;
-
-static int __init overo_soc_init(void)
-{
-       int ret;
-
-       if (!(machine_is_overo() || machine_is_cm_t35())) {
-               pr_debug("Incomatible machine!\n");
-               return -ENODEV;
-       }
-       printk(KERN_INFO "overo SoC init\n");
-
-       overo_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!overo_snd_device) {
-               printk(KERN_ERR "Platform device allocation failed\n");
-               return -ENOMEM;
-       }
-
-       platform_set_drvdata(overo_snd_device, &snd_soc_card_overo);
-
-       ret = platform_device_add(overo_snd_device);
-       if (ret)
-               goto err1;
-
-       return 0;
-
-err1:
-       printk(KERN_ERR "Unable to add platform device\n");
-       platform_device_put(overo_snd_device);
-
-       return ret;
-}
-module_init(overo_soc_init);
-
-static void __exit overo_soc_exit(void)
-{
-       platform_device_unregister(overo_snd_device);
-}
-module_exit(overo_soc_exit);
-
-MODULE_AUTHOR("Steve Sakoman <steve@sakoman.com>");
-MODULE_DESCRIPTION("ALSA SoC overo");
-MODULE_LICENSE("GPL");
index 23de2b21d69678b4027332c6691bd63aeedbd95a..677b567935f8055b6899f74e276bd4c0a39dd213 100644 (file)
@@ -191,9 +191,6 @@ static int __init zoom2_soc_init(void)
        BUG_ON(gpio_request(ZOOM2_HEADSET_MUX_GPIO, "hs_mux") < 0);
        gpio_direction_output(ZOOM2_HEADSET_MUX_GPIO, 0);
 
-       BUG_ON(gpio_request(ZOOM2_HEADSET_EXTMUTE_GPIO, "ext_mute") < 0);
-       gpio_direction_output(ZOOM2_HEADSET_EXTMUTE_GPIO, 0);
-
        return 0;
 
 err1:
@@ -207,7 +204,6 @@ module_init(zoom2_soc_init);
 static void __exit zoom2_soc_exit(void)
 {
        gpio_free(ZOOM2_HEADSET_MUX_GPIO);
-       gpio_free(ZOOM2_HEADSET_EXTMUTE_GPIO);
 
        platform_device_unregister(zoom2_snd_device);
 }
index fe3995ce9b380f00674d0841e29269fdf422d1eb..e7b83179aca2b1469af4ec1e03f35e62df1227b2 100644 (file)
@@ -1,6 +1,6 @@
 config SND_SOC_SAMSUNG
        tristate "ASoC support for Samsung"
-       depends on ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5P64X0 || ARCH_EXYNOS4
+       depends on PLAT_SAMSUNG
        select S3C64XX_DMA if ARCH_S3C64XX
        select S3C2410_DMA if ARCH_S3C24XX
        help
@@ -191,6 +191,7 @@ config SND_SOC_SPEYSIDE
        select SND_SAMSUNG_I2S
        select SND_SOC_WM8996
        select SND_SOC_WM9081
+       select SND_SOC_WM0010
        select SND_SOC_WM1250_EV1
 
 config SND_SOC_TOBERMORY
@@ -199,6 +200,14 @@ config SND_SOC_TOBERMORY
        select SND_SAMSUNG_I2S
        select SND_SOC_WM8962
 
+config SND_SOC_BELLS
+       tristate "Audio support for Wolfson Bells"
+       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+       select SND_SAMSUNG_I2S
+       select SND_SOC_WM5102
+       select SND_SOC_WM5110
+       select SND_SOC_WM9081
+
 config SND_SOC_LOWLAND
        tristate "Audio support for Wolfson Lowland"
        depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
index 9d03beb40c86909e51671f531ef67e43fe73a0d8..709f6059ad67da928245a2faf3df900552e82d44 100644 (file)
@@ -42,6 +42,7 @@ snd-soc-speyside-objs := speyside.o
 snd-soc-tobermory-objs := tobermory.o
 snd-soc-lowland-objs := lowland.o
 snd-soc-littlemill-objs := littlemill.o
+snd-soc-bells-objs := bells.o
 
 obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
@@ -65,3 +66,4 @@ obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o
 obj-$(CONFIG_SND_SOC_TOBERMORY) += snd-soc-tobermory.o
 obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o
 obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o
+obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o
diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c
new file mode 100644 (file)
index 0000000..5dc10df
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * Bells audio support
+ *
+ * Copyright 2012 Wolfson Microelectronics
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+
+#include "../codecs/wm5102.h"
+#include "../codecs/wm9081.h"
+
+/*
+ * 44.1kHz based clocks for the SYSCLK domain, use a very high clock
+ * to allow all the DSP functionality to be enabled if desired.
+ */
+#define SYSCLK_RATE (44100 * 1024)
+
+/* 48kHz based clocks for the ASYNC domain */
+#define ASYNCCLK_RATE (48000 * 512)
+
+/* BCLK2 is fixed at this currently */
+#define BCLK2_RATE (64 * 8000)
+
+/*
+ * Expect a 24.576MHz crystal if one is fitted (the driver will function
+ * if this is not fitted).
+ */
+#define MCLK_RATE 24576000
+
+#define WM9081_AUDIO_RATE 44100
+#define WM9081_MCLK_RATE  (WM9081_AUDIO_RATE * 256)
+
+static int bells_set_bias_level(struct snd_soc_card *card,
+                               struct snd_soc_dapm_context *dapm,
+                               enum snd_soc_bias_level level)
+{
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int ret;
+
+       if (dapm->dev != codec_dai->dev)
+               return 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_PREPARE:
+               if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
+                       ret = snd_soc_codec_set_pll(codec, WM5102_FLL1,
+                                                   ARIZONA_FLL_SRC_MCLK1,
+                                                   MCLK_RATE,
+                                                   SYSCLK_RATE);
+                       if (ret < 0)
+                               pr_err("Failed to start FLL: %d\n", ret);
+
+                       ret = snd_soc_codec_set_pll(codec, WM5102_FLL2,
+                                                   ARIZONA_FLL_SRC_AIF2BCLK,
+                                                   BCLK2_RATE,
+                                                   ASYNCCLK_RATE);
+                       if (ret < 0)
+                               pr_err("Failed to start FLL: %d\n", ret);
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int bells_set_bias_level_post(struct snd_soc_card *card,
+                                    struct snd_soc_dapm_context *dapm,
+                                    enum snd_soc_bias_level level)
+{
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int ret;
+
+       if (dapm->dev != codec_dai->dev)
+               return 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_STANDBY:
+               ret = snd_soc_codec_set_pll(codec, WM5102_FLL1, 0, 0, 0);
+               if (ret < 0) {
+                       pr_err("Failed to stop FLL: %d\n", ret);
+                       return ret;
+               }
+
+               ret = snd_soc_codec_set_pll(codec, WM5102_FLL2, 0, 0, 0);
+               if (ret < 0) {
+                       pr_err("Failed to stop FLL: %d\n", ret);
+                       return ret;
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       dapm->bias_level = level;
+
+       return 0;
+}
+
+static int bells_late_probe(struct snd_soc_card *card)
+{
+       struct snd_soc_codec *codec = card->rtd[0].codec;
+       struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
+       struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai;
+       struct snd_soc_dai *aif3_dai = card->rtd[2].cpu_dai;
+       struct snd_soc_dai *wm9081_dai = card->rtd[2].codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0);
+       if (ret != 0) {
+               dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0);
+       if (ret != 0) {
+               dev_err(aif2_dai->dev, "Failed to set AIF2 clock: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0);
+       if (ret != 0) {
+               dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
+                                      ARIZONA_CLK_SRC_FLL1, SYSCLK_RATE,
+                                      SND_SOC_CLOCK_IN);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_OPCLK, 0,
+                                      WM9081_MCLK_RATE, SND_SOC_CLOCK_OUT);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set OPCLK: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK,
+                                      ARIZONA_CLK_SRC_FLL2, ASYNCCLK_RATE,
+                                      SND_SOC_CLOCK_IN);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_codec_set_sysclk(wm9081_dai->codec, WM9081_SYSCLK_MCLK,
+                                      0, WM9081_MCLK_RATE, 0);
+       if (ret != 0) {
+               dev_err(wm9081_dai->dev, "Failed to set MCLK: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_pcm_stream baseband_params = {
+       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+       .rate_min = 8000,
+       .rate_max = 8000,
+       .channels_min = 2,
+       .channels_max = 2,
+};
+
+static const struct snd_soc_pcm_stream sub_params = {
+       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+       .rate_min = WM9081_AUDIO_RATE,
+       .rate_max = WM9081_AUDIO_RATE,
+       .channels_min = 2,
+       .channels_max = 2,
+};
+
+static struct snd_soc_dai_link bells_dai_wm5102[] = {
+       {
+               .name = "CPU",
+               .stream_name = "CPU",
+               .cpu_dai_name = "samsung-i2s.0",
+               .codec_dai_name = "wm5102-aif1",
+               .platform_name = "samsung-audio",
+               .codec_name = "wm5102-codec",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBM_CFM,
+       },
+       {
+               .name = "Baseband",
+               .stream_name = "Baseband",
+               .cpu_dai_name = "wm5102-aif2",
+               .codec_dai_name = "wm1250-ev1",
+               .codec_name = "wm1250-ev1.1-0027",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBM_CFM,
+               .ignore_suspend = 1,
+               .params = &baseband_params,
+       },
+       {
+               .name = "Sub",
+               .stream_name = "Sub",
+               .cpu_dai_name = "wm5102-aif3",
+               .codec_dai_name = "wm9081-hifi",
+               .codec_name = "wm9081.1-006c",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBS_CFS,
+               .ignore_suspend = 1,
+               .params = &sub_params,
+       },
+};
+
+static struct snd_soc_dai_link bells_dai_wm5110[] = {
+       {
+               .name = "CPU",
+               .stream_name = "CPU",
+               .cpu_dai_name = "samsung-i2s.0",
+               .codec_dai_name = "wm5110-aif1",
+               .platform_name = "samsung-audio",
+               .codec_name = "wm5110-codec",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBM_CFM,
+       },
+       {
+               .name = "Baseband",
+               .stream_name = "Baseband",
+               .cpu_dai_name = "wm5110-aif2",
+               .codec_dai_name = "wm1250-ev1",
+               .codec_name = "wm1250-ev1.1-0027",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBM_CFM,
+               .ignore_suspend = 1,
+               .params = &baseband_params,
+       },
+       {
+               .name = "Sub",
+               .stream_name = "Sub",
+               .cpu_dai_name = "wm5102-aif3",
+               .codec_dai_name = "wm9081-hifi",
+               .codec_name = "wm9081.1-006c",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBS_CFS,
+               .ignore_suspend = 1,
+               .params = &sub_params,
+       },
+};
+
+static struct snd_soc_codec_conf bells_codec_conf[] = {
+       {
+               .dev_name = "wm9081.1-006c",
+               .name_prefix = "Sub",
+       },
+};
+
+static struct snd_soc_dapm_route bells_routes[] = {
+       { "Sub CLK_SYS", NULL, "OPCLK" },
+};
+
+static struct snd_soc_card bells_cards[] = {
+       {
+               .name = "Bells WM5102",
+               .owner = THIS_MODULE,
+               .dai_link = bells_dai_wm5102,
+               .num_links = ARRAY_SIZE(bells_dai_wm5102),
+               .codec_conf = bells_codec_conf,
+               .num_configs = ARRAY_SIZE(bells_codec_conf),
+
+               .late_probe = bells_late_probe,
+
+               .dapm_routes = bells_routes,
+               .num_dapm_routes = ARRAY_SIZE(bells_routes),
+
+               .set_bias_level = bells_set_bias_level,
+               .set_bias_level_post = bells_set_bias_level_post,
+       },
+       {
+               .name = "Bells WM5110",
+               .owner = THIS_MODULE,
+               .dai_link = bells_dai_wm5110,
+               .num_links = ARRAY_SIZE(bells_dai_wm5110),
+               .codec_conf = bells_codec_conf,
+               .num_configs = ARRAY_SIZE(bells_codec_conf),
+
+               .late_probe = bells_late_probe,
+
+               .dapm_routes = bells_routes,
+               .num_dapm_routes = ARRAY_SIZE(bells_routes),
+
+               .set_bias_level = bells_set_bias_level,
+               .set_bias_level_post = bells_set_bias_level_post,
+       },
+};
+
+
+static __devinit int bells_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       bells_cards[pdev->id].dev = &pdev->dev;
+
+       ret = snd_soc_register_card(&bells_cards[pdev->id]);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "snd_soc_register_card(%s) failed: %d\n",
+                       bells_cards[pdev->id].name, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __devexit bells_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_card(&bells_cards[pdev->id]);
+
+       return 0;
+}
+
+static struct platform_driver bells_driver = {
+       .driver = {
+               .name = "bells",
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+       },
+       .probe = bells_probe,
+       .remove = __devexit_p(bells_remove),
+};
+
+module_platform_driver(bells_driver);
+
+MODULE_DESCRIPTION("Bells audio support");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:bells");
index a4a9fc7e8c762c610f8f1f616fc516894e8506da..c7e1c28528a4a6861593539a30afa1e41de30dd6 100644 (file)
@@ -25,7 +25,7 @@ static int speyside_set_bias_level(struct snd_soc_card *card,
                                   struct snd_soc_dapm_context *dapm,
                                   enum snd_soc_bias_level level)
 {
-       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct snd_soc_dai *codec_dai = card->rtd[1].codec_dai;
        int ret;
 
        if (dapm->dev != codec_dai->dev)
@@ -57,7 +57,7 @@ static int speyside_set_bias_level_post(struct snd_soc_card *card,
                                        struct snd_soc_dapm_context *dapm,
                                        enum snd_soc_bias_level level)
 {
-       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct snd_soc_dai *codec_dai = card->rtd[1].codec_dai;
        int ret;
 
        if (dapm->dev != codec_dai->dev)
@@ -126,6 +126,18 @@ static void speyside_set_polarity(struct snd_soc_codec *codec,
        snd_soc_dapm_sync(&codec->dapm);
 }
 
+static int speyside_wm0010_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *dai = rtd->codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(dai, 0, MCLK_AUDIO_RATE, 0);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
 static int speyside_wm8996_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_dai *dai = rtd->codec_dai;
@@ -172,17 +184,37 @@ static int speyside_late_probe(struct snd_soc_card *card)
        return 0;
 }
 
+static const struct snd_soc_pcm_stream dsp_codec_params = {
+       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+       .rate_min = 48000,
+       .rate_max = 48000,
+       .channels_min = 2,
+       .channels_max = 2,
+};
+
 static struct snd_soc_dai_link speyside_dai[] = {
        {
-               .name = "CPU",
-               .stream_name = "CPU",
+               .name = "CPU-DSP",
+               .stream_name = "CPU-DSP",
                .cpu_dai_name = "samsung-i2s.0",
-               .codec_dai_name = "wm8996-aif1",
+               .codec_dai_name = "wm0010-sdi1",
                .platform_name = "samsung-audio",
+               .codec_name = "spi0.0",
+               .init = speyside_wm0010_init,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBM_CFM,
+       },
+       {
+               .name = "DSP-CODEC",
+               .stream_name = "DSP-CODEC",
+               .cpu_dai_name = "wm0010-sdi2",
+               .codec_dai_name = "wm8996-aif1",
                .codec_name = "wm8996.1-001a",
                .init = speyside_wm8996_init,
                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
                                | SND_SOC_DAIFMT_CBM_CFM,
+               .params = &dsp_codec_params,
+               .ignore_suspend = 1,
        },
        {
                .name = "Baseband",
index 0540408a9fa9ab706c28e7ef6ed60a329bec027c..5328ae5539f16e67571566f313a5d9689f79cac5 100644 (file)
@@ -1655,22 +1655,20 @@ static int fsi_probe(struct platform_device *pdev)
        irq = platform_get_irq(pdev, 0);
        if (!res || (int)irq <= 0) {
                dev_err(&pdev->dev, "Not enough FSI platform resources.\n");
-               ret = -ENODEV;
-               goto exit;
+               return -ENODEV;
        }
 
-       master = kzalloc(sizeof(*master), GFP_KERNEL);
+       master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
        if (!master) {
                dev_err(&pdev->dev, "Could not allocate master\n");
-               ret = -ENOMEM;
-               goto exit;
+               return -ENOMEM;
        }
 
-       master->base = ioremap_nocache(res->start, resource_size(res));
+       master->base = devm_ioremap_nocache(&pdev->dev,
+                                           res->start, resource_size(res));
        if (!master->base) {
-               ret = -ENXIO;
                dev_err(&pdev->dev, "Unable to ioremap FSI registers.\n");
-               goto exit_kfree;
+               return -ENXIO;
        }
 
        /* master setting */
@@ -1686,7 +1684,7 @@ static int fsi_probe(struct platform_device *pdev)
        ret = fsi_stream_probe(&master->fsia, &pdev->dev);
        if (ret < 0) {
                dev_err(&pdev->dev, "FSIA stream probe failed\n");
-               goto exit_iounmap;
+               return ret;
        }
 
        /* FSI B setting */
@@ -1730,16 +1728,11 @@ exit_snd_soc:
 exit_free_irq:
        free_irq(irq, master);
 exit_fsib:
+       pm_runtime_disable(&pdev->dev);
        fsi_stream_remove(&master->fsib);
 exit_fsia:
        fsi_stream_remove(&master->fsia);
-exit_iounmap:
-       iounmap(master->base);
-       pm_runtime_disable(&pdev->dev);
-exit_kfree:
-       kfree(master);
-       master = NULL;
-exit:
+
        return ret;
 }
 
@@ -1758,9 +1751,6 @@ static int fsi_remove(struct platform_device *pdev)
        fsi_stream_remove(&master->fsia);
        fsi_stream_remove(&master->fsib);
 
-       iounmap(master->base);
-       kfree(master);
-
        return 0;
 }
 
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
new file mode 100644 (file)
index 0000000..967d0e1
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * soc-compress.c  --  ALSA SoC Compress
+ *
+ * Copyright (C) 2012 Intel Corp.
+ *
+ * Authors: Namarta Kohli <namartax.kohli@intel.com>
+ *          Ramesh Babu K V <ramesh.babu@linux.intel.com>
+ *          Vinod Koul <vinod.koul@linux.intel.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include <sound/compress_params.h>
+#include <sound/compress_driver.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+static int soc_compr_open(struct snd_compr_stream *cstream)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret = 0;
+
+       if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
+               ret = platform->driver->compr_ops->open(cstream);
+               if (ret < 0) {
+                       pr_err("compress asoc: can't open platform %s\n", platform->name);
+                       goto out;
+               }
+       }
+
+       if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->startup) {
+               ret = rtd->dai_link->compr_ops->startup(cstream);
+               if (ret < 0) {
+                       pr_err("compress asoc: %s startup failed\n", rtd->dai_link->name);
+                       goto machine_err;
+               }
+       }
+
+       if (cstream->direction == SND_COMPRESS_PLAYBACK) {
+               cpu_dai->playback_active++;
+               codec_dai->playback_active++;
+       } else {
+               cpu_dai->capture_active++;
+               codec_dai->capture_active++;
+       }
+
+       cpu_dai->active++;
+       codec_dai->active++;
+       rtd->codec->active++;
+
+       return 0;
+
+machine_err:
+       if (platform->driver->compr_ops && platform->driver->compr_ops->free)
+               platform->driver->compr_ops->free(cstream);
+out:
+       return ret;
+}
+
+static int soc_compr_free(struct snd_compr_stream *cstream)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = rtd->codec;
+
+       if (cstream->direction == SND_COMPRESS_PLAYBACK) {
+               cpu_dai->playback_active--;
+               codec_dai->playback_active--;
+       } else {
+               cpu_dai->capture_active--;
+               codec_dai->capture_active--;
+       }
+
+       snd_soc_dai_digital_mute(codec_dai, 1);
+
+       cpu_dai->active--;
+       codec_dai->active--;
+       codec->active--;
+
+       if (!cpu_dai->active)
+               cpu_dai->rate = 0;
+
+       if (!codec_dai->active)
+               codec_dai->rate = 0;
+
+
+       if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown)
+               rtd->dai_link->compr_ops->shutdown(cstream);
+
+       if (platform->driver->compr_ops && platform->driver->compr_ops->free)
+               platform->driver->compr_ops->free(cstream);
+       cpu_dai->runtime = NULL;
+
+       if (cstream->direction == SND_COMPRESS_PLAYBACK) {
+               if (!rtd->pmdown_time || codec->ignore_pmdown_time ||
+                   rtd->dai_link->ignore_pmdown_time) {
+                       snd_soc_dapm_stream_event(rtd,
+                                       SNDRV_PCM_STREAM_PLAYBACK,
+                                       SND_SOC_DAPM_STREAM_STOP);
+               } else
+                       codec_dai->pop_wait = 1;
+                       schedule_delayed_work(&rtd->delayed_work,
+                               msecs_to_jiffies(rtd->pmdown_time));
+       } else {
+               /* capture streams can be powered down now */
+               snd_soc_dapm_stream_event(rtd,
+                       SNDRV_PCM_STREAM_CAPTURE,
+                       SND_SOC_DAPM_STREAM_STOP);
+       }
+
+       return 0;
+}
+
+static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
+{
+
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret = 0;
+
+       if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
+               ret = platform->driver->compr_ops->trigger(cstream, cmd);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (cmd == SNDRV_PCM_TRIGGER_START)
+               snd_soc_dai_digital_mute(codec_dai, 0);
+       else if (cmd == SNDRV_PCM_TRIGGER_STOP)
+               snd_soc_dai_digital_mute(codec_dai, 1);
+
+       return ret;
+}
+
+static int soc_compr_set_params(struct snd_compr_stream *cstream,
+                                       struct snd_compr_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+       int ret = 0;
+
+       /* first we call set_params for the platform driver
+        * this should configure the soc side
+        * if the machine has compressed ops then we call that as well
+        * expectation is that platform and machine will configure everything
+        * for this compress path, like configuring pcm port for codec
+        */
+       if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
+               ret = platform->driver->compr_ops->set_params(cstream, params);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) {
+               ret = rtd->dai_link->compr_ops->set_params(cstream);
+               if (ret < 0)
+                       return ret;
+       }
+
+       snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
+                               SND_SOC_DAPM_STREAM_START);
+
+       return ret;
+}
+
+static int soc_compr_get_params(struct snd_compr_stream *cstream,
+                                       struct snd_codec *params)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+       int ret = 0;
+
+       if (platform->driver->compr_ops && platform->driver->compr_ops->get_params)
+               ret = platform->driver->compr_ops->get_params(cstream, params);
+
+       return ret;
+}
+
+static int soc_compr_get_caps(struct snd_compr_stream *cstream,
+                               struct snd_compr_caps *caps)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+       int ret = 0;
+
+       if (platform->driver->compr_ops && platform->driver->compr_ops->get_caps)
+               ret = platform->driver->compr_ops->get_caps(cstream, caps);
+
+       return ret;
+}
+
+static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream,
+                               struct snd_compr_codec_caps *codec)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+       int ret = 0;
+
+       if (platform->driver->compr_ops && platform->driver->compr_ops->get_codec_caps)
+               ret = platform->driver->compr_ops->get_codec_caps(cstream, codec);
+
+       return ret;
+}
+
+static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+       int ret = 0;
+
+       if (platform->driver->compr_ops && platform->driver->compr_ops->ack)
+               ret = platform->driver->compr_ops->ack(cstream, bytes);
+
+       return ret;
+}
+
+static int soc_compr_pointer(struct snd_compr_stream *cstream,
+                       struct snd_compr_tstamp *tstamp)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+
+       if (platform->driver->compr_ops && platform->driver->compr_ops->pointer)
+                platform->driver->compr_ops->pointer(cstream, tstamp);
+
+       return 0;
+}
+
+/* ASoC Compress operations */
+static struct snd_compr_ops soc_compr_ops = {
+       .open           = soc_compr_open,
+       .free           = soc_compr_free,
+       .set_params     = soc_compr_set_params,
+       .get_params     = soc_compr_get_params,
+       .trigger        = soc_compr_trigger,
+       .pointer        = soc_compr_pointer,
+       .ack            = soc_compr_ack,
+       .get_caps       = soc_compr_get_caps,
+       .get_codec_caps = soc_compr_get_codec_caps
+};
+
+/* create a new compress */
+int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct snd_compr *compr;
+       char new_name[64];
+       int ret = 0, direction = 0;
+
+       /* check client and interface hw capabilities */
+       snprintf(new_name, sizeof(new_name), "%s %s-%d",
+                       rtd->dai_link->stream_name, codec_dai->name, num);
+       direction = SND_COMPRESS_PLAYBACK;
+       compr = kzalloc(sizeof(*compr), GFP_KERNEL);
+       if (compr == NULL) {
+               snd_printk(KERN_ERR "Cannot allocate compr\n");
+               return -ENOMEM;
+       }
+
+       compr->ops = &soc_compr_ops;
+       mutex_init(&compr->lock);
+       ret = snd_compress_new(rtd->card->snd_card, num, direction, compr);
+       if (ret < 0) {
+               pr_err("compress asoc: can't create compress for codec %s\n",
+                       codec->name);
+               kfree(compr);
+               return ret;
+       }
+
+       rtd->compr = compr;
+       compr->private_data = rtd;
+
+       printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name,
+               cpu_dai->name);
+       return ret;
+}
index cf3d0b0c71b9ac4bd249d4b3a5d3cabb2641dece..d1198627fc40397b772adad1104579c35842507f 100644 (file)
@@ -609,6 +609,10 @@ int snd_soc_suspend(struct device *dev)
                                          SND_SOC_DAPM_STREAM_SUSPEND);
        }
 
+       /* Recheck all analogue paths too */
+       dapm_mark_io_dirty(&card->dapm);
+       snd_soc_dapm_sync(&card->dapm);
+
        /* suspend all CODECs */
        list_for_each_entry(codec, &card->codec_dev_list, card_list) {
                /* If there are paths active then the CODEC will be held with
@@ -631,6 +635,8 @@ int snd_soc_suspend(struct device *dev)
                                codec->driver->suspend(codec);
                                codec->suspended = 1;
                                codec->cache_sync = 1;
+                               if (codec->using_regmap)
+                                       regcache_mark_dirty(codec->control_data);
                                break;
                        default:
                                dev_dbg(codec->dev, "CODEC is on over suspend\n");
@@ -756,6 +762,10 @@ static void soc_resume_deferred(struct work_struct *work)
 
        /* userspace can access us now we are back as we were before */
        snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0);
+
+       /* Recheck all analogue paths too */
+       dapm_mark_io_dirty(&card->dapm);
+       snd_soc_dapm_sync(&card->dapm);
 }
 
 /* powers up audio subsystem after a suspend */
@@ -1388,37 +1398,48 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
        if (ret < 0)
                pr_warn("asoc: failed to add pmdown_time sysfs:%d\n", ret);
 
-       if (!dai_link->params) {
-               /* create the pcm */
-               ret = soc_new_pcm(rtd, num);
+       if (cpu_dai->driver->compress_dai) {
+               /*create compress_device"*/
+               ret = soc_new_compress(rtd, num);
                if (ret < 0) {
-                       pr_err("asoc: can't create pcm %s :%d\n",
-                              dai_link->stream_name, ret);
+                       pr_err("asoc: can't create compress %s\n",
+                                        dai_link->stream_name);
                        return ret;
                }
        } else {
-               /* link the DAI widgets */
-               play_w = codec_dai->playback_widget;
-               capture_w = cpu_dai->capture_widget;
-               if (play_w && capture_w) {
-                       ret = snd_soc_dapm_new_pcm(card, dai_link->params,
-                                                  capture_w, play_w);
-                       if (ret != 0) {
-                               dev_err(card->dev, "Can't link %s to %s: %d\n",
-                                       play_w->name, capture_w->name, ret);
+
+               if (!dai_link->params) {
+                       /* create the pcm */
+                       ret = soc_new_pcm(rtd, num);
+                       if (ret < 0) {
+                               pr_err("asoc: can't create pcm %s :%d\n",
+                                      dai_link->stream_name, ret);
                                return ret;
                        }
-               }
+               } else {
+                       /* link the DAI widgets */
+                       play_w = codec_dai->playback_widget;
+                       capture_w = cpu_dai->capture_widget;
+                       if (play_w && capture_w) {
+                               ret = snd_soc_dapm_new_pcm(card, dai_link->params,
+                                                  capture_w, play_w);
+                               if (ret != 0) {
+                                       dev_err(card->dev, "Can't link %s to %s: %d\n",
+                                               play_w->name, capture_w->name, ret);
+                                       return ret;
+                               }
+                       }
 
-               play_w = cpu_dai->playback_widget;
-               capture_w = codec_dai->capture_widget;
-               if (play_w && capture_w) {
-                       ret = snd_soc_dapm_new_pcm(card, dai_link->params,
+                       play_w = cpu_dai->playback_widget;
+                       capture_w = codec_dai->capture_widget;
+                       if (play_w && capture_w) {
+                               ret = snd_soc_dapm_new_pcm(card, dai_link->params,
                                                   capture_w, play_w);
-                       if (ret != 0) {
-                               dev_err(card->dev, "Can't link %s to %s: %d\n",
-                                       play_w->name, capture_w->name, ret);
-                               return ret;
+                               if (ret != 0) {
+                                       dev_err(card->dev, "Can't link %s to %s: %d\n",
+                                               play_w->name, capture_w->name, ret);
+                                       return ret;
+                               }
                        }
                }
        }
@@ -1816,7 +1837,6 @@ base_error:
 static int soc_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card = platform_get_drvdata(pdev);
-       int ret = 0;
 
        /*
         * no card, so machine driver should be registering card
@@ -1832,13 +1852,7 @@ static int soc_probe(struct platform_device *pdev)
        /* Bodge while we unpick instantiation */
        card->dev = &pdev->dev;
 
-       ret = snd_soc_register_card(card);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "Failed to register card\n");
-               return ret;
-       }
-
-       return 0;
+       return snd_soc_register_card(card);
 }
 
 static int soc_cleanup_card_resources(struct snd_soc_card *card)
@@ -2399,16 +2413,14 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-       unsigned int val, bitmask;
+       unsigned int val;
 
-       for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
-               ;
        val = snd_soc_read(codec, e->reg);
        ucontrol->value.enumerated.item[0]
-               = (val >> e->shift_l) & (bitmask - 1);
+               = (val >> e->shift_l) & e->mask;
        if (e->shift_l != e->shift_r)
                ucontrol->value.enumerated.item[1] =
-                       (val >> e->shift_r) & (bitmask - 1);
+                       (val >> e->shift_r) & e->mask;
 
        return 0;
 }
@@ -2429,19 +2441,17 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val;
-       unsigned int mask, bitmask;
+       unsigned int mask;
 
-       for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
-               ;
        if (ucontrol->value.enumerated.item[0] > e->max - 1)
                return -EINVAL;
        val = ucontrol->value.enumerated.item[0] << e->shift_l;
-       mask = (bitmask - 1) << e->shift_l;
+       mask = e->mask << e->shift_l;
        if (e->shift_l != e->shift_r) {
                if (ucontrol->value.enumerated.item[1] > e->max - 1)
                        return -EINVAL;
                val |= ucontrol->value.enumerated.item[1] << e->shift_r;
-               mask |= (bitmask - 1) << e->shift_r;
+               mask |= e->mask << e->shift_r;
        }
 
        return snd_soc_update_bits_locked(codec, e->reg, mask, val);
@@ -3717,6 +3727,9 @@ int snd_soc_register_dai(struct device *dev,
                }
        }
 
+       if (!dai->codec)
+               dai->dapm.idle_bias_off = 1;
+
        list_add(&dai->list, &dai_list);
 
        mutex_unlock(&client_mutex);
@@ -3805,6 +3818,9 @@ int snd_soc_register_dais(struct device *dev,
                        }
                }
 
+               if (!dai->codec)
+                       dai->dapm.idle_bias_off = 1;
+
                list_add(&dai->list, &dai_list);
 
                mutex_unlock(&client_mutex);
@@ -4034,8 +4050,6 @@ int snd_soc_register_codec(struct device *dev,
        return 0;
 
 fail:
-       kfree(codec->reg_def_copy);
-       codec->reg_def_copy = NULL;
        kfree(codec->name);
        kfree(codec);
        return ret;
index f90139b5f50d74089dc98fd0d19de42cb3732a84..d0a4be38dc0f0473bdafe38d6b18ca30b11de61b 100644 (file)
@@ -141,6 +141,28 @@ void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
 }
 EXPORT_SYMBOL_GPL(dapm_mark_dirty);
 
+void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm)
+{
+       struct snd_soc_card *card = dapm->card;
+       struct snd_soc_dapm_widget *w;
+
+       mutex_lock(&card->dapm_mutex);
+
+       list_for_each_entry(w, &card->widgets, list) {
+               switch (w->id) {
+               case snd_soc_dapm_input:
+               case snd_soc_dapm_output:
+                       dapm_mark_dirty(w, "Rechecking inputs and outputs");
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       mutex_unlock(&card->dapm_mutex);
+}
+EXPORT_SYMBOL_GPL(dapm_mark_io_dirty);
+
 /* create a new dapm widget */
 static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
        const struct snd_soc_dapm_widget *_widget)
@@ -336,12 +358,10 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
        case snd_soc_dapm_mux: {
                struct soc_enum *e = (struct soc_enum *)
                        w->kcontrol_news[i].private_value;
-               int val, item, bitmask;
+               int val, item;
 
-               for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
-                       ;
                val = soc_widget_read(w, e->reg);
-               item = (val >> e->shift_l) & (bitmask - 1);
+               item = (val >> e->shift_l) & e->mask;
 
                p->connect = 0;
                for (i = 0; i < e->max; i++) {
@@ -997,10 +1017,29 @@ EXPORT_SYMBOL_GPL(dapm_reg_event);
 int dapm_regulator_event(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol, int event)
 {
-       if (SND_SOC_DAPM_EVENT_ON(event))
+       int ret;
+
+       if (SND_SOC_DAPM_EVENT_ON(event)) {
+               if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
+                       ret = regulator_allow_bypass(w->regulator, true);
+                       if (ret != 0)
+                               dev_warn(w->dapm->dev,
+                                        "Failed to bypass %s: %d\n",
+                                        w->name, ret);
+               }
+
                return regulator_enable(w->regulator);
-       else
+       } else {
+               if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
+                       ret = regulator_allow_bypass(w->regulator, false);
+                       if (ret != 0)
+                               dev_warn(w->dapm->dev,
+                                        "Failed to unbypass %s: %d\n",
+                                        w->name, ret);
+               }
+
                return regulator_disable_deferred(w->regulator, w->shift);
+       }
 }
 EXPORT_SYMBOL_GPL(dapm_regulator_event);
 
@@ -2658,15 +2697,13 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
        struct snd_soc_dapm_widget *widget = wlist->widgets[0];
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-       unsigned int val, bitmask;
+       unsigned int val;
 
-       for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
-               ;
        val = snd_soc_read(widget->codec, e->reg);
-       ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
+       ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask;
        if (e->shift_l != e->shift_r)
                ucontrol->value.enumerated.item[1] =
-                       (val >> e->shift_r) & (bitmask - 1);
+                       (val >> e->shift_r) & e->mask;
 
        return 0;
 }
@@ -2690,22 +2727,20 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_soc_card *card = codec->card;
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val, mux, change;
-       unsigned int mask, bitmask;
+       unsigned int mask;
        struct snd_soc_dapm_update update;
        int wi;
 
-       for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
-               ;
        if (ucontrol->value.enumerated.item[0] > e->max - 1)
                return -EINVAL;
        mux = ucontrol->value.enumerated.item[0];
        val = mux << e->shift_l;
-       mask = (bitmask - 1) << e->shift_l;
+       mask = e->mask << e->shift_l;
        if (e->shift_l != e->shift_r) {
                if (ucontrol->value.enumerated.item[1] > e->max - 1)
                        return -EINVAL;
                val |= ucontrol->value.enumerated.item[1] << e->shift_r;
-               mask |= (bitmask - 1) << e->shift_r;
+               mask |= e->mask << e->shift_r;
        }
 
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
index 5df529eda251abdda685de949747050cc3e066a0..bbc125748a3843decc6ffd04d171fcf6f6b9fc5c 100644 (file)
@@ -140,14 +140,18 @@ static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream)
        struct dma_chan *chan = prtd->dma_chan;
        struct dma_async_tx_descriptor *desc;
        enum dma_transfer_direction direction;
+       unsigned long flags = DMA_CTRL_ACK;
 
        direction = snd_pcm_substream_to_dma_direction(substream);
 
+       if (!substream->runtime->no_period_wakeup)
+               flags |= DMA_PREP_INTERRUPT;
+
        prtd->pos = 0;
        desc = dmaengine_prep_dma_cyclic(chan,
                substream->runtime->dma_addr,
                snd_pcm_lib_buffer_bytes(substream),
-               snd_pcm_lib_period_bytes(substream), direction);
+               snd_pcm_lib_period_bytes(substream), direction, flags);
 
        if (!desc)
                return -ENOMEM;
index 0c172938b82a09a1d38f790cf07d4e2b48515b2f..fa0fd8ddae90fc17f280543c9399741c9a33038b 100644 (file)
@@ -83,11 +83,6 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
        jack->status &= ~mask;
        jack->status |= status & mask;
 
-       /* The DAPM sync is expensive enough to be worth skipping.
-        * However, empty mask means pin synchronization is desired. */
-       if (mask && (jack->status == oldstatus))
-               goto out;
-
        trace_snd_soc_jack_notify(jack, status);
 
        list_for_each_entry(pin, &jack->pins, list) {
@@ -109,7 +104,6 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
 
        snd_jack_report(jack->jack, jack->status);
 
-out:
        mutex_unlock(&jack->mutex);
 }
 EXPORT_SYMBOL_GPL(snd_soc_jack_report);
index d4f14e492341f3751446057b68ee8d61f0c9bfbd..cee13b7bfb949ffacd8e8cdabccea8030ba8659a 100644 (file)
 #include <linux/gpio.h>
 #include <linux/of_gpio.h>
 
-#include <mach/tegra_wm8903_pdata.h>
-
 #include <sound/core.h>
 #include <sound/jack.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/tegra_wm8903.h>
 
 #include "../codecs/wm8903.h"
 
index 45e43b4057b0661b71afe8767806cf72fdf183f5..be94bf9bf94f51b31b4ba5d1aaeeeabcc58ea043 100644 (file)
@@ -760,6 +760,9 @@ static int __devinit ux500_msp_drv_probe(struct platform_device *pdev)
        drvdata = devm_kzalloc(&pdev->dev,
                                sizeof(struct ux500_msp_i2s_drvdata),
                                GFP_KERNEL);
+       if (!drvdata)
+               return -ENOMEM;
+
        drvdata->fmt = 0;
        drvdata->slots = 1;
        drvdata->tx_mask = 0x01;
index e5c79ca425183e47cdf1a255cd1c2ef237dced18..b7c996e77570bd527a0a92fd904276a40c44cd2b 100644 (file)
@@ -689,6 +689,8 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
 
        *msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL);
        msp = *msp_p;
+       if (!msp)
+               return -ENOMEM;
 
        if (np) {
                if (!platform_data) {
index b63b3a86d3f40f45eeef765a960b705268dd8d77..5701787c0e6bce406603ebb8590668d853900fd6 100644 (file)
@@ -813,7 +813,7 @@ static int snd_amd7930_get_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem
        default:
                swval = &amd->pgain;
                break;
-       };
+       }
 
        ucontrol->value.integer.value[0] = *swval;
 
@@ -838,7 +838,7 @@ static int snd_amd7930_put_volume(struct snd_kcontrol *kctl, struct snd_ctl_elem
        default:
                swval = &amd->pgain;
                break;
-       };
+       }
 
        spin_lock_irqsave(&amd->lock, flags);
 
index a6b0deb77746c11646e42dd9f5f6353311e94656..ae35f5342e105dc3700e5589da6d23a4f4a6ab63 100644 (file)
@@ -592,7 +592,7 @@ static __u32 reverse_bytes(__u32 b, int len)
                break;
        default:
                printk(KERN_ERR "DBRI reverse_bytes: unsupported length\n");
-       };
+       }
 
        return b;
 }
index 56ad923bf6b5cb74db2f5a56cdc2a16807c66a03..a1d9b0792a1e5b1b68816ad794a77fb76bae2398 100644 (file)
@@ -346,11 +346,10 @@ static int usb6fire_fw_check(u8 *version)
                if (!memcmp(version, known_fw_versions + i, 4))
                        return 0;
 
-       snd_printk(KERN_ERR PREFIX "invalid fimware version in device: "
-                       "%02x %02x %02x %02x. "
+       snd_printk(KERN_ERR PREFIX "invalid fimware version in device: %*ph. "
                        "please reconnect to power. if this failure "
                        "still happens, check your firmware installation.",
-                       version[0], version[1], version[2], version[3]);
+                       4, version);
        return -EINVAL;
 }
 
index 4a469f0cb6d4750b03fab852d13515022fe0b4af..561bb74fd364ae388cb8dc2af548e014b0bb801b 100644 (file)
@@ -646,6 +646,8 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
                        list_for_each(p, &chip->pcm_list) {
                                as = list_entry(p, struct snd_usb_stream, list);
                                snd_pcm_suspend_all(as->pcm);
+                               as->substream[0].need_setup_ep =
+                                       as->substream[1].need_setup_ep = true;
                        }
                }
        } else {
index 2b9fffff23b62a5449d39f2a4b03cbaadb1529a6..afa4f9e9b27a2673b1fc955d680859cb7f964f02 100644 (file)
@@ -92,6 +92,8 @@ struct snd_usb_endpoint {
        unsigned char silence_value;
        unsigned int stride;
        int iface, alt_idx;
+       int skip_packets;               /* quirks for devices to ignore the first n packets
+                                          in a stream */
 
        spinlock_t lock;
        struct list_head list;
@@ -105,6 +107,8 @@ struct snd_usb_substream {
        int interface;  /* current interface */
        int endpoint;   /* assigned endpoint */
        struct audioformat *cur_audiofmt;       /* current audioformat pointer (for hw_params callback) */
+       snd_pcm_format_t pcm_format;    /* current audio format (for hw_params callback) */
+       unsigned int channels;          /* current number of channels (for hw_params callback) */
        unsigned int cur_rate;          /* current rate (for hw_params callback) */
        unsigned int period_bytes;      /* current period bytes (for hw_params callback) */
        unsigned int altset_idx;     /* USB data format: index of alternate setting */
@@ -115,14 +119,13 @@ struct snd_usb_substream {
 
        unsigned int hwptr_done;        /* processed byte position in the buffer */
        unsigned int transfer_done;             /* processed frames since last period update */
-       unsigned long active_mask;      /* bitmask of active urbs */
-       unsigned long unlink_mask;      /* bitmask of unlinked urbs */
 
        /* data and sync endpoints for this stream */
        unsigned int ep_num;            /* the endpoint number */
        struct snd_usb_endpoint *data_endpoint;
        struct snd_usb_endpoint *sync_endpoint;
        unsigned long flags;
+       bool need_setup_ep;             /* (re)configure EP at prepare? */
 
        u64 formats;                    /* format bitmasks (all or'ed) */
        unsigned int num_formats;               /* number of supported audio formats (list) */
index 060dccb9ec75513def50e6f8be32f60f4f3b05f1..7f78c6d782b079d621d007f7c757e7cfd93587c7 100644 (file)
@@ -31,6 +31,7 @@
 #include "card.h"
 #include "endpoint.h"
 #include "pcm.h"
+#include "quirks.h"
 
 #define EP_FLAG_ACTIVATED      0
 #define EP_FLAG_RUNNING                1
@@ -170,6 +171,11 @@ static void retire_inbound_urb(struct snd_usb_endpoint *ep,
 {
        struct urb *urb = urb_ctx->urb;
 
+       if (unlikely(ep->skip_packets > 0)) {
+               ep->skip_packets--;
+               return;
+       }
+
        if (ep->sync_slave)
                snd_usb_handle_sync_urb(ep->sync_slave, ep, urb);
 
@@ -567,20 +573,19 @@ static void release_urbs(struct snd_usb_endpoint *ep, int force)
  * configure a data endpoint
  */
 static int data_ep_set_params(struct snd_usb_endpoint *ep,
-                             struct snd_pcm_hw_params *hw_params,
+                             snd_pcm_format_t pcm_format,
+                             unsigned int channels,
+                             unsigned int period_bytes,
                              struct audioformat *fmt,
                              struct snd_usb_endpoint *sync_ep)
 {
        unsigned int maxsize, i, urb_packs, total_packs, packs_per_ms;
-       int period_bytes = params_period_bytes(hw_params);
-       int format = params_format(hw_params);
        int is_playback = usb_pipeout(ep->pipe);
-       int frame_bits = snd_pcm_format_physical_width(params_format(hw_params)) *
-                                                       params_channels(hw_params);
+       int frame_bits = snd_pcm_format_physical_width(pcm_format) * channels;
 
        ep->datainterval = fmt->datainterval;
        ep->stride = frame_bits >> 3;
-       ep->silence_value = format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0;
+       ep->silence_value = pcm_format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0;
 
        /* calculate max. frequency */
        if (ep->maxpacksize) {
@@ -693,7 +698,6 @@ out_of_memory:
  * configure a sync endpoint
  */
 static int sync_ep_set_params(struct snd_usb_endpoint *ep,
-                             struct snd_pcm_hw_params *hw_params,
                              struct audioformat *fmt)
 {
        int i;
@@ -736,7 +740,10 @@ out_of_memory:
  * snd_usb_endpoint_set_params: configure an snd_usb_endpoint
  *
  * @ep: the snd_usb_endpoint to configure
- * @hw_params: the hardware parameters
+ * @pcm_format: the audio fomat.
+ * @channels: the number of audio channels.
+ * @period_bytes: the number of bytes in one alsa period.
+ * @rate: the frame rate.
  * @fmt: the USB audio format information
  * @sync_ep: the sync endpoint to use, if any
  *
@@ -745,7 +752,10 @@ out_of_memory:
  * An endpoint that is already running can not be reconfigured.
  */
 int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
-                               struct snd_pcm_hw_params *hw_params,
+                               snd_pcm_format_t pcm_format,
+                               unsigned int channels,
+                               unsigned int period_bytes,
+                               unsigned int rate,
                                struct audioformat *fmt,
                                struct snd_usb_endpoint *sync_ep)
 {
@@ -765,9 +775,9 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
        ep->fill_max = !!(fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX);
 
        if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_FULL)
-               ep->freqn = get_usb_full_speed_rate(params_rate(hw_params));
+               ep->freqn = get_usb_full_speed_rate(rate);
        else
-               ep->freqn = get_usb_high_speed_rate(params_rate(hw_params));
+               ep->freqn = get_usb_high_speed_rate(rate);
 
        /* calculate the frequency in 16.16 format */
        ep->freqm = ep->freqn;
@@ -777,10 +787,11 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
 
        switch (ep->type) {
        case  SND_USB_ENDPOINT_TYPE_DATA:
-               err = data_ep_set_params(ep, hw_params, fmt, sync_ep);
+               err = data_ep_set_params(ep, pcm_format, channels,
+                                        period_bytes, fmt, sync_ep);
                break;
        case  SND_USB_ENDPOINT_TYPE_SYNC:
-               err = sync_ep_set_params(ep, hw_params, fmt);
+               err = sync_ep_set_params(ep, fmt);
                break;
        default:
                err = -EINVAL;
@@ -828,6 +839,8 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep)
        ep->unlink_mask = 0;
        ep->phase = 0;
 
+       snd_usb_endpoint_start_quirk(ep);
+
        /*
         * If this endpoint has a data endpoint as implicit feedback source,
         * don't start the urbs here. Instead, mark them all as available,
index cbbbdf226d66b6fa9eec51fe829a1b03cdd8d518..6376ccf10fd470688daf103b37ff74bcf67af3ea 100644 (file)
@@ -9,7 +9,10 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
                                              int ep_num, int direction, int type);
 
 int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
-                               struct snd_pcm_hw_params *hw_params,
+                               snd_pcm_format_t pcm_format,
+                               unsigned int channels,
+                               unsigned int period_bytes,
+                               unsigned int rate,
                                struct audioformat *fmt,
                                struct snd_usb_endpoint *sync_ep);
 
index 9eed8f40b179dd199702c1247dd65bdd0b56ff35..c1db28f874c285d12f2ee310a57ce34daa54e301 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "usbaudio.h"
 #include "helper.h"
+#include "quirks.h"
 
 /*
  * combine bytes and get an integer value
@@ -97,6 +98,10 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
                memcpy(data, buf, size);
                kfree(buf);
        }
+
+       snd_usb_ctl_msg_quirk(dev, pipe, request, requesttype,
+                             value, index, data, size);
+
        return err;
 }
 
index 4f40ba82316316fdad18839c1bc906af2a2af66f..fe56c9da38e9e6c78cdd6706f09e9639d8a502ab 100644 (file)
@@ -1267,6 +1267,13 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
                /* disable non-functional volume control */
                master_bits &= ~UAC_CONTROL_BIT(UAC_FU_VOLUME);
                break;
+       case USB_ID(0x1130, 0xf211):
+               snd_printk(KERN_INFO
+                          "usbmixer: volume control quirk for Tenx TP6911 Audio Headset\n");
+               /* disable non-functional volume control */
+               channels = 0;
+               break;
+
        }
        if (channels > 0)
                first_ch_bits = snd_usb_combine_bytes(bmaControls + csize, csize);
index f782ce19bf5aa14be92a43df553d66b177cb9429..55e19e1b80ec4eeb282c91cea482ef7434cf8dce 100644 (file)
@@ -82,8 +82,7 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream
 /*
  * find a matching audio format
  */
-static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned int format,
-                                      unsigned int rate, unsigned int channels)
+static struct audioformat *find_format(struct snd_usb_substream *subs)
 {
        struct list_head *p;
        struct audioformat *found = NULL;
@@ -92,16 +91,17 @@ static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned
        list_for_each(p, &subs->fmt_list) {
                struct audioformat *fp;
                fp = list_entry(p, struct audioformat, list);
-               if (!(fp->formats & (1uLL << format)))
+               if (!(fp->formats & (1uLL << subs->pcm_format)))
                        continue;
-               if (fp->channels != channels)
+               if (fp->channels != subs->channels)
                        continue;
-               if (rate < fp->rate_min || rate > fp->rate_max)
+               if (subs->cur_rate < fp->rate_min ||
+                   subs->cur_rate > fp->rate_max)
                        continue;
                if (! (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)) {
                        unsigned int i;
                        for (i = 0; i < fp->nr_rates; i++)
-                               if (fp->rate_table[i] == rate)
+                               if (fp->rate_table[i] == subs->cur_rate)
                                        break;
                        if (i >= fp->nr_rates)
                                continue;
@@ -435,6 +435,42 @@ add_sync_ep:
        return 0;
 }
 
+/*
+ * configure endpoint params
+ *
+ * called  during initial setup and upon resume
+ */
+static int configure_endpoint(struct snd_usb_substream *subs)
+{
+       int ret;
+
+       mutex_lock(&subs->stream->chip->shutdown_mutex);
+       /* format changed */
+       stop_endpoints(subs, 0, 0, 0);
+       ret = snd_usb_endpoint_set_params(subs->data_endpoint,
+                                         subs->pcm_format,
+                                         subs->channels,
+                                         subs->period_bytes,
+                                         subs->cur_rate,
+                                         subs->cur_audiofmt,
+                                         subs->sync_endpoint);
+       if (ret < 0)
+               goto unlock;
+
+       if (subs->sync_endpoint)
+               ret = snd_usb_endpoint_set_params(subs->data_endpoint,
+                                                 subs->pcm_format,
+                                                 subs->channels,
+                                                 subs->period_bytes,
+                                                 subs->cur_rate,
+                                                 subs->cur_audiofmt,
+                                                 NULL);
+
+unlock:
+       mutex_unlock(&subs->stream->chip->shutdown_mutex);
+       return ret;
+}
+
 /*
  * hw_params callback
  *
@@ -450,63 +486,33 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_usb_substream *subs = substream->runtime->private_data;
        struct audioformat *fmt;
-       unsigned int channels, rate, format;
-       int ret, changed;
+       int ret;
 
        ret = snd_pcm_lib_alloc_vmalloc_buffer(substream,
                                               params_buffer_bytes(hw_params));
        if (ret < 0)
                return ret;
 
-       format = params_format(hw_params);
-       rate = params_rate(hw_params);
-       channels = params_channels(hw_params);
-       fmt = find_format(subs, format, rate, channels);
+       subs->pcm_format = params_format(hw_params);
+       subs->period_bytes = params_period_bytes(hw_params);
+       subs->channels = params_channels(hw_params);
+       subs->cur_rate = params_rate(hw_params);
+
+       fmt = find_format(subs);
        if (!fmt) {
                snd_printd(KERN_DEBUG "cannot set format: format = %#x, rate = %d, channels = %d\n",
-                          format, rate, channels);
+                          subs->pcm_format, subs->cur_rate, subs->channels);
                return -EINVAL;
        }
 
-       changed = subs->cur_audiofmt != fmt ||
-               subs->period_bytes != params_period_bytes(hw_params) ||
-               subs->cur_rate != rate;
        if ((ret = set_format(subs, fmt)) < 0)
                return ret;
 
-       if (subs->cur_rate != rate) {
-               struct usb_host_interface *alts;
-               struct usb_interface *iface;
-               iface = usb_ifnum_to_if(subs->dev, fmt->iface);
-               alts = &iface->altsetting[fmt->altset_idx];
-               ret = snd_usb_init_sample_rate(subs->stream->chip, fmt->iface, alts, fmt, rate);
-               if (ret < 0)
-                       return ret;
-               subs->cur_rate = rate;
-       }
-
-       if (changed) {
-               mutex_lock(&subs->stream->chip->shutdown_mutex);
-               /* format changed */
-               stop_endpoints(subs, 0, 0, 0);
-               ret = snd_usb_endpoint_set_params(subs->data_endpoint, hw_params, fmt,
-                                                 subs->sync_endpoint);
-               if (ret < 0)
-                       goto unlock;
+       subs->interface = fmt->iface;
+       subs->altset_idx = fmt->altset_idx;
+       subs->need_setup_ep = true;
 
-               if (subs->sync_endpoint)
-                       ret = snd_usb_endpoint_set_params(subs->sync_endpoint,
-                                                         hw_params, fmt, NULL);
-unlock:
-               mutex_unlock(&subs->stream->chip->shutdown_mutex);
-       }
-
-       if (ret == 0) {
-               subs->interface = fmt->iface;
-               subs->altset_idx = fmt->altset_idx;
-       }
-
-       return ret;
+       return 0;
 }
 
 /*
@@ -537,6 +543,9 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_usb_substream *subs = runtime->private_data;
+       struct usb_host_interface *alts;
+       struct usb_interface *iface;
+       int ret;
 
        if (! subs->cur_audiofmt) {
                snd_printk(KERN_ERR "usbaudio: no format is specified!\n");
@@ -546,6 +555,27 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
        if (snd_BUG_ON(!subs->data_endpoint))
                return -EIO;
 
+       ret = set_format(subs, subs->cur_audiofmt);
+       if (ret < 0)
+               return ret;
+
+       iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface);
+       alts = &iface->altsetting[subs->cur_audiofmt->altset_idx];
+       ret = snd_usb_init_sample_rate(subs->stream->chip,
+                                      subs->cur_audiofmt->iface,
+                                      alts,
+                                      subs->cur_audiofmt,
+                                      subs->cur_rate);
+       if (ret < 0)
+               return ret;
+
+       if (subs->need_setup_ep) {
+               ret = configure_endpoint(subs);
+               if (ret < 0)
+                       return ret;
+               subs->need_setup_ep = false;
+       }
+
        /* some unit conversions in runtime */
        subs->data_endpoint->maxframesize =
                bytes_to_frames(runtime, subs->data_endpoint->maxpacksize);
index 79780fa57a431345e28896730d12a9fbedf11426..d73ac9bc427298f0f35ddf3cea7245b201f55709 100644 (file)
@@ -2781,6 +2781,59 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
 
+/* Microsoft XboxLive Headset/Xbox Communicator */
+{
+       USB_DEVICE(0x045e, 0x0283),
+       .bInterfaceClass = USB_CLASS_PER_INTERFACE,
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Microsoft",
+               .product_name = "XboxLive Headset/Xbox Communicator",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = &(const struct snd_usb_audio_quirk[]) {
+                       {
+                               /* playback */
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                                       .channels = 1,
+                                       .iface = 0,
+                                       .altsetting = 0,
+                                       .altset_idx = 0,
+                                       .attributes = 0,
+                                       .endpoint = 0x04,
+                                       .ep_attr = 0x05,
+                                       .rates = SNDRV_PCM_RATE_CONTINUOUS,
+                                       .rate_min = 22050,
+                                       .rate_max = 22050
+                               }
+                       },
+                       {
+                               /* capture */
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                                       .channels = 1,
+                                       .iface = 1,
+                                       .altsetting = 0,
+                                       .altset_idx = 0,
+                                       .attributes = 0,
+                                       .endpoint = 0x85,
+                                       .ep_attr = 0x05,
+                                       .rates = SNDRV_PCM_RATE_CONTINUOUS,
+                                       .rate_min = 16000,
+                                       .rate_max = 16000
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
+
 {
        /*
         * Some USB MIDI devices don't have an audio control interface,
index 27817266867ae2c17b09f4ea85b6522a9d39e4ea..0f58b4b6d7023d0e4c47734216e276132c2fbe80 100644 (file)
@@ -761,3 +761,27 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
        }
 }
 
+void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep)
+{
+       /*
+        * "Playback Design" products send bogus feedback data at the start
+        * of the stream. Ignore them.
+        */
+       if ((le16_to_cpu(ep->chip->dev->descriptor.idVendor) == 0x23ba) &&
+           ep->type == SND_USB_ENDPOINT_TYPE_SYNC)
+               ep->skip_packets = 4;
+}
+
+void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
+                          __u8 request, __u8 requesttype, __u16 value,
+                          __u16 index, void *data, __u16 size)
+{
+       /*
+        * "Playback Design" products need a 20ms delay after each
+        * class compliant request
+        */
+       if ((le16_to_cpu(dev->descriptor.idVendor) == 0x23ba) &&
+           (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
+               mdelay(20);
+}
+
index 03e5e94098cdc8f97d7510c4090204bc1c7bce03..0ca9e91067a664e6544f22161cf026c118469860 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef __USBAUDIO_QUIRKS_H
 #define __USBAUDIO_QUIRKS_H
 
+struct audioformat;
+struct snd_usb_endpoint;
+struct snd_usb_substream;
+
 int snd_usb_create_quirk(struct snd_usb_audio *chip,
                         struct usb_interface *iface,
                         struct usb_driver *driver,
@@ -20,4 +24,10 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
 int snd_usb_is_big_endian_format(struct snd_usb_audio *chip,
                                 struct audioformat *fp);
 
+void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep);
+
+void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
+                          __u8 request, __u8 requesttype, __u16 value,
+                          __u16 index, void *data, __u16 size);
+
 #endif /* __USBAUDIO_QUIRKS_H */