aboutsummaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/Kconfig2
-rw-r--r--sound/Makefile2
-rw-r--r--sound/aoa/aoa-gpio.h2
-rw-r--r--sound/aoa/core/alsa.c7
-rw-r--r--sound/aoa/core/gpio-feature.c17
-rw-r--r--sound/aoa/fabrics/layout.c81
-rw-r--r--sound/aoa/soundbus/i2sbus/core.c22
-rw-r--r--sound/arm/Kconfig11
-rw-r--r--sound/arm/Makefile3
-rw-r--r--sound/arm/aaci.c13
-rw-r--r--sound/arm/pxa2xx-ac97-lib.c71
-rw-r--r--sound/arm/pxa2xx-ac97.c7
-rw-r--r--sound/arm/sa11xx-uda1341.c983
-rw-r--r--sound/atmel/Kconfig19
-rw-r--r--sound/atmel/Makefile5
-rw-r--r--sound/atmel/abdac.c602
-rw-r--r--sound/atmel/ac97c.c932
-rw-r--r--sound/atmel/ac97c.h71
-rw-r--r--sound/core/hwdep.c9
-rw-r--r--sound/core/init.c89
-rw-r--r--sound/core/jack.c47
-rw-r--r--sound/core/misc.c10
-rw-r--r--sound/core/oss/mixer_oss.c3
-rw-r--r--sound/core/oss/pcm_oss.c55
-rw-r--r--sound/core/oss/pcm_plugin.h4
-rw-r--r--sound/core/oss/rate.c2
-rw-r--r--sound/core/pcm.c3
-rw-r--r--sound/core/pcm_lib.c155
-rw-r--r--sound/core/pcm_native.c6
-rw-r--r--sound/core/pcm_timer.c6
-rw-r--r--sound/core/rawmidi.c379
-rw-r--r--sound/core/seq/oss/seq_oss_device.h2
-rw-r--r--sound/core/seq/seq_prioq.c3
-rw-r--r--sound/core/sgbuf.c7
-rw-r--r--sound/core/vmaster.c62
-rw-r--r--sound/drivers/dummy.c8
-rw-r--r--sound/drivers/ml403-ac97cr.c6
-rw-r--r--sound/drivers/mpu401/mpu401.c6
-rw-r--r--sound/drivers/mtpav.c21
-rw-r--r--sound/drivers/mts64.c8
-rw-r--r--sound/drivers/opl3/opl3_lib.c2
-rw-r--r--sound/drivers/opl3/opl3_midi.c30
-rw-r--r--sound/drivers/opl3/opl3_oss.c8
-rw-r--r--sound/drivers/opl3/opl3_synth.c2
-rw-r--r--sound/drivers/pcsp/pcsp.c8
-rw-r--r--sound/drivers/portman2x4.c6
-rw-r--r--sound/drivers/serial-u16550.c24
-rw-r--r--sound/drivers/virmidi.c12
-rw-r--r--sound/drivers/vx/vx_core.c3
-rw-r--r--sound/drivers/vx/vx_hwdep.c12
-rw-r--r--sound/drivers/vx/vx_uer.c2
-rw-r--r--sound/i2c/Makefile2
-rw-r--r--sound/i2c/l3/Makefile8
-rw-r--r--sound/i2c/l3/uda1341.c935
-rw-r--r--sound/isa/Kconfig25
-rw-r--r--sound/isa/ad1816a/ad1816a.c21
-rw-r--r--sound/isa/ad1816a/ad1816a_lib.c11
-rw-r--r--sound/isa/ad1848/ad1848.c6
-rw-r--r--sound/isa/adlib.c6
-rw-r--r--sound/isa/als100.c7
-rw-r--r--sound/isa/azt2320.c7
-rw-r--r--sound/isa/cmi8330.c94
-rw-r--r--sound/isa/cs423x/Makefile8
-rw-r--r--sound/isa/cs423x/cs4231.c6
-rw-r--r--sound/isa/cs423x/cs4232.c2
-rw-r--r--sound/isa/cs423x/cs4236.c185
-rw-r--r--sound/isa/cs423x/cs4236_lib.c45
-rw-r--r--sound/isa/dt019x.c7
-rw-r--r--sound/isa/es1688/es1688.c29
-rw-r--r--sound/isa/es1688/es1688_lib.c23
-rw-r--r--sound/isa/es18xx.c24
-rw-r--r--sound/isa/gus/gus_dma.c27
-rw-r--r--sound/isa/gus/gus_irq.c6
-rw-r--r--sound/isa/gus/gus_pcm.c26
-rw-r--r--sound/isa/gus/gus_uart.c10
-rw-r--r--sound/isa/gus/gusclassic.c6
-rw-r--r--sound/isa/gus/gusextreme.c6
-rw-r--r--sound/isa/gus/gusmax.c8
-rw-r--r--sound/isa/gus/interwave.c42
-rw-r--r--sound/isa/opl3sa2.c59
-rw-r--r--sound/isa/opti9xx/miro.c7
-rw-r--r--sound/isa/opti9xx/opti92x-ad1848.c65
-rw-r--r--sound/isa/sb/es968.c7
-rw-r--r--sound/isa/sb/sb16.c28
-rw-r--r--sound/isa/sb/sb8.c8
-rw-r--r--sound/isa/sc6000.c10
-rw-r--r--sound/isa/sgalaxy.c6
-rw-r--r--sound/isa/sscape.c16
-rw-r--r--sound/isa/wavefront/wavefront.c30
-rw-r--r--sound/isa/wavefront/wavefront_synth.c2
-rw-r--r--sound/isa/wss/wss_lib.c79
-rw-r--r--sound/mips/au1x00.c9
-rw-r--r--sound/mips/hal2.c6
-rw-r--r--sound/mips/sgio2audio.c6
-rw-r--r--sound/oss/dmasound/dmasound_atari.c16
-rw-r--r--sound/parisc/harmony.c6
-rw-r--r--sound/pci/Kconfig20
-rw-r--r--sound/pci/ac97/ac97_codec.c6
-rw-r--r--sound/pci/ad1889.c6
-rw-r--r--sound/pci/ak4531_codec.c3
-rw-r--r--sound/pci/ali5451/ali5451.c10
-rw-r--r--sound/pci/als300.c8
-rw-r--r--sound/pci/als4000.c9
-rw-r--r--sound/pci/atiixp.c6
-rw-r--r--sound/pci/atiixp_modem.c6
-rw-r--r--sound/pci/au88x0/au88x0.c6
-rw-r--r--sound/pci/au88x0/au88x0_a3d.c7
-rw-r--r--sound/pci/au88x0/au88x0_core.c21
-rw-r--r--sound/pci/au88x0/au88x0_synth.c39
-rw-r--r--sound/pci/aw2/aw2-alsa.c8
-rw-r--r--sound/pci/azt3328.c14
-rw-r--r--sound/pci/bt87x.c6
-rw-r--r--sound/pci/ca0106/ca0106_main.c105
-rw-r--r--sound/pci/cmipci.c6
-rw-r--r--sound/pci/cs4281.c12
-rw-r--r--sound/pci/cs46xx/cs46xx.c6
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c6
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.h6
-rw-r--r--sound/pci/cs5530.c6
-rw-r--r--sound/pci/cs5535audio/cs5535audio.c8
-rw-r--r--sound/pci/echoaudio/Makefile4
-rw-r--r--sound/pci/echoaudio/echo3g_dsp.c2
-rw-r--r--sound/pci/echoaudio/echoaudio.c23
-rw-r--r--sound/pci/echoaudio/echoaudio.h3
-rw-r--r--sound/pci/echoaudio/echoaudio_3g.c3
-rw-r--r--sound/pci/echoaudio/echoaudio_dsp.c6
-rw-r--r--sound/pci/echoaudio/echoaudio_dsp.h9
-rw-r--r--sound/pci/echoaudio/gina20_dsp.c4
-rw-r--r--sound/pci/echoaudio/indigo_dsp.c12
-rw-r--r--sound/pci/echoaudio/indigo_express_dsp.c119
-rw-r--r--sound/pci/echoaudio/indigodj_dsp.c12
-rw-r--r--sound/pci/echoaudio/indigodjx.c107
-rw-r--r--sound/pci/echoaudio/indigodjx_dsp.c68
-rw-r--r--sound/pci/echoaudio/indigoio_dsp.c12
-rw-r--r--sound/pci/echoaudio/indigoiox.c109
-rw-r--r--sound/pci/echoaudio/indigoiox_dsp.c68
-rw-r--r--sound/pci/echoaudio/layla20_dsp.c4
-rw-r--r--sound/pci/echoaudio/mia_dsp.c16
-rw-r--r--sound/pci/echoaudio/midi.c4
-rw-r--r--sound/pci/emu10k1/emu10k1.c6
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c1
-rw-r--r--sound/pci/emu10k1/emu10k1x.c6
-rw-r--r--sound/pci/ens1370.c9
-rw-r--r--sound/pci/es1938.c29
-rw-r--r--sound/pci/es1968.c6
-rw-r--r--sound/pci/fm801.c6
-rw-r--r--sound/pci/hda/hda_codec.c19
-rw-r--r--sound/pci/hda/hda_codec.h1
-rw-r--r--sound/pci/hda/hda_hwdep.c17
-rw-r--r--sound/pci/hda/hda_intel.c55
-rw-r--r--sound/pci/hda/hda_local.h2
-rw-r--r--sound/pci/hda/hda_proc.c3
-rw-r--r--sound/pci/hda/patch_analog.c15
-rw-r--r--sound/pci/hda/patch_conexant.c14
-rw-r--r--sound/pci/hda/patch_intelhdmi.c61
-rw-r--r--sound/pci/hda/patch_realtek.c11
-rw-r--r--sound/pci/hda/patch_sigmatel.c25
-rw-r--r--sound/pci/ice1712/ice1712.c6
-rw-r--r--sound/pci/ice1712/ice1724.c6
-rw-r--r--sound/pci/intel8x0.c8
-rw-r--r--sound/pci/intel8x0m.c6
-rw-r--r--sound/pci/korg1212/korg1212.c6
-rw-r--r--sound/pci/maestro3.c6
-rw-r--r--sound/pci/mixart/mixart.c7
-rw-r--r--sound/pci/mixart/mixart_hwdep.c58
-rw-r--r--sound/pci/nm256/nm256.c6
-rw-r--r--sound/pci/oxygen/oxygen_lib.c8
-rw-r--r--sound/pci/oxygen/virtuoso.c17
-rw-r--r--sound/pci/pcxhr/pcxhr.c6
-rw-r--r--sound/pci/pcxhr/pcxhr.h12
-rw-r--r--sound/pci/pcxhr/pcxhr_hwdep.c12
-rw-r--r--sound/pci/riptide/riptide.c6
-rw-r--r--sound/pci/rme32.c7
-rw-r--r--sound/pci/rme96.c7
-rw-r--r--sound/pci/rme9652/hdsp.c15
-rw-r--r--sound/pci/rme9652/hdspm.c17
-rw-r--r--sound/pci/rme9652/rme9652.c8
-rw-r--r--sound/pci/sis7019.c5
-rw-r--r--sound/pci/sonicvibes.c115
-rw-r--r--sound/pci/trident/trident.c6
-rw-r--r--sound/pci/trident/trident_main.c57
-rw-r--r--sound/pci/via82xx.c29
-rw-r--r--sound/pci/via82xx_modem.c11
-rw-r--r--sound/pci/vx222/vx222.c6
-rw-r--r--sound/pci/vx222/vx222_ops.c8
-rw-r--r--sound/pci/ymfpci/ymfpci.c6
-rw-r--r--sound/pci/ymfpci/ymfpci_main.c14
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf.c19
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf_core.c23
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf_irq.c4
-rw-r--r--sound/pcmcia/vx/vxpocket.c32
-rw-r--r--sound/ppc/powermac.c6
-rw-r--r--sound/ppc/snd_ps3.c6
-rw-r--r--sound/sh/aica.c8
-rw-r--r--sound/soc/Kconfig1
-rw-r--r--sound/soc/Makefile2
-rw-r--r--sound/soc/atmel/atmel-pcm.c2
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c35
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.h2
-rw-r--r--sound/soc/atmel/playpaq_wm8510.c24
-rw-r--r--sound/soc/atmel/sam9g20_wm8731.c124
-rw-r--r--sound/soc/au1x/dbdma2.c2
-rw-r--r--sound/soc/au1x/psc-ac97.c10
-rw-r--r--sound/soc/au1x/psc-i2s.c12
-rw-r--r--sound/soc/blackfin/bf5xx-ac97-pcm.c2
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.c94
-rw-r--r--sound/soc/blackfin/bf5xx-ad73311.c4
-rw-r--r--sound/soc/blackfin/bf5xx-i2s-pcm.c2
-rw-r--r--sound/soc/blackfin/bf5xx-i2s.c14
-rw-r--r--sound/soc/blackfin/bf5xx-sport.c104
-rw-r--r--sound/soc/codecs/Kconfig23
-rw-r--r--sound/soc/codecs/Makefile7
-rw-r--r--sound/soc/codecs/ac97.c29
-rw-r--r--sound/soc/codecs/ad1980.c33
-rw-r--r--sound/soc/codecs/ad73311.c8
-rw-r--r--sound/soc/codecs/ad73311.h2
-rw-r--r--sound/soc/codecs/ak4104.c365
-rw-r--r--sound/soc/codecs/ak4104.h7
-rw-r--r--sound/soc/codecs/ak4535.c46
-rw-r--r--sound/soc/codecs/cs4270.c667
-rw-r--r--sound/soc/codecs/pcm3008.c12
-rw-r--r--sound/soc/codecs/ssm2602.c58
-rw-r--r--sound/soc/codecs/tlv320aic23.c57
-rw-r--r--sound/soc/codecs/tlv320aic26.c29
-rw-r--r--sound/soc/codecs/tlv320aic3x.c172
-rw-r--r--sound/soc/codecs/twl4030.c524
-rw-r--r--sound/soc/codecs/twl4030.h15
-rw-r--r--sound/soc/codecs/uda134x.c84
-rw-r--r--sound/soc/codecs/uda1380.c241
-rw-r--r--sound/soc/codecs/wm8350.c168
-rw-r--r--sound/soc/codecs/wm8350.h8
-rw-r--r--sound/soc/codecs/wm8400.c1582
-rw-r--r--sound/soc/codecs/wm8400.h62
-rw-r--r--sound/soc/codecs/wm8510.c55
-rw-r--r--sound/soc/codecs/wm8580.c381
-rw-r--r--sound/soc/codecs/wm8580.h5
-rw-r--r--sound/soc/codecs/wm8728.c50
-rw-r--r--sound/soc/codecs/wm8731.c432
-rw-r--r--sound/soc/codecs/wm8731.h6
-rw-r--r--sound/soc/codecs/wm8750.c48
-rw-r--r--sound/soc/codecs/wm8753.c551
-rw-r--r--sound/soc/codecs/wm8753.h6
-rw-r--r--sound/soc/codecs/wm8900.c51
-rw-r--r--sound/soc/codecs/wm8903.c60
-rw-r--r--sound/soc/codecs/wm8971.c46
-rw-r--r--sound/soc/codecs/wm8990.c61
-rw-r--r--sound/soc/codecs/wm9705.c415
-rw-r--r--sound/soc/codecs/wm9705.h14
-rw-r--r--sound/soc/codecs/wm9712.c57
-rw-r--r--sound/soc/codecs/wm9713.c96
-rw-r--r--sound/soc/davinci/Kconfig2
-rw-r--r--sound/soc/davinci/davinci-evm.c3
-rw-r--r--sound/soc/davinci/davinci-i2s.c14
-rw-r--r--sound/soc/davinci/davinci-pcm.c2
-rw-r--r--sound/soc/davinci/davinci-sffsdr.c43
-rw-r--r--sound/soc/fsl/Kconfig17
-rw-r--r--sound/soc/fsl/Makefile7
-rw-r--r--sound/soc/fsl/fsl_dma.c181
-rw-r--r--sound/soc/fsl/fsl_ssi.c98
-rw-r--r--sound/soc/fsl/fsl_ssi.h2
-rw-r--r--sound/soc/fsl/mpc5200_psc_i2s.c20
-rw-r--r--sound/soc/fsl/mpc8610_hpcd.c5
-rw-r--r--sound/soc/omap/Kconfig14
-rw-r--r--sound/soc/omap/Makefile2
-rw-r--r--sound/soc/omap/n810.c47
-rw-r--r--sound/soc/omap/omap-mcbsp.c24
-rw-r--r--sound/soc/omap/omap-pcm.c7
-rw-r--r--sound/soc/omap/omap3pandora.c49
-rw-r--r--sound/soc/omap/osk5912.c12
-rw-r--r--sound/soc/omap/sdp3430.c119
-rw-r--r--sound/soc/pxa/Kconfig27
-rw-r--r--sound/soc/pxa/Makefile6
-rw-r--r--sound/soc/pxa/corgi.c58
-rw-r--r--sound/soc/pxa/e740_wm9705.c211
-rw-r--r--sound/soc/pxa/e750_wm9705.c187
-rw-r--r--sound/soc/pxa/e800_wm9712.c115
-rw-r--r--sound/soc/pxa/mioa701_wm9713.c250
-rw-r--r--sound/soc/pxa/palm27x.c15
-rw-r--r--sound/soc/pxa/poodle.c56
-rw-r--r--sound/soc/pxa/pxa-ssp.c150
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c59
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c54
-rw-r--r--sound/soc/pxa/spitz.c14
-rw-r--r--sound/soc/pxa/tosa.c14
-rw-r--r--sound/soc/pxa/zylonite.c132
-rw-r--r--sound/soc/s3c24xx/Kconfig29
-rw-r--r--sound/soc/s3c24xx/Makefile6
-rw-r--r--sound/soc/s3c24xx/jive_wm8750.c201
-rw-r--r--sound/soc/s3c24xx/neo1973_wm8753.c67
-rw-r--r--sound/soc/s3c24xx/s3c-i2s-v2.c638
-rw-r--r--sound/soc/s3c24xx/s3c-i2s-v2.h90
-rw-r--r--sound/soc/s3c24xx/s3c2412-i2s.c622
-rw-r--r--sound/soc/s3c24xx/s3c2412-i2s.h17
-rw-r--r--sound/soc/s3c24xx/s3c2443-ac97.c20
-rw-r--r--sound/soc/s3c24xx/s3c24xx-i2s.c71
-rw-r--r--sound/soc/s3c24xx/s3c24xx-pcm.c49
-rw-r--r--sound/soc/s3c24xx/s3c24xx_uda134x.c2
-rw-r--r--sound/soc/s3c24xx/s3c64xx-i2s.c222
-rw-r--r--sound/soc/s3c24xx/s3c64xx-i2s.h31
-rw-r--r--sound/soc/sh/hac.c12
-rw-r--r--sound/soc/sh/ssi.c30
-rw-r--r--sound/soc/soc-core.c186
-rw-r--r--sound/soc/soc-dapm.c390
-rw-r--r--sound/soc/soc-jack.c267
-rw-r--r--sound/sparc/amd7930.c12
-rw-r--r--sound/sparc/cs4231.c9
-rw-r--r--sound/sparc/dbri.c8
-rw-r--r--sound/spi/at73c213.c7
-rw-r--r--sound/synth/emux/emux_hwdep.c21
-rw-r--r--sound/synth/emux/emux_oss.c2
-rw-r--r--sound/synth/emux/emux_seq.c16
-rw-r--r--sound/synth/emux/emux_synth.c6
-rw-r--r--sound/synth/emux/soundfont.c28
-rw-r--r--sound/usb/caiaq/caiaq-device.c22
-rw-r--r--sound/usb/usbaudio.c27
-rw-r--r--sound/usb/usbmidi.c1
-rw-r--r--sound/usb/usbmixer.c22
-rw-r--r--sound/usb/usx2y/us122l.c59
-rw-r--r--sound/usb/usx2y/usX2Yhwdep.c15
-rw-r--r--sound/usb/usx2y/usbusx2y.c56
-rw-r--r--sound/usb/usx2y/usx2yhwdeppcm.h2
321 files changed, 12676 insertions, 7142 deletions
diff --git a/sound/Kconfig b/sound/Kconfig
index 200aca1faa7..1eceb85287c 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -60,6 +60,8 @@ source "sound/aoa/Kconfig"
source "sound/arm/Kconfig"
+source "sound/atmel/Kconfig"
+
source "sound/spi/Kconfig"
source "sound/mips/Kconfig"
diff --git a/sound/Makefile b/sound/Makefile
index c76d70716fa..ec467decfa7 100644
--- a/sound/Makefile
+++ b/sound/Makefile
@@ -6,7 +6,7 @@ obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o
obj-$(CONFIG_SOUND_PRIME) += oss/
obj-$(CONFIG_DMASOUND) += oss/
obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \
- sparc/ spi/ parisc/ pcmcia/ mips/ soc/
+ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/
obj-$(CONFIG_SND_AOA) += aoa/
# This one must be compilable even if sound is configured out
diff --git a/sound/aoa/aoa-gpio.h b/sound/aoa/aoa-gpio.h
index ee64f5de896..6065b0344e2 100644
--- a/sound/aoa/aoa-gpio.h
+++ b/sound/aoa/aoa-gpio.h
@@ -34,10 +34,12 @@ struct gpio_methods {
void (*set_headphone)(struct gpio_runtime *rt, int on);
void (*set_speakers)(struct gpio_runtime *rt, int on);
void (*set_lineout)(struct gpio_runtime *rt, int on);
+ void (*set_master)(struct gpio_runtime *rt, int on);
int (*get_headphone)(struct gpio_runtime *rt);
int (*get_speakers)(struct gpio_runtime *rt);
int (*get_lineout)(struct gpio_runtime *rt);
+ int (*get_master)(struct gpio_runtime *rt);
void (*set_hw_reset)(struct gpio_runtime *rt, int on);
diff --git a/sound/aoa/core/alsa.c b/sound/aoa/core/alsa.c
index 61785046358..0fa3855b479 100644
--- a/sound/aoa/core/alsa.c
+++ b/sound/aoa/core/alsa.c
@@ -23,9 +23,10 @@ int aoa_alsa_init(char *name, struct module *mod, struct device *dev)
/* cannot be EEXIST due to usage in aoa_fabric_register */
return -EBUSY;
- alsa_card = snd_card_new(index, name, mod, sizeof(struct aoa_card));
- if (!alsa_card)
- return -ENOMEM;
+ err = snd_card_create(index, name, mod, sizeof(struct aoa_card),
+ &alsa_card);
+ if (err < 0)
+ return err;
aoa_card = alsa_card->private_data;
aoa_card->alsa_card = alsa_card;
alsa_card->dev = dev;
diff --git a/sound/aoa/core/gpio-feature.c b/sound/aoa/core/gpio-feature.c
index c93ad5dec66..de8e03afa97 100644
--- a/sound/aoa/core/gpio-feature.c
+++ b/sound/aoa/core/gpio-feature.c
@@ -14,7 +14,7 @@
#include <linux/interrupt.h>
#include "../aoa.h"
-/* TODO: these are 20 global variables
+/* TODO: these are lots of global variables
* that aren't used on most machines...
* Move them into a dynamically allocated
* structure and use that.
@@ -23,6 +23,7 @@
/* these are the GPIO numbers (register addresses as offsets into
* the GPIO space) */
static int headphone_mute_gpio;
+static int master_mute_gpio;
static int amp_mute_gpio;
static int lineout_mute_gpio;
static int hw_reset_gpio;
@@ -32,6 +33,7 @@ static int linein_detect_gpio;
/* see the SWITCH_GPIO macro */
static int headphone_mute_gpio_activestate;
+static int master_mute_gpio_activestate;
static int amp_mute_gpio_activestate;
static int lineout_mute_gpio_activestate;
static int hw_reset_gpio_activestate;
@@ -156,6 +158,7 @@ static int ftr_gpio_get_##name(struct gpio_runtime *rt) \
FTR_GPIO(headphone, 0);
FTR_GPIO(amp, 1);
FTR_GPIO(lineout, 2);
+FTR_GPIO(master, 3);
static void ftr_gpio_set_hw_reset(struct gpio_runtime *rt, int on)
{
@@ -172,6 +175,8 @@ static void ftr_gpio_set_hw_reset(struct gpio_runtime *rt, int on)
hw_reset_gpio, v);
}
+static struct gpio_methods methods;
+
static void ftr_gpio_all_amps_off(struct gpio_runtime *rt)
{
int saved;
@@ -181,6 +186,8 @@ static void ftr_gpio_all_amps_off(struct gpio_runtime *rt)
ftr_gpio_set_headphone(rt, 0);
ftr_gpio_set_amp(rt, 0);
ftr_gpio_set_lineout(rt, 0);
+ if (methods.set_master)
+ ftr_gpio_set_master(rt, 0);
rt->implementation_private = saved;
}
@@ -193,6 +200,8 @@ static void ftr_gpio_all_amps_restore(struct gpio_runtime *rt)
ftr_gpio_set_headphone(rt, (s>>0)&1);
ftr_gpio_set_amp(rt, (s>>1)&1);
ftr_gpio_set_lineout(rt, (s>>2)&1);
+ if (methods.set_master)
+ ftr_gpio_set_master(rt, (s>>3)&1);
}
static void ftr_handle_notify(struct work_struct *work)
@@ -231,6 +240,12 @@ static void ftr_gpio_init(struct gpio_runtime *rt)
get_gpio("hw-reset", "audio-hw-reset",
&hw_reset_gpio,
&hw_reset_gpio_activestate);
+ if (get_gpio("master-mute", NULL,
+ &master_mute_gpio,
+ &master_mute_gpio_activestate)) {
+ methods.set_master = ftr_gpio_set_master;
+ methods.get_master = ftr_gpio_get_master;
+ }
headphone_detect_node = get_gpio("headphone-detect", NULL,
&headphone_detect_gpio,
diff --git a/sound/aoa/fabrics/layout.c b/sound/aoa/fabrics/layout.c
index ad60f5d10e8..fbf5c933baa 100644
--- a/sound/aoa/fabrics/layout.c
+++ b/sound/aoa/fabrics/layout.c
@@ -1,16 +1,14 @@
/*
- * Apple Onboard Audio driver -- layout fabric
+ * Apple Onboard Audio driver -- layout/machine id fabric
*
- * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net>
*
* GPL v2, can be found in COPYING.
*
*
- * This fabric module looks for sound codecs
- * based on the layout-id property in the device tree.
- *
+ * This fabric module looks for sound codecs based on the
+ * layout-id or device-id property in the device tree.
*/
-
#include <asm/prom.h>
#include <linux/list.h>
#include <linux/module.h>
@@ -63,7 +61,7 @@ struct codec_connect_info {
#define LAYOUT_FLAG_COMBO_LINEOUT_SPDIF (1<<0)
struct layout {
- unsigned int layout_id;
+ unsigned int layout_id, device_id;
struct codec_connect_info codecs[MAX_CODECS_PER_BUS];
int flags;
@@ -111,6 +109,10 @@ MODULE_ALIAS("sound-layout-96");
MODULE_ALIAS("sound-layout-98");
MODULE_ALIAS("sound-layout-100");
+MODULE_ALIAS("aoa-device-id-14");
+MODULE_ALIAS("aoa-device-id-22");
+MODULE_ALIAS("aoa-device-id-35");
+
/* onyx with all but microphone connected */
static struct codec_connection onyx_connections_nomic[] = {
{
@@ -518,6 +520,27 @@ static struct layout layouts[] = {
.connections = onyx_connections_noheadphones,
},
},
+ /* PowerMac3,4 */
+ { .device_id = 14,
+ .codecs[0] = {
+ .name = "tas",
+ .connections = tas_connections_noline,
+ },
+ },
+ /* PowerMac3,6 */
+ { .device_id = 22,
+ .codecs[0] = {
+ .name = "tas",
+ .connections = tas_connections_all,
+ },
+ },
+ /* PowerBook5,2 */
+ { .device_id = 35,
+ .codecs[0] = {
+ .name = "tas",
+ .connections = tas_connections_all,
+ },
+ },
{}
};
@@ -526,7 +549,7 @@ static struct layout *find_layout_by_id(unsigned int id)
struct layout *l;
l = layouts;
- while (l->layout_id) {
+ while (l->codecs[0].name) {
if (l->layout_id == id)
return l;
l++;
@@ -534,6 +557,19 @@ static struct layout *find_layout_by_id(unsigned int id)
return NULL;
}
+static struct layout *find_layout_by_device(unsigned int id)
+{
+ struct layout *l;
+
+ l = layouts;
+ while (l->codecs[0].name) {
+ if (l->device_id == id)
+ return l;
+ l++;
+ }
+ return NULL;
+}
+
static void use_layout(struct layout *l)
{
int i;
@@ -564,6 +600,7 @@ struct layout_dev {
struct snd_kcontrol *headphone_ctrl;
struct snd_kcontrol *lineout_ctrl;
struct snd_kcontrol *speaker_ctrl;
+ struct snd_kcontrol *master_ctrl;
struct snd_kcontrol *headphone_detected_ctrl;
struct snd_kcontrol *lineout_detected_ctrl;
@@ -615,6 +652,7 @@ static struct snd_kcontrol_new n##_ctl = { \
AMP_CONTROL(headphone, "Headphone Switch");
AMP_CONTROL(speakers, "Speakers Switch");
AMP_CONTROL(lineout, "Line-Out Switch");
+AMP_CONTROL(master, "Master Switch");
static int detect_choice_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -855,6 +893,11 @@ static void layout_attached_codec(struct aoa_codec *codec)
lineout = codec->gpio->methods->get_detect(codec->gpio,
AOA_NOTIFY_LINE_OUT);
+ if (codec->gpio->methods->set_master) {
+ ctl = snd_ctl_new1(&master_ctl, codec->gpio);
+ ldev->master_ctrl = ctl;
+ aoa_snd_ctl_add(ctl);
+ }
while (cc->connected) {
if (cc->connected & CC_SPEAKERS) {
if (headphones <= 0 && lineout <= 0)
@@ -938,8 +981,8 @@ static struct aoa_fabric layout_fabric = {
static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
{
struct device_node *sound = NULL;
- const unsigned int *layout_id;
- struct layout *layout;
+ const unsigned int *id;
+ struct layout *layout = NULL;
struct layout_dev *ldev = NULL;
int err;
@@ -952,15 +995,18 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
if (sound->type && strcasecmp(sound->type, "soundchip") == 0)
break;
}
- if (!sound) return -ENODEV;
+ if (!sound)
+ return -ENODEV;
- layout_id = of_get_property(sound, "layout-id", NULL);
- if (!layout_id)
- goto outnodev;
- printk(KERN_INFO "snd-aoa-fabric-layout: found bus with layout %d\n",
- *layout_id);
+ id = of_get_property(sound, "layout-id", NULL);
+ if (id) {
+ layout = find_layout_by_id(*id);
+ } else {
+ id = of_get_property(sound, "device-id", NULL);
+ if (id)
+ layout = find_layout_by_device(*id);
+ }
- layout = find_layout_by_id(*layout_id);
if (!layout) {
printk(KERN_ERR "snd-aoa-fabric-layout: unknown layout\n");
goto outnodev;
@@ -976,6 +1022,7 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
ldev->layout = layout;
ldev->gpio.node = sound->parent;
switch (layout->layout_id) {
+ case 0: /* anything with device_id, not layout_id */
case 41: /* that unknown machine no one seems to have */
case 51: /* PowerBook5,4 */
case 58: /* Mac Mini */
diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c
index be468edf3ec..418c84c99d6 100644
--- a/sound/aoa/soundbus/i2sbus/core.c
+++ b/sound/aoa/soundbus/i2sbus/core.c
@@ -1,7 +1,7 @@
/*
* i2sbus driver
*
- * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net>
*
* GPL v2, can be found in COPYING.
*/
@@ -186,13 +186,25 @@ static int i2sbus_add_dev(struct macio_dev *macio,
}
}
if (i == 1) {
- const u32 *layout_id =
- of_get_property(sound, "layout-id", NULL);
- if (layout_id) {
- layout = *layout_id;
+ const u32 *id = of_get_property(sound, "layout-id", NULL);
+
+ if (id) {
+ layout = *id;
snprintf(dev->sound.modalias, 32,
"sound-layout-%d", layout);
ok = 1;
+ } else {
+ id = of_get_property(sound, "device-id", NULL);
+ /*
+ * We probably cannot handle all device-id machines,
+ * so restrict to those we do handle for now.
+ */
+ if (id && (*id == 22 || *id == 14 || *id == 35)) {
+ snprintf(dev->sound.modalias, 32,
+ "aoa-device-id-%d", *id);
+ ok = 1;
+ layout = -1;
+ }
}
}
/* for the time being, until we can handle non-layout-id
diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig
index f8e6de48d81..885683a3b0b 100644
--- a/sound/arm/Kconfig
+++ b/sound/arm/Kconfig
@@ -11,17 +11,6 @@ menuconfig SND_ARM
if SND_ARM
-config SND_SA11XX_UDA1341
- tristate "SA11xx UDA1341TS driver (iPaq H3600)"
- depends on ARCH_SA1100 && L3
- select SND_PCM
- help
- Say Y here if you have a Compaq iPaq H3x00 handheld computer
- and want to use its Philips UDA 1341 audio chip.
-
- To compile this driver as a module, choose M here: the module
- will be called snd-sa11xx-uda1341.
-
config SND_ARMAACI
tristate "ARM PrimeCell PL041 AC Link support"
depends on ARM_AMBA
diff --git a/sound/arm/Makefile b/sound/arm/Makefile
index 2054de11de8..5a549ed6c8a 100644
--- a/sound/arm/Makefile
+++ b/sound/arm/Makefile
@@ -2,9 +2,6 @@
# Makefile for ALSA
#
-obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-sa11xx-uda1341.o
-snd-sa11xx-uda1341-objs := sa11xx-uda1341.o
-
obj-$(CONFIG_SND_ARMAACI) += snd-aaci.o
snd-aaci-objs := aaci.o devdma.o
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index 89096e811a4..7fbd68fab94 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -90,7 +90,7 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
*/
do {
v = readl(aaci->base + AACI_SLFR);
- } while ((v & (SLFR_1TXB|SLFR_2TXB)) && timeout--);
+ } while ((v & (SLFR_1TXB|SLFR_2TXB)) && --timeout);
if (!timeout)
dev_err(&aaci->dev->dev,
@@ -126,7 +126,7 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
*/
do {
v = readl(aaci->base + AACI_SLFR);
- } while ((v & SLFR_1TXB) && timeout--);
+ } while ((v & SLFR_1TXB) && --timeout);
if (!timeout) {
dev_err(&aaci->dev->dev, "timeout on slot 1 TX busy\n");
@@ -147,7 +147,7 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
do {
cond_resched();
v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV);
- } while ((v != (SLFR_1RXV|SLFR_2RXV)) && timeout--);
+ } while ((v != (SLFR_1RXV|SLFR_2RXV)) && --timeout);
if (!timeout) {
dev_err(&aaci->dev->dev, "timeout on RX valid\n");
@@ -995,10 +995,11 @@ static struct aaci * __devinit aaci_init_card(struct amba_device *dev)
{
struct aaci *aaci;
struct snd_card *card;
+ int err;
- card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
- THIS_MODULE, sizeof(struct aaci));
- if (card == NULL)
+ err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, sizeof(struct aaci), &card);
+ if (err < 0)
return NULL;
card->private_free = aaci_free_card;
diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c
index 35afd0c33be..2e6355f4cbb 100644
--- a/sound/arm/pxa2xx-ac97-lib.c
+++ b/sound/arm/pxa2xx-ac97-lib.c
@@ -31,6 +31,7 @@ static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
static volatile long gsr_bits;
static struct clk *ac97_clk;
static struct clk *ac97conf_clk;
+static int reset_gpio;
/*
* Beware PXA27x bugs:
@@ -42,6 +43,45 @@ static struct clk *ac97conf_clk;
* 1 jiffy timeout if interrupt never comes).
*/
+enum {
+ RESETGPIO_FORCE_HIGH,
+ RESETGPIO_FORCE_LOW,
+ RESETGPIO_NORMAL_ALTFUNC
+};
+
+/**
+ * set_resetgpio_mode - computes and sets the AC97_RESET gpio mode on PXA
+ * @mode: chosen action
+ *
+ * As the PXA27x CPUs suffer from a AC97 bug, a manual control of the reset line
+ * must be done to insure proper work of AC97 reset line. This function
+ * computes the correct gpio_mode for further use by reset functions, and
+ * applied the change through pxa_gpio_mode.
+ */
+static void set_resetgpio_mode(int resetgpio_action)
+{
+ int mode = 0;
+
+ if (reset_gpio)
+ switch (resetgpio_action) {
+ case RESETGPIO_NORMAL_ALTFUNC:
+ if (reset_gpio == 113)
+ mode = 113 | GPIO_OUT | GPIO_DFLT_LOW;
+ if (reset_gpio == 95)
+ mode = 95 | GPIO_ALT_FN_1_OUT;
+ break;
+ case RESETGPIO_FORCE_LOW:
+ mode = reset_gpio | GPIO_OUT | GPIO_DFLT_LOW;
+ break;
+ case RESETGPIO_FORCE_HIGH:
+ mode = reset_gpio | GPIO_OUT | GPIO_DFLT_HIGH;
+ break;
+ };
+
+ if (mode)
+ pxa_gpio_mode(mode);
+}
+
unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
{
unsigned short val = -1;
@@ -137,10 +177,10 @@ static inline void pxa_ac97_warm_pxa27x(void)
/* warm reset broken on Bulverde,
so manually keep AC97 reset high */
- pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH);
+ set_resetgpio_mode(RESETGPIO_FORCE_HIGH);
udelay(10);
GCR |= GCR_WARM_RST;
- pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+ set_resetgpio_mode(RESETGPIO_NORMAL_ALTFUNC);
udelay(500);
}
@@ -308,8 +348,8 @@ int pxa2xx_ac97_hw_resume(void)
pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD);
}
if (cpu_is_pxa27x()) {
- /* Use GPIO 113 as AC97 Reset on Bulverde */
- pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+ /* Use GPIO 113 or 95 as AC97 Reset on Bulverde */
+ set_resetgpio_mode(RESETGPIO_NORMAL_ALTFUNC);
}
clk_enable(ac97_clk);
return 0;
@@ -320,6 +360,27 @@ EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_resume);
int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev)
{
int ret;
+ struct pxa2xx_ac97_platform_data *pdata = dev->dev.platform_data;
+
+ if (pdata) {
+ switch (pdata->reset_gpio) {
+ case 95:
+ case 113:
+ reset_gpio = pdata->reset_gpio;
+ break;
+ case 0:
+ reset_gpio = 113;
+ break;
+ case -1:
+ break;
+ default:
+ dev_err(&dev->dev, "Invalid reset GPIO %d\n",
+ pdata->reset_gpio);
+ }
+ } else {
+ if (cpu_is_pxa27x())
+ reset_gpio = 113;
+ }
if (cpu_is_pxa25x() || cpu_is_pxa27x()) {
pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
@@ -330,7 +391,7 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev)
if (cpu_is_pxa27x()) {
/* Use GPIO 113 as AC97 Reset on Bulverde */
- pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+ set_resetgpio_mode(RESETGPIO_NORMAL_ALTFUNC);
ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK");
if (IS_ERR(ac97conf_clk)) {
ret = PTR_ERR(ac97conf_clk);
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
index 85cf591d4e1..7ed100c80a5 100644
--- a/sound/arm/pxa2xx-ac97.c
+++ b/sound/arm/pxa2xx-ac97.c
@@ -173,10 +173,9 @@ static int __devinit pxa2xx_ac97_probe(struct platform_device *dev)
struct snd_ac97_template ac97_template;
int ret;
- ret = -ENOMEM;
- card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
- THIS_MODULE, 0);
- if (!card)
+ ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, 0, &card);
+ if (ret < 0)
goto err;
card->dev = &dev->dev;
diff --git a/sound/arm/sa11xx-uda1341.c b/sound/arm/sa11xx-uda1341.c
deleted file mode 100644
index 1dcd51d81d1..00000000000
--- a/sound/arm/sa11xx-uda1341.c
+++ /dev/null
@@ -1,983 +0,0 @@
-/*
- * Driver for Philips UDA1341TS on Compaq iPAQ H3600 soundcard
- * Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License.
- *
- * History:
- *
- * 2002-03-13 Tomas Kasparek initial release - based on h3600-uda1341.c from OSS
- * 2002-03-20 Tomas Kasparek playback over ALSA is working
- * 2002-03-28 Tomas Kasparek playback over OSS emulation is working
- * 2002-03-29 Tomas Kasparek basic capture is working (native ALSA)
- * 2002-03-29 Tomas Kasparek capture is working (OSS emulation)
- * 2002-04-04 Tomas Kasparek better rates handling (allow non-standard rates)
- * 2003-02-14 Brian Avery fixed full duplex mode, other updates
- * 2003-02-20 Tomas Kasparek merged updates by Brian (except HAL)
- * 2003-04-19 Jaroslav Kysela recoded DMA stuff to follow 2.4.18rmk3-hh24 kernel
- * working suspend and resume
- * 2003-04-28 Tomas Kasparek updated work by Jaroslav to compile it under 2.5.x again
- * merged HAL layer (patches from Brian)
- */
-
-/***************************************************************************************************
-*
-* To understand what Alsa Drivers should be doing look at "Writing an Alsa Driver" by Takashi Iwai
-* available in the Alsa doc section on the website
-*
-* A few notes to make things clearer. The UDA1341 is hooked up to Serial port 4 on the SA1100.
-* We are using SSP mode to talk to the UDA1341. The UDA1341 bit & wordselect clocks are generated
-* by this UART. Unfortunately, the clock only runs if the transmit buffer has something in it.
-* So, if we are just recording, we feed the transmit DMA stream a bunch of 0x0000 so that the
-* transmit buffer is full and the clock keeps going. The zeroes come from FLUSH_BASE_PHYS which
-* is a mem loc that always decodes to 0's w/ no off chip access.
-*
-* Some alsa terminology:
-* frame => num_channels * sample_size e.g stereo 16 bit is 2 * 16 = 32 bytes
-* period => the least number of bytes that will generate an interrupt e.g. we have a 1024 byte
-* buffer and 4 periods in the runtime structure this means we'll get an int every 256
-* bytes or 4 times per buffer.
-* A number of the sizes are in frames rather than bytes, use frames_to_bytes and
-* bytes_to_frames to convert. The easiest way to tell the units is to look at the
-* type i.e. runtime-> buffer_size is in frames and its type is snd_pcm_uframes_t
-*
-* Notes about the pointer fxn:
-* The pointer fxn needs to return the offset into the dma buffer in frames.
-* Interrupts must be blocked before calling the dma_get_pos fxn to avoid race with interrupts.
-*
-* Notes about pause/resume
-* Implementing this would be complicated so it's skipped. The problem case is:
-* A full duplex connection is going, then play is paused. At this point you need to start xmitting
-* 0's to keep the record active which means you cant just freeze the dma and resume it later you'd
-* need to save off the dma info, and restore it properly on a resume. Yeach!
-*
-* Notes about transfer methods:
-* The async write calls fail. I probably need to implement something else to support them?
-*
-***************************************************************************************************/
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/errno.h>
-#include <linux/ioctl.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-
-#ifdef CONFIG_PM
-#include <linux/pm.h>
-#endif
-
-#include <mach/hardware.h>
-#include <mach/h3600.h>
-#include <asm/mach-types.h>
-#include <asm/dma.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/initval.h>
-
-#include <linux/l3/l3.h>
-
-#undef DEBUG_MODE
-#undef DEBUG_FUNCTION_NAMES
-#include <sound/uda1341.h>
-
-/*
- * FIXME: Is this enough as autodetection of 2.4.X-rmkY-hhZ kernels?
- * We use DMA stuff from 2.4.18-rmk3-hh24 here to be able to compile this
- * module for Familiar 0.6.1
- */
-
-/* {{{ Type definitions */
-
-MODULE_AUTHOR("Tomas Kasparek <tomas.kasparek@seznam.cz>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SA1100/SA1111 + UDA1341TS driver for ALSA");
-MODULE_SUPPORTED_DEVICE("{{UDA1341,iPAQ H3600 UDA1341TS}}");
-
-static char *id; /* ID for this card */
-
-module_param(id, charp, 0444);
-MODULE_PARM_DESC(id, "ID string for SA1100/SA1111 + UDA1341TS soundcard.");
-
-struct audio_stream {
- char *id; /* identification string */
- int stream_id; /* numeric identification */
- dma_device_t dma_dev; /* device identifier for DMA */
-#ifdef HH_VERSION
- dmach_t dmach; /* dma channel identification */
-#else
- dma_regs_t *dma_regs; /* points to our DMA registers */
-#endif
- unsigned int active:1; /* we are using this stream for transfer now */
- int period; /* current transfer period */
- int periods; /* current count of periods registerd in the DMA engine */
- int tx_spin; /* are we recoding - flag used to do DMA trans. for sync */
- unsigned int old_offset;
- spinlock_t dma_lock; /* for locking in DMA operations (see dma-sa1100.c in the kernel) */
- struct snd_pcm_substream *stream;
-};
-
-struct sa11xx_uda1341 {
- struct snd_card *card;
- struct l3_client *uda1341;
- struct snd_pcm *pcm;
- long samplerate;
- struct audio_stream s[2]; /* playback & capture */
-};
-
-static unsigned int rates[] = {
- 8000, 10666, 10985, 14647,
- 16000, 21970, 22050, 24000,
- 29400, 32000, 44100, 48000,
-};
-
-static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
- .count = ARRAY_SIZE(rates),
- .list = rates,
- .mask = 0,
-};
-
-static struct platform_device *device;
-
-/* }}} */
-
-/* {{{ Clock and sample rate stuff */
-
-/*
- * Stop-gap solution until rest of hh.org HAL stuff is merged.
- */
-#define GPIO_H3600_CLK_SET0 GPIO_GPIO (12)
-#define GPIO_H3600_CLK_SET1 GPIO_GPIO (13)
-
-#ifdef CONFIG_SA1100_H3XXX
-#define clr_sa11xx_uda1341_egpio(x) clr_h3600_egpio(x)
-#define set_sa11xx_uda1341_egpio(x) set_h3600_egpio(x)
-#else
-#error This driver could serve H3x00 handhelds only!
-#endif
-
-static void sa11xx_uda1341_set_audio_clock(long val)
-{
- switch (val) {
- case 24000: case 32000: case 48000: /* 00: 12.288 MHz */
- GPCR = GPIO_H3600_CLK_SET0 | GPIO_H3600_CLK_SET1;
- break;
-
- case 22050: case 29400: case 44100: /* 01: 11.2896 MHz */
- GPSR = GPIO_H3600_CLK_SET0;
- GPCR = GPIO_H3600_CLK_SET1;
- break;
-
- case 8000: case 10666: case 16000: /* 10: 4.096 MHz */
- GPCR = GPIO_H3600_CLK_SET0;
- GPSR = GPIO_H3600_CLK_SET1;
- break;
-
- case 10985: case 14647: case 21970: /* 11: 5.6245 MHz */
- GPSR = GPIO_H3600_CLK_SET0 | GPIO_H3600_CLK_SET1;
- break;
- }
-}
-
-static void sa11xx_uda1341_set_samplerate(struct sa11xx_uda1341 *sa11xx_uda1341, long rate)
-{
- int clk_div = 0;
- int clk=0;
-
- /* We don't want to mess with clocks when frames are in flight */
- Ser4SSCR0 &= ~SSCR0_SSE;
- /* wait for any frame to complete */
- udelay(125);
-
- /*
- * We have the following clock sources:
- * 4.096 MHz, 5.6245 MHz, 11.2896 MHz, 12.288 MHz
- * Those can be divided either by 256, 384 or 512.
- * This makes up 12 combinations for the following samplerates...
- */
- if (rate >= 48000)
- rate = 48000;
- else if (rate >= 44100)
- rate = 44100;
- else if (rate >= 32000)
- rate = 32000;
- else if (rate >= 29400)
- rate = 29400;
- else if (rate >= 24000)
- rate = 24000;
- else if (rate >= 22050)
- rate = 22050;
- else if (rate >= 21970)
- rate = 21970;
- else if (rate >= 16000)
- rate = 16000;
- else if (rate >= 14647)
- rate = 14647;
- else if (rate >= 10985)
- rate = 10985;
- else if (rate >= 10666)
- rate = 10666;
- else
- rate = 8000;
-
- /* Set the external clock generator */
-
- sa11xx_uda1341_set_audio_clock(rate);
-
- /* Select the clock divisor */
- switch (rate) {
- case 8000:
- case 10985:
- case 22050:
- case 24000:
- clk = F512;
- clk_div = SSCR0_SerClkDiv(16);
- break;
- case 16000:
- case 21970:
- case 44100:
- case 48000:
- clk = F256;
- clk_div = SSCR0_SerClkDiv(8);
- break;
- case 10666:
- case 14647:
- case 29400:
- case 32000:
- clk = F384;
- clk_div = SSCR0_SerClkDiv(12);
- break;
- }
-
- /* FMT setting should be moved away when other FMTs are added (FIXME) */
- l3_command(sa11xx_uda1341->uda1341, CMD_FORMAT, (void *)LSB16);
-
- l3_command(sa11xx_uda1341->uda1341, CMD_FS, (void *)clk);
- Ser4SSCR0 = (Ser4SSCR0 & ~0xff00) + clk_div + SSCR0_SSE;
- sa11xx_uda1341->samplerate = rate;
-}
-
-/* }}} */
-
-/* {{{ HW init and shutdown */
-
-static void sa11xx_uda1341_audio_init(struct sa11xx_uda1341 *sa11xx_uda1341)
-{
- unsigned long flags;
-
- /* Setup DMA stuff */
- sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK].id = "UDA1341 out";
- sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id = SNDRV_PCM_STREAM_PLAYBACK;
- sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev = DMA_Ser4SSPWr;
-
- sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE].id = "UDA1341 in";
- sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE].stream_id = SNDRV_PCM_STREAM_CAPTURE;
- sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev = DMA_Ser4SSPRd;
-
- /* Initialize the UDA1341 internal state */
-
- /* Setup the uarts */
- local_irq_save(flags);
- GAFR |= (GPIO_SSP_CLK);
- GPDR &= ~(GPIO_SSP_CLK);
- Ser4SSCR0 = 0;
- Ser4SSCR0 = SSCR0_DataSize(16) + SSCR0_TI + SSCR0_SerClkDiv(8);
- Ser4SSCR1 = SSCR1_SClkIactL + SSCR1_SClk1P + SSCR1_ExtClk;
- Ser4SSCR0 |= SSCR0_SSE;
- local_irq_restore(flags);
-
- /* Enable the audio power */
-
- clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
- set_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON);
- set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
-
- /* Wait for the UDA1341 to wake up */
- mdelay(1); //FIXME - was removed by Perex - Why?
-
- /* Initialize the UDA1341 internal state */
- l3_open(sa11xx_uda1341->uda1341);
-
- /* external clock configuration (after l3_open - regs must be initialized */
- sa11xx_uda1341_set_samplerate(sa11xx_uda1341, sa11xx_uda1341->samplerate);
-
- /* Wait for the UDA1341 to wake up */
- set_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
- mdelay(1);
-
- /* make the left and right channels unswapped (flip the WS latch) */
- Ser4SSDR = 0;
-
- clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
-}
-
-static void sa11xx_uda1341_audio_shutdown(struct sa11xx_uda1341 *sa11xx_uda1341)
-{
- /* mute on */
- set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
-
- /* disable the audio power and all signals leading to the audio chip */
- l3_close(sa11xx_uda1341->uda1341);
- Ser4SSCR0 = 0;
- clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET);
-
- /* power off and mute off */
- /* FIXME - is muting off necesary??? */
-
- clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON);
- clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE);
-}
-
-/* }}} */
-
-/* {{{ DMA staff */
-
-/*
- * these are the address and sizes used to fill the xmit buffer
- * so we can get a clock in record only mode
- */
-#define FORCE_CLOCK_ADDR (dma_addr_t)FLUSH_BASE_PHYS
-#define FORCE_CLOCK_SIZE 4096 // was 2048
-
-// FIXME Why this value exactly - wrote comment
-#define DMA_BUF_SIZE 8176 /* <= MAX_DMA_SIZE from asm/arch-sa1100/dma.h */
-
-#ifdef HH_VERSION
-
-static int audio_dma_request(struct audio_stream *s, void (*callback)(void *, int))
-{
- int ret;
-
- ret = sa1100_request_dma(&s->dmach, s->id, s->dma_dev);
- if (ret < 0) {
- printk(KERN_ERR "unable to grab audio dma 0x%x\n", s->dma_dev);
- return ret;
- }
- sa1100_dma_set_callback(s->dmach, callback);
- return 0;
-}
-
-static inline void audio_dma_free(struct audio_stream *s)
-{
- sa1100_free_dma(s->dmach);
- s->dmach = -1;
-}
-
-#else
-
-static int audio_dma_request(struct audio_stream *s, void (*callback)(void *))
-{
- int ret;
-
- ret = sa1100_request_dma(s->dma_dev, s->id, callback, s, &s->dma_regs);
- if (ret < 0)
- printk(KERN_ERR "unable to grab audio dma 0x%x\n", s->dma_dev);
- return ret;
-}
-
-static void audio_dma_free(struct audio_stream *s)
-{
- sa1100_free_dma(s->dma_regs);
- s->dma_regs = 0;
-}
-
-#endif
-
-static u_int audio_get_dma_pos(struct audio_stream *s)
-{
- struct snd_pcm_substream *substream = s->stream;
- struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned int offset;
- unsigned long flags;
- dma_addr_t addr;
-
- // this must be called w/ interrupts locked out see dma-sa1100.c in the kernel
- spin_lock_irqsave(&s->dma_lock, flags);
-#ifdef HH_VERSION
- sa1100_dma_get_current(s->dmach, NULL, &addr);
-#else
- addr = sa1100_get_dma_pos((s)->dma_regs);
-#endif
- offset = addr - runtime->dma_addr;
- spin_unlock_irqrestore(&s->dma_lock, flags);
-
- offset = bytes_to_frames(runtime,offset);
- if (offset >= runtime->buffer_size)
- offset = 0;
-
- return offset;
-}
-
-/*
- * this stops the dma and clears the dma ptrs
- */
-static void audio_stop_dma(struct audio_stream *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->dma_lock, flags);
- s->active = 0;
- s->period = 0;
- /* this stops the dma channel and clears the buffer ptrs */
-#ifdef HH_VERSION
- sa1100_dma_flush_all(s->dmach);
-#else
- sa1100_clear_dma(s->dma_regs);
-#endif
- spin_unlock_irqrestore(&s->dma_lock, flags);
-}
-
-static void audio_process_dma(struct audio_stream *s)
-{
- struct snd_pcm_substream *substream = s->stream;
- struct snd_pcm_runtime *runtime;
- unsigned int dma_size;
- unsigned int offset;
- int ret;
-
- /* we are requested to process synchronization DMA transfer */
- if (s->tx_spin) {
- if (snd_BUG_ON(s->stream_id != SNDRV_PCM_STREAM_PLAYBACK))
- return;
- /* fill the xmit dma buffers and return */
-#ifdef HH_VERSION
- sa1100_dma_set_spin(s->dmach, FORCE_CLOCK_ADDR, FORCE_CLOCK_SIZE);
-#else
- while (1) {
- ret = sa1100_start_dma(s->dma_regs, FORCE_CLOCK_ADDR, FORCE_CLOCK_SIZE);
- if (ret)
- return;
- }
-#endif
- return;
- }
-
- /* must be set here - only valid for running streams, not for forced_clock dma fills */
- runtime = substream->runtime;
- while (s->active && s->periods < runtime->periods) {
- dma_size = frames_to_bytes(runtime, runtime->period_size);
- if (s->old_offset) {
- /* a little trick, we need resume from old position */
- offset = frames_to_bytes(runtime, s->old_offset - 1);
- s->old_offset = 0;
- s->periods = 0;
- s->period = offset / dma_size;
- offset %= dma_size;
- dma_size = dma_size - offset;
- if (!dma_size)
- continue; /* special case */
- } else {
- offset = dma_size * s->period;
- snd_BUG_ON(dma_size > DMA_BUF_SIZE);
- }
-#ifdef HH_VERSION
- ret = sa1100_dma_queue_buffer(s->dmach, s, runtime->dma_addr + offset, dma_size);
- if (ret)
- return; //FIXME
-#else
- ret = sa1100_start_dma((s)->dma_regs, runtime->dma_addr + offset, dma_size);
- if (ret) {
- printk(KERN_ERR "audio_process_dma: cannot queue DMA buffer (%i)\n", ret);
- return;
- }
-#endif
-
- s->period++;
- s->period %= runtime->periods;
- s->periods++;
- }
-}
-
-#ifdef HH_VERSION
-static void audio_dma_callback(void *data, int size)
-#else
-static void audio_dma_callback(void *data)
-#endif
-{
- struct audio_stream *s = data;
-
- /*
- * If we are getting a callback for an active stream then we inform
- * the PCM middle layer we've finished a period
- */
- if (s->active)
- snd_pcm_period_elapsed(s->stream);
-
- spin_lock(&s->dma_lock);
- if (!s->tx_spin && s->periods > 0)
- s->periods--;
- audio_process_dma(s);
- spin_unlock(&s->dma_lock);
-}
-
-/* }}} */
-
-/* {{{ PCM setting */
-
-/* {{{ trigger & timer */
-
-static int snd_sa11xx_uda1341_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
- int stream_id = substream->pstr->stream;
- struct audio_stream *s = &chip->s[stream_id];
- struct audio_stream *s1 = &chip->s[stream_id ^ 1];
- int err = 0;
-
- /* note local interrupts are already disabled in the midlevel code */
- spin_lock(&s->dma_lock);
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- /* now we need to make sure a record only stream has a clock */
- if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) {
- /* we need to force fill the xmit DMA with zeros */
- s1->tx_spin = 1;
- audio_process_dma(s1);
- }
- /* this case is when you were recording then you turn on a
- * playback stream so we stop (also clears it) the dma first,
- * clear the sync flag and then we let it turned on
- */
- else {
- s->tx_spin = 0;
- }
-
- /* requested stream startup */
- s->active = 1;
- audio_process_dma(s);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- /* requested stream shutdown */
- audio_stop_dma(s);
-
- /*
- * now we need to make sure a record only stream has a clock
- * so if we're stopping a playback with an active capture
- * we need to turn the 0 fill dma on for the xmit side
- */
- if (stream_id == SNDRV_PCM_STREAM_PLAYBACK && s1->active) {
- /* we need to force fill the xmit DMA with zeros */
- s->tx_spin = 1;
- audio_process_dma(s);
- }
- /*
- * we killed a capture only stream, so we should also kill
- * the zero fill transmit
- */
- else {
- if (s1->tx_spin) {
- s1->tx_spin = 0;
- audio_stop_dma(s1);
- }
- }
-
- break;
- case SNDRV_PCM_TRIGGER_SUSPEND:
- s->active = 0;
-#ifdef HH_VERSION
- sa1100_dma_stop(s->dmach);
-#else
- //FIXME - DMA API
-#endif
- s->old_offset = audio_get_dma_pos(s) + 1;
-#ifdef HH_VERSION
- sa1100_dma_flush_all(s->dmach);
-#else
- //FIXME - DMA API
-#endif
- s->periods = 0;
- break;
- case SNDRV_PCM_TRIGGER_RESUME:
- s->active = 1;
- s->tx_spin = 0;
- audio_process_dma(s);
- if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) {
- s1->tx_spin = 1;
- audio_process_dma(s1);
- }
- break;
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-#ifdef HH_VERSION
- sa1100_dma_stop(s->dmach);
-#else
- //FIXME - DMA API
-#endif
- s->active = 0;
- if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
- if (s1->active) {
- s->tx_spin = 1;
- s->old_offset = audio_get_dma_pos(s) + 1;
-#ifdef HH_VERSION
- sa1100_dma_flush_all(s->dmach);
-#else
- //FIXME - DMA API
-#endif
- audio_process_dma(s);
- }
- } else {
- if (s1->tx_spin) {
- s1->tx_spin = 0;
-#ifdef HH_VERSION
- sa1100_dma_flush_all(s1->dmach);
-#else
- //FIXME - DMA API
-#endif
- }
- }
- break;
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- s->active = 1;
- if (s->old_offset) {
- s->tx_spin = 0;
- audio_process_dma(s);
- break;
- }
- if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) {
- s1->tx_spin = 1;
- audio_process_dma(s1);
- }
-#ifdef HH_VERSION
- sa1100_dma_resume(s->dmach);
-#else
- //FIXME - DMA API
-#endif
- break;
- default:
- err = -EINVAL;
- break;
- }
- spin_unlock(&s->dma_lock);
- return err;
-}
-
-static int snd_sa11xx_uda1341_prepare(struct snd_pcm_substream *substream)
-{
- struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct audio_stream *s = &chip->s[substream->pstr->stream];
-
- /* set requested samplerate */
- sa11xx_uda1341_set_samplerate(chip, runtime->rate);
-
- /* set requestd format when available */
- /* set FMT here !!! FIXME */
-
- s->period = 0;
- s->periods = 0;
-
- return 0;
-}
-
-static snd_pcm_uframes_t snd_sa11xx_uda1341_pointer(struct snd_pcm_substream *substream)
-{
- struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
- return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
-}
-
-/* }}} */
-
-static struct snd_pcm_hardware snd_sa11xx_uda1341_capture =
-{
- .info = (SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
- SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |\
- SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
- SNDRV_PCM_RATE_KNOT),
- .rate_min = 8000,
- .rate_max = 48000,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 64*1024,
- .period_bytes_min = 64,
- .period_bytes_max = DMA_BUF_SIZE,
- .periods_min = 2,
- .periods_max = 255,
- .fifo_size = 0,
-};
-
-static struct snd_pcm_hardware snd_sa11xx_uda1341_playback =
-{
- .info = (SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
- SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |\
- SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
- SNDRV_PCM_RATE_KNOT),
- .rate_min = 8000,
- .rate_max = 48000,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 64*1024,
- .period_bytes_min = 64,
- .period_bytes_max = DMA_BUF_SIZE,
- .periods_min = 2,
- .periods_max = 255,
- .fifo_size = 0,
-};
-
-static int snd_card_sa11xx_uda1341_open(struct snd_pcm_substream *substream)
-{
- struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- int stream_id = substream->pstr->stream;
- int err;
-
- chip->s[stream_id].stream = substream;
-
- if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
- runtime->hw = snd_sa11xx_uda1341_playback;
- else
- runtime->hw = snd_sa11xx_uda1341_capture;
- if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
- return err;
- if ((err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates)) < 0)
- return err;
-
- return 0;
-}
-
-static int snd_card_sa11xx_uda1341_close(struct snd_pcm_substream *substream)
-{
- struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
-
- chip->s[substream->pstr->stream].stream = NULL;
- return 0;
-}
-
-/* {{{ HW params & free */
-
-static int snd_sa11xx_uda1341_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
-
- return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
-}
-
-static int snd_sa11xx_uda1341_hw_free(struct snd_pcm_substream *substream)
-{
- return snd_pcm_lib_free_pages(substream);
-}
-
-/* }}} */
-
-static struct snd_pcm_ops snd_card_sa11xx_uda1341_playback_ops = {
- .open = snd_card_sa11xx_uda1341_open,
- .close = snd_card_sa11xx_uda1341_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_sa11xx_uda1341_hw_params,
- .hw_free = snd_sa11xx_uda1341_hw_free,
- .prepare = snd_sa11xx_uda1341_prepare,
- .trigger = snd_sa11xx_uda1341_trigger,
- .pointer = snd_sa11xx_uda1341_pointer,
-};
-
-static struct snd_pcm_ops snd_card_sa11xx_uda1341_capture_ops = {
- .open = snd_card_sa11xx_uda1341_open,
- .close = snd_card_sa11xx_uda1341_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_sa11xx_uda1341_hw_params,
- .hw_free = snd_sa11xx_uda1341_hw_free,
- .prepare = snd_sa11xx_uda1341_prepare,
- .trigger = snd_sa11xx_uda1341_trigger,
- .pointer = snd_sa11xx_uda1341_pointer,
-};
-
-static int __init snd_card_sa11xx_uda1341_pcm(struct sa11xx_uda1341 *sa11xx_uda1341, int device)
-{
- struct snd_pcm *pcm;
- int err;
-
- if ((err = snd_pcm_new(sa11xx_uda1341->card, "UDA1341 PCM", device, 1, 1, &pcm)) < 0)
- return err;
-
- /*
- * this sets up our initial buffers and sets the dma_type to isa.
- * isa works but I'm not sure why (or if) it's the right choice
- * this may be too large, trying it for now
- */
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
- snd_dma_isa_data(),
- 64*1024, 64*1024);
-
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_sa11xx_uda1341_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_sa11xx_uda1341_capture_ops);
- pcm->private_data = sa11xx_uda1341;
- pcm->info_flags = 0;
- strcpy(pcm->name, "UDA1341 PCM");
-
- sa11xx_uda1341_audio_init(sa11xx_uda1341);
-
- /* setup DMA controller */
- audio_dma_request(&sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK], audio_dma_callback);
- audio_dma_request(&sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE], audio_dma_callback);
-
- sa11xx_uda1341->pcm = pcm;
-
- return 0;
-}
-
-/* }}} */
-
-/* {{{ module init & exit */
-
-#ifdef CONFIG_PM
-
-static int snd_sa11xx_uda1341_suspend(struct platform_device *devptr,
- pm_message_t state)
-{
- struct snd_card *card = platform_get_drvdata(devptr);
- struct sa11xx_uda1341 *chip = card->private_data;
-
- snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
- snd_pcm_suspend_all(chip->pcm);
-#ifdef HH_VERSION
- sa1100_dma_sleep(chip->s[SNDRV_PCM_STREAM_PLAYBACK].dmach);
- sa1100_dma_sleep(chip->s[SNDRV_PCM_STREAM_CAPTURE].dmach);
-#else
- //FIXME
-#endif
- l3_command(chip->uda1341, CMD_SUSPEND, NULL);
- sa11xx_uda1341_audio_shutdown(chip);
-
- return 0;
-}
-
-static int snd_sa11xx_uda1341_resume(struct platform_device *devptr)
-{
- struct snd_card *card = platform_get_drvdata(devptr);
- struct sa11xx_uda1341 *chip = card->private_data;
-
- sa11xx_uda1341_audio_init(chip);
- l3_command(chip->uda1341, CMD_RESUME, NULL);
-#ifdef HH_VERSION
- sa1100_dma_wakeup(chip->s[SNDRV_PCM_STREAM_PLAYBACK].dmach);
- sa1100_dma_wakeup(chip->s[SNDRV_PCM_STREAM_CAPTURE].dmach);
-#else
- //FIXME
-#endif
- snd_power_change_state(card, SNDRV_CTL_POWER_D0);
- return 0;
-}
-#endif /* COMFIG_PM */
-
-void snd_sa11xx_uda1341_free(struct snd_card *card)
-{
- struct sa11xx_uda1341 *chip = card->private_data;
-
- audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
- audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
-}
-
-static int __devinit sa11xx_uda1341_probe(struct platform_device *devptr)
-{
- int err;
- struct snd_card *card;
- struct sa11xx_uda1341 *chip;
-
- /* register the soundcard */
- card = snd_card_new(-1, id, THIS_MODULE, sizeof(struct sa11xx_uda1341));
- if (card == NULL)
- return -ENOMEM;
-
- chip = card->private_data;
- spin_lock_init(&chip->s[0].dma_lock);
- spin_lock_init(&chip->s[1].dma_lock);
-
- card->private_free = snd_sa11xx_uda1341_free;
- chip->card = card;
- chip->samplerate = AUDIO_RATE_DEFAULT;
-
- // mixer
- if ((err = snd_chip_uda1341_mixer_new(card, &chip->uda1341)))
- goto nodev;
-
- // PCM
- if ((err = snd_card_sa11xx_uda1341_pcm(chip, 0)) < 0)
- goto nodev;
-
- strcpy(card->driver, "UDA1341");
- strcpy(card->shortname, "H3600 UDA1341TS");
- sprintf(card->longname, "Compaq iPAQ H3600 with Philips UDA1341TS");
-
- snd_card_set_dev(card, &devptr->dev);
-
- if ((err = snd_card_register(card)) == 0) {
- printk( KERN_INFO "iPAQ audio support initialized\n" );
- platform_set_drvdata(devptr, card);
- return 0;
- }
-
- nodev:
- snd_card_free(card);
- return err;
-}
-
-static int __devexit sa11xx_uda1341_remove(struct platform_device *devptr)
-{
- snd_card_free(platform_get_drvdata(devptr));
- platform_set_drvdata(devptr, NULL);
- return 0;
-}
-
-#define SA11XX_UDA1341_DRIVER "sa11xx_uda1341"
-
-static struct platform_driver sa11xx_uda1341_driver = {
- .probe = sa11xx_uda1341_probe,
- .remove = __devexit_p(sa11xx_uda1341_remove),
-#ifdef CONFIG_PM
- .suspend = snd_sa11xx_uda1341_suspend,
- .resume = snd_sa11xx_uda1341_resume,
-#endif
- .driver = {
- .name = SA11XX_UDA1341_DRIVER,
- },
-};
-
-static int __init sa11xx_uda1341_init(void)
-{
- int err;
-
- if (!machine_is_h3xxx())
- return -ENODEV;
- if ((err = platform_driver_register(&sa11xx_uda1341_driver)) < 0)
- return err;
- device = platform_device_register_simple(SA11XX_UDA1341_DRIVER, -1, NULL, 0);
- if (!IS_ERR(device)) {
- if (platform_get_drvdata(device))
- return 0;
- platform_device_unregister(device);
- err = -ENODEV;
- } else
- err = PTR_ERR(device);
- platform_driver_unregister(&sa11xx_uda1341_driver);
- return err;
-}
-
-static void __exit sa11xx_uda1341_exit(void)
-{
- platform_device_unregister(device);
- platform_driver_unregister(&sa11xx_uda1341_driver);
-}
-
-module_init(sa11xx_uda1341_init);
-module_exit(sa11xx_uda1341_exit);
-
-/* }}} */
-
-/*
- * Local variables:
- * indent-tabs-mode: t
- * End:
- */
diff --git a/sound/atmel/Kconfig b/sound/atmel/Kconfig
new file mode 100644
index 00000000000..6c228a91940
--- /dev/null
+++ b/sound/atmel/Kconfig
@@ -0,0 +1,19 @@
+menu "Atmel devices (AVR32 and AT91)"
+ depends on AVR32 || ARCH_AT91
+
+config SND_ATMEL_ABDAC
+ tristate "Atmel Audio Bitstream DAC (ABDAC) driver"
+ select SND_PCM
+ depends on DW_DMAC && AVR32
+ help
+ ALSA sound driver for the Atmel Audio Bitstream DAC (ABDAC).
+
+config SND_ATMEL_AC97C
+ tristate "Atmel AC97 Controller (AC97C) driver"
+ select SND_PCM
+ select SND_AC97_CODEC
+ depends on DW_DMAC && AVR32
+ help
+ ALSA sound driver for the Atmel AC97 controller.
+
+endmenu
diff --git a/sound/atmel/Makefile b/sound/atmel/Makefile
new file mode 100644
index 00000000000..219dcfac608
--- /dev/null
+++ b/sound/atmel/Makefile
@@ -0,0 +1,5 @@
+snd-atmel-abdac-objs := abdac.o
+snd-atmel-ac97c-objs := ac97c.o
+
+obj-$(CONFIG_SND_ATMEL_ABDAC) += snd-atmel-abdac.o
+obj-$(CONFIG_SND_ATMEL_AC97C) += snd-atmel-ac97c.o
diff --git a/sound/atmel/abdac.c b/sound/atmel/abdac.c
new file mode 100644
index 00000000000..28b3c7f7cfe
--- /dev/null
+++ b/sound/atmel/abdac.c
@@ -0,0 +1,602 @@
+/*
+ * Driver for the Atmel on-chip Audio Bitstream DAC (ABDAC)
+ *
+ * Copyright (C) 2006-2009 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+#include <linux/clk.h>
+#include <linux/bitmap.h>
+#include <linux/dw_dmac.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/atmel-abdac.h>
+
+/* DAC register offsets */
+#define DAC_DATA 0x0000
+#define DAC_CTRL 0x0008
+#define DAC_INT_MASK 0x000c
+#define DAC_INT_EN 0x0010
+#define DAC_INT_DIS 0x0014
+#define DAC_INT_CLR 0x0018
+#define DAC_INT_STATUS 0x001c
+
+/* Bitfields in CTRL */
+#define DAC_SWAP_OFFSET 30
+#define DAC_SWAP_SIZE 1
+#define DAC_EN_OFFSET 31
+#define DAC_EN_SIZE 1
+
+/* Bitfields in INT_MASK/INT_EN/INT_DIS/INT_STATUS/INT_CLR */
+#define DAC_UNDERRUN_OFFSET 28
+#define DAC_UNDERRUN_SIZE 1
+#define DAC_TX_READY_OFFSET 29
+#define DAC_TX_READY_SIZE 1
+
+/* Bit manipulation macros */
+#define DAC_BIT(name) \
+ (1 << DAC_##name##_OFFSET)
+#define DAC_BF(name, value) \
+ (((value) & ((1 << DAC_##name##_SIZE) - 1)) \
+ << DAC_##name##_OFFSET)
+#define DAC_BFEXT(name, value) \
+ (((value) >> DAC_##name##_OFFSET) \
+ & ((1 << DAC_##name##_SIZE) - 1))
+#define DAC_BFINS(name, value, old) \
+ (((old) & ~(((1 << DAC_##name##_SIZE) - 1) \
+ << DAC_##name##_OFFSET)) \
+ | DAC_BF(name, value))
+
+/* Register access macros */
+#define dac_readl(port, reg) \
+ __raw_readl((port)->regs + DAC_##reg)
+#define dac_writel(port, reg, value) \
+ __raw_writel((value), (port)->regs + DAC_##reg)
+
+/*
+ * ABDAC supports a maximum of 6 different rates from a generic clock. The
+ * generic clock has a power of two divider, which gives 6 steps from 192 kHz
+ * to 5112 Hz.
+ */
+#define MAX_NUM_RATES 6
+/* ALSA seems to use rates between 192000 Hz and 5112 Hz. */
+#define RATE_MAX 192000
+#define RATE_MIN 5112
+
+enum {
+ DMA_READY = 0,
+};
+
+struct atmel_abdac_dma {
+ struct dma_chan *chan;
+ struct dw_cyclic_desc *cdesc;
+};
+
+struct atmel_abdac {
+ struct clk *pclk;
+ struct clk *sample_clk;
+ struct platform_device *pdev;
+ struct atmel_abdac_dma dma;
+
+ struct snd_pcm_hw_constraint_list constraints_rates;
+ struct snd_pcm_substream *substream;
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+
+ void __iomem *regs;
+ unsigned long flags;
+ unsigned int rates[MAX_NUM_RATES];
+ unsigned int rates_num;
+ int irq;
+};
+
+#define get_dac(card) ((struct atmel_abdac *)(card)->private_data)
+
+/* This function is called by the DMA driver. */
+static void atmel_abdac_dma_period_done(void *arg)
+{
+ struct atmel_abdac *dac = arg;
+ snd_pcm_period_elapsed(dac->substream);
+}
+
+static int atmel_abdac_prepare_dma(struct atmel_abdac *dac,
+ struct snd_pcm_substream *substream,
+ enum dma_data_direction direction)
+{
+ struct dma_chan *chan = dac->dma.chan;
+ struct dw_cyclic_desc *cdesc;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned long buffer_len, period_len;
+
+ /*
+ * We don't do DMA on "complex" transfers, i.e. with
+ * non-halfword-aligned buffers or lengths.
+ */
+ if (runtime->dma_addr & 1 || runtime->buffer_size & 1) {
+ dev_dbg(&dac->pdev->dev, "too complex transfer\n");
+ return -EINVAL;
+ }
+
+ buffer_len = frames_to_bytes(runtime, runtime->buffer_size);
+ period_len = frames_to_bytes(runtime, runtime->period_size);
+
+ cdesc = dw_dma_cyclic_prep(chan, runtime->dma_addr, buffer_len,
+ period_len, DMA_TO_DEVICE);
+ if (IS_ERR(cdesc)) {
+ dev_dbg(&dac->pdev->dev, "could not prepare cyclic DMA\n");
+ return PTR_ERR(cdesc);
+ }
+
+ cdesc->period_callback = atmel_abdac_dma_period_done;
+ cdesc->period_callback_param = dac;
+
+ dac->dma.cdesc = cdesc;
+
+ set_bit(DMA_READY, &dac->flags);
+
+ return 0;
+}
+
+static struct snd_pcm_hardware atmel_abdac_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP
+ | SNDRV_PCM_INFO_MMAP_VALID
+ | SNDRV_PCM_INFO_INTERLEAVED
+ | SNDRV_PCM_INFO_BLOCK_TRANSFER
+ | SNDRV_PCM_INFO_RESUME
+ | SNDRV_PCM_INFO_PAUSE),
+ .formats = (SNDRV_PCM_FMTBIT_S16_BE),
+ .rates = (SNDRV_PCM_RATE_KNOT),
+ .rate_min = RATE_MIN,
+ .rate_max = RATE_MAX,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 64 * 4096,
+ .period_bytes_min = 4096,
+ .period_bytes_max = 4096,
+ .periods_min = 4,
+ .periods_max = 64,
+};
+
+static int atmel_abdac_open(struct snd_pcm_substream *substream)
+{
+ struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
+
+ dac->substream = substream;
+ atmel_abdac_hw.rate_max = dac->rates[dac->rates_num - 1];
+ atmel_abdac_hw.rate_min = dac->rates[0];
+ substream->runtime->hw = atmel_abdac_hw;
+
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, &dac->constraints_rates);
+}
+
+static int atmel_abdac_close(struct snd_pcm_substream *substream)
+{
+ struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
+ dac->substream = NULL;
+ return 0;
+}
+
+static int atmel_abdac_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
+ int retval;
+
+ retval = snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+ if (retval < 0)
+ return retval;
+ /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
+ if (retval == 1)
+ if (test_and_clear_bit(DMA_READY, &dac->flags))
+ dw_dma_cyclic_free(dac->dma.chan);
+
+ return retval;
+}
+
+static int atmel_abdac_hw_free(struct snd_pcm_substream *substream)
+{
+ struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
+ if (test_and_clear_bit(DMA_READY, &dac->flags))
+ dw_dma_cyclic_free(dac->dma.chan);
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static int atmel_abdac_prepare(struct snd_pcm_substream *substream)
+{
+ struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
+ int retval;
+
+ retval = clk_set_rate(dac->sample_clk, 256 * substream->runtime->rate);
+ if (retval)
+ return retval;
+
+ if (!test_bit(DMA_READY, &dac->flags))
+ retval = atmel_abdac_prepare_dma(dac, substream, DMA_TO_DEVICE);
+
+ return retval;
+}
+
+static int atmel_abdac_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
+ int retval = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
+ case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
+ case SNDRV_PCM_TRIGGER_START:
+ clk_enable(dac->sample_clk);
+ retval = dw_dma_cyclic_start(dac->dma.chan);
+ if (retval)
+ goto out;
+ dac_writel(dac, CTRL, DAC_BIT(EN));
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
+ case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
+ case SNDRV_PCM_TRIGGER_STOP:
+ dw_dma_cyclic_stop(dac->dma.chan);
+ dac_writel(dac, DATA, 0);
+ dac_writel(dac, CTRL, 0);
+ clk_disable(dac->sample_clk);
+ break;
+ default:
+ retval = -EINVAL;
+ break;
+ }
+out:
+ return retval;
+}
+
+static snd_pcm_uframes_t
+atmel_abdac_pointer(struct snd_pcm_substream *substream)
+{
+ struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ snd_pcm_uframes_t frames;
+ unsigned long bytes;
+
+ bytes = dw_dma_get_src_addr(dac->dma.chan);
+ bytes -= runtime->dma_addr;
+
+ frames = bytes_to_frames(runtime, bytes);
+ if (frames >= runtime->buffer_size)
+ frames -= runtime->buffer_size;
+
+ return frames;
+}
+
+static irqreturn_t abdac_interrupt(int irq, void *dev_id)
+{
+ struct atmel_abdac *dac = dev_id;
+ u32 status;
+
+ status = dac_readl(dac, INT_STATUS);
+ if (status & DAC_BIT(UNDERRUN)) {
+ dev_err(&dac->pdev->dev, "underrun detected\n");
+ dac_writel(dac, INT_CLR, DAC_BIT(UNDERRUN));
+ } else {
+ dev_err(&dac->pdev->dev, "spurious interrupt (status=0x%x)\n",
+ status);
+ dac_writel(dac, INT_CLR, status);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static struct snd_pcm_ops atmel_abdac_ops = {
+ .open = atmel_abdac_open,
+ .close = atmel_abdac_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = atmel_abdac_hw_params,
+ .hw_free = atmel_abdac_hw_free,
+ .prepare = atmel_abdac_prepare,
+ .trigger = atmel_abdac_trigger,
+ .pointer = atmel_abdac_pointer,
+};
+
+static int __devinit atmel_abdac_pcm_new(struct atmel_abdac *dac)
+{
+ struct snd_pcm_hardware hw = atmel_abdac_hw;
+ struct snd_pcm *pcm;
+ int retval;
+
+ retval = snd_pcm_new(dac->card, dac->card->shortname,
+ dac->pdev->id, 1, 0, &pcm);
+ if (retval)
+ return retval;
+
+ strcpy(pcm->name, dac->card->shortname);
+ pcm->private_data = dac;
+ pcm->info_flags = 0;
+ dac->pcm = pcm;
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &atmel_abdac_ops);
+
+ retval = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ &dac->pdev->dev, hw.periods_min * hw.period_bytes_min,
+ hw.buffer_bytes_max);
+
+ return retval;
+}
+
+static bool filter(struct dma_chan *chan, void *slave)
+{
+ struct dw_dma_slave *dws = slave;
+
+ if (dws->dma_dev == chan->device->dev) {
+ chan->private = dws;
+ return true;
+ } else
+ return false;
+}
+
+static int set_sample_rates(struct atmel_abdac *dac)
+{
+ long new_rate = RATE_MAX;
+ int retval = -EINVAL;
+ int index = 0;
+
+ /* we start at 192 kHz and work our way down to 5112 Hz */
+ while (new_rate >= RATE_MIN && index < (MAX_NUM_RATES + 1)) {
+ new_rate = clk_round_rate(dac->sample_clk, 256 * new_rate);
+ if (new_rate < 0)
+ break;
+ /* make sure we are below the ABDAC clock */
+ if (new_rate <= clk_get_rate(dac->pclk)) {
+ dac->rates[index] = new_rate / 256;
+ index++;
+ }
+ /* divide by 256 and then by two to get next rate */
+ new_rate /= 256 * 2;
+ }
+
+ if (index) {
+ int i;
+
+ /* reverse array, smallest go first */
+ for (i = 0; i < (index / 2); i++) {
+ unsigned int tmp = dac->rates[index - 1 - i];
+ dac->rates[index - 1 - i] = dac->rates[i];
+ dac->rates[i] = tmp;
+ }
+
+ dac->constraints_rates.count = index;
+ dac->constraints_rates.list = dac->rates;
+ dac->constraints_rates.mask = 0;
+ dac->rates_num = index;
+
+ retval = 0;
+ }
+
+ return retval;
+}
+
+static int __devinit atmel_abdac_probe(struct platform_device *pdev)
+{
+ struct snd_card *card;
+ struct atmel_abdac *dac;
+ struct resource *regs;
+ struct atmel_abdac_pdata *pdata;
+ struct clk *pclk;
+ struct clk *sample_clk;
+ int retval;
+ int irq;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs) {
+ dev_dbg(&pdev->dev, "no memory resource\n");
+ return -ENXIO;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_dbg(&pdev->dev, "could not get IRQ number\n");
+ return irq;
+ }
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_dbg(&pdev->dev, "no platform data\n");
+ return -ENXIO;
+ }
+
+ pclk = clk_get(&pdev->dev, "pclk");
+ if (IS_ERR(pclk)) {
+ dev_dbg(&pdev->dev, "no peripheral clock\n");
+ return PTR_ERR(pclk);
+ }
+ sample_clk = clk_get(&pdev->dev, "sample_clk");
+ if (IS_ERR(pclk)) {
+ dev_dbg(&pdev->dev, "no sample clock\n");
+ retval = PTR_ERR(pclk);
+ goto out_put_pclk;
+ }
+ clk_enable(pclk);
+
+ retval = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, sizeof(struct atmel_abdac), &card);
+ if (retval) {
+ dev_dbg(&pdev->dev, "could not create sound card device\n");
+ goto out_put_sample_clk;
+ }
+
+ dac = get_dac(card);
+
+ dac->irq = irq;
+ dac->card = card;
+ dac->pclk = pclk;
+ dac->sample_clk = sample_clk;
+ dac->pdev = pdev;
+
+ retval = set_sample_rates(dac);
+ if (retval < 0) {
+ dev_dbg(&pdev->dev, "could not set supported rates\n");
+ goto out_free_card;
+ }
+
+ dac->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ if (!dac->regs) {
+ dev_dbg(&pdev->dev, "could not remap register memory\n");
+ goto out_free_card;
+ }
+
+ /* make sure the DAC is silent and disabled */
+ dac_writel(dac, DATA, 0);
+ dac_writel(dac, CTRL, 0);
+
+ retval = request_irq(irq, abdac_interrupt, 0, "abdac", dac);
+ if (retval) {
+ dev_dbg(&pdev->dev, "could not request irq\n");
+ goto out_unmap_regs;
+ }
+
+ snd_card_set_dev(card, &pdev->dev);
+
+ if (pdata->dws.dma_dev) {
+ struct dw_dma_slave *dws = &pdata->dws;
+ dma_cap_mask_t mask;
+
+ dws->tx_reg = regs->start + DAC_DATA;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ dac->dma.chan = dma_request_channel(mask, filter, dws);
+ }
+ if (!pdata->dws.dma_dev || !dac->dma.chan) {
+ dev_dbg(&pdev->dev, "DMA not available\n");
+ retval = -ENODEV;
+ goto out_unset_card_dev;
+ }
+
+ strcpy(card->driver, "Atmel ABDAC");
+ strcpy(card->shortname, "Atmel ABDAC");
+ sprintf(card->longname, "Atmel Audio Bitstream DAC");
+
+ retval = atmel_abdac_pcm_new(dac);
+ if (retval) {
+ dev_dbg(&pdev->dev, "could not register ABDAC pcm device\n");
+ goto out_release_dma;
+ }
+
+ retval = snd_card_register(card);
+ if (retval) {
+ dev_dbg(&pdev->dev, "could not register sound card\n");
+ goto out_release_dma;
+ }
+
+ platform_set_drvdata(pdev, card);
+
+ dev_info(&pdev->dev, "Atmel ABDAC at 0x%p using %s\n",
+ dac->regs, dac->dma.chan->dev->device.bus_id);
+
+ return retval;
+
+out_release_dma:
+ dma_release_channel(dac->dma.chan);
+ dac->dma.chan = NULL;
+out_unset_card_dev:
+ snd_card_set_dev(card, NULL);
+ free_irq(irq, dac);
+out_unmap_regs:
+ iounmap(dac->regs);
+out_free_card:
+ snd_card_free(card);
+out_put_sample_clk:
+ clk_put(sample_clk);
+ clk_disable(pclk);
+out_put_pclk:
+ clk_put(pclk);
+ return retval;
+}
+
+#ifdef CONFIG_PM
+static int atmel_abdac_suspend(struct platform_device *pdev, pm_message_t msg)
+{
+ struct snd_card *card = platform_get_drvdata(pdev);
+ struct atmel_abdac *dac = card->private_data;
+
+ dw_dma_cyclic_stop(dac->dma.chan);
+ clk_disable(dac->sample_clk);
+ clk_disable(dac->pclk);
+
+ return 0;
+}
+
+static int atmel_abdac_resume(struct platform_device *pdev)
+{
+ struct snd_card *card = platform_get_drvdata(pdev);
+ struct atmel_abdac *dac = card->private_data;
+
+ clk_enable(dac->pclk);
+ clk_enable(dac->sample_clk);
+ if (test_bit(DMA_READY, &dac->flags))
+ dw_dma_cyclic_start(dac->dma.chan);
+
+ return 0;
+}
+#else
+#define atmel_abdac_suspend NULL
+#define atmel_abdac_resume NULL
+#endif
+
+static int __devexit atmel_abdac_remove(struct platform_device *pdev)
+{
+ struct snd_card *card = platform_get_drvdata(pdev);
+ struct atmel_abdac *dac = get_dac(card);
+
+ clk_put(dac->sample_clk);
+ clk_disable(dac->pclk);
+ clk_put(dac->pclk);
+
+ dma_release_channel(dac->dma.chan);
+ dac->dma.chan = NULL;
+ snd_card_set_dev(card, NULL);
+ iounmap(dac->regs);
+ free_irq(dac->irq, dac);
+ snd_card_free(card);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver atmel_abdac_driver = {
+ .remove = __devexit_p(atmel_abdac_remove),
+ .driver = {
+ .name = "atmel_abdac",
+ },
+ .suspend = atmel_abdac_suspend,
+ .resume = atmel_abdac_resume,
+};
+
+static int __init atmel_abdac_init(void)
+{
+ return platform_driver_probe(&atmel_abdac_driver,
+ atmel_abdac_probe);
+}
+module_init(atmel_abdac_init);
+
+static void __exit atmel_abdac_exit(void)
+{
+ platform_driver_unregister(&atmel_abdac_driver);
+}
+module_exit(atmel_abdac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Driver for Atmel Audio Bitstream DAC (ABDAC)");
+MODULE_AUTHOR("Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>");
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
new file mode 100644
index 00000000000..dd72e00e5ae
--- /dev/null
+++ b/sound/atmel/ac97c.c
@@ -0,0 +1,932 @@
+/*
+ * Driver for the Atmel AC97C controller
+ *
+ * Copyright (C) 2005-2009 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/bitmap.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/ac97_codec.h>
+#include <sound/atmel-ac97c.h>
+#include <sound/memalloc.h>
+
+#include <linux/dw_dmac.h>
+
+#include "ac97c.h"
+
+enum {
+ DMA_TX_READY = 0,
+ DMA_RX_READY,
+ DMA_TX_CHAN_PRESENT,
+ DMA_RX_CHAN_PRESENT,
+};
+
+/* Serialize access to opened variable */
+static DEFINE_MUTEX(opened_mutex);
+
+struct atmel_ac97c_dma {
+ struct dma_chan *rx_chan;
+ struct dma_chan *tx_chan;
+};
+
+struct atmel_ac97c {
+ struct clk *pclk;
+ struct platform_device *pdev;
+ struct atmel_ac97c_dma dma;
+
+ struct snd_pcm_substream *playback_substream;
+ struct snd_pcm_substream *capture_substream;
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+ struct snd_ac97 *ac97;
+ struct snd_ac97_bus *ac97_bus;
+
+ u64 cur_format;
+ unsigned int cur_rate;
+ unsigned long flags;
+ /* Serialize access to opened variable */
+ spinlock_t lock;
+ void __iomem *regs;
+ int opened;
+ int reset_pin;
+};
+
+#define get_chip(card) ((struct atmel_ac97c *)(card)->private_data)
+
+#define ac97c_writel(chip, reg, val) \
+ __raw_writel((val), (chip)->regs + AC97C_##reg)
+#define ac97c_readl(chip, reg) \
+ __raw_readl((chip)->regs + AC97C_##reg)
+
+/* This function is called by the DMA driver. */
+static void atmel_ac97c_dma_playback_period_done(void *arg)
+{
+ struct atmel_ac97c *chip = arg;
+ snd_pcm_period_elapsed(chip->playback_substream);
+}
+
+static void atmel_ac97c_dma_capture_period_done(void *arg)
+{
+ struct atmel_ac97c *chip = arg;
+ snd_pcm_period_elapsed(chip->capture_substream);
+}
+
+static int atmel_ac97c_prepare_dma(struct atmel_ac97c *chip,
+ struct snd_pcm_substream *substream,
+ enum dma_data_direction direction)
+{
+ struct dma_chan *chan;
+ struct dw_cyclic_desc *cdesc;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned long buffer_len, period_len;
+
+ /*
+ * We don't do DMA on "complex" transfers, i.e. with
+ * non-halfword-aligned buffers or lengths.
+ */
+ if (runtime->dma_addr & 1 || runtime->buffer_size & 1) {
+ dev_dbg(&chip->pdev->dev, "too complex transfer\n");
+ return -EINVAL;
+ }
+
+ if (direction == DMA_TO_DEVICE)
+ chan = chip->dma.tx_chan;
+ else
+ chan = chip->dma.rx_chan;
+
+ buffer_len = frames_to_bytes(runtime, runtime->buffer_size);
+ period_len = frames_to_bytes(runtime, runtime->period_size);
+
+ cdesc = dw_dma_cyclic_prep(chan, runtime->dma_addr, buffer_len,
+ period_len, direction);
+ if (IS_ERR(cdesc)) {
+ dev_dbg(&chip->pdev->dev, "could not prepare cyclic DMA\n");
+ return PTR_ERR(cdesc);
+ }
+
+ if (direction == DMA_TO_DEVICE) {
+ cdesc->period_callback = atmel_ac97c_dma_playback_period_done;
+ set_bit(DMA_TX_READY, &chip->flags);
+ } else {
+ cdesc->period_callback = atmel_ac97c_dma_capture_period_done;
+ set_bit(DMA_RX_READY, &chip->flags);
+ }
+
+ cdesc->period_callback_param = chip;
+
+ return 0;
+}
+
+static struct snd_pcm_hardware atmel_ac97c_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP
+ | SNDRV_PCM_INFO_MMAP_VALID
+ | SNDRV_PCM_INFO_INTERLEAVED
+ | SNDRV_PCM_INFO_BLOCK_TRANSFER
+ | SNDRV_PCM_INFO_JOINT_DUPLEX
+ | SNDRV_PCM_INFO_RESUME
+ | SNDRV_PCM_INFO_PAUSE),
+ .formats = (SNDRV_PCM_FMTBIT_S16_BE
+ | SNDRV_PCM_FMTBIT_S16_LE),
+ .rates = (SNDRV_PCM_RATE_CONTINUOUS),
+ .rate_min = 4000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = 64 * 4096,
+ .period_bytes_min = 4096,
+ .period_bytes_max = 4096,
+ .periods_min = 4,
+ .periods_max = 64,
+};
+
+static int atmel_ac97c_playback_open(struct snd_pcm_substream *substream)
+{
+ struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ mutex_lock(&opened_mutex);
+ chip->opened++;
+ runtime->hw = atmel_ac97c_hw;
+ if (chip->cur_rate) {
+ runtime->hw.rate_min = chip->cur_rate;
+ runtime->hw.rate_max = chip->cur_rate;
+ }
+ if (chip->cur_format)
+ runtime->hw.formats = (1ULL << chip->cur_format);
+ mutex_unlock(&opened_mutex);
+ chip->playback_substream = substream;
+ return 0;
+}
+
+static int atmel_ac97c_capture_open(struct snd_pcm_substream *substream)
+{
+ struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ mutex_lock(&opened_mutex);
+ chip->opened++;
+ runtime->hw = atmel_ac97c_hw;
+ if (chip->cur_rate) {
+ runtime->hw.rate_min = chip->cur_rate;
+ runtime->hw.rate_max = chip->cur_rate;
+ }
+ if (chip->cur_format)
+ runtime->hw.formats = (1ULL << chip->cur_format);
+ mutex_unlock(&opened_mutex);
+ chip->capture_substream = substream;
+ return 0;
+}
+
+static int atmel_ac97c_playback_close(struct snd_pcm_substream *substream)
+{
+ struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+
+ mutex_lock(&opened_mutex);
+ chip->opened--;
+ if (!chip->opened) {
+ chip->cur_rate = 0;
+ chip->cur_format = 0;
+ }
+ mutex_unlock(&opened_mutex);
+
+ chip->playback_substream = NULL;
+
+ return 0;
+}
+
+static int atmel_ac97c_capture_close(struct snd_pcm_substream *substream)
+{
+ struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+
+ mutex_lock(&opened_mutex);
+ chip->opened--;
+ if (!chip->opened) {
+ chip->cur_rate = 0;
+ chip->cur_format = 0;
+ }
+ mutex_unlock(&opened_mutex);
+
+ chip->capture_substream = NULL;
+
+ return 0;
+}
+
+static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+ int retval;
+
+ retval = snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+ if (retval < 0)
+ return retval;
+ /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
+ if (retval == 1)
+ if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
+ dw_dma_cyclic_free(chip->dma.tx_chan);
+
+ /* Set restrictions to params. */
+ mutex_lock(&opened_mutex);
+ chip->cur_rate = params_rate(hw_params);
+ chip->cur_format = params_format(hw_params);
+ mutex_unlock(&opened_mutex);
+
+ return retval;
+}
+
+static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+ int retval;
+
+ retval = snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+ if (retval < 0)
+ return retval;
+ /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
+ if (retval == 1)
+ if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
+ dw_dma_cyclic_free(chip->dma.rx_chan);
+
+ /* Set restrictions to params. */
+ mutex_lock(&opened_mutex);
+ chip->cur_rate = params_rate(hw_params);
+ chip->cur_format = params_format(hw_params);
+ mutex_unlock(&opened_mutex);
+
+ return retval;
+}
+
+static int atmel_ac97c_playback_hw_free(struct snd_pcm_substream *substream)
+{
+ struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+ if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
+ dw_dma_cyclic_free(chip->dma.tx_chan);
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static int atmel_ac97c_capture_hw_free(struct snd_pcm_substream *substream)
+{
+ struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+ if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
+ dw_dma_cyclic_free(chip->dma.rx_chan);
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
+{
+ struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned long word = 0;
+ int retval;
+
+ /* assign channels to AC97C channel A */
+ switch (runtime->channels) {
+ case 1:
+ word |= AC97C_CH_ASSIGN(PCM_LEFT, A);
+ break;
+ case 2:
+ word |= AC97C_CH_ASSIGN(PCM_LEFT, A)
+ | AC97C_CH_ASSIGN(PCM_RIGHT, A);
+ break;
+ default:
+ /* TODO: support more than two channels */
+ return -EINVAL;
+ break;
+ }
+ ac97c_writel(chip, OCA, word);
+
+ /* configure sample format and size */
+ word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
+
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ word |= AC97C_CMR_CEM_LITTLE;
+ break;
+ case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
+ default:
+ word &= ~(AC97C_CMR_CEM_LITTLE);
+ break;
+ }
+
+ ac97c_writel(chip, CAMR, word);
+
+ /* set variable rate if needed */
+ if (runtime->rate != 48000) {
+ word = ac97c_readl(chip, MR);
+ word |= AC97C_MR_VRA;
+ ac97c_writel(chip, MR, word);
+ } else {
+ word = ac97c_readl(chip, MR);
+ word &= ~(AC97C_MR_VRA);
+ ac97c_writel(chip, MR, word);
+ }
+
+ retval = snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE,
+ runtime->rate);
+ if (retval)
+ dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n",
+ runtime->rate);
+
+ if (!test_bit(DMA_TX_READY, &chip->flags))
+ retval = atmel_ac97c_prepare_dma(chip, substream,
+ DMA_TO_DEVICE);
+
+ return retval;
+}
+
+static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned long word = 0;
+ int retval;
+
+ /* assign channels to AC97C channel A */
+ switch (runtime->channels) {
+ case 1:
+ word |= AC97C_CH_ASSIGN(PCM_LEFT, A);
+ break;
+ case 2:
+ word |= AC97C_CH_ASSIGN(PCM_LEFT, A)
+ | AC97C_CH_ASSIGN(PCM_RIGHT, A);
+ break;
+ default:
+ /* TODO: support more than two channels */
+ return -EINVAL;
+ break;
+ }
+ ac97c_writel(chip, ICA, word);
+
+ /* configure sample format and size */
+ word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
+
+ switch (runtime->format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ word |= AC97C_CMR_CEM_LITTLE;
+ break;
+ case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
+ default:
+ word &= ~(AC97C_CMR_CEM_LITTLE);
+ break;
+ }
+
+ ac97c_writel(chip, CAMR, word);
+
+ /* set variable rate if needed */
+ if (runtime->rate != 48000) {
+ word = ac97c_readl(chip, MR);
+ word |= AC97C_MR_VRA;
+ ac97c_writel(chip, MR, word);
+ } else {
+ word = ac97c_readl(chip, MR);
+ word &= ~(AC97C_MR_VRA);
+ ac97c_writel(chip, MR, word);
+ }
+
+ retval = snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE,
+ runtime->rate);
+ if (retval)
+ dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n",
+ runtime->rate);
+
+ if (!test_bit(DMA_RX_READY, &chip->flags))
+ retval = atmel_ac97c_prepare_dma(chip, substream,
+ DMA_FROM_DEVICE);
+
+ return retval;
+}
+
+static int
+atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+ unsigned long camr;
+ int retval = 0;
+
+ camr = ac97c_readl(chip, CAMR);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
+ case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
+ case SNDRV_PCM_TRIGGER_START:
+ retval = dw_dma_cyclic_start(chip->dma.tx_chan);
+ if (retval)
+ goto out;
+ camr |= AC97C_CMR_CENA;
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
+ case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
+ case SNDRV_PCM_TRIGGER_STOP:
+ dw_dma_cyclic_stop(chip->dma.tx_chan);
+ if (chip->opened <= 1)
+ camr &= ~AC97C_CMR_CENA;
+ break;
+ default:
+ retval = -EINVAL;
+ goto out;
+ }
+
+ ac97c_writel(chip, CAMR, camr);
+out:
+ return retval;
+}
+
+static int
+atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+ unsigned long camr;
+ int retval = 0;
+
+ camr = ac97c_readl(chip, CAMR);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
+ case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
+ case SNDRV_PCM_TRIGGER_START:
+ retval = dw_dma_cyclic_start(chip->dma.rx_chan);
+ if (retval)
+ goto out;
+ camr |= AC97C_CMR_CENA;
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
+ case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
+ case SNDRV_PCM_TRIGGER_STOP:
+ dw_dma_cyclic_stop(chip->dma.rx_chan);
+ if (chip->opened <= 1)
+ camr &= ~AC97C_CMR_CENA;
+ break;
+ default:
+ retval = -EINVAL;
+ break;
+ }
+
+ ac97c_writel(chip, CAMR, camr);
+out:
+ return retval;
+}
+
+static snd_pcm_uframes_t
+atmel_ac97c_playback_pointer(struct snd_pcm_substream *substream)
+{
+ struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ snd_pcm_uframes_t frames;
+ unsigned long bytes;
+
+ bytes = dw_dma_get_src_addr(chip->dma.tx_chan);
+ bytes -= runtime->dma_addr;
+
+ frames = bytes_to_frames(runtime, bytes);
+ if (frames >= runtime->buffer_size)
+ frames -= runtime->buffer_size;
+ return frames;
+}
+
+static snd_pcm_uframes_t
+atmel_ac97c_capture_pointer(struct snd_pcm_substream *substream)
+{
+ struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ snd_pcm_uframes_t frames;
+ unsigned long bytes;
+
+ bytes = dw_dma_get_dst_addr(chip->dma.rx_chan);
+ bytes -= runtime->dma_addr;
+
+ frames = bytes_to_frames(runtime, bytes);
+ if (frames >= runtime->buffer_size)
+ frames -= runtime->buffer_size;
+ return frames;
+}
+
+static struct snd_pcm_ops atmel_ac97_playback_ops = {
+ .open = atmel_ac97c_playback_open,
+ .close = atmel_ac97c_playback_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = atmel_ac97c_playback_hw_params,
+ .hw_free = atmel_ac97c_playback_hw_free,
+ .prepare = atmel_ac97c_playback_prepare,
+ .trigger = atmel_ac97c_playback_trigger,
+ .pointer = atmel_ac97c_playback_pointer,
+};
+
+static struct snd_pcm_ops atmel_ac97_capture_ops = {
+ .open = atmel_ac97c_capture_open,
+ .close = atmel_ac97c_capture_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = atmel_ac97c_capture_hw_params,
+ .hw_free = atmel_ac97c_capture_hw_free,
+ .prepare = atmel_ac97c_capture_prepare,
+ .trigger = atmel_ac97c_capture_trigger,
+ .pointer = atmel_ac97c_capture_pointer,
+};
+
+static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip)
+{
+ struct snd_pcm *pcm;
+ struct snd_pcm_hardware hw = atmel_ac97c_hw;
+ int capture, playback, retval;
+
+ capture = test_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
+ playback = test_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
+
+ retval = snd_pcm_new(chip->card, chip->card->shortname,
+ chip->pdev->id, playback, capture, &pcm);
+ if (retval)
+ return retval;
+
+ if (capture)
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &atmel_ac97_capture_ops);
+ if (playback)
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &atmel_ac97_playback_ops);
+
+ retval = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ &chip->pdev->dev, hw.periods_min * hw.period_bytes_min,
+ hw.buffer_bytes_max);
+ if (retval)
+ return retval;
+
+ pcm->private_data = chip;
+ pcm->info_flags = 0;
+ strcpy(pcm->name, chip->card->shortname);
+ chip->pcm = pcm;
+
+ return 0;
+}
+
+static int atmel_ac97c_mixer_new(struct atmel_ac97c *chip)
+{
+ struct snd_ac97_template template;
+ memset(&template, 0, sizeof(template));
+ template.private_data = chip;
+ return snd_ac97_mixer(chip->ac97_bus, &template, &chip->ac97);
+}
+
+static void atmel_ac97c_write(struct snd_ac97 *ac97, unsigned short reg,
+ unsigned short val)
+{
+ struct atmel_ac97c *chip = get_chip(ac97);
+ unsigned long word;
+ int timeout = 40;
+
+ word = (reg & 0x7f) << 16 | val;
+
+ do {
+ if (ac97c_readl(chip, COSR) & AC97C_CSR_TXRDY) {
+ ac97c_writel(chip, COTHR, word);
+ return;
+ }
+ udelay(1);
+ } while (--timeout);
+
+ dev_dbg(&chip->pdev->dev, "codec write timeout\n");
+}
+
+static unsigned short atmel_ac97c_read(struct snd_ac97 *ac97,
+ unsigned short reg)
+{
+ struct atmel_ac97c *chip = get_chip(ac97);
+ unsigned long word;
+ int timeout = 40;
+ int write = 10;
+
+ word = (0x80 | (reg & 0x7f)) << 16;
+
+ if ((ac97c_readl(chip, COSR) & AC97C_CSR_RXRDY) != 0)
+ ac97c_readl(chip, CORHR);
+
+retry_write:
+ timeout = 40;
+
+ do {
+ if ((ac97c_readl(chip, COSR) & AC97C_CSR_TXRDY) != 0) {
+ ac97c_writel(chip, COTHR, word);
+ goto read_reg;
+ }
+ udelay(10);
+ } while (--timeout);
+
+ if (!--write)
+ goto timed_out;
+ goto retry_write;
+
+read_reg:
+ do {
+ if ((ac97c_readl(chip, COSR) & AC97C_CSR_RXRDY) != 0) {
+ unsigned short val = ac97c_readl(chip, CORHR);
+ return val;
+ }
+ udelay(10);
+ } while (--timeout);
+
+ if (!--write)
+ goto timed_out;
+ goto retry_write;
+
+timed_out:
+ dev_dbg(&chip->pdev->dev, "codec read timeout\n");
+ return 0xffff;
+}
+
+static bool filter(struct dma_chan *chan, void *slave)
+{
+ struct dw_dma_slave *dws = slave;
+
+ if (dws->dma_dev == chan->device->dev) {
+ chan->private = dws;
+ return true;
+ } else
+ return false;
+}
+
+static void atmel_ac97c_reset(struct atmel_ac97c *chip)
+{
+ ac97c_writel(chip, MR, AC97C_MR_WRST);
+
+ if (gpio_is_valid(chip->reset_pin)) {
+ gpio_set_value(chip->reset_pin, 0);
+ /* AC97 v2.2 specifications says minimum 1 us. */
+ udelay(10);
+ gpio_set_value(chip->reset_pin, 1);
+ }
+
+ udelay(1);
+ ac97c_writel(chip, MR, AC97C_MR_ENA);
+}
+
+static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
+{
+ struct snd_card *card;
+ struct atmel_ac97c *chip;
+ struct resource *regs;
+ struct ac97c_platform_data *pdata;
+ struct clk *pclk;
+ static struct snd_ac97_bus_ops ops = {
+ .write = atmel_ac97c_write,
+ .read = atmel_ac97c_read,
+ };
+ int retval;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs) {
+ dev_dbg(&pdev->dev, "no memory resource\n");
+ return -ENXIO;
+ }
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_dbg(&pdev->dev, "no platform data\n");
+ return -ENXIO;
+ }
+
+ pclk = clk_get(&pdev->dev, "pclk");
+ if (IS_ERR(pclk)) {
+ dev_dbg(&pdev->dev, "no peripheral clock\n");
+ return PTR_ERR(pclk);
+ }
+ clk_enable(pclk);
+
+ retval = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, sizeof(struct atmel_ac97c), &card);
+ if (retval) {
+ dev_dbg(&pdev->dev, "could not create sound card device\n");
+ goto err_snd_card_new;
+ }
+
+ chip = get_chip(card);
+
+ spin_lock_init(&chip->lock);
+
+ strcpy(card->driver, "Atmel AC97C");
+ strcpy(card->shortname, "Atmel AC97C");
+ sprintf(card->longname, "Atmel AC97 controller");
+
+ chip->card = card;
+ chip->pclk = pclk;
+ chip->pdev = pdev;
+ chip->regs = ioremap(regs->start, regs->end - regs->start + 1);
+
+ if (!chip->regs) {
+ dev_dbg(&pdev->dev, "could not remap register memory\n");
+ goto err_ioremap;
+ }
+
+ if (gpio_is_valid(pdata->reset_pin)) {
+ if (gpio_request(pdata->reset_pin, "reset_pin")) {
+ dev_dbg(&pdev->dev, "reset pin not available\n");
+ chip->reset_pin = -ENODEV;
+ } else {
+ gpio_direction_output(pdata->reset_pin, 1);
+ chip->reset_pin = pdata->reset_pin;
+ }
+ }
+
+ snd_card_set_dev(card, &pdev->dev);
+
+ retval = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus);
+ if (retval) {
+ dev_dbg(&pdev->dev, "could not register on ac97 bus\n");
+ goto err_ac97_bus;
+ }
+
+ atmel_ac97c_reset(chip);
+
+ retval = atmel_ac97c_mixer_new(chip);
+ if (retval) {
+ dev_dbg(&pdev->dev, "could not register ac97 mixer\n");
+ goto err_ac97_bus;
+ }
+
+ if (pdata->rx_dws.dma_dev) {
+ struct dw_dma_slave *dws = &pdata->rx_dws;
+ dma_cap_mask_t mask;
+
+ dws->rx_reg = regs->start + AC97C_CARHR + 2;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ chip->dma.rx_chan = dma_request_channel(mask, filter, dws);
+
+ dev_info(&chip->pdev->dev, "using %s for DMA RX\n",
+ chip->dma.rx_chan->dev->device.bus_id);
+ set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
+ }
+
+ if (pdata->tx_dws.dma_dev) {
+ struct dw_dma_slave *dws = &pdata->tx_dws;
+ dma_cap_mask_t mask;
+
+ dws->tx_reg = regs->start + AC97C_CATHR + 2;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ chip->dma.tx_chan = dma_request_channel(mask, filter, dws);
+
+ dev_info(&chip->pdev->dev, "using %s for DMA TX\n",
+ chip->dma.tx_chan->dev->device.bus_id);
+ set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
+ }
+
+ if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) &&
+ !test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) {
+ dev_dbg(&pdev->dev, "DMA not available\n");
+ retval = -ENODEV;
+ goto err_dma;
+ }
+
+ retval = atmel_ac97c_pcm_new(chip);
+ if (retval) {
+ dev_dbg(&pdev->dev, "could not register ac97 pcm device\n");
+ goto err_dma;
+ }
+
+ retval = snd_card_register(card);
+ if (retval) {
+ dev_dbg(&pdev->dev, "could not register sound card\n");
+ goto err_ac97_bus;
+ }
+
+ platform_set_drvdata(pdev, card);
+
+ dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p\n",
+ chip->regs);
+
+ return 0;
+
+err_dma:
+ if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
+ dma_release_channel(chip->dma.rx_chan);
+ if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
+ dma_release_channel(chip->dma.tx_chan);
+ clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
+ clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
+ chip->dma.rx_chan = NULL;
+ chip->dma.tx_chan = NULL;
+err_ac97_bus:
+ snd_card_set_dev(card, NULL);
+
+ if (gpio_is_valid(chip->reset_pin))
+ gpio_free(chip->reset_pin);
+
+ iounmap(chip->regs);
+err_ioremap:
+ snd_card_free(card);
+err_snd_card_new:
+ clk_disable(pclk);
+ clk_put(pclk);
+ return retval;
+}
+
+#ifdef CONFIG_PM
+static int atmel_ac97c_suspend(struct platform_device *pdev, pm_message_t msg)
+{
+ struct snd_card *card = platform_get_drvdata(pdev);
+ struct atmel_ac97c *chip = card->private_data;
+
+ if (test_bit(DMA_RX_READY, &chip->flags))
+ dw_dma_cyclic_stop(chip->dma.rx_chan);
+ if (test_bit(DMA_TX_READY, &chip->flags))
+ dw_dma_cyclic_stop(chip->dma.tx_chan);
+ clk_disable(chip->pclk);
+
+ return 0;
+}
+
+static int atmel_ac97c_resume(struct platform_device *pdev)
+{
+ struct snd_card *card = platform_get_drvdata(pdev);
+ struct atmel_ac97c *chip = card->private_data;
+
+ clk_enable(chip->pclk);
+ if (test_bit(DMA_RX_READY, &chip->flags))
+ dw_dma_cyclic_start(chip->dma.rx_chan);
+ if (test_bit(DMA_TX_READY, &chip->flags))
+ dw_dma_cyclic_start(chip->dma.tx_chan);
+
+ return 0;
+}
+#else
+#define atmel_ac97c_suspend NULL
+#define atmel_ac97c_resume NULL
+#endif
+
+static int __devexit atmel_ac97c_remove(struct platform_device *pdev)
+{
+ struct snd_card *card = platform_get_drvdata(pdev);
+ struct atmel_ac97c *chip = get_chip(card);
+
+ if (gpio_is_valid(chip->reset_pin))
+ gpio_free(chip->reset_pin);
+
+ clk_disable(chip->pclk);
+ clk_put(chip->pclk);
+ iounmap(chip->regs);
+
+ if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
+ dma_release_channel(chip->dma.rx_chan);
+ if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
+ dma_release_channel(chip->dma.tx_chan);
+ clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
+ clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
+ chip->dma.rx_chan = NULL;
+ chip->dma.tx_chan = NULL;
+
+ snd_card_set_dev(card, NULL);
+ snd_card_free(card);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver atmel_ac97c_driver = {
+ .remove = __devexit_p(atmel_ac97c_remove),
+ .driver = {
+ .name = "atmel_ac97c",
+ },
+ .suspend = atmel_ac97c_suspend,
+ .resume = atmel_ac97c_resume,
+};
+
+static int __init atmel_ac97c_init(void)
+{
+ return platform_driver_probe(&atmel_ac97c_driver,
+ atmel_ac97c_probe);
+}
+module_init(atmel_ac97c_init);
+
+static void __exit atmel_ac97c_exit(void)
+{
+ platform_driver_unregister(&atmel_ac97c_driver);
+}
+module_exit(atmel_ac97c_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Driver for Atmel AC97 controller");
+MODULE_AUTHOR("Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>");
diff --git a/sound/atmel/ac97c.h b/sound/atmel/ac97c.h
new file mode 100644
index 00000000000..c17bd582598
--- /dev/null
+++ b/sound/atmel/ac97c.h
@@ -0,0 +1,71 @@
+/*
+ * Register definitions for the Atmel AC97C controller
+ *
+ * Copyright (C) 2005-2009 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+#ifndef __SOUND_ATMEL_AC97C_H
+#define __SOUND_ATMEL_AC97C_H
+
+#define AC97C_MR 0x08
+#define AC97C_ICA 0x10
+#define AC97C_OCA 0x14
+#define AC97C_CARHR 0x20
+#define AC97C_CATHR 0x24
+#define AC97C_CASR 0x28
+#define AC97C_CAMR 0x2c
+#define AC97C_CBRHR 0x30
+#define AC97C_CBTHR 0x34
+#define AC97C_CBSR 0x38
+#define AC97C_CBMR 0x3c
+#define AC97C_CORHR 0x40
+#define AC97C_COTHR 0x44
+#define AC97C_COSR 0x48
+#define AC97C_COMR 0x4c
+#define AC97C_SR 0x50
+#define AC97C_IER 0x54
+#define AC97C_IDR 0x58
+#define AC97C_IMR 0x5c
+#define AC97C_VERSION 0xfc
+
+#define AC97C_CATPR PDC_TPR
+#define AC97C_CATCR PDC_TCR
+#define AC97C_CATNPR PDC_TNPR
+#define AC97C_CATNCR PDC_TNCR
+#define AC97C_CARPR PDC_RPR
+#define AC97C_CARCR PDC_RCR
+#define AC97C_CARNPR PDC_RNPR
+#define AC97C_CARNCR PDC_RNCR
+#define AC97C_PTCR PDC_PTCR
+
+#define AC97C_MR_ENA (1 << 0)
+#define AC97C_MR_WRST (1 << 1)
+#define AC97C_MR_VRA (1 << 2)
+
+#define AC97C_CSR_TXRDY (1 << 0)
+#define AC97C_CSR_UNRUN (1 << 2)
+#define AC97C_CSR_RXRDY (1 << 4)
+#define AC97C_CSR_ENDTX (1 << 10)
+#define AC97C_CSR_ENDRX (1 << 14)
+
+#define AC97C_CMR_SIZE_20 (0 << 16)
+#define AC97C_CMR_SIZE_18 (1 << 16)
+#define AC97C_CMR_SIZE_16 (2 << 16)
+#define AC97C_CMR_SIZE_10 (3 << 16)
+#define AC97C_CMR_CEM_LITTLE (1 << 18)
+#define AC97C_CMR_CEM_BIG (0 << 18)
+#define AC97C_CMR_CENA (1 << 21)
+#define AC97C_CMR_DMAEN (1 << 22)
+
+#define AC97C_SR_CAEVT (1 << 3)
+
+#define AC97C_CH_ASSIGN(slot, channel) \
+ (AC97C_CHANNEL_##channel << (3 * (AC97_SLOT_##slot - 3)))
+#define AC97C_CHANNEL_NONE 0x0
+#define AC97C_CHANNEL_A 0x1
+#define AC97C_CHANNEL_B 0x2
+
+#endif /* __SOUND_ATMEL_AC97C_H */
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 195cafc5a55..a70ee7f1ed9 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -99,9 +99,6 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
if (hw == NULL)
return -ENODEV;
- if (!hw->ops.open)
- return -ENXIO;
-
if (!try_module_get(hw->card->module))
return -EFAULT;
@@ -113,6 +110,10 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
err = -EBUSY;
break;
}
+ if (!hw->ops.open) {
+ err = 0;
+ break;
+ }
err = hw->ops.open(hw, file);
if (err >= 0)
break;
@@ -151,7 +152,7 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
static int snd_hwdep_release(struct inode *inode, struct file * file)
{
- int err = -ENXIO;
+ int err = 0;
struct snd_hwdep *hw = file->private_data;
struct module *mod = hw->card->module;
diff --git a/sound/core/init.c b/sound/core/init.c
index 0d5520c415d..fd56afe846e 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -121,31 +121,44 @@ static inline int init_info_for_card(struct snd_card *card)
#endif
/**
- * snd_card_new - create and initialize a soundcard structure
+ * snd_card_create - create and initialize a soundcard structure
* @idx: card index (address) [0 ... (SNDRV_CARDS-1)]
* @xid: card identification (ASCII string)
* @module: top level module for locking
* @extra_size: allocate this extra size after the main soundcard structure
+ * @card_ret: the pointer to store the created card instance
*
* Creates and initializes a soundcard structure.
*
- * Returns kmallocated snd_card structure. Creates the ALSA control interface
- * (which is blocked until snd_card_register function is called).
+ * The function allocates snd_card instance via kzalloc with the given
+ * space for the driver to use freely. The allocated struct is stored
+ * in the given card_ret pointer.
+ *
+ * Returns zero if successful or a negative error code.
*/
-struct snd_card *snd_card_new(int idx, const char *xid,
- struct module *module, int extra_size)
+int snd_card_create(int idx, const char *xid,
+ struct module *module, int extra_size,
+ struct snd_card **card_ret)
{
struct snd_card *card;
int err, idx2;
+ if (snd_BUG_ON(!card_ret))
+ return -EINVAL;
+ *card_ret = NULL;
+
if (extra_size < 0)
extra_size = 0;
card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL);
- if (card == NULL)
- return NULL;
+ if (!card)
+ return -ENOMEM;
if (xid) {
- if (!snd_info_check_reserved_words(xid))
+ if (!snd_info_check_reserved_words(xid)) {
+ snd_printk(KERN_ERR
+ "given id string '%s' is reserved.\n", xid);
+ err = -EBUSY;
goto __error;
+ }
strlcpy(card->id, xid, sizeof(card->id));
}
err = 0;
@@ -195,6 +208,7 @@ struct snd_card *snd_card_new(int idx, const char *xid,
INIT_LIST_HEAD(&card->controls);
INIT_LIST_HEAD(&card->ctl_files);
spin_lock_init(&card->files_lock);
+ INIT_LIST_HEAD(&card->files_list);
init_waitqueue_head(&card->shutdown_sleep);
#ifdef CONFIG_PM
mutex_init(&card->power_lock);
@@ -202,26 +216,28 @@ struct snd_card *snd_card_new(int idx, const char *xid,
#endif
/* the control interface cannot be accessed from the user space until */
/* snd_cards_bitmask and snd_cards are set with snd_card_register */
- if ((err = snd_ctl_create(card)) < 0) {
- snd_printd("unable to register control minors\n");
+ err = snd_ctl_create(card);
+ if (err < 0) {
+ snd_printk(KERN_ERR "unable to register control minors\n");
goto __error;
}
- if ((err = snd_info_card_create(card)) < 0) {
- snd_printd("unable to create card info\n");
+ err = snd_info_card_create(card);
+ if (err < 0) {
+ snd_printk(KERN_ERR "unable to create card info\n");
goto __error_ctl;
}
if (extra_size > 0)
card->private_data = (char *)card + sizeof(struct snd_card);
- return card;
+ *card_ret = card;
+ return 0;
__error_ctl:
snd_device_free_all(card, SNDRV_DEV_CMD_PRE);
__error:
kfree(card);
- return NULL;
+ return err;
}
-
-EXPORT_SYMBOL(snd_card_new);
+EXPORT_SYMBOL(snd_card_create);
/* return non-zero if a card is already locked */
int snd_card_locked(int card)
@@ -259,6 +275,7 @@ static int snd_disconnect_release(struct inode *inode, struct file *file)
list_for_each_entry(_df, &shutdown_files, shutdown_list) {
if (_df->file == file) {
df = _df;
+ list_del_init(&df->shutdown_list);
break;
}
}
@@ -347,8 +364,7 @@ int snd_card_disconnect(struct snd_card *card)
/* phase 2: replace file->f_op with special dummy operations */
spin_lock(&card->files_lock);
- mfile = card->files;
- while (mfile) {
+ list_for_each_entry(mfile, &card->files_list, list) {
file = mfile->file;
/* it's critical part, use endless loop */
@@ -361,8 +377,6 @@ int snd_card_disconnect(struct snd_card *card)
mfile->file->f_op = &snd_shutdown_f_ops;
fops_get(mfile->file->f_op);
-
- mfile = mfile->next;
}
spin_unlock(&card->files_lock);
@@ -442,7 +456,7 @@ int snd_card_free_when_closed(struct snd_card *card)
return ret;
spin_lock(&card->files_lock);
- if (card->files == NULL)
+ if (list_empty(&card->files_list))
free_now = 1;
else
card->free_on_last_close = 1;
@@ -462,7 +476,7 @@ int snd_card_free(struct snd_card *card)
return ret;
/* wait, until all devices are ready for the free operation */
- wait_event(card->shutdown_sleep, card->files == NULL);
+ wait_event(card->shutdown_sleep, list_empty(&card->files_list));
snd_card_do_free(card);
return 0;
}
@@ -809,15 +823,13 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
return -ENOMEM;
mfile->file = file;
mfile->disconnected_f_op = NULL;
- mfile->next = NULL;
spin_lock(&card->files_lock);
if (card->shutdown) {
spin_unlock(&card->files_lock);
kfree(mfile);
return -ENODEV;
}
- mfile->next = card->files;
- card->files = mfile;
+ list_add(&mfile->list, &card->files_list);
spin_unlock(&card->files_lock);
return 0;
}
@@ -839,29 +851,20 @@ EXPORT_SYMBOL(snd_card_file_add);
*/
int snd_card_file_remove(struct snd_card *card, struct file *file)
{
- struct snd_monitor_file *mfile, *pfile = NULL;
+ struct snd_monitor_file *mfile, *found = NULL;
int last_close = 0;
spin_lock(&card->files_lock);
- mfile = card->files;
- while (mfile) {
+ list_for_each_entry(mfile, &card->files_list, list) {
if (mfile->file == file) {
- if (pfile)
- pfile->next = mfile->next;
- else
- card->files = mfile->next;
+ list_del(&mfile->list);
+ if (mfile->disconnected_f_op)
+ fops_put(mfile->disconnected_f_op);
+ found = mfile;
break;
}
- pfile = mfile;
- mfile = mfile->next;
- }
- if (mfile && mfile->disconnected_f_op) {
- fops_put(mfile->disconnected_f_op);
- spin_lock(&shutdown_lock);
- list_del(&mfile->shutdown_list);
- spin_unlock(&shutdown_lock);
}
- if (card->files == NULL)
+ if (list_empty(&card->files_list))
last_close = 1;
spin_unlock(&card->files_lock);
if (last_close) {
@@ -869,11 +872,11 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
if (card->free_on_last_close)
snd_card_do_free(card);
}
- if (!mfile) {
+ if (!found) {
snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
return -ENOENT;
}
- kfree(mfile);
+ kfree(found);
return 0;
}
diff --git a/sound/core/jack.c b/sound/core/jack.c
index dd4a12dc09a..c8254c667c6 100644
--- a/sound/core/jack.c
+++ b/sound/core/jack.c
@@ -23,6 +23,14 @@
#include <sound/jack.h>
#include <sound/core.h>
+static int jack_types[] = {
+ SW_HEADPHONE_INSERT,
+ SW_MICROPHONE_INSERT,
+ SW_LINEOUT_INSERT,
+ SW_JACK_PHYSICAL_INSERT,
+ SW_VIDEOOUT_INSERT,
+};
+
static int snd_jack_dev_free(struct snd_device *device)
{
struct snd_jack *jack = device->device_data;
@@ -47,7 +55,7 @@ static int snd_jack_dev_register(struct snd_device *device)
int err;
snprintf(jack->name, sizeof(jack->name), "%s %s",
- card->longname, jack->id);
+ card->shortname, jack->id);
jack->input_dev->name = jack->name;
/* Default to the sound card device. */
@@ -79,6 +87,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
{
struct snd_jack *jack;
int err;
+ int i;
static struct snd_device_ops ops = {
.dev_free = snd_jack_dev_free,
.dev_register = snd_jack_dev_register,
@@ -100,18 +109,10 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
jack->type = type;
- if (type & SND_JACK_HEADPHONE)
- input_set_capability(jack->input_dev, EV_SW,
- SW_HEADPHONE_INSERT);
- if (type & SND_JACK_LINEOUT)
- input_set_capability(jack->input_dev, EV_SW,
- SW_LINEOUT_INSERT);
- if (type & SND_JACK_MICROPHONE)
- input_set_capability(jack->input_dev, EV_SW,
- SW_MICROPHONE_INSERT);
- if (type & SND_JACK_MECHANICAL)
- input_set_capability(jack->input_dev, EV_SW,
- SW_JACK_PHYSICAL_INSERT);
+ for (i = 0; i < ARRAY_SIZE(jack_types); i++)
+ if (type & (1 << i))
+ input_set_capability(jack->input_dev, EV_SW,
+ jack_types[i]);
err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops);
if (err < 0)
@@ -154,21 +155,17 @@ EXPORT_SYMBOL(snd_jack_set_parent);
*/
void snd_jack_report(struct snd_jack *jack, int status)
{
+ int i;
+
if (!jack)
return;
- if (jack->type & SND_JACK_HEADPHONE)
- input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT,
- status & SND_JACK_HEADPHONE);
- if (jack->type & SND_JACK_LINEOUT)
- input_report_switch(jack->input_dev, SW_LINEOUT_INSERT,
- status & SND_JACK_LINEOUT);
- if (jack->type & SND_JACK_MICROPHONE)
- input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT,
- status & SND_JACK_MICROPHONE);
- if (jack->type & SND_JACK_MECHANICAL)
- input_report_switch(jack->input_dev, SW_JACK_PHYSICAL_INSERT,
- status & SND_JACK_MECHANICAL);
+ for (i = 0; i < ARRAY_SIZE(jack_types); i++) {
+ int testbit = 1 << i;
+ if (jack->type & testbit)
+ input_report_switch(jack->input_dev, jack_types[i],
+ status & testbit);
+ }
input_sync(jack->input_dev);
}
diff --git a/sound/core/misc.c b/sound/core/misc.c
index 38524f615d9..a9710e0c97a 100644
--- a/sound/core/misc.c
+++ b/sound/core/misc.c
@@ -95,12 +95,14 @@ snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list)
{
const struct snd_pci_quirk *q;
- for (q = list; q->subvendor; q++)
- if (q->subvendor == pci->subsystem_vendor &&
- (!q->subdevice || q->subdevice == pci->subsystem_device))
+ for (q = list; q->subvendor; q++) {
+ if (q->subvendor != pci->subsystem_vendor)
+ continue;
+ if (!q->subdevice ||
+ (pci->subsystem_device & q->subdevice_mask) == q->subdevice)
return q;
+ }
return NULL;
}
-
EXPORT_SYMBOL(snd_pci_quirk_lookup);
#endif
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 4690b8b5681..e570649184e 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -692,6 +692,9 @@ static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME)
snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right);
+ } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME) {
+ snd_mixer_oss_put_volume1_vol(fmixer, pslot,
+ slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right);
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) {
snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right);
} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) {
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index e17836680f4..2864cefb773 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -1160,9 +1160,11 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const
runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
- printk("pcm_oss: write: recovering from XRUN\n");
+ printk(KERN_DEBUG "pcm_oss: write: "
+ "recovering from XRUN\n");
else
- printk("pcm_oss: write: recovering from SUSPEND\n");
+ printk(KERN_DEBUG "pcm_oss: write: "
+ "recovering from SUSPEND\n");
#endif
ret = snd_pcm_oss_prepare(substream);
if (ret < 0)
@@ -1196,9 +1198,11 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p
runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
- printk("pcm_oss: read: recovering from XRUN\n");
+ printk(KERN_DEBUG "pcm_oss: read: "
+ "recovering from XRUN\n");
else
- printk("pcm_oss: read: recovering from SUSPEND\n");
+ printk(KERN_DEBUG "pcm_oss: read: "
+ "recovering from SUSPEND\n");
#endif
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
if (ret < 0)
@@ -1242,9 +1246,11 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void
runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
- printk("pcm_oss: writev: recovering from XRUN\n");
+ printk(KERN_DEBUG "pcm_oss: writev: "
+ "recovering from XRUN\n");
else
- printk("pcm_oss: writev: recovering from SUSPEND\n");
+ printk(KERN_DEBUG "pcm_oss: writev: "
+ "recovering from SUSPEND\n");
#endif
ret = snd_pcm_oss_prepare(substream);
if (ret < 0)
@@ -1278,9 +1284,11 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void *
runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
#ifdef OSS_DEBUG
if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
- printk("pcm_oss: readv: recovering from XRUN\n");
+ printk(KERN_DEBUG "pcm_oss: readv: "
+ "recovering from XRUN\n");
else
- printk("pcm_oss: readv: recovering from SUSPEND\n");
+ printk(KERN_DEBUG "pcm_oss: readv: "
+ "recovering from SUSPEND\n");
#endif
ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
if (ret < 0)
@@ -1533,7 +1541,7 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)
init_waitqueue_entry(&wait, current);
add_wait_queue(&runtime->sleep, &wait);
#ifdef OSS_DEBUG
- printk("sync1: size = %li\n", size);
+ printk(KERN_DEBUG "sync1: size = %li\n", size);
#endif
while (1) {
result = snd_pcm_oss_write2(substream, runtime->oss.buffer, size, 1);
@@ -1590,7 +1598,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
mutex_lock(&runtime->oss.params_lock);
if (runtime->oss.buffer_used > 0) {
#ifdef OSS_DEBUG
- printk("sync: buffer_used\n");
+ printk(KERN_DEBUG "sync: buffer_used\n");
#endif
size = (8 * (runtime->oss.period_bytes - runtime->oss.buffer_used) + 7) / width;
snd_pcm_format_set_silence(format,
@@ -1603,7 +1611,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
}
} else if (runtime->oss.period_ptr > 0) {
#ifdef OSS_DEBUG
- printk("sync: period_ptr\n");
+ printk(KERN_DEBUG "sync: period_ptr\n");
#endif
size = runtime->oss.period_bytes - runtime->oss.period_ptr;
snd_pcm_format_set_silence(format,
@@ -1767,7 +1775,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
AFMT_S8 | AFMT_U16_LE |
AFMT_U16_BE |
AFMT_S32_LE | AFMT_S32_BE |
- AFMT_S24_LE | AFMT_S24_LE |
+ AFMT_S24_LE | AFMT_S24_BE |
AFMT_S24_PACKED;
params = kmalloc(sizeof(*params), GFP_KERNEL);
if (!params)
@@ -1952,7 +1960,7 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
int err, cmd;
#ifdef OSS_DEBUG
- printk("pcm_oss: trigger = 0x%x\n", trigger);
+ printk(KERN_DEBUG "pcm_oss: trigger = 0x%x\n", trigger);
#endif
psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
@@ -2170,7 +2178,9 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stre
}
#ifdef OSS_DEBUG
- printk("pcm_oss: space: bytes = %i, fragments = %i, fragstotal = %i, fragsize = %i\n", info.bytes, info.fragments, info.fragstotal, info.fragsize);
+ printk(KERN_DEBUG "pcm_oss: space: bytes = %i, fragments = %i, "
+ "fragstotal = %i, fragsize = %i\n",
+ info.bytes, info.fragments, info.fragstotal, info.fragsize);
#endif
if (copy_to_user(_info, &info, sizeof(info)))
return -EFAULT;
@@ -2473,7 +2483,7 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
if (((cmd >> 8) & 0xff) != 'P')
return -EINVAL;
#ifdef OSS_DEBUG
- printk("pcm_oss: ioctl = 0x%x\n", cmd);
+ printk(KERN_DEBUG "pcm_oss: ioctl = 0x%x\n", cmd);
#endif
switch (cmd) {
case SNDCTL_DSP_RESET:
@@ -2627,7 +2637,8 @@ static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t coun
#else
{
ssize_t res = snd_pcm_oss_read1(substream, buf, count);
- printk("pcm_oss: read %li bytes (returned %li bytes)\n", (long)count, (long)res);
+ printk(KERN_DEBUG "pcm_oss: read %li bytes "
+ "(returned %li bytes)\n", (long)count, (long)res);
return res;
}
#endif
@@ -2646,7 +2657,8 @@ static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size
substream->f_flags = file->f_flags & O_NONBLOCK;
result = snd_pcm_oss_write1(substream, buf, count);
#ifdef OSS_DEBUG
- printk("pcm_oss: write %li bytes (wrote %li bytes)\n", (long)count, (long)result);
+ printk(KERN_DEBUG "pcm_oss: write %li bytes (wrote %li bytes)\n",
+ (long)count, (long)result);
#endif
return result;
}
@@ -2720,7 +2732,7 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
int err;
#ifdef OSS_DEBUG
- printk("pcm_oss: mmap begin\n");
+ printk(KERN_DEBUG "pcm_oss: mmap begin\n");
#endif
pcm_oss_file = file->private_data;
switch ((area->vm_flags & (VM_READ | VM_WRITE))) {
@@ -2770,7 +2782,8 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
runtime->silence_threshold = 0;
runtime->silence_size = 0;
#ifdef OSS_DEBUG
- printk("pcm_oss: mmap ok, bytes = 0x%x\n", runtime->oss.mmap_bytes);
+ printk(KERN_DEBUG "pcm_oss: mmap ok, bytes = 0x%x\n",
+ runtime->oss.mmap_bytes);
#endif
/* In mmap mode we never stop */
runtime->stop_threshold = runtime->boundary;
@@ -2872,7 +2885,7 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
setup = kmalloc(sizeof(*setup), GFP_KERNEL);
if (! setup) {
buffer->error = -ENOMEM;
- mutex_lock(&pstr->oss.setup_mutex);
+ mutex_unlock(&pstr->oss.setup_mutex);
return;
}
if (pstr->oss.setup_list == NULL)
@@ -2886,7 +2899,7 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry,
if (! template.task_name) {
kfree(setup);
buffer->error = -ENOMEM;
- mutex_lock(&pstr->oss.setup_mutex);
+ mutex_unlock(&pstr->oss.setup_mutex);
return;
}
}
diff --git a/sound/core/oss/pcm_plugin.h b/sound/core/oss/pcm_plugin.h
index ca2f4c39be4..b9afab60371 100644
--- a/sound/core/oss/pcm_plugin.h
+++ b/sound/core/oss/pcm_plugin.h
@@ -176,9 +176,9 @@ static inline int snd_pcm_plug_slave_format(int format, struct snd_mask *format_
#endif
#ifdef PLUGIN_DEBUG
-#define pdprintf( fmt, args... ) printk( "plugin: " fmt, ##args)
+#define pdprintf(fmt, args...) printk(KERN_DEBUG "plugin: " fmt, ##args)
#else
-#define pdprintf( fmt, args... )
+#define pdprintf(fmt, args...)
#endif
#endif /* __PCM_PLUGIN_H */
diff --git a/sound/core/oss/rate.c b/sound/core/oss/rate.c
index a466443c4a2..2fa9299a440 100644
--- a/sound/core/oss/rate.c
+++ b/sound/core/oss/rate.c
@@ -157,7 +157,7 @@ static void resample_shrink(struct snd_pcm_plugin *plugin,
while (dst_frames1 > 0) {
S1 = S2;
if (src_frames1-- > 0) {
- S1 = *src;
+ S2 = *src;
src += src_step;
}
if (pos & ~R_MASK) {
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 192a433a240..145931a9ff3 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -667,7 +667,6 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
spin_lock_init(&substream->self_group.lock);
INIT_LIST_HEAD(&substream->self_group.substreams);
list_add_tail(&substream->link_list, &substream->self_group.substreams);
- spin_lock_init(&substream->timer_lock);
atomic_set(&substream->mmap_count, 0);
prev = substream;
}
@@ -692,7 +691,7 @@ EXPORT_SYMBOL(snd_pcm_new_stream);
*
* Returns zero if successful, or a negative error code on failure.
*/
-int snd_pcm_new(struct snd_card *card, char *id, int device,
+int snd_pcm_new(struct snd_card *card, const char *id, int device,
int playback_count, int capture_count,
struct snd_pcm ** rpcm)
{
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 921691080f3..fbb2e391591 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -125,23 +125,32 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
}
}
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+#define xrun_debug(substream) ((substream)->pstr->xrun_debug)
+#else
+#define xrun_debug(substream) 0
+#endif
+
+#define dump_stack_on_xrun(substream) do { \
+ if (xrun_debug(substream) > 1) \
+ dump_stack(); \
+ } while (0)
+
static void xrun(struct snd_pcm_substream *substream)
{
snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-#ifdef CONFIG_SND_PCM_XRUN_DEBUG
- if (substream->pstr->xrun_debug) {
+ if (xrun_debug(substream)) {
snd_printd(KERN_DEBUG "XRUN: pcmC%dD%d%c\n",
substream->pcm->card->number,
substream->pcm->device,
substream->stream ? 'c' : 'p');
- if (substream->pstr->xrun_debug > 1)
- dump_stack();
+ dump_stack_on_xrun(substream);
}
-#endif
}
-static inline snd_pcm_uframes_t snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream,
- struct snd_pcm_runtime *runtime)
+static snd_pcm_uframes_t
+snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream,
+ struct snd_pcm_runtime *runtime)
{
snd_pcm_uframes_t pos;
@@ -150,17 +159,21 @@ static inline snd_pcm_uframes_t snd_pcm_update_hw_ptr_pos(struct snd_pcm_substre
pos = substream->ops->pointer(substream);
if (pos == SNDRV_PCM_POS_XRUN)
return pos; /* XRUN */
-#ifdef CONFIG_SND_DEBUG
if (pos >= runtime->buffer_size) {
- snd_printk(KERN_ERR "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size);
+ if (printk_ratelimit()) {
+ snd_printd(KERN_ERR "BUG: stream = %i, pos = 0x%lx, "
+ "buffer size = 0x%lx, period size = 0x%lx\n",
+ substream->stream, pos, runtime->buffer_size,
+ runtime->period_size);
+ }
+ pos = 0;
}
-#endif
pos -= pos % runtime->min_align;
return pos;
}
-static inline int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
- struct snd_pcm_runtime *runtime)
+static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
+ struct snd_pcm_runtime *runtime)
{
snd_pcm_uframes_t avail;
@@ -182,11 +195,21 @@ static inline int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream
return 0;
}
-static inline int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
+#define hw_ptr_error(substream, fmt, args...) \
+ do { \
+ if (xrun_debug(substream)) { \
+ if (printk_ratelimit()) { \
+ snd_printd("PCM: " fmt, ##args); \
+ } \
+ dump_stack_on_xrun(substream); \
+ } \
+ } while (0)
+
+static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t pos;
- snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt;
+ snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt, hw_base;
snd_pcm_sframes_t delta;
pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
@@ -194,36 +217,53 @@ static inline int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *subs
xrun(substream);
return -EPIPE;
}
- if (runtime->period_size == runtime->buffer_size)
- goto __next_buf;
- new_hw_ptr = runtime->hw_ptr_base + pos;
+ hw_base = runtime->hw_ptr_base;
+ new_hw_ptr = hw_base + pos;
hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size;
-
- delta = hw_ptr_interrupt - new_hw_ptr;
- if (delta > 0) {
- if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) {
-#ifdef CONFIG_SND_PCM_XRUN_DEBUG
- if (runtime->periods > 1 && substream->pstr->xrun_debug) {
- snd_printd(KERN_ERR "Unexpected hw_pointer value [1] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2);
- if (substream->pstr->xrun_debug > 1)
- dump_stack();
- }
-#endif
- return 0;
+ delta = new_hw_ptr - hw_ptr_interrupt;
+ if (hw_ptr_interrupt >= runtime->boundary) {
+ hw_ptr_interrupt -= runtime->boundary;
+ if (hw_base < runtime->boundary / 2)
+ /* hw_base was already lapped; recalc delta */
+ delta = new_hw_ptr - hw_ptr_interrupt;
+ }
+ if (delta < 0) {
+ delta += runtime->buffer_size;
+ if (delta < 0) {
+ hw_ptr_error(substream,
+ "Unexpected hw_pointer value "
+ "(stream=%i, pos=%ld, intr_ptr=%ld)\n",
+ substream->stream, (long)pos,
+ (long)hw_ptr_interrupt);
+ /* rebase to interrupt position */
+ hw_base = new_hw_ptr = hw_ptr_interrupt;
+ /* align hw_base to buffer_size */
+ hw_base -= hw_base % runtime->buffer_size;
+ delta = 0;
+ } else {
+ hw_base += runtime->buffer_size;
+ if (hw_base >= runtime->boundary)
+ hw_base = 0;
+ new_hw_ptr = hw_base + pos;
}
- __next_buf:
- runtime->hw_ptr_base += runtime->buffer_size;
- if (runtime->hw_ptr_base == runtime->boundary)
- runtime->hw_ptr_base = 0;
- new_hw_ptr = runtime->hw_ptr_base + pos;
}
-
+ if (delta > runtime->period_size) {
+ hw_ptr_error(substream,
+ "Lost interrupts? "
+ "(stream=%i, delta=%ld, intr_ptr=%ld)\n",
+ substream->stream, (long)delta,
+ (long)hw_ptr_interrupt);
+ /* rebase hw_ptr_interrupt */
+ hw_ptr_interrupt =
+ new_hw_ptr - new_hw_ptr % runtime->period_size;
+ }
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
snd_pcm_playback_silence(substream, new_hw_ptr);
+ runtime->hw_ptr_base = hw_base;
runtime->status->hw_ptr = new_hw_ptr;
- runtime->hw_ptr_interrupt = new_hw_ptr - new_hw_ptr % runtime->period_size;
+ runtime->hw_ptr_interrupt = hw_ptr_interrupt;
return snd_pcm_update_hw_ptr_post(substream, runtime);
}
@@ -233,7 +273,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t pos;
- snd_pcm_uframes_t old_hw_ptr, new_hw_ptr;
+ snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
snd_pcm_sframes_t delta;
old_hw_ptr = runtime->status->hw_ptr;
@@ -242,29 +282,38 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
xrun(substream);
return -EPIPE;
}
- new_hw_ptr = runtime->hw_ptr_base + pos;
-
- delta = old_hw_ptr - new_hw_ptr;
- if (delta > 0) {
- if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) {
-#ifdef CONFIG_SND_PCM_XRUN_DEBUG
- if (runtime->periods > 2 && substream->pstr->xrun_debug) {
- snd_printd(KERN_ERR "Unexpected hw_pointer value [2] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2);
- if (substream->pstr->xrun_debug > 1)
- dump_stack();
- }
-#endif
+ hw_base = runtime->hw_ptr_base;
+ new_hw_ptr = hw_base + pos;
+
+ delta = new_hw_ptr - old_hw_ptr;
+ if (delta < 0) {
+ delta += runtime->buffer_size;
+ if (delta < 0) {
+ hw_ptr_error(substream,
+ "Unexpected hw_pointer value [2] "
+ "(stream=%i, pos=%ld, old_ptr=%ld)\n",
+ substream->stream, (long)pos,
+ (long)old_hw_ptr);
return 0;
}
- runtime->hw_ptr_base += runtime->buffer_size;
- if (runtime->hw_ptr_base == runtime->boundary)
- runtime->hw_ptr_base = 0;
- new_hw_ptr = runtime->hw_ptr_base + pos;
+ hw_base += runtime->buffer_size;
+ if (hw_base >= runtime->boundary)
+ hw_base = 0;
+ new_hw_ptr = hw_base + pos;
+ }
+ if (delta > runtime->period_size && runtime->periods > 1) {
+ hw_ptr_error(substream,
+ "hw_ptr skipping! "
+ "(pos=%ld, delta=%ld, period=%ld)\n",
+ (long)pos, (long)delta,
+ (long)runtime->period_size);
+ return 0;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
snd_pcm_playback_silence(substream, new_hw_ptr);
+ runtime->hw_ptr_base = hw_base;
runtime->status->hw_ptr = new_hw_ptr;
return snd_pcm_update_hw_ptr_post(substream, runtime);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index a789efc9df3..d9b8f537942 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -186,7 +186,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
if (!(params->rmask & (1 << k)))
continue;
#ifdef RULES_DEBUG
- printk("%s = ", snd_pcm_hw_param_names[k]);
+ printk(KERN_DEBUG "%s = ", snd_pcm_hw_param_names[k]);
printk("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
#endif
changed = snd_mask_refine(m, constrs_mask(constrs, k));
@@ -206,7 +206,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
if (!(params->rmask & (1 << k)))
continue;
#ifdef RULES_DEBUG
- printk("%s = ", snd_pcm_hw_param_names[k]);
+ printk(KERN_DEBUG "%s = ", snd_pcm_hw_param_names[k]);
if (i->empty)
printk("empty");
else
@@ -251,7 +251,7 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
if (!doit)
continue;
#ifdef RULES_DEBUG
- printk("Rule %d [%p]: ", k, r->func);
+ printk(KERN_DEBUG "Rule %d [%p]: ", k, r->func);
if (r->var >= 0) {
printk("%s = ", snd_pcm_hw_param_names[r->var]);
if (hw_is_mask(r->var)) {
diff --git a/sound/core/pcm_timer.c b/sound/core/pcm_timer.c
index 2c89c04f291..ca8068b63d6 100644
--- a/sound/core/pcm_timer.c
+++ b/sound/core/pcm_timer.c
@@ -85,25 +85,19 @@ static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer)
static int snd_pcm_timer_start(struct snd_timer * timer)
{
- unsigned long flags;
struct snd_pcm_substream *substream;
substream = snd_timer_chip(timer);
- spin_lock_irqsave(&substream->timer_lock, flags);
substream->timer_running = 1;
- spin_unlock_irqrestore(&substream->timer_lock, flags);
return 0;
}
static int snd_pcm_timer_stop(struct snd_timer * timer)
{
- unsigned long flags;
struct snd_pcm_substream *substream;
substream = snd_timer_chip(timer);
- spin_lock_irqsave(&substream->timer_lock, flags);
substream->timer_running = 0;
- spin_unlock_irqrestore(&substream->timer_lock, flags);
return 0;
}
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 002777ba336..473247c8e6d 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -224,156 +224,143 @@ int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream)
return 0;
}
-int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice,
- int mode, struct snd_rawmidi_file * rfile)
+/* look for an available substream for the given stream direction;
+ * if a specific subdevice is given, try to assign it
+ */
+static int assign_substream(struct snd_rawmidi *rmidi, int subdevice,
+ int stream, int mode,
+ struct snd_rawmidi_substream **sub_ret)
+{
+ struct snd_rawmidi_substream *substream;
+ struct snd_rawmidi_str *s = &rmidi->streams[stream];
+ static unsigned int info_flags[2] = {
+ [SNDRV_RAWMIDI_STREAM_OUTPUT] = SNDRV_RAWMIDI_INFO_OUTPUT,
+ [SNDRV_RAWMIDI_STREAM_INPUT] = SNDRV_RAWMIDI_INFO_INPUT,
+ };
+
+ if (!(rmidi->info_flags & info_flags[stream]))
+ return -ENXIO;
+ if (subdevice >= 0 && subdevice >= s->substream_count)
+ return -ENODEV;
+ if (s->substream_opened >= s->substream_count)
+ return -EAGAIN;
+
+ list_for_each_entry(substream, &s->substreams, list) {
+ if (substream->opened) {
+ if (stream == SNDRV_RAWMIDI_STREAM_INPUT ||
+ !(mode & SNDRV_RAWMIDI_LFLG_APPEND))
+ continue;
+ }
+ if (subdevice < 0 || subdevice == substream->number) {
+ *sub_ret = substream;
+ return 0;
+ }
+ }
+ return -EAGAIN;
+}
+
+/* open and do ref-counting for the given substream */
+static int open_substream(struct snd_rawmidi *rmidi,
+ struct snd_rawmidi_substream *substream,
+ int mode)
+{
+ int err;
+
+ err = snd_rawmidi_runtime_create(substream);
+ if (err < 0)
+ return err;
+ err = substream->ops->open(substream);
+ if (err < 0)
+ return err;
+ substream->opened = 1;
+ if (substream->use_count++ == 0)
+ substream->active_sensing = 1;
+ if (mode & SNDRV_RAWMIDI_LFLG_APPEND)
+ substream->append = 1;
+ rmidi->streams[substream->stream].substream_opened++;
+ return 0;
+}
+
+static void close_substream(struct snd_rawmidi *rmidi,
+ struct snd_rawmidi_substream *substream,
+ int cleanup);
+
+static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode,
+ struct snd_rawmidi_file *rfile)
{
- struct snd_rawmidi *rmidi;
- struct list_head *list1, *list2;
struct snd_rawmidi_substream *sinput = NULL, *soutput = NULL;
- struct snd_rawmidi_runtime *input = NULL, *output = NULL;
int err;
- if (rfile)
- rfile->input = rfile->output = NULL;
- mutex_lock(&register_mutex);
- rmidi = snd_rawmidi_search(card, device);
- mutex_unlock(&register_mutex);
- if (rmidi == NULL) {
- err = -ENODEV;
- goto __error1;
- }
- if (!try_module_get(rmidi->card->module)) {
- err = -EFAULT;
- goto __error1;
- }
- if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
- mutex_lock(&rmidi->open_mutex);
+ rfile->input = rfile->output = NULL;
if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
- if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT)) {
- err = -ENXIO;
- goto __error;
- }
- if (subdevice >= 0 && (unsigned int)subdevice >= rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_count) {
- err = -ENODEV;
- goto __error;
- }
- if (rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened >=
- rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_count) {
- err = -EAGAIN;
+ err = assign_substream(rmidi, subdevice,
+ SNDRV_RAWMIDI_STREAM_INPUT,
+ mode, &sinput);
+ if (err < 0)
goto __error;
- }
}
if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
- if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT)) {
- err = -ENXIO;
- goto __error;
- }
- if (subdevice >= 0 && (unsigned int)subdevice >= rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_count) {
- err = -ENODEV;
- goto __error;
- }
- if (rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened >=
- rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_count) {
- err = -EAGAIN;
+ err = assign_substream(rmidi, subdevice,
+ SNDRV_RAWMIDI_STREAM_OUTPUT,
+ mode, &soutput);
+ if (err < 0)
goto __error;
- }
- }
- list1 = rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams.next;
- while (1) {
- if (list1 == &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) {
- sinput = NULL;
- if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
- err = -EAGAIN;
- goto __error;
- }
- break;
- }
- sinput = list_entry(list1, struct snd_rawmidi_substream, list);
- if ((mode & SNDRV_RAWMIDI_LFLG_INPUT) && sinput->opened)
- goto __nexti;
- if (subdevice < 0 || (subdevice >= 0 && subdevice == sinput->number))
- break;
- __nexti:
- list1 = list1->next;
}
- list2 = rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams.next;
- while (1) {
- if (list2 == &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) {
- soutput = NULL;
- if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
- err = -EAGAIN;
- goto __error;
- }
- break;
- }
- soutput = list_entry(list2, struct snd_rawmidi_substream, list);
- if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
- if (mode & SNDRV_RAWMIDI_LFLG_APPEND) {
- if (soutput->opened && !soutput->append)
- goto __nexto;
- } else {
- if (soutput->opened)
- goto __nexto;
- }
- }
- if (subdevice < 0 || (subdevice >= 0 && subdevice == soutput->number))
- break;
- __nexto:
- list2 = list2->next;
- }
- if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
- if ((err = snd_rawmidi_runtime_create(sinput)) < 0)
- goto __error;
- input = sinput->runtime;
- if ((err = sinput->ops->open(sinput)) < 0)
+
+ if (sinput) {
+ err = open_substream(rmidi, sinput, mode);
+ if (err < 0)
goto __error;
- sinput->opened = 1;
- rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened++;
- } else {
- sinput = NULL;
}
- if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
- if (soutput->opened)
- goto __skip_output;
- if ((err = snd_rawmidi_runtime_create(soutput)) < 0) {
- if (mode & SNDRV_RAWMIDI_LFLG_INPUT)
- sinput->ops->close(sinput);
- goto __error;
- }
- output = soutput->runtime;
- if ((err = soutput->ops->open(soutput)) < 0) {
- if (mode & SNDRV_RAWMIDI_LFLG_INPUT)
- sinput->ops->close(sinput);
+ if (soutput) {
+ err = open_substream(rmidi, soutput, mode);
+ if (err < 0) {
+ if (sinput)
+ close_substream(rmidi, sinput, 0);
goto __error;
}
- __skip_output:
- soutput->opened = 1;
- if (mode & SNDRV_RAWMIDI_LFLG_APPEND)
- soutput->append = 1;
- if (soutput->use_count++ == 0)
- soutput->active_sensing = 1;
- rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened++;
- } else {
- soutput = NULL;
- }
- if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
- mutex_unlock(&rmidi->open_mutex);
- if (rfile) {
- rfile->rmidi = rmidi;
- rfile->input = sinput;
- rfile->output = soutput;
}
+
+ rfile->rmidi = rmidi;
+ rfile->input = sinput;
+ rfile->output = soutput;
return 0;
__error:
- if (input != NULL)
+ if (sinput && sinput->runtime)
snd_rawmidi_runtime_free(sinput);
- if (output != NULL)
+ if (soutput && soutput->runtime)
snd_rawmidi_runtime_free(soutput);
- module_put(rmidi->card->module);
- if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
- mutex_unlock(&rmidi->open_mutex);
- __error1:
+ return err;
+}
+
+/* called from sound/core/seq/seq_midi.c */
+int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice,
+ int mode, struct snd_rawmidi_file * rfile)
+{
+ struct snd_rawmidi *rmidi;
+ int err;
+
+ if (snd_BUG_ON(!rfile))
+ return -EINVAL;
+
+ mutex_lock(&register_mutex);
+ rmidi = snd_rawmidi_search(card, device);
+ if (rmidi == NULL) {
+ mutex_unlock(&register_mutex);
+ return -ENODEV;
+ }
+ if (!try_module_get(rmidi->card->module)) {
+ mutex_unlock(&register_mutex);
+ return -ENXIO;
+ }
+ mutex_unlock(&register_mutex);
+
+ mutex_lock(&rmidi->open_mutex);
+ err = rawmidi_open_priv(rmidi, subdevice, mode, rfile);
+ mutex_unlock(&rmidi->open_mutex);
+ if (err < 0)
+ module_put(rmidi->card->module);
return err;
}
@@ -385,10 +372,13 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
unsigned short fflags;
int err;
struct snd_rawmidi *rmidi;
- struct snd_rawmidi_file *rawmidi_file;
+ struct snd_rawmidi_file *rawmidi_file = NULL;
wait_queue_t wait;
struct snd_ctl_file *kctl;
+ if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK))
+ return -EINVAL; /* invalid combination */
+
if (maj == snd_major) {
rmidi = snd_lookup_minor_data(iminor(inode),
SNDRV_DEVICE_TYPE_RAWMIDI);
@@ -402,24 +392,25 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
if (rmidi == NULL)
return -ENODEV;
- if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK))
- return -EINVAL; /* invalid combination */
+
+ if (!try_module_get(rmidi->card->module))
+ return -ENXIO;
+
+ mutex_lock(&rmidi->open_mutex);
card = rmidi->card;
err = snd_card_file_add(card, file);
if (err < 0)
- return -ENODEV;
+ goto __error_card;
fflags = snd_rawmidi_file_flags(file);
if ((file->f_flags & O_APPEND) || maj == SOUND_MAJOR) /* OSS emul? */
fflags |= SNDRV_RAWMIDI_LFLG_APPEND;
- fflags |= SNDRV_RAWMIDI_LFLG_NOOPENLOCK;
rawmidi_file = kmalloc(sizeof(*rawmidi_file), GFP_KERNEL);
if (rawmidi_file == NULL) {
- snd_card_file_remove(card, file);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto __error;
}
init_waitqueue_entry(&wait, current);
add_wait_queue(&rmidi->open_wait, &wait);
- mutex_lock(&rmidi->open_mutex);
while (1) {
subdevice = -1;
read_lock(&card->ctl_files_rwlock);
@@ -431,8 +422,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
}
}
read_unlock(&card->ctl_files_rwlock);
- err = snd_rawmidi_kernel_open(rmidi->card, rmidi->device,
- subdevice, fflags, rawmidi_file);
+ err = rawmidi_open_priv(rmidi, subdevice, fflags, rawmidi_file);
if (err >= 0)
break;
if (err == -EAGAIN) {
@@ -451,67 +441,89 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
break;
}
}
+ remove_wait_queue(&rmidi->open_wait, &wait);
+ if (err < 0) {
+ kfree(rawmidi_file);
+ goto __error;
+ }
#ifdef CONFIG_SND_OSSEMUL
if (rawmidi_file->input && rawmidi_file->input->runtime)
rawmidi_file->input->runtime->oss = (maj == SOUND_MAJOR);
if (rawmidi_file->output && rawmidi_file->output->runtime)
rawmidi_file->output->runtime->oss = (maj == SOUND_MAJOR);
#endif
- remove_wait_queue(&rmidi->open_wait, &wait);
- if (err >= 0) {
- file->private_data = rawmidi_file;
- } else {
- snd_card_file_remove(card, file);
- kfree(rawmidi_file);
- }
+ file->private_data = rawmidi_file;
+ mutex_unlock(&rmidi->open_mutex);
+ return 0;
+
+ __error:
+ snd_card_file_remove(card, file);
+ __error_card:
mutex_unlock(&rmidi->open_mutex);
+ module_put(rmidi->card->module);
return err;
}
-int snd_rawmidi_kernel_release(struct snd_rawmidi_file * rfile)
+static void close_substream(struct snd_rawmidi *rmidi,
+ struct snd_rawmidi_substream *substream,
+ int cleanup)
{
- struct snd_rawmidi *rmidi;
- struct snd_rawmidi_substream *substream;
- struct snd_rawmidi_runtime *runtime;
+ rmidi->streams[substream->stream].substream_opened--;
+ if (--substream->use_count)
+ return;
- if (snd_BUG_ON(!rfile))
- return -ENXIO;
- rmidi = rfile->rmidi;
- mutex_lock(&rmidi->open_mutex);
- if (rfile->input != NULL) {
- substream = rfile->input;
- rfile->input = NULL;
- runtime = substream->runtime;
- snd_rawmidi_input_trigger(substream, 0);
- substream->ops->close(substream);
- if (runtime->private_free != NULL)
- runtime->private_free(substream);
- snd_rawmidi_runtime_free(substream);
- substream->opened = 0;
- rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened--;
- }
- if (rfile->output != NULL) {
- substream = rfile->output;
- rfile->output = NULL;
- if (--substream->use_count == 0) {
- runtime = substream->runtime;
+ if (cleanup) {
+ if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT)
+ snd_rawmidi_input_trigger(substream, 0);
+ else {
if (substream->active_sensing) {
unsigned char buf = 0xfe;
- /* sending single active sensing message to shut the device up */
+ /* sending single active sensing message
+ * to shut the device up
+ */
snd_rawmidi_kernel_write(substream, &buf, 1);
}
if (snd_rawmidi_drain_output(substream) == -ERESTARTSYS)
snd_rawmidi_output_trigger(substream, 0);
- substream->ops->close(substream);
- if (runtime->private_free != NULL)
- runtime->private_free(substream);
- snd_rawmidi_runtime_free(substream);
- substream->opened = 0;
- substream->append = 0;
}
- rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened--;
}
+ substream->ops->close(substream);
+ if (substream->runtime->private_free)
+ substream->runtime->private_free(substream);
+ snd_rawmidi_runtime_free(substream);
+ substream->opened = 0;
+ substream->append = 0;
+}
+
+static void rawmidi_release_priv(struct snd_rawmidi_file *rfile)
+{
+ struct snd_rawmidi *rmidi;
+
+ rmidi = rfile->rmidi;
+ mutex_lock(&rmidi->open_mutex);
+ if (rfile->input) {
+ close_substream(rmidi, rfile->input, 1);
+ rfile->input = NULL;
+ }
+ if (rfile->output) {
+ close_substream(rmidi, rfile->output, 1);
+ rfile->output = NULL;
+ }
+ rfile->rmidi = NULL;
mutex_unlock(&rmidi->open_mutex);
+ wake_up(&rmidi->open_wait);
+}
+
+/* called from sound/core/seq/seq_midi.c */
+int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile)
+{
+ struct snd_rawmidi *rmidi;
+
+ if (snd_BUG_ON(!rfile))
+ return -ENXIO;
+
+ rmidi = rfile->rmidi;
+ rawmidi_release_priv(rfile);
module_put(rmidi->card->module);
return 0;
}
@@ -520,15 +532,14 @@ static int snd_rawmidi_release(struct inode *inode, struct file *file)
{
struct snd_rawmidi_file *rfile;
struct snd_rawmidi *rmidi;
- int err;
rfile = file->private_data;
- err = snd_rawmidi_kernel_release(rfile);
rmidi = rfile->rmidi;
- wake_up(&rmidi->open_wait);
+ rawmidi_release_priv(rfile);
kfree(rfile);
snd_card_file_remove(rmidi->card, file);
- return err;
+ module_put(rmidi->card->module);
+ return 0;
}
static int snd_rawmidi_info(struct snd_rawmidi_substream *substream,
diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h
index bf8d2b4cb15..c0154a959d5 100644
--- a/sound/core/seq/oss/seq_oss_device.h
+++ b/sound/core/seq/oss/seq_oss_device.h
@@ -181,7 +181,7 @@ char *enabled_str(int bool);
/* for debug */
#ifdef SNDRV_SEQ_OSS_DEBUG
extern int seq_oss_debug;
-#define debug_printk(x) do { if (seq_oss_debug > 0) snd_printk x; } while (0)
+#define debug_printk(x) do { if (seq_oss_debug > 0) snd_printd x; } while (0)
#else
#define debug_printk(x) /**/
#endif
diff --git a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c
index 0101a8b99b7..29896ab2340 100644
--- a/sound/core/seq/seq_prioq.c
+++ b/sound/core/seq/seq_prioq.c
@@ -321,7 +321,8 @@ void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp)
freeprev = cell;
} else {
#if 0
- printk("type = %i, source = %i, dest = %i, client = %i\n",
+ printk(KERN_DEBUG "type = %i, source = %i, dest = %i, "
+ "client = %i\n",
cell->event.type,
cell->event.source.client,
cell->event.dest.client,
diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c
index d4564edd61d..4e7ec2b4987 100644
--- a/sound/core/sgbuf.c
+++ b/sound/core/sgbuf.c
@@ -38,6 +38,10 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
if (! sgbuf)
return -EINVAL;
+ if (dmab->area)
+ vunmap(dmab->area);
+ dmab->area = NULL;
+
tmpb.dev.type = SNDRV_DMA_TYPE_DEV;
tmpb.dev.dev = sgbuf->dev;
for (i = 0; i < sgbuf->pages; i++) {
@@ -48,9 +52,6 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
tmpb.bytes = (sgbuf->table[i].addr & ~PAGE_MASK) << PAGE_SHIFT;
snd_dma_free_pages(&tmpb);
}
- if (dmab->area)
- vunmap(dmab->area);
- dmab->area = NULL;
kfree(sgbuf->table);
kfree(sgbuf->page_table);
diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c
index 4cc57f902e2..257624bd199 100644
--- a/sound/core/vmaster.c
+++ b/sound/core/vmaster.c
@@ -50,18 +50,38 @@ struct link_slave {
struct link_master *master;
struct link_ctl_info info;
int vals[2]; /* current values */
+ unsigned int flags;
struct snd_kcontrol slave; /* the copy of original control entry */
};
+static int slave_update(struct link_slave *slave)
+{
+ struct snd_ctl_elem_value *uctl;
+ int err, ch;
+
+ uctl = kmalloc(sizeof(*uctl), GFP_KERNEL);
+ if (!uctl)
+ return -ENOMEM;
+ uctl->id = slave->slave.id;
+ err = slave->slave.get(&slave->slave, uctl);
+ for (ch = 0; ch < slave->info.count; ch++)
+ slave->vals[ch] = uctl->value.integer.value[ch];
+ kfree(uctl);
+ return 0;
+}
+
/* get the slave ctl info and save the initial values */
static int slave_init(struct link_slave *slave)
{
struct snd_ctl_elem_info *uinfo;
- struct snd_ctl_elem_value *uctl;
- int err, ch;
+ int err;
- if (slave->info.count)
- return 0; /* already initialized */
+ if (slave->info.count) {
+ /* already initialized */
+ if (slave->flags & SND_CTL_SLAVE_NEED_UPDATE)
+ return slave_update(slave);
+ return 0;
+ }
uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL);
if (!uinfo)
@@ -85,15 +105,7 @@ static int slave_init(struct link_slave *slave)
slave->info.max_val = uinfo->value.integer.max;
kfree(uinfo);
- uctl = kmalloc(sizeof(*uctl), GFP_KERNEL);
- if (!uctl)
- return -ENOMEM;
- uctl->id = slave->slave.id;
- err = slave->slave.get(&slave->slave, uctl);
- for (ch = 0; ch < slave->info.count; ch++)
- slave->vals[ch] = uctl->value.integer.value[ch];
- kfree(uctl);
- return 0;
+ return slave_update(slave);
}
/* initialize master volume */
@@ -229,7 +241,8 @@ static void slave_free(struct snd_kcontrol *kcontrol)
* - logarithmic volume control (dB level), no linear volume
* - master can only attenuate the volume, no gain
*/
-int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
+int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave,
+ unsigned int flags)
{
struct link_master *master_link = snd_kcontrol_chip(master);
struct link_slave *srec;
@@ -241,6 +254,7 @@ int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
srec->slave = *slave;
memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd));
srec->master = master_link;
+ srec->flags = flags;
/* override callbacks */
slave->info = slave_info;
@@ -254,8 +268,7 @@ int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
list_add_tail(&srec->list, &master_link->slaves);
return 0;
}
-
-EXPORT_SYMBOL(snd_ctl_add_slave);
+EXPORT_SYMBOL(_snd_ctl_add_slave);
/*
* ctl callbacks for master controls
@@ -327,8 +340,20 @@ static void master_free(struct snd_kcontrol *kcontrol)
}
-/*
- * Create a virtual master control with the given name
+/**
+ * snd_ctl_make_virtual_master - Create a virtual master control
+ * @name: name string of the control element to create
+ * @tlv: optional TLV int array for dB information
+ *
+ * Creates a virtual matster control with the given name string.
+ * Returns the created control element, or NULL for errors (ENOMEM).
+ *
+ * After creating a vmaster element, you can add the slave controls
+ * via snd_ctl_add_slave() or snd_ctl_add_slave_uncached().
+ *
+ * The optional argument @tlv can be used to specify the TLV information
+ * for dB scale of the master control. It should be a single element
+ * with #SNDRV_CTL_TLVT_DB_SCALE type, and should be the max 0dB.
*/
struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
const unsigned int *tlv)
@@ -367,5 +392,4 @@ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
return kctl;
}
-
EXPORT_SYMBOL(snd_ctl_make_virtual_master);
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index 73be7e14a60..54239d2e099 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -588,10 +588,10 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr)
int idx, err;
int dev = devptr->id;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_dummy));
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_dummy), &card);
+ if (err < 0)
+ return err;
dummy = card->private_data;
dummy->card = card;
for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) {
diff --git a/sound/drivers/ml403-ac97cr.c b/sound/drivers/ml403-ac97cr.c
index 7783843ca9a..1950ffce2b5 100644
--- a/sound/drivers/ml403-ac97cr.c
+++ b/sound/drivers/ml403-ac97cr.c
@@ -1279,9 +1279,9 @@ static int __devinit snd_ml403_ac97cr_probe(struct platform_device *pfdev)
if (!enable[dev])
return -ENOENT;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
err = snd_ml403_ac97cr_create(card, pfdev, &ml403_ac97cr);
if (err < 0) {
PDEBUG(INIT_FAILURE, "probe(): create failed!\n");
diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c
index 5b996f3faba..149d05a8202 100644
--- a/sound/drivers/mpu401/mpu401.c
+++ b/sound/drivers/mpu401/mpu401.c
@@ -73,9 +73,9 @@ static int snd_mpu401_create(int dev, struct snd_card **rcard)
snd_printk(KERN_ERR "the uart_enter option is obsolete; remove it\n");
*rcard = NULL;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
strcpy(card->driver, "MPU-401 UART");
strcpy(card->shortname, card->driver);
sprintf(card->longname, "%s at %#lx, ", card->shortname, port[dev]);
diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c
index 5b89c0883d6..2f8f295d6b0 100644
--- a/sound/drivers/mtpav.c
+++ b/sound/drivers/mtpav.c
@@ -303,8 +303,10 @@ static void snd_mtpav_output_port_write(struct mtpav *mtp_card,
snd_mtpav_send_byte(mtp_card, 0xf5);
snd_mtpav_send_byte(mtp_card, portp->hwport);
- //snd_printk("new outport: 0x%x\n", (unsigned int) portp->hwport);
-
+ /*
+ snd_printk(KERN_DEBUG "new outport: 0x%x\n",
+ (unsigned int) portp->hwport);
+ */
if (!(outbyte & 0x80) && portp->running_status)
snd_mtpav_send_byte(mtp_card, portp->running_status);
}
@@ -540,7 +542,7 @@ static void snd_mtpav_read_bytes(struct mtpav *mcrd)
u8 sbyt = snd_mtpav_getreg(mcrd, SREG);
- //printk("snd_mtpav_read_bytes() sbyt: 0x%x\n", sbyt);
+ /* printk(KERN_DEBUG "snd_mtpav_read_bytes() sbyt: 0x%x\n", sbyt); */
if (!(sbyt & SIGS_BYTE))
return;
@@ -585,12 +587,12 @@ static irqreturn_t snd_mtpav_irqh(int irq, void *dev_id)
static int __devinit snd_mtpav_get_ISA(struct mtpav * mcard)
{
if ((mcard->res_port = request_region(port, 3, "MotuMTPAV MIDI")) == NULL) {
- snd_printk("MTVAP port 0x%lx is busy\n", port);
+ snd_printk(KERN_ERR "MTVAP port 0x%lx is busy\n", port);
return -EBUSY;
}
mcard->port = port;
if (request_irq(irq, snd_mtpav_irqh, IRQF_DISABLED, "MOTU MTPAV", mcard)) {
- snd_printk("MTVAP IRQ %d busy\n", irq);
+ snd_printk(KERN_ERR "MTVAP IRQ %d busy\n", irq);
return -EBUSY;
}
mcard->irq = irq;
@@ -696,9 +698,9 @@ static int __devinit snd_mtpav_probe(struct platform_device *dev)
int err;
struct mtpav *mtp_card;
- card = snd_card_new(index, id, THIS_MODULE, sizeof(*mtp_card));
- if (! card)
- return -ENOMEM;
+ err = snd_card_create(index, id, THIS_MODULE, sizeof(*mtp_card), &card);
+ if (err < 0)
+ return err;
mtp_card = card->private_data;
spin_lock_init(&mtp_card->spinlock);
@@ -706,7 +708,6 @@ static int __devinit snd_mtpav_probe(struct platform_device *dev)
mtp_card->card = card;
mtp_card->irq = -1;
mtp_card->share_irq = 0;
- mtp_card->inmidiport = 0xffffffff;
mtp_card->inmidistate = 0;
mtp_card->outmidihwport = 0xffffffff;
init_timer(&mtp_card->timer);
@@ -719,6 +720,8 @@ static int __devinit snd_mtpav_probe(struct platform_device *dev)
if (err < 0)
goto __error;
+ mtp_card->inmidiport = mtp_card->num_ports + MTPAV_PIDX_BROADCAST;
+
err = snd_mtpav_get_ISA(mtp_card);
if (err < 0)
goto __error;
diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c
index 87ba1ddc011..9284829bf92 100644
--- a/sound/drivers/mts64.c
+++ b/sound/drivers/mts64.c
@@ -957,10 +957,10 @@ static int __devinit snd_mts64_probe(struct platform_device *pdev)
if ((err = snd_mts64_probe_port(p)) < 0)
return err;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL) {
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0) {
snd_printd("Cannot create card\n");
- return -ENOMEM;
+ return err;
}
strcpy(card->driver, DRIVER_NAME);
strcpy(card->shortname, "ESI " CARD_NAME);
@@ -1015,7 +1015,7 @@ static int __devinit snd_mts64_probe(struct platform_device *pdev)
goto __err;
}
- snd_printk("ESI Miditerminal 4140 on 0x%lx\n", p->base);
+ snd_printk(KERN_INFO "ESI Miditerminal 4140 on 0x%lx\n", p->base);
return 0;
__err:
diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c
index 780582340fe..6e31e46ca39 100644
--- a/sound/drivers/opl3/opl3_lib.c
+++ b/sound/drivers/opl3/opl3_lib.c
@@ -302,7 +302,7 @@ void snd_opl3_interrupt(struct snd_hwdep * hw)
opl3 = hw->private_data;
status = inb(opl3->l_port);
#if 0
- snd_printk("AdLib IRQ status = 0x%x\n", status);
+ snd_printk(KERN_DEBUG "AdLib IRQ status = 0x%x\n", status);
#endif
if (!(status & 0x80))
return;
diff --git a/sound/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c
index 16feafa2c51..6e7d09ae0e8 100644
--- a/sound/drivers/opl3/opl3_midi.c
+++ b/sound/drivers/opl3/opl3_midi.c
@@ -125,7 +125,7 @@ static void debug_alloc(struct snd_opl3 *opl3, char *s, int voice) {
int i;
char *str = "x.24";
- printk("time %.5i: %s [%.2i]: ", opl3->use_time, s, voice);
+ printk(KERN_DEBUG "time %.5i: %s [%.2i]: ", opl3->use_time, s, voice);
for (i = 0; i < opl3->max_voices; i++)
printk("%c", *(str + opl3->voices[i].state + 1));
printk("\n");
@@ -218,7 +218,7 @@ static int opl3_get_voice(struct snd_opl3 *opl3, int instr_4op,
for (i = 0; i < END; i++) {
if (best[i].voice >= 0) {
#ifdef DEBUG_ALLOC
- printk("%s %iop allocation on voice %i\n",
+ printk(KERN_DEBUG "%s %iop allocation on voice %i\n",
alloc_type[i], instr_4op ? 4 : 2,
best[i].voice);
#endif
@@ -317,7 +317,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
opl3 = p;
#ifdef DEBUG_MIDI
- snd_printk("Note on, ch %i, inst %i, note %i, vel %i\n",
+ snd_printk(KERN_DEBUG "Note on, ch %i, inst %i, note %i, vel %i\n",
chan->number, chan->midi_program, note, vel);
#endif
@@ -372,7 +372,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
return;
}
#ifdef DEBUG_MIDI
- snd_printk(" --> OPL%i instrument: %s\n",
+ snd_printk(KERN_DEBUG " --> OPL%i instrument: %s\n",
instr_4op ? 3 : 2, patch->name);
#endif
/* in SYNTH mode, application takes care of voices */
@@ -431,7 +431,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
}
#ifdef DEBUG_MIDI
- snd_printk(" --> setting OPL3 connection: 0x%x\n",
+ snd_printk(KERN_DEBUG " --> setting OPL3 connection: 0x%x\n",
opl3->connection_reg);
#endif
/*
@@ -466,7 +466,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
/* Program the FM voice characteristics */
for (i = 0; i < (instr_4op ? 4 : 2); i++) {
#ifdef DEBUG_MIDI
- snd_printk(" --> programming operator %i\n", i);
+ snd_printk(KERN_DEBUG " --> programming operator %i\n", i);
#endif
op_offset = snd_opl3_regmap[voice_offset][i];
@@ -546,7 +546,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
blocknum |= OPL3_KEYON_BIT;
#ifdef DEBUG_MIDI
- snd_printk(" --> trigger voice %i\n", voice);
+ snd_printk(KERN_DEBUG " --> trigger voice %i\n", voice);
#endif
/* Set OPL3 KEYON_BLOCK register of requested voice */
opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);
@@ -602,7 +602,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
prg = extra_prg - 1;
}
#ifdef DEBUG_MIDI
- snd_printk(" *** allocating extra program\n");
+ snd_printk(KERN_DEBUG " *** allocating extra program\n");
#endif
goto __extra_prg;
}
@@ -633,7 +633,7 @@ static void snd_opl3_kill_voice(struct snd_opl3 *opl3, int voice)
/* kill voice */
#ifdef DEBUG_MIDI
- snd_printk(" --> kill voice %i\n", voice);
+ snd_printk(KERN_DEBUG " --> kill voice %i\n", voice);
#endif
opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset);
/* clear Key ON bit */
@@ -670,7 +670,7 @@ void snd_opl3_note_off(void *p, int note, int vel, struct snd_midi_channel *chan
opl3 = p;
#ifdef DEBUG_MIDI
- snd_printk("Note off, ch %i, inst %i, note %i\n",
+ snd_printk(KERN_DEBUG "Note off, ch %i, inst %i, note %i\n",
chan->number, chan->midi_program, note);
#endif
@@ -709,7 +709,7 @@ void snd_opl3_key_press(void *p, int note, int vel, struct snd_midi_channel *cha
opl3 = p;
#ifdef DEBUG_MIDI
- snd_printk("Key pressure, ch#: %i, inst#: %i\n",
+ snd_printk(KERN_DEBUG "Key pressure, ch#: %i, inst#: %i\n",
chan->number, chan->midi_program);
#endif
}
@@ -723,7 +723,7 @@ void snd_opl3_terminate_note(void *p, int note, struct snd_midi_channel *chan)
opl3 = p;
#ifdef DEBUG_MIDI
- snd_printk("Terminate note, ch#: %i, inst#: %i\n",
+ snd_printk(KERN_DEBUG "Terminate note, ch#: %i, inst#: %i\n",
chan->number, chan->midi_program);
#endif
}
@@ -812,7 +812,7 @@ void snd_opl3_control(void *p, int type, struct snd_midi_channel *chan)
opl3 = p;
#ifdef DEBUG_MIDI
- snd_printk("Controller, TYPE = %i, ch#: %i, inst#: %i\n",
+ snd_printk(KERN_DEBUG "Controller, TYPE = %i, ch#: %i, inst#: %i\n",
type, chan->number, chan->midi_program);
#endif
@@ -849,7 +849,7 @@ void snd_opl3_nrpn(void *p, struct snd_midi_channel *chan,
opl3 = p;
#ifdef DEBUG_MIDI
- snd_printk("NRPN, ch#: %i, inst#: %i\n",
+ snd_printk(KERN_DEBUG "NRPN, ch#: %i, inst#: %i\n",
chan->number, chan->midi_program);
#endif
}
@@ -864,6 +864,6 @@ void snd_opl3_sysex(void *p, unsigned char *buf, int len,
opl3 = p;
#ifdef DEBUG_MIDI
- snd_printk("SYSEX\n");
+ snd_printk(KERN_DEBUG "SYSEX\n");
#endif
}
diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c
index 9a2271dc046..a54b1dc5cc7 100644
--- a/sound/drivers/opl3/opl3_oss.c
+++ b/sound/drivers/opl3/opl3_oss.c
@@ -220,14 +220,14 @@ static int snd_opl3_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
return -EINVAL;
if (count < (int)sizeof(sbi)) {
- snd_printk("FM Error: Patch record too short\n");
+ snd_printk(KERN_ERR "FM Error: Patch record too short\n");
return -EINVAL;
}
if (copy_from_user(&sbi, buf, sizeof(sbi)))
return -EFAULT;
if (sbi.channel < 0 || sbi.channel >= SBFM_MAXINSTR) {
- snd_printk("FM Error: Invalid instrument number %d\n",
+ snd_printk(KERN_ERR "FM Error: Invalid instrument number %d\n",
sbi.channel);
return -EINVAL;
}
@@ -254,7 +254,9 @@ static int snd_opl3_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd,
opl3 = arg->private_data;
switch (cmd) {
case SNDCTL_FM_LOAD_INSTR:
- snd_printk("OPL3: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n");
+ snd_printk(KERN_ERR "OPL3: "
+ "Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. "
+ "Fix the program.\n");
return -EINVAL;
case SNDCTL_SYNTH_MEMAVL:
diff --git a/sound/drivers/opl3/opl3_synth.c b/sound/drivers/opl3/opl3_synth.c
index 962bb9c8b9c..6d57b6441de 100644
--- a/sound/drivers/opl3/opl3_synth.c
+++ b/sound/drivers/opl3/opl3_synth.c
@@ -168,7 +168,7 @@ int snd_opl3_ioctl(struct snd_hwdep * hw, struct file *file,
#ifdef CONFIG_SND_DEBUG
default:
- snd_printk("unknown IOCTL: 0x%x\n", cmd);
+ snd_printk(KERN_WARNING "unknown IOCTL: 0x%x\n", cmd);
#endif
}
return -ENOTTY;
diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c
index a4049eb94d3..b60cef257b5 100644
--- a/sound/drivers/pcsp/pcsp.c
+++ b/sound/drivers/pcsp/pcsp.c
@@ -57,7 +57,7 @@ static int __devinit snd_pcsp_create(struct snd_card *card)
else
min_div = MAX_DIV;
#if PCSP_DEBUG
- printk("PCSP: lpj=%li, min_div=%i, res=%li\n",
+ printk(KERN_DEBUG "PCSP: lpj=%li, min_div=%i, res=%li\n",
loops_per_jiffy, min_div, tp.tv_nsec);
#endif
@@ -98,9 +98,9 @@ static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev)
hrtimer_init(&pcsp_chip.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
pcsp_chip.timer.function = pcsp_do_timer;
- card = snd_card_new(index, id, THIS_MODULE, 0);
- if (!card)
- return -ENOMEM;
+ err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
err = snd_pcsp_create(card);
if (err < 0) {
diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c
index b1c047ec19a..60158e2e0ea 100644
--- a/sound/drivers/portman2x4.c
+++ b/sound/drivers/portman2x4.c
@@ -746,10 +746,10 @@ static int __devinit snd_portman_probe(struct platform_device *pdev)
if ((err = snd_portman_probe_port(p)) < 0)
return err;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL) {
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0) {
snd_printd("Cannot create card\n");
- return -ENOMEM;
+ return err;
}
strcpy(card->driver, DRIVER_NAME);
strcpy(card->shortname, CARD_NAME);
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
index d8aab9da97c..b2b6d50c942 100644
--- a/sound/drivers/serial-u16550.c
+++ b/sound/drivers/serial-u16550.c
@@ -241,7 +241,8 @@ static void snd_uart16550_io_loop(struct snd_uart16550 * uart)
snd_rawmidi_receive(uart->midi_input[substream], &c, 1);
if (status & UART_LSR_OE)
- snd_printk("%s: Overrun on device at 0x%lx\n",
+ snd_printk(KERN_WARNING
+ "%s: Overrun on device at 0x%lx\n",
uart->rmidi->name, uart->base);
}
@@ -636,7 +637,8 @@ static int snd_uart16550_output_byte(struct snd_uart16550 *uart,
}
} else {
if (!snd_uart16550_write_buffer(uart, midi_byte)) {
- snd_printk("%s: Buffer overrun on device at 0x%lx\n",
+ snd_printk(KERN_WARNING
+ "%s: Buffer overrun on device at 0x%lx\n",
uart->rmidi->name, uart->base);
return 0;
}
@@ -815,7 +817,8 @@ static int __devinit snd_uart16550_create(struct snd_card *card,
if (irq >= 0 && irq != SNDRV_AUTO_IRQ) {
if (request_irq(irq, snd_uart16550_interrupt,
IRQF_DISABLED, "Serial MIDI", uart)) {
- snd_printk("irq %d busy. Using Polling.\n", irq);
+ snd_printk(KERN_WARNING
+ "irq %d busy. Using Polling.\n", irq);
} else {
uart->irq = irq;
}
@@ -919,26 +922,29 @@ static int __devinit snd_serial_probe(struct platform_device *devptr)
case SNDRV_SERIAL_GENERIC:
break;
default:
- snd_printk("Adaptor type is out of range 0-%d (%d)\n",
+ snd_printk(KERN_ERR
+ "Adaptor type is out of range 0-%d (%d)\n",
SNDRV_SERIAL_MAX_ADAPTOR, adaptor[dev]);
return -ENODEV;
}
if (outs[dev] < 1 || outs[dev] > SNDRV_SERIAL_MAX_OUTS) {
- snd_printk("Count of outputs is out of range 1-%d (%d)\n",
+ snd_printk(KERN_ERR
+ "Count of outputs is out of range 1-%d (%d)\n",
SNDRV_SERIAL_MAX_OUTS, outs[dev]);
return -ENODEV;
}
if (ins[dev] < 1 || ins[dev] > SNDRV_SERIAL_MAX_INS) {
- snd_printk("Count of inputs is out of range 1-%d (%d)\n",
+ snd_printk(KERN_ERR
+ "Count of inputs is out of range 1-%d (%d)\n",
SNDRV_SERIAL_MAX_INS, ins[dev]);
return -ENODEV;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
strcpy(card->driver, "Serial");
strcpy(card->shortname, "Serial MIDI (UART16550A)");
diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c
index f79e3614079..0e631c3221e 100644
--- a/sound/drivers/virmidi.c
+++ b/sound/drivers/virmidi.c
@@ -90,15 +90,17 @@ static int __devinit snd_virmidi_probe(struct platform_device *devptr)
int idx, err;
int dev = devptr->id;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_virmidi));
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_virmidi), &card);
+ if (err < 0)
+ return err;
vmidi = (struct snd_card_virmidi *)card->private_data;
vmidi->card = card;
if (midi_devs[dev] > MAX_MIDI_DEVICES) {
- snd_printk("too much midi devices for virmidi %d: force to use %d\n", dev, MAX_MIDI_DEVICES);
+ snd_printk(KERN_WARNING
+ "too much midi devices for virmidi %d: "
+ "force to use %d\n", dev, MAX_MIDI_DEVICES);
midi_devs[dev] = MAX_MIDI_DEVICES;
}
for (idx = 0; idx < midi_devs[dev]; idx++) {
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
index 14e3354be43..19c6e376c7c 100644
--- a/sound/drivers/vx/vx_core.c
+++ b/sound/drivers/vx/vx_core.c
@@ -688,7 +688,8 @@ int snd_vx_dsp_load(struct vx_core *chip, const struct firmware *dsp)
image = dsp->data + i;
/* Wait DSP ready for a new read */
if ((err = vx_wait_isr_bit(chip, ISR_TX_EMPTY)) < 0) {
- printk("dsp loading error at position %d\n", i);
+ printk(KERN_ERR
+ "dsp loading error at position %d\n", i);
return err;
}
cptr = image;
diff --git a/sound/drivers/vx/vx_hwdep.c b/sound/drivers/vx/vx_hwdep.c
index 8d6362e2d4c..46df8817c18 100644
--- a/sound/drivers/vx/vx_hwdep.c
+++ b/sound/drivers/vx/vx_hwdep.c
@@ -119,16 +119,6 @@ void snd_vx_free_firmware(struct vx_core *chip)
#else /* old style firmware loading */
-static int vx_hwdep_open(struct snd_hwdep *hw, struct file *file)
-{
- return 0;
-}
-
-static int vx_hwdep_release(struct snd_hwdep *hw, struct file *file)
-{
- return 0;
-}
-
static int vx_hwdep_dsp_status(struct snd_hwdep *hw,
struct snd_hwdep_dsp_status *info)
{
@@ -243,8 +233,6 @@ int snd_vx_setup_firmware(struct vx_core *chip)
hw->iface = SNDRV_HWDEP_IFACE_VX;
hw->private_data = chip;
- hw->ops.open = vx_hwdep_open;
- hw->ops.release = vx_hwdep_release;
hw->ops.dsp_status = vx_hwdep_dsp_status;
hw->ops.dsp_load = vx_hwdep_dsp_load;
hw->exclusive = 1;
diff --git a/sound/drivers/vx/vx_uer.c b/sound/drivers/vx/vx_uer.c
index 0e1ba9b4790..b0560fec6bb 100644
--- a/sound/drivers/vx/vx_uer.c
+++ b/sound/drivers/vx/vx_uer.c
@@ -103,7 +103,7 @@ static void vx_write_one_cbit(struct vx_core *chip, int index, int val)
* returns the frequency of UER, or 0 if not sync,
* or a negative error code.
*/
-static int vx_read_uer_status(struct vx_core *chip, int *mode)
+static int vx_read_uer_status(struct vx_core *chip, unsigned int *mode)
{
int val, freq;
diff --git a/sound/i2c/Makefile b/sound/i2c/Makefile
index 37970666a45..36879bf8870 100644
--- a/sound/i2c/Makefile
+++ b/sound/i2c/Makefile
@@ -7,8 +7,6 @@ snd-i2c-objs := i2c.o
snd-cs8427-objs := cs8427.o
snd-tea6330t-objs := tea6330t.o
-obj-$(CONFIG_L3) += l3/
-
obj-$(CONFIG_SND) += other/
# Toplevel Module Dependency
diff --git a/sound/i2c/l3/Makefile b/sound/i2c/l3/Makefile
deleted file mode 100644
index 49455b8dcc0..00000000000
--- a/sound/i2c/l3/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Makefile for ALSA
-#
-
-snd-uda1341-objs := uda1341.o
-
-# Module Dependency
-obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-uda1341.o
diff --git a/sound/i2c/l3/uda1341.c b/sound/i2c/l3/uda1341.c
deleted file mode 100644
index 9840eb43648..00000000000
--- a/sound/i2c/l3/uda1341.c
+++ /dev/null
@@ -1,935 +0,0 @@
-/*
- * Philips UDA1341 mixer device driver
- * Copyright (c) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
- *
- * Portions are Copyright (C) 2000 Lernout & Hauspie Speech Products, N.V.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License.
- *
- * History:
- *
- * 2002-03-13 Tomas Kasparek initial release - based on uda1341.c from OSS
- * 2002-03-28 Tomas Kasparek basic mixer is working (volume, bass, treble)
- * 2002-03-30 Tomas Kasparek proc filesystem support, complete mixer and DSP
- * features support
- * 2002-04-12 Tomas Kasparek proc interface update, code cleanup
- * 2002-05-12 Tomas Kasparek another code cleanup
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/ioctl.h>
-
-#include <asm/uaccess.h>
-
-#include <sound/core.h>
-#include <sound/control.h>
-#include <sound/initval.h>
-#include <sound/info.h>
-
-#include <linux/l3/l3.h>
-
-#include <sound/uda1341.h>
-
-/* {{{ HW regs definition */
-
-#define STAT0 0x00
-#define STAT1 0x80
-#define STAT_MASK 0x80
-
-#define DATA0_0 0x00
-#define DATA0_1 0x40
-#define DATA0_2 0x80
-#define DATA_MASK 0xc0
-
-#define IS_DATA0(x) ((x) >= data0_0 && (x) <= data0_2)
-#define IS_DATA1(x) ((x) == data1)
-#define IS_STATUS(x) ((x) == stat0 || (x) == stat1)
-#define IS_EXTEND(x) ((x) >= ext0 && (x) <= ext6)
-
-/* }}} */
-
-
-static const char *peak_names[] = {
- "before",
- "after",
-};
-
-static const char *filter_names[] = {
- "flat",
- "min",
- "min",
- "max",
-};
-
-static const char *mixer_names[] = {
- "double differential",
- "input channel 1 (line in)",
- "input channel 2 (microphone)",
- "digital mixer",
-};
-
-static const char *deemp_names[] = {
- "none",
- "32 kHz",
- "44.1 kHz",
- "48 kHz",
-};
-
-enum uda1341_regs_names {
- stat0,
- stat1,
- data0_0,
- data0_1,
- data0_2,
- data1,
- ext0,
- ext1,
- ext2,
- empty,
- ext4,
- ext5,
- ext6,
- uda1341_reg_last,
-};
-
-static const char *uda1341_reg_names[] = {
- "stat 0 ",
- "stat 1 ",
- "data 00",
- "data 01",
- "data 02",
- "data 1 ",
- "ext 0",
- "ext 1",
- "ext 2",
- "empty",
- "ext 4",
- "ext 5",
- "ext 6",
-};
-
-static const int uda1341_enum_items[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 2, //peak - before/after
- 4, //deemp - none/32/44.1/48
- 0,
- 4, //filter - flat/min/min/max
- 0, 0, 0,
- 4, //mixer - differ/line/mic/mixer
- 0, 0, 0, 0, 0,
-};
-
-static const char ** uda1341_enum_names[] = {
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- peak_names, //peak - before/after
- deemp_names, //deemp - none/32/44.1/48
- NULL,
- filter_names, //filter - flat/min/min/max
- NULL, NULL, NULL,
- mixer_names, //mixer - differ/line/mic/mixer
- NULL, NULL, NULL, NULL, NULL,
-};
-
-typedef int uda1341_cfg[CMD_LAST];
-
-struct uda1341 {
- int (*write) (struct l3_client *uda1341, unsigned short reg, unsigned short val);
- int (*read) (struct l3_client *uda1341, unsigned short reg);
- unsigned char regs[uda1341_reg_last];
- int active;
- spinlock_t reg_lock;
- struct snd_card *card;
- uda1341_cfg cfg;
-#ifdef CONFIG_PM
- unsigned char suspend_regs[uda1341_reg_last];
- uda1341_cfg suspend_cfg;
-#endif
-};
-
-/* transfer 8bit integer into string with binary representation */
-static void int2str_bin8(uint8_t val, char *buf)
-{
- const int size = sizeof(val) * 8;
- int i;
-
- for (i= 0; i < size; i++){
- *(buf++) = (val >> (size - 1)) ? '1' : '0';
- val <<= 1;
- }
- *buf = '\0'; //end the string with zero
-}
-
-/* {{{ HW manipulation routines */
-
-static int snd_uda1341_codec_write(struct l3_client *clnt, unsigned short reg, unsigned short val)
-{
- struct uda1341 *uda = clnt->driver_data;
- unsigned char buf[2] = { 0xc0, 0xe0 }; // for EXT addressing
- int err = 0;
-
- uda->regs[reg] = val;
-
- if (uda->active) {
- if (IS_DATA0(reg)) {
- err = l3_write(clnt, UDA1341_DATA0, (const unsigned char *)&val, 1);
- } else if (IS_DATA1(reg)) {
- err = l3_write(clnt, UDA1341_DATA1, (const unsigned char *)&val, 1);
- } else if (IS_STATUS(reg)) {
- err = l3_write(clnt, UDA1341_STATUS, (const unsigned char *)&val, 1);
- } else if (IS_EXTEND(reg)) {
- buf[0] |= (reg - ext0) & 0x7; //EXT address
- buf[1] |= val; //EXT data
- err = l3_write(clnt, UDA1341_DATA0, (const unsigned char *)buf, 2);
- }
- } else
- printk(KERN_ERR "UDA1341 codec not active!\n");
- return err;
-}
-
-static int snd_uda1341_codec_read(struct l3_client *clnt, unsigned short reg)
-{
- unsigned char val;
- int err;
-
- err = l3_read(clnt, reg, &val, 1);
- if (err == 1)
- // use just 6bits - the rest is address of the reg
- return val & 63;
- return err < 0 ? err : -EIO;
-}
-
-static inline int snd_uda1341_valid_reg(struct l3_client *clnt, unsigned short reg)
-{
- return reg < uda1341_reg_last;
-}
-
-static int snd_uda1341_update_bits(struct l3_client *clnt, unsigned short reg,
- unsigned short mask, unsigned short shift,
- unsigned short value, int flush)
-{
- int change;
- unsigned short old, new;
- struct uda1341 *uda = clnt->driver_data;
-
-#if 0
- printk(KERN_DEBUG "update_bits: reg: %s mask: %d shift: %d val: %d\n",
- uda1341_reg_names[reg], mask, shift, value);
-#endif
-
- if (!snd_uda1341_valid_reg(clnt, reg))
- return -EINVAL;
- spin_lock(&uda->reg_lock);
- old = uda->regs[reg];
- new = (old & ~(mask << shift)) | (value << shift);
- change = old != new;
- if (change) {
- if (flush) uda->write(clnt, reg, new);
- uda->regs[reg] = new;
- }
- spin_unlock(&uda->reg_lock);
- return change;
-}
-
-static int snd_uda1341_cfg_write(struct l3_client *clnt, unsigned short what,
- unsigned short value, int flush)
-{
- struct uda1341 *uda = clnt->driver_data;
- int ret = 0;
-#ifdef CONFIG_PM
- int reg;
-#endif
-
-#if 0
- printk(KERN_DEBUG "cfg_write what: %d value: %d\n", what, value);
-#endif
-
- uda->cfg[what] = value;
-
- switch(what) {
- case CMD_RESET:
- ret = snd_uda1341_update_bits(clnt, data0_2, 1, 2, 1, flush); // MUTE
- ret = snd_uda1341_update_bits(clnt, stat0, 1, 6, 1, flush); // RESET
- ret = snd_uda1341_update_bits(clnt, stat0, 1, 6, 0, flush); // RESTORE
- uda->cfg[CMD_RESET]=0;
- break;
- case CMD_FS:
- ret = snd_uda1341_update_bits(clnt, stat0, 3, 4, value, flush);
- break;
- case CMD_FORMAT:
- ret = snd_uda1341_update_bits(clnt, stat0, 7, 1, value, flush);
- break;
- case CMD_OGAIN:
- ret = snd_uda1341_update_bits(clnt, stat1, 1, 6, value, flush);
- break;
- case CMD_IGAIN:
- ret = snd_uda1341_update_bits(clnt, stat1, 1, 5, value, flush);
- break;
- case CMD_DAC:
- ret = snd_uda1341_update_bits(clnt, stat1, 1, 0, value, flush);
- break;
- case CMD_ADC:
- ret = snd_uda1341_update_bits(clnt, stat1, 1, 1, value, flush);
- break;
- case CMD_VOLUME:
- ret = snd_uda1341_update_bits(clnt, data0_0, 63, 0, value, flush);
- break;
- case CMD_BASS:
- ret = snd_uda1341_update_bits(clnt, data0_1, 15, 2, value, flush);
- break;
- case CMD_TREBBLE:
- ret = snd_uda1341_update_bits(clnt, data0_1, 3, 0, value, flush);
- break;
- case CMD_PEAK:
- ret = snd_uda1341_update_bits(clnt, data0_2, 1, 5, value, flush);
- break;
- case CMD_DEEMP:
- ret = snd_uda1341_update_bits(clnt, data0_2, 3, 3, value, flush);
- break;
- case CMD_MUTE:
- ret = snd_uda1341_update_bits(clnt, data0_2, 1, 2, value, flush);
- break;
- case CMD_FILTER:
- ret = snd_uda1341_update_bits(clnt, data0_2, 3, 0, value, flush);
- break;
- case CMD_CH1:
- ret = snd_uda1341_update_bits(clnt, ext0, 31, 0, value, flush);
- break;
- case CMD_CH2:
- ret = snd_uda1341_update_bits(clnt, ext1, 31, 0, value, flush);
- break;
- case CMD_MIC:
- ret = snd_uda1341_update_bits(clnt, ext2, 7, 2, value, flush);
- break;
- case CMD_MIXER:
- ret = snd_uda1341_update_bits(clnt, ext2, 3, 0, value, flush);
- break;
- case CMD_AGC:
- ret = snd_uda1341_update_bits(clnt, ext4, 1, 4, value, flush);
- break;
- case CMD_IG:
- ret = snd_uda1341_update_bits(clnt, ext4, 3, 0, value & 0x3, flush);
- ret = snd_uda1341_update_bits(clnt, ext5, 31, 0, value >> 2, flush);
- break;
- case CMD_AGC_TIME:
- ret = snd_uda1341_update_bits(clnt, ext6, 7, 2, value, flush);
- break;
- case CMD_AGC_LEVEL:
- ret = snd_uda1341_update_bits(clnt, ext6, 3, 0, value, flush);
- break;
-#ifdef CONFIG_PM
- case CMD_SUSPEND:
- for (reg = stat0; reg < uda1341_reg_last; reg++)
- uda->suspend_regs[reg] = uda->regs[reg];
- for (reg = 0; reg < CMD_LAST; reg++)
- uda->suspend_cfg[reg] = uda->cfg[reg];
- break;
- case CMD_RESUME:
- for (reg = stat0; reg < uda1341_reg_last; reg++)
- snd_uda1341_codec_write(clnt, reg, uda->suspend_regs[reg]);
- for (reg = 0; reg < CMD_LAST; reg++)
- uda->cfg[reg] = uda->suspend_cfg[reg];
- break;
-#endif
- default:
- ret = -EINVAL;
- break;
- }
-
- if (!uda->active)
- printk(KERN_ERR "UDA1341 codec not active!\n");
- return ret;
-}
-
-/* }}} */
-
-/* {{{ Proc interface */
-#ifdef CONFIG_PROC_FS
-
-static const char *format_names[] = {
- "I2S-bus",
- "LSB 16bits",
- "LSB 18bits",
- "LSB 20bits",
- "MSB",
- "in LSB 16bits/out MSB",
- "in LSB 18bits/out MSB",
- "in LSB 20bits/out MSB",
-};
-
-static const char *fs_names[] = {
- "512*fs",
- "384*fs",
- "256*fs",
- "Unused - bad value!",
-};
-
-static const char* bass_values[][16] = {
- {"0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB", "0 dB",
- "0 dB", "0 dB", "0 dB", "0 dB", "undefined", }, //flat
- {"0 dB", "2 dB", "4 dB", "6 dB", "8 dB", "10 dB", "12 dB", "14 dB", "16 dB", "18 dB", "18 dB",
- "18 dB", "18 dB", "18 dB", "18 dB", "undefined",}, // min
- {"0 dB", "2 dB", "4 dB", "6 dB", "8 dB", "10 dB", "12 dB", "14 dB", "16 dB", "18 dB", "18 dB",
- "18 dB", "18 dB", "18 dB", "18 dB", "undefined",}, // min
- {"0 dB", "2 dB", "4 dB", "6 dB", "8 dB", "10 dB", "12 dB", "14 dB", "16 dB", "18 dB", "20 dB",
- "22 dB", "24 dB", "24 dB", "24 dB", "undefined",}, // max
-};
-
-static const char *mic_sens_value[] = {
- "-3 dB", "0 dB", "3 dB", "9 dB", "15 dB", "21 dB", "27 dB", "not used",
-};
-
-static const unsigned short AGC_atime[] = {
- 11, 16, 11, 16, 21, 11, 16, 21,
-};
-
-static const unsigned short AGC_dtime[] = {
- 100, 100, 200, 200, 200, 400, 400, 400,
-};
-
-static const char *AGC_level[] = {
- "-9.0", "-11.5", "-15.0", "-17.5",
-};
-
-static const char *ig_small_value[] = {
- "-3.0", "-2.5", "-2.0", "-1.5", "-1.0", "-0.5",
-};
-
-/*
- * this was computed as peak_value[i] = pow((63-i)*1.42,1.013)
- *
- * UDA1341 datasheet on page 21: Peak value (dB) = (Peak level - 63.5)*5*log2
- * There is an table with these values [level]=value: [3]=-90.31, [7]=-84.29
- * [61]=-2.78, [62] = -1.48, [63] = 0.0
- * I tried to compute it, but using but even using logarithm with base either 10 or 2
- * i was'n able to get values in the table from the formula. So I constructed another
- * formula (see above) to interpolate the values as good as possible. If there is some
- * mistake, please contact me on tomas.kasparek@seznam.cz. Thanks.
- * UDA1341TS datasheet is available at:
- * http://www-us9.semiconductors.com/acrobat/datasheets/UDA1341TS_3.pdf
- */
-static const char *peak_value[] = {
- "-INF dB", "N.A.", "N.A", "90.31 dB", "N.A.", "N.A.", "N.A.", "-84.29 dB",
- "-82.65 dB", "-81.13 dB", "-79.61 dB", "-78.09 dB", "-76.57 dB", "-75.05 dB", "-73.53 dB",
- "-72.01 dB", "-70.49 dB", "-68.97 dB", "-67.45 dB", "-65.93 dB", "-64.41 dB", "-62.90 dB",
- "-61.38 dB", "-59.86 dB", "-58.35 dB", "-56.83 dB", "-55.32 dB", "-53.80 dB", "-52.29 dB",
- "-50.78 dB", "-49.26 dB", "-47.75 dB", "-46.24 dB", "-44.73 dB", "-43.22 dB", "-41.71 dB",
- "-40.20 dB", "-38.69 dB", "-37.19 dB", "-35.68 dB", "-34.17 dB", "-32.67 dB", "-31.17 dB",
- "-29.66 dB", "-28.16 dB", "-26.66 dB", "-25.16 dB", "-23.66 dB", "-22.16 dB", "-20.67 dB",
- "-19.17 dB", "-17.68 dB", "-16.19 dB", "-14.70 dB", "-13.21 dB", "-11.72 dB", "-10.24 dB",
- "-8.76 dB", "-7.28 dB", "-5.81 dB", "-4.34 dB", "-2.88 dB", "-1.43 dB", "0.00 dB",
-};
-
-static void snd_uda1341_proc_read(struct snd_info_entry *entry,
- struct snd_info_buffer *buffer)
-{
- struct l3_client *clnt = entry->private_data;
- struct uda1341 *uda = clnt->driver_data;
- int peak;
-
- peak = snd_uda1341_codec_read(clnt, UDA1341_DATA1);
- if (peak < 0)
- peak = 0;
-
- snd_iprintf(buffer, "%s\n\n", uda->card->longname);
-
- // for information about computed values see UDA1341TS datasheet pages 15 - 21
- snd_iprintf(buffer, "DAC power : %s\n", uda->cfg[CMD_DAC] ? "on" : "off");
- snd_iprintf(buffer, "ADC power : %s\n", uda->cfg[CMD_ADC] ? "on" : "off");
- snd_iprintf(buffer, "Clock frequency : %s\n", fs_names[uda->cfg[CMD_FS]]);
- snd_iprintf(buffer, "Data format : %s\n\n", format_names[uda->cfg[CMD_FORMAT]]);
-
- snd_iprintf(buffer, "Filter mode : %s\n", filter_names[uda->cfg[CMD_FILTER]]);
- snd_iprintf(buffer, "Mixer mode : %s\n", mixer_names[uda->cfg[CMD_MIXER]]);
- snd_iprintf(buffer, "De-emphasis : %s\n", deemp_names[uda->cfg[CMD_DEEMP]]);
- snd_iprintf(buffer, "Peak detection pos. : %s\n", uda->cfg[CMD_PEAK] ? "after" : "before");
- snd_iprintf(buffer, "Peak value : %s\n\n", peak_value[peak]);
-
- snd_iprintf(buffer, "Automatic Gain Ctrl : %s\n", uda->cfg[CMD_AGC] ? "on" : "off");
- snd_iprintf(buffer, "AGC attack time : %d ms\n", AGC_atime[uda->cfg[CMD_AGC_TIME]]);
- snd_iprintf(buffer, "AGC decay time : %d ms\n", AGC_dtime[uda->cfg[CMD_AGC_TIME]]);
- snd_iprintf(buffer, "AGC output level : %s dB\n\n", AGC_level[uda->cfg[CMD_AGC_LEVEL]]);
-
- snd_iprintf(buffer, "Mute : %s\n", uda->cfg[CMD_MUTE] ? "on" : "off");
-
- if (uda->cfg[CMD_VOLUME] == 0)
- snd_iprintf(buffer, "Volume : 0 dB\n");
- else if (uda->cfg[CMD_VOLUME] < 62)
- snd_iprintf(buffer, "Volume : %d dB\n", -1*uda->cfg[CMD_VOLUME] +1);
- else
- snd_iprintf(buffer, "Volume : -INF dB\n");
- snd_iprintf(buffer, "Bass : %s\n", bass_values[uda->cfg[CMD_FILTER]][uda->cfg[CMD_BASS]]);
- snd_iprintf(buffer, "Trebble : %d dB\n", uda->cfg[CMD_FILTER] ? 2*uda->cfg[CMD_TREBBLE] : 0);
- snd_iprintf(buffer, "Input Gain (6dB) : %s\n", uda->cfg[CMD_IGAIN] ? "on" : "off");
- snd_iprintf(buffer, "Output Gain (6dB) : %s\n", uda->cfg[CMD_OGAIN] ? "on" : "off");
- snd_iprintf(buffer, "Mic sensitivity : %s\n", mic_sens_value[uda->cfg[CMD_MIC]]);
-
-
- if(uda->cfg[CMD_CH1] < 31)
- snd_iprintf(buffer, "Mixer gain channel 1: -%d.%c dB\n",
- ((uda->cfg[CMD_CH1] >> 1) * 3) + (uda->cfg[CMD_CH1] & 1),
- uda->cfg[CMD_CH1] & 1 ? '5' : '0');
- else
- snd_iprintf(buffer, "Mixer gain channel 1: -INF dB\n");
- if(uda->cfg[CMD_CH2] < 31)
- snd_iprintf(buffer, "Mixer gain channel 2: -%d.%c dB\n",
- ((uda->cfg[CMD_CH2] >> 1) * 3) + (uda->cfg[CMD_CH2] & 1),
- uda->cfg[CMD_CH2] & 1 ? '5' : '0');
- else
- snd_iprintf(buffer, "Mixer gain channel 2: -INF dB\n");
-
- if(uda->cfg[CMD_IG] > 5)
- snd_iprintf(buffer, "Input Amp. Gain ch 2: %d.%c dB\n",
- (uda->cfg[CMD_IG] >> 1) -3, uda->cfg[CMD_IG] & 1 ? '5' : '0');
- else
- snd_iprintf(buffer, "Input Amp. Gain ch 2: %s dB\n", ig_small_value[uda->cfg[CMD_IG]]);
-}
-
-static void snd_uda1341_proc_regs_read(struct snd_info_entry *entry,
- struct snd_info_buffer *buffer)
-{
- struct l3_client *clnt = entry->private_data;
- struct uda1341 *uda = clnt->driver_data;
- int reg;
- char buf[12];
-
- for (reg = 0; reg < uda1341_reg_last; reg ++) {
- if (reg == empty)
- continue;
- int2str_bin8(uda->regs[reg], buf);
- snd_iprintf(buffer, "%s = %s\n", uda1341_reg_names[reg], buf);
- }
-
- int2str_bin8(snd_uda1341_codec_read(clnt, UDA1341_DATA1), buf);
- snd_iprintf(buffer, "DATA1 = %s\n", buf);
-}
-#endif /* CONFIG_PROC_FS */
-
-static void __devinit snd_uda1341_proc_init(struct snd_card *card, struct l3_client *clnt)
-{
- struct snd_info_entry *entry;
-
- if (! snd_card_proc_new(card, "uda1341", &entry))
- snd_info_set_text_ops(entry, clnt, snd_uda1341_proc_read);
- if (! snd_card_proc_new(card, "uda1341-regs", &entry))
- snd_info_set_text_ops(entry, clnt, snd_uda1341_proc_regs_read);
-}
-
-/* }}} */
-
-/* {{{ Mixer controls setting */
-
-/* {{{ UDA1341 single functions */
-
-#define UDA1341_SINGLE(xname, where, reg, shift, mask, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_uda1341_info_single, \
- .get = snd_uda1341_get_single, .put = snd_uda1341_put_single, \
- .private_value = where | (reg << 5) | (shift << 9) | (mask << 12) | (invert << 18) \
-}
-
-static int snd_uda1341_info_single(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- int mask = (kcontrol->private_value >> 12) & 63;
-
- uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = mask;
- return 0;
-}
-
-static int snd_uda1341_get_single(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct l3_client *clnt = snd_kcontrol_chip(kcontrol);
- struct uda1341 *uda = clnt->driver_data;
- int where = kcontrol->private_value & 31;
- int mask = (kcontrol->private_value >> 12) & 63;
- int invert = (kcontrol->private_value >> 18) & 1;
-
- ucontrol->value.integer.value[0] = uda->cfg[where];
- if (invert)
- ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
-
- return 0;
-}
-
-static int snd_uda1341_put_single(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct l3_client *clnt = snd_kcontrol_chip(kcontrol);
- struct uda1341 *uda = clnt->driver_data;
- int where = kcontrol->private_value & 31;
- int reg = (kcontrol->private_value >> 5) & 15;
- int shift = (kcontrol->private_value >> 9) & 7;
- int mask = (kcontrol->private_value >> 12) & 63;
- int invert = (kcontrol->private_value >> 18) & 1;
- unsigned short val;
-
- val = (ucontrol->value.integer.value[0] & mask);
- if (invert)
- val = mask - val;
-
- uda->cfg[where] = val;
- return snd_uda1341_update_bits(clnt, reg, mask, shift, val, FLUSH);
-}
-
-/* }}} */
-
-/* {{{ UDA1341 enum functions */
-
-#define UDA1341_ENUM(xname, where, reg, shift, mask, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_uda1341_info_enum, \
- .get = snd_uda1341_get_enum, .put = snd_uda1341_put_enum, \
- .private_value = where | (reg << 5) | (shift << 9) | (mask << 12) | (invert << 18) \
-}
-
-static int snd_uda1341_info_enum(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- int where = kcontrol->private_value & 31;
- const char **texts;
-
- // this register we don't handle this way
- if (!uda1341_enum_items[where])
- return -EINVAL;
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = uda1341_enum_items[where];
-
- if (uinfo->value.enumerated.item >= uda1341_enum_items[where])
- uinfo->value.enumerated.item = uda1341_enum_items[where] - 1;
-
- texts = uda1341_enum_names[where];
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
-}
-
-static int snd_uda1341_get_enum(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct l3_client *clnt = snd_kcontrol_chip(kcontrol);
- struct uda1341 *uda = clnt->driver_data;
- int where = kcontrol->private_value & 31;
-
- ucontrol->value.enumerated.item[0] = uda->cfg[where];
- return 0;
-}
-
-static int snd_uda1341_put_enum(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct l3_client *clnt = snd_kcontrol_chip(kcontrol);
- struct uda1341 *uda = clnt->driver_data;
- int where = kcontrol->private_value & 31;
- int reg = (kcontrol->private_value >> 5) & 15;
- int shift = (kcontrol->private_value >> 9) & 7;
- int mask = (kcontrol->private_value >> 12) & 63;
-
- uda->cfg[where] = (ucontrol->value.enumerated.item[0] & mask);
-
- return snd_uda1341_update_bits(clnt, reg, mask, shift, uda->cfg[where], FLUSH);
-}
-
-/* }}} */
-
-/* {{{ UDA1341 2regs functions */
-
-#define UDA1341_2REGS(xname, where, reg_1, reg_2, shift_1, shift_2, mask_1, mask_2, invert) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), .info = snd_uda1341_info_2regs, \
- .get = snd_uda1341_get_2regs, .put = snd_uda1341_put_2regs, \
- .private_value = where | (reg_1 << 5) | (reg_2 << 9) | (shift_1 << 13) | (shift_2 << 16) | \
- (mask_1 << 19) | (mask_2 << 25) | (invert << 31) \
-}
-
-
-static int snd_uda1341_info_2regs(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- int mask_1 = (kcontrol->private_value >> 19) & 63;
- int mask_2 = (kcontrol->private_value >> 25) & 63;
- int mask;
-
- mask = (mask_2 + 1) * (mask_1 + 1) - 1;
- uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = mask;
- return 0;
-}
-
-static int snd_uda1341_get_2regs(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct l3_client *clnt = snd_kcontrol_chip(kcontrol);
- struct uda1341 *uda = clnt->driver_data;
- int where = kcontrol->private_value & 31;
- int mask_1 = (kcontrol->private_value >> 19) & 63;
- int mask_2 = (kcontrol->private_value >> 25) & 63;
- int invert = (kcontrol->private_value >> 31) & 1;
- int mask;
-
- mask = (mask_2 + 1) * (mask_1 + 1) - 1;
-
- ucontrol->value.integer.value[0] = uda->cfg[where];
- if (invert)
- ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
- return 0;
-}
-
-static int snd_uda1341_put_2regs(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct l3_client *clnt = snd_kcontrol_chip(kcontrol);
- struct uda1341 *uda = clnt->driver_data;
- int where = kcontrol->private_value & 31;
- int reg_1 = (kcontrol->private_value >> 5) & 15;
- int reg_2 = (kcontrol->private_value >> 9) & 15;
- int shift_1 = (kcontrol->private_value >> 13) & 7;
- int shift_2 = (kcontrol->private_value >> 16) & 7;
- int mask_1 = (kcontrol->private_value >> 19) & 63;
- int mask_2 = (kcontrol->private_value >> 25) & 63;
- int invert = (kcontrol->private_value >> 31) & 1;
- int mask;
- unsigned short val1, val2, val;
-
- val = ucontrol->value.integer.value[0];
-
- mask = (mask_2 + 1) * (mask_1 + 1) - 1;
-
- val1 = val & mask_1;
- val2 = (val / (mask_1 + 1)) & mask_2;
-
- if (invert) {
- val1 = mask_1 - val1;
- val2 = mask_2 - val2;
- }
-
- uda->cfg[where] = invert ? mask - val : val;
-
- //FIXME - return value
- snd_uda1341_update_bits(clnt, reg_1, mask_1, shift_1, val1, FLUSH);
- return snd_uda1341_update_bits(clnt, reg_2, mask_2, shift_2, val2, FLUSH);
-}
-
-/* }}} */
-
-static struct snd_kcontrol_new snd_uda1341_controls[] = {
- UDA1341_SINGLE("Master Playback Switch", CMD_MUTE, data0_2, 2, 1, 1),
- UDA1341_SINGLE("Master Playback Volume", CMD_VOLUME, data0_0, 0, 63, 1),
-
- UDA1341_SINGLE("Bass Playback Volume", CMD_BASS, data0_1, 2, 15, 0),
- UDA1341_SINGLE("Treble Playback Volume", CMD_TREBBLE, data0_1, 0, 3, 0),
-
- UDA1341_SINGLE("Input Gain Switch", CMD_IGAIN, stat1, 5, 1, 0),
- UDA1341_SINGLE("Output Gain Switch", CMD_OGAIN, stat1, 6, 1, 0),
-
- UDA1341_SINGLE("Mixer Gain Channel 1 Volume", CMD_CH1, ext0, 0, 31, 1),
- UDA1341_SINGLE("Mixer Gain Channel 2 Volume", CMD_CH2, ext1, 0, 31, 1),
-
- UDA1341_SINGLE("Mic Sensitivity Volume", CMD_MIC, ext2, 2, 7, 0),
-
- UDA1341_SINGLE("AGC Output Level", CMD_AGC_LEVEL, ext6, 0, 3, 0),
- UDA1341_SINGLE("AGC Time Constant", CMD_AGC_TIME, ext6, 2, 7, 0),
- UDA1341_SINGLE("AGC Time Constant Switch", CMD_AGC, ext4, 4, 1, 0),
-
- UDA1341_SINGLE("DAC Power", CMD_DAC, stat1, 0, 1, 0),
- UDA1341_SINGLE("ADC Power", CMD_ADC, stat1, 1, 1, 0),
-
- UDA1341_ENUM("Peak detection", CMD_PEAK, data0_2, 5, 1, 0),
- UDA1341_ENUM("De-emphasis", CMD_DEEMP, data0_2, 3, 3, 0),
- UDA1341_ENUM("Mixer mode", CMD_MIXER, ext2, 0, 3, 0),
- UDA1341_ENUM("Filter mode", CMD_FILTER, data0_2, 0, 3, 0),
-
- UDA1341_2REGS("Gain Input Amplifier Gain (channel 2)", CMD_IG, ext4, ext5, 0, 0, 3, 31, 0),
-};
-
-static void uda1341_free(struct l3_client *clnt)
-{
- l3_detach_client(clnt); // calls kfree for driver_data (struct uda1341)
- kfree(clnt);
-}
-
-static int uda1341_dev_free(struct snd_device *device)
-{
- struct l3_client *clnt = device->device_data;
- uda1341_free(clnt);
- return 0;
-}
-
-int __init snd_chip_uda1341_mixer_new(struct snd_card *card, struct l3_client **clntp)
-{
- static struct snd_device_ops ops = {
- .dev_free = uda1341_dev_free,
- };
- struct l3_client *clnt;
- int idx, err;
-
- if (snd_BUG_ON(!card))
- return -EINVAL;
-
- clnt = kzalloc(sizeof(*clnt), GFP_KERNEL);
- if (clnt == NULL)
- return -ENOMEM;
-
- if ((err = l3_attach_client(clnt, "l3-bit-sa1100-gpio", UDA1341_ALSA_NAME))) {
- kfree(clnt);
- return err;
- }
-
- for (idx = 0; idx < ARRAY_SIZE(snd_uda1341_controls); idx++) {
- if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_uda1341_controls[idx], clnt))) < 0) {
- uda1341_free(clnt);
- return err;
- }
- }
-
- if ((err = snd_device_new(card, SNDRV_DEV_CODEC, clnt, &ops)) < 0) {
- uda1341_free(clnt);
- return err;
- }
-
- *clntp = clnt;
- strcpy(card->mixername, "UDA1341TS Mixer");
- ((struct uda1341 *)clnt->driver_data)->card = card;
-
- snd_uda1341_proc_init(card, clnt);
-
- return 0;
-}
-
-/* }}} */
-
-/* {{{ L3 operations */
-
-static int uda1341_attach(struct l3_client *clnt)
-{
- struct uda1341 *uda;
-
- uda = kzalloc(sizeof(*uda), 0, GFP_KERNEL);
- if (!uda)
- return -ENOMEM;
-
- /* init fixed parts of my copy of registers */
- uda->regs[stat0] = STAT0;
- uda->regs[stat1] = STAT1;
-
- uda->regs[data0_0] = DATA0_0;
- uda->regs[data0_1] = DATA0_1;
- uda->regs[data0_2] = DATA0_2;
-
- uda->write = snd_uda1341_codec_write;
- uda->read = snd_uda1341_codec_read;
-
- spin_lock_init(&uda->reg_lock);
-
- clnt->driver_data = uda;
- return 0;
-}
-
-static void uda1341_detach(struct l3_client *clnt)
-{
- kfree(clnt->driver_data);
-}
-
-static int
-uda1341_command(struct l3_client *clnt, int cmd, void *arg)
-{
- if (cmd != CMD_READ_REG)
- return snd_uda1341_cfg_write(clnt, cmd, (int) arg, FLUSH);
-
- return snd_uda1341_codec_read(clnt, (int) arg);
-}
-
-static int uda1341_open(struct l3_client *clnt)
-{
- struct uda1341 *uda = clnt->driver_data;
-
- uda->active = 1;
-
- /* init default configuration */
- snd_uda1341_cfg_write(clnt, CMD_RESET, 0, REGS_ONLY);
- snd_uda1341_cfg_write(clnt, CMD_FS, F256, FLUSH); // unknown state after reset
- snd_uda1341_cfg_write(clnt, CMD_FORMAT, LSB16, FLUSH); // unknown state after reset
- snd_uda1341_cfg_write(clnt, CMD_OGAIN, ON, FLUSH); // default off after reset
- snd_uda1341_cfg_write(clnt, CMD_IGAIN, ON, FLUSH); // default off after reset
- snd_uda1341_cfg_write(clnt, CMD_DAC, ON, FLUSH); // ??? default value after reset
- snd_uda1341_cfg_write(clnt, CMD_ADC, ON, FLUSH); // ??? default value after reset
- snd_uda1341_cfg_write(clnt, CMD_VOLUME, 20, FLUSH); // default 0dB after reset
- snd_uda1341_cfg_write(clnt, CMD_BASS, 0, REGS_ONLY); // default value after reset
- snd_uda1341_cfg_write(clnt, CMD_TREBBLE, 0, REGS_ONLY); // default value after reset
- snd_uda1341_cfg_write(clnt, CMD_PEAK, AFTER, REGS_ONLY);// default value after reset
- snd_uda1341_cfg_write(clnt, CMD_DEEMP, NONE, REGS_ONLY);// default value after reset
- //at this moment should be QMUTED by h3600_audio_init
- snd_uda1341_cfg_write(clnt, CMD_MUTE, OFF, REGS_ONLY); // default value after reset
- snd_uda1341_cfg_write(clnt, CMD_FILTER, MAX, FLUSH); // defaul flat after reset
- snd_uda1341_cfg_write(clnt, CMD_CH1, 31, FLUSH); // default value after reset
- snd_uda1341_cfg_write(clnt, CMD_CH2, 4, FLUSH); // default value after reset
- snd_uda1341_cfg_write(clnt, CMD_MIC, 4, FLUSH); // default 0dB after reset
- snd_uda1341_cfg_write(clnt, CMD_MIXER, MIXER, FLUSH); // default doub.dif.mode
- snd_uda1341_cfg_write(clnt, CMD_AGC, OFF, FLUSH); // default value after reset
- snd_uda1341_cfg_write(clnt, CMD_IG, 0, FLUSH); // unknown state after reset
- snd_uda1341_cfg_write(clnt, CMD_AGC_TIME, 0, FLUSH); // default value after reset
- snd_uda1341_cfg_write(clnt, CMD_AGC_LEVEL, 0, FLUSH); // default value after reset
-
- return 0;
-}
-
-static void uda1341_close(struct l3_client *clnt)
-{
- struct uda1341 *uda = clnt->driver_data;
-
- uda->active = 0;
-}
-
-/* }}} */
-
-/* {{{ Module and L3 initialization */
-
-static struct l3_ops uda1341_ops = {
- .open = uda1341_open,
- .command = uda1341_command,
- .close = uda1341_close,
-};
-
-static struct l3_driver uda1341_driver = {
- .name = UDA1341_ALSA_NAME,
- .attach_client = uda1341_attach,
- .detach_client = uda1341_detach,
- .ops = &uda1341_ops,
- .owner = THIS_MODULE,
-};
-
-static int __init uda1341_init(void)
-{
- return l3_add_driver(&uda1341_driver);
-}
-
-static void __exit uda1341_exit(void)
-{
- l3_del_driver(&uda1341_driver);
-}
-
-module_init(uda1341_init);
-module_exit(uda1341_exit);
-
-MODULE_AUTHOR("Tomas Kasparek <tomas.kasparek@seznam.cz>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Philips UDA1341 CODEC driver for ALSA");
-MODULE_SUPPORTED_DEVICE("{{UDA1341,UDA1341TS}}");
-
-EXPORT_SYMBOL(snd_chip_uda1341_mixer_new);
-
-/* }}} */
-
-/*
- * Local variables:
- * indent-tabs-mode: t
- * End:
- */
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index ce0aa044e27..4e06bbd9298 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -56,8 +56,8 @@ config SND_AD1848
Say Y here to include support for AD1848 (Analog Devices) or
CS4248 (Cirrus Logic - Crystal Semiconductors) chips.
- For newer chips from Cirrus Logic, use the CS4231, CS4232 or
- CS4236+ drivers.
+ For newer chips from Cirrus Logic, use the CS4231 or CS4232+
+ drivers.
To compile this driver as a module, choose M here: the module
will be called snd-ad1848.
@@ -94,6 +94,8 @@ config SND_CMI8330
tristate "C-Media CMI8330"
select SND_WSS_LIB
select SND_SB16_DSP
+ select SND_OPL3_LIB
+ select SND_MPU401_UART
help
Say Y here to include support for soundcards based on the
C-Media CMI8330 chip.
@@ -112,26 +114,15 @@ config SND_CS4231
To compile this driver as a module, choose M here: the module
will be called snd-cs4231.
-config SND_CS4232
- tristate "Generic Cirrus Logic CS4232 driver"
- select SND_OPL3_LIB
- select SND_MPU401_UART
- select SND_WSS_LIB
- help
- Say Y here to include support for CS4232 chips from Cirrus
- Logic - Crystal Semiconductors.
-
- To compile this driver as a module, choose M here: the module
- will be called snd-cs4232.
-
config SND_CS4236
- tristate "Generic Cirrus Logic CS4236+ driver"
+ tristate "Generic Cirrus Logic CS4232/CS4236+ driver"
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_WSS_LIB
help
- Say Y to include support for CS4235,CS4236,CS4237B,CS4238B,
- CS4239 chips from Cirrus Logic - Crystal Semiconductors.
+ Say Y to include support for CS4232,CS4235,CS4236,CS4237B,
+ CS4238B,CS4239 chips from Cirrus Logic - Crystal
+ Semiconductors.
To compile this driver as a module, choose M here: the module
will be called snd-cs4236.
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c
index 77524244a84..bbcbf92a8eb 100644
--- a/sound/isa/ad1816a/ad1816a.c
+++ b/sound/isa/ad1816a/ad1816a.c
@@ -156,10 +156,12 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
struct snd_card_ad1816a *acard;
struct snd_ad1816a *chip;
struct snd_opl3 *opl3;
+ struct snd_timer *timer;
- if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_ad1816a))) == NULL)
- return -ENOMEM;
+ error = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_ad1816a), &card);
+ if (error < 0)
+ return error;
acard = (struct snd_card_ad1816a *)card->private_data;
if ((error = snd_card_ad1816a_pnp(dev, acard, pcard, pid))) {
@@ -194,6 +196,12 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
return error;
}
+ error = snd_ad1816a_timer(chip, 0, &timer);
+ if (error < 0) {
+ snd_card_free(card);
+ return error;
+ }
+
if (mpu_port[dev] > 0) {
if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
mpu_port[dev], 0, mpu_irq[dev], IRQF_DISABLED,
@@ -207,11 +215,8 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
OPL3_HW_AUTO, 0, &opl3) < 0) {
printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx.\n", fm_port[dev], fm_port[dev] + 2);
} else {
- if ((error = snd_opl3_timer_new(opl3, 1, 2)) < 0) {
- snd_card_free(card);
- return error;
- }
- if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
+ error = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+ if (error < 0) {
snd_card_free(card);
return error;
}
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
index 3bfca7c59ba..05aef8b97e9 100644
--- a/sound/isa/ad1816a/ad1816a_lib.c
+++ b/sound/isa/ad1816a/ad1816a_lib.c
@@ -37,7 +37,7 @@ static inline int snd_ad1816a_busy_wait(struct snd_ad1816a *chip)
if (inb(AD1816A_REG(AD1816A_CHIP_STATUS)) & AD1816A_READY)
return 0;
- snd_printk("chip busy.\n");
+ snd_printk(KERN_WARNING "chip busy.\n");
return -EBUSY;
}
@@ -196,7 +196,7 @@ static int snd_ad1816a_trigger(struct snd_ad1816a *chip, unsigned char what,
spin_unlock(&chip->lock);
break;
default:
- snd_printk("invalid trigger mode 0x%x.\n", what);
+ snd_printk(KERN_WARNING "invalid trigger mode 0x%x.\n", what);
error = -EINVAL;
}
@@ -377,7 +377,6 @@ static struct snd_pcm_hardware snd_ad1816a_capture = {
.fifo_size = 0,
};
-#if 0 /* not used now */
static int snd_ad1816a_timer_close(struct snd_timer *timer)
{
struct snd_ad1816a *chip = snd_timer_chip(timer);
@@ -442,8 +441,6 @@ static struct snd_timer_hardware snd_ad1816a_timer_table = {
.start = snd_ad1816a_timer_start,
.stop = snd_ad1816a_timer_stop,
};
-#endif /* not used now */
-
static int snd_ad1816a_playback_open(struct snd_pcm_substream *substream)
{
@@ -568,7 +565,7 @@ static const char __devinit *snd_ad1816a_chip_id(struct snd_ad1816a *chip)
case AD1816A_HW_AD1815: return "AD1815";
case AD1816A_HW_AD18MAX10: return "AD18max10";
default:
- snd_printk("Unknown chip version %d:%d.\n",
+ snd_printk(KERN_WARNING "Unknown chip version %d:%d.\n",
chip->version, chip->hardware);
return "AD1816A - unknown";
}
@@ -687,7 +684,6 @@ int __devinit snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_p
return 0;
}
-#if 0 /* not used now */
int __devinit snd_ad1816a_timer(struct snd_ad1816a *chip, int device, struct snd_timer **rtimer)
{
struct snd_timer *timer;
@@ -709,7 +705,6 @@ int __devinit snd_ad1816a_timer(struct snd_ad1816a *chip, int device, struct snd
*rtimer = timer;
return 0;
}
-#endif /* not used now */
/*
*
diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c
index 223a6c03881..4beeb6f98e0 100644
--- a/sound/isa/ad1848/ad1848.c
+++ b/sound/isa/ad1848/ad1848.c
@@ -91,9 +91,9 @@ static int __devinit snd_ad1848_probe(struct device *dev, unsigned int n)
struct snd_pcm *pcm;
int error;
- card = snd_card_new(index[n], id[n], THIS_MODULE, 0);
- if (!card)
- return -EINVAL;
+ error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+ if (error < 0)
+ return error;
error = snd_wss_create(card, port[n], -1, irq[n], dma1[n], -1,
thinkpad[n] ? WSS_HW_THINKPAD : WSS_HW_DETECT,
diff --git a/sound/isa/adlib.c b/sound/isa/adlib.c
index 374b7177e11..7465ae036e0 100644
--- a/sound/isa/adlib.c
+++ b/sound/isa/adlib.c
@@ -53,10 +53,10 @@ static int __devinit snd_adlib_probe(struct device *dev, unsigned int n)
struct snd_opl3 *opl3;
int error;
- card = snd_card_new(index[n], id[n], THIS_MODULE, 0);
- if (!card) {
+ error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+ if (error < 0) {
dev_err(dev, "could not create card\n");
- return -EINVAL;
+ return error;
}
card->private_data = request_region(port[n], 4, CRD_NAME);
diff --git a/sound/isa/als100.c b/sound/isa/als100.c
index f1ce30f379c..5fd52e4d707 100644
--- a/sound/isa/als100.c
+++ b/sound/isa/als100.c
@@ -163,9 +163,10 @@ static int __devinit snd_card_als100_probe(int dev,
struct snd_card_als100 *acard;
struct snd_opl3 *opl3;
- if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_als100))) == NULL)
- return -ENOMEM;
+ error = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_als100), &card);
+ if (error < 0)
+ return error;
acard = card->private_data;
if ((error = snd_card_als100_pnp(dev, acard, pcard, pid))) {
diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c
index 3e74d1a3928..f7aa637b0d1 100644
--- a/sound/isa/azt2320.c
+++ b/sound/isa/azt2320.c
@@ -184,9 +184,10 @@ static int __devinit snd_card_azt2320_probe(int dev,
struct snd_wss *chip;
struct snd_opl3 *opl3;
- if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_azt2320))) == NULL)
- return -ENOMEM;
+ error = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_azt2320), &card);
+ if (error < 0)
+ return error;
acard = (struct snd_card_azt2320 *)card->private_data;
if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) {
diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c
index e49aec700a5..de83608719e 100644
--- a/sound/isa/cmi8330.c
+++ b/sound/isa/cmi8330.c
@@ -31,11 +31,11 @@
* To quickly load the module,
*
* modprobe -a snd-cmi8330 sbport=0x220 sbirq=5 sbdma8=1
- * sbdma16=5 wssport=0x530 wssirq=11 wssdma=0
+ * sbdma16=5 wssport=0x530 wssirq=11 wssdma=0 fmport=0x388
*
* This card has two mixers and two PCM devices. I've cheesed it such
* that recording and playback can be done through the same device.
- * The driver "magically" routes the capturing to the AD1848 codec,
+ * The driver "magically" routes the capturing to the CMI8330 codec,
* and playback to the SB16 codec. This allows for full-duplex mode
* to some extent.
* The utilities in alsa-utils are aware of both devices, so passing
@@ -51,6 +51,8 @@
#include <linux/moduleparam.h>
#include <sound/core.h>
#include <sound/wss.h>
+#include <sound/opl3.h>
+#include <sound/mpu401.h>
#include <sound/sb.h>
#include <sound/initval.h>
@@ -79,6 +81,9 @@ static int sbdma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
static long wssport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
static int wssirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
static int wssdma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
+static long fmport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static long mpuport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
+static int mpuirq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for CMI8330 soundcard.");
@@ -107,6 +112,12 @@ MODULE_PARM_DESC(wssirq, "IRQ # for CMI8330 WSS driver.");
module_param_array(wssdma, int, NULL, 0444);
MODULE_PARM_DESC(wssdma, "DMA for CMI8330 WSS driver.");
+module_param_array(fmport, long, NULL, 0444);
+MODULE_PARM_DESC(fmport, "FM port # for CMI8330 driver.");
+module_param_array(mpuport, long, NULL, 0444);
+MODULE_PARM_DESC(mpuport, "MPU-401 port # for CMI8330 driver.");
+module_param_array(mpuirq, int, NULL, 0444);
+MODULE_PARM_DESC(mpuirq, "IRQ # for CMI8330 MPU-401 port.");
#ifdef CONFIG_PNP
static int isa_registered;
static int pnp_registered;
@@ -149,6 +160,7 @@ struct snd_cmi8330 {
#ifdef CONFIG_PNP
struct pnp_dev *cap;
struct pnp_dev *play;
+ struct pnp_dev *mpu;
#endif
struct snd_card *card;
struct snd_wss *wss;
@@ -165,7 +177,7 @@ struct snd_cmi8330 {
#ifdef CONFIG_PNP
static struct pnp_card_device_id snd_cmi8330_pnpids[] = {
- { .id = "CMI0001", .devs = { { "@@@0001" }, { "@X@0001" } } },
+ { .id = "CMI0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } } },
{ .id = "" }
};
@@ -219,8 +231,10 @@ WSS_SINGLE("3D Control - Switch", 0,
CMI8330_RMUX3D, 5, 1, 1),
WSS_SINGLE("PC Speaker Playback Volume", 0,
CMI8330_OUTPUTVOL, 3, 3, 0),
-WSS_SINGLE("FM Playback Switch", 0,
- CMI8330_RECMUX, 3, 1, 1),
+WSS_DOUBLE("FM Playback Switch", 0,
+ CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+WSS_DOUBLE("FM Playback Volume", 0,
+ CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
WSS_SINGLE(SNDRV_CTL_NAME_IEC958("Input ", CAPTURE, SWITCH), 0,
CMI8330_RMUX3D, 7, 1, 1),
WSS_SINGLE(SNDRV_CTL_NAME_IEC958("Input ", PLAYBACK, SWITCH), 0,
@@ -323,16 +337,21 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
if (acard->play == NULL)
return -EBUSY;
+ acard->mpu = pnp_request_card_device(card, id->devs[2].id, NULL);
+ if (acard->play == NULL)
+ return -EBUSY;
+
pdev = acard->cap;
err = pnp_activate_dev(pdev);
if (err < 0) {
- snd_printk(KERN_ERR "CMI8330/C3D (AD1848) PnP configure failure\n");
+ snd_printk(KERN_ERR "CMI8330/C3D PnP configure failure\n");
return -EBUSY;
}
wssport[dev] = pnp_port_start(pdev, 0);
wssdma[dev] = pnp_dma(pdev, 0);
wssirq[dev] = pnp_irq(pdev, 0);
+ fmport[dev] = pnp_port_start(pdev, 1);
/* allocate SB16 resources */
pdev = acard->play;
@@ -347,6 +366,17 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
sbdma16[dev] = pnp_dma(pdev, 1);
sbirq[dev] = pnp_irq(pdev, 0);
+ /* allocate MPU-401 resources */
+ pdev = acard->mpu;
+
+ err = pnp_activate_dev(pdev);
+ if (err < 0) {
+ snd_printk(KERN_ERR
+ "CMI8330/C3D (MPU-401) PnP configure failure\n");
+ return -EBUSY;
+ }
+ mpuport[dev] = pnp_port_start(pdev, 0);
+ mpuirq[dev] = pnp_irq(pdev, 0);
return 0;
}
#endif
@@ -467,26 +497,29 @@ static int snd_cmi8330_resume(struct snd_card *card)
#define PFX "cmi8330: "
-static struct snd_card *snd_cmi8330_card_new(int dev)
+static int snd_cmi8330_card_new(int dev, struct snd_card **cardp)
{
struct snd_card *card;
struct snd_cmi8330 *acard;
+ int err;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_cmi8330));
- if (card == NULL) {
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_cmi8330), &card);
+ if (err < 0) {
snd_printk(KERN_ERR PFX "could not get a new card\n");
- return NULL;
+ return err;
}
acard = card->private_data;
acard->card = card;
- return card;
+ *cardp = card;
+ return 0;
}
static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
{
struct snd_cmi8330 *acard;
int i, err;
+ struct snd_opl3 *opl3;
acard = card->private_data;
err = snd_wss_create(card, wssport[dev] + 4, -1,
@@ -494,11 +527,11 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
wssdma[dev], -1,
WSS_HW_DETECT, 0, &acard->wss);
if (err < 0) {
- snd_printk(KERN_ERR PFX "(AD1848) device busy??\n");
+ snd_printk(KERN_ERR PFX "(CMI8330) device busy??\n");
return err;
}
if (acard->wss->hardware != WSS_HW_CMI8330) {
- snd_printk(KERN_ERR PFX "(AD1848) not found during probe\n");
+ snd_printk(KERN_ERR PFX "(CMI8330) not found during probe\n");
return -ENODEV;
}
@@ -530,6 +563,27 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev)
snd_printk(KERN_ERR PFX "failed to create pcms\n");
return err;
}
+ if (fmport[dev] != SNDRV_AUTO_PORT) {
+ if (snd_opl3_create(card,
+ fmport[dev], fmport[dev] + 2,
+ OPL3_HW_AUTO, 0, &opl3) < 0) {
+ snd_printk(KERN_ERR PFX
+ "no OPL device at 0x%lx-0x%lx ?\n",
+ fmport[dev], fmport[dev] + 2);
+ } else {
+ err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+ if (err < 0)
+ return err;
+ }
+ }
+
+ if (mpuport[dev] != SNDRV_AUTO_PORT) {
+ if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
+ mpuport[dev], 0, mpuirq[dev],
+ IRQF_DISABLED, NULL) < 0)
+ printk(KERN_ERR PFX "no MPU-401 device at 0x%lx.\n",
+ mpuport[dev]);
+ }
strcpy(card->driver, "CMI8330/C3D");
strcpy(card->shortname, "C-Media CMI8330/C3D");
@@ -564,9 +618,9 @@ static int __devinit snd_cmi8330_isa_probe(struct device *pdev,
struct snd_card *card;
int err;
- card = snd_cmi8330_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_cmi8330_card_new(dev, &card);
+ if (err < 0)
+ return err;
snd_card_set_dev(card, pdev);
if ((err = snd_cmi8330_probe(card, dev)) < 0) {
snd_card_free(card);
@@ -628,9 +682,9 @@ static int __devinit snd_cmi8330_pnp_detect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_cmi8330_card_new(dev);
- if (! card)
- return -ENOMEM;
+ res = snd_cmi8330_card_new(dev, &card);
+ if (res < 0)
+ return res;
if ((res = snd_cmi8330_pnp(dev, card->private_data, pcard, pid)) < 0) {
snd_printk(KERN_ERR PFX "PnP detection failed\n");
snd_card_free(card);
diff --git a/sound/isa/cs423x/Makefile b/sound/isa/cs423x/Makefile
index 5870ca21ab5..6d397e8d54a 100644
--- a/sound/isa/cs423x/Makefile
+++ b/sound/isa/cs423x/Makefile
@@ -3,13 +3,11 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
#
-snd-cs4236-lib-objs := cs4236_lib.o
snd-cs4231-objs := cs4231.o
-snd-cs4232-objs := cs4232.o
-snd-cs4236-objs := cs4236.o
+snd-cs4236-objs := cs4236.o cs4236_lib.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_CS4231) += snd-cs4231.o
-obj-$(CONFIG_SND_CS4232) += snd-cs4232.o
-obj-$(CONFIG_SND_CS4236) += snd-cs4236.o snd-cs4236-lib.o
+obj-$(CONFIG_SND_CS4236) += snd-cs4236.o
+
diff --git a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c
index f019d449e2d..cb9153e75b8 100644
--- a/sound/isa/cs423x/cs4231.c
+++ b/sound/isa/cs423x/cs4231.c
@@ -95,9 +95,9 @@ static int __devinit snd_cs4231_probe(struct device *dev, unsigned int n)
struct snd_pcm *pcm;
int error;
- card = snd_card_new(index[n], id[n], THIS_MODULE, 0);
- if (!card)
- return -EINVAL;
+ error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+ if (error < 0)
+ return error;
error = snd_wss_create(card, port[n], -1, irq[n], dma1[n], dma2[n],
WSS_HW_DETECT, 0, &chip);
diff --git a/sound/isa/cs423x/cs4232.c b/sound/isa/cs423x/cs4232.c
deleted file mode 100644
index 9fad2e6c0c2..00000000000
--- a/sound/isa/cs423x/cs4232.c
+++ /dev/null
@@ -1,2 +0,0 @@
-#define CS4232
-#include "cs4236.c"
diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c
index 019c9401663..a076a6ce807 100644
--- a/sound/isa/cs423x/cs4236.c
+++ b/sound/isa/cs423x/cs4236.c
@@ -33,17 +33,14 @@
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_LICENSE("GPL");
-#ifdef CS4232
-MODULE_DESCRIPTION("Cirrus Logic CS4232");
+MODULE_DESCRIPTION("Cirrus Logic CS4232-9");
MODULE_SUPPORTED_DEVICE("{{Turtle Beach,TBS-2000},"
"{Turtle Beach,Tropez Plus},"
"{SIC CrystalWave 32},"
"{Hewlett Packard,Omnibook 5500},"
"{TerraTec,Maestro 32/96},"
- "{Philips,PCA70PS}}");
-#else
-MODULE_DESCRIPTION("Cirrus Logic CS4235-9");
-MODULE_SUPPORTED_DEVICE("{{Crystal Semiconductors,CS4235},"
+ "{Philips,PCA70PS}},"
+ "{{Crystal Semiconductors,CS4235},"
"{Crystal Semiconductors,CS4236},"
"{Crystal Semiconductors,CS4237},"
"{Crystal Semiconductors,CS4238},"
@@ -70,15 +67,11 @@ MODULE_SUPPORTED_DEVICE("{{Crystal Semiconductors,CS4235},"
"{Typhoon Soundsystem,CS4236B},"
"{Turtle Beach,Malibu},"
"{Unknown,Digital PC 5000 Onboard}}");
-#endif
-#ifdef CS4232
-#define IDENT "CS4232"
-#define DEV_NAME "cs4232"
-#else
-#define IDENT "CS4236+"
-#define DEV_NAME "cs4236"
-#endif
+MODULE_ALIAS("snd_cs4232");
+
+#define IDENT "CS4232+"
+#define DEV_NAME "cs4232+"
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
@@ -128,9 +121,7 @@ MODULE_PARM_DESC(dma2, "DMA2 # for " IDENT " driver.");
#ifdef CONFIG_PNP
static int isa_registered;
static int pnpc_registered;
-#ifdef CS4232
static int pnp_registered;
-#endif
#endif /* CONFIG_PNP */
struct snd_card_cs4236 {
@@ -145,11 +136,10 @@ struct snd_card_cs4236 {
#ifdef CONFIG_PNP
-#ifdef CS4232
/*
* PNP BIOS
*/
-static const struct pnp_device_id snd_cs4232_pnpbiosids[] = {
+static const struct pnp_device_id snd_cs423x_pnpbiosids[] = {
{ .id = "CSC0100" },
{ .id = "CSC0000" },
/* Guillemot Turtlebeach something appears to be cs4232 compatible
@@ -157,10 +147,8 @@ static const struct pnp_device_id snd_cs4232_pnpbiosids[] = {
{ .id = "GIM0100" },
{ .id = "" }
};
-MODULE_DEVICE_TABLE(pnp, snd_cs4232_pnpbiosids);
-#endif /* CS4232 */
+MODULE_DEVICE_TABLE(pnp, snd_cs423x_pnpbiosids);
-#ifdef CS4232
#define CS423X_ISAPNP_DRIVER "cs4232_isapnp"
static struct pnp_card_device_id snd_cs423x_pnpids[] = {
/* Philips PCA70PS */
@@ -179,12 +167,6 @@ static struct pnp_card_device_id snd_cs423x_pnpids[] = {
{ .id = "CSCf032", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
/* Netfinity 3000 on-board soundcard */
{ .id = "CSCe825", .devs = { { "CSC0100" }, { "CSC0110" }, { "CSC010f" } } },
- /* --- */
- { .id = "" } /* end */
-};
-#else /* CS4236 */
-#define CS423X_ISAPNP_DRIVER "cs4236_isapnp"
-static struct pnp_card_device_id snd_cs423x_pnpids[] = {
/* Intel Marlin Spike Motherboard - CS4235 */
{ .id = "CSC0225", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
/* Intel Marlin Spike Motherboard (#2) - CS4235 */
@@ -266,7 +248,6 @@ static struct pnp_card_device_id snd_cs423x_pnpids[] = {
/* --- */
{ .id = "" } /* end */
};
-#endif
MODULE_DEVICE_TABLE(pnp_card, snd_cs423x_pnpids);
@@ -323,17 +304,19 @@ static int __devinit snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev)
return 0;
}
-#ifdef CS4232
-static int __devinit snd_card_cs4232_pnp(int dev, struct snd_card_cs4236 *acard,
- struct pnp_dev *pdev)
+static int __devinit snd_card_cs423x_pnp(int dev, struct snd_card_cs4236 *acard,
+ struct pnp_dev *pdev,
+ struct pnp_dev *cdev)
{
acard->wss = pdev;
if (snd_cs423x_pnp_init_wss(dev, acard->wss) < 0)
return -EBUSY;
- cport[dev] = -1;
+ if (cdev)
+ cport[dev] = pnp_port_start(cdev, 0);
+ else
+ cport[dev] = -1;
return 0;
}
-#endif
static int __devinit snd_card_cs423x_pnpc(int dev, struct snd_card_cs4236 *acard,
struct pnp_card_link *card,
@@ -382,16 +365,18 @@ static void snd_card_cs4236_free(struct snd_card *card)
release_and_free_resource(acard->res_sb_port);
}
-static struct snd_card *snd_cs423x_card_new(int dev)
+static int snd_cs423x_card_new(int dev, struct snd_card **cardp)
{
struct snd_card *card;
+ int err;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_cs4236));
- if (card == NULL)
- return NULL;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_cs4236), &card);
+ if (err < 0)
+ return err;
card->private_free = snd_card_cs4236_free;
- return card;
+ *cardp = card;
+ return 0;
}
static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
@@ -409,40 +394,39 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
return -EBUSY;
}
-#ifdef CS4232
err = snd_wss_create(card, port[dev], cport[dev],
irq[dev],
dma1[dev], dma2[dev],
- WSS_HW_DETECT, 0, &chip);
- if (err < 0)
- return err;
- acard->chip = chip;
-
- err = snd_wss_pcm(chip, 0, &pcm);
- if (err < 0)
- return err;
-
- err = snd_wss_mixer(chip);
+ WSS_HW_DETECT3, 0, &chip);
if (err < 0)
return err;
-
-#else /* CS4236 */
- err = snd_cs4236_create(card,
- port[dev], cport[dev],
- irq[dev], dma1[dev], dma2[dev],
- WSS_HW_DETECT, 0, &chip);
- if (err < 0)
- return err;
- acard->chip = chip;
-
- err = snd_cs4236_pcm(chip, 0, &pcm);
- if (err < 0)
- return err;
-
- err = snd_cs4236_mixer(chip);
- if (err < 0)
- return err;
-#endif
+ if (chip->hardware & WSS_HW_CS4236B_MASK) {
+ snd_wss_free(chip);
+ err = snd_cs4236_create(card,
+ port[dev], cport[dev],
+ irq[dev], dma1[dev], dma2[dev],
+ WSS_HW_DETECT, 0, &chip);
+ if (err < 0)
+ return err;
+ acard->chip = chip;
+
+ err = snd_cs4236_pcm(chip, 0, &pcm);
+ if (err < 0)
+ return err;
+
+ err = snd_cs4236_mixer(chip);
+ if (err < 0)
+ return err;
+ } else {
+ acard->chip = chip;
+ err = snd_wss_pcm(chip, 0, &pcm);
+ if (err < 0)
+ return err;
+
+ err = snd_wss_mixer(chip);
+ if (err < 0)
+ return err;
+ }
strcpy(card->driver, pcm->name);
strcpy(card->shortname, pcm->name);
sprintf(card->longname, "%s at 0x%lx, irq %i, dma %i",
@@ -512,9 +496,9 @@ static int __devinit snd_cs423x_isa_probe(struct device *pdev,
struct snd_card *card;
int err;
- card = snd_cs423x_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_cs423x_card_new(dev, &card);
+ if (err < 0)
+ return err;
snd_card_set_dev(card, pdev);
if ((err = snd_cs423x_probe(card, dev)) < 0) {
snd_card_free(card);
@@ -577,13 +561,14 @@ static struct isa_driver cs423x_isa_driver = {
#ifdef CONFIG_PNP
-#ifdef CS4232
-static int __devinit snd_cs4232_pnpbios_detect(struct pnp_dev *pdev,
+static int __devinit snd_cs423x_pnpbios_detect(struct pnp_dev *pdev,
const struct pnp_device_id *id)
{
static int dev;
int err;
struct snd_card *card;
+ struct pnp_dev *cdev;
+ char cid[PNP_ID_LEN];
if (pnp_device_is_isapnp(pdev))
return -ENOENT; /* we have another procedure - card */
@@ -594,10 +579,19 @@ static int __devinit snd_cs4232_pnpbios_detect(struct pnp_dev *pdev,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_cs423x_card_new(dev);
- if (! card)
- return -ENOMEM;
- if ((err = snd_card_cs4232_pnp(dev, card->private_data, pdev)) < 0) {
+ /* prepare second id */
+ strcpy(cid, pdev->id[0].id);
+ cid[5] = '1';
+ cdev = NULL;
+ list_for_each_entry(cdev, &(pdev->protocol->devices), protocol_list) {
+ if (!strcmp(cdev->id[0].id, cid))
+ break;
+ }
+ err = snd_cs423x_card_new(dev, &card);
+ if (err < 0)
+ return err;
+ err = snd_card_cs423x_pnp(dev, card->private_data, pdev, cdev);
+ if (err < 0) {
printk(KERN_ERR "PnP BIOS detection failed for " IDENT "\n");
snd_card_free(card);
return err;
@@ -612,35 +606,34 @@ static int __devinit snd_cs4232_pnpbios_detect(struct pnp_dev *pdev,
return 0;
}
-static void __devexit snd_cs4232_pnp_remove(struct pnp_dev * pdev)
+static void __devexit snd_cs423x_pnp_remove(struct pnp_dev *pdev)
{
snd_card_free(pnp_get_drvdata(pdev));
pnp_set_drvdata(pdev, NULL);
}
#ifdef CONFIG_PM
-static int snd_cs4232_pnp_suspend(struct pnp_dev *pdev, pm_message_t state)
+static int snd_cs423x_pnp_suspend(struct pnp_dev *pdev, pm_message_t state)
{
return snd_cs423x_suspend(pnp_get_drvdata(pdev));
}
-static int snd_cs4232_pnp_resume(struct pnp_dev *pdev)
+static int snd_cs423x_pnp_resume(struct pnp_dev *pdev)
{
return snd_cs423x_resume(pnp_get_drvdata(pdev));
}
#endif
-static struct pnp_driver cs4232_pnp_driver = {
- .name = "cs4232-pnpbios",
- .id_table = snd_cs4232_pnpbiosids,
- .probe = snd_cs4232_pnpbios_detect,
- .remove = __devexit_p(snd_cs4232_pnp_remove),
+static struct pnp_driver cs423x_pnp_driver = {
+ .name = "cs423x-pnpbios",
+ .id_table = snd_cs423x_pnpbiosids,
+ .probe = snd_cs423x_pnpbios_detect,
+ .remove = __devexit_p(snd_cs423x_pnp_remove),
#ifdef CONFIG_PM
- .suspend = snd_cs4232_pnp_suspend,
- .resume = snd_cs4232_pnp_resume,
+ .suspend = snd_cs423x_pnp_suspend,
+ .resume = snd_cs423x_pnp_resume,
#endif
};
-#endif /* CS4232 */
static int __devinit snd_cs423x_pnpc_detect(struct pnp_card_link *pcard,
const struct pnp_card_device_id *pid)
@@ -656,9 +649,9 @@ static int __devinit snd_cs423x_pnpc_detect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_cs423x_card_new(dev);
- if (! card)
- return -ENOMEM;
+ res = snd_cs423x_card_new(dev, &card);
+ if (res < 0)
+ return res;
if ((res = snd_card_cs423x_pnpc(dev, card->private_data, pcard, pid)) < 0) {
printk(KERN_ERR "isapnp detection failed and probing for " IDENT
" is not supported\n");
@@ -714,18 +707,14 @@ static int __init alsa_card_cs423x_init(void)
#ifdef CONFIG_PNP
if (!err)
isa_registered = 1;
-#ifdef CS4232
- err = pnp_register_driver(&cs4232_pnp_driver);
+ err = pnp_register_driver(&cs423x_pnp_driver);
if (!err)
pnp_registered = 1;
-#endif
err = pnp_register_card_driver(&cs423x_pnpc_driver);
if (!err)
pnpc_registered = 1;
-#ifdef CS4232
if (pnp_registered)
err = 0;
-#endif
if (isa_registered)
err = 0;
#endif
@@ -737,10 +726,8 @@ static void __exit alsa_card_cs423x_exit(void)
#ifdef CONFIG_PNP
if (pnpc_registered)
pnp_unregister_card_driver(&cs423x_pnpc_driver);
-#ifdef CS4232
if (pnp_registered)
- pnp_unregister_driver(&cs4232_pnp_driver);
-#endif
+ pnp_unregister_driver(&cs423x_pnp_driver);
if (isa_registered)
#endif
isa_unregister_driver(&cs423x_isa_driver);
diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c
index 6a85fdc53b6..38835f31298 100644
--- a/sound/isa/cs423x/cs4236_lib.c
+++ b/sound/isa/cs423x/cs4236_lib.c
@@ -88,10 +88,6 @@
#include <sound/wss.h>
#include <sound/asoundef.h>
-MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
-MODULE_DESCRIPTION("Routines for control of CS4235/4236B/4237B/4238B/4239 chips");
-MODULE_LICENSE("GPL");
-
/*
*
*/
@@ -286,7 +282,8 @@ int snd_cs4236_create(struct snd_card *card,
if (hardware == WSS_HW_DETECT)
hardware = WSS_HW_DETECT3;
if (cport < 0x100) {
- snd_printk("please, specify control port for CS4236+ chips\n");
+ snd_printk(KERN_ERR "please, specify control port "
+ "for CS4236+ chips\n");
return -ENODEV;
}
err = snd_wss_create(card, port, cport,
@@ -295,7 +292,8 @@ int snd_cs4236_create(struct snd_card *card,
return err;
if (!(chip->hardware & WSS_HW_CS4236B_MASK)) {
- snd_printk("CS4236+: MODE3 and extended registers not available, hardware=0x%x\n",chip->hardware);
+ snd_printk(KERN_ERR "CS4236+: MODE3 and extended registers "
+ "not available, hardware=0x%x\n", chip->hardware);
snd_device_free(card, chip);
return -ENODEV;
}
@@ -303,16 +301,19 @@ int snd_cs4236_create(struct snd_card *card,
{
int idx;
for (idx = 0; idx < 8; idx++)
- snd_printk("CD%i = 0x%x\n", idx, inb(chip->cport + idx));
+ snd_printk(KERN_DEBUG "CD%i = 0x%x\n",
+ idx, inb(chip->cport + idx));
for (idx = 0; idx < 9; idx++)
- snd_printk("C%i = 0x%x\n", idx, snd_cs4236_ctrl_in(chip, idx));
+ snd_printk(KERN_DEBUG "C%i = 0x%x\n",
+ idx, snd_cs4236_ctrl_in(chip, idx));
}
#endif
ver1 = snd_cs4236_ctrl_in(chip, 1);
ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION);
snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", cport, ver1, ver2);
if (ver1 != ver2) {
- snd_printk("CS4236+ chip detected, but control port 0x%lx is not valid\n", cport);
+ snd_printk(KERN_ERR "CS4236+ chip detected, but "
+ "control port 0x%lx is not valid\n", cport);
snd_device_free(card, chip);
return -ENODEV;
}
@@ -883,7 +884,8 @@ static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct sn
spin_lock_irqsave(&chip->reg_lock, flags);
ucontrol->value.integer.value[0] = chip->image[CS4231_ALT_FEATURE_1] & 0x02 ? 1 : 0;
#if 0
- printk("get valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
+ printk(KERN_DEBUG "get valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, "
+ "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
snd_wss_in(chip, CS4231_ALT_FEATURE_1),
snd_cs4236_ctrl_in(chip, 3),
snd_cs4236_ctrl_in(chip, 4),
@@ -920,7 +922,8 @@ static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct sn
mutex_unlock(&chip->mce_mutex);
#if 0
- printk("set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
+ printk(KERN_DEBUG "set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, "
+ "C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
snd_wss_in(chip, CS4231_ALT_FEATURE_1),
snd_cs4236_ctrl_in(chip, 3),
snd_cs4236_ctrl_in(chip, 4),
@@ -1015,23 +1018,3 @@ int snd_cs4236_mixer(struct snd_wss *chip)
}
return 0;
}
-
-EXPORT_SYMBOL(snd_cs4236_create);
-EXPORT_SYMBOL(snd_cs4236_pcm);
-EXPORT_SYMBOL(snd_cs4236_mixer);
-
-/*
- * INIT part
- */
-
-static int __init alsa_cs4236_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_cs4236_exit(void)
-{
-}
-
-module_init(alsa_cs4236_init)
-module_exit(alsa_cs4236_exit)
diff --git a/sound/isa/dt019x.c b/sound/isa/dt019x.c
index a0242c3b613..80f5b1af9be 100644
--- a/sound/isa/dt019x.c
+++ b/sound/isa/dt019x.c
@@ -150,9 +150,10 @@ static int __devinit snd_card_dt019x_probe(int dev, struct pnp_card_link *pcard,
struct snd_card_dt019x *acard;
struct snd_opl3 *opl3;
- if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_dt019x))) == NULL)
- return -ENOMEM;
+ error = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_dt019x), &card);
+ if (error < 0)
+ return error;
acard = card->private_data;
snd_card_set_dev(card, &pcard->card->dev);
diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c
index b46377139cf..442b081cafb 100644
--- a/sound/isa/es1688/es1688.c
+++ b/sound/isa/es1688/es1688.c
@@ -49,6 +49,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260 */
+static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* Usually 0x388 */
static long mpu_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1};
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,10 */
static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,10 */
@@ -65,6 +66,8 @@ MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
module_param_array(mpu_port, long, NULL, 0444);
MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver.");
module_param_array(irq, int, NULL, 0444);
+module_param_array(fm_port, long, NULL, 0444);
+MODULE_PARM_DESC(fm_port, "FM port # for ES1688 driver.");
MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
module_param_array(mpu_irq, int, NULL, 0444);
MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
@@ -122,9 +125,9 @@ static int __devinit snd_es1688_probe(struct device *dev, unsigned int n)
struct snd_pcm *pcm;
int error;
- card = snd_card_new(index[n], id[n], THIS_MODULE, 0);
- if (!card)
- return -EINVAL;
+ error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+ if (error < 0)
+ return error;
error = snd_es1688_legacy_create(card, dev, n, &chip);
if (error < 0)
@@ -143,13 +146,19 @@ static int __devinit snd_es1688_probe(struct device *dev, unsigned int n)
sprintf(card->longname, "%s at 0x%lx, irq %i, dma %i", pcm->name,
chip->port, chip->irq, chip->dma8);
- if (snd_opl3_create(card, chip->port, chip->port + 2,
- OPL3_HW_OPL3, 0, &opl3) < 0)
- dev_warn(dev, "opl3 not detected at 0x%lx\n", chip->port);
- else {
- error = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
- if (error < 0)
- goto out;
+ if (fm_port[n] == SNDRV_AUTO_PORT)
+ fm_port[n] = port[n]; /* share the same port */
+
+ if (fm_port[n] > 0) {
+ if (snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
+ OPL3_HW_OPL3, 0, &opl3) < 0)
+ dev_warn(dev,
+ "opl3 not detected at 0x%lx\n", fm_port[n]);
+ else {
+ error = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
+ if (error < 0)
+ goto out;
+ }
}
if (mpu_irq[n] >= 0 && mpu_irq[n] != SNDRV_AUTO_IRQ &&
diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c
index 4fbb508a817..4c6e14f87f2 100644
--- a/sound/isa/es1688/es1688_lib.c
+++ b/sound/isa/es1688/es1688_lib.c
@@ -45,7 +45,7 @@ static int snd_es1688_dsp_command(struct snd_es1688 *chip, unsigned char val)
return 1;
}
#ifdef CONFIG_SND_DEBUG
- printk("snd_es1688_dsp_command: timeout (0x%x)\n", val);
+ printk(KERN_DEBUG "snd_es1688_dsp_command: timeout (0x%x)\n", val);
#endif
return 0;
}
@@ -167,13 +167,16 @@ static int snd_es1688_probe(struct snd_es1688 *chip)
hw = ES1688_HW_AUTO;
switch (chip->version & 0xfff0) {
case 0x4880:
- snd_printk("[0x%lx] ESS: AudioDrive ES488 detected, but driver is in another place\n", chip->port);
+ snd_printk(KERN_ERR "[0x%lx] ESS: AudioDrive ES488 detected, "
+ "but driver is in another place\n", chip->port);
return -ENODEV;
case 0x6880:
hw = (chip->version & 0x0f) >= 8 ? ES1688_HW_1688 : ES1688_HW_688;
break;
default:
- snd_printk("[0x%lx] ESS: unknown AudioDrive chip with version 0x%x (Jazz16 soundcard?)\n", chip->port, chip->version);
+ snd_printk(KERN_ERR "[0x%lx] ESS: unknown AudioDrive chip "
+ "with version 0x%x (Jazz16 soundcard?)\n",
+ chip->port, chip->version);
return -ENODEV;
}
@@ -223,7 +226,7 @@ static int snd_es1688_init(struct snd_es1688 * chip, int enable)
}
}
#if 0
- snd_printk("mpu cfg = 0x%x\n", cfg);
+ snd_printk(KERN_DEBUG "mpu cfg = 0x%x\n", cfg);
#endif
spin_lock_irqsave(&chip->reg_lock, flags);
snd_es1688_mixer_write(chip, 0x40, cfg);
@@ -237,7 +240,9 @@ static int snd_es1688_init(struct snd_es1688 * chip, int enable)
cfg = 0xf0; /* enable only DMA counter interrupt */
irq_bits = irqs[chip->irq & 0x0f];
if (irq_bits < 0) {
- snd_printk("[0x%lx] ESS: bad IRQ %d for ES1688 chip!!\n", chip->port, chip->irq);
+ snd_printk(KERN_ERR "[0x%lx] ESS: bad IRQ %d "
+ "for ES1688 chip!!\n",
+ chip->port, chip->irq);
#if 0
irq_bits = 0;
cfg = 0x10;
@@ -250,7 +255,8 @@ static int snd_es1688_init(struct snd_es1688 * chip, int enable)
cfg = 0xf0; /* extended mode DMA enable */
dma = chip->dma8;
if (dma > 3 || dma == 2) {
- snd_printk("[0x%lx] ESS: bad DMA channel %d for ES1688 chip!!\n", chip->port, dma);
+ snd_printk(KERN_ERR "[0x%lx] ESS: bad DMA channel %d "
+ "for ES1688 chip!!\n", chip->port, dma);
#if 0
dma_bits = 0;
cfg = 0x00; /* disable all DMA */
@@ -341,8 +347,9 @@ static int snd_es1688_trigger(struct snd_es1688 *chip, int cmd, unsigned char va
return -EINVAL; /* something is wrong */
}
#if 0
- printk("trigger: val = 0x%x, value = 0x%x\n", val, value);
- printk("trigger: pointer = 0x%x\n", snd_dma_pointer(chip->dma8, chip->dma_size));
+ printk(KERN_DEBUG "trigger: val = 0x%x, value = 0x%x\n", val, value);
+ printk(KERN_DEBUG "trigger: pointer = 0x%x\n",
+ snd_dma_pointer(chip->dma8, chip->dma_size));
#endif
snd_es1688_write(chip, 0xb8, (val & 0xf0) | value);
spin_unlock(&chip->reg_lock);
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
index 90498e4ca26..8cfbff73a83 100644
--- a/sound/isa/es18xx.c
+++ b/sound/isa/es18xx.c
@@ -2125,10 +2125,10 @@ static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard,
#define is_isapnp_selected(dev) 0
#endif
-static struct snd_card *snd_es18xx_card_new(int dev)
+static int snd_es18xx_card_new(int dev, struct snd_card **cardp)
{
- return snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_audiodrive));
+ return snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_audiodrive), cardp);
}
static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev)
@@ -2197,9 +2197,9 @@ static int __devinit snd_es18xx_isa_probe1(int dev, struct device *devptr)
struct snd_card *card;
int err;
- card = snd_es18xx_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_es18xx_card_new(dev, &card);
+ if (err < 0)
+ return err;
snd_card_set_dev(card, devptr);
if ((err = snd_audiodrive_probe(card, dev)) < 0) {
snd_card_free(card);
@@ -2303,9 +2303,9 @@ static int __devinit snd_audiodrive_pnp_detect(struct pnp_dev *pdev,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_es18xx_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_es18xx_card_new(dev, &card);
+ if (err < 0)
+ return err;
if ((err = snd_audiodrive_pnp(dev, card->private_data, pdev)) < 0) {
snd_card_free(card);
return err;
@@ -2362,9 +2362,9 @@ static int __devinit snd_audiodrive_pnpc_detect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_es18xx_card_new(dev);
- if (! card)
- return -ENOMEM;
+ res = snd_es18xx_card_new(dev, &card);
+ if (res < 0)
+ return res;
if ((res = snd_audiodrive_pnpc(dev, card->private_data, pcard, pid)) < 0) {
snd_card_free(card);
diff --git a/sound/isa/gus/gus_dma.c b/sound/isa/gus/gus_dma.c
index f45f6116c77..36c27c83236 100644
--- a/sound/isa/gus/gus_dma.c
+++ b/sound/isa/gus/gus_dma.c
@@ -45,7 +45,8 @@ static void snd_gf1_dma_program(struct snd_gus_card * gus,
unsigned char dma_cmd;
unsigned int address_high;
- // snd_printk("dma_transfer: addr=0x%x, buf=0x%lx, count=0x%x\n", addr, (long) buf, count);
+ snd_printdd("dma_transfer: addr=0x%x, buf=0x%lx, count=0x%x\n",
+ addr, buf_addr, count);
if (gus->gf1.dma1 > 3) {
if (gus->gf1.enh_mode) {
@@ -77,7 +78,8 @@ static void snd_gf1_dma_program(struct snd_gus_card * gus,
snd_gf1_dma_ack(gus);
snd_dma_program(gus->gf1.dma1, buf_addr, count, dma_cmd & SNDRV_GF1_DMA_READ ? DMA_MODE_READ : DMA_MODE_WRITE);
#if 0
- snd_printk("address = 0x%x, count = 0x%x, dma_cmd = 0x%x\n", address << 1, count, dma_cmd);
+ snd_printk(KERN_DEBUG "address = 0x%x, count = 0x%x, dma_cmd = 0x%x\n",
+ address << 1, count, dma_cmd);
#endif
spin_lock_irqsave(&gus->reg_lock, flags);
if (gus->gf1.enh_mode) {
@@ -142,7 +144,9 @@ static void snd_gf1_dma_interrupt(struct snd_gus_card * gus)
snd_gf1_dma_program(gus, block->addr, block->buf_addr, block->count, (unsigned short) block->cmd);
kfree(block);
#if 0
- printk("program dma (IRQ) - addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n", addr, (long) buffer, count, cmd);
+ snd_printd(KERN_DEBUG "program dma (IRQ) - "
+ "addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n",
+ block->addr, block->buf_addr, block->count, block->cmd);
#endif
}
@@ -203,13 +207,16 @@ int snd_gf1_dma_transfer_block(struct snd_gus_card * gus,
}
*block = *__block;
block->next = NULL;
-#if 0
- printk("addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n", block->addr, (long) block->buffer, block->count, block->cmd);
-#endif
-#if 0
- printk("gus->gf1.dma_data_pcm_last = 0x%lx\n", (long)gus->gf1.dma_data_pcm_last);
- printk("gus->gf1.dma_data_pcm = 0x%lx\n", (long)gus->gf1.dma_data_pcm);
-#endif
+
+ snd_printdd("addr = 0x%x, buffer = 0x%lx, count = 0x%x, cmd = 0x%x\n",
+ block->addr, (long) block->buffer, block->count,
+ block->cmd);
+
+ snd_printdd("gus->gf1.dma_data_pcm_last = 0x%lx\n",
+ (long)gus->gf1.dma_data_pcm_last);
+ snd_printdd("gus->gf1.dma_data_pcm = 0x%lx\n",
+ (long)gus->gf1.dma_data_pcm);
+
spin_lock_irqsave(&gus->dma_lock, flags);
if (synth) {
if (gus->gf1.dma_data_synth_last) {
diff --git a/sound/isa/gus/gus_irq.c b/sound/isa/gus/gus_irq.c
index 041894ddd01..2055aff71b5 100644
--- a/sound/isa/gus/gus_irq.c
+++ b/sound/isa/gus/gus_irq.c
@@ -41,7 +41,7 @@ __again:
if (status == 0)
return IRQ_RETVAL(handled);
handled = 1;
- // snd_printk("IRQ: status = 0x%x\n", status);
+ /* snd_printk(KERN_DEBUG "IRQ: status = 0x%x\n", status); */
if (status & 0x02) {
STAT_ADD(gus->gf1.interrupt_stat_midi_in);
if (gus->gf1.interrupt_handler_midi_in)
@@ -65,7 +65,9 @@ __again:
continue; /* multi request */
already |= _current_; /* mark request */
#if 0
- printk("voice = %i, voice_status = 0x%x, voice_verify = %i\n", voice, voice_status, inb(GUSP(gus, GF1PAGE)));
+ printk(KERN_DEBUG "voice = %i, voice_status = 0x%x, "
+ "voice_verify = %i\n",
+ voice, voice_status, inb(GUSP(gus, GF1PAGE)));
#endif
pvoice = &gus->gf1.voices[voice];
if (pvoice->use) {
diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c
index 38510aeb21c..edb11eefdfe 100644
--- a/sound/isa/gus/gus_pcm.c
+++ b/sound/isa/gus/gus_pcm.c
@@ -82,7 +82,10 @@ static int snd_gf1_pcm_block_change(struct snd_pcm_substream *substream,
count += offset & 31;
offset &= ~31;
- // snd_printk("block change - offset = 0x%x, count = 0x%x\n", offset, count);
+ /*
+ snd_printk(KERN_DEBUG "block change - offset = 0x%x, count = 0x%x\n",
+ offset, count);
+ */
memset(&block, 0, sizeof(block));
block.cmd = SNDRV_GF1_DMA_IRQ;
if (snd_pcm_format_unsigned(runtime->format))
@@ -135,7 +138,11 @@ static void snd_gf1_pcm_trigger_up(struct snd_pcm_substream *substream)
curr = begin + (pcmp->bpos * pcmp->block_size) / runtime->channels;
end = curr + (pcmp->block_size / runtime->channels);
end -= snd_pcm_format_width(runtime->format) == 16 ? 2 : 1;
- // snd_printk("init: curr=0x%x, begin=0x%x, end=0x%x, ctrl=0x%x, ramp=0x%x, rate=0x%x\n", curr, begin, end, voice_ctrl, ramp_ctrl, rate);
+ /*
+ snd_printk(KERN_DEBUG "init: curr=0x%x, begin=0x%x, end=0x%x, "
+ "ctrl=0x%x, ramp=0x%x, rate=0x%x\n",
+ curr, begin, end, voice_ctrl, ramp_ctrl, rate);
+ */
pan = runtime->channels == 2 ? (!voice ? 1 : 14) : 8;
vol = !voice ? gus->gf1.pcm_volume_level_left : gus->gf1.pcm_volume_level_right;
spin_lock_irqsave(&gus->reg_lock, flags);
@@ -205,9 +212,11 @@ static void snd_gf1_pcm_interrupt_wave(struct snd_gus_card * gus,
ramp_ctrl = (snd_gf1_read8(gus, SNDRV_GF1_VB_VOLUME_CONTROL) & ~0xa4) | 0x03;
#if 0
snd_gf1_select_voice(gus, pvoice->number);
- printk("position = 0x%x\n", (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
+ printk(KERN_DEBUG "position = 0x%x\n",
+ (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
snd_gf1_select_voice(gus, pcmp->pvoices[1]->number);
- printk("position = 0x%x\n", (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
+ printk(KERN_DEBUG "position = 0x%x\n",
+ (snd_gf1_read_addr(gus, SNDRV_GF1_VA_CURRENT, voice_ctrl & 4) >> 4));
snd_gf1_select_voice(gus, pvoice->number);
#endif
pcmp->bpos++;
@@ -299,7 +308,11 @@ static int snd_gf1_pcm_poke_block(struct snd_gus_card *gus, unsigned char *buf,
unsigned int len;
unsigned long flags;
- // printk("poke block; buf = 0x%x, pos = %i, count = %i, port = 0x%x\n", (int)buf, pos, count, gus->gf1.port);
+ /*
+ printk(KERN_DEBUG
+ "poke block; buf = 0x%x, pos = %i, count = %i, port = 0x%x\n",
+ (int)buf, pos, count, gus->gf1.port);
+ */
while (count > 0) {
len = count;
if (len > 512) /* limit, to allow IRQ */
@@ -680,7 +693,8 @@ static int snd_gf1_pcm_playback_open(struct snd_pcm_substream *substream)
runtime->private_free = snd_gf1_pcm_playback_free;
#if 0
- printk("playback.buffer = 0x%lx, gf1.pcm_buffer = 0x%lx\n", (long) pcm->playback.buffer, (long) gus->gf1.pcm_buffer);
+ printk(KERN_DEBUG "playback.buffer = 0x%lx, gf1.pcm_buffer = 0x%lx\n",
+ (long) pcm->playback.buffer, (long) gus->gf1.pcm_buffer);
#endif
if ((err = snd_gf1_dma_init(gus)) < 0)
return err;
diff --git a/sound/isa/gus/gus_uart.c b/sound/isa/gus/gus_uart.c
index f0af3f79b08..21cc42e4c4b 100644
--- a/sound/isa/gus/gus_uart.c
+++ b/sound/isa/gus/gus_uart.c
@@ -129,8 +129,14 @@ static int snd_gf1_uart_input_open(struct snd_rawmidi_substream *substream)
}
spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
#if 0
- snd_printk("read init - enable = %i, cmd = 0x%x, stat = 0x%x\n", gus->uart_enable, gus->gf1.uart_cmd, snd_gf1_uart_stat(gus));
- snd_printk("[0x%x] reg (ctrl/status) = 0x%x, reg (data) = 0x%x (page = 0x%x)\n", gus->gf1.port + 0x100, inb(gus->gf1.port + 0x100), inb(gus->gf1.port + 0x101), inb(gus->gf1.port + 0x102));
+ snd_printk(KERN_DEBUG
+ "read init - enable = %i, cmd = 0x%x, stat = 0x%x\n",
+ gus->uart_enable, gus->gf1.uart_cmd, snd_gf1_uart_stat(gus));
+ snd_printk(KERN_DEBUG
+ "[0x%x] reg (ctrl/status) = 0x%x, reg (data) = 0x%x "
+ "(page = 0x%x)\n",
+ gus->gf1.port + 0x100, inb(gus->gf1.port + 0x100),
+ inb(gus->gf1.port + 0x101), inb(gus->gf1.port + 0x102));
#endif
return 0;
}
diff --git a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c
index 426532a4d73..086b8f0e0f9 100644
--- a/sound/isa/gus/gusclassic.c
+++ b/sound/isa/gus/gusclassic.c
@@ -148,9 +148,9 @@ static int __devinit snd_gusclassic_probe(struct device *dev, unsigned int n)
struct snd_gus_card *gus;
int error;
- card = snd_card_new(index[n], id[n], THIS_MODULE, 0);
- if (!card)
- return -EINVAL;
+ error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+ if (error < 0)
+ return error;
if (pcm_channels[n] < 2)
pcm_channels[n] = 2;
diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c
index 7ad4c3b41a8..180a8dea6bd 100644
--- a/sound/isa/gus/gusextreme.c
+++ b/sound/isa/gus/gusextreme.c
@@ -241,9 +241,9 @@ static int __devinit snd_gusextreme_probe(struct device *dev, unsigned int n)
struct snd_opl3 *opl3;
int error;
- card = snd_card_new(index[n], id[n], THIS_MODULE, 0);
- if (!card)
- return -EINVAL;
+ error = snd_card_create(index[n], id[n], THIS_MODULE, 0, &card);
+ if (error < 0)
+ return error;
if (mpu_port[n] == SNDRV_AUTO_PORT)
mpu_port[n] = 0;
diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c
index f94c1976e63..f26eac8d811 100644
--- a/sound/isa/gus/gusmax.c
+++ b/sound/isa/gus/gusmax.c
@@ -214,10 +214,10 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev)
struct snd_wss *wss;
struct snd_gusmax *maxcard;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_gusmax));
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_gusmax), &card);
+ if (err < 0)
+ return err;
card->private_free = snd_gusmax_free;
maxcard = (struct snd_gusmax *)card->private_data;
maxcard->card = card;
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
index 5faecfb602d..534a6eced2b 100644
--- a/sound/isa/gus/interwave.c
+++ b/sound/isa/gus/interwave.c
@@ -170,7 +170,7 @@ static void snd_interwave_i2c_setlines(struct snd_i2c_bus *bus, int ctrl, int da
unsigned long port = bus->private_value;
#if 0
- printk("i2c_setlines - 0x%lx <- %i,%i\n", port, ctrl, data);
+ printk(KERN_DEBUG "i2c_setlines - 0x%lx <- %i,%i\n", port, ctrl, data);
#endif
outb((data << 1) | ctrl, port);
udelay(10);
@@ -183,7 +183,7 @@ static int snd_interwave_i2c_getclockline(struct snd_i2c_bus *bus)
res = inb(port) & 1;
#if 0
- printk("i2c_getclockline - 0x%lx -> %i\n", port, res);
+ printk(KERN_DEBUG "i2c_getclockline - 0x%lx -> %i\n", port, res);
#endif
return res;
}
@@ -197,7 +197,7 @@ static int snd_interwave_i2c_getdataline(struct snd_i2c_bus *bus, int ack)
udelay(10);
res = (inb(port) & 2) >> 1;
#if 0
- printk("i2c_getdataline - 0x%lx -> %i\n", port, res);
+ printk(KERN_DEBUG "i2c_getdataline - 0x%lx -> %i\n", port, res);
#endif
return res;
}
@@ -342,7 +342,8 @@ static void __devinit snd_interwave_bank_sizes(struct snd_gus_card * gus, int *s
snd_gf1_poke(gus, local, d);
snd_gf1_poke(gus, local + 1, d + 1);
#if 0
- printk("d = 0x%x, local = 0x%x, local + 1 = 0x%x, idx << 22 = 0x%x\n",
+ printk(KERN_DEBUG "d = 0x%x, local = 0x%x, "
+ "local + 1 = 0x%x, idx << 22 = 0x%x\n",
d,
snd_gf1_peek(gus, local),
snd_gf1_peek(gus, local + 1),
@@ -356,7 +357,8 @@ static void __devinit snd_interwave_bank_sizes(struct snd_gus_card * gus, int *s
}
}
#if 0
- printk("sizes: %i %i %i %i\n", sizes[0], sizes[1], sizes[2], sizes[3]);
+ printk(KERN_DEBUG "sizes: %i %i %i %i\n",
+ sizes[0], sizes[1], sizes[2], sizes[3]);
#endif
}
@@ -410,12 +412,12 @@ static void __devinit snd_interwave_detect_memory(struct snd_gus_card * gus)
lmct = (psizes[3] << 24) | (psizes[2] << 16) |
(psizes[1] << 8) | psizes[0];
#if 0
- printk("lmct = 0x%08x\n", lmct);
+ printk(KERN_DEBUG "lmct = 0x%08x\n", lmct);
#endif
for (i = 0; i < ARRAY_SIZE(lmc); i++)
if (lmct == lmc[i]) {
#if 0
- printk("found !!! %i\n", i);
+ printk(KERN_DEBUG "found !!! %i\n", i);
#endif
snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG, (snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG) & 0xfff0) | i);
snd_interwave_bank_sizes(gus, psizes);
@@ -626,20 +628,22 @@ static void snd_interwave_free(struct snd_card *card)
free_irq(iwcard->irq, (void *)iwcard);
}
-static struct snd_card *snd_interwave_card_new(int dev)
+static int snd_interwave_card_new(int dev, struct snd_card **cardp)
{
struct snd_card *card;
struct snd_interwave *iwcard;
+ int err;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_interwave));
- if (card == NULL)
- return NULL;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_interwave), &card);
+ if (err < 0)
+ return err;
iwcard = card->private_data;
iwcard->card = card;
iwcard->irq = -1;
card->private_free = snd_interwave_free;
- return card;
+ *cardp = card;
+ return 0;
}
static int __devinit snd_interwave_probe(struct snd_card *card, int dev)
@@ -778,9 +782,9 @@ static int __devinit snd_interwave_isa_probe1(int dev, struct device *devptr)
struct snd_card *card;
int err;
- card = snd_interwave_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_interwave_card_new(dev, &card);
+ if (err < 0)
+ return err;
snd_card_set_dev(card, devptr);
if ((err = snd_interwave_probe(card, dev)) < 0) {
@@ -876,9 +880,9 @@ static int __devinit snd_interwave_pnp_detect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_interwave_card_new(dev);
- if (! card)
- return -ENOMEM;
+ res = snd_interwave_card_new(dev, &card);
+ if (res < 0)
+ return res;
if ((res = snd_interwave_pnp(dev, card->private_data, pcard, pid)) < 0) {
snd_card_free(card);
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index 58c972b2af0..9c5fce31f06 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -179,12 +179,13 @@ static unsigned char __snd_opl3sa2_read(struct snd_opl3sa2 *chip, unsigned char
unsigned char result;
#if 0
outb(0x1d, port); /* password */
- printk("read [0x%lx] = 0x%x\n", port, inb(port));
+ printk(KERN_DEBUG "read [0x%lx] = 0x%x\n", port, inb(port));
#endif
outb(reg, chip->port); /* register */
result = inb(chip->port + 1);
#if 0
- printk("read [0x%lx] = 0x%x [0x%x]\n", port, result, inb(port));
+ printk(KERN_DEBUG "read [0x%lx] = 0x%x [0x%x]\n",
+ port, result, inb(port));
#endif
return result;
}
@@ -233,7 +234,10 @@ static int __devinit snd_opl3sa2_detect(struct snd_card *card)
snd_printk(KERN_ERR PFX "can't grab port 0x%lx\n", port);
return -EBUSY;
}
- // snd_printk("REG 0A = 0x%x\n", snd_opl3sa2_read(chip, 0x0a));
+ /*
+ snd_printk(KERN_DEBUG "REG 0A = 0x%x\n",
+ snd_opl3sa2_read(chip, 0x0a));
+ */
chip->version = 0;
tmp = snd_opl3sa2_read(chip, OPL3SA2_MISC);
if (tmp == 0xff) {
@@ -550,21 +554,27 @@ static int __devinit snd_opl3sa2_mixer(struct snd_card *card)
#ifdef CONFIG_PM
static int snd_opl3sa2_suspend(struct snd_card *card, pm_message_t state)
{
- struct snd_opl3sa2 *chip = card->private_data;
+ if (card) {
+ struct snd_opl3sa2 *chip = card->private_data;
- snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
- chip->wss->suspend(chip->wss);
- /* power down */
- snd_opl3sa2_write(chip, OPL3SA2_PM_CTRL, OPL3SA2_PM_D3);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ chip->wss->suspend(chip->wss);
+ /* power down */
+ snd_opl3sa2_write(chip, OPL3SA2_PM_CTRL, OPL3SA2_PM_D3);
+ }
return 0;
}
static int snd_opl3sa2_resume(struct snd_card *card)
{
- struct snd_opl3sa2 *chip = card->private_data;
+ struct snd_opl3sa2 *chip;
int i;
+ if (!card)
+ return 0;
+
+ chip = card->private_data;
/* power up */
snd_opl3sa2_write(chip, OPL3SA2_PM_CTRL, OPL3SA2_PM_D0);
@@ -617,21 +627,24 @@ static void snd_opl3sa2_free(struct snd_card *card)
release_and_free_resource(chip->res_port);
}
-static struct snd_card *snd_opl3sa2_card_new(int dev)
+static int snd_opl3sa2_card_new(int dev, struct snd_card **cardp)
{
struct snd_card *card;
struct snd_opl3sa2 *chip;
+ int err;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct snd_opl3sa2));
- if (card == NULL)
- return NULL;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_opl3sa2), &card);
+ if (err < 0)
+ return err;
strcpy(card->driver, "OPL3SA2");
strcpy(card->shortname, "Yamaha OPL3-SA2");
chip = card->private_data;
spin_lock_init(&chip->reg_lock);
chip->irq = -1;
card->private_free = snd_opl3sa2_free;
- return card;
+ *cardp = card;
+ return 0;
}
static int __devinit snd_opl3sa2_probe(struct snd_card *card, int dev)
@@ -723,9 +736,9 @@ static int __devinit snd_opl3sa2_pnp_detect(struct pnp_dev *pdev,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_opl3sa2_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_opl3sa2_card_new(dev, &card);
+ if (err < 0)
+ return err;
if ((err = snd_opl3sa2_pnp(dev, card->private_data, pdev)) < 0) {
snd_card_free(card);
return err;
@@ -789,9 +802,9 @@ static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_opl3sa2_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_opl3sa2_card_new(dev, &card);
+ if (err < 0)
+ return err;
if ((err = snd_opl3sa2_pnp(dev, card->private_data, pdev)) < 0) {
snd_card_free(card);
return err;
@@ -870,9 +883,9 @@ static int __devinit snd_opl3sa2_isa_probe(struct device *pdev,
struct snd_card *card;
int err;
- card = snd_opl3sa2_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_opl3sa2_card_new(dev, &card);
+ if (err < 0)
+ return err;
snd_card_set_dev(card, pdev);
if ((err = snd_opl3sa2_probe(card, dev)) < 0) {
snd_card_free(card);
diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c
index 440755cc001..02e30d7c6a9 100644
--- a/sound/isa/opti9xx/miro.c
+++ b/sound/isa/opti9xx/miro.c
@@ -1228,9 +1228,10 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n)
struct snd_pcm *pcm;
struct snd_rawmidi *rmidi;
- if (!(card = snd_card_new(index, id, THIS_MODULE,
- sizeof(struct snd_miro))))
- return -ENOMEM;
+ error = snd_card_create(index, id, THIS_MODULE,
+ sizeof(struct snd_miro), &card);
+ if (error < 0)
+ return error;
card->private_free = snd_card_miro_free;
miro = card->private_data;
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index 19706b0d849..5cd555325b9 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -252,7 +252,7 @@ static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip,
#endif /* OPTi93X */
default:
- snd_printk("chip %d not supported\n", hardware);
+ snd_printk(KERN_ERR "chip %d not supported\n", hardware);
return -ENODEV;
}
return 0;
@@ -294,7 +294,7 @@ static unsigned char snd_opti9xx_read(struct snd_opti9xx *chip,
#endif /* OPTi93X */
default:
- snd_printk("chip %d not supported\n", chip->hardware);
+ snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
}
spin_unlock_irqrestore(&chip->lock, flags);
@@ -336,7 +336,7 @@ static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg,
#endif /* OPTi93X */
default:
- snd_printk("chip %d not supported\n", chip->hardware);
+ snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
}
spin_unlock_irqrestore(&chip->lock, flags);
@@ -412,7 +412,7 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip)
#endif /* OPTi93X */
default:
- snd_printk("chip %d not supported\n", chip->hardware);
+ snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
return -EINVAL;
}
@@ -430,7 +430,8 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip)
wss_base_bits = 0x02;
break;
default:
- snd_printk("WSS port 0x%lx not valid\n", chip->wss_base);
+ snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n",
+ chip->wss_base);
goto __skip_base;
}
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30);
@@ -455,7 +456,7 @@ __skip_base:
irq_bits = 0x04;
break;
default:
- snd_printk("WSS irq # %d not valid\n", chip->irq);
+ snd_printk(KERN_WARNING "WSS irq # %d not valid\n", chip->irq);
goto __skip_resources;
}
@@ -470,13 +471,14 @@ __skip_base:
dma_bits = 0x03;
break;
default:
- snd_printk("WSS dma1 # %d not valid\n", chip->dma1);
+ snd_printk(KERN_WARNING "WSS dma1 # %d not valid\n",
+ chip->dma1);
goto __skip_resources;
}
#if defined(CS4231) || defined(OPTi93X)
if (chip->dma1 == chip->dma2) {
- snd_printk("don't want to share dmas\n");
+ snd_printk(KERN_ERR "don't want to share dmas\n");
return -EBUSY;
}
@@ -485,7 +487,8 @@ __skip_base:
case 1:
break;
default:
- snd_printk("WSS dma2 # %d not valid\n", chip->dma2);
+ snd_printk(KERN_WARNING "WSS dma2 # %d not valid\n",
+ chip->dma2);
goto __skip_resources;
}
dma_bits |= 0x04;
@@ -516,7 +519,8 @@ __skip_resources:
mpu_port_bits = 0x00;
break;
default:
- snd_printk("MPU-401 port 0x%lx not valid\n",
+ snd_printk(KERN_WARNING
+ "MPU-401 port 0x%lx not valid\n",
chip->mpu_port);
goto __skip_mpu;
}
@@ -535,7 +539,7 @@ __skip_resources:
mpu_irq_bits = 0x01;
break;
default:
- snd_printk("MPU-401 irq # %d not valid\n",
+ snd_printk(KERN_WARNING "MPU-401 irq # %d not valid\n",
chip->mpu_irq);
goto __skip_mpu;
}
@@ -726,7 +730,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
if (chip->wss_base == SNDRV_AUTO_PORT) {
chip->wss_base = snd_legacy_find_free_ioport(possible_ports, 4);
if (chip->wss_base < 0) {
- snd_printk("unable to find a free WSS port\n");
+ snd_printk(KERN_ERR "unable to find a free WSS port\n");
return -EBUSY;
}
}
@@ -815,14 +819,8 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
chip->fm_port, chip->fm_port + 4 - 1);
}
if (opl3) {
-#ifdef CS4231
- const int t1dev = 1;
-#else
- const int t1dev = 0;
-#endif
- if ((error = snd_opl3_timer_new(opl3, t1dev, t1dev+1)) < 0)
- return error;
- if ((error = snd_opl3_hwdep_new(opl3, 0, 1, &synth)) < 0)
+ error = snd_opl3_hwdep_new(opl3, 0, 1, &synth);
+ if (error < 0)
return error;
}
}
@@ -830,15 +828,18 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
return snd_card_register(card);
}
-static struct snd_card *snd_opti9xx_card_new(void)
+static int snd_opti9xx_card_new(struct snd_card **cardp)
{
struct snd_card *card;
+ int err;
- card = snd_card_new(index, id, THIS_MODULE, sizeof(struct snd_opti9xx));
- if (! card)
- return NULL;
+ err = snd_card_create(index, id, THIS_MODULE,
+ sizeof(struct snd_opti9xx), &card);
+ if (err < 0)
+ return err;
card->private_free = snd_card_opti9xx_free;
- return card;
+ *cardp = card;
+ return 0;
}
static int __devinit snd_opti9xx_isa_match(struct device *devptr,
@@ -897,15 +898,15 @@ static int __devinit snd_opti9xx_isa_probe(struct device *devptr,
#if defined(CS4231) || defined(OPTi93X)
if (dma2 == SNDRV_AUTO_DMA) {
if ((dma2 = snd_legacy_find_free_dma(possible_dma2s[dma1 % 4])) < 0) {
- snd_printk("unable to find a free DMA2\n");
+ snd_printk(KERN_ERR "unable to find a free DMA2\n");
return -EBUSY;
}
}
#endif
- card = snd_opti9xx_card_new();
- if (! card)
- return -ENOMEM;
+ error = snd_opti9xx_card_new(&card);
+ if (error < 0)
+ return error;
if ((error = snd_card_opti9xx_detect(card, card->private_data)) < 0) {
snd_card_free(card);
@@ -950,9 +951,9 @@ static int __devinit snd_opti9xx_pnp_probe(struct pnp_card_link *pcard,
return -EBUSY;
if (! isapnp)
return -ENODEV;
- card = snd_opti9xx_card_new();
- if (! card)
- return -ENOMEM;
+ error = snd_opti9xx_card_new(&card);
+ if (error < 0)
+ return error;
chip = card->private_data;
hw = snd_card_opti9xx_pnp(chip, pcard, pid);
diff --git a/sound/isa/sb/es968.c b/sound/isa/sb/es968.c
index c8c8e214c84..cafc3a7316a 100644
--- a/sound/isa/sb/es968.c
+++ b/sound/isa/sb/es968.c
@@ -108,9 +108,10 @@ static int __devinit snd_card_es968_probe(int dev,
struct snd_card *card;
struct snd_card_es968 *acard;
- if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_es968))) == NULL)
- return -ENOMEM;
+ error = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_es968), &card);
+ if (error < 0)
+ return error;
acard = card->private_data;
if ((error = snd_card_es968_pnp(dev, acard, pcard, pid))) {
snd_card_free(card);
diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c
index 2c201f78ce5..519c36346de 100644
--- a/sound/isa/sb/sb16.c
+++ b/sound/isa/sb/sb16.c
@@ -324,14 +324,18 @@ static void snd_sb16_free(struct snd_card *card)
#define is_isapnp_selected(dev) 0
#endif
-static struct snd_card *snd_sb16_card_new(int dev)
+static int snd_sb16_card_new(int dev, struct snd_card **cardp)
{
- struct snd_card *card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_card_sb16));
- if (card == NULL)
- return NULL;
+ struct snd_card *card;
+ int err;
+
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_card_sb16), &card);
+ if (err < 0)
+ return err;
card->private_free = snd_sb16_free;
- return card;
+ *cardp = card;
+ return 0;
}
static int __devinit snd_sb16_probe(struct snd_card *card, int dev)
@@ -489,9 +493,9 @@ static int __devinit snd_sb16_isa_probe1(int dev, struct device *pdev)
struct snd_card *card;
int err;
- card = snd_sb16_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_sb16_card_new(dev, &card);
+ if (err < 0)
+ return err;
acard = card->private_data;
/* non-PnP FM port address is hardwired with base port address */
@@ -610,9 +614,9 @@ static int __devinit snd_sb16_pnp_detect(struct pnp_card_link *pcard,
for ( ; dev < SNDRV_CARDS; dev++) {
if (!enable[dev] || !isapnp[dev])
continue;
- card = snd_sb16_card_new(dev);
- if (! card)
- return -ENOMEM;
+ res = snd_sb16_card_new(dev, &card);
+ if (res < 0)
+ return res;
snd_card_set_dev(card, &pcard->card->dev);
if ((res = snd_card_sb16_pnp(dev, card->private_data, pcard, pid)) < 0 ||
(res = snd_sb16_probe(card, dev)) < 0) {
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c
index ea06877be4b..3cd57ee5466 100644
--- a/sound/isa/sb/sb8.c
+++ b/sound/isa/sb/sb8.c
@@ -103,10 +103,10 @@ static int __devinit snd_sb8_probe(struct device *pdev, unsigned int dev)
struct snd_opl3 *opl3;
int err;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_sb8));
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_sb8), &card);
+ if (err < 0)
+ return err;
acard = card->private_data;
card->private_free = snd_sb8_free;
diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c
index ca35924dc3b..782010608ef 100644
--- a/sound/isa/sc6000.c
+++ b/sound/isa/sc6000.c
@@ -489,9 +489,9 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
char __iomem *vmss_port;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (!card)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
if (xirq == SNDRV_AUTO_IRQ) {
xirq = snd_legacy_find_free_irq(possible_irqs);
@@ -576,10 +576,6 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
snd_printk(KERN_ERR PFX "no OPL device at 0x%x-0x%x ?\n",
0x388, 0x388 + 2);
} else {
- err = snd_opl3_timer_new(opl3, 0, 1);
- if (err < 0)
- goto err_unmap2;
-
err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
if (err < 0)
goto err_unmap2;
diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c
index 2c7503bf127..6fe27b9d944 100644
--- a/sound/isa/sgalaxy.c
+++ b/sound/isa/sgalaxy.c
@@ -243,9 +243,9 @@ static int __devinit snd_sgalaxy_probe(struct device *devptr, unsigned int dev)
struct snd_card *card;
struct snd_wss *chip;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
xirq = irq[dev];
if (xirq == SNDRV_AUTO_IRQ) {
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c
index 48a16d86583..4025fb558c5 100644
--- a/sound/isa/sscape.c
+++ b/sound/isa/sscape.c
@@ -1357,10 +1357,10 @@ static int __devinit snd_sscape_probe(struct device *pdev, unsigned int dev)
struct soundscape *sscape;
int ret;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct soundscape));
- if (!card)
- return -ENOMEM;
+ ret = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct soundscape), &card);
+ if (ret < 0)
+ return ret;
sscape = get_card_soundscape(card);
sscape->type = SSCAPE;
@@ -1462,10 +1462,10 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard,
* Create a new ALSA sound card entry, in anticipation
* of detecting our hardware ...
*/
- card = snd_card_new(index[idx], id[idx], THIS_MODULE,
- sizeof(struct soundscape));
- if (!card)
- return -ENOMEM;
+ ret = snd_card_create(index[idx], id[idx], THIS_MODULE,
+ sizeof(struct soundscape), &card);
+ if (ret < 0)
+ return ret;
sscape = get_card_soundscape(card);
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c
index 4c095bc7c72..a34ae7b1f7d 100644
--- a/sound/isa/wavefront/wavefront.c
+++ b/sound/isa/wavefront/wavefront.c
@@ -338,15 +338,16 @@ snd_wavefront_free(struct snd_card *card)
}
}
-static struct snd_card *snd_wavefront_card_new(int dev)
+static int snd_wavefront_card_new(int dev, struct snd_card **cardp)
{
struct snd_card *card;
snd_wavefront_card_t *acard;
+ int err;
- card = snd_card_new (index[dev], id[dev], THIS_MODULE,
- sizeof(snd_wavefront_card_t));
- if (card == NULL)
- return NULL;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(snd_wavefront_card_t), &card);
+ if (err < 0)
+ return err;
acard = card->private_data;
acard->wavefront.irq = -1;
@@ -357,7 +358,8 @@ static struct snd_card *snd_wavefront_card_new(int dev)
acard->wavefront.card = card;
card->private_free = snd_wavefront_free;
- return card;
+ *cardp = card;
+ return 0;
}
static int __devinit
@@ -551,11 +553,11 @@ static int __devinit snd_wavefront_isa_match(struct device *pdev,
return 0;
#endif
if (cs4232_pcm_port[dev] == SNDRV_AUTO_PORT) {
- snd_printk("specify CS4232 port\n");
+ snd_printk(KERN_ERR "specify CS4232 port\n");
return 0;
}
if (ics2115_port[dev] == SNDRV_AUTO_PORT) {
- snd_printk("specify ICS2115 port\n");
+ snd_printk(KERN_ERR "specify ICS2115 port\n");
return 0;
}
return 1;
@@ -567,9 +569,9 @@ static int __devinit snd_wavefront_isa_probe(struct device *pdev,
struct snd_card *card;
int err;
- card = snd_wavefront_card_new(dev);
- if (! card)
- return -ENOMEM;
+ err = snd_wavefront_card_new(dev, &card);
+ if (err < 0)
+ return err;
snd_card_set_dev(card, pdev);
if ((err = snd_wavefront_probe(card, dev)) < 0) {
snd_card_free(card);
@@ -616,9 +618,9 @@ static int __devinit snd_wavefront_pnp_detect(struct pnp_card_link *pcard,
if (dev >= SNDRV_CARDS)
return -ENODEV;
- card = snd_wavefront_card_new(dev);
- if (! card)
- return -ENOMEM;
+ res = snd_wavefront_card_new(dev, &card);
+ if (res < 0)
+ return res;
if (snd_wavefront_pnp (dev, card->private_data, pcard, pid) < 0) {
if (cs4232_pcm_port[dev] == SNDRV_AUTO_PORT) {
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
index 4c410820a99..beb312cca75 100644
--- a/sound/isa/wavefront/wavefront_synth.c
+++ b/sound/isa/wavefront/wavefront_synth.c
@@ -633,7 +633,7 @@ wavefront_get_sample_status (snd_wavefront_t *dev, int assume_rom)
wbuf[1] = i >> 7;
if (snd_wavefront_cmd (dev, WFC_IDENTIFY_SAMPLE_TYPE, rbuf, wbuf)) {
- snd_printk("cannot identify sample "
+ snd_printk(KERN_WARNING "cannot identify sample "
"type of slot %d\n", i);
dev->sample_status[i] = WF_ST_EMPTY;
continue;
diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c
index 3d6c5f2838a..ac27832b2c6 100644
--- a/sound/isa/wss/wss_lib.c
+++ b/sound/isa/wss/wss_lib.c
@@ -219,7 +219,8 @@ void snd_wss_out(struct snd_wss *chip, unsigned char reg, unsigned char value)
snd_wss_wait(chip);
#ifdef CONFIG_SND_DEBUG
if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
+ snd_printk(KERN_DEBUG "out: auto calibration time out "
+ "- reg = 0x%x, value = 0x%x\n", reg, value);
#endif
wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
wss_outb(chip, CS4231P(REG), value);
@@ -235,7 +236,8 @@ unsigned char snd_wss_in(struct snd_wss *chip, unsigned char reg)
snd_wss_wait(chip);
#ifdef CONFIG_SND_DEBUG
if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- snd_printk("in: auto calibration time out - reg = 0x%x\n", reg);
+ snd_printk(KERN_DEBUG "in: auto calibration time out "
+ "- reg = 0x%x\n", reg);
#endif
wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
mb();
@@ -252,7 +254,7 @@ void snd_cs4236_ext_out(struct snd_wss *chip, unsigned char reg,
wss_outb(chip, CS4231P(REG), val);
chip->eimage[CS4236_REG(reg)] = val;
#if 0
- printk("ext out : reg = 0x%x, val = 0x%x\n", reg, val);
+ printk(KERN_DEBUG "ext out : reg = 0x%x, val = 0x%x\n", reg, val);
#endif
}
EXPORT_SYMBOL(snd_cs4236_ext_out);
@@ -268,7 +270,8 @@ unsigned char snd_cs4236_ext_in(struct snd_wss *chip, unsigned char reg)
{
unsigned char res;
res = wss_inb(chip, CS4231P(REG));
- printk("ext in : reg = 0x%x, val = 0x%x\n", reg, res);
+ printk(KERN_DEBUG "ext in : reg = 0x%x, val = 0x%x\n",
+ reg, res);
return res;
}
#endif
@@ -394,13 +397,16 @@ void snd_wss_mce_up(struct snd_wss *chip)
snd_wss_wait(chip);
#ifdef CONFIG_SND_DEBUG
if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- snd_printk("mce_up - auto calibration time out (0)\n");
+ snd_printk(KERN_DEBUG
+ "mce_up - auto calibration time out (0)\n");
#endif
spin_lock_irqsave(&chip->reg_lock, flags);
chip->mce_bit |= CS4231_MCE;
timeout = wss_inb(chip, CS4231P(REGSEL));
if (timeout == 0x80)
- snd_printk("mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port);
+ snd_printk(KERN_DEBUG "mce_up [0x%lx]: "
+ "serious init problem - codec still busy\n",
+ chip->port);
if (!(timeout & CS4231_MCE))
wss_outb(chip, CS4231P(REGSEL),
chip->mce_bit | (timeout & 0x1f));
@@ -419,7 +425,9 @@ void snd_wss_mce_down(struct snd_wss *chip)
#ifdef CONFIG_SND_DEBUG
if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
- snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", (long)CS4231P(REGSEL));
+ snd_printk(KERN_DEBUG "mce_down [0x%lx] - "
+ "auto calibration time out (0)\n",
+ (long)CS4231P(REGSEL));
#endif
spin_lock_irqsave(&chip->reg_lock, flags);
chip->mce_bit &= ~CS4231_MCE;
@@ -427,7 +435,9 @@ void snd_wss_mce_down(struct snd_wss *chip)
wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
spin_unlock_irqrestore(&chip->reg_lock, flags);
if (timeout == 0x80)
- snd_printk("mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port);
+ snd_printk(KERN_DEBUG "mce_down [0x%lx]: "
+ "serious init problem - codec still busy\n",
+ chip->port);
if ((timeout & CS4231_MCE) == 0 || !(chip->hardware & hw_mask))
return;
@@ -565,7 +575,7 @@ static unsigned char snd_wss_get_format(struct snd_wss *chip,
if (channels > 1)
rformat |= CS4231_STEREO;
#if 0
- snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);
+ snd_printk(KERN_DEBUG "get_format: 0x%x (mode=0x%x)\n", format, mode);
#endif
return rformat;
}
@@ -774,7 +784,7 @@ static void snd_wss_init(struct snd_wss *chip)
snd_wss_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE
- snd_printk("init: (1)\n");
+ snd_printk(KERN_DEBUG "init: (1)\n");
#endif
snd_wss_mce_up(chip);
spin_lock_irqsave(&chip->reg_lock, flags);
@@ -789,7 +799,7 @@ static void snd_wss_init(struct snd_wss *chip)
snd_wss_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE
- snd_printk("init: (2)\n");
+ snd_printk(KERN_DEBUG "init: (2)\n");
#endif
snd_wss_mce_up(chip);
@@ -800,7 +810,7 @@ static void snd_wss_init(struct snd_wss *chip)
snd_wss_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE
- snd_printk("init: (3) - afei = 0x%x\n",
+ snd_printk(KERN_DEBUG "init: (3) - afei = 0x%x\n",
chip->image[CS4231_ALT_FEATURE_1]);
#endif
@@ -817,7 +827,7 @@ static void snd_wss_init(struct snd_wss *chip)
snd_wss_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE
- snd_printk("init: (4)\n");
+ snd_printk(KERN_DEBUG "init: (4)\n");
#endif
snd_wss_mce_up(chip);
@@ -829,7 +839,7 @@ static void snd_wss_init(struct snd_wss *chip)
snd_wss_mce_down(chip);
#ifdef SNDRV_DEBUG_MCE
- snd_printk("init: (5)\n");
+ snd_printk(KERN_DEBUG "init: (5)\n");
#endif
}
@@ -1278,7 +1288,8 @@ static int snd_wss_probe(struct snd_wss *chip)
} else if (rev == 0x03) {
chip->hardware = WSS_HW_CS4236B;
} else {
- snd_printk("unknown CS chip with version 0x%x\n", rev);
+ snd_printk(KERN_ERR
+ "unknown CS chip with version 0x%x\n", rev);
return -ENODEV; /* unknown CS4231 chip? */
}
}
@@ -1342,7 +1353,10 @@ static int snd_wss_probe(struct snd_wss *chip)
case 6:
break;
default:
- snd_printk("unknown CS4235 chip (enhanced version = 0x%x)\n", id);
+ snd_printk(KERN_WARNING
+ "unknown CS4235 chip "
+ "(enhanced version = 0x%x)\n",
+ id);
}
} else if ((id & 0x1f) == 0x0b) { /* CS4236/B */
switch (id >> 5) {
@@ -1353,7 +1367,10 @@ static int snd_wss_probe(struct snd_wss *chip)
chip->hardware = WSS_HW_CS4236B;
break;
default:
- snd_printk("unknown CS4236 chip (enhanced version = 0x%x)\n", id);
+ snd_printk(KERN_WARNING
+ "unknown CS4236 chip "
+ "(enhanced version = 0x%x)\n",
+ id);
}
} else if ((id & 0x1f) == 0x08) { /* CS4237B */
chip->hardware = WSS_HW_CS4237B;
@@ -1364,7 +1381,10 @@ static int snd_wss_probe(struct snd_wss *chip)
case 7:
break;
default:
- snd_printk("unknown CS4237B chip (enhanced version = 0x%x)\n", id);
+ snd_printk(KERN_WARNING
+ "unknown CS4237B chip "
+ "(enhanced version = 0x%x)\n",
+ id);
}
} else if ((id & 0x1f) == 0x09) { /* CS4238B */
chip->hardware = WSS_HW_CS4238B;
@@ -1374,7 +1394,10 @@ static int snd_wss_probe(struct snd_wss *chip)
case 7:
break;
default:
- snd_printk("unknown CS4238B chip (enhanced version = 0x%x)\n", id);
+ snd_printk(KERN_WARNING
+ "unknown CS4238B chip "
+ "(enhanced version = 0x%x)\n",
+ id);
}
} else if ((id & 0x1f) == 0x1e) { /* CS4239 */
chip->hardware = WSS_HW_CS4239;
@@ -1384,10 +1407,15 @@ static int snd_wss_probe(struct snd_wss *chip)
case 6:
break;
default:
- snd_printk("unknown CS4239 chip (enhanced version = 0x%x)\n", id);
+ snd_printk(KERN_WARNING
+ "unknown CS4239 chip "
+ "(enhanced version = 0x%x)\n",
+ id);
}
} else {
- snd_printk("unknown CS4236/CS423xB chip (enhanced version = 0x%x)\n", id);
+ snd_printk(KERN_WARNING
+ "unknown CS4236/CS423xB chip "
+ "(enhanced version = 0x%x)\n", id);
}
}
}
@@ -1618,7 +1646,8 @@ static void snd_wss_resume(struct snd_wss *chip)
wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
spin_unlock_irqrestore(&chip->reg_lock, flags);
if (timeout == 0x80)
- snd_printk("down [0x%lx]: serious init problem - codec still busy\n", chip->port);
+ snd_printk(KERN_ERR "down [0x%lx]: serious init problem "
+ "- codec still busy\n", chip->port);
if ((timeout & CS4231_MCE) == 0 ||
!(chip->hardware & (WSS_HW_CS4231_MASK | WSS_HW_CS4232_MASK))) {
return;
@@ -1628,7 +1657,7 @@ static void snd_wss_resume(struct snd_wss *chip)
}
#endif /* CONFIG_PM */
-static int snd_wss_free(struct snd_wss *chip)
+int snd_wss_free(struct snd_wss *chip)
{
release_and_free_resource(chip->res_port);
release_and_free_resource(chip->res_cport);
@@ -1651,6 +1680,7 @@ static int snd_wss_free(struct snd_wss *chip)
kfree(chip);
return 0;
}
+EXPORT_SYMBOL(snd_wss_free);
static int snd_wss_dev_free(struct snd_device *device)
{
@@ -1820,7 +1850,8 @@ int snd_wss_create(struct snd_card *card,
#if 0
if (chip->hardware & WSS_HW_CS4232_MASK) {
if (chip->res_cport == NULL)
- snd_printk("CS4232 control port features are not accessible\n");
+ snd_printk(KERN_ERR "CS4232 control port features are "
+ "not accessible\n");
}
#endif
diff --git a/sound/mips/au1x00.c b/sound/mips/au1x00.c
index 1881cec11e7..3e763d6a5d6 100644
--- a/sound/mips/au1x00.c
+++ b/sound/mips/au1x00.c
@@ -636,9 +636,10 @@ au1000_init(void)
struct snd_card *card;
struct snd_au1000 *au1000;
- card = snd_card_new(-1, "AC97", THIS_MODULE, sizeof(struct snd_au1000));
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(-1, "AC97", THIS_MODULE,
+ sizeof(struct snd_au1000), &card);
+ if (err < 0)
+ return err;
card->private_free = snd_au1000_free;
au1000 = card->private_data;
@@ -678,7 +679,7 @@ au1000_init(void)
return err;
}
- printk( KERN_INFO "ALSA AC97: Driver Initialized\n" );
+ printk(KERN_INFO "ALSA AC97: Driver Initialized\n");
au1000_card = card;
return 0;
}
diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c
index db495be0186..c52691c2fc4 100644
--- a/sound/mips/hal2.c
+++ b/sound/mips/hal2.c
@@ -878,9 +878,9 @@ static int __devinit hal2_probe(struct platform_device *pdev)
struct snd_hal2 *chip;
int err;
- card = snd_card_new(index, id, THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
err = hal2_create(card, &chip);
if (err < 0) {
diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c
index 4c63504348d..66f3b48ceaf 100644
--- a/sound/mips/sgio2audio.c
+++ b/sound/mips/sgio2audio.c
@@ -936,9 +936,9 @@ static int __devinit snd_sgio2audio_probe(struct platform_device *pdev)
struct snd_sgio2audio *chip;
int err;
- card = snd_card_new(index, id, THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
err = snd_sgio2audio_create(card, &chip);
if (err < 0) {
diff --git a/sound/oss/dmasound/dmasound_atari.c b/sound/oss/dmasound/dmasound_atari.c
index 57d9f154c88..38931f2f696 100644
--- a/sound/oss/dmasound/dmasound_atari.c
+++ b/sound/oss/dmasound/dmasound_atari.c
@@ -847,23 +847,23 @@ static int __init AtaIrqInit(void)
of events. So all we need to keep the music playing is
to provide the sound hardware with new data upon
an interrupt from timer A. */
- mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */
- mfp.tim_dt_a = 1; /* Cause interrupt after first event. */
- mfp.tim_ct_a = 8; /* Turn on event counting. */
+ st_mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */
+ st_mfp.tim_dt_a = 1; /* Cause interrupt after first event. */
+ st_mfp.tim_ct_a = 8; /* Turn on event counting. */
/* Register interrupt handler. */
if (request_irq(IRQ_MFP_TIMA, AtaInterrupt, IRQ_TYPE_SLOW, "DMA sound",
AtaInterrupt))
return 0;
- mfp.int_en_a |= 0x20; /* Turn interrupt on. */
- mfp.int_mk_a |= 0x20;
+ st_mfp.int_en_a |= 0x20; /* Turn interrupt on. */
+ st_mfp.int_mk_a |= 0x20;
return 1;
}
#ifdef MODULE
static void AtaIrqCleanUp(void)
{
- mfp.tim_ct_a = 0; /* stop timer */
- mfp.int_en_a &= ~0x20; /* turn interrupt off */
+ st_mfp.tim_ct_a = 0; /* stop timer */
+ st_mfp.int_en_a &= ~0x20; /* turn interrupt off */
free_irq(IRQ_MFP_TIMA, AtaInterrupt);
}
#endif /* MODULE */
@@ -1599,7 +1599,7 @@ static int __init dmasound_atari_init(void)
is_falcon = 0;
} else
return -ENODEV;
- if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)
+ if ((st_mfp.int_en_a & st_mfp.int_mk_a & 0x20) == 0)
return dmasound_init();
else {
printk("DMA sound driver: Timer A interrupt already in use\n");
diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c
index 41f870f8a11..6055fd6d3b3 100644
--- a/sound/parisc/harmony.c
+++ b/sound/parisc/harmony.c
@@ -975,9 +975,9 @@ snd_harmony_probe(struct parisc_device *padev)
struct snd_card *card;
struct snd_harmony *h;
- card = snd_card_new(index, id, THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
err = snd_harmony_create(card, padev, &h);
if (err < 0)
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 82b9bddcdcd..9387ab00a41 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -400,6 +400,26 @@ config SND_INDIGODJ
To compile this driver as a module, choose M here: the module
will be called snd-indigodj
+config SND_INDIGOIOX
+ tristate "(Echoaudio) Indigo IOx"
+ select FW_LOADER
+ select SND_PCM
+ help
+ Say 'Y' or 'M' to include support for Echoaudio Indigo IOx.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-indigoiox
+
+config SND_INDIGODJX
+ tristate "(Echoaudio) Indigo DJx"
+ select FW_LOADER
+ select SND_PCM
+ help
+ Say 'Y' or 'M' to include support for Echoaudio Indigo DJx.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-indigodjx
+
config SND_EMU10K1
tristate "Emu10k1 (SB Live!, Audigy, E-mu APS)"
select FW_LOADER
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index e2b843b4f9d..44f2381b0ae 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -143,6 +143,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
{ 0x43525970, 0xfffffff8, "CS4202", NULL, NULL },
{ 0x43585421, 0xffffffff, "HSD11246", NULL, NULL }, // SmartMC II
{ 0x43585428, 0xfffffff8, "Cx20468", patch_conexant, NULL }, // SmartAMC fixme: the mask might be different
+{ 0x43585430, 0xffffffff, "Cx20468-31", patch_conexant, NULL },
{ 0x43585431, 0xffffffff, "Cx20551", patch_cx20551, NULL },
{ 0x44543031, 0xfffffff0, "DT0398", NULL, NULL },
{ 0x454d4328, 0xffffffff, "EM28028", NULL, NULL }, // same as TR28028?
@@ -1643,7 +1644,10 @@ static int snd_ac97_modem_build(struct snd_card *card, struct snd_ac97 * ac97)
{
int err, idx;
- //printk("AC97_GPIO_CFG = %x\n",snd_ac97_read(ac97,AC97_GPIO_CFG));
+ /*
+ printk(KERN_DEBUG "AC97_GPIO_CFG = %x\n",
+ snd_ac97_read(ac97,AC97_GPIO_CFG));
+ */
snd_ac97_write(ac97, AC97_GPIO_CFG, 0xffff & ~(AC97_GPIO_LINE1_OH));
snd_ac97_write(ac97, AC97_GPIO_POLARITY, 0xffff & ~(AC97_GPIO_LINE1_OH));
snd_ac97_write(ac97, AC97_GPIO_STICKY, 0xffff);
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index a7f38e63303..d1f242bd0ac 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -995,10 +995,10 @@ snd_ad1889_probe(struct pci_dev *pci,
}
/* (2) */
- card = snd_card_new(index[devno], id[devno], THIS_MODULE, 0);
+ err = snd_card_create(index[devno], id[devno], THIS_MODULE, 0, &card);
/* XXX REVISIT: we can probably allocate chip in this call */
- if (card == NULL)
- return -ENOMEM;
+ if (err < 0)
+ return err;
strcpy(card->driver, "AD1889");
strcpy(card->shortname, "Analog Devices AD1889");
diff --git a/sound/pci/ak4531_codec.c b/sound/pci/ak4531_codec.c
index 0f819ddb3eb..fd135e3d8a8 100644
--- a/sound/pci/ak4531_codec.c
+++ b/sound/pci/ak4531_codec.c
@@ -51,7 +51,8 @@ static void snd_ak4531_dump(struct snd_ak4531 *ak4531)
int idx;
for (idx = 0; idx < 0x19; idx++)
- printk("ak4531 0x%x: 0x%x\n", idx, ak4531->regs[idx]);
+ printk(KERN_DEBUG "ak4531 0x%x: 0x%x\n",
+ idx, ak4531->regs[idx]);
}
#endif
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index 1a0fd65ec28..4edf270a780 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -2142,7 +2142,7 @@ static int __devinit snd_ali_resources(struct snd_ali *codec)
{
int err;
- snd_ali_printk("resouces allocation ...\n");
+ snd_ali_printk("resources allocation ...\n");
err = pci_request_regions(codec->pci, "ALI 5451");
if (err < 0)
return err;
@@ -2154,7 +2154,7 @@ static int __devinit snd_ali_resources(struct snd_ali *codec)
return -EBUSY;
}
codec->irq = codec->pci->irq;
- snd_ali_printk("resouces allocated.\n");
+ snd_ali_printk("resources allocated.\n");
return 0;
}
static int snd_ali_dev_free(struct snd_device *device)
@@ -2307,9 +2307,9 @@ static int __devinit snd_ali_probe(struct pci_dev *pci,
snd_ali_printk("probe ...\n");
- card = snd_card_new(index, id, THIS_MODULE, 0);
- if (!card)
- return -ENOMEM;
+ err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
err = snd_ali_create(card, pci, pcm_channels, spdif, &codec);
if (err < 0)
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
index 8df6824b51c..009b4c8225a 100644
--- a/sound/pci/als300.c
+++ b/sound/pci/als300.c
@@ -91,7 +91,7 @@
#define DEBUG_PLAY_REC 0
#if DEBUG_CALLS
-#define snd_als300_dbgcalls(format, args...) printk(format, ##args)
+#define snd_als300_dbgcalls(format, args...) printk(KERN_DEBUG format, ##args)
#define snd_als300_dbgcallenter() printk(KERN_ERR "--> %s\n", __func__)
#define snd_als300_dbgcallleave() printk(KERN_ERR "<-- %s\n", __func__)
#else
@@ -812,10 +812,10 @@ static int __devinit snd_als300_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
- if (card == NULL)
- return -ENOMEM;
+ if (err < 0)
+ return err;
chip_type = pci_id->driver_data;
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index ba570053d4d..542a0c65a92 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -889,12 +889,13 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci,
pci_write_config_word(pci, PCI_COMMAND, word | PCI_COMMAND_IO);
pci_set_master(pci);
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(*acard) /* private_data: acard */);
- if (card == NULL) {
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(*acard) /* private_data: acard */,
+ &card);
+ if (err < 0) {
pci_release_regions(pci);
pci_disable_device(pci);
- return -ENOMEM;
+ return err;
}
acard = card->private_data;
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 226fe8237d3..9ce8548c03e 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -1645,9 +1645,9 @@ static int __devinit snd_atiixp_probe(struct pci_dev *pci,
struct atiixp *chip;
int err;
- card = snd_card_new(index, id, THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
strcpy(card->driver, spdif_aclink ? "ATIIXP" : "ATIIXP-SPDMA");
strcpy(card->shortname, "ATI IXP");
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index 0e6e5cc1c50..c3136cccc55 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -1288,9 +1288,9 @@ static int __devinit snd_atiixp_probe(struct pci_dev *pci,
struct atiixp_modem *chip;
int err;
- card = snd_card_new(index, id, THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
strcpy(card->driver, "ATIIXP-MODEM");
strcpy(card->shortname, "ATI IXP Modem");
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
index a36d4d1fd41..9ec122383ee 100644
--- a/sound/pci/au88x0/au88x0.c
+++ b/sound/pci/au88x0/au88x0.c
@@ -250,9 +250,9 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
return -ENOENT;
}
// (2)
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
// (3)
if ((err = snd_vortex_create(card, pci, &chip)) < 0) {
diff --git a/sound/pci/au88x0/au88x0_a3d.c b/sound/pci/au88x0/au88x0_a3d.c
index 649849e540d..f4aa8ff6f5f 100644
--- a/sound/pci/au88x0/au88x0_a3d.c
+++ b/sound/pci/au88x0/au88x0_a3d.c
@@ -462,9 +462,10 @@ static void a3dsrc_ZeroSliceIO(a3dsrc_t * a)
/* Reset Single A3D source. */
static void a3dsrc_ZeroState(a3dsrc_t * a)
{
-
- //printk("vortex: ZeroState slice: %d, source %d\n", a->slice, a->source);
-
+ /*
+ printk(KERN_DEBUG "vortex: ZeroState slice: %d, source %d\n",
+ a->slice, a->source);
+ */
a3dsrc_SetAtmosState(a, 0, 0, 0, 0);
a3dsrc_SetHrtfState(a, A3dHrirZeros, A3dHrirZeros);
a3dsrc_SetItdDline(a, A3dItdDlineZeros);
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
index b070e571451..3906f5afe27 100644
--- a/sound/pci/au88x0/au88x0_core.c
+++ b/sound/pci/au88x0/au88x0_core.c
@@ -1135,7 +1135,10 @@ vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
snd_pcm_sgbuf_get_addr(dma->substream, 0));
break;
}
- //printk("vortex: cfg0 = 0x%x\nvortex: cfg1=0x%x\n", dma->cfg0, dma->cfg1);
+ /*
+ printk(KERN_DEBUG "vortex: cfg0 = 0x%x\nvortex: cfg1=0x%x\n",
+ dma->cfg0, dma->cfg1);
+ */
hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFCFG0 + (adbdma << 3), dma->cfg0);
hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFCFG1 + (adbdma << 3), dma->cfg1);
@@ -1959,7 +1962,7 @@ vortex_connect_codecplay(vortex_t * vortex, int en, unsigned char mixers[])
ADB_CODECOUT(0 + 4));
vortex_connection_mix_adb(vortex, en, 0x11, mixers[3],
ADB_CODECOUT(1 + 4));
- //printk("SDAC detected ");
+ /* printk(KERN_DEBUG "SDAC detected "); */
}
#else
// Use plain direct output to codec.
@@ -2013,7 +2016,11 @@ vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype)
resmap[restype] |= (1 << i);
else
vortex->dma_adb[i].resources[restype] |= (1 << i);
- //printk("vortex: ResManager: type %d out %d\n", restype, i);
+ /*
+ printk(KERN_DEBUG
+ "vortex: ResManager: type %d out %d\n",
+ restype, i);
+ */
return i;
}
}
@@ -2024,7 +2031,11 @@ vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype)
for (i = 0; i < qty; i++) {
if (resmap[restype] & (1 << i)) {
resmap[restype] &= ~(1 << i);
- //printk("vortex: ResManager: type %d in %d\n",restype, i);
+ /*
+ printk(KERN_DEBUG
+ "vortex: ResManager: type %d in %d\n",
+ restype, i);
+ */
return i;
}
}
@@ -2789,7 +2800,7 @@ vortex_translateformat(vortex_t * vortex, char bits, char nch, int encod)
{
int a, this_194;
- if ((bits != 8) || (bits != 16))
+ if ((bits != 8) && (bits != 16))
return -1;
switch (encod) {
diff --git a/sound/pci/au88x0/au88x0_synth.c b/sound/pci/au88x0/au88x0_synth.c
index 978b856f562..2805e34bd41 100644
--- a/sound/pci/au88x0/au88x0_synth.c
+++ b/sound/pci/au88x0/au88x0_synth.c
@@ -213,38 +213,59 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
switch (reg) {
/* Voice specific parameters */
case 0: /* running */
- //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_RUN(wt), (int)val);
+ /*
+ printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+ WT_RUN(wt), (int)val);
+ */
hwwrite(vortex->mmio, WT_RUN(wt), val);
return 0xc;
break;
case 1: /* param 0 */
- //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,0), (int)val);
+ /*
+ printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+ WT_PARM(wt,0), (int)val);
+ */
hwwrite(vortex->mmio, WT_PARM(wt, 0), val);
return 0xc;
break;
case 2: /* param 1 */
- //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,1), (int)val);
+ /*
+ printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+ WT_PARM(wt,1), (int)val);
+ */
hwwrite(vortex->mmio, WT_PARM(wt, 1), val);
return 0xc;
break;
case 3: /* param 2 */
- //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,2), (int)val);
+ /*
+ printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+ WT_PARM(wt,2), (int)val);
+ */
hwwrite(vortex->mmio, WT_PARM(wt, 2), val);
return 0xc;
break;
case 4: /* param 3 */
- //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,3), (int)val);
+ /*
+ printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+ WT_PARM(wt,3), (int)val);
+ */
hwwrite(vortex->mmio, WT_PARM(wt, 3), val);
return 0xc;
break;
case 6: /* mute */
- //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_MUTE(wt), (int)val);
+ /*
+ printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+ WT_MUTE(wt), (int)val);
+ */
hwwrite(vortex->mmio, WT_MUTE(wt), val);
return 0xc;
break;
case 0xb:
{ /* delay */
- //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_DELAY(wt,0), (int)val);
+ /*
+ printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
+ WT_DELAY(wt,0), (int)val);
+ */
hwwrite(vortex->mmio, WT_DELAY(wt, 3), val);
hwwrite(vortex->mmio, WT_DELAY(wt, 2), val);
hwwrite(vortex->mmio, WT_DELAY(wt, 1), val);
@@ -272,7 +293,9 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
return 0;
break;
}
- //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", ecx, (int)val);
+ /*
+ printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", ecx, (int)val);
+ */
hwwrite(vortex->mmio, ecx, val);
return 1;
}
diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c
index 3f00ddf450f..8eea29fc42f 100644
--- a/sound/pci/aw2/aw2-alsa.c
+++ b/sound/pci/aw2/aw2-alsa.c
@@ -165,7 +165,7 @@ module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable Audiowerk2 soundcard.");
static struct pci_device_id snd_aw2_ids[] = {
- {PCI_VENDOR_ID_SAA7146, PCI_DEVICE_ID_SAA7146, PCI_ANY_ID, PCI_ANY_ID,
+ {PCI_VENDOR_ID_SAA7146, PCI_DEVICE_ID_SAA7146, 0, 0,
0, 0, 0},
{0}
};
@@ -368,9 +368,9 @@ static int __devinit snd_aw2_probe(struct pci_dev *pci,
}
/* (2) Create card instance */
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
/* (3) Create main component */
err = snd_aw2_create(card, pci, &chip);
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 333007c523a..e9e9b5821d4 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -211,25 +211,25 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}");
#endif
#if DEBUG_MIXER
-#define snd_azf3328_dbgmixer(format, args...) printk(format, ##args)
+#define snd_azf3328_dbgmixer(format, args...) printk(KERN_DEBUG format, ##args)
#else
#define snd_azf3328_dbgmixer(format, args...)
#endif
#if DEBUG_PLAY_REC
-#define snd_azf3328_dbgplay(format, args...) printk(KERN_ERR format, ##args)
+#define snd_azf3328_dbgplay(format, args...) printk(KERN_DEBUG format, ##args)
#else
#define snd_azf3328_dbgplay(format, args...)
#endif
#if DEBUG_MISC
-#define snd_azf3328_dbgtimer(format, args...) printk(KERN_ERR format, ##args)
+#define snd_azf3328_dbgtimer(format, args...) printk(KERN_DEBUG format, ##args)
#else
#define snd_azf3328_dbgtimer(format, args...)
#endif
#if DEBUG_GAME
-#define snd_azf3328_dbggame(format, args...) printk(KERN_ERR format, ##args)
+#define snd_azf3328_dbggame(format, args...) printk(KERN_DEBUG format, ##args)
#else
#define snd_azf3328_dbggame(format, args...)
#endif
@@ -2216,9 +2216,9 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
strcpy(card->driver, "AZF3328");
strcpy(card->shortname, "Aztech AZF3328 (PCI168)");
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 1aa1c040254..a299340519d 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -888,9 +888,9 @@ static int __devinit snd_bt87x_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (!card)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
err = snd_bt87x_create(card, pci, &chip);
if (err < 0)
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 0e62205d408..df757575798 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -255,6 +255,14 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
.gpio_type = 2,
.i2c_adc = 1,
.spi_dac = 1 } ,
+ /* Giga-byte GA-G1975X mobo
+ * Novell bnc#395807
+ */
+ /* FIXME: the GPIO and I2C setting aren't tested well */
+ { .serial = 0x1458a006,
+ .name = "Giga-byte GA-G1975X",
+ .gpio_type = 1,
+ .i2c_adc = 1 },
/* Shuttle XPC SD31P which has an onboard Creative Labs
* Sound Blaster Live! 24-bit EAX
* high-definition 7.1 audio processor".
@@ -404,7 +412,9 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
}
tmp = reg << 25 | value << 16;
- // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value);
+ /*
+ snd_printk(KERN_DEBUG "I2C-write:reg=0x%x, value=0x%x\n", reg, value);
+ */
/* Not sure what this I2C channel controls. */
/* snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); */
@@ -422,7 +432,7 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
/* Wait till the transaction ends */
while (1) {
status = snd_ca0106_ptr_read(emu, I2C_A, 0);
- //snd_printk("I2C:status=0x%x\n", status);
+ /*snd_printk(KERN_DEBUG "I2C:status=0x%x\n", status);*/
timeout++;
if ((status & I2C_A_ADC_START) == 0)
break;
@@ -521,7 +531,10 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr
channel->number = channel_id;
channel->use = 1;
- //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel);
+ /*
+ printk(KERN_DEBUG "open:channel_id=%d, chip=%p, channel=%p\n",
+ channel_id, chip, channel);
+ */
//channel->interrupt = snd_ca0106_pcm_channel_interrupt;
channel->epcm = epcm;
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
@@ -614,7 +627,10 @@ static int snd_ca0106_pcm_open_capture_channel(struct snd_pcm_substream *substre
channel->number = channel_id;
channel->use = 1;
- //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel);
+ /*
+ printk(KERN_DEBUG "open:channel_id=%d, chip=%p, channel=%p\n",
+ channel_id, chip, channel);
+ */
//channel->interrupt = snd_ca0106_pcm_channel_interrupt;
channel->epcm = epcm;
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
@@ -705,9 +721,20 @@ static int snd_ca0106_pcm_prepare_playback(struct snd_pcm_substream *substream)
u32 reg71;
int i;
- //snd_printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1));
- //snd_printk("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base);
- //snd_printk("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->buffer.addr, emu->buffer.area, emu->buffer.bytes);
+#if 0 /* debug */
+ snd_printk(KERN_DEBUG
+ "prepare:channel_number=%d, rate=%d, format=0x%x, "
+ "channels=%d, buffer_size=%ld, period_size=%ld, "
+ "periods=%u, frames_to_bytes=%d\n",
+ channel, runtime->rate, runtime->format,
+ runtime->channels, runtime->buffer_size,
+ runtime->period_size, runtime->periods,
+ frames_to_bytes(runtime, 1));
+ snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, table_base=%p\n",
+ runtime->dma_addr, runtime->dma_area, table_base);
+ snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",
+ emu->buffer.addr, emu->buffer.area, emu->buffer.bytes);
+#endif /* debug */
/* Rate can be set per channel. */
/* reg40 control host to fifo */
/* reg71 controls DAC rate. */
@@ -799,9 +826,20 @@ static int snd_ca0106_pcm_prepare_capture(struct snd_pcm_substream *substream)
u32 reg71_set = 0;
u32 reg71;
- //snd_printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1));
- //snd_printk("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base);
- //snd_printk("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->buffer.addr, emu->buffer.area, emu->buffer.bytes);
+#if 0 /* debug */
+ snd_printk(KERN_DEBUG
+ "prepare:channel_number=%d, rate=%d, format=0x%x, "
+ "channels=%d, buffer_size=%ld, period_size=%ld, "
+ "periods=%u, frames_to_bytes=%d\n",
+ channel, runtime->rate, runtime->format,
+ runtime->channels, runtime->buffer_size,
+ runtime->period_size, runtime->periods,
+ frames_to_bytes(runtime, 1));
+ snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, table_base=%p\n",
+ runtime->dma_addr, runtime->dma_area, table_base);
+ snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",
+ emu->buffer.addr, emu->buffer.area, emu->buffer.bytes);
+#endif /* debug */
/* reg71 controls ADC rate. */
switch (runtime->rate) {
case 44100:
@@ -846,7 +884,14 @@ static int snd_ca0106_pcm_prepare_capture(struct snd_pcm_substream *substream)
}
- //printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, frames_to_bytes(runtime, 1));
+ /*
+ printk(KERN_DEBUG
+ "prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, "
+ "buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",
+ channel, runtime->rate, runtime->format, runtime->channels,
+ runtime->buffer_size, runtime->period_size,
+ frames_to_bytes(runtime, 1));
+ */
snd_ca0106_ptr_write(emu, 0x13, channel, 0);
snd_ca0106_ptr_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr);
snd_ca0106_ptr_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes
@@ -888,13 +933,13 @@ static int snd_ca0106_pcm_trigger_playback(struct snd_pcm_substream *substream,
runtime = s->runtime;
epcm = runtime->private_data;
channel = epcm->channel_id;
- /* snd_printk("channel=%d\n",channel); */
+ /* snd_printk(KERN_DEBUG "channel=%d\n", channel); */
epcm->running = running;
basic |= (0x1 << channel);
extended |= (0x10 << channel);
snd_pcm_trigger_done(s, substream);
}
- /* snd_printk("basic=0x%x, extended=0x%x\n",basic, extended); */
+ /* snd_printk(KERN_DEBUG "basic=0x%x, extended=0x%x\n",basic, extended); */
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -972,8 +1017,13 @@ snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream)
ptr=ptr2;
if (ptr >= runtime->buffer_size)
ptr -= runtime->buffer_size;
- //printk("ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr1, ptr2, ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits, (int)runtime->rate);
-
+ /*
+ printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
+ "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n",
+ ptr1, ptr2, ptr, (int)runtime->buffer_size,
+ (int)runtime->period_size, (int)runtime->frame_bits,
+ (int)runtime->rate);
+ */
return ptr;
}
@@ -995,8 +1045,13 @@ snd_ca0106_pcm_pointer_capture(struct snd_pcm_substream *substream)
ptr=ptr2;
if (ptr >= runtime->buffer_size)
ptr -= runtime->buffer_size;
- //printk("ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr1, ptr2, ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits, (int)runtime->rate);
-
+ /*
+ printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
+ "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n",
+ ptr1, ptr2, ptr, (int)runtime->buffer_size,
+ (int)runtime->period_size, (int)runtime->frame_bits,
+ (int)runtime->rate);
+ */
return ptr;
}
@@ -1181,8 +1236,12 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id)
return IRQ_NONE;
stat76 = snd_ca0106_ptr_read(chip, EXTENDED_INT, 0);
- //snd_printk("interrupt status = 0x%08x, stat76=0x%08x\n", status, stat76);
- //snd_printk("ptr=0x%08x\n",snd_ca0106_ptr_read(chip, PLAYBACK_POINTER, 0));
+ /*
+ snd_printk(KERN_DEBUG "interrupt status = 0x%08x, stat76=0x%08x\n",
+ status, stat76);
+ snd_printk(KERN_DEBUG "ptr=0x%08x\n",
+ snd_ca0106_ptr_read(chip, PLAYBACK_POINTER, 0));
+ */
mask = 0x11; /* 0x1 for one half, 0x10 for the other half period. */
for(i = 0; i < 4; i++) {
pchannel = &(chip->playback_channels[i]);
@@ -1470,7 +1529,7 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
int size, n;
size = ARRAY_SIZE(i2c_adc_init);
- /* snd_printk("I2C:array size=0x%x\n", size); */
+ /* snd_printk(KERN_DEBUG "I2C:array size=0x%x\n", size); */
for (n = 0; n < size; n++)
snd_ca0106_i2c_write(chip, i2c_adc_init[n][0],
i2c_adc_init[n][1]);
@@ -1707,9 +1766,9 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
err = snd_ca0106_create(dev, card, pci, &chip);
if (err < 0)
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index 1a74ca62c31..c7899c32aba 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -3272,9 +3272,9 @@ static int __devinit snd_cmipci_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
switch (pci->device) {
case PCI_DEVICE_ID_CMEDIA_CM8738:
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index 192e7842e18..f6286f84a22 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -834,7 +834,11 @@ static snd_pcm_uframes_t snd_cs4281_pointer(struct snd_pcm_substream *substream)
struct cs4281_dma *dma = runtime->private_data;
struct cs4281 *chip = snd_pcm_substream_chip(substream);
- // printk("DCC = 0x%x, buffer_size = 0x%x, jiffies = %li\n", snd_cs4281_peekBA0(chip, dma->regDCC), runtime->buffer_size, jiffies);
+ /*
+ printk(KERN_DEBUG "DCC = 0x%x, buffer_size = 0x%x, jiffies = %li\n",
+ snd_cs4281_peekBA0(chip, dma->regDCC), runtime->buffer_size,
+ jiffies);
+ */
return runtime->buffer_size -
snd_cs4281_peekBA0(chip, dma->regDCC) - 1;
}
@@ -1925,9 +1929,9 @@ static int __devinit snd_cs4281_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
if ((err = snd_cs4281_create(card, pci, &chip, dual_codec[dev])) < 0) {
snd_card_free(card);
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c
index e876b3263e4..c9b3e3d48cb 100644
--- a/sound/pci/cs46xx/cs46xx.c
+++ b/sound/pci/cs46xx/cs46xx.c
@@ -88,9 +88,9 @@ static int __devinit snd_card_cs46xx_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
if ((err = snd_cs46xx_create(card, pci,
external_amp[dev], thinkpad[dev],
&chip)) < 0) {
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index 8ab07aa6365..1be96ead424 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -194,7 +194,7 @@ static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip,
* ACSDA = Status Data Register = 474h
*/
#if 0
- printk("e) reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n", reg,
+ printk(KERN_DEBUG "e) reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n", reg,
snd_cs46xx_peekBA0(chip, BA0_ACSDA),
snd_cs46xx_peekBA0(chip, BA0_ACCAD));
#endif
@@ -428,8 +428,8 @@ static int cs46xx_wait_for_fifo(struct snd_cs46xx * chip,int retry_timeout)
}
if(status & SERBST_WBSY) {
- snd_printk( KERN_ERR "cs46xx: failure waiting for FIFO command to complete\n");
-
+ snd_printk(KERN_ERR "cs46xx: failure waiting for "
+ "FIFO command to complete\n");
return -EINVAL;
}
diff --git a/sound/pci/cs46xx/cs46xx_lib.h b/sound/pci/cs46xx/cs46xx_lib.h
index 018a7de5601..4eb55aa3361 100644
--- a/sound/pci/cs46xx/cs46xx_lib.h
+++ b/sound/pci/cs46xx/cs46xx_lib.h
@@ -62,7 +62,11 @@ static inline void snd_cs46xx_poke(struct snd_cs46xx *chip, unsigned long reg, u
unsigned int bank = reg >> 16;
unsigned int offset = reg & 0xffff;
- /*if (bank == 0) printk("snd_cs46xx_poke: %04X - %08X\n",reg >> 2,val); */
+ /*
+ if (bank == 0)
+ printk(KERN_DEBUG "snd_cs46xx_poke: %04X - %08X\n",
+ reg >> 2,val);
+ */
writel(val, chip->region.idx[bank+1].remap_addr + offset);
}
diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c
index 6dea5b5cc77..dc464321d0f 100644
--- a/sound/pci/cs5530.c
+++ b/sound/pci/cs5530.c
@@ -258,10 +258,10 @@ static int __devinit snd_cs5530_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
- if (card == NULL)
- return -ENOMEM;
+ if (err < 0)
+ return err;
err = snd_cs5530_create(card, pci, &chip);
if (err < 0) {
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
index 826e6dec2e9..c89ed1f5bc2 100644
--- a/sound/pci/cs5535audio/cs5535audio.c
+++ b/sound/pci/cs5535audio/cs5535audio.c
@@ -312,7 +312,7 @@ static int __devinit snd_cs5535audio_create(struct snd_card *card,
if (request_irq(pci->irq, snd_cs5535audio_interrupt,
IRQF_SHARED, "CS5535 Audio", cs5535au)) {
- snd_printk("unable to grab IRQ %d\n", pci->irq);
+ snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
err = -EBUSY;
goto sndfail;
}
@@ -353,9 +353,9 @@ static int __devinit snd_cs5535audio_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
if ((err = snd_cs5535audio_create(card, pci, &cs5535au)) < 0)
goto probefail_out;
diff --git a/sound/pci/echoaudio/Makefile b/sound/pci/echoaudio/Makefile
index 7b576aeb3f8..1361de77e0c 100644
--- a/sound/pci/echoaudio/Makefile
+++ b/sound/pci/echoaudio/Makefile
@@ -15,6 +15,8 @@ snd-echo3g-objs := echo3g.o
snd-indigo-objs := indigo.o
snd-indigoio-objs := indigoio.o
snd-indigodj-objs := indigodj.o
+snd-indigoiox-objs := indigoiox.o
+snd-indigodjx-objs := indigodjx.o
obj-$(CONFIG_SND_DARLA20) += snd-darla20.o
obj-$(CONFIG_SND_GINA20) += snd-gina20.o
@@ -28,3 +30,5 @@ obj-$(CONFIG_SND_ECHO3G) += snd-echo3g.o
obj-$(CONFIG_SND_INDIGO) += snd-indigo.o
obj-$(CONFIG_SND_INDIGOIO) += snd-indigoio.o
obj-$(CONFIG_SND_INDIGODJ) += snd-indigodj.o
+obj-$(CONFIG_SND_INDIGOIOX) += snd-indigoiox.o
+obj-$(CONFIG_SND_INDIGODJX) += snd-indigodjx.o
diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c
index 417e25add82..57967e58057 100644
--- a/sound/pci/echoaudio/echo3g_dsp.c
+++ b/sound/pci/echoaudio/echo3g_dsp.c
@@ -56,7 +56,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
}
chip->comm_page->e3g_frq_register =
- __constant_cpu_to_le32((E3G_MAGIC_NUMBER / 48000) - 2);
+ cpu_to_le32((E3G_MAGIC_NUMBER / 48000) - 2);
chip->device_id = device_id;
chip->subdevice_id = subdevice_id;
chip->bad_board = TRUE;
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index 8dbc5c4ba42..da2065cd2c0 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -950,6 +950,8 @@ static int __devinit snd_echo_new_pcm(struct echoaudio *chip)
Control interface
******************************************************************************/
+#ifndef ECHOCARD_HAS_VMIXER
+
/******************* PCM output volume *******************/
static int snd_echo_output_gain_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
@@ -1001,18 +1003,6 @@ static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol,
return changed;
}
-#ifdef ECHOCARD_HAS_VMIXER
-/* On Vmixer cards this one controls the line-out volume */
-static struct snd_kcontrol_new snd_echo_line_output_gain __devinitdata = {
- .name = "Line Playback Volume",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
- .info = snd_echo_output_gain_info,
- .get = snd_echo_output_gain_get,
- .put = snd_echo_output_gain_put,
- .tlv = {.p = db_scale_output_gain},
-};
-#else
static struct snd_kcontrol_new snd_echo_pcm_output_gain __devinitdata = {
.name = "PCM Playback Volume",
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -1022,6 +1012,7 @@ static struct snd_kcontrol_new snd_echo_pcm_output_gain __devinitdata = {
.put = snd_echo_output_gain_put,
.tlv = {.p = db_scale_output_gain},
};
+
#endif
@@ -1997,9 +1988,9 @@ static int __devinit snd_echo_probe(struct pci_dev *pci,
DE_INIT(("Echoaudio driver starting...\n"));
i = 0;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
snd_card_set_dev(card, &pci->dev);
@@ -2037,8 +2028,6 @@ static int __devinit snd_echo_probe(struct pci_dev *pci,
#ifdef ECHOCARD_HAS_VMIXER
snd_echo_vmixer.count = num_pipes_out(chip) * num_busses_out(chip);
- if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_line_output_gain, chip))) < 0)
- goto ctl_error;
if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vmixer, chip))) < 0)
goto ctl_error;
#else
diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h
index 1c88e051abf..f9490ae36c2 100644
--- a/sound/pci/echoaudio/echoaudio.h
+++ b/sound/pci/echoaudio/echoaudio.h
@@ -189,6 +189,9 @@
#define INDIGO 0x0090
#define INDIGO_IO 0x00a0
#define INDIGO_DJ 0x00b0
+#define DC8 0x00c0
+#define INDIGO_IOX 0x00d0
+#define INDIGO_DJX 0x00e0
#define ECHO3G 0x0100
diff --git a/sound/pci/echoaudio/echoaudio_3g.c b/sound/pci/echoaudio/echoaudio_3g.c
index c3736bbd819..e32a7489792 100644
--- a/sound/pci/echoaudio/echoaudio_3g.c
+++ b/sound/pci/echoaudio/echoaudio_3g.c
@@ -40,8 +40,7 @@ static int check_asic_status(struct echoaudio *chip)
if (wait_handshake(chip))
return -EIO;
- chip->comm_page->ext_box_status =
- __constant_cpu_to_le32(E3G_ASIC_NOT_LOADED);
+ chip->comm_page->ext_box_status = cpu_to_le32(E3G_ASIC_NOT_LOADED);
chip->asic_loaded = FALSE;
clear_handshake(chip);
send_vector(chip, DSP_VC_TEST_ASIC);
diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c
index be0e18192de..4df51ef5e09 100644
--- a/sound/pci/echoaudio/echoaudio_dsp.c
+++ b/sound/pci/echoaudio/echoaudio_dsp.c
@@ -926,11 +926,11 @@ static int init_dsp_comm_page(struct echoaudio *chip)
/* Init the comm page */
chip->comm_page->comm_size =
- __constant_cpu_to_le32(sizeof(struct comm_page));
+ cpu_to_le32(sizeof(struct comm_page));
chip->comm_page->handshake = 0xffffffff;
chip->comm_page->midi_out_free_count =
- __constant_cpu_to_le32(DSP_MIDI_OUT_FIFO_SIZE);
- chip->comm_page->sample_rate = __constant_cpu_to_le32(44100);
+ cpu_to_le32(DSP_MIDI_OUT_FIFO_SIZE);
+ chip->comm_page->sample_rate = cpu_to_le32(44100);
chip->sample_rate = 44100;
/* Set line levels so we don't blast any inputs on startup */
diff --git a/sound/pci/echoaudio/echoaudio_dsp.h b/sound/pci/echoaudio/echoaudio_dsp.h
index e352f3ae292..cb7d75a0a50 100644
--- a/sound/pci/echoaudio/echoaudio_dsp.h
+++ b/sound/pci/echoaudio/echoaudio_dsp.h
@@ -576,8 +576,13 @@ SET_LAYLA24_FREQUENCY_REG command.
#define E3G_ASIC_NOT_LOADED 0xffff
#define E3G_BOX_TYPE_MASK 0xf0
-#define EXT_3GBOX_NC 0x01
-#define EXT_3GBOX_NOT_SET 0x02
+/* Indigo express control register values */
+#define INDIGO_EXPRESS_32000 0x02
+#define INDIGO_EXPRESS_44100 0x01
+#define INDIGO_EXPRESS_48000 0x00
+#define INDIGO_EXPRESS_DOUBLE_SPEED 0x10
+#define INDIGO_EXPRESS_QUAD_SPEED 0x04
+#define INDIGO_EXPRESS_CLOCK_MASK 0x17
/*
diff --git a/sound/pci/echoaudio/gina20_dsp.c b/sound/pci/echoaudio/gina20_dsp.c
index db6c952e9d7..3f1e7475fae 100644
--- a/sound/pci/echoaudio/gina20_dsp.c
+++ b/sound/pci/echoaudio/gina20_dsp.c
@@ -208,10 +208,10 @@ static int set_professional_spdif(struct echoaudio *chip, char prof)
DE_ACT(("set_professional_spdif %d\n", prof));
if (prof)
chip->comm_page->flags |=
- __constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
+ cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
else
chip->comm_page->flags &=
- ~__constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
+ ~cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
chip->professional_spdif = prof;
return update_flags(chip);
}
diff --git a/sound/pci/echoaudio/indigo_dsp.c b/sound/pci/echoaudio/indigo_dsp.c
index f05e39f7aad..0b2cd9c8627 100644
--- a/sound/pci/echoaudio/indigo_dsp.c
+++ b/sound/pci/echoaudio/indigo_dsp.c
@@ -63,18 +63,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
if ((err = init_line_levels(chip)) < 0)
return err;
- /* Default routing of the virtual channels: all vchannels are routed
- to the stereo output */
- set_vmixer_gain(chip, 0, 0, 0);
- set_vmixer_gain(chip, 1, 1, 0);
- set_vmixer_gain(chip, 0, 2, 0);
- set_vmixer_gain(chip, 1, 3, 0);
- set_vmixer_gain(chip, 0, 4, 0);
- set_vmixer_gain(chip, 1, 5, 0);
- set_vmixer_gain(chip, 0, 6, 0);
- set_vmixer_gain(chip, 1, 7, 0);
- err = update_vmixer_level(chip);
-
DE_INIT(("init_hw done\n"));
return err;
}
diff --git a/sound/pci/echoaudio/indigo_express_dsp.c b/sound/pci/echoaudio/indigo_express_dsp.c
new file mode 100644
index 00000000000..9ab625e1565
--- /dev/null
+++ b/sound/pci/echoaudio/indigo_express_dsp.c
@@ -0,0 +1,119 @@
+/************************************************************************
+
+This file is part of Echo Digital Audio's generic driver library.
+Copyright Echo Digital Audio Corporation (c) 1998 - 2005
+All rights reserved
+www.echoaudio.com
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+*************************************************************************/
+
+static int set_sample_rate(struct echoaudio *chip, u32 rate)
+{
+ u32 clock, control_reg, old_control_reg;
+
+ if (wait_handshake(chip))
+ return -EIO;
+
+ old_control_reg = le32_to_cpu(chip->comm_page->control_register);
+ control_reg = old_control_reg & ~INDIGO_EXPRESS_CLOCK_MASK;
+
+ switch (rate) {
+ case 32000:
+ clock = INDIGO_EXPRESS_32000;
+ break;
+ case 44100:
+ clock = INDIGO_EXPRESS_44100;
+ break;
+ case 48000:
+ clock = INDIGO_EXPRESS_48000;
+ break;
+ case 64000:
+ clock = INDIGO_EXPRESS_32000|INDIGO_EXPRESS_DOUBLE_SPEED;
+ break;
+ case 88200:
+ clock = INDIGO_EXPRESS_44100|INDIGO_EXPRESS_DOUBLE_SPEED;
+ break;
+ case 96000:
+ clock = INDIGO_EXPRESS_48000|INDIGO_EXPRESS_DOUBLE_SPEED;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ control_reg |= clock;
+ if (control_reg != old_control_reg) {
+ chip->comm_page->control_register = cpu_to_le32(control_reg);
+ chip->sample_rate = rate;
+ clear_handshake(chip);
+ return send_vector(chip, DSP_VC_UPDATE_CLOCKS);
+ }
+ return 0;
+}
+
+
+
+/* This function routes the sound from a virtual channel to a real output */
+static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
+ int gain)
+{
+ int index;
+
+ if (snd_BUG_ON(pipe >= num_pipes_out(chip) ||
+ output >= num_busses_out(chip)))
+ return -EINVAL;
+
+ if (wait_handshake(chip))
+ return -EIO;
+
+ chip->vmixer_gain[output][pipe] = gain;
+ index = output * num_pipes_out(chip) + pipe;
+ chip->comm_page->vmixer[index] = gain;
+
+ DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain));
+ return 0;
+}
+
+
+
+/* Tell the DSP to read and update virtual mixer levels in comm page. */
+static int update_vmixer_level(struct echoaudio *chip)
+{
+ if (wait_handshake(chip))
+ return -EIO;
+ clear_handshake(chip);
+ return send_vector(chip, DSP_VC_SET_VMIXER_GAIN);
+}
+
+
+
+static u32 detect_input_clocks(const struct echoaudio *chip)
+{
+ return ECHO_CLOCK_BIT_INTERNAL;
+}
+
+
+
+/* The IndigoIO has no ASIC. Just do nothing */
+static int load_asic(struct echoaudio *chip)
+{
+ return 0;
+}
diff --git a/sound/pci/echoaudio/indigodj_dsp.c b/sound/pci/echoaudio/indigodj_dsp.c
index 90730a5ecb4..08392916691 100644
--- a/sound/pci/echoaudio/indigodj_dsp.c
+++ b/sound/pci/echoaudio/indigodj_dsp.c
@@ -63,18 +63,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
if ((err = init_line_levels(chip)) < 0)
return err;
- /* Default routing of the virtual channels: vchannels 0-3 and
- vchannels 4-7 are routed to real channels 0-4 */
- set_vmixer_gain(chip, 0, 0, 0);
- set_vmixer_gain(chip, 1, 1, 0);
- set_vmixer_gain(chip, 2, 2, 0);
- set_vmixer_gain(chip, 3, 3, 0);
- set_vmixer_gain(chip, 0, 4, 0);
- set_vmixer_gain(chip, 1, 5, 0);
- set_vmixer_gain(chip, 2, 6, 0);
- set_vmixer_gain(chip, 3, 7, 0);
- err = update_vmixer_level(chip);
-
DE_INIT(("init_hw done\n"));
return err;
}
diff --git a/sound/pci/echoaudio/indigodjx.c b/sound/pci/echoaudio/indigodjx.c
new file mode 100644
index 00000000000..3482ef69f49
--- /dev/null
+++ b/sound/pci/echoaudio/indigodjx.c
@@ -0,0 +1,107 @@
+/*
+ * ALSA driver for Echoaudio soundcards.
+ * Copyright (C) 2009 Giuliano Pochini <pochini@shiny.it>
+ *
+ * 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.
+ */
+
+#define INDIGO_FAMILY
+#define ECHOCARD_INDIGO_DJX
+#define ECHOCARD_NAME "Indigo DJx"
+#define ECHOCARD_HAS_SUPER_INTERLEAVE
+#define ECHOCARD_HAS_VMIXER
+#define ECHOCARD_HAS_STEREO_BIG_ENDIAN32
+
+/* Pipe indexes */
+#define PX_ANALOG_OUT 0 /* 8 */
+#define PX_DIGITAL_OUT 8 /* 0 */
+#define PX_ANALOG_IN 8 /* 0 */
+#define PX_DIGITAL_IN 8 /* 0 */
+#define PX_NUM 8
+
+/* Bus indexes */
+#define BX_ANALOG_OUT 0 /* 4 */
+#define BX_DIGITAL_OUT 4 /* 0 */
+#define BX_ANALOG_IN 4 /* 0 */
+#define BX_DIGITAL_IN 4 /* 0 */
+#define BX_NUM 4
+
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/asoundef.h>
+#include <sound/initval.h>
+#include <asm/atomic.h>
+#include "echoaudio.h"
+
+MODULE_FIRMWARE("ea/loader_dsp.fw");
+MODULE_FIRMWARE("ea/indigo_djx_dsp.fw");
+
+#define FW_361_LOADER 0
+#define FW_INDIGO_DJX_DSP 1
+
+static const struct firmware card_fw[] = {
+ {0, "loader_dsp.fw"},
+ {0, "indigo_djx_dsp.fw"}
+};
+
+static struct pci_device_id snd_echo_ids[] = {
+ {0x1057, 0x3410, 0xECC0, 0x00E0, 0, 0, 0}, /* Indigo DJx*/
+ {0,}
+};
+
+static struct snd_pcm_hardware pcm_hardware_skel = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_SYNC_START,
+ .formats = SNDRV_PCM_FMTBIT_U8 |
+ SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE |
+ SNDRV_PCM_FMTBIT_S32_BE,
+ .rates = SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000,
+ .rate_min = 32000,
+ .rate_max = 96000,
+ .channels_min = 1,
+ .channels_max = 4,
+ .buffer_bytes_max = 262144,
+ .period_bytes_min = 32,
+ .period_bytes_max = 131072,
+ .periods_min = 2,
+ .periods_max = 220,
+};
+
+#include "indigodjx_dsp.c"
+#include "indigo_express_dsp.c"
+#include "echoaudio_dsp.c"
+#include "echoaudio.c"
diff --git a/sound/pci/echoaudio/indigodjx_dsp.c b/sound/pci/echoaudio/indigodjx_dsp.c
new file mode 100644
index 00000000000..f591fc2ed96
--- /dev/null
+++ b/sound/pci/echoaudio/indigodjx_dsp.c
@@ -0,0 +1,68 @@
+/************************************************************************
+
+This file is part of Echo Digital Audio's generic driver library.
+Copyright Echo Digital Audio Corporation (c) 1998 - 2005
+All rights reserved
+www.echoaudio.com
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+*************************************************************************/
+
+static int update_vmixer_level(struct echoaudio *chip);
+static int set_vmixer_gain(struct echoaudio *chip, u16 output,
+ u16 pipe, int gain);
+
+
+static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
+{
+ int err;
+
+ DE_INIT(("init_hw() - Indigo DJx\n"));
+ if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_DJX))
+ return -ENODEV;
+
+ err = init_dsp_comm_page(chip);
+ if (err < 0) {
+ DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ return err;
+ }
+
+ chip->device_id = device_id;
+ chip->subdevice_id = subdevice_id;
+ chip->bad_board = TRUE;
+ chip->dsp_code_to_load = &card_fw[FW_INDIGO_DJX_DSP];
+ /* Since this card has no ASIC, mark it as loaded so everything
+ works OK */
+ chip->asic_loaded = TRUE;
+ chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL;
+
+ err = load_firmware(chip);
+ if (err < 0)
+ return err;
+ chip->bad_board = FALSE;
+
+ err = init_line_levels(chip);
+ if (err < 0)
+ return err;
+
+ DE_INIT(("init_hw done\n"));
+ return err;
+}
diff --git a/sound/pci/echoaudio/indigoio_dsp.c b/sound/pci/echoaudio/indigoio_dsp.c
index a7e09ec2107..0604c8a8522 100644
--- a/sound/pci/echoaudio/indigoio_dsp.c
+++ b/sound/pci/echoaudio/indigoio_dsp.c
@@ -63,18 +63,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
if ((err = init_line_levels(chip)) < 0)
return err;
- /* Default routing of the virtual channels: all vchannels are routed
- to the stereo output */
- set_vmixer_gain(chip, 0, 0, 0);
- set_vmixer_gain(chip, 1, 1, 0);
- set_vmixer_gain(chip, 0, 2, 0);
- set_vmixer_gain(chip, 1, 3, 0);
- set_vmixer_gain(chip, 0, 4, 0);
- set_vmixer_gain(chip, 1, 5, 0);
- set_vmixer_gain(chip, 0, 6, 0);
- set_vmixer_gain(chip, 1, 7, 0);
- err = update_vmixer_level(chip);
-
DE_INIT(("init_hw done\n"));
return err;
}
diff --git a/sound/pci/echoaudio/indigoiox.c b/sound/pci/echoaudio/indigoiox.c
new file mode 100644
index 00000000000..aebee27a40f
--- /dev/null
+++ b/sound/pci/echoaudio/indigoiox.c
@@ -0,0 +1,109 @@
+/*
+ * ALSA driver for Echoaudio soundcards.
+ * Copyright (C) 2009 Giuliano Pochini <pochini@shiny.it>
+ *
+ * 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.
+ */
+
+#define INDIGO_FAMILY
+#define ECHOCARD_INDIGO_IOX
+#define ECHOCARD_NAME "Indigo IOx"
+#define ECHOCARD_HAS_MONITOR
+#define ECHOCARD_HAS_SUPER_INTERLEAVE
+#define ECHOCARD_HAS_VMIXER
+#define ECHOCARD_HAS_STEREO_BIG_ENDIAN32
+
+/* Pipe indexes */
+#define PX_ANALOG_OUT 0 /* 8 */
+#define PX_DIGITAL_OUT 8 /* 0 */
+#define PX_ANALOG_IN 8 /* 2 */
+#define PX_DIGITAL_IN 10 /* 0 */
+#define PX_NUM 10
+
+/* Bus indexes */
+#define BX_ANALOG_OUT 0 /* 2 */
+#define BX_DIGITAL_OUT 2 /* 0 */
+#define BX_ANALOG_IN 2 /* 2 */
+#define BX_DIGITAL_IN 4 /* 0 */
+#define BX_NUM 4
+
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/asoundef.h>
+#include <sound/initval.h>
+#include <asm/atomic.h>
+#include "echoaudio.h"
+
+MODULE_FIRMWARE("ea/loader_dsp.fw");
+MODULE_FIRMWARE("ea/indigo_iox_dsp.fw");
+
+#define FW_361_LOADER 0
+#define FW_INDIGO_IOX_DSP 1
+
+static const struct firmware card_fw[] = {
+ {0, "loader_dsp.fw"},
+ {0, "indigo_iox_dsp.fw"}
+};
+
+static struct pci_device_id snd_echo_ids[] = {
+ {0x1057, 0x3410, 0xECC0, 0x00D0, 0, 0, 0}, /* Indigo IOx */
+ {0,}
+};
+
+static struct snd_pcm_hardware pcm_hardware_skel = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_SYNC_START,
+ .formats = SNDRV_PCM_FMTBIT_U8 |
+ SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S32_LE |
+ SNDRV_PCM_FMTBIT_S32_BE,
+ .rates = SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000,
+ .rate_min = 32000,
+ .rate_max = 96000,
+ .channels_min = 1,
+ .channels_max = 8,
+ .buffer_bytes_max = 262144,
+ .period_bytes_min = 32,
+ .period_bytes_max = 131072,
+ .periods_min = 2,
+ .periods_max = 220,
+};
+
+#include "indigoiox_dsp.c"
+#include "indigo_express_dsp.c"
+#include "echoaudio_dsp.c"
+#include "echoaudio.c"
+
diff --git a/sound/pci/echoaudio/indigoiox_dsp.c b/sound/pci/echoaudio/indigoiox_dsp.c
new file mode 100644
index 00000000000..f357521c79e
--- /dev/null
+++ b/sound/pci/echoaudio/indigoiox_dsp.c
@@ -0,0 +1,68 @@
+/************************************************************************
+
+This file is part of Echo Digital Audio's generic driver library.
+Copyright Echo Digital Audio Corporation (c) 1998 - 2005
+All rights reserved
+www.echoaudio.com
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*************************************************************************
+
+ Translation from C++ and adaptation for use in ALSA-Driver
+ were made by Giuliano Pochini <pochini@shiny.it>
+
+*************************************************************************/
+
+static int update_vmixer_level(struct echoaudio *chip);
+static int set_vmixer_gain(struct echoaudio *chip, u16 output,
+ u16 pipe, int gain);
+
+
+static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
+{
+ int err;
+
+ DE_INIT(("init_hw() - Indigo IOx\n"));
+ if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_IOX))
+ return -ENODEV;
+
+ err = init_dsp_comm_page(chip);
+ if (err < 0) {
+ DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ return err;
+ }
+
+ chip->device_id = device_id;
+ chip->subdevice_id = subdevice_id;
+ chip->bad_board = TRUE;
+ chip->dsp_code_to_load = &card_fw[FW_INDIGO_IOX_DSP];
+ /* Since this card has no ASIC, mark it as loaded so everything
+ works OK */
+ chip->asic_loaded = TRUE;
+ chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL;
+
+ err = load_firmware(chip);
+ if (err < 0)
+ return err;
+ chip->bad_board = FALSE;
+
+ err = init_line_levels(chip);
+ if (err < 0)
+ return err;
+
+ DE_INIT(("init_hw done\n"));
+ return err;
+}
diff --git a/sound/pci/echoaudio/layla20_dsp.c b/sound/pci/echoaudio/layla20_dsp.c
index ede75c6ca0f..83750e9fd7b 100644
--- a/sound/pci/echoaudio/layla20_dsp.c
+++ b/sound/pci/echoaudio/layla20_dsp.c
@@ -284,10 +284,10 @@ static int set_professional_spdif(struct echoaudio *chip, char prof)
DE_ACT(("set_professional_spdif %d\n", prof));
if (prof)
chip->comm_page->flags |=
- __constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
+ cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
else
chip->comm_page->flags &=
- ~__constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
+ ~cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
chip->professional_spdif = prof;
return update_flags(chip);
}
diff --git a/sound/pci/echoaudio/mia_dsp.c b/sound/pci/echoaudio/mia_dsp.c
index 227386602f9..551405114cb 100644
--- a/sound/pci/echoaudio/mia_dsp.c
+++ b/sound/pci/echoaudio/mia_dsp.c
@@ -69,18 +69,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
if ((err = init_line_levels(chip)))
return err;
- /* Default routing of the virtual channels: vchannels 0-3 go to analog
- outputs and vchannels 4-7 go to S/PDIF outputs */
- set_vmixer_gain(chip, 0, 0, 0);
- set_vmixer_gain(chip, 1, 1, 0);
- set_vmixer_gain(chip, 0, 2, 0);
- set_vmixer_gain(chip, 1, 3, 0);
- set_vmixer_gain(chip, 2, 4, 0);
- set_vmixer_gain(chip, 3, 5, 0);
- set_vmixer_gain(chip, 2, 6, 0);
- set_vmixer_gain(chip, 3, 7, 0);
- err = update_vmixer_level(chip);
-
DE_INIT(("init_hw done\n"));
return err;
}
@@ -222,10 +210,10 @@ static int set_professional_spdif(struct echoaudio *chip, char prof)
DE_ACT(("set_professional_spdif %d\n", prof));
if (prof)
chip->comm_page->flags |=
- __constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
+ cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
else
chip->comm_page->flags &=
- ~__constant_cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
+ ~cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
chip->professional_spdif = prof;
return update_flags(chip);
}
diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c
index 77bf2a83d99..a953d142cb4 100644
--- a/sound/pci/echoaudio/midi.c
+++ b/sound/pci/echoaudio/midi.c
@@ -44,10 +44,10 @@ static int enable_midi_input(struct echoaudio *chip, char enable)
if (enable) {
chip->mtc_state = MIDI_IN_STATE_NORMAL;
chip->comm_page->flags |=
- __constant_cpu_to_le32(DSP_FLAG_MIDI_INPUT);
+ cpu_to_le32(DSP_FLAG_MIDI_INPUT);
} else
chip->comm_page->flags &=
- ~__constant_cpu_to_le32(DSP_FLAG_MIDI_INPUT);
+ ~cpu_to_le32(DSP_FLAG_MIDI_INPUT);
clear_handshake(chip);
return send_vector(chip, DSP_VC_UPDATE_FLAGS);
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
index 8354c1a8331..c7f3b994101 100644
--- a/sound/pci/emu10k1/emu10k1.c
+++ b/sound/pci/emu10k1/emu10k1.c
@@ -114,9 +114,9 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
if (max_buffer_size[dev] < 32)
max_buffer_size[dev] = 32;
else if (max_buffer_size[dev] > 1024)
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index e6836fc3388..f18bd6207c5 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -1527,6 +1527,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
.ca0151_chip = 1,
.spk71 = 1,
.spdif_bug = 1,
+ .invert_shared_spdif = 1, /* digital/analog switch swapped */
.ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10021102,
.driver = "Audigy2", .name = "SB Audigy 2 Platinum [SB0240P]",
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 5ff4dbb62da..31542adc6b7 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -1544,9 +1544,9 @@ static int __devinit snd_emu10k1x_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
if ((err = snd_emu10k1x_create(card, pci, &chip)) < 0) {
snd_card_free(card);
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index 9bf95367c88..18f4d1e98c4 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -584,7 +584,8 @@ static void snd_es1370_codec_write(struct snd_ak4531 *ak4531,
unsigned long end_time = jiffies + HZ / 10;
#if 0
- printk("CODEC WRITE: reg = 0x%x, val = 0x%x (0x%x), creg = 0x%x\n",
+ printk(KERN_DEBUG
+ "CODEC WRITE: reg = 0x%x, val = 0x%x (0x%x), creg = 0x%x\n",
reg, val, ES_1370_CODEC_WRITE(reg, val), ES_REG(ensoniq, 1370_CODEC));
#endif
do {
@@ -2409,9 +2410,9 @@ static int __devinit snd_audiopci_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
if ((err = snd_ensoniq_create(card, pci, &ensoniq)) < 0) {
snd_card_free(card);
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 4cd9a1faaec..dd63b132fb8 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -1673,18 +1673,22 @@ static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id)
status = inb(SLIO_REG(chip, IRQCONTROL));
#if 0
- printk("Es1938debug - interrupt status: =0x%x\n", status);
+ printk(KERN_DEBUG "Es1938debug - interrupt status: =0x%x\n", status);
#endif
/* AUDIO 1 */
if (status & 0x10) {
#if 0
- printk("Es1938debug - AUDIO channel 1 interrupt\n");
- printk("Es1938debug - AUDIO channel 1 DMAC DMA count: %u\n",
+ printk(KERN_DEBUG
+ "Es1938debug - AUDIO channel 1 interrupt\n");
+ printk(KERN_DEBUG
+ "Es1938debug - AUDIO channel 1 DMAC DMA count: %u\n",
inw(SLDM_REG(chip, DMACOUNT)));
- printk("Es1938debug - AUDIO channel 1 DMAC DMA base: %u\n",
+ printk(KERN_DEBUG
+ "Es1938debug - AUDIO channel 1 DMAC DMA base: %u\n",
inl(SLDM_REG(chip, DMAADDR)));
- printk("Es1938debug - AUDIO channel 1 DMAC DMA status: 0x%x\n",
+ printk(KERN_DEBUG
+ "Es1938debug - AUDIO channel 1 DMAC DMA status: 0x%x\n",
inl(SLDM_REG(chip, DMASTATUS)));
#endif
/* clear irq */
@@ -1699,10 +1703,13 @@ static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id)
/* AUDIO 2 */
if (status & 0x20) {
#if 0
- printk("Es1938debug - AUDIO channel 2 interrupt\n");
- printk("Es1938debug - AUDIO channel 2 DMAC DMA count: %u\n",
+ printk(KERN_DEBUG
+ "Es1938debug - AUDIO channel 2 interrupt\n");
+ printk(KERN_DEBUG
+ "Es1938debug - AUDIO channel 2 DMAC DMA count: %u\n",
inw(SLIO_REG(chip, AUDIO2DMACOUNT)));
- printk("Es1938debug - AUDIO channel 2 DMAC DMA base: %u\n",
+ printk(KERN_DEBUG
+ "Es1938debug - AUDIO channel 2 DMAC DMA base: %u\n",
inl(SLIO_REG(chip, AUDIO2DMAADDR)));
#endif
@@ -1799,9 +1806,9 @@ static int __devinit snd_es1938_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
for (idx = 0; idx < 5; idx++) {
if (pci_resource_start(pci, idx) == 0 ||
!(pci_resource_flags(pci, idx) & IORESOURCE_IO)) {
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index e9c3794bbcb..dc97e811614 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -2645,9 +2645,9 @@ static int __devinit snd_es1968_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (!card)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
if (total_bufsize[dev] < 128)
total_bufsize[dev] = 128;
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index c129f9e2072..60cdb9e0b68 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -1468,9 +1468,9 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
if ((err = snd_fm801_create(card, pci, tea575x_tuner[dev], &chip)) < 0) {
snd_card_free(card);
return err;
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index b7bba7dc7cf..d03f99298be 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -487,7 +487,6 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card,
{
struct hda_bus *bus;
int err;
- char qname[8];
static struct snd_device_ops dev_ops = {
.dev_register = snd_hda_bus_dev_register,
.dev_free = snd_hda_bus_dev_free,
@@ -517,10 +516,12 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card,
mutex_init(&bus->cmd_mutex);
INIT_LIST_HEAD(&bus->codec_list);
- snprintf(qname, sizeof(qname), "hda%d", card->number);
- bus->workq = create_workqueue(qname);
+ snprintf(bus->workq_name, sizeof(bus->workq_name),
+ "hd-audio%d", card->number);
+ bus->workq = create_singlethread_workqueue(bus->workq_name);
if (!bus->workq) {
- snd_printk(KERN_ERR "cannot create workqueue %s\n", qname);
+ snd_printk(KERN_ERR "cannot create workqueue %s\n",
+ bus->workq_name);
kfree(bus);
return -ENOMEM;
}
@@ -3087,6 +3088,16 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
}
EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_prepare);
+int snd_hda_multi_out_dig_cleanup(struct hda_codec *codec,
+ struct hda_multi_out *mout)
+{
+ mutex_lock(&codec->spdif_mutex);
+ cleanup_dig_out_stream(codec, mout->dig_out_nid);
+ mutex_unlock(&codec->spdif_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_cleanup);
+
/*
* release the digital out
*/
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 5810ef58840..09a332ada0c 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -614,6 +614,7 @@ struct hda_bus {
/* unsolicited event queue */
struct hda_bus_unsolicited *unsol;
+ char workq_name[16];
struct workqueue_struct *workq; /* common workqueue for codecs */
/* assigned PCMs */
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index 300ab407cf4..4ae51dcb81a 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -175,7 +175,7 @@ static int reconfig_codec(struct hda_codec *codec)
err = snd_hda_codec_build_controls(codec);
if (err < 0)
return err;
- return 0;
+ return snd_card_register(codec->bus->card);
}
/*
@@ -277,18 +277,19 @@ static ssize_t init_verbs_store(struct device *dev,
{
struct snd_hwdep *hwdep = dev_get_drvdata(dev);
struct hda_codec *codec = hwdep->private_data;
- char *p;
- struct hda_verb verb, *v;
+ struct hda_verb *v;
+ int nid, verb, param;
- verb.nid = simple_strtoul(buf, &p, 0);
- verb.verb = simple_strtoul(p, &p, 0);
- verb.param = simple_strtoul(p, &p, 0);
- if (!verb.nid || !verb.verb || !verb.param)
+ if (sscanf(buf, "%i %i %i", &nid, &verb, &param) != 3)
+ return -EINVAL;
+ if (!nid || !verb)
return -EINVAL;
v = snd_array_new(&codec->init_verbs);
if (!v)
return -ENOMEM;
- *v = verb;
+ v->nid = nid;
+ v->verb = verb;
+ v->param = param;
return count;
}
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 11e791b965f..3683978324e 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1947,16 +1947,13 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
return 0;
}
-static int azx_resume_early(struct pci_dev *pci)
-{
- return pci_restore_state(pci);
-}
-
static int azx_resume(struct pci_dev *pci)
{
struct snd_card *card = pci_get_drvdata(pci);
struct azx *chip = card->private_data;
+ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
printk(KERN_ERR "hda-intel: pci_enable_device failed, "
"disabling device\n");
@@ -2062,26 +2059,31 @@ static int __devinit check_position_fix(struct azx *chip, int fix)
{
const struct snd_pci_quirk *q;
- /* Check VIA HD Audio Controller exist */
- if (chip->pci->vendor == PCI_VENDOR_ID_VIA &&
- chip->pci->device == VIA_HDAC_DEVICE_ID) {
+ switch (fix) {
+ case POS_FIX_LPIB:
+ case POS_FIX_POSBUF:
+ return fix;
+ }
+
+ /* Check VIA/ATI HD Audio Controller exist */
+ switch (chip->driver_type) {
+ case AZX_DRIVER_VIA:
+ case AZX_DRIVER_ATI:
chip->via_dmapos_patch = 1;
/* Use link position directly, avoid any transfer problem. */
return POS_FIX_LPIB;
}
chip->via_dmapos_patch = 0;
- if (fix == POS_FIX_AUTO) {
- q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
- if (q) {
- printk(KERN_INFO
- "hda_intel: position_fix set to %d "
- "for device %04x:%04x\n",
- q->value, q->subvendor, q->subdevice);
- return q->value;
- }
+ q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
+ if (q) {
+ printk(KERN_INFO
+ "hda_intel: position_fix set to %d "
+ "for device %04x:%04x\n",
+ q->value, q->subvendor, q->subdevice);
+ return q->value;
}
- return fix;
+ return POS_FIX_AUTO;
}
/*
@@ -2098,6 +2100,8 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = {
SND_PCI_QUIRK(0x1028, 0x20ac, "Dell Studio Desktop", 0x01),
/* including bogus ALC268 in slot#2 that conflicts with ALC888 */
SND_PCI_QUIRK(0x17c0, 0x4085, "Medion MD96630", 0x01),
+ /* conflict of ALC268 in slot#3 (digital I/O); a temporary fix */
+ SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba laptop", 0x03),
{}
};
@@ -2211,9 +2215,17 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
gcap = azx_readw(chip, GCAP);
snd_printdd("chipset global capabilities = 0x%x\n", gcap);
+ /* ATI chips seems buggy about 64bit DMA addresses */
+ if (chip->driver_type == AZX_DRIVER_ATI)
+ gcap &= ~0x01;
+
/* allow 64bit DMA address if supported by H/W */
if ((gcap & 0x01) && !pci_set_dma_mask(pci, DMA_64BIT_MASK))
pci_set_consistent_dma_mask(pci, DMA_64BIT_MASK);
+ else {
+ pci_set_dma_mask(pci, DMA_32BIT_MASK);
+ pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK);
+ }
/* read number of streams from GCAP register instead of using
* hardcoded value
@@ -2335,10 +2347,10 @@ static int __devinit azx_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (!card) {
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0) {
snd_printk(KERN_ERR SFX "Error creating card!\n");
- return -ENOMEM;
+ return err;
}
err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
@@ -2468,7 +2480,6 @@ static struct pci_driver driver = {
.remove = __devexit_p(azx_remove),
#ifdef CONFIG_PM
.suspend = azx_suspend,
- .resume_early = azx_resume_early,
.resume = azx_resume,
#endif
};
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 1dd8716c387..44f189cb97a 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -251,6 +251,8 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
unsigned int stream_tag,
unsigned int format,
struct snd_pcm_substream *substream);
+int snd_hda_multi_out_dig_cleanup(struct hda_codec *codec,
+ struct hda_multi_out *mout);
int snd_hda_multi_out_analog_open(struct hda_codec *codec,
struct hda_multi_out *mout,
struct snd_pcm_substream *substream,
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index 7ca66d65414..144b85276d5 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -399,7 +399,8 @@ static void print_conn_list(struct snd_info_buffer *buffer,
{
int c, curr = -1;
- if (conn_len > 1 && wid_type != AC_WID_AUD_MIX)
+ if (conn_len > 1 && wid_type != AC_WID_AUD_MIX &&
+ wid_type != AC_WID_VOL_KNB)
curr = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_CONNECT_SEL, 0);
snd_iprintf(buffer, " Connection: %d\n", conn_len);
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 2e7371ec2e2..e48612323aa 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -275,6 +275,14 @@ static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
format, substream);
}
+static int ad198x_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct ad198x_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
+}
+
/*
* Analog capture
*/
@@ -333,7 +341,8 @@ static struct hda_pcm_stream ad198x_pcm_digital_playback = {
.ops = {
.open = ad198x_dig_playback_pcm_open,
.close = ad198x_dig_playback_pcm_close,
- .prepare = ad198x_dig_playback_pcm_prepare
+ .prepare = ad198x_dig_playback_pcm_prepare,
+ .cleanup = ad198x_dig_playback_pcm_cleanup
},
};
@@ -1885,8 +1894,8 @@ static hda_nid_t ad1988_capsrc_nids[3] = {
#define AD1988_SPDIF_OUT_HDMI 0x0b
#define AD1988_SPDIF_IN 0x07
-static hda_nid_t ad1989b_slave_dig_outs[2] = {
- AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI
+static hda_nid_t ad1989b_slave_dig_outs[] = {
+ AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0
};
static struct hda_input_mux ad1988_6stack_capture_source = {
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 75de40aaab0..0177ef8f4c9 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -347,6 +347,7 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol,
&spec->cur_mux[adc_idx]);
}
+#ifdef CONFIG_SND_JACK
static int conexant_add_jack(struct hda_codec *codec,
hda_nid_t nid, int type)
{
@@ -394,7 +395,6 @@ static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid)
static int conexant_init_jacks(struct hda_codec *codec)
{
-#ifdef CONFIG_SND_JACK
struct conexant_spec *spec = codec->spec;
int i;
@@ -422,10 +422,19 @@ static int conexant_init_jacks(struct hda_codec *codec)
++hv;
}
}
-#endif
return 0;
}
+#else
+static inline void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid)
+{
+}
+
+static inline int conexant_init_jacks(struct hda_codec *codec)
+{
+ return 0;
+}
+#endif
static int conexant_init(struct hda_codec *codec)
{
@@ -1566,6 +1575,7 @@ static struct snd_pci_quirk cxt5047_cfg_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP),
SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP),
SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2000Z", CXT5047_LAPTOP),
+ SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6700", CXT5047_LAPTOP),
SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD),
{}
};
diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c
index 3564f4e4b74..fcc77fec448 100644
--- a/sound/pci/hda/patch_intelhdmi.c
+++ b/sound/pci/hda/patch_intelhdmi.c
@@ -49,11 +49,6 @@ static struct hda_verb pinout_enable_verb[] = {
{} /* terminator */
};
-static struct hda_verb pinout_disable_verb[] = {
- {PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00},
- {}
-};
-
static struct hda_verb unsolicited_response_verb[] = {
{PIN_NID, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN |
INTEL_HDMI_EVENT_TAG},
@@ -248,10 +243,6 @@ static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid,
static void hdmi_enable_output(struct hda_codec *codec)
{
- /* Enable Audio InfoFrame Transmission */
- hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0);
- snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT,
- AC_DIPXMIT_BEST);
/* Unmute */
if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP)
snd_hda_codec_write(codec, PIN_NID, 0,
@@ -260,17 +251,24 @@ static void hdmi_enable_output(struct hda_codec *codec)
snd_hda_sequence_write(codec, pinout_enable_verb);
}
-static void hdmi_disable_output(struct hda_codec *codec)
+/*
+ * Enable Audio InfoFrame Transmission
+ */
+static void hdmi_start_infoframe_trans(struct hda_codec *codec)
{
- snd_hda_sequence_write(codec, pinout_disable_verb);
- if (get_wcaps(codec, PIN_NID) & AC_WCAP_OUT_AMP)
- snd_hda_codec_write(codec, PIN_NID, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+ hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0);
+ snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT,
+ AC_DIPXMIT_BEST);
+}
- /*
- * FIXME: noises may arise when playing music after reloading the
- * kernel module, until the next X restart or monitor repower.
- */
+/*
+ * Disable Audio InfoFrame Transmission
+ */
+static void hdmi_stop_infoframe_trans(struct hda_codec *codec)
+{
+ hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0);
+ snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT,
+ AC_DIPXMIT_DISABLE);
}
static int hdmi_get_channel_count(struct hda_codec *codec)
@@ -368,11 +366,16 @@ static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
struct hdmi_audio_infoframe *ai)
{
u8 *params = (u8 *)ai;
+ u8 sum = 0;
int i;
hdmi_debug_dip_size(codec);
hdmi_clear_dip_buffers(codec); /* be paranoid */
+ for (i = 0; i < sizeof(ai); i++)
+ sum += params[i];
+ ai->checksum = - sum;
+
hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0);
for (i = 0; i < sizeof(ai); i++)
hdmi_write_dip_byte(codec, PIN_NID, params[i]);
@@ -419,14 +422,18 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec,
/*
* CA defaults to 0 for basic stereo audio
*/
- if (!eld->eld_ver)
- return 0;
- if (!eld->spk_alloc)
- return 0;
if (channels <= 2)
return 0;
/*
+ * HDMI sink's ELD info cannot always be retrieved for now, e.g.
+ * in console or for audio devices. Assume the highest speakers
+ * configuration, to _not_ prohibit multi-channel audio playback.
+ */
+ if (!eld->spk_alloc)
+ eld->spk_alloc = 0xffff;
+
+ /*
* expand ELD's speaker allocation mask
*
* ELD tells the speaker mask in a compact(paired) form,
@@ -485,6 +492,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
hdmi_setup_channel_mapping(codec, &ai);
hdmi_fill_audio_infoframe(codec, &ai);
+ hdmi_start_infoframe_trans(codec);
}
@@ -562,7 +570,7 @@ static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo,
{
struct intel_hdmi_spec *spec = codec->spec;
- hdmi_disable_output(codec);
+ hdmi_stop_infoframe_trans(codec);
return snd_hda_multi_out_dig_close(codec, &spec->multiout);
}
@@ -582,8 +590,6 @@ static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
hdmi_setup_audio_infoframe(codec, substream);
- hdmi_enable_output(codec);
-
return 0;
}
@@ -628,8 +634,7 @@ static int intel_hdmi_build_controls(struct hda_codec *codec)
static int intel_hdmi_init(struct hda_codec *codec)
{
- /* disable audio output as early as possible */
- hdmi_disable_output(codec);
+ hdmi_enable_output(codec);
snd_hda_sequence_write(codec, unsolicited_response_verb);
@@ -679,6 +684,7 @@ static struct hda_codec_preset snd_hda_preset_intelhdmi[] = {
{ .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi },
{ .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi },
{ .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi },
+ { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi },
{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi },
{} /* terminator */
};
@@ -687,6 +693,7 @@ MODULE_ALIAS("snd-hda-codec-id:808629fb");
MODULE_ALIAS("snd-hda-codec-id:80862801");
MODULE_ALIAS("snd-hda-codec-id:80862802");
MODULE_ALIAS("snd-hda-codec-id:80862803");
+MODULE_ALIAS("snd-hda-codec-id:80862804");
MODULE_ALIAS("snd-hda-codec-id:10951392");
MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 5d249a547fb..6c26afcb826 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -1037,6 +1037,7 @@ do_sku:
case 0x10ec0267:
case 0x10ec0268:
case 0x10ec0269:
+ case 0x10ec0272:
case 0x10ec0660:
case 0x10ec0662:
case 0x10ec0663:
@@ -1065,6 +1066,7 @@ do_sku:
case 0x10ec0882:
case 0x10ec0883:
case 0x10ec0885:
+ case 0x10ec0887:
case 0x10ec0889:
snd_hda_codec_write(codec, 0x20, 0,
AC_VERB_SET_COEF_INDEX, 7);
@@ -7012,12 +7014,15 @@ static int patch_alc882(struct hda_codec *codec)
break;
case 0x106b1000: /* iMac 24 */
case 0x106b2800: /* AppleTV */
+ case 0x106b3e00: /* iMac 24 Aluminium */
board_config = ALC885_IMAC24;
break;
+ case 0x106b00a0: /* MacBookPro3,1 - Another revision */
case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
case 0x106b00a4: /* MacbookPro4,1 */
case 0x106b2c00: /* Macbook Pro rev3 */
case 0x106b3600: /* Macbook 3.1 */
+ case 0x106b3800: /* MacbookPro4,1 - latter revision */
board_config = ALC885_MBP3;
break;
default:
@@ -8465,6 +8470,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
ALC888_ACER_ASPIRE_4930G),
SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
ALC888_ACER_ASPIRE_4930G),
+ SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
+ ALC888_ACER_ASPIRE_4930G),
SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
@@ -8474,6 +8481,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
+ SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
@@ -8513,6 +8521,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
+ SND_PCI_QUIRK(0x1734, 0x1107, "FSC AMILO Xi2550",
+ ALC883_FUJITSU_PI2515),
SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515),
SND_PCI_QUIRK(0x1734, 0x113d, "Fujitsu AMILO Xa3530",
ALC888_FUJITSU_XA3530),
@@ -10547,6 +10557,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC),
SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC),
SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC),
+ SND_PCI_QUIRK(0x103c, 0x170b, "HP xw*", ALC262_HP_BPC),
SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 3dd4eee70b7..6094344fb22 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -1207,7 +1207,7 @@ static const char *slave_vols[] = {
"LFE Playback Volume",
"Side Playback Volume",
"Headphone Playback Volume",
- "Headphone Playback Volume",
+ "Headphone2 Playback Volume",
"Speaker Playback Volume",
"External Speaker Playback Volume",
"Speaker2 Playback Volume",
@@ -1221,7 +1221,7 @@ static const char *slave_sws[] = {
"LFE Playback Switch",
"Side Playback Switch",
"Headphone Playback Switch",
- "Headphone Playback Switch",
+ "Headphone2 Playback Switch",
"Speaker Playback Switch",
"External Speaker Playback Switch",
"Speaker2 Playback Switch",
@@ -1799,11 +1799,13 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = {
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f2,
"HP dv5", STAC_HP_M4),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4,
- "HP dv7", STAC_HP_M4),
+ "HP dv7", STAC_HP_DV5),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f7,
"HP dv4", STAC_HP_DV5),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fc,
"HP dv7", STAC_HP_M4),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3600,
+ "HP dv5", STAC_HP_DV5),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3603,
"HP dv5", STAC_HP_DV5),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
@@ -2440,6 +2442,14 @@ static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
stream_tag, format, substream);
}
+static int stac92xx_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
+}
+
/*
* Analog capture callbacks
@@ -2484,7 +2494,8 @@ static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
.ops = {
.open = stac92xx_dig_playback_pcm_open,
.close = stac92xx_dig_playback_pcm_close,
- .prepare = stac92xx_dig_playback_pcm_prepare
+ .prepare = stac92xx_dig_playback_pcm_prepare,
+ .cleanup = stac92xx_dig_playback_pcm_cleanup
},
};
@@ -2539,6 +2550,8 @@ static int stac92xx_build_pcms(struct hda_codec *codec)
info->name = "STAC92xx Analog";
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+ spec->multiout.dac_nids[0];
info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
@@ -3503,6 +3516,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
if (! spec->autocfg.line_outs)
return 0; /* can't find valid pin config */
+#if 0 /* FIXME: temporarily disabled */
/* If we have no real line-out pin and multiple hp-outs, HPs should
* be set up as multi-channel outputs.
*/
@@ -3522,6 +3536,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out
spec->autocfg.line_out_type = AUTO_PIN_HP_OUT;
spec->autocfg.hp_outs = 0;
}
+#endif /* FIXME: temporarily disabled */
if (spec->autocfg.mono_out_pin) {
int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) &
(AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP);
@@ -4976,7 +4991,7 @@ again:
case STAC_DELL_M4_3:
spec->num_dmics = 1;
spec->num_smuxes = 0;
- spec->num_dmuxes = 0;
+ spec->num_dmuxes = 1;
break;
default:
spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index 58d7cda03de..bab1c700f49 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -2648,9 +2648,9 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
strcpy(card->driver, "ICE1712");
strcpy(card->shortname, "ICEnsemble ICE1712");
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index bb8d8c766b9..7ff36d3f0f4 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -2456,9 +2456,9 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
strcpy(card->driver, "ICE1724");
strcpy(card->shortname, "ICEnsemble ICE1724");
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 19d3391e229..608655e9275 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -617,7 +617,7 @@ static int snd_intel8x0_ali_codec_semaphore(struct intel8x0 *chip)
int time = 100;
if (chip->buggy_semaphore)
return 0; /* just ignore ... */
- while (time-- && (igetdword(chip, ICHREG(ALI_CAS)) & ALI_CAS_SEM_BUSY))
+ while (--time && (igetdword(chip, ICHREG(ALI_CAS)) & ALI_CAS_SEM_BUSY))
udelay(1);
if (! time && ! chip->in_ac97_init)
snd_printk(KERN_WARNING "ali_codec_semaphore timeout\n");
@@ -3058,9 +3058,9 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci,
int err;
struct shortname_table *name;
- card = snd_card_new(index, id, THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
if (spdif_aclink < 0)
spdif_aclink = check_default_spdif_aclink(pci);
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index 93449e46456..33a843c1931 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -1269,9 +1269,9 @@ static int __devinit snd_intel8x0m_probe(struct pci_dev *pci,
int err;
struct shortname_table *name;
- card = snd_card_new(index, id, THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
strcpy(card->driver, "ICH-MODEM");
strcpy(card->shortname, "Intel ICH");
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 5f8006b4275..8b79969034b 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -2443,9 +2443,9 @@ snd_korg1212_probe(struct pci_dev *pci,
dev++;
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
if ((err = snd_korg1212_create(card, pci, &korg1212)) < 0) {
snd_card_free(card);
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 59bbaf8f3e5..70141548f25 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -2691,9 +2691,9 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
switch (pci->device) {
case PCI_DEVICE_ID_ESS_ALLEGRO:
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index f23a73577c2..c1eb84a14c4 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -607,6 +607,7 @@ static int snd_mixart_hw_params(struct snd_pcm_substream *subs,
/* set the format to the board */
err = mixart_set_format(stream, format);
if(err < 0) {
+ mutex_unlock(&mgr->setup_mutex);
return err;
}
@@ -1365,12 +1366,12 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci,
else
idx = index[dev] + i;
snprintf(tmpid, sizeof(tmpid), "%s-%d", id[dev] ? id[dev] : "MIXART", i);
- card = snd_card_new(idx, tmpid, THIS_MODULE, 0);
+ err = snd_card_create(idx, tmpid, THIS_MODULE, 0, &card);
- if (! card) {
+ if (err < 0) {
snd_printk(KERN_ERR "cannot allocate the card %d\n", i);
snd_mixart_free(mgr);
- return -ENOMEM;
+ return err;
}
strcpy(card->driver, CARD_NAME);
diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c
index 3782b52bc0e..4cf4cd8c939 100644
--- a/sound/pci/mixart/mixart_hwdep.c
+++ b/sound/pci/mixart/mixart_hwdep.c
@@ -345,8 +345,8 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
status_daught = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
/* motherboard xilinx status 5 will say that the board is performing a reset */
- if( status_xilinx == 5 ) {
- snd_printk( KERN_ERR "miXart is resetting !\n");
+ if (status_xilinx == 5) {
+ snd_printk(KERN_ERR "miXart is resetting !\n");
return -EAGAIN; /* try again later */
}
@@ -354,13 +354,14 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
case MIXART_MOTHERBOARD_XLX_INDEX:
/* xilinx already loaded ? */
- if( status_xilinx == 4 ) {
- snd_printk( KERN_DEBUG "xilinx is already loaded !\n");
+ if (status_xilinx == 4) {
+ snd_printk(KERN_DEBUG "xilinx is already loaded !\n");
return 0;
}
/* the status should be 0 == "idle" */
- if( status_xilinx != 0 ) {
- snd_printk( KERN_ERR "xilinx load error ! status = %d\n", status_xilinx);
+ if (status_xilinx != 0) {
+ snd_printk(KERN_ERR "xilinx load error ! status = %d\n",
+ status_xilinx);
return -EIO; /* modprob -r may help ? */
}
@@ -389,21 +390,23 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
case MIXART_MOTHERBOARD_ELF_INDEX:
- if( status_elf == 4 ) {
- snd_printk( KERN_DEBUG "elf file already loaded !\n");
+ if (status_elf == 4) {
+ snd_printk(KERN_DEBUG "elf file already loaded !\n");
return 0;
}
/* the status should be 0 == "idle" */
- if( status_elf != 0 ) {
- snd_printk( KERN_ERR "elf load error ! status = %d\n", status_elf);
+ if (status_elf != 0) {
+ snd_printk(KERN_ERR "elf load error ! status = %d\n",
+ status_elf);
return -EIO; /* modprob -r may help ? */
}
/* wait for xilinx status == 4 */
err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET, 1, 4, 500); /* 5sec */
if (err < 0) {
- snd_printk( KERN_ERR "xilinx was not loaded or could not be started\n");
+ snd_printk(KERN_ERR "xilinx was not loaded or "
+ "could not be started\n");
return err;
}
@@ -424,7 +427,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
/* wait for elf status == 4 */
err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET, 1, 4, 300); /* 3sec */
if (err < 0) {
- snd_printk( KERN_ERR "elf could not be started\n");
+ snd_printk(KERN_ERR "elf could not be started\n");
return err;
}
@@ -437,15 +440,16 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
default:
/* elf and xilinx should be loaded */
- if( (status_elf != 4) || (status_xilinx != 4) ) {
- printk( KERN_ERR "xilinx or elf not successfully loaded\n");
+ if (status_elf != 4 || status_xilinx != 4) {
+ printk(KERN_ERR "xilinx or elf not "
+ "successfully loaded\n");
return -EIO; /* modprob -r may help ? */
}
/* wait for daughter detection != 0 */
err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET, 0, 0, 30); /* 300msec */
if (err < 0) {
- snd_printk( KERN_ERR "error starting elf file\n");
+ snd_printk(KERN_ERR "error starting elf file\n");
return err;
}
@@ -460,8 +464,9 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
return -EINVAL;
/* daughter should be idle */
- if( status_daught != 0 ) {
- printk( KERN_ERR "daughter load error ! status = %d\n", status_daught);
+ if (status_daught != 0) {
+ printk(KERN_ERR "daughter load error ! status = %d\n",
+ status_daught);
return -EIO; /* modprob -r may help ? */
}
@@ -480,7 +485,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
/* wait for status == 2 */
err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 2, 30); /* 300msec */
if (err < 0) {
- snd_printk( KERN_ERR "daughter board load error\n");
+ snd_printk(KERN_ERR "daughter board load error\n");
return err;
}
@@ -502,7 +507,8 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
/* wait for daughter status == 3 */
err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 3, 300); /* 3sec */
if (err < 0) {
- snd_printk( KERN_ERR "daughter board could not be initialised\n");
+ snd_printk(KERN_ERR
+ "daughter board could not be initialised\n");
return err;
}
@@ -512,7 +518,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw
/* first communication with embedded */
err = mixart_first_init(mgr);
if (err < 0) {
- snd_printk( KERN_ERR "miXart could not be set up\n");
+ snd_printk(KERN_ERR "miXart could not be set up\n");
return err;
}
@@ -581,16 +587,6 @@ MODULE_FIRMWARE("mixart/miXart8AES.xlx");
/* miXart hwdep interface id string */
#define SND_MIXART_HWDEP_ID "miXart Loader"
-static int mixart_hwdep_open(struct snd_hwdep *hw, struct file *file)
-{
- return 0;
-}
-
-static int mixart_hwdep_release(struct snd_hwdep *hw, struct file *file)
-{
- return 0;
-}
-
static int mixart_hwdep_dsp_status(struct snd_hwdep *hw,
struct snd_hwdep_dsp_status *info)
{
@@ -643,8 +639,6 @@ int snd_mixart_setup_firmware(struct mixart_mgr *mgr)
hw->iface = SNDRV_HWDEP_IFACE_MIXART;
hw->private_data = mgr;
- hw->ops.open = mixart_hwdep_open;
- hw->ops.release = mixart_hwdep_release;
hw->ops.dsp_status = mixart_hwdep_dsp_status;
hw->ops.dsp_load = mixart_hwdep_dsp_load;
hw->exclusive = 1;
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 50c9f8a0508..522a040855d 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -1668,9 +1668,9 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci,
}
}
- card = snd_card_new(index, id, THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
switch (pci->device) {
case PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO:
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index 84f481d41ef..9c81e0b0511 100644
--- a/sound/pci/oxygen/oxygen_lib.c
+++ b/sound/pci/oxygen/oxygen_lib.c
@@ -459,10 +459,10 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
struct oxygen *chip;
int err;
- card = snd_card_new(index, id, model->owner,
- sizeof *chip + model->model_data_size);
- if (!card)
- return -ENOMEM;
+ err = snd_card_create(index, id, model->owner,
+ sizeof(*chip) + model->model_data_size, &card);
+ if (err < 0)
+ return err;
chip = card->private_data;
chip->card = card;
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c
index 18c7c91786b..6c870c12a17 100644
--- a/sound/pci/oxygen/virtuoso.c
+++ b/sound/pci/oxygen/virtuoso.c
@@ -26,7 +26,7 @@
* SPI 0 -> 1st PCM1796 (front)
* SPI 1 -> 2nd PCM1796 (surround)
* SPI 2 -> 3rd PCM1796 (center/LFE)
- * SPI 4 -> 4th PCM1796 (back) and EEPROM self-destruct (do not use!)
+ * SPI 4 -> 4th PCM1796 (back)
*
* GPIO 2 -> M0 of CS5381
* GPIO 3 -> M1 of CS5381
@@ -207,12 +207,6 @@ static void xonar_gpio_changed(struct oxygen *chip);
static inline void pcm1796_write_spi(struct oxygen *chip, unsigned int codec,
u8 reg, u8 value)
{
- /*
- * We don't want to do writes on SPI 4 because the EEPROM, which shares
- * the same pin, might get confused and broken. We'd better take care
- * that the driver works with the default register values ...
- */
-#if 0
/* maps ALSA channel pair number to SPI output */
static const u8 codec_map[4] = {
0, 1, 2, 4
@@ -223,7 +217,6 @@ static inline void pcm1796_write_spi(struct oxygen *chip, unsigned int codec,
(codec_map[codec] << OXYGEN_SPI_CODEC_SHIFT) |
OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
(reg << 8) | value);
-#endif
}
static inline void pcm1796_write_i2c(struct oxygen *chip, unsigned int codec,
@@ -757,9 +750,6 @@ static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -12700, 100, 0);
static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
{
- if (!strncmp(template->name, "Master Playback ", 16))
- /* disable volume/mute because they would require SPI writes */
- return 1;
if (!strncmp(template->name, "CD Capture ", 11))
/* CD in is actually connected to the video in pin */
template->private_value ^= AC97_CD ^ AC97_VIDEO;
@@ -850,8 +840,9 @@ static const struct oxygen_model model_xonar_d2 = {
.dac_volume_min = 0x0f,
.dac_volume_max = 0xff,
.misc_flags = OXYGEN_MISC_MIDI,
- .function_flags = OXYGEN_FUNCTION_SPI,
- .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S,
+ .function_flags = OXYGEN_FUNCTION_SPI |
+ OXYGEN_FUNCTION_ENABLE_SPI_4_5,
+ .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
.adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
};
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index 27cf2c28d11..7f95459c8b1 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -1510,12 +1510,12 @@ static int __devinit pcxhr_probe(struct pci_dev *pci,
snprintf(tmpid, sizeof(tmpid), "%s-%d",
id[dev] ? id[dev] : card_name, i);
- card = snd_card_new(idx, tmpid, THIS_MODULE, 0);
+ err = snd_card_create(idx, tmpid, THIS_MODULE, 0, &card);
- if (! card) {
+ if (err < 0) {
snd_printk(KERN_ERR "cannot allocate the card %d\n", i);
pcxhr_free(mgr);
- return -ENOMEM;
+ return err;
}
strcpy(card->driver, DRIVER_NAME);
diff --git a/sound/pci/pcxhr/pcxhr.h b/sound/pci/pcxhr/pcxhr.h
index 84131a916c9..69d87dee699 100644
--- a/sound/pci/pcxhr/pcxhr.h
+++ b/sound/pci/pcxhr/pcxhr.h
@@ -97,12 +97,12 @@ struct pcxhr_mgr {
int capture_chips;
int fw_file_set;
int firmware_num;
- int is_hr_stereo:1;
- int board_has_aes1:1; /* if 1 board has AES1 plug and SRC */
- int board_has_analog:1; /* if 0 the board is digital only */
- int board_has_mic:1; /* if 1 the board has microphone input */
- int board_aes_in_192k:1;/* if 1 the aes input plugs do support 192kHz */
- int mono_capture:1; /* if 1 the board does mono capture */
+ unsigned int is_hr_stereo:1;
+ unsigned int board_has_aes1:1; /* if 1 board has AES1 plug and SRC */
+ unsigned int board_has_analog:1; /* if 0 the board is digital only */
+ unsigned int board_has_mic:1; /* if 1 the board has microphone input */
+ unsigned int board_aes_in_192k:1;/* if 1 the aes input plugs do support 192kHz */
+ unsigned int mono_capture:1; /* if 1 the board does mono capture */
struct snd_dma_buffer hostport;
diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c
index 592743a298b..17cb1233a90 100644
--- a/sound/pci/pcxhr/pcxhr_hwdep.c
+++ b/sound/pci/pcxhr/pcxhr_hwdep.c
@@ -471,16 +471,6 @@ static int pcxhr_hwdep_dsp_load(struct snd_hwdep *hw,
return 0;
}
-static int pcxhr_hwdep_open(struct snd_hwdep *hw, struct file *file)
-{
- return 0;
-}
-
-static int pcxhr_hwdep_release(struct snd_hwdep *hw, struct file *file)
-{
- return 0;
-}
-
int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
{
int err;
@@ -495,8 +485,6 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
hw->iface = SNDRV_HWDEP_IFACE_PCXHR;
hw->private_data = mgr;
- hw->ops.open = pcxhr_hwdep_open;
- hw->ops.release = pcxhr_hwdep_release;
hw->ops.dsp_status = pcxhr_hwdep_dsp_status;
hw->ops.dsp_load = pcxhr_hwdep_dsp_load;
hw->exclusive = 1;
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index 3caacfb9d8e..6f1034417a0 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -2102,9 +2102,9 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
if ((err = snd_riptide_create(card, pci, &chip)) < 0) {
snd_card_free(card);
return err;
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
index e7ef3a1a25a..d7b966e7c4c 100644
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -1941,9 +1941,10 @@ snd_rme32_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
return -ENOENT;
}
- if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct rme32))) == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct rme32), &card);
+ if (err < 0)
+ return err;
card->private_free = snd_rme32_card_free;
rme32 = (struct rme32 *) card->private_data;
rme32->card = card;
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index 3fdd488d097..55fb1c131f5 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -2348,9 +2348,10 @@ snd_rme96_probe(struct pci_dev *pci,
dev++;
return -ENOENT;
}
- if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct rme96))) == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct rme96), &card);
+ if (err < 0)
+ return err;
card->private_free = snd_rme96_card_free;
rme96 = (struct rme96 *)card->private_data;
rme96->card = card;
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 44d0c15e2b7..bacfdd12619 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -4413,13 +4413,6 @@ static int snd_hdsp_capture_release(struct snd_pcm_substream *substream)
return 0;
}
-static int snd_hdsp_hwdep_dummy_op(struct snd_hwdep *hw, struct file *file)
-{
- /* we have nothing to initialize but the call is required */
- return 0;
-}
-
-
/* helper functions for copying meter values */
static inline int copy_u32_le(void __user *dest, void __iomem *src)
{
@@ -4738,9 +4731,7 @@ static int snd_hdsp_create_hwdep(struct snd_card *card, struct hdsp *hdsp)
hw->private_data = hdsp;
strcpy(hw->name, "HDSP hwdep interface");
- hw->ops.open = snd_hdsp_hwdep_dummy_op;
hw->ops.ioctl = snd_hdsp_hwdep_ioctl;
- hw->ops.release = snd_hdsp_hwdep_dummy_op;
return 0;
}
@@ -5158,8 +5149,10 @@ static int __devinit snd_hdsp_probe(struct pci_dev *pci,
return -ENOENT;
}
- if (!(card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct hdsp))))
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct hdsp), &card);
+ if (err < 0)
+ return err;
hdsp = (struct hdsp *) card->private_data;
card->private_free = snd_hdsp_card_free;
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 71231cf1b2b..bac2dc0c5d8 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -4100,13 +4100,6 @@ static int snd_hdspm_capture_release(struct snd_pcm_substream *substream)
return 0;
}
-static int snd_hdspm_hwdep_dummy_op(struct snd_hwdep * hw, struct file *file)
-{
- /* we have nothing to initialize but the call is required */
- return 0;
-}
-
-
static int snd_hdspm_hwdep_ioctl(struct snd_hwdep * hw, struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -4213,9 +4206,7 @@ static int __devinit snd_hdspm_create_hwdep(struct snd_card *card,
hw->private_data = hdspm;
strcpy(hw->name, "HDSPM hwdep interface");
- hw->ops.open = snd_hdspm_hwdep_dummy_op;
hw->ops.ioctl = snd_hdspm_hwdep_ioctl;
- hw->ops.release = snd_hdspm_hwdep_dummy_op;
return 0;
}
@@ -4503,10 +4494,10 @@ static int __devinit snd_hdspm_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev],
- THIS_MODULE, sizeof(struct hdspm));
- if (!card)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev],
+ THIS_MODULE, sizeof(struct hdspm), &card);
+ if (err < 0)
+ return err;
hdspm = card->private_data;
card->private_free = snd_hdspm_card_free;
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index 2570907134d..bc539abb210 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -2594,11 +2594,11 @@ static int __devinit snd_rme9652_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_rme9652));
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_rme9652), &card);
- if (!card)
- return -ENOMEM;
+ if (err < 0)
+ return err;
rme9652 = (struct snd_rme9652 *) card->private_data;
card->private_free = snd_rme9652_card_free;
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c
index df2007e3be7..baf6d8e3dab 100644
--- a/sound/pci/sis7019.c
+++ b/sound/pci/sis7019.c
@@ -1387,9 +1387,8 @@ static int __devinit snd_sis7019_probe(struct pci_dev *pci,
if (!enable)
goto error_out;
- rc = -ENOMEM;
- card = snd_card_new(index, id, THIS_MODULE, sizeof(*sis));
- if (!card)
+ rc = snd_card_create(index, id, THIS_MODULE, sizeof(*sis), &card);
+ if (rc < 0)
goto error_out;
strcpy(card->driver, "SiS7019");
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index cd408b86c83..d989215f355 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -273,7 +273,8 @@ static inline void snd_sonicvibes_setdmaa(struct sonicvibes * sonic,
outl(count, sonic->dmaa_port + SV_DMA_COUNT0);
outb(0x18, sonic->dmaa_port + SV_DMA_MODE);
#if 0
- printk("program dmaa: addr = 0x%x, paddr = 0x%x\n", addr, inl(sonic->dmaa_port + SV_DMA_ADDR0));
+ printk(KERN_DEBUG "program dmaa: addr = 0x%x, paddr = 0x%x\n",
+ addr, inl(sonic->dmaa_port + SV_DMA_ADDR0));
#endif
}
@@ -288,7 +289,8 @@ static inline void snd_sonicvibes_setdmac(struct sonicvibes * sonic,
outl(count, sonic->dmac_port + SV_DMA_COUNT0);
outb(0x14, sonic->dmac_port + SV_DMA_MODE);
#if 0
- printk("program dmac: addr = 0x%x, paddr = 0x%x\n", addr, inl(sonic->dmac_port + SV_DMA_ADDR0));
+ printk(KERN_DEBUG "program dmac: addr = 0x%x, paddr = 0x%x\n",
+ addr, inl(sonic->dmac_port + SV_DMA_ADDR0));
#endif
}
@@ -355,71 +357,104 @@ static unsigned char snd_sonicvibes_in(struct sonicvibes * sonic, unsigned char
#if 0
static void snd_sonicvibes_debug(struct sonicvibes * sonic)
{
- printk("SV REGS: INDEX = 0x%02x ", inb(SV_REG(sonic, INDEX)));
+ printk(KERN_DEBUG
+ "SV REGS: INDEX = 0x%02x ", inb(SV_REG(sonic, INDEX)));
printk(" STATUS = 0x%02x\n", inb(SV_REG(sonic, STATUS)));
- printk(" 0x00: left input = 0x%02x ", snd_sonicvibes_in(sonic, 0x00));
+ printk(KERN_DEBUG
+ " 0x00: left input = 0x%02x ", snd_sonicvibes_in(sonic, 0x00));
printk(" 0x20: synth rate low = 0x%02x\n", snd_sonicvibes_in(sonic, 0x20));
- printk(" 0x01: right input = 0x%02x ", snd_sonicvibes_in(sonic, 0x01));
+ printk(KERN_DEBUG
+ " 0x01: right input = 0x%02x ", snd_sonicvibes_in(sonic, 0x01));
printk(" 0x21: synth rate high = 0x%02x\n", snd_sonicvibes_in(sonic, 0x21));
- printk(" 0x02: left AUX1 = 0x%02x ", snd_sonicvibes_in(sonic, 0x02));
+ printk(KERN_DEBUG
+ " 0x02: left AUX1 = 0x%02x ", snd_sonicvibes_in(sonic, 0x02));
printk(" 0x22: ADC clock = 0x%02x\n", snd_sonicvibes_in(sonic, 0x22));
- printk(" 0x03: right AUX1 = 0x%02x ", snd_sonicvibes_in(sonic, 0x03));
+ printk(KERN_DEBUG
+ " 0x03: right AUX1 = 0x%02x ", snd_sonicvibes_in(sonic, 0x03));
printk(" 0x23: ADC alt rate = 0x%02x\n", snd_sonicvibes_in(sonic, 0x23));
- printk(" 0x04: left CD = 0x%02x ", snd_sonicvibes_in(sonic, 0x04));
+ printk(KERN_DEBUG
+ " 0x04: left CD = 0x%02x ", snd_sonicvibes_in(sonic, 0x04));
printk(" 0x24: ADC pll M = 0x%02x\n", snd_sonicvibes_in(sonic, 0x24));
- printk(" 0x05: right CD = 0x%02x ", snd_sonicvibes_in(sonic, 0x05));
+ printk(KERN_DEBUG
+ " 0x05: right CD = 0x%02x ", snd_sonicvibes_in(sonic, 0x05));
printk(" 0x25: ADC pll N = 0x%02x\n", snd_sonicvibes_in(sonic, 0x25));
- printk(" 0x06: left line = 0x%02x ", snd_sonicvibes_in(sonic, 0x06));
+ printk(KERN_DEBUG
+ " 0x06: left line = 0x%02x ", snd_sonicvibes_in(sonic, 0x06));
printk(" 0x26: Synth pll M = 0x%02x\n", snd_sonicvibes_in(sonic, 0x26));
- printk(" 0x07: right line = 0x%02x ", snd_sonicvibes_in(sonic, 0x07));
+ printk(KERN_DEBUG
+ " 0x07: right line = 0x%02x ", snd_sonicvibes_in(sonic, 0x07));
printk(" 0x27: Synth pll N = 0x%02x\n", snd_sonicvibes_in(sonic, 0x27));
- printk(" 0x08: MIC = 0x%02x ", snd_sonicvibes_in(sonic, 0x08));
+ printk(KERN_DEBUG
+ " 0x08: MIC = 0x%02x ", snd_sonicvibes_in(sonic, 0x08));
printk(" 0x28: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x28));
- printk(" 0x09: Game port = 0x%02x ", snd_sonicvibes_in(sonic, 0x09));
+ printk(KERN_DEBUG
+ " 0x09: Game port = 0x%02x ", snd_sonicvibes_in(sonic, 0x09));
printk(" 0x29: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x29));
- printk(" 0x0a: left synth = 0x%02x ", snd_sonicvibes_in(sonic, 0x0a));
+ printk(KERN_DEBUG
+ " 0x0a: left synth = 0x%02x ", snd_sonicvibes_in(sonic, 0x0a));
printk(" 0x2a: MPU401 = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2a));
- printk(" 0x0b: right synth = 0x%02x ", snd_sonicvibes_in(sonic, 0x0b));
+ printk(KERN_DEBUG
+ " 0x0b: right synth = 0x%02x ", snd_sonicvibes_in(sonic, 0x0b));
printk(" 0x2b: drive ctrl = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2b));
- printk(" 0x0c: left AUX2 = 0x%02x ", snd_sonicvibes_in(sonic, 0x0c));
+ printk(KERN_DEBUG
+ " 0x0c: left AUX2 = 0x%02x ", snd_sonicvibes_in(sonic, 0x0c));
printk(" 0x2c: SRS space = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2c));
- printk(" 0x0d: right AUX2 = 0x%02x ", snd_sonicvibes_in(sonic, 0x0d));
+ printk(KERN_DEBUG
+ " 0x0d: right AUX2 = 0x%02x ", snd_sonicvibes_in(sonic, 0x0d));
printk(" 0x2d: SRS center = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2d));
- printk(" 0x0e: left analog = 0x%02x ", snd_sonicvibes_in(sonic, 0x0e));
+ printk(KERN_DEBUG
+ " 0x0e: left analog = 0x%02x ", snd_sonicvibes_in(sonic, 0x0e));
printk(" 0x2e: wave source = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2e));
- printk(" 0x0f: right analog = 0x%02x ", snd_sonicvibes_in(sonic, 0x0f));
+ printk(KERN_DEBUG
+ " 0x0f: right analog = 0x%02x ", snd_sonicvibes_in(sonic, 0x0f));
printk(" 0x2f: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2f));
- printk(" 0x10: left PCM = 0x%02x ", snd_sonicvibes_in(sonic, 0x10));
+ printk(KERN_DEBUG
+ " 0x10: left PCM = 0x%02x ", snd_sonicvibes_in(sonic, 0x10));
printk(" 0x30: analog power = 0x%02x\n", snd_sonicvibes_in(sonic, 0x30));
- printk(" 0x11: right PCM = 0x%02x ", snd_sonicvibes_in(sonic, 0x11));
+ printk(KERN_DEBUG
+ " 0x11: right PCM = 0x%02x ", snd_sonicvibes_in(sonic, 0x11));
printk(" 0x31: analog power = 0x%02x\n", snd_sonicvibes_in(sonic, 0x31));
- printk(" 0x12: DMA data format = 0x%02x ", snd_sonicvibes_in(sonic, 0x12));
+ printk(KERN_DEBUG
+ " 0x12: DMA data format = 0x%02x ", snd_sonicvibes_in(sonic, 0x12));
printk(" 0x32: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x32));
- printk(" 0x13: P/C enable = 0x%02x ", snd_sonicvibes_in(sonic, 0x13));
+ printk(KERN_DEBUG
+ " 0x13: P/C enable = 0x%02x ", snd_sonicvibes_in(sonic, 0x13));
printk(" 0x33: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x33));
- printk(" 0x14: U/D button = 0x%02x ", snd_sonicvibes_in(sonic, 0x14));
+ printk(KERN_DEBUG
+ " 0x14: U/D button = 0x%02x ", snd_sonicvibes_in(sonic, 0x14));
printk(" 0x34: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x34));
- printk(" 0x15: revision = 0x%02x ", snd_sonicvibes_in(sonic, 0x15));
+ printk(KERN_DEBUG
+ " 0x15: revision = 0x%02x ", snd_sonicvibes_in(sonic, 0x15));
printk(" 0x35: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x35));
- printk(" 0x16: ADC output ctrl = 0x%02x ", snd_sonicvibes_in(sonic, 0x16));
+ printk(KERN_DEBUG
+ " 0x16: ADC output ctrl = 0x%02x ", snd_sonicvibes_in(sonic, 0x16));
printk(" 0x36: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x36));
- printk(" 0x17: --- = 0x%02x ", snd_sonicvibes_in(sonic, 0x17));
+ printk(KERN_DEBUG
+ " 0x17: --- = 0x%02x ", snd_sonicvibes_in(sonic, 0x17));
printk(" 0x37: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x37));
- printk(" 0x18: DMA A upper cnt = 0x%02x ", snd_sonicvibes_in(sonic, 0x18));
+ printk(KERN_DEBUG
+ " 0x18: DMA A upper cnt = 0x%02x ", snd_sonicvibes_in(sonic, 0x18));
printk(" 0x38: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x38));
- printk(" 0x19: DMA A lower cnt = 0x%02x ", snd_sonicvibes_in(sonic, 0x19));
+ printk(KERN_DEBUG
+ " 0x19: DMA A lower cnt = 0x%02x ", snd_sonicvibes_in(sonic, 0x19));
printk(" 0x39: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x39));
- printk(" 0x1a: --- = 0x%02x ", snd_sonicvibes_in(sonic, 0x1a));
+ printk(KERN_DEBUG
+ " 0x1a: --- = 0x%02x ", snd_sonicvibes_in(sonic, 0x1a));
printk(" 0x3a: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3a));
- printk(" 0x1b: --- = 0x%02x ", snd_sonicvibes_in(sonic, 0x1b));
+ printk(KERN_DEBUG
+ " 0x1b: --- = 0x%02x ", snd_sonicvibes_in(sonic, 0x1b));
printk(" 0x3b: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3b));
- printk(" 0x1c: DMA C upper cnt = 0x%02x ", snd_sonicvibes_in(sonic, 0x1c));
+ printk(KERN_DEBUG
+ " 0x1c: DMA C upper cnt = 0x%02x ", snd_sonicvibes_in(sonic, 0x1c));
printk(" 0x3c: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3c));
- printk(" 0x1d: DMA C upper cnt = 0x%02x ", snd_sonicvibes_in(sonic, 0x1d));
+ printk(KERN_DEBUG
+ " 0x1d: DMA C upper cnt = 0x%02x ", snd_sonicvibes_in(sonic, 0x1d));
printk(" 0x3d: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3d));
- printk(" 0x1e: PCM rate low = 0x%02x ", snd_sonicvibes_in(sonic, 0x1e));
+ printk(KERN_DEBUG
+ " 0x1e: PCM rate low = 0x%02x ", snd_sonicvibes_in(sonic, 0x1e));
printk(" 0x3e: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3e));
- printk(" 0x1f: PCM rate high = 0x%02x ", snd_sonicvibes_in(sonic, 0x1f));
+ printk(KERN_DEBUG
+ " 0x1f: PCM rate high = 0x%02x ", snd_sonicvibes_in(sonic, 0x1f));
printk(" 0x3f: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3f));
}
@@ -476,8 +511,8 @@ static void snd_sonicvibes_pll(unsigned int rate,
*res_m = m;
*res_n = n;
#if 0
- printk("metric = %i, xm = %i, xn = %i\n", metric, xm, xn);
- printk("pll: m = 0x%x, r = 0x%x, n = 0x%x\n", reg, m, r, n);
+ printk(KERN_DEBUG "metric = %i, xm = %i, xn = %i\n", metric, xm, xn);
+ printk(KERN_DEBUG "pll: m = 0x%x, r = 0x%x, n = 0x%x\n", reg, m, r, n);
#endif
}
@@ -1423,9 +1458,9 @@ static int __devinit snd_sonic_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
for (idx = 0; idx < 5; idx++) {
if (pci_resource_start(pci, idx) == 0 ||
!(pci_resource_flags(pci, idx) & IORESOURCE_IO)) {
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c
index d94b16ffb38..21cef97d478 100644
--- a/sound/pci/trident/trident.c
+++ b/sound/pci/trident/trident.c
@@ -89,9 +89,9 @@ static int __devinit snd_trident_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
if ((err = snd_trident_create(card, pci,
pcm_channels[dev],
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index c612b435ca2..a9da9c18466 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -68,40 +68,40 @@ static void snd_trident_print_voice_regs(struct snd_trident *trident, int voice)
{
unsigned int val, tmp;
- printk("Trident voice %i:\n", voice);
+ printk(KERN_DEBUG "Trident voice %i:\n", voice);
outb(voice, TRID_REG(trident, T4D_LFO_GC_CIR));
val = inl(TRID_REG(trident, CH_LBA));
- printk("LBA: 0x%x\n", val);
+ printk(KERN_DEBUG "LBA: 0x%x\n", val);
val = inl(TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC));
- printk("GVSel: %i\n", val >> 31);
- printk("Pan: 0x%x\n", (val >> 24) & 0x7f);
- printk("Vol: 0x%x\n", (val >> 16) & 0xff);
- printk("CTRL: 0x%x\n", (val >> 12) & 0x0f);
- printk("EC: 0x%x\n", val & 0x0fff);
+ printk(KERN_DEBUG "GVSel: %i\n", val >> 31);
+ printk(KERN_DEBUG "Pan: 0x%x\n", (val >> 24) & 0x7f);
+ printk(KERN_DEBUG "Vol: 0x%x\n", (val >> 16) & 0xff);
+ printk(KERN_DEBUG "CTRL: 0x%x\n", (val >> 12) & 0x0f);
+ printk(KERN_DEBUG "EC: 0x%x\n", val & 0x0fff);
if (trident->device != TRIDENT_DEVICE_ID_NX) {
val = inl(TRID_REG(trident, CH_DX_CSO_ALPHA_FMS));
- printk("CSO: 0x%x\n", val >> 16);
+ printk(KERN_DEBUG "CSO: 0x%x\n", val >> 16);
printk("Alpha: 0x%x\n", (val >> 4) & 0x0fff);
- printk("FMS: 0x%x\n", val & 0x0f);
+ printk(KERN_DEBUG "FMS: 0x%x\n", val & 0x0f);
val = inl(TRID_REG(trident, CH_DX_ESO_DELTA));
- printk("ESO: 0x%x\n", val >> 16);
- printk("Delta: 0x%x\n", val & 0xffff);
+ printk(KERN_DEBUG "ESO: 0x%x\n", val >> 16);
+ printk(KERN_DEBUG "Delta: 0x%x\n", val & 0xffff);
val = inl(TRID_REG(trident, CH_DX_FMC_RVOL_CVOL));
} else { // TRIDENT_DEVICE_ID_NX
val = inl(TRID_REG(trident, CH_NX_DELTA_CSO));
tmp = (val >> 24) & 0xff;
- printk("CSO: 0x%x\n", val & 0x00ffffff);
+ printk(KERN_DEBUG "CSO: 0x%x\n", val & 0x00ffffff);
val = inl(TRID_REG(trident, CH_NX_DELTA_ESO));
tmp |= (val >> 16) & 0xff00;
- printk("Delta: 0x%x\n", tmp);
- printk("ESO: 0x%x\n", val & 0x00ffffff);
+ printk(KERN_DEBUG "Delta: 0x%x\n", tmp);
+ printk(KERN_DEBUG "ESO: 0x%x\n", val & 0x00ffffff);
val = inl(TRID_REG(trident, CH_NX_ALPHA_FMS_FMC_RVOL_CVOL));
- printk("Alpha: 0x%x\n", val >> 20);
- printk("FMS: 0x%x\n", (val >> 16) & 0x0f);
+ printk(KERN_DEBUG "Alpha: 0x%x\n", val >> 20);
+ printk(KERN_DEBUG "FMS: 0x%x\n", (val >> 16) & 0x0f);
}
- printk("FMC: 0x%x\n", (val >> 14) & 3);
- printk("RVol: 0x%x\n", (val >> 7) & 0x7f);
- printk("CVol: 0x%x\n", val & 0x7f);
+ printk(KERN_DEBUG "FMC: 0x%x\n", (val >> 14) & 3);
+ printk(KERN_DEBUG "RVol: 0x%x\n", (val >> 7) & 0x7f);
+ printk(KERN_DEBUG "CVol: 0x%x\n", val & 0x7f);
}
#endif
@@ -496,12 +496,17 @@ void snd_trident_write_voice_regs(struct snd_trident * trident,
outl(regs[4], TRID_REG(trident, CH_START + 16));
#if 0
- printk("written %i channel:\n", voice->number);
- printk(" regs[0] = 0x%x/0x%x\n", regs[0], inl(TRID_REG(trident, CH_START + 0)));
- printk(" regs[1] = 0x%x/0x%x\n", regs[1], inl(TRID_REG(trident, CH_START + 4)));
- printk(" regs[2] = 0x%x/0x%x\n", regs[2], inl(TRID_REG(trident, CH_START + 8)));
- printk(" regs[3] = 0x%x/0x%x\n", regs[3], inl(TRID_REG(trident, CH_START + 12)));
- printk(" regs[4] = 0x%x/0x%x\n", regs[4], inl(TRID_REG(trident, CH_START + 16)));
+ printk(KERN_DEBUG "written %i channel:\n", voice->number);
+ printk(KERN_DEBUG " regs[0] = 0x%x/0x%x\n",
+ regs[0], inl(TRID_REG(trident, CH_START + 0)));
+ printk(KERN_DEBUG " regs[1] = 0x%x/0x%x\n",
+ regs[1], inl(TRID_REG(trident, CH_START + 4)));
+ printk(KERN_DEBUG " regs[2] = 0x%x/0x%x\n",
+ regs[2], inl(TRID_REG(trident, CH_START + 8)));
+ printk(KERN_DEBUG " regs[3] = 0x%x/0x%x\n",
+ regs[3], inl(TRID_REG(trident, CH_START + 12)));
+ printk(KERN_DEBUG " regs[4] = 0x%x/0x%x\n",
+ regs[4], inl(TRID_REG(trident, CH_START + 16)));
#endif
}
@@ -583,7 +588,7 @@ static void snd_trident_write_vol_reg(struct snd_trident * trident,
outb(voice->Vol >> 2, TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC + 2));
break;
case TRIDENT_DEVICE_ID_SI7018:
- // printk("voice->Vol = 0x%x\n", voice->Vol);
+ /* printk(KERN_DEBUG "voice->Vol = 0x%x\n", voice->Vol); */
outw((voice->CTRL << 12) | voice->Vol,
TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC));
break;
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 1aafe956ee2..809b233dd4a 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -466,7 +466,10 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre
flag = VIA_TBL_BIT_FLAG; /* period boundary */
} else
flag = 0; /* period continues to the next */
- // printk("via: tbl %d: at %d size %d (rest %d)\n", idx, ofs, r, rest);
+ /*
+ printk(KERN_DEBUG "via: tbl %d: at %d size %d "
+ "(rest %d)\n", idx, ofs, r, rest);
+ */
((u32 *)dev->table.area)[(idx<<1) + 1] = cpu_to_le32(r | flag);
dev->idx_table[idx].offset = ofs;
dev->idx_table[idx].size = r;
@@ -2360,14 +2363,14 @@ static struct snd_pci_quirk dxs_whitelist[] __devinitdata = {
SND_PCI_QUIRK(0x1019, 0x0996, "ESC Mobo", VIA_DXS_48K),
SND_PCI_QUIRK(0x1019, 0x0a81, "ECS K7VTA3 v8.0", VIA_DXS_NO_VRA),
SND_PCI_QUIRK(0x1019, 0x0a85, "ECS L7VMM2", VIA_DXS_NO_VRA),
- SND_PCI_QUIRK(0x1019, 0, "ESC K8", VIA_DXS_SRC),
+ SND_PCI_QUIRK_VENDOR(0x1019, "ESC K8", VIA_DXS_SRC),
SND_PCI_QUIRK(0x1019, 0xaa01, "ESC K8T890-A", VIA_DXS_SRC),
SND_PCI_QUIRK(0x1025, 0x0033, "Acer Inspire 1353LM", VIA_DXS_NO_VRA),
SND_PCI_QUIRK(0x1025, 0x0046, "Acer Aspire 1524 WLMi", VIA_DXS_SRC),
- SND_PCI_QUIRK(0x1043, 0, "ASUS A7/A8", VIA_DXS_NO_VRA),
- SND_PCI_QUIRK(0x1071, 0, "Diverse Notebook", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK_VENDOR(0x1043, "ASUS A7/A8", VIA_DXS_NO_VRA),
+ SND_PCI_QUIRK_VENDOR(0x1071, "Diverse Notebook", VIA_DXS_NO_VRA),
SND_PCI_QUIRK(0x10cf, 0x118e, "FSC Laptop", VIA_DXS_ENABLE),
- SND_PCI_QUIRK(0x1106, 0, "ASRock", VIA_DXS_SRC),
+ SND_PCI_QUIRK_VENDOR(0x1106, "ASRock", VIA_DXS_SRC),
SND_PCI_QUIRK(0x1297, 0xa231, "Shuttle AK31v2", VIA_DXS_SRC),
SND_PCI_QUIRK(0x1297, 0xa232, "Shuttle", VIA_DXS_SRC),
SND_PCI_QUIRK(0x1297, 0xc160, "Shuttle Sk41G", VIA_DXS_SRC),
@@ -2375,7 +2378,7 @@ static struct snd_pci_quirk dxs_whitelist[] __devinitdata = {
SND_PCI_QUIRK(0x1462, 0x3800, "MSI KT266", VIA_DXS_ENABLE),
SND_PCI_QUIRK(0x1462, 0x7120, "MSI KT4V", VIA_DXS_ENABLE),
SND_PCI_QUIRK(0x1462, 0x7142, "MSI K8MM-V", VIA_DXS_ENABLE),
- SND_PCI_QUIRK(0x1462, 0, "MSI Mobo", VIA_DXS_SRC),
+ SND_PCI_QUIRK_VENDOR(0x1462, "MSI Mobo", VIA_DXS_SRC),
SND_PCI_QUIRK(0x147b, 0x1401, "ABIT KD7(-RAID)", VIA_DXS_ENABLE),
SND_PCI_QUIRK(0x147b, 0x1411, "ABIT VA-20", VIA_DXS_ENABLE),
SND_PCI_QUIRK(0x147b, 0x1413, "ABIT KV8 Pro", VIA_DXS_ENABLE),
@@ -2389,11 +2392,11 @@ static struct snd_pci_quirk dxs_whitelist[] __devinitdata = {
SND_PCI_QUIRK(0x161f, 0x2032, "m680x machines", VIA_DXS_48K),
SND_PCI_QUIRK(0x1631, 0xe004, "PB EasyNote 3174", VIA_DXS_ENABLE),
SND_PCI_QUIRK(0x1695, 0x3005, "EPoX EP-8K9A", VIA_DXS_ENABLE),
- SND_PCI_QUIRK(0x1695, 0, "EPoX mobo", VIA_DXS_SRC),
- SND_PCI_QUIRK(0x16f3, 0, "Jetway K8", VIA_DXS_SRC),
- SND_PCI_QUIRK(0x1734, 0, "FSC Laptop", VIA_DXS_SRC),
+ SND_PCI_QUIRK_VENDOR(0x1695, "EPoX mobo", VIA_DXS_SRC),
+ SND_PCI_QUIRK_VENDOR(0x16f3, "Jetway K8", VIA_DXS_SRC),
+ SND_PCI_QUIRK_VENDOR(0x1734, "FSC Laptop", VIA_DXS_SRC),
SND_PCI_QUIRK(0x1849, 0x3059, "ASRock K7VM2", VIA_DXS_NO_VRA),
- SND_PCI_QUIRK(0x1849, 0, "ASRock mobo", VIA_DXS_SRC),
+ SND_PCI_QUIRK_VENDOR(0x1849, "ASRock mobo", VIA_DXS_SRC),
SND_PCI_QUIRK(0x1919, 0x200a, "Soltek SL-K8", VIA_DXS_NO_VRA),
SND_PCI_QUIRK(0x4005, 0x4710, "MSI K7T266", VIA_DXS_SRC),
{ } /* terminator */
@@ -2433,9 +2436,9 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci,
unsigned int i;
int err;
- card = snd_card_new(index, id, THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
card_type = pci_id->driver_data;
switch (card_type) {
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index 5bd79d2a5a1..0d54e3503c1 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -328,7 +328,10 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre
flag = VIA_TBL_BIT_FLAG; /* period boundary */
} else
flag = 0; /* period continues to the next */
- // printk("via: tbl %d: at %d size %d (rest %d)\n", idx, ofs, r, rest);
+ /*
+ printk(KERN_DEBUG "via: tbl %d: at %d size %d "
+ "(rest %d)\n", idx, ofs, r, rest);
+ */
((u32 *)dev->table.area)[(idx<<1) + 1] = cpu_to_le32(r | flag);
dev->idx_table[idx].offset = ofs;
dev->idx_table[idx].size = r;
@@ -1167,9 +1170,9 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci,
unsigned int i;
int err;
- card = snd_card_new(index, id, THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
card_type = pci_id->driver_data;
switch (card_type) {
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c
index acc352f4a44..fc9136c3e0d 100644
--- a/sound/pci/vx222/vx222.c
+++ b/sound/pci/vx222/vx222.c
@@ -204,9 +204,9 @@ static int __devinit snd_vx222_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
switch ((int)pci_id->driver_data) {
case VX_PCI_VX222_OLD:
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
index 7e87f398ff0..c0efe449111 100644
--- a/sound/pci/vx222/vx222_ops.c
+++ b/sound/pci/vx222/vx222_ops.c
@@ -107,7 +107,9 @@ static unsigned char vx2_inb(struct vx_core *chip, int offset)
static void vx2_outb(struct vx_core *chip, int offset, unsigned char val)
{
outb(val, vx2_reg_addr(chip, offset));
- //printk("outb: %x -> %x\n", val, vx2_reg_addr(chip, offset));
+ /*
+ printk(KERN_DEBUG "outb: %x -> %x\n", val, vx2_reg_addr(chip, offset));
+ */
}
/**
@@ -126,7 +128,9 @@ static unsigned int vx2_inl(struct vx_core *chip, int offset)
*/
static void vx2_outl(struct vx_core *chip, int offset, unsigned int val)
{
- // printk("outl: %x -> %x\n", val, vx2_reg_addr(chip, offset));
+ /*
+ printk(KERN_DEBUG "outl: %x -> %x\n", val, vx2_reg_addr(chip, offset));
+ */
outl(val, vx2_reg_addr(chip, offset));
}
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
index 2631a554845..4af66661f9b 100644
--- a/sound/pci/ymfpci/ymfpci.c
+++ b/sound/pci/ymfpci/ymfpci.c
@@ -187,9 +187,9 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci,
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
switch (pci_id->device) {
case 0x0004: str = "YMF724"; model = "DS-1"; break;
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index 90d0d62bd0b..2f0925236a1 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -318,7 +318,12 @@ static void snd_ymfpci_pcm_interrupt(struct snd_ymfpci *chip, struct snd_ymfpci_
ypcm->period_pos += delta;
ypcm->last_pos = pos;
if (ypcm->period_pos >= ypcm->period_size) {
- // printk("done - active_bank = 0x%x, start = 0x%x\n", chip->active_bank, voice->bank[chip->active_bank].start);
+ /*
+ printk(KERN_DEBUG
+ "done - active_bank = 0x%x, start = 0x%x\n",
+ chip->active_bank,
+ voice->bank[chip->active_bank].start);
+ */
ypcm->period_pos %= ypcm->period_size;
spin_unlock(&chip->reg_lock);
snd_pcm_period_elapsed(ypcm->substream);
@@ -366,7 +371,12 @@ static void snd_ymfpci_pcm_capture_interrupt(struct snd_pcm_substream *substream
ypcm->last_pos = pos;
if (ypcm->period_pos >= ypcm->period_size) {
ypcm->period_pos %= ypcm->period_size;
- // printk("done - active_bank = 0x%x, start = 0x%x\n", chip->active_bank, voice->bank[chip->active_bank].start);
+ /*
+ printk(KERN_DEBUG
+ "done - active_bank = 0x%x, start = 0x%x\n",
+ chip->active_bank,
+ voice->bank[chip->active_bank].start);
+ */
spin_unlock(&chip->reg_lock);
snd_pcm_period_elapsed(substream);
spin_lock(&chip->reg_lock);
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c
index 819aaaac432..7dea74b71cf 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c
@@ -91,7 +91,7 @@ static int snd_pdacf_dev_free(struct snd_device *device)
*/
static int snd_pdacf_probe(struct pcmcia_device *link)
{
- int i;
+ int i, err;
struct snd_pdacf *pdacf;
struct snd_card *card;
static struct snd_device_ops ops = {
@@ -112,20 +112,23 @@ static int snd_pdacf_probe(struct pcmcia_device *link)
return -ENODEV; /* disabled explicitly */
/* ok, create a card instance */
- card = snd_card_new(index[i], id[i], THIS_MODULE, 0);
- if (card == NULL) {
+ err = snd_card_create(index[i], id[i], THIS_MODULE, 0, &card);
+ if (err < 0) {
snd_printk(KERN_ERR "pdacf: cannot create a card instance\n");
- return -ENOMEM;
+ return err;
}
pdacf = snd_pdacf_create(card);
- if (! pdacf)
- return -EIO;
+ if (!pdacf) {
+ snd_card_free(card);
+ return -ENOMEM;
+ }
- if (snd_device_new(card, SNDRV_DEV_LOWLEVEL, pdacf, &ops) < 0) {
+ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, pdacf, &ops);
+ if (err < 0) {
kfree(pdacf);
snd_card_free(card);
- return -ENODEV;
+ return err;
}
snd_card_set_dev(card, &handle_to_dev(link));
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
index dfa40b0ed86..5d2afa0b0ce 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
@@ -82,14 +82,21 @@ static void pdacf_ak4117_write(void *private_data, unsigned char reg, unsigned c
#if 0
void pdacf_dump(struct snd_pdacf *chip)
{
- printk("PDAUDIOCF DUMP (0x%lx):\n", chip->port);
- printk("WPD : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_WDP));
- printk("RDP : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_RDP));
- printk("TCR : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_TCR));
- printk("SCR : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_SCR));
- printk("ISR : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_ISR));
- printk("IER : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_IER));
- printk("AK_IFR : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_AK_IFR));
+ printk(KERN_DEBUG "PDAUDIOCF DUMP (0x%lx):\n", chip->port);
+ printk(KERN_DEBUG "WPD : 0x%x\n",
+ inw(chip->port + PDAUDIOCF_REG_WDP));
+ printk(KERN_DEBUG "RDP : 0x%x\n",
+ inw(chip->port + PDAUDIOCF_REG_RDP));
+ printk(KERN_DEBUG "TCR : 0x%x\n",
+ inw(chip->port + PDAUDIOCF_REG_TCR));
+ printk(KERN_DEBUG "SCR : 0x%x\n",
+ inw(chip->port + PDAUDIOCF_REG_SCR));
+ printk(KERN_DEBUG "ISR : 0x%x\n",
+ inw(chip->port + PDAUDIOCF_REG_ISR));
+ printk(KERN_DEBUG "IER : 0x%x\n",
+ inw(chip->port + PDAUDIOCF_REG_IER));
+ printk(KERN_DEBUG "AK_IFR : 0x%x\n",
+ inw(chip->port + PDAUDIOCF_REG_AK_IFR));
}
#endif
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
index ea903c8e90d..dcd32201bc8 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
@@ -269,7 +269,7 @@ void pdacf_tasklet(unsigned long private_data)
rdp = inw(chip->port + PDAUDIOCF_REG_RDP);
wdp = inw(chip->port + PDAUDIOCF_REG_WDP);
- // printk("TASKLET: rdp = %x, wdp = %x\n", rdp, wdp);
+ /* printk(KERN_DEBUG "TASKLET: rdp = %x, wdp = %x\n", rdp, wdp); */
size = wdp - rdp;
if (size < 0)
size += 0x10000;
@@ -321,5 +321,5 @@ void pdacf_tasklet(unsigned long private_data)
spin_lock(&chip->reg_lock);
}
spin_unlock(&chip->reg_lock);
- // printk("TASKLET: end\n");
+ /* printk(KERN_DEBUG "TASKLET: end\n"); */
}
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c
index 706602a4060..7445cc8a47d 100644
--- a/sound/pcmcia/vx/vxpocket.c
+++ b/sound/pcmcia/vx/vxpocket.c
@@ -130,23 +130,26 @@ static struct snd_vx_hardware vxp440_hw = {
/*
* create vxpocket instance
*/
-static struct snd_vxpocket *snd_vxpocket_new(struct snd_card *card, int ibl,
- struct pcmcia_device *link)
+static int snd_vxpocket_new(struct snd_card *card, int ibl,
+ struct pcmcia_device *link,
+ struct snd_vxpocket **chip_ret)
{
struct vx_core *chip;
struct snd_vxpocket *vxp;
static struct snd_device_ops ops = {
.dev_free = snd_vxpocket_dev_free,
};
+ int err;
chip = snd_vx_create(card, &vxpocket_hw, &snd_vxpocket_ops,
sizeof(struct snd_vxpocket) - sizeof(struct vx_core));
- if (! chip)
- return NULL;
+ if (!chip)
+ return -ENOMEM;
- if (snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops) < 0) {
+ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+ if (err < 0) {
kfree(chip);
- return NULL;
+ return err;
}
chip->ibl.size = ibl;
@@ -169,7 +172,8 @@ static struct snd_vxpocket *snd_vxpocket_new(struct snd_card *card, int ibl,
link->conf.ConfigIndex = 1;
link->conf.Present = PRESENT_OPTION;
- return vxp;
+ *chip_ret = vxp;
+ return 0;
}
@@ -292,7 +296,7 @@ static int vxpocket_probe(struct pcmcia_device *p_dev)
{
struct snd_card *card;
struct snd_vxpocket *vxp;
- int i;
+ int i, err;
/* find an empty slot from the card list */
for (i = 0; i < SNDRV_CARDS; i++) {
@@ -307,16 +311,16 @@ static int vxpocket_probe(struct pcmcia_device *p_dev)
return -ENODEV; /* disabled explicitly */
/* ok, create a card instance */
- card = snd_card_new(index[i], id[i], THIS_MODULE, 0);
- if (card == NULL) {
+ err = snd_card_create(index[i], id[i], THIS_MODULE, 0, &card);
+ if (err < 0) {
snd_printk(KERN_ERR "vxpocket: cannot create a card instance\n");
- return -ENOMEM;
+ return err;
}
- vxp = snd_vxpocket_new(card, ibl[i], p_dev);
- if (! vxp) {
+ err = snd_vxpocket_new(card, ibl[i], p_dev, &vxp);
+ if (err < 0) {
snd_card_free(card);
- return -ENODEV;
+ return err;
}
card->private_data = vxp;
diff --git a/sound/ppc/powermac.c b/sound/ppc/powermac.c
index c936225771b..2e18ed0ea89 100644
--- a/sound/ppc/powermac.c
+++ b/sound/ppc/powermac.c
@@ -58,9 +58,9 @@ static int __init snd_pmac_probe(struct platform_device *devptr)
char *name_ext;
int err;
- card = snd_card_new(index, id, THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
if ((err = snd_pmac_new(card, &chip)) < 0)
goto __error;
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c
index ff321110ec0..f361c26506a 100644
--- a/sound/ppc/snd_ps3.c
+++ b/sound/ppc/snd_ps3.c
@@ -969,11 +969,9 @@ static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
}
/* create card instance */
- the_card.card = snd_card_new(index, id, THIS_MODULE, 0);
- if (!the_card.card) {
- ret = -ENXIO;
+ ret = snd_card_create(index, id, THIS_MODULE, 0, &the_card.card);
+ if (ret < 0)
goto clean_irq;
- }
strcpy(the_card.card->driver, "PS3");
strcpy(the_card.card->shortname, "PS3");
diff --git a/sound/sh/aica.c b/sound/sh/aica.c
index 7c920f3e7fe..f551233c5a0 100644
--- a/sound/sh/aica.c
+++ b/sound/sh/aica.c
@@ -609,11 +609,11 @@ static int __devinit snd_aica_probe(struct platform_device *devptr)
dreamcastcard = kmalloc(sizeof(struct snd_card_aica), GFP_KERNEL);
if (unlikely(!dreamcastcard))
return -ENOMEM;
- dreamcastcard->card =
- snd_card_new(index, SND_AICA_DRIVER, THIS_MODULE, 0);
- if (unlikely(!dreamcastcard->card)) {
+ err = snd_card_create(index, SND_AICA_DRIVER, THIS_MODULE, 0,
+ &dreamcastcard->card);
+ if (unlikely(err < 0)) {
kfree(dreamcastcard);
- return -ENODEV;
+ return err;
}
strcpy(dreamcastcard->card->driver, "snd_aica");
strcpy(dreamcastcard->card->shortname, SND_AICA_DRIVER);
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index ef025c66cc6..3d2bb6fc6dc 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -6,6 +6,7 @@ menuconfig SND_SOC
tristate "ALSA for SoC audio support"
select SND_PCM
select AC97_BUS if SND_SOC_AC97_BUS
+ select SND_JACK if INPUT=y || INPUT=SND
---help---
If you want ASoC support, you should say Y here and also to the
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 86a9b1f5b0f..0237879fd41 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -1,4 +1,4 @@
-snd-soc-core-objs := soc-core.o soc-dapm.o
+snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o
obj-$(CONFIG_SND_SOC) += snd-soc-core.o
obj-$(CONFIG_SND_SOC) += codecs/
diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c
index 3dcdc4e3cfa..9ef6b96373f 100644
--- a/sound/soc/atmel/atmel-pcm.c
+++ b/sound/soc/atmel/atmel-pcm.c
@@ -347,7 +347,7 @@ static int atmel_pcm_mmap(struct snd_pcm_substream *substream,
vma->vm_end - vma->vm_start, vma->vm_page_prot);
}
-struct snd_pcm_ops atmel_pcm_ops = {
+static struct snd_pcm_ops atmel_pcm_ops = {
.open = atmel_pcm_open,
.close = atmel_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index c5d67900d66..e588e63f18d 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -10,7 +10,7 @@
* Based on at91-ssc.c by
* Frank Mandarino <fmandarino@endrelia.com>
* Based on pxa2xx Platform drivers by
- * Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -697,6 +697,15 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
#define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+static struct snd_soc_dai_ops atmel_ssc_dai_ops = {
+ .startup = atmel_ssc_startup,
+ .shutdown = atmel_ssc_shutdown,
+ .prepare = atmel_ssc_prepare,
+ .hw_params = atmel_ssc_hw_params,
+ .set_fmt = atmel_ssc_set_dai_fmt,
+ .set_clkdiv = atmel_ssc_set_dai_clkdiv,
+};
+
struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
{ .name = "atmel-ssc0",
.id = 0,
@@ -712,13 +721,7 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
.channels_max = 2,
.rates = ATMEL_SSC_RATES,
.formats = ATMEL_SSC_FORMATS,},
- .ops = {
- .startup = atmel_ssc_startup,
- .shutdown = atmel_ssc_shutdown,
- .prepare = atmel_ssc_prepare,
- .hw_params = atmel_ssc_hw_params,
- .set_fmt = atmel_ssc_set_dai_fmt,
- .set_clkdiv = atmel_ssc_set_dai_clkdiv,},
+ .ops = &atmel_ssc_dai_ops,
.private_data = &ssc_info[0],
},
#if NUM_SSC_DEVICES == 3
@@ -736,13 +739,7 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
.channels_max = 2,
.rates = ATMEL_SSC_RATES,
.formats = ATMEL_SSC_FORMATS,},
- .ops = {
- .startup = atmel_ssc_startup,
- .shutdown = atmel_ssc_shutdown,
- .prepare = atmel_ssc_prepare,
- .hw_params = atmel_ssc_hw_params,
- .set_fmt = atmel_ssc_set_dai_fmt,
- .set_clkdiv = atmel_ssc_set_dai_clkdiv,},
+ .ops = &atmel_ssc_dai_ops,
.private_data = &ssc_info[1],
},
{ .name = "atmel-ssc2",
@@ -759,13 +756,7 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
.channels_max = 2,
.rates = ATMEL_SSC_RATES,
.formats = ATMEL_SSC_FORMATS,},
- .ops = {
- .startup = atmel_ssc_startup,
- .shutdown = atmel_ssc_shutdown,
- .prepare = atmel_ssc_prepare,
- .hw_params = atmel_ssc_hw_params,
- .set_fmt = atmel_ssc_set_dai_fmt,
- .set_clkdiv = atmel_ssc_set_dai_clkdiv,},
+ .ops = &atmel_ssc_dai_ops,
.private_data = &ssc_info[2],
},
#endif
diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h
index a828746e8a2..391135f9c6c 100644
--- a/sound/soc/atmel/atmel_ssc_dai.h
+++ b/sound/soc/atmel/atmel_ssc_dai.h
@@ -10,7 +10,7 @@
* Based on at91-ssc.c by
* Frank Mandarino <fmandarino@endrelia.com>
* Based on pxa2xx Platform drivers by
- * Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Liam Girdwood <lrg@slimlogic.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c
index 43dd8cee83c..70657534e6b 100644
--- a/sound/soc/atmel/playpaq_wm8510.c
+++ b/sound/soc/atmel/playpaq_wm8510.c
@@ -164,38 +164,38 @@ static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream,
*/
switch (params_rate(params)) {
case 48000:
- pll_out = 12288000;
- mclk_div = WM8510_MCLKDIV_1;
+ pll_out = 24576000;
+ mclk_div = WM8510_MCLKDIV_2;
bclk = WM8510_BCLKDIV_8;
break;
case 44100:
- pll_out = 11289600;
- mclk_div = WM8510_MCLKDIV_1;
+ pll_out = 22579200;
+ mclk_div = WM8510_MCLKDIV_2;
bclk = WM8510_BCLKDIV_8;
break;
case 22050:
- pll_out = 11289600;
- mclk_div = WM8510_MCLKDIV_2;
+ pll_out = 22579200;
+ mclk_div = WM8510_MCLKDIV_4;
bclk = WM8510_BCLKDIV_8;
break;
case 16000:
- pll_out = 12288000;
- mclk_div = WM8510_MCLKDIV_3;
+ pll_out = 24576000;
+ mclk_div = WM8510_MCLKDIV_6;
bclk = WM8510_BCLKDIV_8;
break;
case 11025:
- pll_out = 11289600;
- mclk_div = WM8510_MCLKDIV_4;
+ pll_out = 22579200;
+ mclk_div = WM8510_MCLKDIV_8;
bclk = WM8510_BCLKDIV_8;
break;
case 8000:
- pll_out = 12288000;
- mclk_div = WM8510_MCLKDIV_6;
+ pll_out = 24576000;
+ mclk_div = WM8510_MCLKDIV_12;
bclk = WM8510_BCLKDIV_8;
break;
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
index 6ea04be911d..173a239a541 100644
--- a/sound/soc/atmel/sam9g20_wm8731.c
+++ b/sound/soc/atmel/sam9g20_wm8731.c
@@ -36,6 +36,7 @@
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
+#include <linux/i2c.h>
#include <linux/atmel-ssc.h>
@@ -45,6 +46,7 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
+#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
@@ -52,6 +54,9 @@
#include "atmel-pcm.h"
#include "atmel_ssc_dai.h"
+#define MCLK_RATE 12000000
+
+static struct clk *mclk;
static int at91sam9g20ek_startup(struct snd_pcm_substream *substream)
{
@@ -59,11 +64,12 @@ static int at91sam9g20ek_startup(struct snd_pcm_substream *substream)
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
int ret;
- /* codec system clock is supplied by PCK0, set to 12MHz */
ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
- 12000000, SND_SOC_CLOCK_IN);
- if (ret < 0)
+ MCLK_RATE, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ clk_disable(mclk);
return ret;
+ }
return 0;
}
@@ -189,6 +195,31 @@ static struct snd_soc_ops at91sam9g20ek_ops = {
.shutdown = at91sam9g20ek_shutdown,
};
+static int at91sam9g20ek_set_bias_level(struct snd_soc_card *card,
+ enum snd_soc_bias_level level)
+{
+ static int mclk_on;
+ int ret = 0;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ case SND_SOC_BIAS_PREPARE:
+ if (!mclk_on)
+ ret = clk_enable(mclk);
+ if (ret == 0)
+ mclk_on = 1;
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ case SND_SOC_BIAS_STANDBY:
+ if (mclk_on)
+ clk_disable(mclk);
+ mclk_on = 0;
+ break;
+ }
+
+ return ret;
+}
static const struct snd_soc_dapm_widget at91sam9g20ek_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Int Mic", NULL),
@@ -243,21 +274,48 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = {
};
static struct snd_soc_card snd_soc_at91sam9g20ek = {
- .name = "WM8731",
+ .name = "AT91SAMG20-EK",
.platform = &atmel_soc_platform,
.dai_link = &at91sam9g20ek_dai,
.num_links = 1,
+ .set_bias_level = at91sam9g20ek_set_bias_level,
};
-static struct wm8731_setup_data at91sam9g20ek_wm8731_setup = {
- .i2c_bus = 0,
- .i2c_address = 0x1b,
-};
+/*
+ * FIXME: This is a temporary bodge to avoid cross-tree merge issues.
+ * New drivers should register the wm8731 I2C device in the machine
+ * setup code (under arch/arm for ARM systems).
+ */
+static int wm8731_i2c_register(void)
+{
+ struct i2c_board_info info;
+ struct i2c_adapter *adapter;
+ struct i2c_client *client;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ info.addr = 0x1b;
+ strlcpy(info.type, "wm8731", I2C_NAME_SIZE);
+
+ adapter = i2c_get_adapter(0);
+ if (!adapter) {
+ printk(KERN_ERR "can't get i2c adapter 0\n");
+ return -ENODEV;
+ }
+
+ client = i2c_new_device(adapter, &info);
+ i2c_put_adapter(adapter);
+ if (!client) {
+ printk(KERN_ERR "can't add i2c device at 0x%x\n",
+ (unsigned int)info.addr);
+ return -ENODEV;
+ }
+
+ return 0;
+}
static struct snd_soc_device at91sam9g20ek_snd_devdata = {
.card = &snd_soc_at91sam9g20ek,
.codec_dev = &soc_codec_dev_wm8731,
- .codec_data = &at91sam9g20ek_wm8731_setup,
};
static struct platform_device *at91sam9g20ek_snd_device;
@@ -266,23 +324,56 @@ static int __init at91sam9g20ek_init(void)
{
struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data;
struct ssc_device *ssc = NULL;
+ struct clk *pllb;
int ret;
+ if (!machine_is_at91sam9g20ek())
+ return -ENODEV;
+
+ /*
+ * Codec MCLK is supplied by PCK0 - set it up.
+ */
+ mclk = clk_get(NULL, "pck0");
+ if (IS_ERR(mclk)) {
+ printk(KERN_ERR "ASoC: Failed to get MCLK\n");
+ ret = PTR_ERR(mclk);
+ goto err;
+ }
+
+ pllb = clk_get(NULL, "pllb");
+ if (IS_ERR(mclk)) {
+ printk(KERN_ERR "ASoC: Failed to get PLLB\n");
+ ret = PTR_ERR(mclk);
+ goto err_mclk;
+ }
+ ret = clk_set_parent(mclk, pllb);
+ clk_put(pllb);
+ if (ret != 0) {
+ printk(KERN_ERR "ASoC: Failed to set MCLK parent\n");
+ goto err_mclk;
+ }
+
+ clk_set_rate(mclk, MCLK_RATE);
+
/*
* Request SSC device
*/
ssc = ssc_request(0);
if (IS_ERR(ssc)) {
+ printk(KERN_ERR "ASoC: Failed to request SSC 0\n");
ret = PTR_ERR(ssc);
ssc = NULL;
goto err_ssc;
}
ssc_p->ssc = ssc;
+ ret = wm8731_i2c_register();
+ if (ret != 0)
+ goto err_ssc;
+
at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1);
if (!at91sam9g20ek_snd_device) {
- printk(KERN_DEBUG
- "platform device allocation failed\n");
+ printk(KERN_ERR "ASoC: Platform device allocation failed\n");
ret = -ENOMEM;
}
@@ -292,14 +383,19 @@ static int __init at91sam9g20ek_init(void)
ret = platform_device_add(at91sam9g20ek_snd_device);
if (ret) {
- printk(KERN_DEBUG
- "platform device allocation failed\n");
+ printk(KERN_ERR "ASoC: Platform device allocation failed\n");
platform_device_put(at91sam9g20ek_snd_device);
}
return ret;
err_ssc:
+ ssc_free(ssc);
+ ssc_p->ssc = NULL;
+err_mclk:
+ clk_put(mclk);
+ mclk = NULL;
+err:
return ret;
}
@@ -317,6 +413,8 @@ static void __exit at91sam9g20ek_exit(void)
platform_device_unregister(at91sam9g20ek_snd_device);
at91sam9g20ek_snd_device = NULL;
+ clk_put(mclk);
+ mclk = NULL;
}
module_init(at91sam9g20ek_init);
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c
index bc8d654576c..30490a25914 100644
--- a/sound/soc/au1x/dbdma2.c
+++ b/sound/soc/au1x/dbdma2.c
@@ -305,7 +305,7 @@ static int au1xpsc_pcm_close(struct snd_pcm_substream *substream)
return 0;
}
-struct snd_pcm_ops au1xpsc_pcm_ops = {
+static struct snd_pcm_ops au1xpsc_pcm_ops = {
.open = au1xpsc_pcm_open,
.close = au1xpsc_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index f0e30aec7f2..479d7bdf186 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -342,6 +342,11 @@ static int au1xpsc_ac97_resume(struct snd_soc_dai *dai)
return 0;
}
+static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
+ .trigger = au1xpsc_ac97_trigger,
+ .hw_params = au1xpsc_ac97_hw_params,
+};
+
struct snd_soc_dai au1xpsc_ac97_dai = {
.name = "au1xpsc_ac97",
.ac97_control = 1,
@@ -361,10 +366,7 @@ struct snd_soc_dai au1xpsc_ac97_dai = {
.channels_min = 2,
.channels_max = 2,
},
- .ops = {
- .trigger = au1xpsc_ac97_trigger,
- .hw_params = au1xpsc_ac97_hw_params,
- },
+ .ops = &au1xpsc_ac97_dai_ops,
};
EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai);
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
index f916de4400e..bb589327ee3 100644
--- a/sound/soc/au1x/psc-i2s.c
+++ b/sound/soc/au1x/psc-i2s.c
@@ -367,6 +367,12 @@ static int au1xpsc_i2s_resume(struct snd_soc_dai *cpu_dai)
return 0;
}
+static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
+ .trigger = au1xpsc_i2s_trigger,
+ .hw_params = au1xpsc_i2s_hw_params,
+ .set_fmt = au1xpsc_i2s_set_fmt,
+};
+
struct snd_soc_dai au1xpsc_i2s_dai = {
.name = "au1xpsc_i2s",
.probe = au1xpsc_i2s_probe,
@@ -385,11 +391,7 @@ struct snd_soc_dai au1xpsc_i2s_dai = {
.channels_min = 2,
.channels_max = 8, /* 2 without external help */
},
- .ops = {
- .trigger = au1xpsc_i2s_trigger,
- .hw_params = au1xpsc_i2s_hw_params,
- .set_fmt = au1xpsc_i2s_set_fmt,
- },
+ .ops = &au1xpsc_i2s_dai_ops,
};
EXPORT_SYMBOL(au1xpsc_i2s_dai);
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c
index 8067cfafa3a..8cfed1a5dcb 100644
--- a/sound/soc/blackfin/bf5xx-ac97-pcm.c
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c
@@ -297,7 +297,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
}
#endif
-struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
+static struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
.open = bf5xx_pcm_open,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = bf5xx_pcm_hw_params,
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
index 3be2be60576..8a935f2d176 100644
--- a/sound/soc/blackfin/bf5xx-ac97.c
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -31,72 +31,46 @@
#include "bf5xx-sport.h"
#include "bf5xx-ac97.h"
-#if defined(CONFIG_BF54x)
-#define PIN_REQ_SPORT_0 {P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, \
- P_SPORT0_RFS, P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0}
-
-#define PIN_REQ_SPORT_1 {P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, \
- P_SPORT1_RFS, P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0}
-
-#define PIN_REQ_SPORT_2 {P_SPORT2_TFS, P_SPORT2_DTPRI, P_SPORT2_TSCLK, \
- P_SPORT2_RFS, P_SPORT2_DRPRI, P_SPORT2_RSCLK, 0}
-
-#define PIN_REQ_SPORT_3 {P_SPORT3_TFS, P_SPORT3_DTPRI, P_SPORT3_TSCLK, \
- P_SPORT3_RFS, P_SPORT3_DRPRI, P_SPORT3_RSCLK, 0}
-#else
-#define PIN_REQ_SPORT_0 {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, \
- P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0}
-
-#define PIN_REQ_SPORT_1 {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, \
- P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0}
-#endif
-
static int *cmd_count;
static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
+#define SPORT_REQ(x) \
+ [x] = {P_SPORT##x##_TFS, P_SPORT##x##_DTPRI, P_SPORT##x##_TSCLK, \
+ P_SPORT##x##_RFS, P_SPORT##x##_DRPRI, P_SPORT##x##_RSCLK, 0}
static u16 sport_req[][7] = {
- PIN_REQ_SPORT_0,
-#ifdef PIN_REQ_SPORT_1
- PIN_REQ_SPORT_1,
+#ifdef SPORT0_TCR1
+ SPORT_REQ(0),
+#endif
+#ifdef SPORT1_TCR1
+ SPORT_REQ(1),
#endif
-#ifdef PIN_REQ_SPORT_2
- PIN_REQ_SPORT_2,
+#ifdef SPORT2_TCR1
+ SPORT_REQ(2),
#endif
-#ifdef PIN_REQ_SPORT_3
- PIN_REQ_SPORT_3,
+#ifdef SPORT3_TCR1
+ SPORT_REQ(3),
#endif
- };
+};
+#define SPORT_PARAMS(x) \
+ [x] = { \
+ .dma_rx_chan = CH_SPORT##x##_RX, \
+ .dma_tx_chan = CH_SPORT##x##_TX, \
+ .err_irq = IRQ_SPORT##x##_ERROR, \
+ .regs = (struct sport_register *)SPORT##x##_TCR1, \
+ }
static struct sport_param sport_params[4] = {
- {
- .dma_rx_chan = CH_SPORT0_RX,
- .dma_tx_chan = CH_SPORT0_TX,
- .err_irq = IRQ_SPORT0_ERROR,
- .regs = (struct sport_register *)SPORT0_TCR1,
- },
-#ifdef PIN_REQ_SPORT_1
- {
- .dma_rx_chan = CH_SPORT1_RX,
- .dma_tx_chan = CH_SPORT1_TX,
- .err_irq = IRQ_SPORT1_ERROR,
- .regs = (struct sport_register *)SPORT1_TCR1,
- },
+#ifdef SPORT0_TCR1
+ SPORT_PARAMS(0),
#endif
-#ifdef PIN_REQ_SPORT_2
- {
- .dma_rx_chan = CH_SPORT2_RX,
- .dma_tx_chan = CH_SPORT2_TX,
- .err_irq = IRQ_SPORT2_ERROR,
- .regs = (struct sport_register *)SPORT2_TCR1,
- },
+#ifdef SPORT1_TCR1
+ SPORT_PARAMS(1),
#endif
-#ifdef PIN_REQ_SPORT_3
- {
- .dma_rx_chan = CH_SPORT3_RX,
- .dma_tx_chan = CH_SPORT3_TX,
- .err_irq = IRQ_SPORT3_ERROR,
- .regs = (struct sport_register *)SPORT3_TCR1,
- }
+#ifdef SPORT2_TCR1
+ SPORT_PARAMS(2),
+#endif
+#ifdef SPORT3_TCR1
+ SPORT_PARAMS(3),
#endif
};
@@ -332,11 +306,11 @@ static int bf5xx_ac97_probe(struct platform_device *pdev,
if (cmd_count == NULL)
return -ENOMEM;
- if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
+ if (peripheral_request_list(sport_req[sport_num], "soc-audio")) {
pr_err("Requesting Peripherals failed\n");
ret = -EFAULT;
goto peripheral_err;
- }
+ }
#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
/* Request PB3 as reset pin */
@@ -383,9 +357,9 @@ sport_config_err:
sport_err:
#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
-#endif
gpio_err:
- peripheral_free_list(&sport_req[sport_num][0]);
+#endif
+ peripheral_free_list(sport_req[sport_num]);
peripheral_err:
free_page((unsigned long)cmd_count);
cmd_count = NULL;
@@ -398,7 +372,7 @@ static void bf5xx_ac97_remove(struct platform_device *pdev,
{
free_page((unsigned long)cmd_count);
cmd_count = NULL;
- peripheral_free_list(&sport_req[sport_num][0]);
+ peripheral_free_list(sport_req[sport_num]);
#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
#endif
diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c
index 7f2a5e19907..edfbdc024e6 100644
--- a/sound/soc/blackfin/bf5xx-ad73311.c
+++ b/sound/soc/blackfin/bf5xx-ad73311.c
@@ -114,7 +114,7 @@ static int snd_ad73311_configure(void)
SSYNC();
/* When TUVF is set, the data is already send out */
- while (!(status & TUVF) && count++ < 10000) {
+ while (!(status & TUVF) && ++count < 10000) {
udelay(1);
status = bfin_read_SPORT_STAT();
SSYNC();
@@ -123,7 +123,7 @@ static int snd_ad73311_configure(void)
SSYNC();
local_irq_enable();
- if (count == 10000) {
+ if (count >= 10000) {
printk(KERN_ERR "ad73311: failed to configure codec\n");
return -1;
}
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c
index 53d290b3ea4..1318c4f627b 100644
--- a/sound/soc/blackfin/bf5xx-i2s-pcm.c
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c
@@ -184,7 +184,7 @@ static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
return 0 ;
}
-struct snd_pcm_ops bf5xx_pcm_i2s_ops = {
+static struct snd_pcm_ops bf5xx_pcm_i2s_ops = {
.open = bf5xx_pcm_open,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = bf5xx_pcm_hw_params,
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c
index d1d95d2393f..96482441967 100644
--- a/sound/soc/blackfin/bf5xx-i2s.c
+++ b/sound/soc/blackfin/bf5xx-i2s.c
@@ -287,6 +287,13 @@ static int bf5xx_i2s_resume(struct platform_device *pdev,
#define BF5XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\
SNDRV_PCM_FMTBIT_S32_LE)
+static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
+ .startup = bf5xx_i2s_startup,
+ .shutdown = bf5xx_i2s_shutdown,
+ .hw_params = bf5xx_i2s_hw_params,
+ .set_fmt = bf5xx_i2s_set_dai_fmt,
+};
+
struct snd_soc_dai bf5xx_i2s_dai = {
.name = "bf5xx-i2s",
.id = 0,
@@ -304,12 +311,7 @@ struct snd_soc_dai bf5xx_i2s_dai = {
.channels_max = 2,
.rates = BF5XX_I2S_RATES,
.formats = BF5XX_I2S_FORMATS,},
- .ops = {
- .startup = bf5xx_i2s_startup,
- .shutdown = bf5xx_i2s_shutdown,
- .hw_params = bf5xx_i2s_hw_params,
- .set_fmt = bf5xx_i2s_set_dai_fmt,
- },
+ .ops = &bf5xx_i2s_dai_ops,
};
EXPORT_SYMBOL_GPL(bf5xx_i2s_dai);
diff --git a/sound/soc/blackfin/bf5xx-sport.c b/sound/soc/blackfin/bf5xx-sport.c
index 3b99e484d55..b7953c8cf83 100644
--- a/sound/soc/blackfin/bf5xx-sport.c
+++ b/sound/soc/blackfin/bf5xx-sport.c
@@ -133,7 +133,7 @@ static void setup_desc(struct dmasg *desc, void *buf, int fragcount,
int i;
for (i = 0; i < fragcount; ++i) {
- desc[i].next_desc_addr = (unsigned long)&(desc[i + 1]);
+ desc[i].next_desc_addr = &(desc[i + 1]);
desc[i].start_addr = (unsigned long)buf + i*fragsize;
desc[i].cfg = cfg;
desc[i].x_count = x_count;
@@ -143,12 +143,12 @@ static void setup_desc(struct dmasg *desc, void *buf, int fragcount,
}
/* make circular */
- desc[fragcount-1].next_desc_addr = (unsigned long)desc;
+ desc[fragcount-1].next_desc_addr = desc;
- pr_debug("setup desc: desc0=%p, next0=%lx, desc1=%p,"
- "next1=%lx\nx_count=%x,y_count=%x,addr=0x%lx,cfs=0x%x\n",
- &(desc[0]), desc[0].next_desc_addr,
- &(desc[1]), desc[1].next_desc_addr,
+ pr_debug("setup desc: desc0=%p, next0=%p, desc1=%p,"
+ "next1=%p\nx_count=%x,y_count=%x,addr=0x%lx,cfs=0x%x\n",
+ desc, desc[0].next_desc_addr,
+ desc+1, desc[1].next_desc_addr,
desc[0].x_count, desc[0].y_count,
desc[0].start_addr, desc[0].cfg);
}
@@ -184,22 +184,20 @@ static inline int sport_hook_rx_dummy(struct sport_device *sport)
BUG_ON(sport->curr_rx_desc == sport->dummy_rx_desc);
/* Maybe the dummy buffer descriptor ring is damaged */
- sport->dummy_rx_desc->next_desc_addr = \
- (unsigned long)(sport->dummy_rx_desc+1);
+ sport->dummy_rx_desc->next_desc_addr = sport->dummy_rx_desc + 1;
local_irq_save(flags);
- desc = (struct dmasg *)get_dma_next_desc_ptr(sport->dma_rx_chan);
+ desc = get_dma_next_desc_ptr(sport->dma_rx_chan);
/* Copy the descriptor which will be damaged to backup */
temp_desc = *desc;
desc->x_count = 0xa;
desc->y_count = 0;
- desc->next_desc_addr = (unsigned long)(sport->dummy_rx_desc);
+ desc->next_desc_addr = sport->dummy_rx_desc;
local_irq_restore(flags);
/* Waiting for dummy buffer descriptor is already hooked*/
while ((get_dma_curr_desc_ptr(sport->dma_rx_chan) -
- sizeof(struct dmasg)) !=
- (unsigned long)sport->dummy_rx_desc)
- ;
+ sizeof(struct dmasg)) != sport->dummy_rx_desc)
+ continue;
sport->curr_rx_desc = sport->dummy_rx_desc;
/* Restore the damaged descriptor */
*desc = temp_desc;
@@ -210,14 +208,12 @@ static inline int sport_hook_rx_dummy(struct sport_device *sport)
static inline int sport_rx_dma_start(struct sport_device *sport, int dummy)
{
if (dummy) {
- sport->dummy_rx_desc->next_desc_addr = \
- (unsigned long) sport->dummy_rx_desc;
+ sport->dummy_rx_desc->next_desc_addr = sport->dummy_rx_desc;
sport->curr_rx_desc = sport->dummy_rx_desc;
} else
sport->curr_rx_desc = sport->dma_rx_desc;
- set_dma_next_desc_addr(sport->dma_rx_chan, \
- (unsigned long)(sport->curr_rx_desc));
+ set_dma_next_desc_addr(sport->dma_rx_chan, sport->curr_rx_desc);
set_dma_x_count(sport->dma_rx_chan, 0);
set_dma_x_modify(sport->dma_rx_chan, 0);
set_dma_config(sport->dma_rx_chan, (DMAFLOW_LARGE | NDSIZE_9 | \
@@ -231,14 +227,12 @@ static inline int sport_rx_dma_start(struct sport_device *sport, int dummy)
static inline int sport_tx_dma_start(struct sport_device *sport, int dummy)
{
if (dummy) {
- sport->dummy_tx_desc->next_desc_addr = \
- (unsigned long) sport->dummy_tx_desc;
+ sport->dummy_tx_desc->next_desc_addr = sport->dummy_tx_desc;
sport->curr_tx_desc = sport->dummy_tx_desc;
} else
sport->curr_tx_desc = sport->dma_tx_desc;
- set_dma_next_desc_addr(sport->dma_tx_chan, \
- (unsigned long)(sport->curr_tx_desc));
+ set_dma_next_desc_addr(sport->dma_tx_chan, sport->curr_tx_desc);
set_dma_x_count(sport->dma_tx_chan, 0);
set_dma_x_modify(sport->dma_tx_chan, 0);
set_dma_config(sport->dma_tx_chan,
@@ -261,11 +255,9 @@ int sport_rx_start(struct sport_device *sport)
BUG_ON(sport->curr_rx_desc != sport->dummy_rx_desc);
local_irq_save(flags);
while ((get_dma_curr_desc_ptr(sport->dma_rx_chan) -
- sizeof(struct dmasg)) !=
- (unsigned long)sport->dummy_rx_desc)
- ;
- sport->dummy_rx_desc->next_desc_addr =
- (unsigned long)(sport->dma_rx_desc);
+ sizeof(struct dmasg)) != sport->dummy_rx_desc)
+ continue;
+ sport->dummy_rx_desc->next_desc_addr = sport->dma_rx_desc;
local_irq_restore(flags);
sport->curr_rx_desc = sport->dma_rx_desc;
} else {
@@ -310,23 +302,21 @@ static inline int sport_hook_tx_dummy(struct sport_device *sport)
BUG_ON(sport->dummy_tx_desc == NULL);
BUG_ON(sport->curr_tx_desc == sport->dummy_tx_desc);
- sport->dummy_tx_desc->next_desc_addr = \
- (unsigned long)(sport->dummy_tx_desc+1);
+ sport->dummy_tx_desc->next_desc_addr = sport->dummy_tx_desc + 1;
/* Shorten the time on last normal descriptor */
local_irq_save(flags);
- desc = (struct dmasg *)get_dma_next_desc_ptr(sport->dma_tx_chan);
+ desc = get_dma_next_desc_ptr(sport->dma_tx_chan);
/* Store the descriptor which will be damaged */
temp_desc = *desc;
desc->x_count = 0xa;
desc->y_count = 0;
- desc->next_desc_addr = (unsigned long)(sport->dummy_tx_desc);
+ desc->next_desc_addr = sport->dummy_tx_desc;
local_irq_restore(flags);
/* Waiting for dummy buffer descriptor is already hooked*/
while ((get_dma_curr_desc_ptr(sport->dma_tx_chan) - \
- sizeof(struct dmasg)) != \
- (unsigned long)sport->dummy_tx_desc)
- ;
+ sizeof(struct dmasg)) != sport->dummy_tx_desc)
+ continue;
sport->curr_tx_desc = sport->dummy_tx_desc;
/* Restore the damaged descriptor */
*desc = temp_desc;
@@ -347,11 +337,9 @@ int sport_tx_start(struct sport_device *sport)
/* Hook the normal buffer descriptor */
local_irq_save(flags);
while ((get_dma_curr_desc_ptr(sport->dma_tx_chan) -
- sizeof(struct dmasg)) !=
- (unsigned long)sport->dummy_tx_desc)
- ;
- sport->dummy_tx_desc->next_desc_addr =
- (unsigned long)(sport->dma_tx_desc);
+ sizeof(struct dmasg)) != sport->dummy_tx_desc)
+ continue;
+ sport->dummy_tx_desc->next_desc_addr = sport->dma_tx_desc;
local_irq_restore(flags);
sport->curr_tx_desc = sport->dma_tx_desc;
} else {
@@ -536,19 +524,17 @@ static int sport_config_rx_dummy(struct sport_device *sport)
unsigned config;
pr_debug("%s entered\n", __func__);
-#if L1_DATA_A_LENGTH != 0
- desc = (struct dmasg *) l1_data_sram_alloc(2 * sizeof(*desc));
-#else
- {
+ if (L1_DATA_A_LENGTH)
+ desc = l1_data_sram_zalloc(2 * sizeof(*desc));
+ else {
dma_addr_t addr;
desc = dma_alloc_coherent(NULL, 2 * sizeof(*desc), &addr, 0);
+ memset(desc, 0, 2 * sizeof(*desc));
}
-#endif
if (desc == NULL) {
pr_err("Failed to allocate memory for dummy rx desc\n");
return -ENOMEM;
}
- memset(desc, 0, 2 * sizeof(*desc));
sport->dummy_rx_desc = desc;
desc->start_addr = (unsigned long)sport->dummy_buf;
config = DMAFLOW_LARGE | NDSIZE_9 | compute_wdsize(sport->wdsize)
@@ -559,8 +545,8 @@ static int sport_config_rx_dummy(struct sport_device *sport)
desc->y_count = 0;
desc->y_modify = 0;
memcpy(desc+1, desc, sizeof(*desc));
- desc->next_desc_addr = (unsigned long)(desc+1);
- desc[1].next_desc_addr = (unsigned long)desc;
+ desc->next_desc_addr = desc + 1;
+ desc[1].next_desc_addr = desc;
return 0;
}
@@ -571,19 +557,17 @@ static int sport_config_tx_dummy(struct sport_device *sport)
pr_debug("%s entered\n", __func__);
-#if L1_DATA_A_LENGTH != 0
- desc = (struct dmasg *) l1_data_sram_alloc(2 * sizeof(*desc));
-#else
- {
+ if (L1_DATA_A_LENGTH)
+ desc = l1_data_sram_zalloc(2 * sizeof(*desc));
+ else {
dma_addr_t addr;
desc = dma_alloc_coherent(NULL, 2 * sizeof(*desc), &addr, 0);
+ memset(desc, 0, 2 * sizeof(*desc));
}
-#endif
if (!desc) {
pr_err("Failed to allocate memory for dummy tx desc\n");
return -ENOMEM;
}
- memset(desc, 0, 2 * sizeof(*desc));
sport->dummy_tx_desc = desc;
desc->start_addr = (unsigned long)sport->dummy_buf + \
sport->dummy_count;
@@ -595,8 +579,8 @@ static int sport_config_tx_dummy(struct sport_device *sport)
desc->y_count = 0;
desc->y_modify = 0;
memcpy(desc+1, desc, sizeof(*desc));
- desc->next_desc_addr = (unsigned long)(desc+1);
- desc[1].next_desc_addr = (unsigned long)desc;
+ desc->next_desc_addr = desc + 1;
+ desc[1].next_desc_addr = desc;
return 0;
}
@@ -872,17 +856,15 @@ struct sport_device *sport_init(struct sport_param *param, unsigned wdsize,
sport->wdsize = wdsize;
sport->dummy_count = dummy_count;
-#if L1_DATA_A_LENGTH != 0
- sport->dummy_buf = l1_data_sram_alloc(dummy_count * 2);
-#else
- sport->dummy_buf = kmalloc(dummy_count * 2, GFP_KERNEL);
-#endif
+ if (L1_DATA_A_LENGTH)
+ sport->dummy_buf = l1_data_sram_zalloc(dummy_count * 2);
+ else
+ sport->dummy_buf = kzalloc(dummy_count * 2, GFP_KERNEL);
if (sport->dummy_buf == NULL) {
pr_err("Failed to allocate dummy buffer\n");
goto __error;
}
- memset(sport->dummy_buf, 0, dummy_count * 2);
ret = sport_config_rx_dummy(sport);
if (ret) {
pr_err("Failed to config rx dummy ring\n");
@@ -939,6 +921,7 @@ void sport_done(struct sport_device *sport)
sport = NULL;
}
EXPORT_SYMBOL(sport_done);
+
/*
* It is only used to send several bytes when dma is not enabled
* sport controller is configured but not enabled.
@@ -1029,4 +1012,3 @@ EXPORT_SYMBOL(sport_send_and_recv);
MODULE_AUTHOR("Roy Huang");
MODULE_DESCRIPTION("SPORT driver for ADI Blackfin");
MODULE_LICENSE("GPL");
-
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index d0e0d691ae5..b6c7f7a01cb 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -10,9 +10,11 @@ config SND_SOC_I2C_AND_SPI
config SND_SOC_ALL_CODECS
tristate "Build all ASoC CODEC drivers"
+ select SND_SOC_L3
select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
select SND_SOC_AD1980 if SND_SOC_AC97_BUS
select SND_SOC_AD73311 if I2C
+ select SND_SOC_AK4104 if SPI_MASTER
select SND_SOC_AK4535 if I2C
select SND_SOC_CS4270 if I2C
select SND_SOC_PCM3008
@@ -24,6 +26,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_UDA134X
select SND_SOC_UDA1380 if I2C
select SND_SOC_WM8350 if MFD_WM8350
+ select SND_SOC_WM8400 if MFD_WM8400
select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8580 if I2C
select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI
@@ -34,6 +37,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8903 if I2C
select SND_SOC_WM8971 if I2C
select SND_SOC_WM8990 if I2C
+ select SND_SOC_WM9705 if SND_SOC_AC97_BUS
select SND_SOC_WM9712 if SND_SOC_AC97_BUS
select SND_SOC_WM9713 if SND_SOC_AC97_BUS
help
@@ -58,6 +62,9 @@ config SND_SOC_AD1980
config SND_SOC_AD73311
tristate
+config SND_SOC_AK4104
+ tristate
+
config SND_SOC_AK4535
tristate
@@ -65,12 +72,6 @@ config SND_SOC_AK4535
config SND_SOC_CS4270
tristate
-# Cirrus Logic CS4270 Codec Hardware Mute Support
-# Select if you have external muting circuitry attached to your CS4270.
-config SND_SOC_CS4270_HWMUTE
- bool
- depends on SND_SOC_CS4270
-
# Cirrus Logic CS4270 Codec VD = 3.3V Errata
# Select if you are affected by the errata where the part will not function
# if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will
@@ -90,7 +91,6 @@ config SND_SOC_SSM2602
config SND_SOC_TLV320AIC23
tristate
- depends on I2C
config SND_SOC_TLV320AIC26
tristate "TI TLV320AIC26 Codec support" if SND_SOC_OF_SIMPLE
@@ -98,15 +98,12 @@ config SND_SOC_TLV320AIC26
config SND_SOC_TLV320AIC3X
tristate
- depends on I2C
config SND_SOC_TWL4030
tristate
- depends on TWL4030_CORE
config SND_SOC_UDA134X
tristate
- select SND_SOC_L3
config SND_SOC_UDA1380
tristate
@@ -114,6 +111,9 @@ config SND_SOC_UDA1380
config SND_SOC_WM8350
tristate
+config SND_SOC_WM8400
+ tristate
+
config SND_SOC_WM8510
tristate
@@ -144,6 +144,9 @@ config SND_SOC_WM8971
config SND_SOC_WM8990
tristate
+config SND_SOC_WM9705
+ tristate
+
config SND_SOC_WM9712
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index c4ddc9aa2bb..030d2454725 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -1,6 +1,7 @@
snd-soc-ac97-objs := ac97.o
snd-soc-ad1980-objs := ad1980.o
snd-soc-ad73311-objs := ad73311.o
+snd-soc-ak4104-objs := ak4104.o
snd-soc-ak4535-objs := ak4535.o
snd-soc-cs4270-objs := cs4270.o
snd-soc-l3-objs := l3.o
@@ -13,6 +14,7 @@ snd-soc-twl4030-objs := twl4030.o
snd-soc-uda134x-objs := uda134x.o
snd-soc-uda1380-objs := uda1380.o
snd-soc-wm8350-objs := wm8350.o
+snd-soc-wm8400-objs := wm8400.o
snd-soc-wm8510-objs := wm8510.o
snd-soc-wm8580-objs := wm8580.o
snd-soc-wm8728-objs := wm8728.o
@@ -23,12 +25,14 @@ snd-soc-wm8900-objs := wm8900.o
snd-soc-wm8903-objs := wm8903.o
snd-soc-wm8971-objs := wm8971.o
snd-soc-wm8990-objs := wm8990.o
+snd-soc-wm9705-objs := wm9705.o
snd-soc-wm9712-objs := wm9712.o
snd-soc-wm9713-objs := wm9713.o
obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
+obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o
obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
@@ -41,6 +45,7 @@ obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o
obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o
+obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o
obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o
obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o
obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o
@@ -51,5 +56,7 @@ obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o
obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o
obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o
obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o
+obj-$(CONFIG_SND_SOC_WM8991) += snd-soc-wm8991.o
+obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o
obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index fb53e6511af..b0d4af145b8 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -30,7 +30,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
@@ -41,6 +41,10 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
SNDRV_PCM_RATE_48000)
+static struct snd_soc_dai_ops ac97_dai_ops = {
+ .prepare = ac97_prepare,
+};
+
struct snd_soc_dai ac97_dai = {
.name = "AC97 HiFi",
.ac97_control = 1,
@@ -56,8 +60,7 @@ struct snd_soc_dai ac97_dai = {
.channels_max = 2,
.rates = STD_AC97_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = {
- .prepare = ac97_prepare,},
+ .ops = &ac97_dai_ops,
};
EXPORT_SYMBOL_GPL(ac97_dai);
@@ -84,10 +87,10 @@ static int ac97_soc_probe(struct platform_device *pdev)
printk(KERN_INFO "AC97 SoC Audio Codec %s\n", AC97_VERSION);
- socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (!socdev->codec)
+ socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (!socdev->card->codec)
return -ENOMEM;
- codec = socdev->codec;
+ codec = socdev->card->codec;
mutex_init(&codec->mutex);
codec->name = "AC97";
@@ -123,23 +126,21 @@ bus_err:
snd_soc_free_pcms(socdev);
err:
- kfree(socdev->codec->reg_cache);
- kfree(socdev->codec);
- socdev->codec = NULL;
+ kfree(socdev->card->codec);
+ socdev->card->codec = NULL;
return ret;
}
static int ac97_soc_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
if (!codec)
return 0;
snd_soc_free_pcms(socdev);
- kfree(socdev->codec->reg_cache);
- kfree(socdev->codec);
+ kfree(socdev->card->codec);
return 0;
}
@@ -149,7 +150,7 @@ static int ac97_soc_suspend(struct platform_device *pdev, pm_message_t msg)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- snd_ac97_suspend(socdev->codec->ac97);
+ snd_ac97_suspend(socdev->card->codec->ac97);
return 0;
}
@@ -158,7 +159,7 @@ static int ac97_soc_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- snd_ac97_resume(socdev->codec->ac97);
+ snd_ac97_resume(socdev->card->codec->ac97);
return 0;
}
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index 73fdbb4d4a3..ddb3b08ac23 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -93,20 +93,6 @@ SOC_ENUM("Capture Source", ad1980_cap_src),
SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0),
};
-/* add non dapm controls */
-static int ad1980_add_controls(struct snd_soc_codec *codec)
-{
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(ad1980_snd_ac97_controls); i++) {
- err = snd_ctl_add(codec->card, snd_soc_cnew(
- &ad1980_snd_ac97_controls[i], codec, NULL));
- if (err < 0)
- return err;
- }
- return 0;
-}
-
static unsigned int ac97_read(struct snd_soc_codec *codec,
unsigned int reg)
{
@@ -123,7 +109,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec,
default:
reg = reg >> 1;
- if (reg >= (ARRAY_SIZE(ad1980_reg)))
+ if (reg >= ARRAY_SIZE(ad1980_reg))
return -EINVAL;
return cache[reg];
@@ -137,7 +123,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
soc_ac97_ops.write(codec->ac97, reg, val);
reg = reg >> 1;
- if (reg < (ARRAY_SIZE(ad1980_reg)))
+ if (reg < ARRAY_SIZE(ad1980_reg))
cache[reg] = val;
return 0;
@@ -200,10 +186,10 @@ static int ad1980_soc_probe(struct platform_device *pdev)
printk(KERN_INFO "AD1980 SoC Audio Codec\n");
- socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (socdev->codec == NULL)
+ socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (socdev->card->codec == NULL)
return -ENOMEM;
- codec = socdev->codec;
+ codec = socdev->card->codec;
mutex_init(&codec->mutex);
codec->reg_cache =
@@ -269,7 +255,8 @@ static int ad1980_soc_probe(struct platform_device *pdev)
ext_status = ac97_read(codec, AC97_EXTENDED_STATUS);
ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800);
- ad1980_add_controls(codec);
+ snd_soc_add_controls(codec, ad1980_snd_ac97_controls,
+ ARRAY_SIZE(ad1980_snd_ac97_controls));
ret = snd_soc_init_card(socdev);
if (ret < 0) {
printk(KERN_ERR "ad1980: failed to register card\n");
@@ -288,15 +275,15 @@ codec_err:
kfree(codec->reg_cache);
cache_err:
- kfree(socdev->codec);
- socdev->codec = NULL;
+ kfree(socdev->card->codec);
+ socdev->card->codec = NULL;
return ret;
}
static int ad1980_soc_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
if (codec == NULL)
return 0;
diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c
index b09289a1e55..e61dac5e7b8 100644
--- a/sound/soc/codecs/ad73311.c
+++ b/sound/soc/codecs/ad73311.c
@@ -53,7 +53,7 @@ static int ad73311_soc_probe(struct platform_device *pdev)
codec->owner = THIS_MODULE;
codec->dai = &ad73311_dai;
codec->num_dai = 1;
- socdev->codec = codec;
+ socdev->card->codec = codec;
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
@@ -75,15 +75,15 @@ static int ad73311_soc_probe(struct platform_device *pdev)
register_err:
snd_soc_free_pcms(socdev);
pcm_err:
- kfree(socdev->codec);
- socdev->codec = NULL;
+ kfree(socdev->card->codec);
+ socdev->card->codec = NULL;
return ret;
}
static int ad73311_soc_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
if (codec == NULL)
return 0;
diff --git a/sound/soc/codecs/ad73311.h b/sound/soc/codecs/ad73311.h
index 507ce0c30ed..569573d2d4d 100644
--- a/sound/soc/codecs/ad73311.h
+++ b/sound/soc/codecs/ad73311.h
@@ -70,7 +70,7 @@
#define REGD_IGS(x) (x & 0x7)
#define REGD_RMOD (1 << 3)
#define REGD_OGS(x) ((x & 0x7) << 4)
-#define REGD_MUTE (x << 7)
+#define REGD_MUTE (1 << 7)
/* Control register E */
#define CTRL_REG_E (4 << 8)
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
new file mode 100644
index 00000000000..4d47bc4f742
--- /dev/null
+++ b/sound/soc/codecs/ak4104.c
@@ -0,0 +1,365 @@
+/*
+ * AK4104 ALSA SoC (ASoC) driver
+ *
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <linux/spi/spi.h>
+#include <sound/asoundef.h>
+
+#include "ak4104.h"
+
+/* AK4104 registers addresses */
+#define AK4104_REG_CONTROL1 0x00
+#define AK4104_REG_RESERVED 0x01
+#define AK4104_REG_CONTROL2 0x02
+#define AK4104_REG_TX 0x03
+#define AK4104_REG_CHN_STATUS(x) ((x) + 0x04)
+#define AK4104_NUM_REGS 10
+
+#define AK4104_REG_MASK 0x1f
+#define AK4104_READ 0xc0
+#define AK4104_WRITE 0xe0
+#define AK4104_RESERVED_VAL 0x5b
+
+/* Bit masks for AK4104 registers */
+#define AK4104_CONTROL1_RSTN (1 << 0)
+#define AK4104_CONTROL1_PW (1 << 1)
+#define AK4104_CONTROL1_DIF0 (1 << 2)
+#define AK4104_CONTROL1_DIF1 (1 << 3)
+
+#define AK4104_CONTROL2_SEL0 (1 << 0)
+#define AK4104_CONTROL2_SEL1 (1 << 1)
+#define AK4104_CONTROL2_MODE (1 << 2)
+
+#define AK4104_TX_TXE (1 << 0)
+#define AK4104_TX_V (1 << 1)
+
+#define DRV_NAME "ak4104"
+
+struct ak4104_private {
+ struct snd_soc_codec codec;
+ u8 reg_cache[AK4104_NUM_REGS];
+};
+
+static int ak4104_fill_cache(struct snd_soc_codec *codec)
+{
+ int i;
+ u8 *reg_cache = codec->reg_cache;
+ struct spi_device *spi = codec->control_data;
+
+ for (i = 0; i < codec->reg_cache_size; i++) {
+ int ret = spi_w8r8(spi, i | AK4104_READ);
+ if (ret < 0) {
+ dev_err(&spi->dev, "SPI write failure\n");
+ return ret;
+ }
+
+ reg_cache[i] = ret;
+ }
+
+ return 0;
+}
+
+static unsigned int ak4104_read_reg_cache(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ u8 *reg_cache = codec->reg_cache;
+
+ if (reg >= codec->reg_cache_size)
+ return -EINVAL;
+
+ return reg_cache[reg];
+}
+
+static int ak4104_spi_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ u8 *cache = codec->reg_cache;
+ struct spi_device *spi = codec->control_data;
+
+ if (reg >= codec->reg_cache_size)
+ return -EINVAL;
+
+ reg &= AK4104_REG_MASK;
+ reg |= AK4104_WRITE;
+
+ /* only write to the hardware if value has changed */
+ if (cache[reg] != value) {
+ u8 tmp[2] = { reg, value };
+ if (spi_write(spi, tmp, sizeof(tmp))) {
+ dev_err(&spi->dev, "SPI write failed\n");
+ return -EIO;
+ }
+
+ cache[reg] = value;
+ }
+
+ return 0;
+}
+
+static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int format)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ int val = 0;
+
+ val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
+ if (val < 0)
+ return val;
+
+ val &= ~(AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1);
+
+ /* set DAI format */
+ switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_RIGHT_J:
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ val |= AK4104_CONTROL1_DIF0;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ val |= AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1;
+ break;
+ default:
+ dev_err(codec->dev, "invalid dai format\n");
+ return -EINVAL;
+ }
+
+ /* This device can only be slave */
+ if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
+ return -EINVAL;
+
+ return ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
+}
+
+static int ak4104_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+ int val = 0;
+
+ /* set the IEC958 bits: consumer mode, no copyright bit */
+ val |= IEC958_AES0_CON_NOT_COPYRIGHT;
+ ak4104_spi_write(codec, AK4104_REG_CHN_STATUS(0), val);
+
+ val = 0;
+
+ switch (params_rate(params)) {
+ case 44100:
+ val |= IEC958_AES3_CON_FS_44100;
+ break;
+ case 48000:
+ val |= IEC958_AES3_CON_FS_48000;
+ break;
+ case 32000:
+ val |= IEC958_AES3_CON_FS_32000;
+ break;
+ default:
+ dev_err(codec->dev, "unsupported sampling rate\n");
+ return -EINVAL;
+ }
+
+ return ak4104_spi_write(codec, AK4104_REG_CHN_STATUS(3), val);
+}
+
+static struct snd_soc_dai_ops ak4101_dai_ops = {
+ .hw_params = ak4104_hw_params,
+ .set_fmt = ak4104_set_dai_fmt,
+};
+
+struct snd_soc_dai ak4104_dai = {
+ .name = DRV_NAME,
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_32000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S24_LE
+ },
+ .ops = &ak4101_dai_ops,
+};
+
+static struct snd_soc_codec *ak4104_codec;
+
+static int ak4104_spi_probe(struct spi_device *spi)
+{
+ struct snd_soc_codec *codec;
+ struct ak4104_private *ak4104;
+ int ret, val;
+
+ spi->bits_per_word = 8;
+ spi->mode = SPI_MODE_0;
+ ret = spi_setup(spi);
+ if (ret < 0)
+ return ret;
+
+ ak4104 = kzalloc(sizeof(struct ak4104_private), GFP_KERNEL);
+ if (!ak4104) {
+ dev_err(&spi->dev, "could not allocate codec\n");
+ return -ENOMEM;
+ }
+
+ codec = &ak4104->codec;
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ codec->dev = &spi->dev;
+ codec->name = DRV_NAME;
+ codec->owner = THIS_MODULE;
+ codec->dai = &ak4104_dai;
+ codec->num_dai = 1;
+ codec->private_data = ak4104;
+ codec->control_data = spi;
+ codec->reg_cache = ak4104->reg_cache;
+ codec->reg_cache_size = AK4104_NUM_REGS;
+
+ /* read all regs and fill the cache */
+ ret = ak4104_fill_cache(codec);
+ if (ret < 0) {
+ dev_err(&spi->dev, "failed to fill register cache\n");
+ return ret;
+ }
+
+ /* read the 'reserved' register - according to the datasheet, it
+ * should contain 0x5b. Not a good way to verify the presence of
+ * the device, but there is no hardware ID register. */
+ if (ak4104_read_reg_cache(codec, AK4104_REG_RESERVED) !=
+ AK4104_RESERVED_VAL) {
+ ret = -ENODEV;
+ goto error_free_codec;
+ }
+
+ /* set power-up and non-reset bits */
+ val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
+ val |= AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN;
+ ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
+ if (ret < 0)
+ goto error_free_codec;
+
+ /* enable transmitter */
+ val = ak4104_read_reg_cache(codec, AK4104_REG_TX);
+ val |= AK4104_TX_TXE;
+ ret = ak4104_spi_write(codec, AK4104_REG_TX, val);
+ if (ret < 0)
+ goto error_free_codec;
+
+ ak4104_codec = codec;
+ ret = snd_soc_register_dai(&ak4104_dai);
+ if (ret < 0) {
+ dev_err(&spi->dev, "failed to register DAI\n");
+ goto error_free_codec;
+ }
+
+ spi_set_drvdata(spi, ak4104);
+ dev_info(&spi->dev, "SPI device initialized\n");
+ return 0;
+
+error_free_codec:
+ kfree(ak4104);
+ ak4104_dai.dev = NULL;
+ return ret;
+}
+
+static int __devexit ak4104_spi_remove(struct spi_device *spi)
+{
+ int ret, val;
+ struct ak4104_private *ak4104 = spi_get_drvdata(spi);
+
+ val = ak4104_read_reg_cache(&ak4104->codec, AK4104_REG_CONTROL1);
+ if (val < 0)
+ return val;
+
+ /* clear power-up and non-reset bits */
+ val &= ~(AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
+ ret = ak4104_spi_write(&ak4104->codec, AK4104_REG_CONTROL1, val);
+ if (ret < 0)
+ return ret;
+
+ ak4104_codec = NULL;
+ kfree(ak4104);
+ return 0;
+}
+
+static int ak4104_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = ak4104_codec;
+ int ret;
+
+ /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */
+ socdev->card->codec = codec;
+
+ /* Register PCMs */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to create pcms\n");
+ return ret;
+ }
+
+ /* Register the socdev */
+ ret = snd_soc_init_card(socdev);
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to register card\n");
+ snd_soc_free_pcms(socdev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ak4104_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ snd_soc_free_pcms(socdev);
+ return 0;
+};
+
+struct snd_soc_codec_device soc_codec_device_ak4104 = {
+ .probe = ak4104_probe,
+ .remove = ak4104_remove
+};
+EXPORT_SYMBOL_GPL(soc_codec_device_ak4104);
+
+static struct spi_driver ak4104_spi_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ak4104_spi_probe,
+ .remove = __devexit_p(ak4104_spi_remove),
+};
+
+static int __init ak4104_init(void)
+{
+ pr_info("Asahi Kasei AK4104 ALSA SoC Codec Driver\n");
+ return spi_register_driver(&ak4104_spi_driver);
+}
+module_init(ak4104_init);
+
+static void __exit ak4104_exit(void)
+{
+ spi_unregister_driver(&ak4104_spi_driver);
+}
+module_exit(ak4104_exit);
+
+MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
+MODULE_DESCRIPTION("Asahi Kasei AK4104 ALSA SoC driver");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/codecs/ak4104.h b/sound/soc/codecs/ak4104.h
new file mode 100644
index 00000000000..eb88fe7e4de
--- /dev/null
+++ b/sound/soc/codecs/ak4104.h
@@ -0,0 +1,7 @@
+#ifndef _AK4104_H
+#define _AK4104_H
+
+extern struct snd_soc_dai ak4104_dai;
+extern struct snd_soc_codec_device soc_codec_device_ak4104;
+
+#endif
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 81300d8d42c..1f63d387a2f 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -155,21 +155,6 @@ static const struct snd_kcontrol_new ak4535_snd_controls[] = {
SOC_SINGLE("Mic Sidetone Volume", AK4535_VOL, 4, 7, 0),
};
-/* add non dapm controls */
-static int ak4535_add_controls(struct snd_soc_codec *codec)
-{
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(ak4535_snd_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&ak4535_snd_controls[i], codec, NULL));
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
/* Mono 1 Mixer */
static const struct snd_kcontrol_new ak4535_mono1_mixer_controls[] = {
SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4535_SIG1, 4, 1, 0),
@@ -344,7 +329,7 @@ static int ak4535_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct ak4535_priv *ak4535 = codec->private_data;
u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5);
int rate = params_rate(params), fs = 256;
@@ -436,6 +421,13 @@ static int ak4535_set_bias_level(struct snd_soc_codec *codec,
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+static struct snd_soc_dai_ops ak4535_dai_ops = {
+ .hw_params = ak4535_hw_params,
+ .set_fmt = ak4535_set_dai_fmt,
+ .digital_mute = ak4535_mute,
+ .set_sysclk = ak4535_set_dai_sysclk,
+};
+
struct snd_soc_dai ak4535_dai = {
.name = "AK4535",
.playback = {
@@ -450,19 +442,14 @@ struct snd_soc_dai ak4535_dai = {
.channels_max = 2,
.rates = AK4535_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = {
- .hw_params = ak4535_hw_params,
- .set_fmt = ak4535_set_dai_fmt,
- .digital_mute = ak4535_mute,
- .set_sysclk = ak4535_set_dai_sysclk,
- },
+ .ops = &ak4535_dai_ops,
};
EXPORT_SYMBOL_GPL(ak4535_dai);
static int ak4535_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
@@ -471,7 +458,7 @@ static int ak4535_suspend(struct platform_device *pdev, pm_message_t state)
static int ak4535_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
ak4535_sync(codec);
ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
ak4535_set_bias_level(codec, codec->suspend_bias_level);
@@ -484,7 +471,7 @@ static int ak4535_resume(struct platform_device *pdev)
*/
static int ak4535_init(struct snd_soc_device *socdev)
{
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int ret = 0;
codec->name = "AK4535";
@@ -510,7 +497,8 @@ static int ak4535_init(struct snd_soc_device *socdev)
/* power on device */
ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- ak4535_add_controls(codec);
+ snd_soc_add_controls(codec, ak4535_snd_controls,
+ ARRAY_SIZE(ak4535_snd_controls));
ak4535_add_widgets(codec);
ret = snd_soc_init_card(socdev);
if (ret < 0) {
@@ -537,7 +525,7 @@ static int ak4535_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct snd_soc_device *socdev = ak4535_socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int ret;
i2c_set_clientdata(i2c, codec);
@@ -636,7 +624,7 @@ static int ak4535_probe(struct platform_device *pdev)
}
codec->private_data = ak4535;
- socdev->codec = codec;
+ socdev->card->codec = codec;
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
@@ -663,7 +651,7 @@ static int ak4535_probe(struct platform_device *pdev)
static int ak4535_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
if (codec->control_data)
ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index f1aa0c34421..7fa09a38762 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -3,27 +3,22 @@
*
* Author: Timur Tabi <timur@freescale.com>
*
- * Copyright 2007 Freescale Semiconductor, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
+ * Copyright 2007-2009 Freescale Semiconductor, Inc. This file is licensed
+ * under the terms of the GNU General Public License version 2. This
+ * program is licensed "as is" without any warranty of any kind, whether
+ * express or implied.
*
* This is an ASoC device driver for the Cirrus Logic CS4270 codec.
*
* Current features/limitations:
*
- * 1) Software mode is supported. Stand-alone mode is automatically
- * selected if I2C is disabled or if a CS4270 is not found on the I2C
- * bus. However, stand-alone mode is only partially implemented because
- * there is no mechanism yet for this driver and the machine driver to
- * communicate the values of the M0, M1, MCLK1, and MCLK2 pins.
- * 2) Only I2C is supported, not SPI
- * 3) Only Master mode is supported, not Slave.
- * 4) The machine driver's 'startup' function must call
- * cs4270_set_dai_sysclk() with the value of MCLK.
- * 5) Only I2S and left-justified modes are supported
- * 6) Power management is not supported
- * 7) The only supported control is volume and hardware mute (if enabled)
+ * - Software mode is supported. Stand-alone mode is not supported.
+ * - Only I2C is supported, not SPI
+ * - Support for master and slave mode
+ * - The machine driver's 'startup' function must call
+ * cs4270_set_dai_sysclk() with the value of MCLK.
+ * - Only I2S and left-justified modes are supported
+ * - Power management is not supported
*/
#include <linux/module.h>
@@ -35,18 +30,6 @@
#include "cs4270.h"
-/* If I2C is defined, then we support software mode. However, if we're
- not compiled as module but I2C is, then we can't use I2C calls. */
-#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-#define USE_I2C
-#endif
-
-/* Private data for the CS4270 */
-struct cs4270_private {
- unsigned int mclk; /* Input frequency of the MCLK pin */
- unsigned int mode; /* The mode (I2S or left-justified) */
-};
-
/*
* The codec isn't really big-endian or little-endian, since the I2S
* interface requires data to be sent serially with the MSbit first.
@@ -60,8 +43,6 @@ struct cs4270_private {
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE)
-#ifdef USE_I2C
-
/* CS4270 registers addresses */
#define CS4270_CHIPID 0x01 /* Chip ID */
#define CS4270_PWRCTL 0x02 /* Power Control */
@@ -121,8 +102,22 @@ struct cs4270_private {
#define CS4270_MUTE_DAC_A 0x01
#define CS4270_MUTE_DAC_B 0x02
-/*
- * Clock Ratio Selection for Master Mode with I2C enabled
+/* Private data for the CS4270 */
+struct cs4270_private {
+ struct snd_soc_codec codec;
+ u8 reg_cache[CS4270_NUMREGS];
+ unsigned int mclk; /* Input frequency of the MCLK pin */
+ unsigned int mode; /* The mode (I2S or left-justified) */
+ unsigned int slave_mode;
+};
+
+/**
+ * struct cs4270_mode_ratios - clock ratio tables
+ * @ratio: the ratio of MCLK to the sample rate
+ * @speed_mode: the Speed Mode bits to set in the Mode Control register for
+ * this ratio
+ * @mclk: the Ratio Select bits to set in the Mode Control register for this
+ * ratio
*
* The data for this chart is taken from Table 5 of the CS4270 reference
* manual.
@@ -131,31 +126,30 @@ struct cs4270_private {
* It is also used by cs4270_set_dai_sysclk() to tell ALSA which sampling
* rates the CS4270 currently supports.
*
- * Each element in this array corresponds to the ratios in mclk_ratios[].
- * These two arrays need to be in sync.
- *
- * 'speed_mode' is the corresponding bit pattern to be written to the
+ * @speed_mode is the corresponding bit pattern to be written to the
* MODE bits of the Mode Control Register
*
- * 'mclk' is the corresponding bit pattern to be wirten to the MCLK bits of
+ * @mclk is the corresponding bit pattern to be wirten to the MCLK bits of
* the Mode Control Register.
*
* In situations where a single ratio is represented by multiple speed
* modes, we favor the slowest speed. E.g, for a ratio of 128, we pick
* double-speed instead of quad-speed. However, the CS4270 errata states
- * that Divide-By-1.5 can cause failures, so we avoid that mode where
+ * that divide-By-1.5 can cause failures, so we avoid that mode where
* possible.
*
- * ERRATA: There is an errata for the CS4270 where divide-by-1.5 does not
- * work if VD = 3.3V. If this effects you, select the
+ * Errata: There is an errata for the CS4270 where divide-by-1.5 does not
+ * work if Vd is 3.3V. If this effects you, select the
* CONFIG_SND_SOC_CS4270_VD33_ERRATA Kconfig option, and the driver will
* never select any sample rates that require divide-by-1.5.
*/
-static struct {
+struct cs4270_mode_ratios {
unsigned int ratio;
u8 speed_mode;
u8 mclk;
-} cs4270_mode_ratios[] = {
+};
+
+static struct cs4270_mode_ratios cs4270_mode_ratios[] = {
{64, CS4270_MODE_4X, CS4270_MODE_DIV1},
#ifndef CONFIG_SND_SOC_CS4270_VD33_ERRATA
{96, CS4270_MODE_4X, CS4270_MODE_DIV15},
@@ -172,34 +166,27 @@ static struct {
/* The number of MCLK/LRCK ratios supported by the CS4270 */
#define NUM_MCLK_RATIOS ARRAY_SIZE(cs4270_mode_ratios)
-/*
- * Determine the CS4270 samples rates.
+/**
+ * cs4270_set_dai_sysclk - determine the CS4270 samples rates.
+ * @codec_dai: the codec DAI
+ * @clk_id: the clock ID (ignored)
+ * @freq: the MCLK input frequency
+ * @dir: the clock direction (ignored)
*
- * 'freq' is the input frequency to MCLK. The other parameters are ignored.
+ * This function is used to tell the codec driver what the input MCLK
+ * frequency is.
*
* The value of MCLK is used to determine which sample rates are supported
* by the CS4270. The ratio of MCLK / Fs must be equal to one of nine
- * support values: 64, 96, 128, 192, 256, 384, 512, 768, and 1024.
+ * supported values - 64, 96, 128, 192, 256, 384, 512, 768, and 1024.
*
* This function calculates the nine ratios and determines which ones match
* a standard sample rate. If there's a match, then it is added to the list
- * of support sample rates.
+ * of supported sample rates.
*
* This function must be called by the machine driver's 'startup' function,
* otherwise the list of supported sample rates will not be available in
* time for ALSA.
- *
- * Note that in stand-alone mode, the sample rate is determined by input
- * pins M0, M1, MDIV1, and MDIV2. Also in stand-alone mode, divide-by-3
- * is not a programmable option. However, divide-by-3 is not an available
- * option in stand-alone mode. This cases two problems: a ratio of 768 is
- * not available (it requires divide-by-3) and B) ratios 192 and 384 can
- * only be selected with divide-by-1.5, but there is an errate that make
- * this selection difficult.
- *
- * In addition, there is no mechanism for communicating with the machine
- * driver what the input settings can be. This would need to be implemented
- * for stand-alone mode to work.
*/
static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
@@ -225,7 +212,7 @@ static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai,
rates &= ~SNDRV_PCM_RATE_KNOT;
if (!rates) {
- printk(KERN_ERR "cs4270: could not find a valid sample rate\n");
+ dev_err(codec->dev, "could not find a valid sample rate\n");
return -EINVAL;
}
@@ -240,8 +227,10 @@ static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai,
return 0;
}
-/*
- * Configure the codec for the selected audio format
+/**
+ * cs4270_set_dai_fmt - configure the codec for the selected audio format
+ * @codec_dai: the codec DAI
+ * @format: a SND_SOC_DAIFMT_x value indicating the data format
*
* This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the
* codec accordingly.
@@ -258,32 +247,43 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,
struct cs4270_private *cs4270 = codec->private_data;
int ret = 0;
+ /* set DAI format */
switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
case SND_SOC_DAIFMT_LEFT_J:
cs4270->mode = format & SND_SOC_DAIFMT_FORMAT_MASK;
break;
default:
- printk(KERN_ERR "cs4270: invalid DAI format\n");
+ dev_err(codec->dev, "invalid dai format\n");
+ ret = -EINVAL;
+ }
+
+ /* set master/slave audio interface */
+ switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ cs4270->slave_mode = 1;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ cs4270->slave_mode = 0;
+ break;
+ default:
+ /* all other modes are unsupported by the hardware */
ret = -EINVAL;
}
return ret;
}
-/*
- * A list of addresses on which this CS4270 could use. I2C addresses are
- * 7 bits. For the CS4270, the upper four bits are always 1001, and the
- * lower three bits are determined via the AD2, AD1, and AD0 pins
- * (respectively).
- */
-static const unsigned short normal_i2c[] = {
- 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, I2C_CLIENT_END
-};
-I2C_CLIENT_INSMOD;
-
-/*
- * Pre-fill the CS4270 register cache.
+/**
+ * cs4270_fill_cache - pre-fill the CS4270 register cache.
+ * @codec: the codec for this CS4270
+ *
+ * This function fills in the CS4270 register cache by reading the register
+ * values from the hardware.
+ *
+ * This CS4270 registers are cached to avoid excessive I2C I/O operations.
+ * After the initial read to pre-fill the cache, the CS4270 never updates
+ * the register values, so we won't have a cache coherency problem.
*
* We use the auto-increment feature of the CS4270 to read all registers in
* one shot.
@@ -298,7 +298,7 @@ static int cs4270_fill_cache(struct snd_soc_codec *codec)
CS4270_FIRSTREG | 0x80, CS4270_NUMREGS, cache);
if (length != CS4270_NUMREGS) {
- printk(KERN_ERR "cs4270: I2C read failure, addr=0x%x\n",
+ dev_err(codec->dev, "i2c read failure, addr=0x%x\n",
i2c_client->addr);
return -EIO;
}
@@ -306,12 +306,17 @@ static int cs4270_fill_cache(struct snd_soc_codec *codec)
return 0;
}
-/*
- * Read from the CS4270 register cache.
+/**
+ * cs4270_read_reg_cache - read from the CS4270 register cache.
+ * @codec: the codec for this CS4270
+ * @reg: the register to read
+ *
+ * This function returns the value for a given register. It reads only from
+ * the register cache, not the hardware itself.
*
* This CS4270 registers are cached to avoid excessive I2C I/O operations.
* After the initial read to pre-fill the cache, the CS4270 never updates
- * the register values, so we won't have a cache coherncy problem.
+ * the register values, so we won't have a cache coherency problem.
*/
static unsigned int cs4270_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
@@ -324,8 +329,11 @@ static unsigned int cs4270_read_reg_cache(struct snd_soc_codec *codec,
return cache[reg - CS4270_FIRSTREG];
}
-/*
- * Write to a CS4270 register via the I2C bus.
+/**
+ * cs4270_i2c_write - write to a CS4270 register via the I2C bus.
+ * @codec: the codec for this CS4270
+ * @reg: the register to write
+ * @value: the value to write to the register
*
* This function writes the given value to the given CS4270 register, and
* also updates the register cache.
@@ -346,7 +354,7 @@ static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg,
if (cache[reg - CS4270_FIRSTREG] != value) {
struct i2c_client *client = codec->control_data;
if (i2c_smbus_write_byte_data(client, reg, value)) {
- printk(KERN_ERR "cs4270: I2C write failed\n");
+ dev_err(codec->dev, "i2c write failed\n");
return -EIO;
}
@@ -357,11 +365,17 @@ static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg,
return 0;
}
-/*
- * Program the CS4270 with the given hardware parameters.
+/**
+ * cs4270_hw_params - program the CS4270 with the given hardware parameters.
+ * @substream: the audio stream
+ * @params: the hardware parameters to set
+ * @dai: the SOC DAI (ignored)
+ *
+ * This function programs the hardware with the values provided.
+ * Specifically, the sample rate and the data format.
*
- * The .ops functions are used to provide board-specific data, like
- * input frequencies, to this driver. This function takes that information,
+ * The .ops functions are used to provide board-specific data, like input
+ * frequencies, to this driver. This function takes that information,
* combines it with the hardware parameters provided, and programs the
* hardware accordingly.
*/
@@ -371,7 +385,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct cs4270_private *cs4270 = codec->private_data;
int ret;
unsigned int i;
@@ -391,33 +405,28 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
if (i == NUM_MCLK_RATIOS) {
/* We did not find a matching ratio */
- printk(KERN_ERR "cs4270: could not find matching ratio\n");
+ dev_err(codec->dev, "could not find matching ratio\n");
return -EINVAL;
}
- /* Freeze and power-down the codec */
-
- ret = snd_soc_write(codec, CS4270_PWRCTL, CS4270_PWRCTL_FREEZE |
- CS4270_PWRCTL_PDN_ADC | CS4270_PWRCTL_PDN_DAC |
- CS4270_PWRCTL_PDN);
- if (ret < 0) {
- printk(KERN_ERR "cs4270: I2C write failed\n");
- return ret;
- }
-
- /* Program the mode control register */
+ /* Set the sample rate */
reg = snd_soc_read(codec, CS4270_MODE);
reg &= ~(CS4270_MODE_SPEED_MASK | CS4270_MODE_DIV_MASK);
- reg |= cs4270_mode_ratios[i].speed_mode | cs4270_mode_ratios[i].mclk;
+ reg |= cs4270_mode_ratios[i].mclk;
+
+ if (cs4270->slave_mode)
+ reg |= CS4270_MODE_SLAVE;
+ else
+ reg |= cs4270_mode_ratios[i].speed_mode;
ret = snd_soc_write(codec, CS4270_MODE, reg);
if (ret < 0) {
- printk(KERN_ERR "cs4270: I2C write failed\n");
+ dev_err(codec->dev, "i2c write failed\n");
return ret;
}
- /* Program the format register */
+ /* Set the DAI format */
reg = snd_soc_read(codec, CS4270_FORMAT);
reg &= ~(CS4270_FORMAT_DAC_MASK | CS4270_FORMAT_ADC_MASK);
@@ -430,55 +439,23 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
reg |= CS4270_FORMAT_DAC_LJ | CS4270_FORMAT_ADC_LJ;
break;
default:
- printk(KERN_ERR "cs4270: unknown format\n");
+ dev_err(codec->dev, "unknown dai format\n");
return -EINVAL;
}
ret = snd_soc_write(codec, CS4270_FORMAT, reg);
if (ret < 0) {
- printk(KERN_ERR "cs4270: I2C write failed\n");
- return ret;
- }
-
- /* Disable auto-mute. This feature appears to be buggy, because in
- some situations, auto-mute will not deactivate when it should. */
-
- reg = snd_soc_read(codec, CS4270_MUTE);
- reg &= ~CS4270_MUTE_AUTO;
- ret = snd_soc_write(codec, CS4270_MUTE, reg);
- if (ret < 0) {
- printk(KERN_ERR "cs4270: I2C write failed\n");
- return ret;
- }
-
- /* Disable automatic volume control. It's enabled by default, and
- * it causes volume change commands to be delayed, sometimes until
- * after playback has started.
- */
-
- reg = cs4270_read_reg_cache(codec, CS4270_TRANS);
- reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO);
- ret = cs4270_i2c_write(codec, CS4270_TRANS, reg);
- if (ret < 0) {
- printk(KERN_ERR "I2C write failed\n");
- return ret;
- }
-
- /* Thaw and power-up the codec */
-
- ret = snd_soc_write(codec, CS4270_PWRCTL, 0);
- if (ret < 0) {
- printk(KERN_ERR "cs4270: I2C write failed\n");
+ dev_err(codec->dev, "i2c write failed\n");
return ret;
}
return ret;
}
-#ifdef CONFIG_SND_SOC_CS4270_HWMUTE
-
-/*
- * Set the CS4270 external mute
+/**
+ * cs4270_mute - enable/disable the CS4270 external mute
+ * @dai: the SOC DAI
+ * @mute: 0 = disable mute, 1 = enable mute
*
* This function toggles the mute bits in the MUTE register. The CS4270's
* mute capability is intended for external muting circuitry, so if the
@@ -493,276 +470,306 @@ static int cs4270_mute(struct snd_soc_dai *dai, int mute)
reg6 = snd_soc_read(codec, CS4270_MUTE);
if (mute)
- reg6 |= CS4270_MUTE_ADC_A | CS4270_MUTE_ADC_B |
- CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B;
+ reg6 |= CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B;
else
- reg6 &= ~(CS4270_MUTE_ADC_A | CS4270_MUTE_ADC_B |
- CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B);
+ reg6 &= ~(CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B);
return snd_soc_write(codec, CS4270_MUTE, reg6);
}
-#endif
-
-static int cs4270_i2c_probe(struct i2c_client *, const struct i2c_device_id *);
-
/* A list of non-DAPM controls that the CS4270 supports */
static const struct snd_kcontrol_new cs4270_snd_controls[] = {
SOC_DOUBLE_R("Master Playback Volume",
- CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 1)
-};
-
-static const struct i2c_device_id cs4270_id[] = {
- {"cs4270", 0},
- {}
-};
-MODULE_DEVICE_TABLE(i2c, cs4270_id);
-
-static struct i2c_driver cs4270_i2c_driver = {
- .driver = {
- .name = "CS4270 I2C",
- .owner = THIS_MODULE,
- },
- .id_table = cs4270_id,
- .probe = cs4270_i2c_probe,
+ CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 1),
+ SOC_SINGLE("Digital Sidetone Switch", CS4270_FORMAT, 5, 1, 0),
+ SOC_SINGLE("Soft Ramp Switch", CS4270_TRANS, 6, 1, 0),
+ SOC_SINGLE("Zero Cross Switch", CS4270_TRANS, 5, 1, 0),
+ SOC_SINGLE("Popguard Switch", CS4270_MODE, 0, 1, 1),
+ SOC_SINGLE("Auto-Mute Switch", CS4270_MUTE, 5, 1, 0),
+ SOC_DOUBLE("Master Capture Switch", CS4270_MUTE, 3, 4, 1, 0)
};
/*
- * Global variable to store socdev for i2c probe function.
+ * cs4270_codec - global variable to store codec for the ASoC probe function
*
* If struct i2c_driver had a private_data field, we wouldn't need to use
- * cs4270_socdec. This is the only way to pass the socdev structure to
- * cs4270_i2c_probe().
- *
- * The real solution to cs4270_socdev is to create a mechanism
- * that maps I2C addresses to snd_soc_device structures. Perhaps the
- * creation of the snd_soc_device object should be moved out of
- * cs4270_probe() and into cs4270_i2c_probe(), but that would make this
- * driver dependent on I2C. The CS4270 supports "stand-alone" mode, whereby
- * the chip is *not* connected to the I2C bus, but is instead configured via
- * input pins.
+ * cs4270_codec. This is the only way to pass the codec structure from
+ * cs4270_i2c_probe() to cs4270_probe(). Unfortunately, there is no good
+ * way to synchronize these two functions. cs4270_i2c_probe() can be called
+ * multiple times before cs4270_probe() is called even once. So for now, we
+ * also only allow cs4270_i2c_probe() to be run once. That means that we do
+ * not support more than one cs4270 device in the system, at least for now.
*/
-static struct snd_soc_device *cs4270_socdev;
+static struct snd_soc_codec *cs4270_codec;
-/*
- * Initialize the I2C interface of the CS4270
- *
- * This function is called for whenever the I2C subsystem finds a device
- * at a particular address.
+static struct snd_soc_dai_ops cs4270_dai_ops = {
+ .hw_params = cs4270_hw_params,
+ .set_sysclk = cs4270_set_dai_sysclk,
+ .set_fmt = cs4270_set_dai_fmt,
+ .digital_mute = cs4270_mute,
+};
+
+struct snd_soc_dai cs4270_dai = {
+ .name = "cs4270",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = 0,
+ .formats = CS4270_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = 0,
+ .formats = CS4270_FORMATS,
+ },
+ .ops = &cs4270_dai_ops,
+};
+EXPORT_SYMBOL_GPL(cs4270_dai);
+
+/**
+ * cs4270_probe - ASoC probe function
+ * @pdev: platform device
*
- * Note: snd_soc_new_pcms() must be called before this function can be called,
- * because of snd_ctl_add().
+ * This function is called when ASoC has all the pieces it needs to
+ * instantiate a sound driver.
*/
-static int cs4270_i2c_probe(struct i2c_client *i2c_client,
- const struct i2c_device_id *id)
+static int cs4270_probe(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = cs4270_socdev;
- struct snd_soc_codec *codec = socdev->codec;
- int i;
- int ret = 0;
-
- /* Probing all possible addresses has one drawback: if there are
- multiple CS4270s on the bus, then you cannot specify which
- socdev is matched with which CS4270. For now, we just reject
- this I2C device if the socdev already has one attached. */
- if (codec->control_data)
- return -ENODEV;
-
- /* Note: codec_dai->codec is NULL here */
-
- codec->reg_cache = kzalloc(CS4270_NUMREGS, GFP_KERNEL);
- if (!codec->reg_cache) {
- printk(KERN_ERR "cs4270: could not allocate register cache\n");
- ret = -ENOMEM;
- goto error;
- }
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = cs4270_codec;
+ int ret;
- /* Verify that we have a CS4270 */
+ /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */
+ socdev->card->codec = codec;
- ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);
+ /* Register PCMs */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if (ret < 0) {
- printk(KERN_ERR "cs4270: failed to read I2C\n");
- goto error;
- }
- /* The top four bits of the chip ID should be 1100. */
- if ((ret & 0xF0) != 0xC0) {
- /* The device at this address is not a CS4270 codec */
- ret = -ENODEV;
- goto error;
+ dev_err(codec->dev, "failed to create pcms\n");
+ return ret;
}
- printk(KERN_INFO "cs4270: found device at I2C address %X\n",
- i2c_client->addr);
- printk(KERN_INFO "cs4270: hardware revision %X\n", ret & 0xF);
-
- codec->control_data = i2c_client;
- codec->read = cs4270_read_reg_cache;
- codec->write = cs4270_i2c_write;
- codec->reg_cache_size = CS4270_NUMREGS;
-
- /* The I2C interface is set up, so pre-fill our register cache */
-
- ret = cs4270_fill_cache(codec);
+ /* Add the non-DAPM controls */
+ ret = snd_soc_add_controls(codec, cs4270_snd_controls,
+ ARRAY_SIZE(cs4270_snd_controls));
if (ret < 0) {
- printk(KERN_ERR "cs4270: failed to fill register cache\n");
- goto error;
+ dev_err(codec->dev, "failed to add controls\n");
+ goto error_free_pcms;
}
- /* Add the non-DAPM controls */
-
- for (i = 0; i < ARRAY_SIZE(cs4270_snd_controls); i++) {
- struct snd_kcontrol *kctrl =
- snd_soc_cnew(&cs4270_snd_controls[i], codec, NULL);
-
- ret = snd_ctl_add(codec->card, kctrl);
- if (ret < 0)
- goto error;
+ /* And finally, register the socdev */
+ ret = snd_soc_init_card(socdev);
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to register card\n");
+ goto error_free_pcms;
}
- i2c_set_clientdata(i2c_client, codec);
-
return 0;
-error:
- codec->control_data = NULL;
-
- kfree(codec->reg_cache);
- codec->reg_cache = NULL;
- codec->reg_cache_size = 0;
+error_free_pcms:
+ snd_soc_free_pcms(socdev);
return ret;
}
-#endif /* USE_I2C*/
+/**
+ * cs4270_remove - ASoC remove function
+ * @pdev: platform device
+ *
+ * This function is the counterpart to cs4270_probe().
+ */
+static int cs4270_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-struct snd_soc_dai cs4270_dai = {
- .name = "CS4270",
- .playback = {
- .stream_name = "Playback",
- .channels_min = 1,
- .channels_max = 2,
- .rates = 0,
- .formats = CS4270_FORMATS,
- },
- .capture = {
- .stream_name = "Capture",
- .channels_min = 1,
- .channels_max = 2,
- .rates = 0,
- .formats = CS4270_FORMATS,
- },
+ snd_soc_free_pcms(socdev);
+
+ return 0;
};
-EXPORT_SYMBOL_GPL(cs4270_dai);
-/*
- * ASoC probe function
+/**
+ * cs4270_i2c_probe - initialize the I2C interface of the CS4270
+ * @i2c_client: the I2C client object
+ * @id: the I2C device ID (ignored)
*
- * This function is called when the machine driver calls
- * platform_device_add().
+ * This function is called whenever the I2C subsystem finds a device that
+ * matches the device ID given via a prior call to i2c_add_driver().
*/
-static int cs4270_probe(struct platform_device *pdev)
+static int cs4270_i2c_probe(struct i2c_client *i2c_client,
+ const struct i2c_device_id *id)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec;
- int ret = 0;
+ struct cs4270_private *cs4270;
+ unsigned int reg;
+ int ret;
- printk(KERN_INFO "CS4270 ALSA SoC Codec\n");
+ /* For now, we only support one cs4270 device in the system. See the
+ * comment for cs4270_codec.
+ */
+ if (cs4270_codec) {
+ dev_err(&i2c_client->dev, "ignoring CS4270 at addr %X\n",
+ i2c_client->addr);
+ dev_err(&i2c_client->dev, "only one per board allowed\n");
+ /* Should we return something other than ENODEV here? */
+ return -ENODEV;
+ }
+
+ /* Verify that we have a CS4270 */
+
+ ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n",
+ i2c_client->addr);
+ return ret;
+ }
+ /* The top four bits of the chip ID should be 1100. */
+ if ((ret & 0xF0) != 0xC0) {
+ dev_err(&i2c_client->dev, "device at addr %X is not a CS4270\n",
+ i2c_client->addr);
+ return -ENODEV;
+ }
+
+ dev_info(&i2c_client->dev, "found device at i2c address %X\n",
+ i2c_client->addr);
+ dev_info(&i2c_client->dev, "hardware revision %X\n", ret & 0xF);
/* Allocate enough space for the snd_soc_codec structure
and our private data together. */
- codec = kzalloc(ALIGN(sizeof(struct snd_soc_codec), 4) +
- sizeof(struct cs4270_private), GFP_KERNEL);
- if (!codec) {
- printk(KERN_ERR "cs4270: Could not allocate codec structure\n");
+ cs4270 = kzalloc(sizeof(struct cs4270_private), GFP_KERNEL);
+ if (!cs4270) {
+ dev_err(&i2c_client->dev, "could not allocate codec\n");
return -ENOMEM;
}
+ codec = &cs4270->codec;
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
+ codec->dev = &i2c_client->dev;
codec->name = "CS4270";
codec->owner = THIS_MODULE;
codec->dai = &cs4270_dai;
codec->num_dai = 1;
- codec->private_data = (void *) codec +
- ALIGN(sizeof(struct snd_soc_codec), 4);
-
- socdev->codec = codec;
+ codec->private_data = cs4270;
+ codec->control_data = i2c_client;
+ codec->read = cs4270_read_reg_cache;
+ codec->write = cs4270_i2c_write;
+ codec->reg_cache = cs4270->reg_cache;
+ codec->reg_cache_size = CS4270_NUMREGS;
- /* Register PCMs */
+ /* The I2C interface is set up, so pre-fill our register cache */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ ret = cs4270_fill_cache(codec);
if (ret < 0) {
- printk(KERN_ERR "cs4270: failed to create PCMs\n");
+ dev_err(&i2c_client->dev, "failed to fill register cache\n");
goto error_free_codec;
}
-#ifdef USE_I2C
- cs4270_socdev = socdev;
+ /* Disable auto-mute. This feature appears to be buggy. In some
+ * situations, auto-mute will not deactivate when it should, so we want
+ * this feature disabled by default. An application (e.g. alsactl) can
+ * re-enabled it by using the controls.
+ */
- ret = i2c_add_driver(&cs4270_i2c_driver);
- if (ret) {
- printk(KERN_ERR "cs4270: failed to attach driver");
- goto error_free_pcms;
+ reg = cs4270_read_reg_cache(codec, CS4270_MUTE);
+ reg &= ~CS4270_MUTE_AUTO;
+ ret = cs4270_i2c_write(codec, CS4270_MUTE, reg);
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "i2c write failed\n");
+ return ret;
}
- /* Did we find a CS4270 on the I2C bus? */
- if (codec->control_data) {
- /* Initialize codec ops */
- cs4270_dai.ops.hw_params = cs4270_hw_params;
- cs4270_dai.ops.set_sysclk = cs4270_set_dai_sysclk;
- cs4270_dai.ops.set_fmt = cs4270_set_dai_fmt;
-#ifdef CONFIG_SND_SOC_CS4270_HWMUTE
- cs4270_dai.ops.digital_mute = cs4270_mute;
-#endif
- } else
- printk(KERN_INFO "cs4270: no I2C device found, "
- "using stand-alone mode\n");
-#else
- printk(KERN_INFO "cs4270: I2C disabled, using stand-alone mode\n");
-#endif
+ /* Disable automatic volume control. The hardware enables, and it
+ * causes volume change commands to be delayed, sometimes until after
+ * playback has started. An application (e.g. alsactl) can
+ * re-enabled it by using the controls.
+ */
- ret = snd_soc_init_card(socdev);
+ reg = cs4270_read_reg_cache(codec, CS4270_TRANS);
+ reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO);
+ ret = cs4270_i2c_write(codec, CS4270_TRANS, reg);
if (ret < 0) {
- printk(KERN_ERR "cs4270: failed to register card\n");
- goto error_del_driver;
+ dev_err(&i2c_client->dev, "i2c write failed\n");
+ return ret;
}
- return 0;
+ /* Initialize the DAI. Normally, we'd prefer to have a kmalloc'd DAI
+ * structure for each CS4270 device, but the machine driver needs to
+ * have a pointer to the DAI structure, so for now it must be a global
+ * variable.
+ */
+ cs4270_dai.dev = &i2c_client->dev;
-error_del_driver:
-#ifdef USE_I2C
- i2c_del_driver(&cs4270_i2c_driver);
+ /* Register the DAI. If all the other ASoC driver have already
+ * registered, then this will call our probe function, so
+ * cs4270_codec needs to be ready.
+ */
+ cs4270_codec = codec;
+ ret = snd_soc_register_dai(&cs4270_dai);
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "failed to register DAIe\n");
+ goto error_free_codec;
+ }
-error_free_pcms:
-#endif
- snd_soc_free_pcms(socdev);
+ i2c_set_clientdata(i2c_client, cs4270);
+
+ return 0;
error_free_codec:
- kfree(socdev->codec);
- socdev->codec = NULL;
+ kfree(cs4270);
+ cs4270_codec = NULL;
+ cs4270_dai.dev = NULL;
return ret;
}
-static int cs4270_remove(struct platform_device *pdev)
+/**
+ * cs4270_i2c_remove - remove an I2C device
+ * @i2c_client: the I2C client object
+ *
+ * This function is the counterpart to cs4270_i2c_probe().
+ */
+static int cs4270_i2c_remove(struct i2c_client *i2c_client)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
- snd_soc_free_pcms(socdev);
-
-#ifdef USE_I2C
- i2c_del_driver(&cs4270_i2c_driver);
-#endif
+ struct cs4270_private *cs4270 = i2c_get_clientdata(i2c_client);
- kfree(socdev->codec);
- socdev->codec = NULL;
+ kfree(cs4270);
+ cs4270_codec = NULL;
+ cs4270_dai.dev = NULL;
return 0;
}
/*
+ * cs4270_id - I2C device IDs supported by this driver
+ */
+static struct i2c_device_id cs4270_id[] = {
+ {"cs4270", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cs4270_id);
+
+/*
+ * cs4270_i2c_driver - I2C device identification
+ *
+ * This structure tells the I2C subsystem how to identify and support a
+ * given I2C device type.
+ */
+static struct i2c_driver cs4270_i2c_driver = {
+ .driver = {
+ .name = "cs4270",
+ .owner = THIS_MODULE,
+ },
+ .id_table = cs4270_id,
+ .probe = cs4270_i2c_probe,
+ .remove = cs4270_i2c_remove,
+};
+
+/*
* ASoC codec device structure
*
* Assign this variable to the codec_dev field of the machine driver's
@@ -776,13 +783,15 @@ EXPORT_SYMBOL_GPL(soc_codec_device_cs4270);
static int __init cs4270_init(void)
{
- return snd_soc_register_dai(&cs4270_dai);
+ pr_info("Cirrus Logic CS4270 ALSA SoC Codec Driver\n");
+
+ return i2c_add_driver(&cs4270_i2c_driver);
}
module_init(cs4270_init);
static void __exit cs4270_exit(void)
{
- snd_soc_unregister_dai(&cs4270_dai);
+ i2c_del_driver(&cs4270_i2c_driver);
}
module_exit(cs4270_exit);
diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c
index 9a3e67e5319..5cda9e6b5a7 100644
--- a/sound/soc/codecs/pcm3008.c
+++ b/sound/soc/codecs/pcm3008.c
@@ -67,11 +67,11 @@ static int pcm3008_soc_probe(struct platform_device *pdev)
printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION);
- socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (!socdev->codec)
+ socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (!socdev->card->codec)
return -ENOMEM;
- codec = socdev->codec;
+ codec = socdev->card->codec;
mutex_init(&codec->mutex);
codec->name = "PCM3008";
@@ -139,7 +139,7 @@ gpio_err:
card_err:
snd_soc_free_pcms(socdev);
pcm_err:
- kfree(socdev->codec);
+ kfree(socdev->card->codec);
return ret;
}
@@ -147,7 +147,7 @@ pcm_err:
static int pcm3008_soc_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct pcm3008_setup_data *setup = socdev->codec_data;
if (!codec)
@@ -155,7 +155,7 @@ static int pcm3008_soc_remove(struct platform_device *pdev)
pcm3008_gpio_free(setup);
snd_soc_free_pcms(socdev);
- kfree(socdev->codec);
+ kfree(socdev->card->codec);
return 0;
}
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index cac37361676..87f606c7682 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -151,21 +151,6 @@ SOC_ENUM("Capture Source", ssm2602_enum[0]),
SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]),
};
-/* add non dapm controls */
-static int ssm2602_add_controls(struct snd_soc_codec *codec)
-{
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(ssm2602_snd_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&ssm2602_snd_controls[i], codec, NULL));
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
/* Output Mixer */
static const struct snd_kcontrol_new ssm2602_output_mixer_controls[] = {
SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0),
@@ -291,7 +276,7 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
u16 srate;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct ssm2602_priv *ssm2602 = codec->private_data;
struct i2c_client *i2c = codec->control_data;
u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3;
@@ -336,7 +321,7 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct ssm2602_priv *ssm2602 = codec->private_data;
struct i2c_client *i2c = codec->control_data;
struct snd_pcm_runtime *master_runtime;
@@ -373,7 +358,7 @@ static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
/* set active */
ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
@@ -385,7 +370,7 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct ssm2602_priv *ssm2602 = codec->private_data;
/* deactivate */
if (!codec->active)
@@ -521,6 +506,16 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
#define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+static struct snd_soc_dai_ops ssm2602_dai_ops = {
+ .startup = ssm2602_startup,
+ .prepare = ssm2602_pcm_prepare,
+ .hw_params = ssm2602_hw_params,
+ .shutdown = ssm2602_shutdown,
+ .digital_mute = ssm2602_mute,
+ .set_sysclk = ssm2602_set_dai_sysclk,
+ .set_fmt = ssm2602_set_dai_fmt,
+};
+
struct snd_soc_dai ssm2602_dai = {
.name = "SSM2602",
.playback = {
@@ -535,22 +530,14 @@ struct snd_soc_dai ssm2602_dai = {
.channels_max = 2,
.rates = SSM2602_RATES,
.formats = SSM2602_FORMATS,},
- .ops = {
- .startup = ssm2602_startup,
- .prepare = ssm2602_pcm_prepare,
- .hw_params = ssm2602_hw_params,
- .shutdown = ssm2602_shutdown,
- .digital_mute = ssm2602_mute,
- .set_sysclk = ssm2602_set_dai_sysclk,
- .set_fmt = ssm2602_set_dai_fmt,
- }
+ .ops = &ssm2602_dai_ops,
};
EXPORT_SYMBOL_GPL(ssm2602_dai);
static int ssm2602_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
@@ -559,7 +546,7 @@ static int ssm2602_suspend(struct platform_device *pdev, pm_message_t state)
static int ssm2602_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -581,7 +568,7 @@ static int ssm2602_resume(struct platform_device *pdev)
*/
static int ssm2602_init(struct snd_soc_device *socdev)
{
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int reg, ret = 0;
codec->name = "SSM2602";
@@ -622,7 +609,8 @@ static int ssm2602_init(struct snd_soc_device *socdev)
APANA_ENABLE_MIC_BOOST);
ssm2602_write(codec, SSM2602_PWR, 0);
- ssm2602_add_controls(codec);
+ snd_soc_add_controls(codec, ssm2602_snd_controls,
+ ARRAY_SIZE(ssm2602_snd_controls));
ssm2602_add_widgets(codec);
ret = snd_soc_init_card(socdev);
if (ret < 0) {
@@ -653,7 +641,7 @@ static int ssm2602_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct snd_soc_device *socdev = ssm2602_socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int ret;
i2c_set_clientdata(i2c, codec);
@@ -747,7 +735,7 @@ static int ssm2602_probe(struct platform_device *pdev)
}
codec->private_data = ssm2602;
- socdev->codec = codec;
+ socdev->card->codec = codec;
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
@@ -768,7 +756,7 @@ static int ssm2602_probe(struct platform_device *pdev)
static int ssm2602_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
if (codec->control_data)
ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF);
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index cfdea007c4c..c3f4afb5d01 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -183,24 +183,6 @@ static const struct snd_kcontrol_new tlv320aic23_snd_controls[] = {
SOC_ENUM("Playback De-emphasis", tlv320aic23_deemph),
};
-/* add non dapm controls */
-static int tlv320aic23_add_controls(struct snd_soc_codec *codec)
-{
-
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(tlv320aic23_snd_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&tlv320aic23_snd_controls[i],
- codec, NULL));
- if (err < 0)
- return err;
- }
-
- return 0;
-
-}
-
/* PGA Mixer controls for Line and Mic switch */
static const struct snd_kcontrol_new tlv320aic23_output_mixer_controls[] = {
SOC_DAPM_SINGLE("Line Bypass Switch", TLV320AIC23_ANLG, 3, 1, 0),
@@ -423,7 +405,7 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
u16 iface_reg;
int ret;
struct aic23 *aic23 = container_of(codec, struct aic23, codec);
@@ -471,7 +453,7 @@ static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
/* set active */
tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001);
@@ -484,7 +466,7 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct aic23 *aic23 = container_of(codec, struct aic23, codec);
/* deactivate */
@@ -598,6 +580,15 @@ static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
#define AIC23_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+static struct snd_soc_dai_ops tlv320aic23_dai_ops = {
+ .prepare = tlv320aic23_pcm_prepare,
+ .hw_params = tlv320aic23_hw_params,
+ .shutdown = tlv320aic23_shutdown,
+ .digital_mute = tlv320aic23_mute,
+ .set_fmt = tlv320aic23_set_dai_fmt,
+ .set_sysclk = tlv320aic23_set_dai_sysclk,
+};
+
struct snd_soc_dai tlv320aic23_dai = {
.name = "tlv320aic23",
.playback = {
@@ -612,14 +603,7 @@ struct snd_soc_dai tlv320aic23_dai = {
.channels_max = 2,
.rates = AIC23_RATES,
.formats = AIC23_FORMATS,},
- .ops = {
- .prepare = tlv320aic23_pcm_prepare,
- .hw_params = tlv320aic23_hw_params,
- .shutdown = tlv320aic23_shutdown,
- .digital_mute = tlv320aic23_mute,
- .set_fmt = tlv320aic23_set_dai_fmt,
- .set_sysclk = tlv320aic23_set_dai_sysclk,
- }
+ .ops = &tlv320aic23_dai_ops,
};
EXPORT_SYMBOL_GPL(tlv320aic23_dai);
@@ -627,7 +611,7 @@ static int tlv320aic23_suspend(struct platform_device *pdev,
pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -638,7 +622,7 @@ static int tlv320aic23_suspend(struct platform_device *pdev,
static int tlv320aic23_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int i;
u16 reg;
@@ -660,7 +644,7 @@ static int tlv320aic23_resume(struct platform_device *pdev)
*/
static int tlv320aic23_init(struct snd_soc_device *socdev)
{
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int ret = 0;
u16 reg;
@@ -718,7 +702,8 @@ static int tlv320aic23_init(struct snd_soc_device *socdev)
tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x1);
- tlv320aic23_add_controls(codec);
+ snd_soc_add_controls(codec, tlv320aic23_snd_controls,
+ ARRAY_SIZE(tlv320aic23_snd_controls));
tlv320aic23_add_widgets(codec);
ret = snd_soc_init_card(socdev);
if (ret < 0) {
@@ -746,7 +731,7 @@ static int tlv320aic23_codec_probe(struct i2c_client *i2c,
const struct i2c_device_id *i2c_id)
{
struct snd_soc_device *socdev = tlv320aic23_socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int ret;
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -804,7 +789,7 @@ static int tlv320aic23_probe(struct platform_device *pdev)
if (aic23 == NULL)
return -ENOMEM;
codec = &aic23->codec;
- socdev->codec = codec;
+ socdev->card->codec = codec;
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
@@ -823,7 +808,7 @@ static int tlv320aic23_probe(struct platform_device *pdev)
static int tlv320aic23_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct aic23 *aic23 = container_of(codec, struct aic23, codec);
if (codec->control_data)
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index 29f2f1a017f..3387d9e736e 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -130,7 +130,7 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct aic26 *aic26 = codec->private_data;
int fsref, divisor, wlen, pval, jval, dval, qval;
u16 reg;
@@ -270,6 +270,13 @@ static int aic26_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
#define AIC26_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |\
SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
+static struct snd_soc_dai_ops aic26_dai_ops = {
+ .hw_params = aic26_hw_params,
+ .digital_mute = aic26_mute,
+ .set_sysclk = aic26_set_sysclk,
+ .set_fmt = aic26_set_fmt,
+};
+
struct snd_soc_dai aic26_dai = {
.name = "tlv320aic26",
.playback = {
@@ -286,12 +293,7 @@ struct snd_soc_dai aic26_dai = {
.rates = AIC26_RATES,
.formats = AIC26_FORMATS,
},
- .ops = {
- .hw_params = aic26_hw_params,
- .digital_mute = aic26_mute,
- .set_sysclk = aic26_set_sysclk,
- .set_fmt = aic26_set_fmt,
- },
+ .ops = &aic26_dai_ops,
};
EXPORT_SYMBOL_GPL(aic26_dai);
@@ -322,9 +324,8 @@ static int aic26_probe(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec;
- struct snd_kcontrol *kcontrol;
struct aic26 *aic26;
- int i, ret, err;
+ int ret, err;
dev_info(&pdev->dev, "Probing AIC26 SoC CODEC driver\n");
dev_dbg(&pdev->dev, "socdev=%p\n", socdev);
@@ -338,7 +339,7 @@ static int aic26_probe(struct platform_device *pdev)
return -ENODEV;
}
codec = &aic26->codec;
- socdev->codec = codec;
+ socdev->card->codec = codec;
dev_dbg(&pdev->dev, "Registering PCMs, dev=%p, socdev->dev=%p\n",
&pdev->dev, socdev->dev);
@@ -351,11 +352,9 @@ static int aic26_probe(struct platform_device *pdev)
/* register controls */
dev_dbg(&pdev->dev, "Registering controls\n");
- for (i = 0; i < ARRAY_SIZE(aic26_snd_controls); i++) {
- kcontrol = snd_soc_cnew(&aic26_snd_controls[i], codec, NULL);
- err = snd_ctl_add(codec->card, kcontrol);
- WARN_ON(err < 0);
- }
+ err = snd_soc_add_controls(codec, aic26_snd_controls,
+ ARRAY_SIZE(aic26_snd_controls));
+ WARN_ON(err < 0);
/* CODEC is setup, we can register the card now */
dev_dbg(&pdev->dev, "Registering card\n");
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index b47a749c5ea..ab099f48248 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -45,6 +45,7 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
+#include <sound/tlv.h>
#include "tlv320aic3x.h"
@@ -165,10 +166,13 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
- int reg = kcontrol->private_value & 0xff;
- int shift = (kcontrol->private_value >> 8) & 0x0f;
- int mask = (kcontrol->private_value >> 16) & 0xff;
- int invert = (kcontrol->private_value >> 24) & 0x01;
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int reg = mc->reg;
+ unsigned int shift = mc->shift;
+ int max = mc->max;
+ unsigned int mask = (1 << fls(max)) - 1;
+ unsigned int invert = mc->invert;
unsigned short val, val_mask;
int ret;
struct snd_soc_dapm_path *path;
@@ -247,56 +251,86 @@ static const struct soc_enum aic3x_enum[] = {
SOC_ENUM_DOUBLE(AIC3X_CODEC_DFILT_CTRL, 6, 4, 4, aic3x_adc_hpf),
};
+/*
+ * DAC digital volumes. From -63.5 to 0 dB in 0.5 dB steps
+ */
+static DECLARE_TLV_DB_SCALE(dac_tlv, -6350, 50, 0);
+/* ADC PGA gain volumes. From 0 to 59.5 dB in 0.5 dB steps */
+static DECLARE_TLV_DB_SCALE(adc_tlv, 0, 50, 0);
+/*
+ * Output stage volumes. From -78.3 to 0 dB. Muted below -78.3 dB.
+ * Step size is approximately 0.5 dB over most of the scale but increasing
+ * near the very low levels.
+ * Define dB scale so that it is mostly correct for range about -55 to 0 dB
+ * but having increasing dB difference below that (and where it doesn't count
+ * so much). This setting shows -50 dB (actual is -50.3 dB) for register
+ * value 100 and -58.5 dB (actual is -78.3 dB) for register value 117.
+ */
+static DECLARE_TLV_DB_SCALE(output_stage_tlv, -5900, 50, 1);
+
static const struct snd_kcontrol_new aic3x_snd_controls[] = {
/* Output */
- SOC_DOUBLE_R("PCM Playback Volume", LDAC_VOL, RDAC_VOL, 0, 0x7f, 1),
+ SOC_DOUBLE_R_TLV("PCM Playback Volume",
+ LDAC_VOL, RDAC_VOL, 0, 0x7f, 1, dac_tlv),
- SOC_DOUBLE_R("Line DAC Playback Volume", DACL1_2_LLOPM_VOL,
- DACR1_2_RLOPM_VOL, 0, 0x7f, 1),
+ SOC_DOUBLE_R_TLV("Line DAC Playback Volume",
+ DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL,
+ 0, 118, 1, output_stage_tlv),
SOC_SINGLE("LineL Playback Switch", LLOPM_CTRL, 3, 0x01, 0),
SOC_SINGLE("LineR Playback Switch", RLOPM_CTRL, 3, 0x01, 0),
- SOC_DOUBLE_R("LineL DAC Playback Volume", DACL1_2_LLOPM_VOL,
- DACR1_2_LLOPM_VOL, 0, 0x7f, 1),
- SOC_SINGLE("LineL Left PGA Bypass Playback Volume", PGAL_2_LLOPM_VOL,
- 0, 0x7f, 1),
- SOC_SINGLE("LineR Right PGA Bypass Playback Volume", PGAR_2_RLOPM_VOL,
- 0, 0x7f, 1),
- SOC_DOUBLE_R("LineL Line2 Bypass Playback Volume", LINE2L_2_LLOPM_VOL,
- LINE2R_2_LLOPM_VOL, 0, 0x7f, 1),
- SOC_DOUBLE_R("LineR Line2 Bypass Playback Volume", LINE2L_2_RLOPM_VOL,
- LINE2R_2_RLOPM_VOL, 0, 0x7f, 1),
-
- SOC_DOUBLE_R("Mono DAC Playback Volume", DACL1_2_MONOLOPM_VOL,
- DACR1_2_MONOLOPM_VOL, 0, 0x7f, 1),
+ SOC_DOUBLE_R_TLV("LineL DAC Playback Volume",
+ DACL1_2_LLOPM_VOL, DACR1_2_LLOPM_VOL,
+ 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("LineL Left PGA Bypass Playback Volume",
+ PGAL_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("LineR Right PGA Bypass Playback Volume",
+ PGAR_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_DOUBLE_R_TLV("LineL Line2 Bypass Playback Volume",
+ LINE2L_2_LLOPM_VOL, LINE2R_2_LLOPM_VOL,
+ 0, 118, 1, output_stage_tlv),
+ SOC_DOUBLE_R_TLV("LineR Line2 Bypass Playback Volume",
+ LINE2L_2_RLOPM_VOL, LINE2R_2_RLOPM_VOL,
+ 0, 118, 1, output_stage_tlv),
+
+ SOC_DOUBLE_R_TLV("Mono DAC Playback Volume",
+ DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL,
+ 0, 118, 1, output_stage_tlv),
SOC_SINGLE("Mono DAC Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
- SOC_DOUBLE_R("Mono PGA Bypass Playback Volume", PGAL_2_MONOLOPM_VOL,
- PGAR_2_MONOLOPM_VOL, 0, 0x7f, 1),
- SOC_DOUBLE_R("Mono Line2 Bypass Playback Volume", LINE2L_2_MONOLOPM_VOL,
- LINE2R_2_MONOLOPM_VOL, 0, 0x7f, 1),
-
- SOC_DOUBLE_R("HP DAC Playback Volume", DACL1_2_HPLOUT_VOL,
- DACR1_2_HPROUT_VOL, 0, 0x7f, 1),
+ SOC_DOUBLE_R_TLV("Mono PGA Bypass Playback Volume",
+ PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL,
+ 0, 118, 1, output_stage_tlv),
+ SOC_DOUBLE_R_TLV("Mono Line2 Bypass Playback Volume",
+ LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
+ 0, 118, 1, output_stage_tlv),
+
+ SOC_DOUBLE_R_TLV("HP DAC Playback Volume",
+ DACL1_2_HPLOUT_VOL, DACR1_2_HPROUT_VOL,
+ 0, 118, 1, output_stage_tlv),
SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
0x01, 0),
- SOC_DOUBLE_R("HP Right PGA Bypass Playback Volume", PGAR_2_HPLOUT_VOL,
- PGAR_2_HPROUT_VOL, 0, 0x7f, 1),
- SOC_SINGLE("HPL PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL,
- 0, 0x7f, 1),
- SOC_SINGLE("HPR PGA Bypass Playback Volume", PGAL_2_HPROUT_VOL,
- 0, 0x7f, 1),
- SOC_DOUBLE_R("HP Line2 Bypass Playback Volume", LINE2L_2_HPLOUT_VOL,
- LINE2R_2_HPROUT_VOL, 0, 0x7f, 1),
-
- SOC_DOUBLE_R("HPCOM DAC Playback Volume", DACL1_2_HPLCOM_VOL,
- DACR1_2_HPRCOM_VOL, 0, 0x7f, 1),
+ SOC_DOUBLE_R_TLV("HP Right PGA Bypass Playback Volume",
+ PGAR_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL,
+ 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("HPL PGA Bypass Playback Volume",
+ PGAL_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("HPR PGA Bypass Playback Volume",
+ PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_DOUBLE_R_TLV("HP Line2 Bypass Playback Volume",
+ LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
+ 0, 118, 1, output_stage_tlv),
+
+ SOC_DOUBLE_R_TLV("HPCOM DAC Playback Volume",
+ DACL1_2_HPLCOM_VOL, DACR1_2_HPRCOM_VOL,
+ 0, 118, 1, output_stage_tlv),
SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
0x01, 0),
- SOC_SINGLE("HPLCOM PGA Bypass Playback Volume", PGAL_2_HPLCOM_VOL,
- 0, 0x7f, 1),
- SOC_SINGLE("HPRCOM PGA Bypass Playback Volume", PGAL_2_HPRCOM_VOL,
- 0, 0x7f, 1),
- SOC_DOUBLE_R("HPCOM Line2 Bypass Playback Volume", LINE2L_2_HPLCOM_VOL,
- LINE2R_2_HPRCOM_VOL, 0, 0x7f, 1),
+ SOC_SINGLE_TLV("HPLCOM PGA Bypass Playback Volume",
+ PGAL_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_SINGLE_TLV("HPRCOM PGA Bypass Playback Volume",
+ PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
+ SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Playback Volume",
+ LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL,
+ 0, 118, 1, output_stage_tlv),
/*
* Note: enable Automatic input Gain Controller with care. It can
@@ -305,28 +339,13 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0),
/* Input */
- SOC_DOUBLE_R("PGA Capture Volume", LADC_VOL, RADC_VOL, 0, 0x7f, 0),
+ SOC_DOUBLE_R_TLV("PGA Capture Volume", LADC_VOL, RADC_VOL,
+ 0, 119, 0, adc_tlv),
SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1),
SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]),
};
-/* add non dapm controls */
-static int aic3x_add_controls(struct snd_soc_codec *codec)
-{
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(aic3x_snd_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&aic3x_snd_controls[i],
- codec, NULL));
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
/* Left DAC Mux */
static const struct snd_kcontrol_new aic3x_left_dac_mux_controls =
SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]);
@@ -743,7 +762,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct aic3x_priv *aic3x = codec->private_data;
int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
@@ -1069,6 +1088,13 @@ EXPORT_SYMBOL_GPL(aic3x_button_pressed);
#define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+static struct snd_soc_dai_ops aic3x_dai_ops = {
+ .hw_params = aic3x_hw_params,
+ .digital_mute = aic3x_mute,
+ .set_sysclk = aic3x_set_dai_sysclk,
+ .set_fmt = aic3x_set_dai_fmt,
+};
+
struct snd_soc_dai aic3x_dai = {
.name = "tlv320aic3x",
.playback = {
@@ -1083,19 +1109,14 @@ struct snd_soc_dai aic3x_dai = {
.channels_max = 2,
.rates = AIC3X_RATES,
.formats = AIC3X_FORMATS,},
- .ops = {
- .hw_params = aic3x_hw_params,
- .digital_mute = aic3x_mute,
- .set_sysclk = aic3x_set_dai_sysclk,
- .set_fmt = aic3x_set_dai_fmt,
- }
+ .ops = &aic3x_dai_ops,
};
EXPORT_SYMBOL_GPL(aic3x_dai);
static int aic3x_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -1105,7 +1126,7 @@ static int aic3x_suspend(struct platform_device *pdev, pm_message_t state)
static int aic3x_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u8 *cache = codec->reg_cache;
@@ -1128,7 +1149,7 @@ static int aic3x_resume(struct platform_device *pdev)
*/
static int aic3x_init(struct snd_soc_device *socdev)
{
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct aic3x_setup_data *setup = socdev->codec_data;
int reg, ret = 0;
@@ -1224,7 +1245,8 @@ static int aic3x_init(struct snd_soc_device *socdev)
aic3x_write(codec, AIC3X_GPIO1_REG, (setup->gpio_func[0] & 0xf) << 4);
aic3x_write(codec, AIC3X_GPIO2_REG, (setup->gpio_func[1] & 0xf) << 4);
- aic3x_add_controls(codec);
+ snd_soc_add_controls(codec, aic3x_snd_controls,
+ ARRAY_SIZE(aic3x_snd_controls));
aic3x_add_widgets(codec);
ret = snd_soc_init_card(socdev);
if (ret < 0) {
@@ -1258,7 +1280,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct snd_soc_device *socdev = aic3x_socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int ret;
i2c_set_clientdata(i2c, codec);
@@ -1363,7 +1385,7 @@ static int aic3x_probe(struct platform_device *pdev)
}
codec->private_data = aic3x;
- socdev->codec = codec;
+ socdev->card->codec = codec;
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
@@ -1389,7 +1411,7 @@ static int aic3x_probe(struct platform_device *pdev)
static int aic3x_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
/* power down chip */
if (codec->control_data)
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index ea370a4f86d..97738e2ece0 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -42,7 +42,7 @@
*/
static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
0x00, /* this register not used */
- 0x93, /* REG_CODEC_MODE (0x1) */
+ 0x91, /* REG_CODEC_MODE (0x1) */
0xc3, /* REG_OPTION (0x2) */
0x00, /* REG_UNKNOWN (0x3) */
0x00, /* REG_MICBIAS_CTL (0x4) */
@@ -117,6 +117,13 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
0x00, /* REG_MISC_SET_2 (0x49) */
};
+/* codec private data */
+struct twl4030_priv {
+ unsigned int bypass_state;
+ unsigned int codec_powered;
+ unsigned int codec_muted;
+};
+
/*
* read twl4030 register cache
*/
@@ -125,6 +132,9 @@ static inline unsigned int twl4030_read_reg_cache(struct snd_soc_codec *codec,
{
u8 *cache = codec->reg_cache;
+ if (reg >= TWL4030_CACHEREGNUM)
+ return -EIO;
+
return cache[reg];
}
@@ -151,26 +161,22 @@ static int twl4030_write(struct snd_soc_codec *codec,
return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg);
}
-static void twl4030_clear_codecpdz(struct snd_soc_codec *codec)
+static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
{
+ struct twl4030_priv *twl4030 = codec->private_data;
u8 mode;
- mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE);
- twl4030_write(codec, TWL4030_REG_CODEC_MODE,
- mode & ~TWL4030_CODECPDZ);
-
- /* REVISIT: this delay is present in TI sample drivers */
- /* but there seems to be no TRM requirement for it */
- udelay(10);
-}
-
-static void twl4030_set_codecpdz(struct snd_soc_codec *codec)
-{
- u8 mode;
+ if (enable == twl4030->codec_powered)
+ return;
mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE);
- twl4030_write(codec, TWL4030_REG_CODEC_MODE,
- mode | TWL4030_CODECPDZ);
+ if (enable)
+ mode |= TWL4030_CODECPDZ;
+ else
+ mode &= ~TWL4030_CODECPDZ;
+
+ twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
+ twl4030->codec_powered = enable;
/* REVISIT: this delay is present in TI sample drivers */
/* but there seems to be no TRM requirement for it */
@@ -182,7 +188,7 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
int i;
/* clear CODECPDZ prior to setting register defaults */
- twl4030_clear_codecpdz(codec);
+ twl4030_codec_enable(codec, 0);
/* set all audio section registers to reasonable defaults */
for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++)
@@ -190,6 +196,122 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
}
+static void twl4030_codec_mute(struct snd_soc_codec *codec, int mute)
+{
+ struct twl4030_priv *twl4030 = codec->private_data;
+ u8 reg_val;
+
+ if (mute == twl4030->codec_muted)
+ return;
+
+ if (mute) {
+ /* Bypass the reg_cache and mute the volumes
+ * Headset mute is done in it's own event handler
+ * Things to mute: Earpiece, PreDrivL/R, CarkitL/R
+ */
+ reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_EAR_CTL);
+ twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+ reg_val & (~TWL4030_EAR_GAIN),
+ TWL4030_REG_EAR_CTL);
+
+ reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PREDL_CTL);
+ twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+ reg_val & (~TWL4030_PREDL_GAIN),
+ TWL4030_REG_PREDL_CTL);
+ reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PREDR_CTL);
+ twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+ reg_val & (~TWL4030_PREDR_GAIN),
+ TWL4030_REG_PREDL_CTL);
+
+ reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PRECKL_CTL);
+ twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+ reg_val & (~TWL4030_PRECKL_GAIN),
+ TWL4030_REG_PRECKL_CTL);
+ reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PRECKR_CTL);
+ twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+ reg_val & (~TWL4030_PRECKL_GAIN),
+ TWL4030_REG_PRECKR_CTL);
+
+ /* Disable PLL */
+ reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL);
+ reg_val &= ~TWL4030_APLL_EN;
+ twl4030_write(codec, TWL4030_REG_APLL_CTL, reg_val);
+ } else {
+ /* Restore the volumes
+ * Headset mute is done in it's own event handler
+ * Things to restore: Earpiece, PreDrivL/R, CarkitL/R
+ */
+ twl4030_write(codec, TWL4030_REG_EAR_CTL,
+ twl4030_read_reg_cache(codec, TWL4030_REG_EAR_CTL));
+
+ twl4030_write(codec, TWL4030_REG_PREDL_CTL,
+ twl4030_read_reg_cache(codec, TWL4030_REG_PREDL_CTL));
+ twl4030_write(codec, TWL4030_REG_PREDR_CTL,
+ twl4030_read_reg_cache(codec, TWL4030_REG_PREDR_CTL));
+
+ twl4030_write(codec, TWL4030_REG_PRECKL_CTL,
+ twl4030_read_reg_cache(codec, TWL4030_REG_PRECKL_CTL));
+ twl4030_write(codec, TWL4030_REG_PRECKR_CTL,
+ twl4030_read_reg_cache(codec, TWL4030_REG_PRECKR_CTL));
+
+ /* Enable PLL */
+ reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL);
+ reg_val |= TWL4030_APLL_EN;
+ twl4030_write(codec, TWL4030_REG_APLL_CTL, reg_val);
+ }
+
+ twl4030->codec_muted = mute;
+}
+
+static void twl4030_power_up(struct snd_soc_codec *codec)
+{
+ struct twl4030_priv *twl4030 = codec->private_data;
+ u8 anamicl, regmisc1, byte;
+ int i = 0;
+
+ if (twl4030->codec_powered)
+ return;
+
+ /* set CODECPDZ to turn on codec */
+ twl4030_codec_enable(codec, 1);
+
+ /* initiate offset cancellation */
+ anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
+ twl4030_write(codec, TWL4030_REG_ANAMICL,
+ anamicl | TWL4030_CNCL_OFFSET_START);
+
+ /* wait for offset cancellation to complete */
+ do {
+ /* this takes a little while, so don't slam i2c */
+ udelay(2000);
+ twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
+ TWL4030_REG_ANAMICL);
+ } while ((i++ < 100) &&
+ ((byte & TWL4030_CNCL_OFFSET_START) ==
+ TWL4030_CNCL_OFFSET_START));
+
+ /* Make sure that the reg_cache has the same value as the HW */
+ twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte);
+
+ /* anti-pop when changing analog gain */
+ regmisc1 = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1);
+ twl4030_write(codec, TWL4030_REG_MISC_SET_1,
+ regmisc1 | TWL4030_SMOOTH_ANAVOL_EN);
+
+ /* toggle CODECPDZ as per TRM */
+ twl4030_codec_enable(codec, 0);
+ twl4030_codec_enable(codec, 1);
+}
+
+/*
+ * Unconditional power down
+ */
+static void twl4030_power_down(struct snd_soc_codec *codec)
+{
+ /* power down */
+ twl4030_codec_enable(codec, 0);
+}
+
/* Earpiece */
static const char *twl4030_earpiece_texts[] =
{"Off", "DACL1", "DACL2", "DACR1"};
@@ -366,6 +488,41 @@ static const struct soc_enum twl4030_micpathtx2_enum =
static const struct snd_kcontrol_new twl4030_dapm_micpathtx2_control =
SOC_DAPM_ENUM("Route", twl4030_micpathtx2_enum);
+/* Analog bypass for AudioR1 */
+static const struct snd_kcontrol_new twl4030_dapm_abypassr1_control =
+ SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXR1_APGA_CTL, 2, 1, 0);
+
+/* Analog bypass for AudioL1 */
+static const struct snd_kcontrol_new twl4030_dapm_abypassl1_control =
+ SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXL1_APGA_CTL, 2, 1, 0);
+
+/* Analog bypass for AudioR2 */
+static const struct snd_kcontrol_new twl4030_dapm_abypassr2_control =
+ SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXR2_APGA_CTL, 2, 1, 0);
+
+/* Analog bypass for AudioL2 */
+static const struct snd_kcontrol_new twl4030_dapm_abypassl2_control =
+ SOC_DAPM_SINGLE("Switch", TWL4030_REG_ARXL2_APGA_CTL, 2, 1, 0);
+
+/* Digital bypass gain, 0 mutes the bypass */
+static const unsigned int twl4030_dapm_dbypass_tlv[] = {
+ TLV_DB_RANGE_HEAD(2),
+ 0, 3, TLV_DB_SCALE_ITEM(-2400, 0, 1),
+ 4, 7, TLV_DB_SCALE_ITEM(-1800, 600, 0),
+};
+
+/* Digital bypass left (TX1L -> RX2L) */
+static const struct snd_kcontrol_new twl4030_dapm_dbypassl_control =
+ SOC_DAPM_SINGLE_TLV("Volume",
+ TWL4030_REG_ATX2ARXPGA, 3, 7, 0,
+ twl4030_dapm_dbypass_tlv);
+
+/* Digital bypass right (TX1R -> RX2R) */
+static const struct snd_kcontrol_new twl4030_dapm_dbypassr_control =
+ SOC_DAPM_SINGLE_TLV("Volume",
+ TWL4030_REG_ATX2ARXPGA, 0, 7, 0,
+ twl4030_dapm_dbypass_tlv);
+
static int micpath_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -420,6 +577,79 @@ static int handsfree_event(struct snd_soc_dapm_widget *w,
return 0;
}
+static int headsetl_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ unsigned char hs_gain, hs_pop;
+
+ /* Save the current volume */
+ hs_gain = twl4030_read_reg_cache(w->codec, TWL4030_REG_HS_GAIN_SET);
+ hs_pop = twl4030_read_reg_cache(w->codec, TWL4030_REG_HS_POPN_SET);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* Do the anti-pop/bias ramp enable according to the TRM */
+ hs_pop |= TWL4030_VMID_EN;
+ twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+ /* Is this needed? Can we just use whatever gain here? */
+ twl4030_write(w->codec, TWL4030_REG_HS_GAIN_SET,
+ (hs_gain & (~0x0f)) | 0x0a);
+ hs_pop |= TWL4030_RAMP_EN;
+ twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+
+ /* Restore the original volume */
+ twl4030_write(w->codec, TWL4030_REG_HS_GAIN_SET, hs_gain);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* Do the anti-pop/bias ramp disable according to the TRM */
+ hs_pop &= ~TWL4030_RAMP_EN;
+ twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+ /* Bypass the reg_cache to mute the headset */
+ twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
+ hs_gain & (~0x0f),
+ TWL4030_REG_HS_GAIN_SET);
+ hs_pop &= ~TWL4030_VMID_EN;
+ twl4030_write(w->codec, TWL4030_REG_HS_POPN_SET, hs_pop);
+ break;
+ }
+ return 0;
+}
+
+static int bypass_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct soc_mixer_control *m =
+ (struct soc_mixer_control *)w->kcontrols->private_value;
+ struct twl4030_priv *twl4030 = w->codec->private_data;
+ unsigned char reg;
+
+ reg = twl4030_read_reg_cache(w->codec, m->reg);
+
+ if (m->reg <= TWL4030_REG_ARXR2_APGA_CTL) {
+ /* Analog bypass */
+ if (reg & (1 << m->shift))
+ twl4030->bypass_state |=
+ (1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL));
+ else
+ twl4030->bypass_state &=
+ ~(1 << (m->reg - TWL4030_REG_ARXL1_APGA_CTL));
+ } else {
+ /* Digital bypass */
+ if (reg & (0x7 << m->shift))
+ twl4030->bypass_state |= (1 << (m->shift ? 5 : 4));
+ else
+ twl4030->bypass_state &= ~(1 << (m->shift ? 5 : 4));
+ }
+
+ if (w->codec->bias_level == SND_SOC_BIAS_STANDBY) {
+ if (twl4030->bypass_state)
+ twl4030_codec_mute(w->codec, 0);
+ else
+ twl4030_codec_mute(w->codec, 1);
+ }
+ return 0;
+}
+
/*
* Some of the gain controls in TWL (mostly those which are associated with
* the outputs) are implemented in an interesting way:
@@ -614,6 +844,17 @@ static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0);
*/
static DECLARE_TLV_DB_SCALE(input_gain_tlv, 0, 600, 0);
+static const char *twl4030_rampdelay_texts[] = {
+ "27/20/14 ms", "55/40/27 ms", "109/81/55 ms", "218/161/109 ms",
+ "437/323/218 ms", "874/645/437 ms", "1748/1291/874 ms",
+ "3495/2581/1748 ms"
+};
+
+static const struct soc_enum twl4030_rampdelay_enum =
+ SOC_ENUM_SINGLE(TWL4030_REG_HS_POPN_SET, 2,
+ ARRAY_SIZE(twl4030_rampdelay_texts),
+ twl4030_rampdelay_texts);
+
static const struct snd_kcontrol_new twl4030_snd_controls[] = {
/* Common playback gain controls */
SOC_DOUBLE_R_TLV("DAC1 Digital Fine Playback Volume",
@@ -668,23 +909,9 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = {
SOC_DOUBLE_TLV("Analog Capture Volume", TWL4030_REG_ANAMIC_GAIN,
0, 3, 5, 0, input_gain_tlv),
-};
-
-/* add non dapm controls */
-static int twl4030_add_controls(struct snd_soc_codec *codec)
-{
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(twl4030_snd_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&twl4030_snd_controls[i],
- codec, NULL));
- if (err < 0)
- return err;
- }
- return 0;
-}
+ SOC_ENUM("HS ramp delay", twl4030_rampdelay_enum),
+};
static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
/* Left channel inputs */
@@ -714,13 +941,13 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
/* DACs */
SND_SOC_DAPM_DAC("DAC Right1", "Right Front Playback",
- TWL4030_REG_AVDAC_CTL, 0, 0),
+ SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC("DAC Left1", "Left Front Playback",
- TWL4030_REG_AVDAC_CTL, 1, 0),
+ SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC("DAC Right2", "Right Rear Playback",
- TWL4030_REG_AVDAC_CTL, 2, 0),
+ SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC("DAC Left2", "Left Rear Playback",
- TWL4030_REG_AVDAC_CTL, 3, 0),
+ SND_SOC_NOPM, 0, 0),
/* Analog PGAs */
SND_SOC_DAPM_PGA("ARXR1_APGA", TWL4030_REG_ARXR1_APGA_CTL,
@@ -732,6 +959,37 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
SND_SOC_DAPM_PGA("ARXL2_APGA", TWL4030_REG_ARXL2_APGA_CTL,
0, 0, NULL, 0),
+ /* Analog bypasses */
+ SND_SOC_DAPM_SWITCH_E("Right1 Analog Loopback", SND_SOC_NOPM, 0, 0,
+ &twl4030_dapm_abypassr1_control, bypass_event,
+ SND_SOC_DAPM_POST_REG),
+ SND_SOC_DAPM_SWITCH_E("Left1 Analog Loopback", SND_SOC_NOPM, 0, 0,
+ &twl4030_dapm_abypassl1_control,
+ bypass_event, SND_SOC_DAPM_POST_REG),
+ SND_SOC_DAPM_SWITCH_E("Right2 Analog Loopback", SND_SOC_NOPM, 0, 0,
+ &twl4030_dapm_abypassr2_control,
+ bypass_event, SND_SOC_DAPM_POST_REG),
+ SND_SOC_DAPM_SWITCH_E("Left2 Analog Loopback", SND_SOC_NOPM, 0, 0,
+ &twl4030_dapm_abypassl2_control,
+ bypass_event, SND_SOC_DAPM_POST_REG),
+
+ /* Digital bypasses */
+ SND_SOC_DAPM_SWITCH_E("Left Digital Loopback", SND_SOC_NOPM, 0, 0,
+ &twl4030_dapm_dbypassl_control, bypass_event,
+ SND_SOC_DAPM_POST_REG),
+ SND_SOC_DAPM_SWITCH_E("Right Digital Loopback", SND_SOC_NOPM, 0, 0,
+ &twl4030_dapm_dbypassr_control, bypass_event,
+ SND_SOC_DAPM_POST_REG),
+
+ SND_SOC_DAPM_MIXER("Analog R1 Playback Mixer", TWL4030_REG_AVDAC_CTL,
+ 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("Analog L1 Playback Mixer", TWL4030_REG_AVDAC_CTL,
+ 1, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("Analog R2 Playback Mixer", TWL4030_REG_AVDAC_CTL,
+ 2, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("Analog L2 Playback Mixer", TWL4030_REG_AVDAC_CTL,
+ 3, 0, NULL, 0),
+
/* Output MUX controls */
/* Earpiece */
SND_SOC_DAPM_VALUE_MUX("Earpiece Mux", SND_SOC_NOPM, 0, 0,
@@ -742,8 +1000,9 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
SND_SOC_DAPM_VALUE_MUX("PredriveR Mux", SND_SOC_NOPM, 0, 0,
&twl4030_dapm_predriver_control),
/* HeadsetL/R */
- SND_SOC_DAPM_MUX("HeadsetL Mux", SND_SOC_NOPM, 0, 0,
- &twl4030_dapm_hsol_control),
+ SND_SOC_DAPM_MUX_E("HeadsetL Mux", SND_SOC_NOPM, 0, 0,
+ &twl4030_dapm_hsol_control, headsetl_event,
+ SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX("HeadsetR Mux", SND_SOC_NOPM, 0, 0,
&twl4030_dapm_hsor_control),
/* CarkitL/R */
@@ -782,16 +1041,16 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD|
SND_SOC_DAPM_POST_REG),
- /* Analog input muxes with power switch for the physical ADCL/R */
+ /* Analog input muxes with switch for the capture amplifiers */
SND_SOC_DAPM_VALUE_MUX("Analog Left Capture Route",
- TWL4030_REG_AVADC_CTL, 3, 0, &twl4030_dapm_analoglmic_control),
+ TWL4030_REG_ANAMICL, 4, 0, &twl4030_dapm_analoglmic_control),
SND_SOC_DAPM_VALUE_MUX("Analog Right Capture Route",
- TWL4030_REG_AVADC_CTL, 1, 0, &twl4030_dapm_analogrmic_control),
+ TWL4030_REG_ANAMICR, 4, 0, &twl4030_dapm_analogrmic_control),
- SND_SOC_DAPM_PGA("Analog Left Amplifier",
- TWL4030_REG_ANAMICL, 4, 0, NULL, 0),
- SND_SOC_DAPM_PGA("Analog Right Amplifier",
- TWL4030_REG_ANAMICR, 4, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ADC Physical Left",
+ TWL4030_REG_AVADC_CTL, 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ADC Physical Right",
+ TWL4030_REG_AVADC_CTL, 1, 0, NULL, 0),
SND_SOC_DAPM_PGA("Digimic0 Enable",
TWL4030_REG_ADCMICSEL, 1, 0, NULL, 0),
@@ -801,13 +1060,19 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
SND_SOC_DAPM_MICBIAS("Mic Bias 1", TWL4030_REG_MICBIAS_CTL, 0, 0),
SND_SOC_DAPM_MICBIAS("Mic Bias 2", TWL4030_REG_MICBIAS_CTL, 1, 0),
SND_SOC_DAPM_MICBIAS("Headset Mic Bias", TWL4030_REG_MICBIAS_CTL, 2, 0),
+
};
static const struct snd_soc_dapm_route intercon[] = {
- {"ARXL1_APGA", NULL, "DAC Left1"},
- {"ARXR1_APGA", NULL, "DAC Right1"},
- {"ARXL2_APGA", NULL, "DAC Left2"},
- {"ARXR2_APGA", NULL, "DAC Right2"},
+ {"Analog L1 Playback Mixer", NULL, "DAC Left1"},
+ {"Analog R1 Playback Mixer", NULL, "DAC Right1"},
+ {"Analog L2 Playback Mixer", NULL, "DAC Left2"},
+ {"Analog R2 Playback Mixer", NULL, "DAC Right2"},
+
+ {"ARXL1_APGA", NULL, "Analog L1 Playback Mixer"},
+ {"ARXR1_APGA", NULL, "Analog R1 Playback Mixer"},
+ {"ARXL2_APGA", NULL, "Analog L2 Playback Mixer"},
+ {"ARXR2_APGA", NULL, "Analog R2 Playback Mixer"},
/* Internal playback routings */
/* Earpiece */
@@ -865,23 +1130,23 @@ static const struct snd_soc_dapm_route intercon[] = {
{"Analog Right Capture Route", "Sub mic", "SUBMIC"},
{"Analog Right Capture Route", "AUXR", "AUXR"},
- {"Analog Left Amplifier", NULL, "Analog Left Capture Route"},
- {"Analog Right Amplifier", NULL, "Analog Right Capture Route"},
+ {"ADC Physical Left", NULL, "Analog Left Capture Route"},
+ {"ADC Physical Right", NULL, "Analog Right Capture Route"},
{"Digimic0 Enable", NULL, "DIGIMIC0"},
{"Digimic1 Enable", NULL, "DIGIMIC1"},
/* TX1 Left capture path */
- {"TX1 Capture Route", "Analog", "Analog Left Amplifier"},
+ {"TX1 Capture Route", "Analog", "ADC Physical Left"},
{"TX1 Capture Route", "Digimic0", "Digimic0 Enable"},
/* TX1 Right capture path */
- {"TX1 Capture Route", "Analog", "Analog Right Amplifier"},
+ {"TX1 Capture Route", "Analog", "ADC Physical Right"},
{"TX1 Capture Route", "Digimic0", "Digimic0 Enable"},
/* TX2 Left capture path */
- {"TX2 Capture Route", "Analog", "Analog Left Amplifier"},
+ {"TX2 Capture Route", "Analog", "ADC Physical Left"},
{"TX2 Capture Route", "Digimic1", "Digimic1 Enable"},
/* TX2 Right capture path */
- {"TX2 Capture Route", "Analog", "Analog Right Amplifier"},
+ {"TX2 Capture Route", "Analog", "ADC Physical Right"},
{"TX2 Capture Route", "Digimic1", "Digimic1 Enable"},
{"ADC Virtual Left1", NULL, "TX1 Capture Route"},
@@ -889,6 +1154,24 @@ static const struct snd_soc_dapm_route intercon[] = {
{"ADC Virtual Left2", NULL, "TX2 Capture Route"},
{"ADC Virtual Right2", NULL, "TX2 Capture Route"},
+ /* Analog bypass routes */
+ {"Right1 Analog Loopback", "Switch", "Analog Right Capture Route"},
+ {"Left1 Analog Loopback", "Switch", "Analog Left Capture Route"},
+ {"Right2 Analog Loopback", "Switch", "Analog Right Capture Route"},
+ {"Left2 Analog Loopback", "Switch", "Analog Left Capture Route"},
+
+ {"Analog R1 Playback Mixer", NULL, "Right1 Analog Loopback"},
+ {"Analog L1 Playback Mixer", NULL, "Left1 Analog Loopback"},
+ {"Analog R2 Playback Mixer", NULL, "Right2 Analog Loopback"},
+ {"Analog L2 Playback Mixer", NULL, "Left2 Analog Loopback"},
+
+ /* Digital bypass routes */
+ {"Right Digital Loopback", "Volume", "TX1 Capture Route"},
+ {"Left Digital Loopback", "Volume", "TX1 Capture Route"},
+
+ {"Analog R2 Playback Mixer", NULL, "Right Digital Loopback"},
+ {"Analog L2 Playback Mixer", NULL, "Left Digital Loopback"},
+
};
static int twl4030_add_widgets(struct snd_soc_codec *codec)
@@ -902,82 +1185,28 @@ static int twl4030_add_widgets(struct snd_soc_codec *codec)
return 0;
}
-static void twl4030_power_up(struct snd_soc_codec *codec)
-{
- u8 anamicl, regmisc1, byte, popn;
- int i = 0;
-
- /* set CODECPDZ to turn on codec */
- twl4030_set_codecpdz(codec);
-
- /* initiate offset cancellation */
- anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
- twl4030_write(codec, TWL4030_REG_ANAMICL,
- anamicl | TWL4030_CNCL_OFFSET_START);
-
-
- /* wait for offset cancellation to complete */
- do {
- /* this takes a little while, so don't slam i2c */
- udelay(2000);
- twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
- TWL4030_REG_ANAMICL);
- } while ((i++ < 100) &&
- ((byte & TWL4030_CNCL_OFFSET_START) ==
- TWL4030_CNCL_OFFSET_START));
-
- /* anti-pop when changing analog gain */
- regmisc1 = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1);
- twl4030_write(codec, TWL4030_REG_MISC_SET_1,
- regmisc1 | TWL4030_SMOOTH_ANAVOL_EN);
-
- /* toggle CODECPDZ as per TRM */
- twl4030_clear_codecpdz(codec);
- twl4030_set_codecpdz(codec);
-
- /* program anti-pop with bias ramp delay */
- popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
- popn &= TWL4030_RAMP_DELAY;
- popn |= TWL4030_RAMP_DELAY_645MS;
- twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn);
- popn |= TWL4030_VMID_EN;
- twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn);
-
- /* enable anti-pop ramp */
- popn |= TWL4030_RAMP_EN;
- twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn);
-}
-
-static void twl4030_power_down(struct snd_soc_codec *codec)
-{
- u8 popn;
-
- /* disable anti-pop ramp */
- popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
- popn &= ~TWL4030_RAMP_EN;
- twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn);
-
- /* disable bias out */
- popn &= ~TWL4030_VMID_EN;
- twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn);
-
- /* power down */
- twl4030_clear_codecpdz(codec);
-}
-
static int twl4030_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
+ struct twl4030_priv *twl4030 = codec->private_data;
+
switch (level) {
case SND_SOC_BIAS_ON:
- twl4030_power_up(codec);
+ twl4030_codec_mute(codec, 0);
break;
case SND_SOC_BIAS_PREPARE:
- /* TODO: develop a twl4030_prepare function */
+ twl4030_power_up(codec);
+ if (twl4030->bypass_state)
+ twl4030_codec_mute(codec, 0);
+ else
+ twl4030_codec_mute(codec, 1);
break;
case SND_SOC_BIAS_STANDBY:
- /* TODO: develop a twl4030_standby function */
- twl4030_power_down(codec);
+ twl4030_power_up(codec);
+ if (twl4030->bypass_state)
+ twl4030_codec_mute(codec, 0);
+ else
+ twl4030_codec_mute(codec, 1);
break;
case SND_SOC_BIAS_OFF:
twl4030_power_down(codec);
@@ -994,10 +1223,9 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
u8 mode, old_mode, format, old_format;
-
/* bit rate */
old_mode = twl4030_read_reg_cache(codec,
TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;
@@ -1039,8 +1267,9 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
if (mode != old_mode) {
/* change rate and set CODECPDZ */
+ twl4030_codec_enable(codec, 0);
twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
- twl4030_set_codecpdz(codec);
+ twl4030_codec_enable(codec, 1);
}
/* sample size */
@@ -1063,13 +1292,13 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
if (format != old_format) {
/* clear CODECPDZ before changing format (codec requirement) */
- twl4030_clear_codecpdz(codec);
+ twl4030_codec_enable(codec, 0);
/* change format */
twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
/* set CODECPDZ afterwards */
- twl4030_set_codecpdz(codec);
+ twl4030_codec_enable(codec, 1);
}
return 0;
}
@@ -1139,13 +1368,13 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
if (format != old_format) {
/* clear CODECPDZ before changing format (codec requirement) */
- twl4030_clear_codecpdz(codec);
+ twl4030_codec_enable(codec, 0);
/* change format */
twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
/* set CODECPDZ afterwards */
- twl4030_set_codecpdz(codec);
+ twl4030_codec_enable(codec, 1);
}
return 0;
@@ -1154,6 +1383,12 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
#define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000)
#define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE)
+static struct snd_soc_dai_ops twl4030_dai_ops = {
+ .hw_params = twl4030_hw_params,
+ .set_sysclk = twl4030_set_dai_sysclk,
+ .set_fmt = twl4030_set_dai_fmt,
+};
+
struct snd_soc_dai twl4030_dai = {
.name = "twl4030",
.playback = {
@@ -1168,18 +1403,14 @@ struct snd_soc_dai twl4030_dai = {
.channels_max = 2,
.rates = TWL4030_RATES,
.formats = TWL4030_FORMATS,},
- .ops = {
- .hw_params = twl4030_hw_params,
- .set_sysclk = twl4030_set_dai_sysclk,
- .set_fmt = twl4030_set_dai_fmt,
- }
+ .ops = &twl4030_dai_ops,
};
EXPORT_SYMBOL_GPL(twl4030_dai);
static int twl4030_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -1189,7 +1420,7 @@ static int twl4030_suspend(struct platform_device *pdev, pm_message_t state)
static int twl4030_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
twl4030_set_bias_level(codec, codec->suspend_bias_level);
@@ -1203,7 +1434,7 @@ static int twl4030_resume(struct platform_device *pdev)
static int twl4030_init(struct snd_soc_device *socdev)
{
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int ret = 0;
printk(KERN_INFO "TWL4030 Audio Codec init \n");
@@ -1233,7 +1464,8 @@ static int twl4030_init(struct snd_soc_device *socdev)
/* power on device */
twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- twl4030_add_controls(codec);
+ snd_soc_add_controls(codec, twl4030_snd_controls,
+ ARRAY_SIZE(twl4030_snd_controls));
twl4030_add_widgets(codec);
ret = snd_soc_init_card(socdev);
@@ -1258,12 +1490,20 @@ static int twl4030_probe(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec;
+ struct twl4030_priv *twl4030;
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
if (codec == NULL)
return -ENOMEM;
- socdev->codec = codec;
+ twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL);
+ if (twl4030 == NULL) {
+ kfree(codec);
+ return -ENOMEM;
+ }
+
+ codec->private_data = twl4030;
+ socdev->card->codec = codec;
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
@@ -1277,11 +1517,13 @@ static int twl4030_probe(struct platform_device *pdev)
static int twl4030_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
printk(KERN_INFO "TWL4030 Audio Codec remove\n");
+ twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev);
+ kfree(codec->private_data);
kfree(codec);
return 0;
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h
index 442e5a82861..33dbb144dad 100644
--- a/sound/soc/codecs/twl4030.h
+++ b/sound/soc/codecs/twl4030.h
@@ -170,6 +170,9 @@
#define TWL4030_CLK256FS_EN 0x02
#define TWL4030_AIF_EN 0x01
+/* EAR_CTL (0x21) */
+#define TWL4030_EAR_GAIN 0x30
+
/* HS_GAIN_SET (0x23) Fields */
#define TWL4030_HSR_GAIN 0x0C
@@ -198,6 +201,18 @@
#define TWL4030_RAMP_DELAY_2581MS 0x1C
#define TWL4030_RAMP_EN 0x02
+/* PREDL_CTL (0x25) */
+#define TWL4030_PREDL_GAIN 0x30
+
+/* PREDR_CTL (0x26) */
+#define TWL4030_PREDR_GAIN 0x30
+
+/* PRECKL_CTL (0x27) */
+#define TWL4030_PRECKL_GAIN 0x30
+
+/* PRECKR_CTL (0x28) */
+#define TWL4030_PRECKR_GAIN 0x30
+
/* HFL_CTL (0x29, 0x2A) Fields */
#define TWL4030_HF_CTL_HB_EN 0x04
#define TWL4030_HF_CTL_LOOP_EN 0x08
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index a2c5064a774..ddefb8f8014 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -173,7 +173,7 @@ static int uda134x_startup(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct uda134x_priv *uda134x = codec->private_data;
struct snd_pcm_runtime *master_runtime;
@@ -206,7 +206,7 @@ static void uda134x_shutdown(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct uda134x_priv *uda134x = codec->private_data;
if (uda134x->master_substream == substream)
@@ -221,7 +221,7 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct uda134x_priv *uda134x = codec->private_data;
u8 hw_params;
@@ -431,38 +431,14 @@ SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
};
-static int uda134x_add_controls(struct snd_soc_codec *codec)
-{
- int err, i, n;
- const struct snd_kcontrol_new *ctrls;
- struct uda134x_platform_data *pd = codec->control_data;
-
- switch (pd->model) {
- case UDA134X_UDA1340:
- case UDA134X_UDA1344:
- n = ARRAY_SIZE(uda1340_snd_controls);
- ctrls = uda1340_snd_controls;
- break;
- case UDA134X_UDA1341:
- n = ARRAY_SIZE(uda1341_snd_controls);
- ctrls = uda1341_snd_controls;
- break;
- default:
- printk(KERN_ERR "%s unkown codec type: %d",
- __func__, pd->model);
- return -EINVAL;
- }
-
- for (i = 0; i < n; i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&ctrls[i],
- codec, NULL));
- if (err < 0)
- return err;
- }
-
- return 0;
-}
+static struct snd_soc_dai_ops uda134x_dai_ops = {
+ .startup = uda134x_startup,
+ .shutdown = uda134x_shutdown,
+ .hw_params = uda134x_hw_params,
+ .digital_mute = uda134x_mute,
+ .set_sysclk = uda134x_set_dai_sysclk,
+ .set_fmt = uda134x_set_dai_fmt,
+};
struct snd_soc_dai uda134x_dai = {
.name = "UDA134X",
@@ -483,14 +459,7 @@ struct snd_soc_dai uda134x_dai = {
.formats = UDA134X_FORMATS,
},
/* pcm operations */
- .ops = {
- .startup = uda134x_startup,
- .shutdown = uda134x_shutdown,
- .hw_params = uda134x_hw_params,
- .digital_mute = uda134x_mute,
- .set_sysclk = uda134x_set_dai_sysclk,
- .set_fmt = uda134x_set_dai_fmt,
- }
+ .ops = &uda134x_dai_ops,
};
EXPORT_SYMBOL(uda134x_dai);
@@ -525,11 +494,11 @@ static int uda134x_soc_probe(struct platform_device *pdev)
return -EINVAL;
}
- socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (socdev->codec == NULL)
+ socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (socdev->card->codec == NULL)
return ret;
- codec = socdev->codec;
+ codec = socdev->card->codec;
uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL);
if (uda134x == NULL)
@@ -572,7 +541,22 @@ static int uda134x_soc_probe(struct platform_device *pdev)
goto pcm_err;
}
- ret = uda134x_add_controls(codec);
+ switch (pd->model) {
+ case UDA134X_UDA1340:
+ case UDA134X_UDA1344:
+ ret = snd_soc_add_controls(codec, uda1340_snd_controls,
+ ARRAY_SIZE(uda1340_snd_controls));
+ break;
+ case UDA134X_UDA1341:
+ ret = snd_soc_add_controls(codec, uda1341_snd_controls,
+ ARRAY_SIZE(uda1341_snd_controls));
+ break;
+ default:
+ printk(KERN_ERR "%s unkown codec type: %d",
+ __func__, pd->model);
+ return -EINVAL;
+ }
+
if (ret < 0) {
printk(KERN_ERR "UDA134X: failed to register controls\n");
goto pcm_err;
@@ -602,7 +586,7 @@ priv_err:
static int uda134x_soc_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -622,7 +606,7 @@ static int uda134x_soc_suspend(struct platform_device *pdev,
pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -632,7 +616,7 @@ static int uda134x_soc_suspend(struct platform_device *pdev,
static int uda134x_soc_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index e6bf0844fbf..5b21594e0e5 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -25,6 +25,7 @@
#include <linux/ioctl.h>
#include <linux/delay.h>
#include <linux/i2c.h>
+#include <linux/workqueue.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/initval.h>
@@ -35,7 +36,8 @@
#include "uda1380.h"
-#define UDA1380_VERSION "0.6"
+static struct work_struct uda1380_work;
+static struct snd_soc_codec *uda1380_codec;
/*
* uda1380 register cache
@@ -52,6 +54,8 @@ static const u16 uda1380_reg[UDA1380_CACHEREGNUM] = {
0x0000, 0x8000, 0x0002, 0x0000,
};
+static unsigned long uda1380_cache_dirty;
+
/*
* read uda1380 register cache
*/
@@ -73,8 +77,11 @@ static inline void uda1380_write_reg_cache(struct snd_soc_codec *codec,
u16 reg, unsigned int value)
{
u16 *cache = codec->reg_cache;
+
if (reg >= UDA1380_CACHEREGNUM)
return;
+ if ((reg >= 0x10) && (cache[reg] != value))
+ set_bit(reg - 0x10, &uda1380_cache_dirty);
cache[reg] = value;
}
@@ -113,6 +120,8 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
(data[0]<<8) | data[1]);
return -EIO;
}
+ if (reg >= 0x10)
+ clear_bit(reg - 0x10, &uda1380_cache_dirty);
return 0;
} else
return -EIO;
@@ -120,6 +129,20 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg,
#define uda1380_reset(c) uda1380_write(c, UDA1380_RESET, 0)
+static void uda1380_flush_work(struct work_struct *work)
+{
+ int bit, reg;
+
+ for_each_bit(bit, &uda1380_cache_dirty, UDA1380_CACHEREGNUM - 0x10) {
+ reg = 0x10 + bit;
+ pr_debug("uda1380: flush reg %x val %x:\n", reg,
+ uda1380_read_reg_cache(uda1380_codec, reg));
+ uda1380_write(uda1380_codec, reg,
+ uda1380_read_reg_cache(uda1380_codec, reg));
+ clear_bit(bit, &uda1380_cache_dirty);
+ }
+}
+
/* declarations of ALSA reg_elem_REAL controls */
static const char *uda1380_deemp[] = {
"None",
@@ -254,7 +277,6 @@ static const struct snd_kcontrol_new uda1380_snd_controls[] = {
SOC_SINGLE("DAC Polarity inverting Switch", UDA1380_MIXER, 15, 1, 0), /* DA_POL_INV */
SOC_ENUM("Noise Shaper", uda1380_sel_ns_enum), /* SEL_NS */
SOC_ENUM("Digital Mixer Signal Control", uda1380_mix_enum), /* MIX_POS, MIX */
- SOC_SINGLE("Silence Switch", UDA1380_MIXER, 7, 1, 0), /* SILENCE, force DAC output to silence */
SOC_SINGLE("Silence Detector Switch", UDA1380_MIXER, 6, 1, 0), /* SDET_ON */
SOC_ENUM("Silence Detector Setting", uda1380_sdet_enum), /* SD_VALUE */
SOC_ENUM("Oversampling Input", uda1380_os_enum), /* OS */
@@ -271,21 +293,6 @@ static const struct snd_kcontrol_new uda1380_snd_controls[] = {
SOC_SINGLE("AGC Switch", UDA1380_AGC, 0, 1, 0),
};
-/* add non dapm controls */
-static int uda1380_add_controls(struct snd_soc_codec *codec)
-{
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(uda1380_snd_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&uda1380_snd_controls[i], codec, NULL));
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
/* Input mux */
static const struct snd_kcontrol_new uda1380_input_mux_control =
SOC_DAPM_ENUM("Route", uda1380_input_sel_enum);
@@ -371,7 +378,7 @@ static int uda1380_add_widgets(struct snd_soc_codec *codec)
return 0;
}
-static int uda1380_set_dai_fmt(struct snd_soc_dai *codec_dai,
+static int uda1380_set_dai_fmt_both(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
@@ -381,61 +388,107 @@ static int uda1380_set_dai_fmt(struct snd_soc_dai *codec_dai,
iface = uda1380_read_reg_cache(codec, UDA1380_IFACE);
iface &= ~(R01_SFORI_MASK | R01_SIM | R01_SFORO_MASK);
- /* FIXME: how to select I2S for DATAO and MSB for DATAI correctly? */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
iface |= R01_SFORI_I2S | R01_SFORO_I2S;
break;
case SND_SOC_DAIFMT_LSB:
- iface |= R01_SFORI_LSB16 | R01_SFORO_I2S;
+ iface |= R01_SFORI_LSB16 | R01_SFORO_LSB16;
break;
case SND_SOC_DAIFMT_MSB:
- iface |= R01_SFORI_MSB | R01_SFORO_I2S;
+ iface |= R01_SFORI_MSB | R01_SFORO_MSB;
}
- if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
- iface |= R01_SIM;
+ /* DATAI is slave only, so in single-link mode, this has to be slave */
+ if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
+ return -EINVAL;
uda1380_write(codec, UDA1380_IFACE, iface);
return 0;
}
-/*
- * Flush reg cache
- * We can only write the interpolator and decimator registers
- * when the DAI is being clocked by the CPU DAI. It's up to the
- * machine and cpu DAI driver to do this before we are called.
- */
-static int uda1380_pcm_prepare(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+static int uda1380_set_dai_fmt_playback(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
- int reg, reg_start, reg_end, clk;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- reg_start = UDA1380_MVOL;
- reg_end = UDA1380_MIXER;
- } else {
- reg_start = UDA1380_DEC;
- reg_end = UDA1380_AGC;
+ struct snd_soc_codec *codec = codec_dai->codec;
+ int iface;
+
+ /* set up DAI based upon fmt */
+ iface = uda1380_read_reg_cache(codec, UDA1380_IFACE);
+ iface &= ~R01_SFORI_MASK;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ iface |= R01_SFORI_I2S;
+ break;
+ case SND_SOC_DAIFMT_LSB:
+ iface |= R01_SFORI_LSB16;
+ break;
+ case SND_SOC_DAIFMT_MSB:
+ iface |= R01_SFORI_MSB;
}
- /* FIXME disable DAC_CLK */
- clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
- uda1380_write(codec, UDA1380_CLK, clk & ~R00_DAC_CLK);
+ /* DATAI is slave only, so this has to be slave */
+ if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
+ return -EINVAL;
+
+ uda1380_write(codec, UDA1380_IFACE, iface);
+
+ return 0;
+}
+
+static int uda1380_set_dai_fmt_capture(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ int iface;
+
+ /* set up DAI based upon fmt */
+ iface = uda1380_read_reg_cache(codec, UDA1380_IFACE);
+ iface &= ~(R01_SIM | R01_SFORO_MASK);
- for (reg = reg_start; reg <= reg_end; reg++) {
- pr_debug("uda1380: flush reg %x val %x:", reg,
- uda1380_read_reg_cache(codec, reg));
- uda1380_write(codec, reg, uda1380_read_reg_cache(codec, reg));
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ iface |= R01_SFORO_I2S;
+ break;
+ case SND_SOC_DAIFMT_LSB:
+ iface |= R01_SFORO_LSB16;
+ break;
+ case SND_SOC_DAIFMT_MSB:
+ iface |= R01_SFORO_MSB;
}
- /* FIXME enable DAC_CLK */
- uda1380_write(codec, UDA1380_CLK, clk | R00_DAC_CLK);
+ if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
+ iface |= R01_SIM;
+ uda1380_write(codec, UDA1380_IFACE, iface);
+
+ return 0;
+}
+
+static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+ int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ uda1380_write_reg_cache(codec, UDA1380_MIXER,
+ mixer & ~R14_SILENCE);
+ schedule_work(&uda1380_work);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ uda1380_write_reg_cache(codec, UDA1380_MIXER,
+ mixer | R14_SILENCE);
+ schedule_work(&uda1380_work);
+ break;
+ }
return 0;
}
@@ -445,7 +498,7 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
/* set WSPLL power and divider if running from this clock */
@@ -484,7 +537,7 @@ static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
/* shut down WSPLL power if running from this clock */
@@ -501,24 +554,6 @@ static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream,
uda1380_write(codec, UDA1380_CLK, clk);
}
-static int uda1380_mute(struct snd_soc_dai *codec_dai, int mute)
-{
- struct snd_soc_codec *codec = codec_dai->codec;
- u16 mute_reg = uda1380_read_reg_cache(codec, UDA1380_DEEMP) & ~R13_MTM;
-
- /* FIXME: mute(codec,0) is called when the magician clock is already
- * set to WSPLL, but for some unknown reason writing to interpolator
- * registers works only when clocked by SYSCLK */
- u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
- uda1380_write(codec, UDA1380_CLK, ~R00_DAC_CLK & clk);
- if (mute)
- uda1380_write(codec, UDA1380_DEEMP, mute_reg | R13_MTM);
- else
- uda1380_write(codec, UDA1380_DEEMP, mute_reg);
- uda1380_write(codec, UDA1380_CLK, clk);
- return 0;
-}
-
static int uda1380_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
@@ -544,6 +579,27 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+static struct snd_soc_dai_ops uda1380_dai_ops = {
+ .hw_params = uda1380_pcm_hw_params,
+ .shutdown = uda1380_pcm_shutdown,
+ .trigger = uda1380_trigger,
+ .set_fmt = uda1380_set_dai_fmt_both,
+};
+
+static struct snd_soc_dai_ops uda1380_dai_ops_playback = {
+ .hw_params = uda1380_pcm_hw_params,
+ .shutdown = uda1380_pcm_shutdown,
+ .trigger = uda1380_trigger,
+ .set_fmt = uda1380_set_dai_fmt_playback,
+};
+
+static struct snd_soc_dai_ops uda1380_dai_ops_capture = {
+ .hw_params = uda1380_pcm_hw_params,
+ .shutdown = uda1380_pcm_shutdown,
+ .trigger = uda1380_trigger,
+ .set_fmt = uda1380_set_dai_fmt_capture,
+};
+
struct snd_soc_dai uda1380_dai[] = {
{
.name = "UDA1380",
@@ -559,13 +615,7 @@ struct snd_soc_dai uda1380_dai[] = {
.channels_max = 2,
.rates = UDA1380_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = {
- .hw_params = uda1380_pcm_hw_params,
- .shutdown = uda1380_pcm_shutdown,
- .prepare = uda1380_pcm_prepare,
- .digital_mute = uda1380_mute,
- .set_fmt = uda1380_set_dai_fmt,
- },
+ .ops = &uda1380_dai_ops,
},
{ /* playback only - dual interface */
.name = "UDA1380",
@@ -576,13 +626,7 @@ struct snd_soc_dai uda1380_dai[] = {
.rates = UDA1380_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
- .ops = {
- .hw_params = uda1380_pcm_hw_params,
- .shutdown = uda1380_pcm_shutdown,
- .prepare = uda1380_pcm_prepare,
- .digital_mute = uda1380_mute,
- .set_fmt = uda1380_set_dai_fmt,
- },
+ .ops = &uda1380_dai_ops_playback,
},
{ /* capture only - dual interface*/
.name = "UDA1380",
@@ -593,12 +637,7 @@ struct snd_soc_dai uda1380_dai[] = {
.rates = UDA1380_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
- .ops = {
- .hw_params = uda1380_pcm_hw_params,
- .shutdown = uda1380_pcm_shutdown,
- .prepare = uda1380_pcm_prepare,
- .set_fmt = uda1380_set_dai_fmt,
- },
+ .ops = &uda1380_dai_ops_capture,
},
};
EXPORT_SYMBOL_GPL(uda1380_dai);
@@ -606,7 +645,7 @@ EXPORT_SYMBOL_GPL(uda1380_dai);
static int uda1380_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
@@ -615,7 +654,7 @@ static int uda1380_suspend(struct platform_device *pdev, pm_message_t state)
static int uda1380_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -637,7 +676,7 @@ static int uda1380_resume(struct platform_device *pdev)
*/
static int uda1380_init(struct snd_soc_device *socdev, int dac_clk)
{
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int ret = 0;
codec->name = "UDA1380";
@@ -655,6 +694,9 @@ static int uda1380_init(struct snd_soc_device *socdev, int dac_clk)
codec->reg_cache_step = 1;
uda1380_reset(codec);
+ uda1380_codec = codec;
+ INIT_WORK(&uda1380_work, uda1380_flush_work);
+
/* register pcms */
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if (ret < 0) {
@@ -675,7 +717,8 @@ static int uda1380_init(struct snd_soc_device *socdev, int dac_clk)
}
/* uda1380 init */
- uda1380_add_controls(codec);
+ snd_soc_add_controls(codec, uda1380_snd_controls,
+ ARRAY_SIZE(uda1380_snd_controls));
uda1380_add_widgets(codec);
ret = snd_soc_init_card(socdev);
if (ret < 0) {
@@ -702,7 +745,7 @@ static int uda1380_i2c_probe(struct i2c_client *i2c,
{
struct snd_soc_device *socdev = uda1380_socdev;
struct uda1380_setup_data *setup = socdev->codec_data;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int ret;
i2c_set_clientdata(i2c, codec);
@@ -786,14 +829,12 @@ static int uda1380_probe(struct platform_device *pdev)
struct snd_soc_codec *codec;
int ret;
- pr_info("UDA1380 Audio Codec %s", UDA1380_VERSION);
-
setup = socdev->codec_data;
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
if (codec == NULL)
return -ENOMEM;
- socdev->codec = codec;
+ socdev->card->codec = codec;
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
@@ -817,7 +858,7 @@ static int uda1380_probe(struct platform_device *pdev)
static int uda1380_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
if (codec->control_data)
uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index e3989d406f5..3b1d0993bed 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2007, 2008 Wolfson Microelectronics PLC.
*
- * Author: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -51,10 +51,17 @@ struct wm8350_output {
u16 mute;
};
+struct wm8350_jack_data {
+ struct snd_soc_jack *jack;
+ int report;
+};
+
struct wm8350_data {
struct snd_soc_codec codec;
struct wm8350_output out1;
struct wm8350_output out2;
+ struct wm8350_jack_data hpl;
+ struct wm8350_jack_data hpr;
struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
};
@@ -775,21 +782,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Beep", NULL, "IN3R PGA"},
};
-static int wm8350_add_controls(struct snd_soc_codec *codec)
-{
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(wm8350_snd_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm8350_snd_controls[i],
- codec, NULL));
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
static int wm8350_add_widgets(struct snd_soc_codec *codec)
{
int ret;
@@ -1309,7 +1301,7 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec,
static int wm8350_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
@@ -1318,7 +1310,7 @@ static int wm8350_suspend(struct platform_device *pdev, pm_message_t state)
static int wm8350_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -1328,6 +1320,95 @@ static int wm8350_resume(struct platform_device *pdev)
return 0;
}
+static void wm8350_hp_jack_handler(struct wm8350 *wm8350, int irq, void *data)
+{
+ struct wm8350_data *priv = data;
+ u16 reg;
+ int report;
+ int mask;
+ struct wm8350_jack_data *jack = NULL;
+
+ switch (irq) {
+ case WM8350_IRQ_CODEC_JCK_DET_L:
+ jack = &priv->hpl;
+ mask = WM8350_JACK_L_LVL;
+ break;
+
+ case WM8350_IRQ_CODEC_JCK_DET_R:
+ jack = &priv->hpr;
+ mask = WM8350_JACK_R_LVL;
+ break;
+
+ default:
+ BUG();
+ }
+
+ if (!jack->jack) {
+ dev_warn(wm8350->dev, "Jack interrupt called with no jack\n");
+ return;
+ }
+
+ /* Debounce */
+ msleep(200);
+
+ reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS);
+ if (reg & mask)
+ report = jack->report;
+ else
+ report = 0;
+
+ snd_soc_jack_report(jack->jack, report, jack->report);
+}
+
+/**
+ * wm8350_hp_jack_detect - Enable headphone jack detection.
+ *
+ * @codec: WM8350 codec
+ * @which: left or right jack detect signal
+ * @jack: jack to report detection events on
+ * @report: value to report
+ *
+ * Enables the headphone jack detection of the WM8350.
+ */
+int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which,
+ struct snd_soc_jack *jack, int report)
+{
+ struct wm8350_data *priv = codec->private_data;
+ struct wm8350 *wm8350 = codec->control_data;
+ int irq;
+ int ena;
+
+ switch (which) {
+ case WM8350_JDL:
+ priv->hpl.jack = jack;
+ priv->hpl.report = report;
+ irq = WM8350_IRQ_CODEC_JCK_DET_L;
+ ena = WM8350_JDL_ENA;
+ break;
+
+ case WM8350_JDR:
+ priv->hpr.jack = jack;
+ priv->hpr.report = report;
+ irq = WM8350_IRQ_CODEC_JCK_DET_R;
+ ena = WM8350_JDR_ENA;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA);
+ wm8350_set_bits(wm8350, WM8350_JACK_DETECT, ena);
+
+ /* Sync status */
+ wm8350_hp_jack_handler(wm8350, irq, priv);
+
+ wm8350_unmask_irq(wm8350, irq);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_hp_jack_detect);
+
static struct snd_soc_codec *wm8350_codec;
static int wm8350_probe(struct platform_device *pdev)
@@ -1342,8 +1423,8 @@ static int wm8350_probe(struct platform_device *pdev)
BUG_ON(!wm8350_codec);
- socdev->codec = wm8350_codec;
- codec = socdev->codec;
+ socdev->card->codec = wm8350_codec;
+ codec = socdev->card->codec;
wm8350 = codec->control_data;
priv = codec->private_data;
@@ -1381,13 +1462,21 @@ static int wm8350_probe(struct platform_device *pdev)
wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME,
WM8350_OUT2_VU | WM8350_OUT2R_MUTE);
+ wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L);
+ wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R);
+ wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L,
+ wm8350_hp_jack_handler, priv);
+ wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R,
+ wm8350_hp_jack_handler, priv);
+
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if (ret < 0) {
dev_err(&pdev->dev, "failed to create pcms\n");
return ret;
}
- wm8350_add_controls(codec);
+ snd_soc_add_controls(codec, wm8350_snd_controls,
+ ARRAY_SIZE(wm8350_snd_controls));
wm8350_add_widgets(codec);
wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -1409,10 +1498,23 @@ card_err:
static int wm8350_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct wm8350 *wm8350 = codec->control_data;
+ struct wm8350_data *priv = codec->private_data;
int ret;
+ wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
+ WM8350_JDL_ENA | WM8350_JDR_ENA);
+ wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA);
+
+ wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L);
+ wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R);
+ wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L);
+ wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R);
+
+ priv->hpl.jack = NULL;
+ priv->hpr.jack = NULL;
+
/* cancel any work waiting to be queued. */
ret = cancel_delayed_work(&codec->delayed_work);
@@ -1436,6 +1538,16 @@ static int wm8350_remove(struct platform_device *pdev)
SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE)
+static struct snd_soc_dai_ops wm8350_dai_ops = {
+ .hw_params = wm8350_pcm_hw_params,
+ .digital_mute = wm8350_mute,
+ .trigger = wm8350_pcm_trigger,
+ .set_fmt = wm8350_set_dai_fmt,
+ .set_sysclk = wm8350_set_dai_sysclk,
+ .set_pll = wm8350_set_fll,
+ .set_clkdiv = wm8350_set_clkdiv,
+};
+
struct snd_soc_dai wm8350_dai = {
.name = "WM8350",
.playback = {
@@ -1452,15 +1564,7 @@ struct snd_soc_dai wm8350_dai = {
.rates = WM8350_RATES,
.formats = WM8350_FORMATS,
},
- .ops = {
- .hw_params = wm8350_pcm_hw_params,
- .digital_mute = wm8350_mute,
- .trigger = wm8350_pcm_trigger,
- .set_fmt = wm8350_set_dai_fmt,
- .set_sysclk = wm8350_set_dai_sysclk,
- .set_pll = wm8350_set_fll,
- .set_clkdiv = wm8350_set_clkdiv,
- },
+ .ops = &wm8350_dai_ops,
};
EXPORT_SYMBOL_GPL(wm8350_dai);
@@ -1472,7 +1576,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8350 = {
};
EXPORT_SYMBOL_GPL(soc_codec_dev_wm8350);
-static int wm8350_codec_probe(struct platform_device *pdev)
+static __devinit int wm8350_codec_probe(struct platform_device *pdev)
{
struct wm8350 *wm8350 = platform_get_drvdata(pdev);
struct wm8350_data *priv;
diff --git a/sound/soc/codecs/wm8350.h b/sound/soc/codecs/wm8350.h
index cc2887aa6c3..d11bd9288cf 100644
--- a/sound/soc/codecs/wm8350.h
+++ b/sound/soc/codecs/wm8350.h
@@ -17,4 +17,12 @@
extern struct snd_soc_dai wm8350_dai;
extern struct snd_soc_codec_device soc_codec_dev_wm8350;
+enum wm8350_jack {
+ WM8350_JDL = 1,
+ WM8350_JDR = 2,
+};
+
+int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which,
+ struct snd_soc_jack *jack, int report);
+
#endif
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
new file mode 100644
index 00000000000..510efa60400
--- /dev/null
+++ b/sound/soc/codecs/wm8400.c
@@ -0,0 +1,1582 @@
+/*
+ * wm8400.c -- WM8400 ALSA Soc Audio driver
+ *
+ * Copyright 2008, 2009 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/wm8400-audio.h>
+#include <linux/mfd/wm8400-private.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "wm8400.h"
+
+/* Fake register for internal state */
+#define WM8400_INTDRIVBITS (WM8400_REGISTER_COUNT + 1)
+#define WM8400_INMIXL_PWR 0
+#define WM8400_AINLMUX_PWR 1
+#define WM8400_INMIXR_PWR 2
+#define WM8400_AINRMUX_PWR 3
+
+static struct regulator_bulk_data power[] = {
+ {
+ .supply = "I2S1VDD",
+ },
+ {
+ .supply = "I2S2VDD",
+ },
+ {
+ .supply = "DCVDD",
+ },
+ {
+ .supply = "AVDD",
+ },
+ {
+ .supply = "FLLVDD",
+ },
+ {
+ .supply = "HPVDD",
+ },
+ {
+ .supply = "SPKVDD",
+ },
+};
+
+/* codec private data */
+struct wm8400_priv {
+ struct snd_soc_codec codec;
+ struct wm8400 *wm8400;
+ u16 fake_register;
+ unsigned int sysclk;
+ unsigned int pcmclk;
+ struct work_struct work;
+ int fll_in, fll_out;
+};
+
+static inline unsigned int wm8400_read(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ struct wm8400_priv *wm8400 = codec->private_data;
+
+ if (reg == WM8400_INTDRIVBITS)
+ return wm8400->fake_register;
+ else
+ return wm8400_reg_read(wm8400->wm8400, reg);
+}
+
+/*
+ * write to the wm8400 register space
+ */
+static int wm8400_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ struct wm8400_priv *wm8400 = codec->private_data;
+
+ if (reg == WM8400_INTDRIVBITS) {
+ wm8400->fake_register = value;
+ return 0;
+ } else
+ return wm8400_set_bits(wm8400->wm8400, reg, 0xffff, value);
+}
+
+static void wm8400_codec_reset(struct snd_soc_codec *codec)
+{
+ struct wm8400_priv *wm8400 = codec->private_data;
+
+ wm8400_reset_codec_reg_cache(wm8400->wm8400);
+}
+
+static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600);
+
+static const DECLARE_TLV_DB_LINEAR(in_pga_tlv, -1650, 3000);
+
+static const DECLARE_TLV_DB_LINEAR(out_mix_tlv, -2100, 0);
+
+static const DECLARE_TLV_DB_LINEAR(out_pga_tlv, -7300, 600);
+
+static const DECLARE_TLV_DB_LINEAR(out_omix_tlv, -600, 0);
+
+static const DECLARE_TLV_DB_LINEAR(out_dac_tlv, -7163, 0);
+
+static const DECLARE_TLV_DB_LINEAR(in_adc_tlv, -7163, 1763);
+
+static const DECLARE_TLV_DB_LINEAR(out_sidetone_tlv, -3600, 0);
+
+static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ int reg = mc->reg;
+ int ret;
+ u16 val;
+
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ if (ret < 0)
+ return ret;
+
+ /* now hit the volume update bits (always bit 8) */
+ val = wm8400_read(codec, reg);
+ return wm8400_write(codec, reg, val | 0x0100);
+}
+
+#define WM8400_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert, tlv_array) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
+ SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+ .tlv.p = (tlv_array), \
+ .info = snd_soc_info_volsw, \
+ .get = snd_soc_get_volsw, .put = wm8400_outpga_put_volsw_vu, \
+ .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
+
+
+static const char *wm8400_digital_sidetone[] =
+ {"None", "Left ADC", "Right ADC", "Reserved"};
+
+static const struct soc_enum wm8400_left_digital_sidetone_enum =
+SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE,
+ WM8400_ADC_TO_DACL_SHIFT, 2, wm8400_digital_sidetone);
+
+static const struct soc_enum wm8400_right_digital_sidetone_enum =
+SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE,
+ WM8400_ADC_TO_DACR_SHIFT, 2, wm8400_digital_sidetone);
+
+static const char *wm8400_adcmode[] =
+ {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"};
+
+static const struct soc_enum wm8400_right_adcmode_enum =
+SOC_ENUM_SINGLE(WM8400_ADC_CTRL, WM8400_ADC_HPF_CUT_SHIFT, 3, wm8400_adcmode);
+
+static const struct snd_kcontrol_new wm8400_snd_controls[] = {
+/* INMIXL */
+SOC_SINGLE("LIN12 PGA Boost", WM8400_INPUT_MIXER3, WM8400_L12MNBST_SHIFT,
+ 1, 0),
+SOC_SINGLE("LIN34 PGA Boost", WM8400_INPUT_MIXER3, WM8400_L34MNBST_SHIFT,
+ 1, 0),
+/* INMIXR */
+SOC_SINGLE("RIN12 PGA Boost", WM8400_INPUT_MIXER3, WM8400_R12MNBST_SHIFT,
+ 1, 0),
+SOC_SINGLE("RIN34 PGA Boost", WM8400_INPUT_MIXER3, WM8400_R34MNBST_SHIFT,
+ 1, 0),
+
+/* LOMIX */
+SOC_SINGLE_TLV("LOMIX LIN3 Bypass Volume", WM8400_OUTPUT_MIXER3,
+ WM8400_LLI3LOVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX RIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER3,
+ WM8400_LR12LOVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX LIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER3,
+ WM8400_LL12LOVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX RIN3 Bypass Volume", WM8400_OUTPUT_MIXER5,
+ WM8400_LRI3LOVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX AINRMUX Bypass Volume", WM8400_OUTPUT_MIXER5,
+ WM8400_LRBLOVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("LOMIX AINLMUX Bypass Volume", WM8400_OUTPUT_MIXER5,
+ WM8400_LRBLOVOL_SHIFT, 7, 0, out_mix_tlv),
+
+/* ROMIX */
+SOC_SINGLE_TLV("ROMIX RIN3 Bypass Volume", WM8400_OUTPUT_MIXER4,
+ WM8400_RRI3ROVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX LIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER4,
+ WM8400_RL12ROVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX RIN12 PGA Bypass Volume", WM8400_OUTPUT_MIXER4,
+ WM8400_RR12ROVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX LIN3 Bypass Volume", WM8400_OUTPUT_MIXER6,
+ WM8400_RLI3ROVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX AINLMUX Bypass Volume", WM8400_OUTPUT_MIXER6,
+ WM8400_RLBROVOL_SHIFT, 7, 0, out_mix_tlv),
+SOC_SINGLE_TLV("ROMIX AINRMUX Bypass Volume", WM8400_OUTPUT_MIXER6,
+ WM8400_RRBROVOL_SHIFT, 7, 0, out_mix_tlv),
+
+/* LOUT */
+WM8400_OUTPGA_SINGLE_R_TLV("LOUT Volume", WM8400_LEFT_OUTPUT_VOLUME,
+ WM8400_LOUTVOL_SHIFT, WM8400_LOUTVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("LOUT ZC", WM8400_LEFT_OUTPUT_VOLUME, WM8400_LOZC_SHIFT, 1, 0),
+
+/* ROUT */
+WM8400_OUTPGA_SINGLE_R_TLV("ROUT Volume", WM8400_RIGHT_OUTPUT_VOLUME,
+ WM8400_ROUTVOL_SHIFT, WM8400_ROUTVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("ROUT ZC", WM8400_RIGHT_OUTPUT_VOLUME, WM8400_ROZC_SHIFT, 1, 0),
+
+/* LOPGA */
+WM8400_OUTPGA_SINGLE_R_TLV("LOPGA Volume", WM8400_LEFT_OPGA_VOLUME,
+ WM8400_LOPGAVOL_SHIFT, WM8400_LOPGAVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("LOPGA ZC Switch", WM8400_LEFT_OPGA_VOLUME,
+ WM8400_LOPGAZC_SHIFT, 1, 0),
+
+/* ROPGA */
+WM8400_OUTPGA_SINGLE_R_TLV("ROPGA Volume", WM8400_RIGHT_OPGA_VOLUME,
+ WM8400_ROPGAVOL_SHIFT, WM8400_ROPGAVOL_MASK, 0, out_pga_tlv),
+SOC_SINGLE("ROPGA ZC Switch", WM8400_RIGHT_OPGA_VOLUME,
+ WM8400_ROPGAZC_SHIFT, 1, 0),
+
+SOC_SINGLE("LON Mute Switch", WM8400_LINE_OUTPUTS_VOLUME,
+ WM8400_LONMUTE_SHIFT, 1, 0),
+SOC_SINGLE("LOP Mute Switch", WM8400_LINE_OUTPUTS_VOLUME,
+ WM8400_LOPMUTE_SHIFT, 1, 0),
+SOC_SINGLE("LOP Attenuation Switch", WM8400_LINE_OUTPUTS_VOLUME,
+ WM8400_LOATTN_SHIFT, 1, 0),
+SOC_SINGLE("RON Mute Switch", WM8400_LINE_OUTPUTS_VOLUME,
+ WM8400_RONMUTE_SHIFT, 1, 0),
+SOC_SINGLE("ROP Mute Switch", WM8400_LINE_OUTPUTS_VOLUME,
+ WM8400_ROPMUTE_SHIFT, 1, 0),
+SOC_SINGLE("ROP Attenuation Switch", WM8400_LINE_OUTPUTS_VOLUME,
+ WM8400_ROATTN_SHIFT, 1, 0),
+
+SOC_SINGLE("OUT3 Mute Switch", WM8400_OUT3_4_VOLUME,
+ WM8400_OUT3MUTE_SHIFT, 1, 0),
+SOC_SINGLE("OUT3 Attenuation Switch", WM8400_OUT3_4_VOLUME,
+ WM8400_OUT3ATTN_SHIFT, 1, 0),
+
+SOC_SINGLE("OUT4 Mute Switch", WM8400_OUT3_4_VOLUME,
+ WM8400_OUT4MUTE_SHIFT, 1, 0),
+SOC_SINGLE("OUT4 Attenuation Switch", WM8400_OUT3_4_VOLUME,
+ WM8400_OUT4ATTN_SHIFT, 1, 0),
+
+SOC_SINGLE("Speaker Mode Switch", WM8400_CLASSD1,
+ WM8400_CDMODE_SHIFT, 1, 0),
+
+SOC_SINGLE("Speaker Output Attenuation Volume", WM8400_SPEAKER_VOLUME,
+ WM8400_SPKATTN_SHIFT, WM8400_SPKATTN_MASK, 0),
+SOC_SINGLE("Speaker DC Boost Volume", WM8400_CLASSD3,
+ WM8400_DCGAIN_SHIFT, 6, 0),
+SOC_SINGLE("Speaker AC Boost Volume", WM8400_CLASSD3,
+ WM8400_ACGAIN_SHIFT, 6, 0),
+
+WM8400_OUTPGA_SINGLE_R_TLV("Left DAC Digital Volume",
+ WM8400_LEFT_DAC_DIGITAL_VOLUME, WM8400_DACL_VOL_SHIFT,
+ 127, 0, out_dac_tlv),
+
+WM8400_OUTPGA_SINGLE_R_TLV("Right DAC Digital Volume",
+ WM8400_RIGHT_DAC_DIGITAL_VOLUME, WM8400_DACR_VOL_SHIFT,
+ 127, 0, out_dac_tlv),
+
+SOC_ENUM("Left Digital Sidetone", wm8400_left_digital_sidetone_enum),
+SOC_ENUM("Right Digital Sidetone", wm8400_right_digital_sidetone_enum),
+
+SOC_SINGLE_TLV("Left Digital Sidetone Volume", WM8400_DIGITAL_SIDE_TONE,
+ WM8400_ADCL_DAC_SVOL_SHIFT, 15, 0, out_sidetone_tlv),
+SOC_SINGLE_TLV("Right Digital Sidetone Volume", WM8400_DIGITAL_SIDE_TONE,
+ WM8400_ADCR_DAC_SVOL_SHIFT, 15, 0, out_sidetone_tlv),
+
+SOC_SINGLE("ADC Digital High Pass Filter Switch", WM8400_ADC_CTRL,
+ WM8400_ADC_HPF_ENA_SHIFT, 1, 0),
+
+SOC_ENUM("ADC HPF Mode", wm8400_right_adcmode_enum),
+
+WM8400_OUTPGA_SINGLE_R_TLV("Left ADC Digital Volume",
+ WM8400_LEFT_ADC_DIGITAL_VOLUME,
+ WM8400_ADCL_VOL_SHIFT,
+ WM8400_ADCL_VOL_MASK,
+ 0,
+ in_adc_tlv),
+
+WM8400_OUTPGA_SINGLE_R_TLV("Right ADC Digital Volume",
+ WM8400_RIGHT_ADC_DIGITAL_VOLUME,
+ WM8400_ADCR_VOL_SHIFT,
+ WM8400_ADCR_VOL_MASK,
+ 0,
+ in_adc_tlv),
+
+WM8400_OUTPGA_SINGLE_R_TLV("LIN12 Volume",
+ WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
+ WM8400_LIN12VOL_SHIFT,
+ WM8400_LIN12VOL_MASK,
+ 0,
+ in_pga_tlv),
+
+SOC_SINGLE("LIN12 ZC Switch", WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
+ WM8400_LI12ZC_SHIFT, 1, 0),
+
+SOC_SINGLE("LIN12 Mute Switch", WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
+ WM8400_LI12MUTE_SHIFT, 1, 0),
+
+WM8400_OUTPGA_SINGLE_R_TLV("LIN34 Volume",
+ WM8400_LEFT_LINE_INPUT_3_4_VOLUME,
+ WM8400_LIN34VOL_SHIFT,
+ WM8400_LIN34VOL_MASK,
+ 0,
+ in_pga_tlv),
+
+SOC_SINGLE("LIN34 ZC Switch", WM8400_LEFT_LINE_INPUT_3_4_VOLUME,
+ WM8400_LI34ZC_SHIFT, 1, 0),
+
+SOC_SINGLE("LIN34 Mute Switch", WM8400_LEFT_LINE_INPUT_3_4_VOLUME,
+ WM8400_LI34MUTE_SHIFT, 1, 0),
+
+WM8400_OUTPGA_SINGLE_R_TLV("RIN12 Volume",
+ WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
+ WM8400_RIN12VOL_SHIFT,
+ WM8400_RIN12VOL_MASK,
+ 0,
+ in_pga_tlv),
+
+SOC_SINGLE("RIN12 ZC Switch", WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
+ WM8400_RI12ZC_SHIFT, 1, 0),
+
+SOC_SINGLE("RIN12 Mute Switch", WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
+ WM8400_RI12MUTE_SHIFT, 1, 0),
+
+WM8400_OUTPGA_SINGLE_R_TLV("RIN34 Volume",
+ WM8400_RIGHT_LINE_INPUT_3_4_VOLUME,
+ WM8400_RIN34VOL_SHIFT,
+ WM8400_RIN34VOL_MASK,
+ 0,
+ in_pga_tlv),
+
+SOC_SINGLE("RIN34 ZC Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME,
+ WM8400_RI34ZC_SHIFT, 1, 0),
+
+SOC_SINGLE("RIN34 Mute Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME,
+ WM8400_RI34MUTE_SHIFT, 1, 0),
+
+};
+
+/* add non dapm controls */
+static int wm8400_add_controls(struct snd_soc_codec *codec)
+{
+ return snd_soc_add_controls(codec, wm8400_snd_controls,
+ ARRAY_SIZE(wm8400_snd_controls));
+}
+
+/*
+ * _DAPM_ Controls
+ */
+
+static int inmixer_event (struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ u16 reg, fakepower;
+
+ reg = wm8400_read(w->codec, WM8400_POWER_MANAGEMENT_2);
+ fakepower = wm8400_read(w->codec, WM8400_INTDRIVBITS);
+
+ if (fakepower & ((1 << WM8400_INMIXL_PWR) |
+ (1 << WM8400_AINLMUX_PWR))) {
+ reg |= WM8400_AINL_ENA;
+ } else {
+ reg &= ~WM8400_AINL_ENA;
+ }
+
+ if (fakepower & ((1 << WM8400_INMIXR_PWR) |
+ (1 << WM8400_AINRMUX_PWR))) {
+ reg |= WM8400_AINR_ENA;
+ } else {
+ reg &= ~WM8400_AINL_ENA;
+ }
+ wm8400_write(w->codec, WM8400_POWER_MANAGEMENT_2, reg);
+
+ return 0;
+}
+
+static int outmixer_event (struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol * kcontrol, int event)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ u32 reg_shift = mc->shift;
+ int ret = 0;
+ u16 reg;
+
+ switch (reg_shift) {
+ case WM8400_SPEAKER_MIXER | (WM8400_LDSPK << 8) :
+ reg = wm8400_read(w->codec, WM8400_OUTPUT_MIXER1);
+ if (reg & WM8400_LDLO) {
+ printk(KERN_WARNING
+ "Cannot set as Output Mixer 1 LDLO Set\n");
+ ret = -1;
+ }
+ break;
+ case WM8400_SPEAKER_MIXER | (WM8400_RDSPK << 8):
+ reg = wm8400_read(w->codec, WM8400_OUTPUT_MIXER2);
+ if (reg & WM8400_RDRO) {
+ printk(KERN_WARNING
+ "Cannot set as Output Mixer 2 RDRO Set\n");
+ ret = -1;
+ }
+ break;
+ case WM8400_OUTPUT_MIXER1 | (WM8400_LDLO << 8):
+ reg = wm8400_read(w->codec, WM8400_SPEAKER_MIXER);
+ if (reg & WM8400_LDSPK) {
+ printk(KERN_WARNING
+ "Cannot set as Speaker Mixer LDSPK Set\n");
+ ret = -1;
+ }
+ break;
+ case WM8400_OUTPUT_MIXER2 | (WM8400_RDRO << 8):
+ reg = wm8400_read(w->codec, WM8400_SPEAKER_MIXER);
+ if (reg & WM8400_RDSPK) {
+ printk(KERN_WARNING
+ "Cannot set as Speaker Mixer RDSPK Set\n");
+ ret = -1;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+/* INMIX dB values */
+static const unsigned int in_mix_tlv[] = {
+ TLV_DB_RANGE_HEAD(1),
+ 0,7, TLV_DB_LINEAR_ITEM(-1200, 600),
+};
+
+/* Left In PGA Connections */
+static const struct snd_kcontrol_new wm8400_dapm_lin12_pga_controls[] = {
+SOC_DAPM_SINGLE("LIN1 Switch", WM8400_INPUT_MIXER2, WM8400_LMN1_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LIN2 Switch", WM8400_INPUT_MIXER2, WM8400_LMP2_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8400_dapm_lin34_pga_controls[] = {
+SOC_DAPM_SINGLE("LIN3 Switch", WM8400_INPUT_MIXER2, WM8400_LMN3_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LIN4 Switch", WM8400_INPUT_MIXER2, WM8400_LMP4_SHIFT, 1, 0),
+};
+
+/* Right In PGA Connections */
+static const struct snd_kcontrol_new wm8400_dapm_rin12_pga_controls[] = {
+SOC_DAPM_SINGLE("RIN1 Switch", WM8400_INPUT_MIXER2, WM8400_RMN1_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("RIN2 Switch", WM8400_INPUT_MIXER2, WM8400_RMP2_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8400_dapm_rin34_pga_controls[] = {
+SOC_DAPM_SINGLE("RIN3 Switch", WM8400_INPUT_MIXER2, WM8400_RMN3_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("RIN4 Switch", WM8400_INPUT_MIXER2, WM8400_RMP4_SHIFT, 1, 0),
+};
+
+/* INMIXL */
+static const struct snd_kcontrol_new wm8400_dapm_inmixl_controls[] = {
+SOC_DAPM_SINGLE_TLV("Record Left Volume", WM8400_INPUT_MIXER3,
+ WM8400_LDBVOL_SHIFT, WM8400_LDBVOL_MASK, 0, in_mix_tlv),
+SOC_DAPM_SINGLE_TLV("LIN2 Volume", WM8400_INPUT_MIXER5, WM8400_LI2BVOL_SHIFT,
+ 7, 0, in_mix_tlv),
+SOC_DAPM_SINGLE("LINPGA12 Switch", WM8400_INPUT_MIXER3, WM8400_L12MNB_SHIFT,
+ 1, 0),
+SOC_DAPM_SINGLE("LINPGA34 Switch", WM8400_INPUT_MIXER3, WM8400_L34MNB_SHIFT,
+ 1, 0),
+};
+
+/* INMIXR */
+static const struct snd_kcontrol_new wm8400_dapm_inmixr_controls[] = {
+SOC_DAPM_SINGLE_TLV("Record Right Volume", WM8400_INPUT_MIXER4,
+ WM8400_RDBVOL_SHIFT, WM8400_RDBVOL_MASK, 0, in_mix_tlv),
+SOC_DAPM_SINGLE_TLV("RIN2 Volume", WM8400_INPUT_MIXER6, WM8400_RI2BVOL_SHIFT,
+ 7, 0, in_mix_tlv),
+SOC_DAPM_SINGLE("RINPGA12 Switch", WM8400_INPUT_MIXER3, WM8400_L12MNB_SHIFT,
+ 1, 0),
+SOC_DAPM_SINGLE("RINPGA34 Switch", WM8400_INPUT_MIXER3, WM8400_L34MNB_SHIFT,
+ 1, 0),
+};
+
+/* AINLMUX */
+static const char *wm8400_ainlmux[] =
+ {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"};
+
+static const struct soc_enum wm8400_ainlmux_enum =
+SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINLMODE_SHIFT,
+ ARRAY_SIZE(wm8400_ainlmux), wm8400_ainlmux);
+
+static const struct snd_kcontrol_new wm8400_dapm_ainlmux_controls =
+SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum);
+
+/* DIFFINL */
+
+/* AINRMUX */
+static const char *wm8400_ainrmux[] =
+ {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"};
+
+static const struct soc_enum wm8400_ainrmux_enum =
+SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINRMODE_SHIFT,
+ ARRAY_SIZE(wm8400_ainrmux), wm8400_ainrmux);
+
+static const struct snd_kcontrol_new wm8400_dapm_ainrmux_controls =
+SOC_DAPM_ENUM("Route", wm8400_ainrmux_enum);
+
+/* RXVOICE */
+static const struct snd_kcontrol_new wm8400_dapm_rxvoice_controls[] = {
+SOC_DAPM_SINGLE_TLV("LIN4/RXN", WM8400_INPUT_MIXER5, WM8400_LR4BVOL_SHIFT,
+ WM8400_LR4BVOL_MASK, 0, in_mix_tlv),
+SOC_DAPM_SINGLE_TLV("RIN4/RXP", WM8400_INPUT_MIXER6, WM8400_RL4BVOL_SHIFT,
+ WM8400_RL4BVOL_MASK, 0, in_mix_tlv),
+};
+
+/* LOMIX */
+static const struct snd_kcontrol_new wm8400_dapm_lomix_controls[] = {
+SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8400_OUTPUT_MIXER1,
+ WM8400_LRBLO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX Left ADC Bypass Switch", WM8400_OUTPUT_MIXER1,
+ WM8400_LLBLO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX RIN3 Bypass Switch", WM8400_OUTPUT_MIXER1,
+ WM8400_LRI3LO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX LIN3 Bypass Switch", WM8400_OUTPUT_MIXER1,
+ WM8400_LLI3LO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX RIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER1,
+ WM8400_LR12LO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX LIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER1,
+ WM8400_LL12LO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOMIX Left DAC Switch", WM8400_OUTPUT_MIXER1,
+ WM8400_LDLO_SHIFT, 1, 0),
+};
+
+/* ROMIX */
+static const struct snd_kcontrol_new wm8400_dapm_romix_controls[] = {
+SOC_DAPM_SINGLE("ROMIX Left ADC Bypass Switch", WM8400_OUTPUT_MIXER2,
+ WM8400_RLBRO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX Right ADC Bypass Switch", WM8400_OUTPUT_MIXER2,
+ WM8400_RRBRO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX LIN3 Bypass Switch", WM8400_OUTPUT_MIXER2,
+ WM8400_RLI3RO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX RIN3 Bypass Switch", WM8400_OUTPUT_MIXER2,
+ WM8400_RRI3RO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX LIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER2,
+ WM8400_RL12RO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX RIN12 PGA Bypass Switch", WM8400_OUTPUT_MIXER2,
+ WM8400_RR12RO_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROMIX Right DAC Switch", WM8400_OUTPUT_MIXER2,
+ WM8400_RDRO_SHIFT, 1, 0),
+};
+
+/* LONMIX */
+static const struct snd_kcontrol_new wm8400_dapm_lonmix_controls[] = {
+SOC_DAPM_SINGLE("LONMIX Left Mixer PGA Switch", WM8400_LINE_MIXER1,
+ WM8400_LLOPGALON_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LONMIX Right Mixer PGA Switch", WM8400_LINE_MIXER1,
+ WM8400_LROPGALON_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LONMIX Inverted LOP Switch", WM8400_LINE_MIXER1,
+ WM8400_LOPLON_SHIFT, 1, 0),
+};
+
+/* LOPMIX */
+static const struct snd_kcontrol_new wm8400_dapm_lopmix_controls[] = {
+SOC_DAPM_SINGLE("LOPMIX Right Mic Bypass Switch", WM8400_LINE_MIXER1,
+ WM8400_LR12LOP_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOPMIX Left Mic Bypass Switch", WM8400_LINE_MIXER1,
+ WM8400_LL12LOP_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("LOPMIX Left Mixer PGA Switch", WM8400_LINE_MIXER1,
+ WM8400_LLOPGALOP_SHIFT, 1, 0),
+};
+
+/* RONMIX */
+static const struct snd_kcontrol_new wm8400_dapm_ronmix_controls[] = {
+SOC_DAPM_SINGLE("RONMIX Right Mixer PGA Switch", WM8400_LINE_MIXER2,
+ WM8400_RROPGARON_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("RONMIX Left Mixer PGA Switch", WM8400_LINE_MIXER2,
+ WM8400_RLOPGARON_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("RONMIX Inverted ROP Switch", WM8400_LINE_MIXER2,
+ WM8400_ROPRON_SHIFT, 1, 0),
+};
+
+/* ROPMIX */
+static const struct snd_kcontrol_new wm8400_dapm_ropmix_controls[] = {
+SOC_DAPM_SINGLE("ROPMIX Left Mic Bypass Switch", WM8400_LINE_MIXER2,
+ WM8400_RL12ROP_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROPMIX Right Mic Bypass Switch", WM8400_LINE_MIXER2,
+ WM8400_RR12ROP_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("ROPMIX Right Mixer PGA Switch", WM8400_LINE_MIXER2,
+ WM8400_RROPGAROP_SHIFT, 1, 0),
+};
+
+/* OUT3MIX */
+static const struct snd_kcontrol_new wm8400_dapm_out3mix_controls[] = {
+SOC_DAPM_SINGLE("OUT3MIX LIN4/RXP Bypass Switch", WM8400_OUT3_4_MIXER,
+ WM8400_LI4O3_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("OUT3MIX Left Out PGA Switch", WM8400_OUT3_4_MIXER,
+ WM8400_LPGAO3_SHIFT, 1, 0),
+};
+
+/* OUT4MIX */
+static const struct snd_kcontrol_new wm8400_dapm_out4mix_controls[] = {
+SOC_DAPM_SINGLE("OUT4MIX Right Out PGA Switch", WM8400_OUT3_4_MIXER,
+ WM8400_RPGAO4_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("OUT4MIX RIN4/RXP Bypass Switch", WM8400_OUT3_4_MIXER,
+ WM8400_RI4O4_SHIFT, 1, 0),
+};
+
+/* SPKMIX */
+static const struct snd_kcontrol_new wm8400_dapm_spkmix_controls[] = {
+SOC_DAPM_SINGLE("SPKMIX LIN2 Bypass Switch", WM8400_SPEAKER_MIXER,
+ WM8400_LI2SPK_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX LADC Bypass Switch", WM8400_SPEAKER_MIXER,
+ WM8400_LB2SPK_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX Left Mixer PGA Switch", WM8400_SPEAKER_MIXER,
+ WM8400_LOPGASPK_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX Left DAC Switch", WM8400_SPEAKER_MIXER,
+ WM8400_LDSPK_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX Right DAC Switch", WM8400_SPEAKER_MIXER,
+ WM8400_RDSPK_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX Right Mixer PGA Switch", WM8400_SPEAKER_MIXER,
+ WM8400_ROPGASPK_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX RADC Bypass Switch", WM8400_SPEAKER_MIXER,
+ WM8400_RL12ROP_SHIFT, 1, 0),
+SOC_DAPM_SINGLE("SPKMIX RIN2 Bypass Switch", WM8400_SPEAKER_MIXER,
+ WM8400_RI2SPK_SHIFT, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget wm8400_dapm_widgets[] = {
+/* Input Side */
+/* Input Lines */
+SND_SOC_DAPM_INPUT("LIN1"),
+SND_SOC_DAPM_INPUT("LIN2"),
+SND_SOC_DAPM_INPUT("LIN3"),
+SND_SOC_DAPM_INPUT("LIN4/RXN"),
+SND_SOC_DAPM_INPUT("RIN3"),
+SND_SOC_DAPM_INPUT("RIN4/RXP"),
+SND_SOC_DAPM_INPUT("RIN1"),
+SND_SOC_DAPM_INPUT("RIN2"),
+SND_SOC_DAPM_INPUT("Internal ADC Source"),
+
+/* DACs */
+SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8400_POWER_MANAGEMENT_2,
+ WM8400_ADCL_ENA_SHIFT, 0),
+SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8400_POWER_MANAGEMENT_2,
+ WM8400_ADCR_ENA_SHIFT, 0),
+
+/* Input PGAs */
+SND_SOC_DAPM_MIXER("LIN12 PGA", WM8400_POWER_MANAGEMENT_2,
+ WM8400_LIN12_ENA_SHIFT,
+ 0, &wm8400_dapm_lin12_pga_controls[0],
+ ARRAY_SIZE(wm8400_dapm_lin12_pga_controls)),
+SND_SOC_DAPM_MIXER("LIN34 PGA", WM8400_POWER_MANAGEMENT_2,
+ WM8400_LIN34_ENA_SHIFT,
+ 0, &wm8400_dapm_lin34_pga_controls[0],
+ ARRAY_SIZE(wm8400_dapm_lin34_pga_controls)),
+SND_SOC_DAPM_MIXER("RIN12 PGA", WM8400_POWER_MANAGEMENT_2,
+ WM8400_RIN12_ENA_SHIFT,
+ 0, &wm8400_dapm_rin12_pga_controls[0],
+ ARRAY_SIZE(wm8400_dapm_rin12_pga_controls)),
+SND_SOC_DAPM_MIXER("RIN34 PGA", WM8400_POWER_MANAGEMENT_2,
+ WM8400_RIN34_ENA_SHIFT,
+ 0, &wm8400_dapm_rin34_pga_controls[0],
+ ARRAY_SIZE(wm8400_dapm_rin34_pga_controls)),
+
+/* INMIXL */
+SND_SOC_DAPM_MIXER_E("INMIXL", WM8400_INTDRIVBITS, WM8400_INMIXL_PWR, 0,
+ &wm8400_dapm_inmixl_controls[0],
+ ARRAY_SIZE(wm8400_dapm_inmixl_controls),
+ inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+/* AINLMUX */
+SND_SOC_DAPM_MUX_E("AILNMUX", WM8400_INTDRIVBITS, WM8400_AINLMUX_PWR, 0,
+ &wm8400_dapm_ainlmux_controls, inmixer_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+/* INMIXR */
+SND_SOC_DAPM_MIXER_E("INMIXR", WM8400_INTDRIVBITS, WM8400_INMIXR_PWR, 0,
+ &wm8400_dapm_inmixr_controls[0],
+ ARRAY_SIZE(wm8400_dapm_inmixr_controls),
+ inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+/* AINRMUX */
+SND_SOC_DAPM_MUX_E("AIRNMUX", WM8400_INTDRIVBITS, WM8400_AINRMUX_PWR, 0,
+ &wm8400_dapm_ainrmux_controls, inmixer_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+/* Output Side */
+/* DACs */
+SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8400_POWER_MANAGEMENT_3,
+ WM8400_DACL_ENA_SHIFT, 0),
+SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8400_POWER_MANAGEMENT_3,
+ WM8400_DACR_ENA_SHIFT, 0),
+
+/* LOMIX */
+SND_SOC_DAPM_MIXER_E("LOMIX", WM8400_POWER_MANAGEMENT_3,
+ WM8400_LOMIX_ENA_SHIFT,
+ 0, &wm8400_dapm_lomix_controls[0],
+ ARRAY_SIZE(wm8400_dapm_lomix_controls),
+ outmixer_event, SND_SOC_DAPM_PRE_REG),
+
+/* LONMIX */
+SND_SOC_DAPM_MIXER("LONMIX", WM8400_POWER_MANAGEMENT_3, WM8400_LON_ENA_SHIFT,
+ 0, &wm8400_dapm_lonmix_controls[0],
+ ARRAY_SIZE(wm8400_dapm_lonmix_controls)),
+
+/* LOPMIX */
+SND_SOC_DAPM_MIXER("LOPMIX", WM8400_POWER_MANAGEMENT_3, WM8400_LOP_ENA_SHIFT,
+ 0, &wm8400_dapm_lopmix_controls[0],
+ ARRAY_SIZE(wm8400_dapm_lopmix_controls)),
+
+/* OUT3MIX */
+SND_SOC_DAPM_MIXER("OUT3MIX", WM8400_POWER_MANAGEMENT_1, WM8400_OUT3_ENA_SHIFT,
+ 0, &wm8400_dapm_out3mix_controls[0],
+ ARRAY_SIZE(wm8400_dapm_out3mix_controls)),
+
+/* SPKMIX */
+SND_SOC_DAPM_MIXER_E("SPKMIX", WM8400_POWER_MANAGEMENT_1, WM8400_SPK_ENA_SHIFT,
+ 0, &wm8400_dapm_spkmix_controls[0],
+ ARRAY_SIZE(wm8400_dapm_spkmix_controls), outmixer_event,
+ SND_SOC_DAPM_PRE_REG),
+
+/* OUT4MIX */
+SND_SOC_DAPM_MIXER("OUT4MIX", WM8400_POWER_MANAGEMENT_1, WM8400_OUT4_ENA_SHIFT,
+ 0, &wm8400_dapm_out4mix_controls[0],
+ ARRAY_SIZE(wm8400_dapm_out4mix_controls)),
+
+/* ROPMIX */
+SND_SOC_DAPM_MIXER("ROPMIX", WM8400_POWER_MANAGEMENT_3, WM8400_ROP_ENA_SHIFT,
+ 0, &wm8400_dapm_ropmix_controls[0],
+ ARRAY_SIZE(wm8400_dapm_ropmix_controls)),
+
+/* RONMIX */
+SND_SOC_DAPM_MIXER("RONMIX", WM8400_POWER_MANAGEMENT_3, WM8400_RON_ENA_SHIFT,
+ 0, &wm8400_dapm_ronmix_controls[0],
+ ARRAY_SIZE(wm8400_dapm_ronmix_controls)),
+
+/* ROMIX */
+SND_SOC_DAPM_MIXER_E("ROMIX", WM8400_POWER_MANAGEMENT_3,
+ WM8400_ROMIX_ENA_SHIFT,
+ 0, &wm8400_dapm_romix_controls[0],
+ ARRAY_SIZE(wm8400_dapm_romix_controls),
+ outmixer_event, SND_SOC_DAPM_PRE_REG),
+
+/* LOUT PGA */
+SND_SOC_DAPM_PGA("LOUT PGA", WM8400_POWER_MANAGEMENT_1, WM8400_LOUT_ENA_SHIFT,
+ 0, NULL, 0),
+
+/* ROUT PGA */
+SND_SOC_DAPM_PGA("ROUT PGA", WM8400_POWER_MANAGEMENT_1, WM8400_ROUT_ENA_SHIFT,
+ 0, NULL, 0),
+
+/* LOPGA */
+SND_SOC_DAPM_PGA("LOPGA", WM8400_POWER_MANAGEMENT_3, WM8400_LOPGA_ENA_SHIFT, 0,
+ NULL, 0),
+
+/* ROPGA */
+SND_SOC_DAPM_PGA("ROPGA", WM8400_POWER_MANAGEMENT_3, WM8400_ROPGA_ENA_SHIFT, 0,
+ NULL, 0),
+
+/* MICBIAS */
+SND_SOC_DAPM_MICBIAS("MICBIAS", WM8400_POWER_MANAGEMENT_1,
+ WM8400_MIC1BIAS_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_OUTPUT("LON"),
+SND_SOC_DAPM_OUTPUT("LOP"),
+SND_SOC_DAPM_OUTPUT("OUT3"),
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("SPKN"),
+SND_SOC_DAPM_OUTPUT("SPKP"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+SND_SOC_DAPM_OUTPUT("OUT4"),
+SND_SOC_DAPM_OUTPUT("ROP"),
+SND_SOC_DAPM_OUTPUT("RON"),
+
+SND_SOC_DAPM_OUTPUT("Internal DAC Sink"),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* Make DACs turn on when playing even if not mixed into any outputs */
+ {"Internal DAC Sink", NULL, "Left DAC"},
+ {"Internal DAC Sink", NULL, "Right DAC"},
+
+ /* Make ADCs turn on when recording
+ * even if not mixed from any inputs */
+ {"Left ADC", NULL, "Internal ADC Source"},
+ {"Right ADC", NULL, "Internal ADC Source"},
+
+ /* Input Side */
+ /* LIN12 PGA */
+ {"LIN12 PGA", "LIN1 Switch", "LIN1"},
+ {"LIN12 PGA", "LIN2 Switch", "LIN2"},
+ /* LIN34 PGA */
+ {"LIN34 PGA", "LIN3 Switch", "LIN3"},
+ {"LIN34 PGA", "LIN4 Switch", "LIN4/RXN"},
+ /* INMIXL */
+ {"INMIXL", "Record Left Volume", "LOMIX"},
+ {"INMIXL", "LIN2 Volume", "LIN2"},
+ {"INMIXL", "LINPGA12 Switch", "LIN12 PGA"},
+ {"INMIXL", "LINPGA34 Switch", "LIN34 PGA"},
+ /* AILNMUX */
+ {"AILNMUX", "INMIXL Mix", "INMIXL"},
+ {"AILNMUX", "DIFFINL Mix", "LIN12 PGA"},
+ {"AILNMUX", "DIFFINL Mix", "LIN34 PGA"},
+ {"AILNMUX", "RXVOICE Mix", "LIN4/RXN"},
+ {"AILNMUX", "RXVOICE Mix", "RIN4/RXP"},
+ /* ADC */
+ {"Left ADC", NULL, "AILNMUX"},
+
+ /* RIN12 PGA */
+ {"RIN12 PGA", "RIN1 Switch", "RIN1"},
+ {"RIN12 PGA", "RIN2 Switch", "RIN2"},
+ /* RIN34 PGA */
+ {"RIN34 PGA", "RIN3 Switch", "RIN3"},
+ {"RIN34 PGA", "RIN4 Switch", "RIN4/RXP"},
+ /* INMIXL */
+ {"INMIXR", "Record Right Volume", "ROMIX"},
+ {"INMIXR", "RIN2 Volume", "RIN2"},
+ {"INMIXR", "RINPGA12 Switch", "RIN12 PGA"},
+ {"INMIXR", "RINPGA34 Switch", "RIN34 PGA"},
+ /* AIRNMUX */
+ {"AIRNMUX", "INMIXR Mix", "INMIXR"},
+ {"AIRNMUX", "DIFFINR Mix", "RIN12 PGA"},
+ {"AIRNMUX", "DIFFINR Mix", "RIN34 PGA"},
+ {"AIRNMUX", "RXVOICE Mix", "LIN4/RXN"},
+ {"AIRNMUX", "RXVOICE Mix", "RIN4/RXP"},
+ /* ADC */
+ {"Right ADC", NULL, "AIRNMUX"},
+
+ /* LOMIX */
+ {"LOMIX", "LOMIX RIN3 Bypass Switch", "RIN3"},
+ {"LOMIX", "LOMIX LIN3 Bypass Switch", "LIN3"},
+ {"LOMIX", "LOMIX LIN12 PGA Bypass Switch", "LIN12 PGA"},
+ {"LOMIX", "LOMIX RIN12 PGA Bypass Switch", "RIN12 PGA"},
+ {"LOMIX", "LOMIX Right ADC Bypass Switch", "AIRNMUX"},
+ {"LOMIX", "LOMIX Left ADC Bypass Switch", "AILNMUX"},
+ {"LOMIX", "LOMIX Left DAC Switch", "Left DAC"},
+
+ /* ROMIX */
+ {"ROMIX", "ROMIX RIN3 Bypass Switch", "RIN3"},
+ {"ROMIX", "ROMIX LIN3 Bypass Switch", "LIN3"},
+ {"ROMIX", "ROMIX LIN12 PGA Bypass Switch", "LIN12 PGA"},
+ {"ROMIX", "ROMIX RIN12 PGA Bypass Switch", "RIN12 PGA"},
+ {"ROMIX", "ROMIX Right ADC Bypass Switch", "AIRNMUX"},
+ {"ROMIX", "ROMIX Left ADC Bypass Switch", "AILNMUX"},
+ {"ROMIX", "ROMIX Right DAC Switch", "Right DAC"},
+
+ /* SPKMIX */
+ {"SPKMIX", "SPKMIX LIN2 Bypass Switch", "LIN2"},
+ {"SPKMIX", "SPKMIX RIN2 Bypass Switch", "RIN2"},
+ {"SPKMIX", "SPKMIX LADC Bypass Switch", "AILNMUX"},
+ {"SPKMIX", "SPKMIX RADC Bypass Switch", "AIRNMUX"},
+ {"SPKMIX", "SPKMIX Left Mixer PGA Switch", "LOPGA"},
+ {"SPKMIX", "SPKMIX Right Mixer PGA Switch", "ROPGA"},
+ {"SPKMIX", "SPKMIX Right DAC Switch", "Right DAC"},
+ {"SPKMIX", "SPKMIX Left DAC Switch", "Right DAC"},
+
+ /* LONMIX */
+ {"LONMIX", "LONMIX Left Mixer PGA Switch", "LOPGA"},
+ {"LONMIX", "LONMIX Right Mixer PGA Switch", "ROPGA"},
+ {"LONMIX", "LONMIX Inverted LOP Switch", "LOPMIX"},
+
+ /* LOPMIX */
+ {"LOPMIX", "LOPMIX Right Mic Bypass Switch", "RIN12 PGA"},
+ {"LOPMIX", "LOPMIX Left Mic Bypass Switch", "LIN12 PGA"},
+ {"LOPMIX", "LOPMIX Left Mixer PGA Switch", "LOPGA"},
+
+ /* OUT3MIX */
+ {"OUT3MIX", "OUT3MIX LIN4/RXP Bypass Switch", "LIN4/RXN"},
+ {"OUT3MIX", "OUT3MIX Left Out PGA Switch", "LOPGA"},
+
+ /* OUT4MIX */
+ {"OUT4MIX", "OUT4MIX Right Out PGA Switch", "ROPGA"},
+ {"OUT4MIX", "OUT4MIX RIN4/RXP Bypass Switch", "RIN4/RXP"},
+
+ /* RONMIX */
+ {"RONMIX", "RONMIX Right Mixer PGA Switch", "ROPGA"},
+ {"RONMIX", "RONMIX Left Mixer PGA Switch", "LOPGA"},
+ {"RONMIX", "RONMIX Inverted ROP Switch", "ROPMIX"},
+
+ /* ROPMIX */
+ {"ROPMIX", "ROPMIX Left Mic Bypass Switch", "LIN12 PGA"},
+ {"ROPMIX", "ROPMIX Right Mic Bypass Switch", "RIN12 PGA"},
+ {"ROPMIX", "ROPMIX Right Mixer PGA Switch", "ROPGA"},
+
+ /* Out Mixer PGAs */
+ {"LOPGA", NULL, "LOMIX"},
+ {"ROPGA", NULL, "ROMIX"},
+
+ {"LOUT PGA", NULL, "LOMIX"},
+ {"ROUT PGA", NULL, "ROMIX"},
+
+ /* Output Pins */
+ {"LON", NULL, "LONMIX"},
+ {"LOP", NULL, "LOPMIX"},
+ {"OUT3", NULL, "OUT3MIX"},
+ {"LOUT", NULL, "LOUT PGA"},
+ {"SPKN", NULL, "SPKMIX"},
+ {"ROUT", NULL, "ROUT PGA"},
+ {"OUT4", NULL, "OUT4MIX"},
+ {"ROP", NULL, "ROPMIX"},
+ {"RON", NULL, "RONMIX"},
+};
+
+static int wm8400_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, wm8400_dapm_widgets,
+ ARRAY_SIZE(wm8400_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ snd_soc_dapm_new_widgets(codec);
+ return 0;
+}
+
+/*
+ * Clock after FLL and dividers
+ */
+static int wm8400_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 wm8400_priv *wm8400 = codec->private_data;
+
+ wm8400->sysclk = freq;
+ return 0;
+}
+
+struct fll_factors {
+ u16 n;
+ u16 k;
+ u16 outdiv;
+ u16 fratio;
+ u16 freq_ref;
+};
+
+#define FIXED_FLL_SIZE ((1 << 16) * 10)
+
+static int fll_factors(struct wm8400_priv *wm8400, struct fll_factors *factors,
+ unsigned int Fref, unsigned int Fout)
+{
+ u64 Kpart;
+ unsigned int K, Nmod, target;
+
+ factors->outdiv = 2;
+ while (Fout * factors->outdiv < 90000000 ||
+ Fout * factors->outdiv > 100000000) {
+ factors->outdiv *= 2;
+ if (factors->outdiv > 32) {
+ dev_err(wm8400->wm8400->dev,
+ "Unsupported FLL output frequency %dHz\n",
+ Fout);
+ return -EINVAL;
+ }
+ }
+ target = Fout * factors->outdiv;
+ factors->outdiv = factors->outdiv >> 2;
+
+ if (Fref < 48000)
+ factors->freq_ref = 1;
+ else
+ factors->freq_ref = 0;
+
+ if (Fref < 1000000)
+ factors->fratio = 9;
+ else
+ factors->fratio = 0;
+
+ /* Ensure we have a fractional part */
+ do {
+ if (Fref < 1000000)
+ factors->fratio--;
+ else
+ factors->fratio++;
+
+ if (factors->fratio < 1 || factors->fratio > 8) {
+ dev_err(wm8400->wm8400->dev,
+ "Unable to calculate FRATIO\n");
+ return -EINVAL;
+ }
+
+ factors->n = target / (Fref * factors->fratio);
+ Nmod = target % (Fref * factors->fratio);
+ } while (Nmod == 0);
+
+ /* Calculate fractional part - scale up so we can round. */
+ Kpart = FIXED_FLL_SIZE * (long long)Nmod;
+
+ do_div(Kpart, (Fref * factors->fratio));
+
+ K = Kpart & 0xFFFFFFFF;
+
+ if ((K % 10) >= 5)
+ K += 5;
+
+ /* Move down to proper range now rounding is done */
+ factors->k = K / 10;
+
+ dev_dbg(wm8400->wm8400->dev,
+ "FLL: Fref=%d Fout=%d N=%x K=%x, FRATIO=%x OUTDIV=%x\n",
+ Fref, Fout,
+ factors->n, factors->k, factors->fratio, factors->outdiv);
+
+ return 0;
+}
+
+static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+ unsigned int freq_in, unsigned int freq_out)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct wm8400_priv *wm8400 = codec->private_data;
+ struct fll_factors factors;
+ int ret;
+ u16 reg;
+
+ if (freq_in == wm8400->fll_in && freq_out == wm8400->fll_out)
+ return 0;
+
+ if (freq_out != 0) {
+ ret = fll_factors(wm8400, &factors, freq_in, freq_out);
+ if (ret != 0)
+ return ret;
+ }
+
+ wm8400->fll_out = freq_out;
+ wm8400->fll_in = freq_in;
+
+ /* We *must* disable the FLL before any changes */
+ reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_2);
+ reg &= ~WM8400_FLL_ENA;
+ wm8400_write(codec, WM8400_POWER_MANAGEMENT_2, reg);
+
+ reg = wm8400_read(codec, WM8400_FLL_CONTROL_1);
+ reg &= ~WM8400_FLL_OSC_ENA;
+ wm8400_write(codec, WM8400_FLL_CONTROL_1, reg);
+
+ if (freq_out == 0)
+ return 0;
+
+ reg &= ~(WM8400_FLL_REF_FREQ | WM8400_FLL_FRATIO_MASK);
+ reg |= WM8400_FLL_FRAC | factors.fratio;
+ reg |= factors.freq_ref << WM8400_FLL_REF_FREQ_SHIFT;
+ wm8400_write(codec, WM8400_FLL_CONTROL_1, reg);
+
+ wm8400_write(codec, WM8400_FLL_CONTROL_2, factors.k);
+ wm8400_write(codec, WM8400_FLL_CONTROL_3, factors.n);
+
+ reg = wm8400_read(codec, WM8400_FLL_CONTROL_4);
+ reg &= WM8400_FLL_OUTDIV_MASK;
+ reg |= factors.outdiv;
+ wm8400_write(codec, WM8400_FLL_CONTROL_4, reg);
+
+ return 0;
+}
+
+/*
+ * Sets ADC and Voice DAC format.
+ */
+static int wm8400_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u16 audio1, audio3;
+
+ audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1);
+ audio3 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_3);
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ audio3 &= ~WM8400_AIF_MSTR1;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ audio3 |= WM8400_AIF_MSTR1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ audio1 &= ~WM8400_AIF_FMT_MASK;
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ audio1 |= WM8400_AIF_FMT_I2S;
+ audio1 &= ~WM8400_AIF_LRCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ audio1 |= WM8400_AIF_FMT_RIGHTJ;
+ audio1 &= ~WM8400_AIF_LRCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ audio1 |= WM8400_AIF_FMT_LEFTJ;
+ audio1 &= ~WM8400_AIF_LRCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ audio1 |= WM8400_AIF_FMT_DSP;
+ audio1 &= ~WM8400_AIF_LRCLK_INV;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ audio1 |= WM8400_AIF_FMT_DSP | WM8400_AIF_LRCLK_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ wm8400_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
+ wm8400_write(codec, WM8400_AUDIO_INTERFACE_3, audio3);
+ return 0;
+}
+
+static int wm8400_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+ int div_id, int div)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u16 reg;
+
+ switch (div_id) {
+ case WM8400_MCLK_DIV:
+ reg = wm8400_read(codec, WM8400_CLOCKING_2) &
+ ~WM8400_MCLK_DIV_MASK;
+ wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
+ break;
+ case WM8400_DACCLK_DIV:
+ reg = wm8400_read(codec, WM8400_CLOCKING_2) &
+ ~WM8400_DAC_CLKDIV_MASK;
+ wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
+ break;
+ case WM8400_ADCCLK_DIV:
+ reg = wm8400_read(codec, WM8400_CLOCKING_2) &
+ ~WM8400_ADC_CLKDIV_MASK;
+ wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
+ break;
+ case WM8400_BCLK_DIV:
+ reg = wm8400_read(codec, WM8400_CLOCKING_1) &
+ ~WM8400_BCLK_DIV_MASK;
+ wm8400_write(codec, WM8400_CLOCKING_1, reg | div);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Set PCM DAI bit size and sample rate.
+ */
+static int wm8400_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+ u16 audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1);
+
+ audio1 &= ~WM8400_AIF_WL_MASK;
+ /* bit size */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ audio1 |= WM8400_AIF_WL_20BITS;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ audio1 |= WM8400_AIF_WL_24BITS;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ audio1 |= WM8400_AIF_WL_32BITS;
+ break;
+ }
+
+ wm8400_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
+ return 0;
+}
+
+static int wm8400_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u16 val = wm8400_read(codec, WM8400_DAC_CTRL) & ~WM8400_DAC_MUTE;
+
+ if (mute)
+ wm8400_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
+ else
+ wm8400_write(codec, WM8400_DAC_CTRL, val);
+
+ return 0;
+}
+
+/* TODO: set bias for best performance at standby */
+static int wm8400_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct wm8400_priv *wm8400 = codec->private_data;
+ u16 val;
+ int ret;
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+
+ case SND_SOC_BIAS_PREPARE:
+ /* VMID=2*50k */
+ val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1) &
+ ~WM8400_VMID_MODE_MASK;
+ wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x2);
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->bias_level == SND_SOC_BIAS_OFF) {
+ ret = regulator_bulk_enable(ARRAY_SIZE(power),
+ &power[0]);
+ if (ret != 0) {
+ dev_err(wm8400->wm8400->dev,
+ "Failed to enable regulators: %d\n",
+ ret);
+ return ret;
+ }
+
+ wm8400_write(codec, WM8400_POWER_MANAGEMENT_1,
+ WM8400_CODEC_ENA | WM8400_SYSCLK_ENA);
+
+ /* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */
+ wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+ WM8400_BUFDCOPEN | WM8400_POBCTRL);
+
+ msleep(50);
+
+ /* Enable VREF & VMID at 2x50k */
+ val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
+ val |= 0x2 | WM8400_VREF_ENA;
+ wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+
+ /* Enable BUFIOEN */
+ wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+ WM8400_BUFDCOPEN | WM8400_POBCTRL |
+ WM8400_BUFIOEN);
+
+ /* disable POBCTRL, SOFT_ST and BUFDCOPEN */
+ wm8400_write(codec, WM8400_ANTIPOP2, WM8400_BUFIOEN);
+ }
+
+ /* VMID=2*300k */
+ val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1) &
+ ~WM8400_VMID_MODE_MASK;
+ wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x4);
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ /* Enable POBCTRL and SOFT_ST */
+ wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+ WM8400_POBCTRL | WM8400_BUFIOEN);
+
+ /* Enable POBCTRL, SOFT_ST and BUFDCOPEN */
+ wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+ WM8400_BUFDCOPEN | WM8400_POBCTRL |
+ WM8400_BUFIOEN);
+
+ /* mute DAC */
+ val = wm8400_read(codec, WM8400_DAC_CTRL);
+ wm8400_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
+
+ /* Enable any disabled outputs */
+ val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
+ val |= WM8400_SPK_ENA | WM8400_OUT3_ENA |
+ WM8400_OUT4_ENA | WM8400_LOUT_ENA |
+ WM8400_ROUT_ENA;
+ wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+
+ /* Disable VMID */
+ val &= ~WM8400_VMID_MODE_MASK;
+ wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+
+ msleep(300);
+
+ /* Enable all output discharge bits */
+ wm8400_write(codec, WM8400_ANTIPOP1, WM8400_DIS_LLINE |
+ WM8400_DIS_RLINE | WM8400_DIS_OUT3 |
+ WM8400_DIS_OUT4 | WM8400_DIS_LOUT |
+ WM8400_DIS_ROUT);
+
+ /* Disable VREF */
+ val &= ~WM8400_VREF_ENA;
+ wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+
+ /* disable POBCTRL, SOFT_ST and BUFDCOPEN */
+ wm8400_write(codec, WM8400_ANTIPOP2, 0x0);
+
+ ret = regulator_bulk_disable(ARRAY_SIZE(power),
+ &power[0]);
+ if (ret != 0)
+ return ret;
+
+ break;
+ }
+
+ codec->bias_level = level;
+ return 0;
+}
+
+#define WM8400_RATES SNDRV_PCM_RATE_8000_96000
+
+#define WM8400_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops wm8400_dai_ops = {
+ .hw_params = wm8400_hw_params,
+ .digital_mute = wm8400_mute,
+ .set_fmt = wm8400_set_dai_fmt,
+ .set_clkdiv = wm8400_set_dai_clkdiv,
+ .set_sysclk = wm8400_set_dai_sysclk,
+ .set_pll = wm8400_set_dai_pll,
+};
+
+/*
+ * The WM8400 supports 2 different and mutually exclusive DAI
+ * configurations.
+ *
+ * 1. ADC/DAC on Primary Interface
+ * 2. ADC on Primary Interface/DAC on secondary
+ */
+struct snd_soc_dai wm8400_dai = {
+/* ADC/DAC on primary */
+ .name = "WM8400 ADC/DAC Primary",
+ .id = 1,
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM8400_RATES,
+ .formats = WM8400_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM8400_RATES,
+ .formats = WM8400_FORMATS,
+ },
+ .ops = &wm8400_dai_ops,
+};
+EXPORT_SYMBOL_GPL(wm8400_dai);
+
+static int wm8400_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->card->codec;
+
+ wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static int wm8400_resume(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->card->codec;
+
+ wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
+}
+
+static struct snd_soc_codec *wm8400_codec;
+
+static int wm8400_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret;
+
+ if (!wm8400_codec) {
+ dev_err(&pdev->dev, "wm8400 not yet discovered\n");
+ return -ENODEV;
+ }
+ codec = wm8400_codec;
+
+ socdev->card->codec = codec;
+
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to create pcms\n");
+ goto pcm_err;
+ }
+
+ wm8400_add_controls(codec);
+ wm8400_add_widgets(codec);
+
+ ret = snd_soc_init_card(socdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register card\n");
+ goto card_err;
+ }
+
+ return ret;
+
+card_err:
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+pcm_err:
+ return ret;
+}
+
+/* power down chip */
+static int wm8400_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8400 = {
+ .probe = wm8400_probe,
+ .remove = wm8400_remove,
+ .suspend = wm8400_suspend,
+ .resume = wm8400_resume,
+};
+
+static void wm8400_probe_deferred(struct work_struct *work)
+{
+ struct wm8400_priv *priv = container_of(work, struct wm8400_priv,
+ work);
+ struct snd_soc_codec *codec = &priv->codec;
+ int ret;
+
+ /* charge output caps */
+ wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ /* We're done, tell the subsystem. */
+ ret = snd_soc_register_codec(codec);
+ if (ret != 0) {
+ dev_err(priv->wm8400->dev,
+ "Failed to register codec: %d\n", ret);
+ goto err;
+ }
+
+ ret = snd_soc_register_dai(&wm8400_dai);
+ if (ret != 0) {
+ dev_err(priv->wm8400->dev,
+ "Failed to register DAI: %d\n", ret);
+ goto err_codec;
+ }
+
+ return;
+
+err_codec:
+ snd_soc_unregister_codec(codec);
+err:
+ wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF);
+}
+
+static int wm8400_codec_probe(struct platform_device *dev)
+{
+ struct wm8400_priv *priv;
+ int ret;
+ u16 reg;
+ struct snd_soc_codec *codec;
+
+ priv = kzalloc(sizeof(struct wm8400_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+
+ codec = &priv->codec;
+ codec->private_data = priv;
+ codec->control_data = dev->dev.driver_data;
+ priv->wm8400 = dev->dev.driver_data;
+
+ ret = regulator_bulk_get(priv->wm8400->dev,
+ ARRAY_SIZE(power), &power[0]);
+ if (ret != 0) {
+ dev_err(&dev->dev, "Failed to get regulators: %d\n", ret);
+ goto err;
+ }
+
+ codec->dev = &dev->dev;
+ wm8400_dai.dev = &dev->dev;
+
+ codec->name = "WM8400";
+ codec->owner = THIS_MODULE;
+ codec->read = wm8400_read;
+ codec->write = wm8400_write;
+ codec->bias_level = SND_SOC_BIAS_OFF;
+ codec->set_bias_level = wm8400_set_bias_level;
+ codec->dai = &wm8400_dai;
+ codec->num_dai = 1;
+ codec->reg_cache_size = WM8400_REGISTER_COUNT;
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+ INIT_WORK(&priv->work, wm8400_probe_deferred);
+
+ wm8400_codec_reset(codec);
+
+ reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
+ wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, reg | WM8400_CODEC_ENA);
+
+ /* Latch volume update bits */
+ reg = wm8400_read(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME);
+ wm8400_write(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
+ reg & WM8400_IPVU);
+ reg = wm8400_read(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME);
+ wm8400_write(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
+ reg & WM8400_IPVU);
+
+ wm8400_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
+ wm8400_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
+
+ wm8400_codec = codec;
+
+ if (!schedule_work(&priv->work)) {
+ ret = -EINVAL;
+ goto err_regulator;
+ }
+
+ return 0;
+
+err_regulator:
+ wm8400_codec = NULL;
+ regulator_bulk_free(ARRAY_SIZE(power), power);
+err:
+ kfree(priv);
+ return ret;
+}
+
+static int __exit wm8400_codec_remove(struct platform_device *dev)
+{
+ struct wm8400_priv *priv = wm8400_codec->private_data;
+ u16 reg;
+
+ snd_soc_unregister_dai(&wm8400_dai);
+ snd_soc_unregister_codec(wm8400_codec);
+
+ reg = wm8400_read(wm8400_codec, WM8400_POWER_MANAGEMENT_1);
+ wm8400_write(wm8400_codec, WM8400_POWER_MANAGEMENT_1,
+ reg & (~WM8400_CODEC_ENA));
+
+ regulator_bulk_free(ARRAY_SIZE(power), power);
+ kfree(priv);
+
+ wm8400_codec = NULL;
+
+ return 0;
+}
+
+static struct platform_driver wm8400_codec_driver = {
+ .driver = {
+ .name = "wm8400-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8400_codec_probe,
+ .remove = __exit_p(wm8400_codec_remove),
+};
+
+static int __init wm8400_codec_init(void)
+{
+ return platform_driver_register(&wm8400_codec_driver);
+}
+module_init(wm8400_codec_init);
+
+static void __exit wm8400_codec_exit(void)
+{
+ platform_driver_unregister(&wm8400_codec_driver);
+}
+module_exit(wm8400_codec_exit);
+
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8400);
+
+MODULE_DESCRIPTION("ASoC WM8400 driver");
+MODULE_AUTHOR("Mark Brown");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8400-codec");
diff --git a/sound/soc/codecs/wm8400.h b/sound/soc/codecs/wm8400.h
new file mode 100644
index 00000000000..79c5934d477
--- /dev/null
+++ b/sound/soc/codecs/wm8400.h
@@ -0,0 +1,62 @@
+/*
+ * wm8400.h -- audio driver for WM8400
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef _WM8400_CODEC_H
+#define _WM8400_CODEC_H
+
+#define WM8400_MCLK_DIV 0
+#define WM8400_DACCLK_DIV 1
+#define WM8400_ADCCLK_DIV 2
+#define WM8400_BCLK_DIV 3
+
+#define WM8400_MCLK_DIV_1 0x400
+#define WM8400_MCLK_DIV_2 0x800
+
+#define WM8400_DAC_CLKDIV_1 0x00
+#define WM8400_DAC_CLKDIV_1_5 0x04
+#define WM8400_DAC_CLKDIV_2 0x08
+#define WM8400_DAC_CLKDIV_3 0x0c
+#define WM8400_DAC_CLKDIV_4 0x10
+#define WM8400_DAC_CLKDIV_5_5 0x14
+#define WM8400_DAC_CLKDIV_6 0x18
+
+#define WM8400_ADC_CLKDIV_1 0x00
+#define WM8400_ADC_CLKDIV_1_5 0x20
+#define WM8400_ADC_CLKDIV_2 0x40
+#define WM8400_ADC_CLKDIV_3 0x60
+#define WM8400_ADC_CLKDIV_4 0x80
+#define WM8400_ADC_CLKDIV_5_5 0xa0
+#define WM8400_ADC_CLKDIV_6 0xc0
+
+
+#define WM8400_BCLK_DIV_1 (0x0 << 1)
+#define WM8400_BCLK_DIV_1_5 (0x1 << 1)
+#define WM8400_BCLK_DIV_2 (0x2 << 1)
+#define WM8400_BCLK_DIV_3 (0x3 << 1)
+#define WM8400_BCLK_DIV_4 (0x4 << 1)
+#define WM8400_BCLK_DIV_5_5 (0x5 << 1)
+#define WM8400_BCLK_DIV_6 (0x6 << 1)
+#define WM8400_BCLK_DIV_8 (0x7 << 1)
+#define WM8400_BCLK_DIV_11 (0x8 << 1)
+#define WM8400_BCLK_DIV_12 (0x9 << 1)
+#define WM8400_BCLK_DIV_16 (0xA << 1)
+#define WM8400_BCLK_DIV_22 (0xB << 1)
+#define WM8400_BCLK_DIV_24 (0xC << 1)
+#define WM8400_BCLK_DIV_32 (0xD << 1)
+#define WM8400_BCLK_DIV_44 (0xE << 1)
+#define WM8400_BCLK_DIV_48 (0xF << 1)
+
+extern struct snd_soc_dai wm8400_dai;
+extern struct snd_soc_codec_device soc_codec_dev_wm8400;
+
+#endif
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 40f8238df71..6a4cea09c45 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -171,22 +171,6 @@ SOC_SINGLE("Capture Boost(+20dB)", WM8510_ADCBOOST, 8, 1, 0),
SOC_SINGLE("Mono Playback Switch", WM8510_MONOMIX, 6, 1, 1),
};
-/* add non dapm controls */
-static int wm8510_add_controls(struct snd_soc_codec *codec)
-{
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(wm8510_snd_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm8510_snd_controls[i], codec,
- NULL));
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
/* Speaker Output Mixer */
static const struct snd_kcontrol_new wm8510_speaker_mixer_controls[] = {
SOC_DAPM_SINGLE("Line Bypass Switch", WM8510_SPKMIX, 1, 1, 0),
@@ -352,7 +336,7 @@ static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai,
return 0;
}
- pll_factors(freq_out*8, freq_in);
+ pll_factors(freq_out*4, freq_in);
wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n);
wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18);
@@ -383,7 +367,7 @@ static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
wm8510_write(codec, WM8510_GPIO, reg | div);
break;
case WM8510_MCLKDIV:
- reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1f;
+ reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x11f;
wm8510_write(codec, WM8510_CLOCK, reg | div);
break;
case WM8510_ADCCLK:
@@ -468,7 +452,7 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
u16 iface = wm8510_read_reg_cache(codec, WM8510_IFACE) & 0x19f;
u16 adn = wm8510_read_reg_cache(codec, WM8510_ADD) & 0x1f1;
@@ -570,6 +554,14 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec,
#define WM8510_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+static struct snd_soc_dai_ops wm8510_dai_ops = {
+ .hw_params = wm8510_pcm_hw_params,
+ .digital_mute = wm8510_mute,
+ .set_fmt = wm8510_set_dai_fmt,
+ .set_clkdiv = wm8510_set_dai_clkdiv,
+ .set_pll = wm8510_set_dai_pll,
+};
+
struct snd_soc_dai wm8510_dai = {
.name = "WM8510 HiFi",
.playback = {
@@ -584,20 +576,14 @@ struct snd_soc_dai wm8510_dai = {
.channels_max = 2,
.rates = WM8510_RATES,
.formats = WM8510_FORMATS,},
- .ops = {
- .hw_params = wm8510_pcm_hw_params,
- .digital_mute = wm8510_mute,
- .set_fmt = wm8510_set_dai_fmt,
- .set_clkdiv = wm8510_set_dai_clkdiv,
- .set_pll = wm8510_set_dai_pll,
- },
+ .ops = &wm8510_dai_ops,
};
EXPORT_SYMBOL_GPL(wm8510_dai);
static int wm8510_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
@@ -606,7 +592,7 @@ static int wm8510_suspend(struct platform_device *pdev, pm_message_t state)
static int wm8510_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -628,7 +614,7 @@ static int wm8510_resume(struct platform_device *pdev)
*/
static int wm8510_init(struct snd_soc_device *socdev)
{
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int ret = 0;
codec->name = "WM8510";
@@ -656,7 +642,8 @@ static int wm8510_init(struct snd_soc_device *socdev)
/* power on device */
codec->bias_level = SND_SOC_BIAS_OFF;
wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- wm8510_add_controls(codec);
+ snd_soc_add_controls(codec, wm8510_snd_controls,
+ ARRAY_SIZE(wm8510_snd_controls));
wm8510_add_widgets(codec);
ret = snd_soc_init_card(socdev);
if (ret < 0) {
@@ -685,7 +672,7 @@ static int wm8510_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct snd_soc_device *socdev = wm8510_socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int ret;
i2c_set_clientdata(i2c, codec);
@@ -766,7 +753,7 @@ err_driver:
static int __devinit wm8510_spi_probe(struct spi_device *spi)
{
struct snd_soc_device *socdev = wm8510_socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int ret;
codec->control_data = spi;
@@ -832,7 +819,7 @@ static int wm8510_probe(struct platform_device *pdev)
if (codec == NULL)
return -ENOMEM;
- socdev->codec = codec;
+ socdev->card->codec = codec;
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
@@ -862,7 +849,7 @@ static int wm8510_probe(struct platform_device *pdev)
static int wm8510_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
if (codec->control_data)
wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index d004e584529..442ea6f160f 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -1,7 +1,7 @@
/*
* wm8580.c -- WM8580 ALSA Soc Audio driver
*
- * Copyright 2008 Wolfson Microelectronics PLC.
+ * Copyright 2008, 2009 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
@@ -35,19 +35,6 @@
#include "wm8580.h"
-#define WM8580_VERSION "0.1"
-
-struct pll_state {
- unsigned int in;
- unsigned int out;
-};
-
-/* codec private data */
-struct wm8580_priv {
- struct pll_state a;
- struct pll_state b;
-};
-
/* WM8580 register space */
#define WM8580_PLLA1 0x00
#define WM8580_PLLA2 0x01
@@ -102,6 +89,8 @@ struct wm8580_priv {
#define WM8580_READBACK 0x34
#define WM8580_RESET 0x35
+#define WM8580_MAX_REGISTER 0x35
+
/* PLLB4 (register 7h) */
#define WM8580_PLLB4_MCLKOUTSRC_MASK 0x60
#define WM8580_PLLB4_MCLKOUTSRC_PLLA 0x20
@@ -193,6 +182,20 @@ static const u16 wm8580_reg[] = {
0x0000, 0x0000 /*R53*/
};
+struct pll_state {
+ unsigned int in;
+ unsigned int out;
+};
+
+/* codec private data */
+struct wm8580_priv {
+ struct snd_soc_codec codec;
+ u16 reg_cache[WM8580_MAX_REGISTER + 1];
+ struct pll_state a;
+ struct pll_state b;
+};
+
+
/*
* read wm8580 register cache
*/
@@ -200,7 +203,7 @@ static inline unsigned int wm8580_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
- BUG_ON(reg > ARRAY_SIZE(wm8580_reg));
+ BUG_ON(reg >= ARRAY_SIZE(wm8580_reg));
return cache[reg];
}
@@ -223,7 +226,7 @@ static int wm8580_write(struct snd_soc_codec *codec, unsigned int reg,
{
u8 data[2];
- BUG_ON(reg > ARRAY_SIZE(wm8580_reg));
+ BUG_ON(reg >= ARRAY_SIZE(wm8580_reg));
/* Registers are 9 bits wide */
value &= 0x1ff;
@@ -330,20 +333,6 @@ SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0),
SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0),
};
-/* Add non-DAPM controls */
-static int wm8580_add_controls(struct snd_soc_codec *codec)
-{
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(wm8580_snd_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm8580_snd_controls[i],
- codec, NULL));
- if (err < 0)
- return err;
- }
- return 0;
-}
static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = {
SND_SOC_DAPM_DAC("DAC1", "Playback", WM8580_PWRDN1, 2, 1),
SND_SOC_DAPM_DAC("DAC2", "Playback", WM8580_PWRDN1, 3, 1),
@@ -553,7 +542,7 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->id);
paifb &= ~WM8580_AIF_LENGTH_MASK;
@@ -771,8 +760,22 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
switch (level) {
case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE:
+ break;
+
case SND_SOC_BIAS_STANDBY:
+ if (codec->bias_level == SND_SOC_BIAS_OFF) {
+ /* Power up and get individual control of the DACs */
+ reg = wm8580_read(codec, WM8580_PWRDN1);
+ reg &= ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD);
+ wm8580_write(codec, WM8580_PWRDN1, reg);
+
+ /* Make VMID high impedence */
+ reg = wm8580_read(codec, WM8580_ADC_CONTROL1);
+ reg &= ~0x100;
+ wm8580_write(codec, WM8580_ADC_CONTROL1, reg);
+ }
break;
+
case SND_SOC_BIAS_OFF:
reg = wm8580_read(codec, WM8580_PWRDN1);
wm8580_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN);
@@ -785,6 +788,21 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
#define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+static struct snd_soc_dai_ops wm8580_dai_ops_playback = {
+ .hw_params = wm8580_paif_hw_params,
+ .set_fmt = wm8580_set_paif_dai_fmt,
+ .set_clkdiv = wm8580_set_dai_clkdiv,
+ .set_pll = wm8580_set_dai_pll,
+ .digital_mute = wm8580_digital_mute,
+};
+
+static struct snd_soc_dai_ops wm8580_dai_ops_capture = {
+ .hw_params = wm8580_paif_hw_params,
+ .set_fmt = wm8580_set_paif_dai_fmt,
+ .set_clkdiv = wm8580_set_dai_clkdiv,
+ .set_pll = wm8580_set_dai_pll,
+};
+
struct snd_soc_dai wm8580_dai[] = {
{
.name = "WM8580 PAIFRX",
@@ -796,13 +814,7 @@ struct snd_soc_dai wm8580_dai[] = {
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = WM8580_FORMATS,
},
- .ops = {
- .hw_params = wm8580_paif_hw_params,
- .set_fmt = wm8580_set_paif_dai_fmt,
- .set_clkdiv = wm8580_set_dai_clkdiv,
- .set_pll = wm8580_set_dai_pll,
- .digital_mute = wm8580_digital_mute,
- },
+ .ops = &wm8580_dai_ops_playback,
},
{
.name = "WM8580 PAIFTX",
@@ -814,109 +826,168 @@ struct snd_soc_dai wm8580_dai[] = {
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = WM8580_FORMATS,
},
- .ops = {
- .hw_params = wm8580_paif_hw_params,
- .set_fmt = wm8580_set_paif_dai_fmt,
- .set_clkdiv = wm8580_set_dai_clkdiv,
- .set_pll = wm8580_set_dai_pll,
- },
+ .ops = &wm8580_dai_ops_capture,
},
};
EXPORT_SYMBOL_GPL(wm8580_dai);
-/*
- * initialise the WM8580 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int wm8580_init(struct snd_soc_device *socdev)
+static struct snd_soc_codec *wm8580_codec;
+
+static int wm8580_probe(struct platform_device *pdev)
{
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
int ret = 0;
- codec->name = "WM8580";
- codec->owner = THIS_MODULE;
- codec->read = wm8580_read_reg_cache;
- codec->write = wm8580_write;
- codec->set_bias_level = wm8580_set_bias_level;
- codec->dai = wm8580_dai;
- codec->num_dai = ARRAY_SIZE(wm8580_dai);
- codec->reg_cache_size = ARRAY_SIZE(wm8580_reg);
- codec->reg_cache = kmemdup(wm8580_reg, sizeof(wm8580_reg),
- GFP_KERNEL);
-
- if (codec->reg_cache == NULL)
- return -ENOMEM;
-
- /* Get the codec into a known state */
- wm8580_write(codec, WM8580_RESET, 0);
-
- /* Power up and get individual control of the DACs */
- wm8580_write(codec, WM8580_PWRDN1, wm8580_read(codec, WM8580_PWRDN1) &
- ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD));
+ if (wm8580_codec == NULL) {
+ dev_err(&pdev->dev, "Codec device not registered\n");
+ return -ENODEV;
+ }
- /* Make VMID high impedence */
- wm8580_write(codec, WM8580_ADC_CONTROL1,
- wm8580_read(codec, WM8580_ADC_CONTROL1) & ~0x100);
+ socdev->card->codec = wm8580_codec;
+ codec = wm8580_codec;
/* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1,
- SNDRV_DEFAULT_STR1);
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if (ret < 0) {
- printk(KERN_ERR "wm8580: failed to create pcms\n");
+ dev_err(codec->dev, "failed to create pcms: %d\n", ret);
goto pcm_err;
}
- wm8580_add_controls(codec);
+ snd_soc_add_controls(codec, wm8580_snd_controls,
+ ARRAY_SIZE(wm8580_snd_controls));
wm8580_add_widgets(codec);
-
ret = snd_soc_init_card(socdev);
if (ret < 0) {
- printk(KERN_ERR "wm8580: failed to register card\n");
+ dev_err(codec->dev, "failed to register card: %d\n", ret);
goto card_err;
}
+
return ret;
card_err:
snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev);
pcm_err:
- kfree(codec->reg_cache);
return ret;
}
-/* If the i2c layer weren't so broken, we could pass this kind of data
- around */
-static struct snd_soc_device *wm8580_socdev;
+/* power down chip */
+static int wm8580_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ return 0;
+}
-/*
- * WM8580 2 wire address is determined by GPIO5
- * state during powerup.
- * low = 0x1a
- * high = 0x1b
- */
+struct snd_soc_codec_device soc_codec_dev_wm8580 = {
+ .probe = wm8580_probe,
+ .remove = wm8580_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580);
+
+static int wm8580_register(struct wm8580_priv *wm8580)
+{
+ int ret, i;
+ struct snd_soc_codec *codec = &wm8580->codec;
+
+ if (wm8580_codec) {
+ dev_err(codec->dev, "Another WM8580 is registered\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+ codec->private_data = wm8580;
+ codec->name = "WM8580";
+ codec->owner = THIS_MODULE;
+ codec->read = wm8580_read_reg_cache;
+ codec->write = wm8580_write;
+ codec->bias_level = SND_SOC_BIAS_OFF;
+ codec->set_bias_level = wm8580_set_bias_level;
+ codec->dai = wm8580_dai;
+ codec->num_dai = ARRAY_SIZE(wm8580_dai);
+ codec->reg_cache_size = ARRAY_SIZE(wm8580->reg_cache);
+ codec->reg_cache = &wm8580->reg_cache;
+
+ memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg));
+
+ /* Get the codec into a known state */
+ ret = wm8580_write(codec, WM8580_RESET, 0);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to reset codec: %d\n", ret);
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wm8580_dai); i++)
+ wm8580_dai[i].dev = codec->dev;
+
+ wm8580_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ wm8580_codec = codec;
+
+ ret = snd_soc_register_codec(codec);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+ goto err;
+ }
+
+ ret = snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+ goto err_codec;
+ }
+
+ return 0;
+
+err_codec:
+ snd_soc_unregister_codec(codec);
+err:
+ kfree(wm8580);
+ return ret;
+}
+
+static void wm8580_unregister(struct wm8580_priv *wm8580)
+{
+ wm8580_set_bias_level(&wm8580->codec, SND_SOC_BIAS_OFF);
+ snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
+ snd_soc_unregister_codec(&wm8580->codec);
+ kfree(wm8580);
+ wm8580_codec = NULL;
+}
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static int wm8580_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
- struct snd_soc_device *socdev = wm8580_socdev;
- struct snd_soc_codec *codec = socdev->codec;
- int ret;
+ struct wm8580_priv *wm8580;
+ struct snd_soc_codec *codec;
- i2c_set_clientdata(i2c, codec);
+ wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL);
+ if (wm8580 == NULL)
+ return -ENOMEM;
+
+ codec = &wm8580->codec;
+ codec->hw_write = (hw_write_t)i2c_master_send;
+
+ i2c_set_clientdata(i2c, wm8580);
codec->control_data = i2c;
- ret = wm8580_init(socdev);
- if (ret < 0)
- dev_err(&i2c->dev, "failed to initialise WM8580\n");
- return ret;
+ codec->dev = &i2c->dev;
+
+ return wm8580_register(wm8580);
}
static int wm8580_i2c_remove(struct i2c_client *client)
{
- struct snd_soc_codec *codec = i2c_get_clientdata(client);
- kfree(codec->reg_cache);
+ struct wm8580_priv *wm8580 = i2c_get_clientdata(client);
+ wm8580_unregister(wm8580);
return 0;
}
@@ -928,129 +999,35 @@ MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id);
static struct i2c_driver wm8580_i2c_driver = {
.driver = {
- .name = "WM8580 I2C Codec",
+ .name = "wm8580",
.owner = THIS_MODULE,
},
.probe = wm8580_i2c_probe,
.remove = wm8580_i2c_remove,
.id_table = wm8580_i2c_id,
};
+#endif
-static int wm8580_add_i2c_device(struct platform_device *pdev,
- const struct wm8580_setup_data *setup)
+static int __init wm8580_modinit(void)
{
- struct i2c_board_info info;
- struct i2c_adapter *adapter;
- struct i2c_client *client;
int ret;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8580_i2c_driver);
if (ret != 0) {
- dev_err(&pdev->dev, "can't add i2c driver\n");
- return ret;
- }
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = setup->i2c_address;
- strlcpy(info.type, "wm8580", I2C_NAME_SIZE);
-
- adapter = i2c_get_adapter(setup->i2c_bus);
- if (!adapter) {
- dev_err(&pdev->dev, "can't get i2c adapter %d\n",
- setup->i2c_bus);
- goto err_driver;
- }
-
- client = i2c_new_device(adapter, &info);
- i2c_put_adapter(adapter);
- if (!client) {
- dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
- (unsigned int)info.addr);
- goto err_driver;
+ pr_err("Failed to register WM8580 I2C driver: %d\n", ret);
}
-
- return 0;
-
-err_driver:
- i2c_del_driver(&wm8580_i2c_driver);
- return -ENODEV;
-}
#endif
-static int wm8580_probe(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct wm8580_setup_data *setup;
- struct snd_soc_codec *codec;
- struct wm8580_priv *wm8580;
- int ret = 0;
-
- pr_info("WM8580 Audio Codec %s\n", WM8580_VERSION);
-
- setup = socdev->codec_data;
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
-
- wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL);
- if (wm8580 == NULL) {
- kfree(codec);
- return -ENOMEM;
- }
-
- codec->private_data = wm8580;
- socdev->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
- wm8580_socdev = socdev;
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- if (setup->i2c_address) {
- codec->hw_write = (hw_write_t)i2c_master_send;
- ret = wm8580_add_i2c_device(pdev, setup);
- }
-#else
- /* Add other interfaces here */
-#endif
- return ret;
-}
-
-/* power down chip */
-static int wm8580_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
-
- if (codec->control_data)
- wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF);
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- i2c_unregister_device(codec->control_data);
- i2c_del_driver(&wm8580_i2c_driver);
-#endif
- kfree(codec->private_data);
- kfree(codec);
-
return 0;
}
-
-struct snd_soc_codec_device soc_codec_dev_wm8580 = {
- .probe = wm8580_probe,
- .remove = wm8580_remove,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580);
-
-static int __init wm8580_modinit(void)
-{
- return snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
-}
module_init(wm8580_modinit);
static void __exit wm8580_exit(void)
{
- snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8580_i2c_driver);
+#endif
}
module_exit(wm8580_exit);
diff --git a/sound/soc/codecs/wm8580.h b/sound/soc/codecs/wm8580.h
index 09e4422f6f2..0dfb5ddde6a 100644
--- a/sound/soc/codecs/wm8580.h
+++ b/sound/soc/codecs/wm8580.h
@@ -28,11 +28,6 @@
#define WM8580_CLKSRC_OSC 4
#define WM8580_CLKSRC_NONE 5
-struct wm8580_setup_data {
- int i2c_bus;
- unsigned short i2c_address;
-};
-
#define WM8580_DAI_PAIFRX 0
#define WM8580_DAI_PAIFTX 1
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index 80b11983e13..e7ff2121ede 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -47,7 +47,7 @@ static inline unsigned int wm8728_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
- BUG_ON(reg > ARRAY_SIZE(wm8728_reg_defaults));
+ BUG_ON(reg >= ARRAY_SIZE(wm8728_reg_defaults));
return cache[reg];
}
@@ -55,7 +55,7 @@ static inline void wm8728_write_reg_cache(struct snd_soc_codec *codec,
u16 reg, unsigned int value)
{
u16 *cache = codec->reg_cache;
- BUG_ON(reg > ARRAY_SIZE(wm8728_reg_defaults));
+ BUG_ON(reg >= ARRAY_SIZE(wm8728_reg_defaults));
cache[reg] = value;
}
@@ -92,21 +92,6 @@ SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8728_DACLVOL, WM8728_DACRVOL,
SOC_SINGLE("Deemphasis", WM8728_DACCTL, 1, 1, 0),
};
-static int wm8728_add_controls(struct snd_soc_codec *codec)
-{
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(wm8728_snd_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm8728_snd_controls[i],
- codec, NULL));
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
/*
* DAPM controls.
*/
@@ -152,7 +137,7 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
u16 dac = wm8728_read_reg_cache(codec, WM8728_DACCTL);
dac &= ~0x18;
@@ -259,6 +244,12 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec,
#define WM8728_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE)
+static struct snd_soc_dai_ops wm8728_dai_ops = {
+ .hw_params = wm8728_hw_params,
+ .digital_mute = wm8728_mute,
+ .set_fmt = wm8728_set_dai_fmt,
+};
+
struct snd_soc_dai wm8728_dai = {
.name = "WM8728",
.playback = {
@@ -268,18 +259,14 @@ struct snd_soc_dai wm8728_dai = {
.rates = WM8728_RATES,
.formats = WM8728_FORMATS,
},
- .ops = {
- .hw_params = wm8728_hw_params,
- .digital_mute = wm8728_mute,
- .set_fmt = wm8728_set_dai_fmt,
- }
+ .ops = &wm8728_dai_ops,
};
EXPORT_SYMBOL_GPL(wm8728_dai);
static int wm8728_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -289,7 +276,7 @@ static int wm8728_suspend(struct platform_device *pdev, pm_message_t state)
static int wm8728_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
wm8728_set_bias_level(codec, codec->suspend_bias_level);
@@ -302,7 +289,7 @@ static int wm8728_resume(struct platform_device *pdev)
*/
static int wm8728_init(struct snd_soc_device *socdev)
{
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int ret = 0;
codec->name = "WM8728";
@@ -330,7 +317,8 @@ static int wm8728_init(struct snd_soc_device *socdev)
/* power on device */
wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- wm8728_add_controls(codec);
+ snd_soc_add_controls(codec, wm8728_snd_controls,
+ ARRAY_SIZE(wm8728_snd_controls));
wm8728_add_widgets(codec);
ret = snd_soc_init_card(socdev);
if (ret < 0) {
@@ -363,7 +351,7 @@ static int wm8728_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct snd_soc_device *socdev = wm8728_socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int ret;
i2c_set_clientdata(i2c, codec);
@@ -444,7 +432,7 @@ err_driver:
static int __devinit wm8728_spi_probe(struct spi_device *spi)
{
struct snd_soc_device *socdev = wm8728_socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int ret;
codec->control_data = spi;
@@ -508,7 +496,7 @@ static int wm8728_probe(struct platform_device *pdev)
if (codec == NULL)
return -ENOMEM;
- socdev->codec = codec;
+ socdev->card->codec = codec;
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
@@ -541,7 +529,7 @@ static int wm8728_probe(struct platform_device *pdev)
static int wm8728_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
if (codec->control_data)
wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index c444b9f2701..e043e3f6000 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -29,15 +29,20 @@
#include "wm8731.h"
-#define WM8731_VERSION "0.13"
-
+static struct snd_soc_codec *wm8731_codec;
struct snd_soc_codec_device soc_codec_dev_wm8731;
/* codec private data */
struct wm8731_priv {
+ struct snd_soc_codec codec;
+ u16 reg_cache[WM8731_CACHEREGNUM];
unsigned int sysclk;
};
+#ifdef CONFIG_SPI_MASTER
+static int wm8731_spi_write(struct spi_device *spi, const char *data, int len);
+#endif
+
/*
* wm8731 register cache
* We can't read the WM8731 register space when we are
@@ -129,22 +134,6 @@ SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0),
SOC_ENUM("Playback De-emphasis", wm8731_enum[1]),
};
-/* add non dapm controls */
-static int wm8731_add_controls(struct snd_soc_codec *codec)
-{
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(wm8731_snd_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm8731_snd_controls[i],
- codec, NULL));
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
/* Output Mixer */
static const struct snd_kcontrol_new wm8731_output_mixer_controls[] = {
SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0),
@@ -269,7 +258,7 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct wm8731_priv *wm8731 = codec->private_data;
u16 iface = wm8731_read_reg_cache(codec, WM8731_IFACE) & 0xfff3;
int i = get_coeff(wm8731->sysclk, params_rate(params));
@@ -299,7 +288,7 @@ static int wm8731_pcm_prepare(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
/* set active */
wm8731_write(codec, WM8731_ACTIVE, 0x0001);
@@ -312,7 +301,7 @@ static void wm8731_shutdown(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
/* deactivate */
if (!codec->active) {
@@ -414,21 +403,19 @@ static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai,
static int wm8731_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f;
+ u16 reg;
switch (level) {
case SND_SOC_BIAS_ON:
- /* vref/mid, osc on, dac unmute */
- wm8731_write(codec, WM8731_PWR, reg);
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- /* everything off except vref/vmid, */
+ /* Clear PWROFF, gate CLKOUT, everything else as-is */
+ reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f;
wm8731_write(codec, WM8731_PWR, reg | 0x0040);
break;
case SND_SOC_BIAS_OFF:
- /* everything off, dac mute, inactive */
wm8731_write(codec, WM8731_ACTIVE, 0x0);
wm8731_write(codec, WM8731_PWR, 0xffff);
break;
@@ -446,6 +433,15 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
#define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE)
+static struct snd_soc_dai_ops wm8731_dai_ops = {
+ .prepare = wm8731_pcm_prepare,
+ .hw_params = wm8731_hw_params,
+ .shutdown = wm8731_shutdown,
+ .digital_mute = wm8731_mute,
+ .set_sysclk = wm8731_set_dai_sysclk,
+ .set_fmt = wm8731_set_dai_fmt,
+};
+
struct snd_soc_dai wm8731_dai = {
.name = "WM8731",
.playback = {
@@ -460,21 +456,14 @@ struct snd_soc_dai wm8731_dai = {
.channels_max = 2,
.rates = WM8731_RATES,
.formats = WM8731_FORMATS,},
- .ops = {
- .prepare = wm8731_pcm_prepare,
- .hw_params = wm8731_hw_params,
- .shutdown = wm8731_shutdown,
- .digital_mute = wm8731_mute,
- .set_sysclk = wm8731_set_dai_sysclk,
- .set_fmt = wm8731_set_dai_fmt,
- }
+ .ops = &wm8731_dai_ops,
};
EXPORT_SYMBOL_GPL(wm8731_dai);
static int wm8731_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
wm8731_write(codec, WM8731_ACTIVE, 0x0);
wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -484,7 +473,7 @@ static int wm8731_suspend(struct platform_device *pdev, pm_message_t state)
static int wm8731_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -500,54 +489,33 @@ static int wm8731_resume(struct platform_device *pdev)
return 0;
}
-/*
- * initialise the WM8731 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int wm8731_init(struct snd_soc_device *socdev)
+static int wm8731_probe(struct platform_device *pdev)
{
- struct snd_soc_codec *codec = socdev->codec;
- int reg, ret = 0;
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret = 0;
- codec->name = "WM8731";
- codec->owner = THIS_MODULE;
- codec->read = wm8731_read_reg_cache;
- codec->write = wm8731_write;
- codec->set_bias_level = wm8731_set_bias_level;
- codec->dai = &wm8731_dai;
- codec->num_dai = 1;
- codec->reg_cache_size = ARRAY_SIZE(wm8731_reg);
- codec->reg_cache = kmemdup(wm8731_reg, sizeof(wm8731_reg), GFP_KERNEL);
- if (codec->reg_cache == NULL)
- return -ENOMEM;
+ if (wm8731_codec == NULL) {
+ dev_err(&pdev->dev, "Codec device not registered\n");
+ return -ENODEV;
+ }
- wm8731_reset(codec);
+ socdev->card->codec = wm8731_codec;
+ codec = wm8731_codec;
/* register pcms */
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if (ret < 0) {
- printk(KERN_ERR "wm8731: failed to create pcms\n");
+ dev_err(codec->dev, "failed to create pcms: %d\n", ret);
goto pcm_err;
}
- /* power on device */
- wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- /* set the update bits */
- reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V);
- wm8731_write(codec, WM8731_LOUT1V, reg & ~0x0100);
- reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V);
- wm8731_write(codec, WM8731_ROUT1V, reg & ~0x0100);
- reg = wm8731_read_reg_cache(codec, WM8731_LINVOL);
- wm8731_write(codec, WM8731_LINVOL, reg & ~0x0100);
- reg = wm8731_read_reg_cache(codec, WM8731_RINVOL);
- wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100);
-
- wm8731_add_controls(codec);
+ snd_soc_add_controls(codec, wm8731_snd_controls,
+ ARRAY_SIZE(wm8731_snd_controls));
wm8731_add_widgets(codec);
ret = snd_soc_init_card(socdev);
if (ret < 0) {
- printk(KERN_ERR "wm8731: failed to register card\n");
+ dev_err(codec->dev, "failed to register card: %d\n", ret);
goto card_err;
}
@@ -557,133 +525,109 @@ card_err:
snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev);
pcm_err:
- kfree(codec->reg_cache);
return ret;
}
-static struct snd_soc_device *wm8731_socdev;
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-/*
- * WM8731 2 wire address is determined by GPIO5
- * state during powerup.
- * low = 0x1a
- * high = 0x1b
- */
-
-static int wm8731_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+/* power down chip */
+static int wm8731_remove(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = wm8731_socdev;
- struct snd_soc_codec *codec = socdev->codec;
- int ret;
-
- i2c_set_clientdata(i2c, codec);
- codec->control_data = i2c;
-
- ret = wm8731_init(socdev);
- if (ret < 0)
- pr_err("failed to initialise WM8731\n");
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- return ret;
-}
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
-static int wm8731_i2c_remove(struct i2c_client *client)
-{
- struct snd_soc_codec *codec = i2c_get_clientdata(client);
- kfree(codec->reg_cache);
return 0;
}
-static const struct i2c_device_id wm8731_i2c_id[] = {
- { "wm8731", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id);
-
-static struct i2c_driver wm8731_i2c_driver = {
- .driver = {
- .name = "WM8731 I2C Codec",
- .owner = THIS_MODULE,
- },
- .probe = wm8731_i2c_probe,
- .remove = wm8731_i2c_remove,
- .id_table = wm8731_i2c_id,
+struct snd_soc_codec_device soc_codec_dev_wm8731 = {
+ .probe = wm8731_probe,
+ .remove = wm8731_remove,
+ .suspend = wm8731_suspend,
+ .resume = wm8731_resume,
};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);
-static int wm8731_add_i2c_device(struct platform_device *pdev,
- const struct wm8731_setup_data *setup)
+static int wm8731_register(struct wm8731_priv *wm8731)
{
- struct i2c_board_info info;
- struct i2c_adapter *adapter;
- struct i2c_client *client;
int ret;
+ struct snd_soc_codec *codec = &wm8731->codec;
+ u16 reg;
- ret = i2c_add_driver(&wm8731_i2c_driver);
- if (ret != 0) {
- dev_err(&pdev->dev, "can't add i2c driver\n");
- return ret;
+ if (wm8731_codec) {
+ dev_err(codec->dev, "Another WM8731 is registered\n");
+ return -EINVAL;
}
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = setup->i2c_address;
- strlcpy(info.type, "wm8731", I2C_NAME_SIZE);
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
- adapter = i2c_get_adapter(setup->i2c_bus);
- if (!adapter) {
- dev_err(&pdev->dev, "can't get i2c adapter %d\n",
- setup->i2c_bus);
- goto err_driver;
- }
+ codec->private_data = wm8731;
+ codec->name = "WM8731";
+ codec->owner = THIS_MODULE;
+ codec->read = wm8731_read_reg_cache;
+ codec->write = wm8731_write;
+ codec->bias_level = SND_SOC_BIAS_OFF;
+ codec->set_bias_level = wm8731_set_bias_level;
+ codec->dai = &wm8731_dai;
+ codec->num_dai = 1;
+ codec->reg_cache_size = WM8731_CACHEREGNUM;
+ codec->reg_cache = &wm8731->reg_cache;
- client = i2c_new_device(adapter, &info);
- i2c_put_adapter(adapter);
- if (!client) {
- dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
- (unsigned int)info.addr);
- goto err_driver;
+ memcpy(codec->reg_cache, wm8731_reg, sizeof(wm8731_reg));
+
+ ret = wm8731_reset(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to issue reset\n");
+ return ret;
}
- return 0;
+ wm8731_dai.dev = codec->dev;
-err_driver:
- i2c_del_driver(&wm8731_i2c_driver);
- return -ENODEV;
-}
-#endif
+ wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-#if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8731_spi_probe(struct spi_device *spi)
-{
- struct snd_soc_device *socdev = wm8731_socdev;
- struct snd_soc_codec *codec = socdev->codec;
- int ret;
+ /* Latch the update bits */
+ reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V);
+ wm8731_write(codec, WM8731_LOUT1V, reg & ~0x0100);
+ reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V);
+ wm8731_write(codec, WM8731_ROUT1V, reg & ~0x0100);
+ reg = wm8731_read_reg_cache(codec, WM8731_LINVOL);
+ wm8731_write(codec, WM8731_LINVOL, reg & ~0x0100);
+ reg = wm8731_read_reg_cache(codec, WM8731_RINVOL);
+ wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100);
- codec->control_data = spi;
+ /* Disable bypass path by default */
+ reg = wm8731_read_reg_cache(codec, WM8731_APANA);
+ wm8731_write(codec, WM8731_APANA, reg & ~0x4);
- ret = wm8731_init(socdev);
- if (ret < 0)
- dev_err(&spi->dev, "failed to initialise WM8731\n");
+ wm8731_codec = codec;
- return ret;
-}
+ ret = snd_soc_register_codec(codec);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_register_dai(&wm8731_dai);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
+ snd_soc_unregister_codec(codec);
+ return ret;
+ }
-static int __devexit wm8731_spi_remove(struct spi_device *spi)
-{
return 0;
}
-static struct spi_driver wm8731_spi_driver = {
- .driver = {
- .name = "wm8731",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- },
- .probe = wm8731_spi_probe,
- .remove = __devexit_p(wm8731_spi_remove),
-};
+static void wm8731_unregister(struct wm8731_priv *wm8731)
+{
+ wm8731_set_bias_level(&wm8731->codec, SND_SOC_BIAS_OFF);
+ snd_soc_unregister_dai(&wm8731_dai);
+ snd_soc_unregister_codec(&wm8731->codec);
+ kfree(wm8731);
+ wm8731_codec = NULL;
+}
+#if defined(CONFIG_SPI_MASTER)
static int wm8731_spi_write(struct spi_device *spi, const char *data, int len)
{
struct spi_transfer t;
@@ -707,101 +651,121 @@ static int wm8731_spi_write(struct spi_device *spi, const char *data, int len)
return len;
}
-#endif /* CONFIG_SPI_MASTER */
-static int wm8731_probe(struct platform_device *pdev)
+static int __devinit wm8731_spi_probe(struct spi_device *spi)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct wm8731_setup_data *setup;
struct snd_soc_codec *codec;
struct wm8731_priv *wm8731;
- int ret = 0;
-
- pr_info("WM8731 Audio Codec %s", WM8731_VERSION);
-
- setup = socdev->codec_data;
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
- if (wm8731 == NULL) {
- kfree(codec);
+ if (wm8731 == NULL)
return -ENOMEM;
- }
- codec->private_data = wm8731;
- socdev->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
+ codec = &wm8731->codec;
+ codec->control_data = spi;
+ codec->hw_write = (hw_write_t)wm8731_spi_write;
+ codec->dev = &spi->dev;
- wm8731_socdev = socdev;
- ret = -ENODEV;
+ spi->dev.driver_data = wm8731;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- if (setup->i2c_address) {
- codec->hw_write = (hw_write_t)i2c_master_send;
- ret = wm8731_add_i2c_device(pdev, setup);
- }
-#endif
-#if defined(CONFIG_SPI_MASTER)
- if (setup->spi) {
- codec->hw_write = (hw_write_t)wm8731_spi_write;
- ret = spi_register_driver(&wm8731_spi_driver);
- if (ret != 0)
- printk(KERN_ERR "can't add spi driver");
- }
-#endif
-
- if (ret != 0) {
- kfree(codec->private_data);
- kfree(codec);
- }
- return ret;
+ return wm8731_register(wm8731);
}
-/* power down chip */
-static int wm8731_remove(struct platform_device *pdev)
+static int __devexit wm8731_spi_remove(struct spi_device *spi)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct wm8731_priv *wm8731 = spi->dev.driver_data;
- if (codec->control_data)
- wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ wm8731_unregister(wm8731);
+
+ return 0;
+}
+
+static struct spi_driver wm8731_spi_driver = {
+ .driver = {
+ .name = "wm8731",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8731_spi_probe,
+ .remove = __devexit_p(wm8731_spi_remove),
+};
+#endif /* CONFIG_SPI_MASTER */
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- i2c_unregister_device(codec->control_data);
- i2c_del_driver(&wm8731_i2c_driver);
-#endif
-#if defined(CONFIG_SPI_MASTER)
- spi_unregister_driver(&wm8731_spi_driver);
-#endif
- kfree(codec->private_data);
- kfree(codec);
+static __devinit int wm8731_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8731_priv *wm8731;
+ struct snd_soc_codec *codec;
+
+ wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
+ if (wm8731 == NULL)
+ return -ENOMEM;
+
+ codec = &wm8731->codec;
+ codec->hw_write = (hw_write_t)i2c_master_send;
+ i2c_set_clientdata(i2c, wm8731);
+ codec->control_data = i2c;
+
+ codec->dev = &i2c->dev;
+
+ return wm8731_register(wm8731);
+}
+
+static __devexit int wm8731_i2c_remove(struct i2c_client *client)
+{
+ struct wm8731_priv *wm8731 = i2c_get_clientdata(client);
+ wm8731_unregister(wm8731);
return 0;
}
-struct snd_soc_codec_device soc_codec_dev_wm8731 = {
- .probe = wm8731_probe,
- .remove = wm8731_remove,
- .suspend = wm8731_suspend,
- .resume = wm8731_resume,
+static const struct i2c_device_id wm8731_i2c_id[] = {
+ { "wm8731", 0 },
+ { }
};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);
+MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id);
+
+static struct i2c_driver wm8731_i2c_driver = {
+ .driver = {
+ .name = "WM8731 I2C Codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8731_i2c_probe,
+ .remove = __devexit_p(wm8731_i2c_remove),
+ .id_table = wm8731_i2c_id,
+};
+#endif
static int __init wm8731_modinit(void)
{
- return snd_soc_register_dai(&wm8731_dai);
+ int ret;
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8731_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8731 I2C driver: %d\n",
+ ret);
+ }
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ ret = spi_register_driver(&wm8731_spi_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register WM8731 SPI driver: %d\n",
+ ret);
+ }
+#endif
+ return 0;
}
module_init(wm8731_modinit);
static void __exit wm8731_exit(void)
{
- snd_soc_unregister_dai(&wm8731_dai);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8731_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ spi_unregister_driver(&wm8731_spi_driver);
+#endif
}
module_exit(wm8731_exit);
diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h
index 95190e9c0c1..cd7b806e8ad 100644
--- a/sound/soc/codecs/wm8731.h
+++ b/sound/soc/codecs/wm8731.h
@@ -34,12 +34,6 @@
#define WM8731_SYSCLK 0
#define WM8731_DAI 0
-struct wm8731_setup_data {
- int spi;
- int i2c_bus;
- unsigned short i2c_address;
-};
-
extern struct snd_soc_dai wm8731_dai;
extern struct snd_soc_codec_device soc_codec_dev_wm8731;
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index 5997fa68e0d..b64509b01a4 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -231,21 +231,6 @@ SOC_SINGLE("Mono Playback Volume", WM8750_MOUTV, 0, 127, 0),
};
-/* add non dapm controls */
-static int wm8750_add_controls(struct snd_soc_codec *codec)
-{
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(wm8750_snd_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm8750_snd_controls[i],
- codec, NULL));
- if (err < 0)
- return err;
- }
- return 0;
-}
-
/*
* DAPM Controls
*/
@@ -619,7 +604,7 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct wm8750_priv *wm8750 = codec->private_data;
u16 iface = wm8750_read_reg_cache(codec, WM8750_IFACE) & 0x1f3;
u16 srate = wm8750_read_reg_cache(codec, WM8750_SRATE) & 0x1c0;
@@ -694,6 +679,13 @@ static int wm8750_set_bias_level(struct snd_soc_codec *codec,
#define WM8750_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE)
+static struct snd_soc_dai_ops wm8750_dai_ops = {
+ .hw_params = wm8750_pcm_hw_params,
+ .digital_mute = wm8750_mute,
+ .set_fmt = wm8750_set_dai_fmt,
+ .set_sysclk = wm8750_set_dai_sysclk,
+};
+
struct snd_soc_dai wm8750_dai = {
.name = "WM8750",
.playback = {
@@ -708,12 +700,7 @@ struct snd_soc_dai wm8750_dai = {
.channels_max = 2,
.rates = WM8750_RATES,
.formats = WM8750_FORMATS,},
- .ops = {
- .hw_params = wm8750_pcm_hw_params,
- .digital_mute = wm8750_mute,
- .set_fmt = wm8750_set_dai_fmt,
- .set_sysclk = wm8750_set_dai_sysclk,
- },
+ .ops = &wm8750_dai_ops,
};
EXPORT_SYMBOL_GPL(wm8750_dai);
@@ -727,7 +714,7 @@ static void wm8750_work(struct work_struct *work)
static int wm8750_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
@@ -736,7 +723,7 @@ static int wm8750_suspend(struct platform_device *pdev, pm_message_t state)
static int wm8750_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -769,7 +756,7 @@ static int wm8750_resume(struct platform_device *pdev)
*/
static int wm8750_init(struct snd_soc_device *socdev)
{
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int reg, ret = 0;
codec->name = "WM8750";
@@ -816,7 +803,8 @@ static int wm8750_init(struct snd_soc_device *socdev)
reg = wm8750_read_reg_cache(codec, WM8750_RINVOL);
wm8750_write(codec, WM8750_RINVOL, reg | 0x0100);
- wm8750_add_controls(codec);
+ snd_soc_add_controls(codec, wm8750_snd_controls,
+ ARRAY_SIZE(wm8750_snd_controls));
wm8750_add_widgets(codec);
ret = snd_soc_init_card(socdev);
if (ret < 0) {
@@ -850,7 +838,7 @@ static int wm8750_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct snd_soc_device *socdev = wm8750_socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int ret;
i2c_set_clientdata(i2c, codec);
@@ -931,7 +919,7 @@ err_driver:
static int __devinit wm8750_spi_probe(struct spi_device *spi)
{
struct snd_soc_device *socdev = wm8750_socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int ret;
codec->control_data = spi;
@@ -1003,7 +991,7 @@ static int wm8750_probe(struct platform_device *pdev)
}
codec->private_data = wm8750;
- socdev->codec = codec;
+ socdev->card->codec = codec;
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
@@ -1057,7 +1045,7 @@ static int run_delayed_work(struct delayed_work *dwork)
static int wm8750_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
if (codec->control_data)
wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF);
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index 6c21b50c937..a6e8f3f7f05 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -51,8 +51,6 @@
#include "wm8753.h"
-#define WM8753_VERSION "0.16"
-
static int caps_charge = 2000;
module_param(caps_charge, int, 0);
MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)");
@@ -60,12 +58,6 @@ MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)");
static void wm8753_set_dai_mode(struct snd_soc_codec *codec,
unsigned int mode);
-/* codec private data */
-struct wm8753_priv {
- unsigned int sysclk;
- unsigned int pcmclk;
-};
-
/*
* wm8753 register cache
* We can't read the WM8753 register space when we
@@ -90,6 +82,14 @@ static const u16 wm8753_reg[] = {
0x0000, 0x0000
};
+/* codec private data */
+struct wm8753_priv {
+ unsigned int sysclk;
+ unsigned int pcmclk;
+ struct snd_soc_codec codec;
+ u16 reg_cache[ARRAY_SIZE(wm8753_reg)];
+};
+
/*
* read wm8753 register cache
*/
@@ -97,7 +97,7 @@ static inline unsigned int wm8753_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
- if (reg < 1 || reg > (ARRAY_SIZE(wm8753_reg) + 1))
+ if (reg < 1 || reg >= (ARRAY_SIZE(wm8753_reg) + 1))
return -1;
return cache[reg - 1];
}
@@ -109,7 +109,7 @@ static inline void wm8753_write_reg_cache(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value)
{
u16 *cache = codec->reg_cache;
- if (reg < 1 || reg > 0x3f)
+ if (reg < 1 || reg >= (ARRAY_SIZE(wm8753_reg) + 1))
return;
cache[reg - 1] = value;
}
@@ -339,21 +339,6 @@ SOC_ENUM("ADC Data Select", wm8753_enum[27]),
SOC_ENUM("ROUT2 Phase", wm8753_enum[28]),
};
-/* add non dapm controls */
-static int wm8753_add_controls(struct snd_soc_codec *codec)
-{
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(wm8753_snd_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm8753_snd_controls[i],
- codec, NULL));
- if (err < 0)
- return err;
- }
- return 0;
-}
-
/*
* _DAPM_ Controls
*/
@@ -927,7 +912,7 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct wm8753_priv *wm8753 = codec->private_data;
u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3;
u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f;
@@ -1161,7 +1146,7 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct wm8753_priv *wm8753 = codec->private_data;
u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0;
u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3;
@@ -1316,6 +1301,51 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec,
* 3. Voice disabled - HIFI over HIFI
* 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture
*/
+static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = {
+ .hw_params = wm8753_i2s_hw_params,
+ .digital_mute = wm8753_mute,
+ .set_fmt = wm8753_mode1h_set_dai_fmt,
+ .set_clkdiv = wm8753_set_dai_clkdiv,
+ .set_pll = wm8753_set_dai_pll,
+ .set_sysclk = wm8753_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = {
+ .hw_params = wm8753_pcm_hw_params,
+ .digital_mute = wm8753_mute,
+ .set_fmt = wm8753_mode1v_set_dai_fmt,
+ .set_clkdiv = wm8753_set_dai_clkdiv,
+ .set_pll = wm8753_set_dai_pll,
+ .set_sysclk = wm8753_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = {
+ .hw_params = wm8753_pcm_hw_params,
+ .digital_mute = wm8753_mute,
+ .set_fmt = wm8753_mode2_set_dai_fmt,
+ .set_clkdiv = wm8753_set_dai_clkdiv,
+ .set_pll = wm8753_set_dai_pll,
+ .set_sysclk = wm8753_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3 = {
+ .hw_params = wm8753_i2s_hw_params,
+ .digital_mute = wm8753_mute,
+ .set_fmt = wm8753_mode3_4_set_dai_fmt,
+ .set_clkdiv = wm8753_set_dai_clkdiv,
+ .set_pll = wm8753_set_dai_pll,
+ .set_sysclk = wm8753_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4 = {
+ .hw_params = wm8753_i2s_hw_params,
+ .digital_mute = wm8753_mute,
+ .set_fmt = wm8753_mode3_4_set_dai_fmt,
+ .set_clkdiv = wm8753_set_dai_clkdiv,
+ .set_pll = wm8753_set_dai_pll,
+ .set_sysclk = wm8753_set_dai_sysclk,
+};
+
static const struct snd_soc_dai wm8753_all_dai[] = {
/* DAI HiFi mode 1 */
{ .name = "WM8753 HiFi",
@@ -1332,14 +1362,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
.channels_max = 2,
.rates = WM8753_RATES,
.formats = WM8753_FORMATS},
- .ops = {
- .hw_params = wm8753_i2s_hw_params,
- .digital_mute = wm8753_mute,
- .set_fmt = wm8753_mode1h_set_dai_fmt,
- .set_clkdiv = wm8753_set_dai_clkdiv,
- .set_pll = wm8753_set_dai_pll,
- .set_sysclk = wm8753_set_dai_sysclk,
- },
+ .ops = &wm8753_dai_ops_hifi_mode1,
},
/* DAI Voice mode 1 */
{ .name = "WM8753 Voice",
@@ -1356,14 +1379,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
.channels_max = 2,
.rates = WM8753_RATES,
.formats = WM8753_FORMATS,},
- .ops = {
- .hw_params = wm8753_pcm_hw_params,
- .digital_mute = wm8753_mute,
- .set_fmt = wm8753_mode1v_set_dai_fmt,
- .set_clkdiv = wm8753_set_dai_clkdiv,
- .set_pll = wm8753_set_dai_pll,
- .set_sysclk = wm8753_set_dai_sysclk,
- },
+ .ops = &wm8753_dai_ops_voice_mode1,
},
/* DAI HiFi mode 2 - dummy */
{ .name = "WM8753 HiFi",
@@ -1384,14 +1400,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
.channels_max = 2,
.rates = WM8753_RATES,
.formats = WM8753_FORMATS,},
- .ops = {
- .hw_params = wm8753_pcm_hw_params,
- .digital_mute = wm8753_mute,
- .set_fmt = wm8753_mode2_set_dai_fmt,
- .set_clkdiv = wm8753_set_dai_clkdiv,
- .set_pll = wm8753_set_dai_pll,
- .set_sysclk = wm8753_set_dai_sysclk,
- },
+ .ops = &wm8753_dai_ops_voice_mode2,
},
/* DAI HiFi mode 3 */
{ .name = "WM8753 HiFi",
@@ -1408,14 +1417,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
.channels_max = 2,
.rates = WM8753_RATES,
.formats = WM8753_FORMATS,},
- .ops = {
- .hw_params = wm8753_i2s_hw_params,
- .digital_mute = wm8753_mute,
- .set_fmt = wm8753_mode3_4_set_dai_fmt,
- .set_clkdiv = wm8753_set_dai_clkdiv,
- .set_pll = wm8753_set_dai_pll,
- .set_sysclk = wm8753_set_dai_sysclk,
- },
+ .ops = &wm8753_dai_ops_hifi_mode3,
},
/* DAI Voice mode 3 - dummy */
{ .name = "WM8753 Voice",
@@ -1436,14 +1438,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
.channels_max = 2,
.rates = WM8753_RATES,
.formats = WM8753_FORMATS,},
- .ops = {
- .hw_params = wm8753_i2s_hw_params,
- .digital_mute = wm8753_mute,
- .set_fmt = wm8753_mode3_4_set_dai_fmt,
- .set_clkdiv = wm8753_set_dai_clkdiv,
- .set_pll = wm8753_set_dai_pll,
- .set_sysclk = wm8753_set_dai_sysclk,
- },
+ .ops = &wm8753_dai_ops_hifi_mode4,
},
/* DAI Voice mode 4 - dummy */
{ .name = "WM8753 Voice",
@@ -1451,7 +1446,14 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
},
};
-struct snd_soc_dai wm8753_dai[2];
+struct snd_soc_dai wm8753_dai[] = {
+ {
+ .name = "WM8753 DAI 0",
+ },
+ {
+ .name = "WM8753 DAI 1",
+ },
+};
EXPORT_SYMBOL_GPL(wm8753_dai);
static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode)
@@ -1459,30 +1461,35 @@ static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode)
if (mode < 4) {
int playback_active, capture_active, codec_active, pop_wait;
void *private_data;
+ struct list_head list;
playback_active = wm8753_dai[0].playback.active;
capture_active = wm8753_dai[0].capture.active;
codec_active = wm8753_dai[0].active;
private_data = wm8753_dai[0].private_data;
pop_wait = wm8753_dai[0].pop_wait;
+ list = wm8753_dai[0].list;
wm8753_dai[0] = wm8753_all_dai[mode << 1];
wm8753_dai[0].playback.active = playback_active;
wm8753_dai[0].capture.active = capture_active;
wm8753_dai[0].active = codec_active;
wm8753_dai[0].private_data = private_data;
wm8753_dai[0].pop_wait = pop_wait;
+ wm8753_dai[0].list = list;
playback_active = wm8753_dai[1].playback.active;
capture_active = wm8753_dai[1].capture.active;
codec_active = wm8753_dai[1].active;
private_data = wm8753_dai[1].private_data;
pop_wait = wm8753_dai[1].pop_wait;
+ list = wm8753_dai[1].list;
wm8753_dai[1] = wm8753_all_dai[(mode << 1) + 1];
wm8753_dai[1].playback.active = playback_active;
wm8753_dai[1].capture.active = capture_active;
wm8753_dai[1].active = codec_active;
wm8753_dai[1].private_data = private_data;
wm8753_dai[1].pop_wait = pop_wait;
+ wm8753_dai[1].list = list;
}
wm8753_dai[0].codec = codec;
wm8753_dai[1].codec = codec;
@@ -1498,7 +1505,7 @@ static void wm8753_work(struct work_struct *work)
static int wm8753_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
/* we only need to suspend if we are a valid card */
if (!codec->card)
@@ -1511,7 +1518,7 @@ static int wm8753_suspend(struct platform_device *pdev, pm_message_t state)
static int wm8753_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -1524,6 +1531,11 @@ static int wm8753_resume(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(wm8753_reg); i++) {
if (i + 1 == WM8753_RESET)
continue;
+
+ /* No point in writing hardware default values back */
+ if (cache[i] == wm8753_reg[i])
+ continue;
+
data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001);
data[1] = cache[i] & 0x00ff;
codec->hw_write(codec->control_data, data, 2);
@@ -1542,44 +1554,129 @@ static int wm8753_resume(struct platform_device *pdev)
return 0;
}
+static struct snd_soc_codec *wm8753_codec;
+
+static int wm8753_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret = 0;
+
+ if (!wm8753_codec) {
+ dev_err(&pdev->dev, "WM8753 codec not yet registered\n");
+ return -EINVAL;
+ }
+
+ socdev->card->codec = wm8753_codec;
+ codec = wm8753_codec;
+
+ wm8753_set_dai_mode(codec, 0);
+
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ printk(KERN_ERR "wm8753: failed to create pcms\n");
+ goto pcm_err;
+ }
+
+ snd_soc_add_controls(codec, wm8753_snd_controls,
+ ARRAY_SIZE(wm8753_snd_controls));
+ wm8753_add_widgets(codec);
+ ret = snd_soc_init_card(socdev);
+ if (ret < 0) {
+ printk(KERN_ERR "wm8753: failed to register card\n");
+ goto card_err;
+ }
+
+ return 0;
+
+card_err:
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+
+pcm_err:
+ return ret;
+}
+
/*
- * initialise the WM8753 driver
- * register the mixer and dsp interfaces with the kernel
+ * This function forces any delayed work to be queued and run.
*/
-static int wm8753_init(struct snd_soc_device *socdev)
+static int run_delayed_work(struct delayed_work *dwork)
+{
+ int ret;
+
+ /* cancel any work waiting to be queued. */
+ ret = cancel_delayed_work(dwork);
+
+ /* if there was any work waiting then we run it now and
+ * wait for it's completion */
+ if (ret) {
+ schedule_delayed_work(dwork, 0);
+ flush_scheduled_work();
+ }
+ return ret;
+}
+
+/* power down chip */
+static int wm8753_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm8753 = {
+ .probe = wm8753_probe,
+ .remove = wm8753_remove,
+ .suspend = wm8753_suspend,
+ .resume = wm8753_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753);
+
+static int wm8753_register(struct wm8753_priv *wm8753)
{
- struct snd_soc_codec *codec = socdev->codec;
- int reg, ret = 0;
+ int ret, i;
+ struct snd_soc_codec *codec = &wm8753->codec;
+ u16 reg;
+
+ if (wm8753_codec) {
+ dev_err(codec->dev, "Multiple WM8753 devices not supported\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
codec->name = "WM8753";
codec->owner = THIS_MODULE;
codec->read = wm8753_read_reg_cache;
codec->write = wm8753_write;
+ codec->bias_level = SND_SOC_BIAS_STANDBY;
codec->set_bias_level = wm8753_set_bias_level;
codec->dai = wm8753_dai;
codec->num_dai = 2;
- codec->reg_cache_size = ARRAY_SIZE(wm8753_reg);
- codec->reg_cache = kmemdup(wm8753_reg, sizeof(wm8753_reg), GFP_KERNEL);
-
- if (codec->reg_cache == NULL)
- return -ENOMEM;
-
- wm8753_set_dai_mode(codec, 0);
+ codec->reg_cache_size = ARRAY_SIZE(wm8753->reg_cache);
+ codec->reg_cache = &wm8753->reg_cache;
+ codec->private_data = wm8753;
- wm8753_reset(codec);
+ memcpy(codec->reg_cache, wm8753_reg, sizeof(codec->reg_cache));
+ INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
- /* register pcms */
- ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ ret = wm8753_reset(codec);
if (ret < 0) {
- printk(KERN_ERR "wm8753: failed to create pcms\n");
- goto pcm_err;
+ dev_err(codec->dev, "Failed to issue reset\n");
+ goto err;
}
/* charge output caps */
wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
- codec->bias_level = SND_SOC_BIAS_STANDBY;
schedule_delayed_work(&codec->delayed_work,
- msecs_to_jiffies(caps_charge));
+ msecs_to_jiffies(caps_charge));
/* set the update bits */
reg = wm8753_read_reg_cache(codec, WM8753_LDAC);
@@ -1603,59 +1700,70 @@ static int wm8753_init(struct snd_soc_device *socdev)
reg = wm8753_read_reg_cache(codec, WM8753_RINVOL);
wm8753_write(codec, WM8753_RINVOL, reg | 0x0100);
- wm8753_add_controls(codec);
- wm8753_add_widgets(codec);
- ret = snd_soc_init_card(socdev);
- if (ret < 0) {
- printk(KERN_ERR "wm8753: failed to register card\n");
- goto card_err;
+ wm8753_codec = codec;
+
+ for (i = 0; i < ARRAY_SIZE(wm8753_dai); i++)
+ wm8753_dai[i].dev = codec->dev;
+
+ ret = snd_soc_register_codec(codec);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+ goto err;
}
- return ret;
+ ret = snd_soc_register_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai));
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
+ goto err_codec;
+ }
-card_err:
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
-pcm_err:
- kfree(codec->reg_cache);
+ return 0;
+
+err_codec:
+ run_delayed_work(&codec->delayed_work);
+ snd_soc_unregister_codec(codec);
+err:
+ kfree(wm8753);
return ret;
}
-/* If the i2c layer weren't so broken, we could pass this kind of data
- around */
-static struct snd_soc_device *wm8753_socdev;
+static void wm8753_unregister(struct wm8753_priv *wm8753)
+{
+ wm8753_set_bias_level(&wm8753->codec, SND_SOC_BIAS_OFF);
+ run_delayed_work(&wm8753->codec.delayed_work);
+ snd_soc_unregister_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai));
+ snd_soc_unregister_codec(&wm8753->codec);
+ kfree(wm8753);
+ wm8753_codec = NULL;
+}
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-/*
- * WM8753 2 wire address is determined by GPIO5
- * state during powerup.
- * low = 0x1a
- * high = 0x1b
- */
-
static int wm8753_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
- struct snd_soc_device *socdev = wm8753_socdev;
- struct snd_soc_codec *codec = socdev->codec;
- int ret;
+ struct snd_soc_codec *codec;
+ struct wm8753_priv *wm8753;
- i2c_set_clientdata(i2c, codec);
- codec->control_data = i2c;
+ wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL);
+ if (wm8753 == NULL)
+ return -ENOMEM;
- ret = wm8753_init(socdev);
- if (ret < 0)
- pr_err("failed to initialise WM8753\n");
+ codec = &wm8753->codec;
+ codec->hw_write = (hw_write_t)i2c_master_send;
+ codec->control_data = i2c;
+ i2c_set_clientdata(i2c, wm8753);
- return ret;
+ codec->dev = &i2c->dev;
+
+ return wm8753_register(wm8753);
}
static int wm8753_i2c_remove(struct i2c_client *client)
{
- struct snd_soc_codec *codec = i2c_get_clientdata(client);
- kfree(codec->reg_cache);
- return 0;
+ struct wm8753_priv *wm8753 = i2c_get_clientdata(client);
+ wm8753_unregister(wm8753);
+ return 0;
}
static const struct i2c_device_id wm8753_i2c_id[] = {
@@ -1666,86 +1774,16 @@ MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id);
static struct i2c_driver wm8753_i2c_driver = {
.driver = {
- .name = "WM8753 I2C Codec",
+ .name = "wm8753",
.owner = THIS_MODULE,
},
.probe = wm8753_i2c_probe,
.remove = wm8753_i2c_remove,
.id_table = wm8753_i2c_id,
};
-
-static int wm8753_add_i2c_device(struct platform_device *pdev,
- const struct wm8753_setup_data *setup)
-{
- struct i2c_board_info info;
- struct i2c_adapter *adapter;
- struct i2c_client *client;
- int ret;
-
- ret = i2c_add_driver(&wm8753_i2c_driver);
- if (ret != 0) {
- dev_err(&pdev->dev, "can't add i2c driver\n");
- return ret;
- }
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = setup->i2c_address;
- strlcpy(info.type, "wm8753", I2C_NAME_SIZE);
-
- adapter = i2c_get_adapter(setup->i2c_bus);
- if (!adapter) {
- dev_err(&pdev->dev, "can't get i2c adapter %d\n",
- setup->i2c_bus);
- goto err_driver;
- }
-
- client = i2c_new_device(adapter, &info);
- i2c_put_adapter(adapter);
- if (!client) {
- dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
- (unsigned int)info.addr);
- goto err_driver;
- }
-
- return 0;
-
-err_driver:
- i2c_del_driver(&wm8753_i2c_driver);
- return -ENODEV;
-}
#endif
#if defined(CONFIG_SPI_MASTER)
-static int __devinit wm8753_spi_probe(struct spi_device *spi)
-{
- struct snd_soc_device *socdev = wm8753_socdev;
- struct snd_soc_codec *codec = socdev->codec;
- int ret;
-
- codec->control_data = spi;
-
- ret = wm8753_init(socdev);
- if (ret < 0)
- dev_err(&spi->dev, "failed to initialise WM8753\n");
-
- return ret;
-}
-
-static int __devexit wm8753_spi_remove(struct spi_device *spi)
-{
- return 0;
-}
-
-static struct spi_driver wm8753_spi_driver = {
- .driver = {
- .name = "wm8753",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- },
- .probe = wm8753_spi_probe,
- .remove = __devexit_p(wm8753_spi_remove),
-};
-
static int wm8753_spi_write(struct spi_device *spi, const char *data, int len)
{
struct spi_transfer t;
@@ -1769,120 +1807,69 @@ static int wm8753_spi_write(struct spi_device *spi, const char *data, int len)
return len;
}
-#endif
-
-static int wm8753_probe(struct platform_device *pdev)
+static int __devinit wm8753_spi_probe(struct spi_device *spi)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct wm8753_setup_data *setup;
struct snd_soc_codec *codec;
struct wm8753_priv *wm8753;
- int ret = 0;
-
- pr_info("WM8753 Audio Codec %s", WM8753_VERSION);
-
- setup = socdev->codec_data;
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (codec == NULL)
- return -ENOMEM;
wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL);
- if (wm8753 == NULL) {
- kfree(codec);
+ if (wm8753 == NULL)
return -ENOMEM;
- }
- codec->private_data = wm8753;
- socdev->codec = codec;
- mutex_init(&codec->mutex);
- INIT_LIST_HEAD(&codec->dapm_widgets);
- INIT_LIST_HEAD(&codec->dapm_paths);
- wm8753_socdev = socdev;
- INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
+ codec = &wm8753->codec;
+ codec->control_data = spi;
+ codec->hw_write = (hw_write_t)wm8753_spi_write;
+ codec->dev = &spi->dev;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- if (setup->i2c_address) {
- codec->hw_write = (hw_write_t)i2c_master_send;
- ret = wm8753_add_i2c_device(pdev, setup);
- }
-#endif
-#if defined(CONFIG_SPI_MASTER)
- if (setup->spi) {
- codec->hw_write = (hw_write_t)wm8753_spi_write;
- ret = spi_register_driver(&wm8753_spi_driver);
- if (ret != 0)
- printk(KERN_ERR "can't add spi driver");
- }
-#endif
+ spi->dev.driver_data = wm8753;
- if (ret != 0) {
- kfree(codec->private_data);
- kfree(codec);
- }
- return ret;
+ return wm8753_register(wm8753);
}
-/*
- * This function forces any delayed work to be queued and run.
- */
-static int run_delayed_work(struct delayed_work *dwork)
+static int __devexit wm8753_spi_remove(struct spi_device *spi)
{
- int ret;
-
- /* cancel any work waiting to be queued. */
- ret = cancel_delayed_work(dwork);
-
- /* if there was any work waiting then we run it now and
- * wait for it's completion */
- if (ret) {
- schedule_delayed_work(dwork, 0);
- flush_scheduled_work();
- }
- return ret;
+ struct wm8753_priv *wm8753 = spi->dev.driver_data;
+ wm8753_unregister(wm8753);
+ return 0;
}
-/* power down chip */
-static int wm8753_remove(struct platform_device *pdev)
-{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+static struct spi_driver wm8753_spi_driver = {
+ .driver = {
+ .name = "wm8753",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8753_spi_probe,
+ .remove = __devexit_p(wm8753_spi_remove),
+};
+#endif
- if (codec->control_data)
- wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
- run_delayed_work(&codec->delayed_work);
- snd_soc_free_pcms(socdev);
- snd_soc_dapm_free(socdev);
+static int __init wm8753_modinit(void)
+{
+ int ret;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- i2c_unregister_device(codec->control_data);
- i2c_del_driver(&wm8753_i2c_driver);
+ ret = i2c_add_driver(&wm8753_i2c_driver);
+ if (ret != 0)
+ pr_err("Failed to register WM8753 I2C driver: %d\n", ret);
#endif
#if defined(CONFIG_SPI_MASTER)
- spi_unregister_driver(&wm8753_spi_driver);
+ ret = spi_register_driver(&wm8753_spi_driver);
+ if (ret != 0)
+ pr_err("Failed to register WM8753 SPI driver: %d\n", ret);
#endif
- kfree(codec->private_data);
- kfree(codec);
-
return 0;
}
-
-struct snd_soc_codec_device soc_codec_dev_wm8753 = {
- .probe = wm8753_probe,
- .remove = wm8753_remove,
- .suspend = wm8753_suspend,
- .resume = wm8753_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753);
-
-static int __init wm8753_modinit(void)
-{
- return snd_soc_register_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai));
-}
module_init(wm8753_modinit);
static void __exit wm8753_exit(void)
{
- snd_soc_unregister_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai));
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8753_i2c_driver);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+ spi_unregister_driver(&wm8753_spi_driver);
+#endif
}
module_exit(wm8753_exit);
diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h
index f55704ce931..57b2ba24404 100644
--- a/sound/soc/codecs/wm8753.h
+++ b/sound/soc/codecs/wm8753.h
@@ -77,12 +77,6 @@
#define WM8753_BIASCTL 0x3d
#define WM8753_ADCTL2 0x3f
-struct wm8753_setup_data {
- int spi;
- int i2c_bus;
- unsigned short i2c_address;
-};
-
#define WM8753_PLL1 0
#define WM8753_PLL2 1
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index 6767de10ded..46c5ea1ff92 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -517,22 +517,6 @@ SOC_SINGLE("LINEOUT2 LP -12dB", WM8900_REG_LOUTMIXCTL1,
};
-/* add non dapm controls */
-static int wm8900_add_controls(struct snd_soc_codec *codec)
-{
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(wm8900_snd_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm8900_snd_controls[i],
- codec, NULL));
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
static const struct snd_kcontrol_new wm8900_dapm_loutput2_control =
SOC_DAPM_SINGLE("LINEOUT2L Switch", WM8900_REG_POWER3, 6, 1, 0);
@@ -736,7 +720,7 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
u16 reg;
reg = wm8900_read(codec, WM8900_REG_AUDIO1) & ~0x60;
@@ -1104,6 +1088,14 @@ static int wm8900_digital_mute(struct snd_soc_dai *codec_dai, int mute)
(SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \
SNDRV_PCM_FORMAT_S24_LE)
+static struct snd_soc_dai_ops wm8900_dai_ops = {
+ .hw_params = wm8900_hw_params,
+ .set_clkdiv = wm8900_set_dai_clkdiv,
+ .set_pll = wm8900_set_dai_pll,
+ .set_fmt = wm8900_set_dai_fmt,
+ .digital_mute = wm8900_digital_mute,
+};
+
struct snd_soc_dai wm8900_dai = {
.name = "WM8900 HiFi",
.playback = {
@@ -1120,13 +1112,7 @@ struct snd_soc_dai wm8900_dai = {
.rates = WM8900_RATES,
.formats = WM8900_PCM_FORMATS,
},
- .ops = {
- .hw_params = wm8900_hw_params,
- .set_clkdiv = wm8900_set_dai_clkdiv,
- .set_pll = wm8900_set_dai_pll,
- .set_fmt = wm8900_set_dai_fmt,
- .digital_mute = wm8900_digital_mute,
- },
+ .ops = &wm8900_dai_ops,
};
EXPORT_SYMBOL_GPL(wm8900_dai);
@@ -1226,7 +1212,7 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec,
static int wm8900_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct wm8900_priv *wm8900 = codec->private_data;
int fll_out = wm8900->fll_out;
int fll_in = wm8900->fll_in;
@@ -1250,7 +1236,7 @@ static int wm8900_suspend(struct platform_device *pdev, pm_message_t state)
static int wm8900_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct wm8900_priv *wm8900 = codec->private_data;
u16 *cache;
int i, ret;
@@ -1288,8 +1274,8 @@ static int wm8900_resume(struct platform_device *pdev)
static struct snd_soc_codec *wm8900_codec;
-static int wm8900_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
struct wm8900_priv *wm8900;
struct snd_soc_codec *codec;
@@ -1388,7 +1374,7 @@ err:
return ret;
}
-static int wm8900_i2c_remove(struct i2c_client *client)
+static __devexit int wm8900_i2c_remove(struct i2c_client *client)
{
snd_soc_unregister_dai(&wm8900_dai);
snd_soc_unregister_codec(wm8900_codec);
@@ -1414,7 +1400,7 @@ static struct i2c_driver wm8900_i2c_driver = {
.owner = THIS_MODULE,
},
.probe = wm8900_i2c_probe,
- .remove = wm8900_i2c_remove,
+ .remove = __devexit_p(wm8900_i2c_remove),
.id_table = wm8900_i2c_id,
};
@@ -1430,7 +1416,7 @@ static int wm8900_probe(struct platform_device *pdev)
}
codec = wm8900_codec;
- socdev->codec = codec;
+ socdev->card->codec = codec;
/* Register pcms */
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
@@ -1439,7 +1425,8 @@ static int wm8900_probe(struct platform_device *pdev)
goto pcm_err;
}
- wm8900_add_controls(codec);
+ snd_soc_add_controls(codec, wm8900_snd_controls,
+ ARRAY_SIZE(wm8900_snd_controls));
wm8900_add_widgets(codec);
ret = snd_soc_init_card(socdev);
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index bde74546db4..8cf571f1a80 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -744,21 +744,6 @@ SOC_DOUBLE_R_TLV("Speaker Volume",
0, 63, 0, out_tlv),
};
-static int wm8903_add_controls(struct snd_soc_codec *codec)
-{
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(wm8903_snd_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm8903_snd_controls[i],
- codec, NULL));
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
static const struct snd_kcontrol_new linput_mode_mux =
SOC_DAPM_ENUM("Left Input Mode Mux", linput_mode_enum);
@@ -1276,7 +1261,7 @@ static int wm8903_startup(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct wm8903_priv *wm8903 = codec->private_data;
struct i2c_client *i2c = codec->control_data;
struct snd_pcm_runtime *master_runtime;
@@ -1318,7 +1303,7 @@ static void wm8903_shutdown(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct wm8903_priv *wm8903 = codec->private_data;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -1338,7 +1323,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct wm8903_priv *wm8903 = codec->private_data;
struct i2c_client *i2c = codec->control_data;
int fs = params_rate(params);
@@ -1512,6 +1497,15 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE)
+static struct snd_soc_dai_ops wm8903_dai_ops = {
+ .startup = wm8903_startup,
+ .shutdown = wm8903_shutdown,
+ .hw_params = wm8903_hw_params,
+ .digital_mute = wm8903_digital_mute,
+ .set_fmt = wm8903_set_dai_fmt,
+ .set_sysclk = wm8903_set_dai_sysclk,
+};
+
struct snd_soc_dai wm8903_dai = {
.name = "WM8903",
.playback = {
@@ -1528,21 +1522,14 @@ struct snd_soc_dai wm8903_dai = {
.rates = WM8903_CAPTURE_RATES,
.formats = WM8903_FORMATS,
},
- .ops = {
- .startup = wm8903_startup,
- .shutdown = wm8903_shutdown,
- .hw_params = wm8903_hw_params,
- .digital_mute = wm8903_digital_mute,
- .set_fmt = wm8903_set_dai_fmt,
- .set_sysclk = wm8903_set_dai_sysclk
- }
+ .ops = &wm8903_dai_ops,
};
EXPORT_SYMBOL_GPL(wm8903_dai);
static int wm8903_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
@@ -1552,7 +1539,7 @@ static int wm8903_suspend(struct platform_device *pdev, pm_message_t state)
static int wm8903_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct i2c_client *i2c = codec->control_data;
int i;
u16 *reg_cache = codec->reg_cache;
@@ -1577,8 +1564,8 @@ static int wm8903_resume(struct platform_device *pdev)
static struct snd_soc_codec *wm8903_codec;
-static int wm8903_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
{
struct wm8903_priv *wm8903;
struct snd_soc_codec *codec;
@@ -1684,7 +1671,7 @@ err:
return ret;
}
-static int wm8903_i2c_remove(struct i2c_client *client)
+static __devexit int wm8903_i2c_remove(struct i2c_client *client)
{
struct snd_soc_codec *codec = i2c_get_clientdata(client);
@@ -1714,7 +1701,7 @@ static struct i2c_driver wm8903_i2c_driver = {
.owner = THIS_MODULE,
},
.probe = wm8903_i2c_probe,
- .remove = wm8903_i2c_remove,
+ .remove = __devexit_p(wm8903_i2c_remove),
.id_table = wm8903_i2c_id,
};
@@ -1728,7 +1715,7 @@ static int wm8903_probe(struct platform_device *pdev)
goto err;
}
- socdev->codec = wm8903_codec;
+ socdev->card->codec = wm8903_codec;
/* register pcms */
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
@@ -1737,8 +1724,9 @@ static int wm8903_probe(struct platform_device *pdev)
goto err;
}
- wm8903_add_controls(socdev->codec);
- wm8903_add_widgets(socdev->codec);
+ snd_soc_add_controls(socdev->card->codec, wm8903_snd_controls,
+ ARRAY_SIZE(wm8903_snd_controls));
+ wm8903_add_widgets(socdev->card->codec);
ret = snd_soc_init_card(socdev);
if (ret < 0) {
@@ -1759,7 +1747,7 @@ err:
static int wm8903_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
if (codec->control_data)
wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index 88ead7f8dd9..032dca22dbd 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -195,21 +195,6 @@ static const struct snd_kcontrol_new wm8971_snd_controls[] = {
SOC_DOUBLE_R("Mic Boost", WM8971_LADCIN, WM8971_RADCIN, 4, 3, 0),
};
-/* add non-DAPM controls */
-static int wm8971_add_controls(struct snd_soc_codec *codec)
-{
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(wm8971_snd_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm8971_snd_controls[i],
- codec, NULL));
- if (err < 0)
- return err;
- }
- return 0;
-}
-
/*
* DAPM Controls
*/
@@ -546,7 +531,7 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct wm8971_priv *wm8971 = codec->private_data;
u16 iface = wm8971_read_reg_cache(codec, WM8971_IFACE) & 0x1f3;
u16 srate = wm8971_read_reg_cache(codec, WM8971_SRATE) & 0x1c0;
@@ -619,6 +604,13 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec,
#define WM8971_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE)
+static struct snd_soc_dai_ops wm8971_dai_ops = {
+ .hw_params = wm8971_pcm_hw_params,
+ .digital_mute = wm8971_mute,
+ .set_fmt = wm8971_set_dai_fmt,
+ .set_sysclk = wm8971_set_dai_sysclk,
+};
+
struct snd_soc_dai wm8971_dai = {
.name = "WM8971",
.playback = {
@@ -633,12 +625,7 @@ struct snd_soc_dai wm8971_dai = {
.channels_max = 2,
.rates = WM8971_RATES,
.formats = WM8971_FORMATS,},
- .ops = {
- .hw_params = wm8971_pcm_hw_params,
- .digital_mute = wm8971_mute,
- .set_fmt = wm8971_set_dai_fmt,
- .set_sysclk = wm8971_set_dai_sysclk,
- },
+ .ops = &wm8971_dai_ops,
};
EXPORT_SYMBOL_GPL(wm8971_dai);
@@ -652,7 +639,7 @@ static void wm8971_work(struct work_struct *work)
static int wm8971_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
@@ -661,7 +648,7 @@ static int wm8971_suspend(struct platform_device *pdev, pm_message_t state)
static int wm8971_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -692,7 +679,7 @@ static int wm8971_resume(struct platform_device *pdev)
static int wm8971_init(struct snd_soc_device *socdev)
{
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int reg, ret = 0;
codec->name = "WM8971";
@@ -745,7 +732,8 @@ static int wm8971_init(struct snd_soc_device *socdev)
reg = wm8971_read_reg_cache(codec, WM8971_RINVOL);
wm8971_write(codec, WM8971_RINVOL, reg | 0x0100);
- wm8971_add_controls(codec);
+ snd_soc_add_controls(codec, wm8971_snd_controls,
+ ARRAY_SIZE(wm8971_snd_controls));
wm8971_add_widgets(codec);
ret = snd_soc_init_card(socdev);
if (ret < 0) {
@@ -772,7 +760,7 @@ static int wm8971_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct snd_soc_device *socdev = wm8971_socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int ret;
i2c_set_clientdata(i2c, codec);
@@ -873,7 +861,7 @@ static int wm8971_probe(struct platform_device *pdev)
}
codec->private_data = wm8971;
- socdev->codec = codec;
+ socdev->card->codec = codec;
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
@@ -908,7 +896,7 @@ static int wm8971_probe(struct platform_device *pdev)
static int wm8971_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
if (codec->control_data)
wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 5b5afc14447..c518c3e5aa3 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -2,8 +2,7 @@
* wm8990.c -- WM8990 ALSA Soc Audio driver
*
* Copyright 2008 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood
- * lg@opensource.wolfsonmicro.com or linux@wolfsonmicro.com
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -116,7 +115,7 @@ static inline unsigned int wm8990_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
- BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1);
+ BUG_ON(reg >= ARRAY_SIZE(wm8990_reg));
return cache[reg];
}
@@ -129,7 +128,7 @@ static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec,
u16 *cache = codec->reg_cache;
/* Reset register and reserved registers are uncached */
- if (reg == 0 || reg > ARRAY_SIZE(wm8990_reg) - 1)
+ if (reg == 0 || reg >= ARRAY_SIZE(wm8990_reg))
return;
cache[reg] = value;
@@ -177,7 +176,9 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- int reg = kcontrol->private_value & 0xff;
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ int reg = mc->reg;
int ret;
u16 val;
@@ -417,21 +418,6 @@ SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME,
};
-/* add non dapm controls */
-static int wm8990_add_controls(struct snd_soc_codec *codec)
-{
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(wm8990_snd_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm8990_snd_controls[i], codec,
- NULL));
- if (err < 0)
- return err;
- }
- return 0;
-}
-
/*
* _DAPM_ Controls
*/
@@ -1177,7 +1163,7 @@ static int wm8990_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
u16 audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1);
audio1 &= ~WM8990_AIF_WL_MASK;
@@ -1346,6 +1332,15 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
* 1. ADC/DAC on Primary Interface
* 2. ADC on Primary Interface/DAC on secondary
*/
+static struct snd_soc_dai_ops wm8990_dai_ops = {
+ .hw_params = wm8990_hw_params,
+ .digital_mute = wm8990_mute,
+ .set_fmt = wm8990_set_dai_fmt,
+ .set_clkdiv = wm8990_set_dai_clkdiv,
+ .set_pll = wm8990_set_dai_pll,
+ .set_sysclk = wm8990_set_dai_sysclk,
+};
+
struct snd_soc_dai wm8990_dai = {
/* ADC/DAC on primary */
.name = "WM8990 ADC/DAC Primary",
@@ -1362,21 +1357,14 @@ struct snd_soc_dai wm8990_dai = {
.channels_max = 2,
.rates = WM8990_RATES,
.formats = WM8990_FORMATS,},
- .ops = {
- .hw_params = wm8990_hw_params,
- .digital_mute = wm8990_mute,
- .set_fmt = wm8990_set_dai_fmt,
- .set_clkdiv = wm8990_set_dai_clkdiv,
- .set_pll = wm8990_set_dai_pll,
- .set_sysclk = wm8990_set_dai_sysclk,
- },
+ .ops = &wm8990_dai_ops,
};
EXPORT_SYMBOL_GPL(wm8990_dai);
static int wm8990_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
/* we only need to suspend if we are a valid card */
if (!codec->card)
@@ -1389,7 +1377,7 @@ static int wm8990_suspend(struct platform_device *pdev, pm_message_t state)
static int wm8990_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
@@ -1417,7 +1405,7 @@ static int wm8990_resume(struct platform_device *pdev)
*/
static int wm8990_init(struct snd_soc_device *socdev)
{
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
u16 reg;
int ret = 0;
@@ -1460,7 +1448,8 @@ static int wm8990_init(struct snd_soc_device *socdev)
wm8990_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
wm8990_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
- wm8990_add_controls(codec);
+ snd_soc_add_controls(codec, wm8990_snd_controls,
+ ARRAY_SIZE(wm8990_snd_controls));
wm8990_add_widgets(codec);
ret = snd_soc_init_card(socdev);
if (ret < 0) {
@@ -1494,7 +1483,7 @@ static int wm8990_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct snd_soc_device *socdev = wm8990_socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int ret;
i2c_set_clientdata(i2c, codec);
@@ -1593,7 +1582,7 @@ static int wm8990_probe(struct platform_device *pdev)
}
codec->private_data = wm8990;
- socdev->codec = codec;
+ socdev->card->codec = codec;
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
@@ -1619,7 +1608,7 @@ static int wm8990_probe(struct platform_device *pdev)
static int wm8990_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
if (codec->control_data)
wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
new file mode 100644
index 00000000000..3265817c5c2
--- /dev/null
+++ b/sound/soc/codecs/wm9705.c
@@ -0,0 +1,415 @@
+/*
+ * wm9705.c -- ALSA Soc WM9705 codec support
+ *
+ * Copyright 2008 Ian Molton <spyro@f2s.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 only.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "wm9705.h"
+
+/*
+ * WM9705 register cache
+ */
+static const u16 wm9705_reg[] = {
+ 0x6150, 0x8000, 0x8000, 0x8000, /* 0x0 */
+ 0x0000, 0x8000, 0x8008, 0x8008, /* 0x8 */
+ 0x8808, 0x8808, 0x8808, 0x8808, /* 0x10 */
+ 0x8808, 0x0000, 0x8000, 0x0000, /* 0x18 */
+ 0x0000, 0x0000, 0x0000, 0x000f, /* 0x20 */
+ 0x0605, 0x0000, 0xbb80, 0x0000, /* 0x28 */
+ 0x0000, 0xbb80, 0x0000, 0x0000, /* 0x30 */
+ 0x0000, 0x2000, 0x0000, 0x0000, /* 0x38 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 0x40 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 0x48 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 0x50 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 0x58 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 0x60 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 0x68 */
+ 0x0000, 0x0808, 0x0000, 0x0006, /* 0x70 */
+ 0x0000, 0x0000, 0x574d, 0x4c05, /* 0x78 */
+};
+
+static const struct snd_kcontrol_new wm9705_snd_ac97_controls[] = {
+ SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1),
+ SOC_SINGLE("Master Playback Switch", AC97_MASTER, 15, 1, 1),
+ SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1),
+ SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 1, 1),
+ SOC_DOUBLE("PCM Playback Volume", AC97_PCM, 8, 0, 31, 1),
+ SOC_SINGLE("PCM Playback Switch", AC97_PCM, 15, 1, 1),
+ SOC_SINGLE("Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1),
+ SOC_SINGLE("Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1),
+ SOC_SINGLE("PCBeep Playback Volume", AC97_PC_BEEP, 1, 15, 1),
+ SOC_SINGLE("Phone Playback Volume", AC97_PHONE, 0, 31, 1),
+ SOC_DOUBLE("Line Playback Volume", AC97_LINE, 8, 0, 31, 1),
+ SOC_DOUBLE("CD Playback Volume", AC97_CD, 8, 0, 31, 1),
+ SOC_SINGLE("Mic Playback Volume", AC97_MIC, 0, 31, 1),
+ SOC_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 6, 1, 0),
+ SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 15, 0),
+ SOC_SINGLE("Capture Switch", AC97_REC_GAIN, 15, 1, 1),
+};
+
+static const char *wm9705_mic[] = {"Mic 1", "Mic 2"};
+static const char *wm9705_rec_sel[] = {"Mic", "CD", "NC", "NC",
+ "Line", "Stereo Mix", "Mono Mix", "Phone"};
+
+static const struct soc_enum wm9705_enum_mic =
+ SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 8, 2, wm9705_mic);
+static const struct soc_enum wm9705_enum_rec_l =
+ SOC_ENUM_SINGLE(AC97_REC_SEL, 8, 8, wm9705_rec_sel);
+static const struct soc_enum wm9705_enum_rec_r =
+ SOC_ENUM_SINGLE(AC97_REC_SEL, 0, 8, wm9705_rec_sel);
+
+/* Headphone Mixer */
+static const struct snd_kcontrol_new wm9705_hp_mixer_controls[] = {
+ SOC_DAPM_SINGLE("PCBeep Playback Switch", AC97_PC_BEEP, 15, 1, 1),
+ SOC_DAPM_SINGLE("CD Playback Switch", AC97_CD, 15, 1, 1),
+ SOC_DAPM_SINGLE("Mic Playback Switch", AC97_MIC, 15, 1, 1),
+ SOC_DAPM_SINGLE("Phone Playback Switch", AC97_PHONE, 15, 1, 1),
+ SOC_DAPM_SINGLE("Line Playback Switch", AC97_LINE, 15, 1, 1),
+};
+
+/* Mic source */
+static const struct snd_kcontrol_new wm9705_mic_src_controls =
+ SOC_DAPM_ENUM("Route", wm9705_enum_mic);
+
+/* Capture source */
+static const struct snd_kcontrol_new wm9705_capture_selectl_controls =
+ SOC_DAPM_ENUM("Route", wm9705_enum_rec_l);
+static const struct snd_kcontrol_new wm9705_capture_selectr_controls =
+ SOC_DAPM_ENUM("Route", wm9705_enum_rec_r);
+
+/* DAPM widgets */
+static const struct snd_soc_dapm_widget wm9705_dapm_widgets[] = {
+ SND_SOC_DAPM_MUX("Mic Source", SND_SOC_NOPM, 0, 0,
+ &wm9705_mic_src_controls),
+ SND_SOC_DAPM_MUX("Left Capture Source", SND_SOC_NOPM, 0, 0,
+ &wm9705_capture_selectl_controls),
+ SND_SOC_DAPM_MUX("Right Capture Source", SND_SOC_NOPM, 0, 0,
+ &wm9705_capture_selectr_controls),
+ SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback",
+ SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback",
+ SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_MIXER_NAMED_CTL("HP Mixer", SND_SOC_NOPM, 0, 0,
+ &wm9705_hp_mixer_controls[0],
+ ARRAY_SIZE(wm9705_hp_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_PGA("Headphone PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Speaker PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Line PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Line out PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Mono PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Phone PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Mic PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("PCBEEP PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("CD PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ADC PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("HPOUTL"),
+ SND_SOC_DAPM_OUTPUT("HPOUTR"),
+ SND_SOC_DAPM_OUTPUT("LOUT"),
+ SND_SOC_DAPM_OUTPUT("ROUT"),
+ SND_SOC_DAPM_OUTPUT("MONOOUT"),
+ SND_SOC_DAPM_INPUT("PHONE"),
+ SND_SOC_DAPM_INPUT("LINEINL"),
+ SND_SOC_DAPM_INPUT("LINEINR"),
+ SND_SOC_DAPM_INPUT("CDINL"),
+ SND_SOC_DAPM_INPUT("CDINR"),
+ SND_SOC_DAPM_INPUT("PCBEEP"),
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+};
+
+/* Audio map
+ * WM9705 has no switches to disable the route from the inputs to the HP mixer
+ * so in order to prevent active inputs from forcing the audio outputs to be
+ * constantly enabled, we use the mutes on those inputs to simulate such
+ * controls.
+ */
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* HP mixer */
+ {"HP Mixer", "PCBeep Playback Switch", "PCBEEP PGA"},
+ {"HP Mixer", "CD Playback Switch", "CD PGA"},
+ {"HP Mixer", "Mic Playback Switch", "Mic PGA"},
+ {"HP Mixer", "Phone Playback Switch", "Phone PGA"},
+ {"HP Mixer", "Line Playback Switch", "Line PGA"},
+ {"HP Mixer", NULL, "Left DAC"},
+ {"HP Mixer", NULL, "Right DAC"},
+
+ /* mono mixer */
+ {"Mono Mixer", NULL, "HP Mixer"},
+
+ /* outputs */
+ {"Headphone PGA", NULL, "HP Mixer"},
+ {"HPOUTL", NULL, "Headphone PGA"},
+ {"HPOUTR", NULL, "Headphone PGA"},
+ {"Line out PGA", NULL, "HP Mixer"},
+ {"LOUT", NULL, "Line out PGA"},
+ {"ROUT", NULL, "Line out PGA"},
+ {"Mono PGA", NULL, "Mono Mixer"},
+ {"MONOOUT", NULL, "Mono PGA"},
+
+ /* inputs */
+ {"CD PGA", NULL, "CDINL"},
+ {"CD PGA", NULL, "CDINR"},
+ {"Line PGA", NULL, "LINEINL"},
+ {"Line PGA", NULL, "LINEINR"},
+ {"Phone PGA", NULL, "PHONE"},
+ {"Mic Source", "Mic 1", "MIC1"},
+ {"Mic Source", "Mic 2", "MIC2"},
+ {"Mic PGA", NULL, "Mic Source"},
+ {"PCBEEP PGA", NULL, "PCBEEP"},
+
+ /* Left capture selector */
+ {"Left Capture Source", "Mic", "Mic Source"},
+ {"Left Capture Source", "CD", "CDINL"},
+ {"Left Capture Source", "Line", "LINEINL"},
+ {"Left Capture Source", "Stereo Mix", "HP Mixer"},
+ {"Left Capture Source", "Mono Mix", "HP Mixer"},
+ {"Left Capture Source", "Phone", "PHONE"},
+
+ /* Right capture source */
+ {"Right Capture Source", "Mic", "Mic Source"},
+ {"Right Capture Source", "CD", "CDINR"},
+ {"Right Capture Source", "Line", "LINEINR"},
+ {"Right Capture Source", "Stereo Mix", "HP Mixer"},
+ {"Right Capture Source", "Mono Mix", "HP Mixer"},
+ {"Right Capture Source", "Phone", "PHONE"},
+
+ {"ADC PGA", NULL, "Left Capture Source"},
+ {"ADC PGA", NULL, "Right Capture Source"},
+
+ /* ADC's */
+ {"Left ADC", NULL, "ADC PGA"},
+ {"Right ADC", NULL, "ADC PGA"},
+};
+
+static int wm9705_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, wm9705_dapm_widgets,
+ ARRAY_SIZE(wm9705_dapm_widgets));
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+ snd_soc_dapm_new_widgets(codec);
+
+ return 0;
+}
+
+/* We use a register cache to enhance read performance. */
+static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+ u16 *cache = codec->reg_cache;
+
+ switch (reg) {
+ case AC97_RESET:
+ case AC97_VENDOR_ID1:
+ case AC97_VENDOR_ID2:
+ return soc_ac97_ops.read(codec->ac97, reg);
+ default:
+ reg = reg >> 1;
+
+ if (reg >= (ARRAY_SIZE(wm9705_reg)))
+ return -EIO;
+
+ return cache[reg];
+ }
+}
+
+static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int val)
+{
+ u16 *cache = codec->reg_cache;
+
+ soc_ac97_ops.write(codec->ac97, reg, val);
+ reg = reg >> 1;
+ if (reg < (ARRAY_SIZE(wm9705_reg)))
+ cache[reg] = val;
+
+ return 0;
+}
+
+static int ac97_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+ int reg;
+ u16 vra;
+
+ vra = ac97_read(codec, AC97_EXTENDED_STATUS);
+ ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ reg = AC97_PCM_FRONT_DAC_RATE;
+ else
+ reg = AC97_PCM_LR_ADC_RATE;
+
+ return ac97_write(codec, reg, runtime->rate);
+}
+
+#define WM9705_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000)
+
+static struct snd_soc_dai_ops wm9705_dai_ops = {
+ .prepare = ac97_prepare,
+};
+
+struct snd_soc_dai wm9705_dai[] = {
+ {
+ .name = "AC97 HiFi",
+ .ac97_control = 1,
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM9705_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "HiFi Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WM9705_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &wm9705_dai_ops,
+ },
+ {
+ .name = "AC97 Aux",
+ .playback = {
+ .stream_name = "Aux Playback",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = WM9705_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ }
+};
+EXPORT_SYMBOL_GPL(wm9705_dai);
+
+static int wm9705_reset(struct snd_soc_codec *codec)
+{
+ if (soc_ac97_ops.reset) {
+ soc_ac97_ops.reset(codec->ac97);
+ if (ac97_read(codec, 0) == wm9705_reg[0])
+ return 0; /* Success */
+ }
+
+ return -EIO;
+}
+
+static int wm9705_soc_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret = 0;
+
+ printk(KERN_INFO "WM9705 SoC Audio Codec\n");
+
+ socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec),
+ GFP_KERNEL);
+ if (socdev->card->codec == NULL)
+ return -ENOMEM;
+ codec = socdev->card->codec;
+ mutex_init(&codec->mutex);
+
+ codec->reg_cache = kmemdup(wm9705_reg, sizeof(wm9705_reg), GFP_KERNEL);
+ if (codec->reg_cache == NULL) {
+ ret = -ENOMEM;
+ goto cache_err;
+ }
+ codec->reg_cache_size = sizeof(wm9705_reg);
+ codec->reg_cache_step = 2;
+
+ codec->name = "WM9705";
+ codec->owner = THIS_MODULE;
+ codec->dai = wm9705_dai;
+ codec->num_dai = ARRAY_SIZE(wm9705_dai);
+ codec->write = ac97_write;
+ codec->read = ac97_read;
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
+ if (ret < 0) {
+ printk(KERN_ERR "wm9705: failed to register AC97 codec\n");
+ goto codec_err;
+ }
+
+ /* register pcms */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0)
+ goto pcm_err;
+
+ ret = wm9705_reset(codec);
+ if (ret)
+ goto reset_err;
+
+ snd_soc_add_controls(codec, wm9705_snd_ac97_controls,
+ ARRAY_SIZE(wm9705_snd_ac97_controls));
+ wm9705_add_widgets(codec);
+
+ ret = snd_soc_init_card(socdev);
+ if (ret < 0) {
+ printk(KERN_ERR "wm9705: failed to register card\n");
+ goto pcm_err;
+ }
+
+ return 0;
+
+reset_err:
+ snd_soc_free_pcms(socdev);
+pcm_err:
+ snd_soc_free_ac97_codec(codec);
+codec_err:
+ kfree(codec->reg_cache);
+cache_err:
+ kfree(socdev->card->codec);
+ socdev->card->codec = NULL;
+ return ret;
+}
+
+static int wm9705_soc_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec = socdev->card->codec;
+
+ if (codec == NULL)
+ return 0;
+
+ snd_soc_dapm_free(socdev);
+ snd_soc_free_pcms(socdev);
+ snd_soc_free_ac97_codec(codec);
+ kfree(codec->reg_cache);
+ kfree(codec);
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_wm9705 = {
+ .probe = wm9705_soc_probe,
+ .remove = wm9705_soc_remove,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_wm9705);
+
+MODULE_DESCRIPTION("ASoC WM9705 driver");
+MODULE_AUTHOR("Ian Molton");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wm9705.h b/sound/soc/codecs/wm9705.h
new file mode 100644
index 00000000000..d380f110f9e
--- /dev/null
+++ b/sound/soc/codecs/wm9705.h
@@ -0,0 +1,14 @@
+/*
+ * wm9705.h -- WM9705 Soc Audio driver
+ */
+
+#ifndef _WM9705_H
+#define _WM9705_H
+
+#define WM9705_DAI_AC97_HIFI 0
+#define WM9705_DAI_AC97_AUX 1
+
+extern struct snd_soc_dai wm9705_dai[2];
+extern struct snd_soc_codec_device soc_codec_dev_wm9705;
+
+#endif
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index af83d629078..765cf1e7369 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -154,21 +154,6 @@ SOC_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1),
SOC_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0),
};
-/* add non dapm controls */
-static int wm9712_add_controls(struct snd_soc_codec *codec)
-{
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(wm9712_snd_ac97_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm9712_snd_ac97_controls[i],
- codec, NULL));
- if (err < 0)
- return err;
- }
- return 0;
-}
-
/* We have to create a fake left and right HP mixers because
* the codec only has a single control that is shared by both channels.
* This makes it impossible to determine the audio path.
@@ -467,7 +452,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec,
else {
reg = reg >> 1;
- if (reg > (ARRAY_SIZE(wm9712_reg)))
+ if (reg >= (ARRAY_SIZE(wm9712_reg)))
return -EIO;
return cache[reg];
@@ -481,7 +466,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
soc_ac97_ops.write(codec->ac97, reg, val);
reg = reg >> 1;
- if (reg <= (ARRAY_SIZE(wm9712_reg)))
+ if (reg < (ARRAY_SIZE(wm9712_reg)))
cache[reg] = val;
return 0;
@@ -493,7 +478,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int reg;
u16 vra;
@@ -514,7 +499,7 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
u16 vra, xsle;
vra = ac97_read(codec, AC97_EXTENDED_STATUS);
@@ -532,6 +517,14 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream,
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
SNDRV_PCM_RATE_48000)
+static struct snd_soc_dai_ops wm9712_dai_ops_hifi = {
+ .prepare = ac97_prepare,
+};
+
+static struct snd_soc_dai_ops wm9712_dai_ops_aux = {
+ .prepare = ac97_aux_prepare,
+};
+
struct snd_soc_dai wm9712_dai[] = {
{
.name = "AC97 HiFi",
@@ -548,8 +541,7 @@ struct snd_soc_dai wm9712_dai[] = {
.channels_max = 2,
.rates = WM9712_AC97_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = {
- .prepare = ac97_prepare,},
+ .ops = &wm9712_dai_ops_hifi,
},
{
.name = "AC97 Aux",
@@ -559,8 +551,7 @@ struct snd_soc_dai wm9712_dai[] = {
.channels_max = 1,
.rates = WM9712_AC97_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = {
- .prepare = ac97_aux_prepare,},
+ .ops = &wm9712_dai_ops_aux,
}
};
EXPORT_SYMBOL_GPL(wm9712_dai);
@@ -607,7 +598,7 @@ static int wm9712_soc_suspend(struct platform_device *pdev,
pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
wm9712_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
@@ -616,7 +607,7 @@ static int wm9712_soc_suspend(struct platform_device *pdev,
static int wm9712_soc_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
int i, ret;
u16 *cache = codec->reg_cache;
@@ -652,10 +643,11 @@ static int wm9712_soc_probe(struct platform_device *pdev)
printk(KERN_INFO "WM9711/WM9712 SoC Audio Codec %s\n", WM9712_VERSION);
- socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (socdev->codec == NULL)
+ socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec),
+ GFP_KERNEL);
+ if (socdev->card->codec == NULL)
return -ENOMEM;
- codec = socdev->codec;
+ codec = socdev->card->codec;
mutex_init(&codec->mutex);
codec->reg_cache = kmemdup(wm9712_reg, sizeof(wm9712_reg), GFP_KERNEL);
@@ -698,7 +690,8 @@ static int wm9712_soc_probe(struct platform_device *pdev)
ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000);
wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- wm9712_add_controls(codec);
+ snd_soc_add_controls(codec, wm9712_snd_ac97_controls,
+ ARRAY_SIZE(wm9712_snd_ac97_controls));
wm9712_add_widgets(codec);
ret = snd_soc_init_card(socdev);
if (ret < 0) {
@@ -718,15 +711,15 @@ codec_err:
kfree(codec->reg_cache);
cache_err:
- kfree(socdev->codec);
- socdev->codec = NULL;
+ kfree(socdev->card->codec);
+ socdev->card->codec = NULL;
return ret;
}
static int wm9712_soc_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
if (codec == NULL)
return 0;
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index f3ca8aaf013..523bad077fa 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -32,7 +32,6 @@
struct wm9713_priv {
u32 pll_in; /* PLL input frequency */
- u32 pll_out; /* PLL output frequency */
};
static unsigned int ac97_read(struct snd_soc_codec *codec,
@@ -190,21 +189,6 @@ SOC_SINGLE("3D Lower Cut-off Switch", AC97_REC_GAIN_MIC, 4, 1, 0),
SOC_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1),
};
-/* add non dapm controls */
-static int wm9713_add_controls(struct snd_soc_codec *codec)
-{
- int err, i;
-
- for (i = 0; i < ARRAY_SIZE(wm9713_snd_ac97_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm9713_snd_ac97_controls[i],
- codec, NULL));
- if (err < 0)
- return err;
- }
- return 0;
-}
-
/* We have to create a fake left and right HP mixers because
* the codec only has a single control that is shared by both channels.
* This makes it impossible to determine the audio path using the current
@@ -636,7 +620,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec,
else {
reg = reg >> 1;
- if (reg > (ARRAY_SIZE(wm9713_reg)))
+ if (reg >= (ARRAY_SIZE(wm9713_reg)))
return -EIO;
return cache[reg];
@@ -650,7 +634,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
if (reg < 0x7c)
soc_ac97_ops.write(codec->ac97, reg, val);
reg = reg >> 1;
- if (reg <= (ARRAY_SIZE(wm9713_reg)))
+ if (reg < (ARRAY_SIZE(wm9713_reg)))
cache[reg] = val;
return 0;
@@ -738,13 +722,13 @@ static int wm9713_set_pll(struct snd_soc_codec *codec,
struct _pll_div pll_div;
/* turn PLL off ? */
- if (freq_in == 0 || freq_out == 0) {
+ if (freq_in == 0) {
/* disable PLL power and select ext source */
reg = ac97_read(codec, AC97_HANDSET_RATE);
ac97_write(codec, AC97_HANDSET_RATE, reg | 0x0080);
reg = ac97_read(codec, AC97_EXTENDED_MID);
ac97_write(codec, AC97_EXTENDED_MID, reg | 0x0200);
- wm9713->pll_out = 0;
+ wm9713->pll_in = 0;
return 0;
}
@@ -788,7 +772,6 @@ static int wm9713_set_pll(struct snd_soc_codec *codec,
ac97_write(codec, AC97_EXTENDED_MID, reg & 0xfdff);
reg = ac97_read(codec, AC97_HANDSET_RATE);
ac97_write(codec, AC97_HANDSET_RATE, reg & 0xff7f);
- wm9713->pll_out = freq_out;
wm9713->pll_in = freq_in;
/* wait 10ms AC97 link frames for the link to stabilise */
@@ -957,13 +940,14 @@ static void wm9713_voiceshutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
- u16 status;
+ u16 status, rate;
/* Gracefully shut down the voice interface. */
status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000;
- ac97_write(codec, AC97_HANDSET_RATE, 0x0280);
+ rate = ac97_read(codec, AC97_HANDSET_RATE) & 0xF0FF;
+ ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0200);
schedule_timeout_interruptible(msecs_to_jiffies(1));
- ac97_write(codec, AC97_HANDSET_RATE, 0x0F80);
+ ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0F00);
ac97_write(codec, AC97_EXTENDED_MID, status);
}
@@ -1021,6 +1005,27 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream,
(SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \
SNDRV_PCM_FORMAT_S24_LE)
+static struct snd_soc_dai_ops wm9713_dai_ops_hifi = {
+ .prepare = ac97_hifi_prepare,
+ .set_clkdiv = wm9713_set_dai_clkdiv,
+ .set_pll = wm9713_set_dai_pll,
+};
+
+static struct snd_soc_dai_ops wm9713_dai_ops_aux = {
+ .prepare = ac97_aux_prepare,
+ .set_clkdiv = wm9713_set_dai_clkdiv,
+ .set_pll = wm9713_set_dai_pll,
+};
+
+static struct snd_soc_dai_ops wm9713_dai_ops_voice = {
+ .hw_params = wm9713_pcm_hw_params,
+ .shutdown = wm9713_voiceshutdown,
+ .set_clkdiv = wm9713_set_dai_clkdiv,
+ .set_pll = wm9713_set_dai_pll,
+ .set_fmt = wm9713_set_dai_fmt,
+ .set_tristate = wm9713_set_dai_tristate,
+};
+
struct snd_soc_dai wm9713_dai[] = {
{
.name = "AC97 HiFi",
@@ -1037,10 +1042,7 @@ struct snd_soc_dai wm9713_dai[] = {
.channels_max = 2,
.rates = WM9713_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = {
- .prepare = ac97_hifi_prepare,
- .set_clkdiv = wm9713_set_dai_clkdiv,
- .set_pll = wm9713_set_dai_pll,},
+ .ops = &wm9713_dai_ops_hifi,
},
{
.name = "AC97 Aux",
@@ -1050,10 +1052,7 @@ struct snd_soc_dai wm9713_dai[] = {
.channels_max = 1,
.rates = WM9713_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = {
- .prepare = ac97_aux_prepare,
- .set_clkdiv = wm9713_set_dai_clkdiv,
- .set_pll = wm9713_set_dai_pll,},
+ .ops = &wm9713_dai_ops_aux,
},
{
.name = "WM9713 Voice",
@@ -1069,14 +1068,7 @@ struct snd_soc_dai wm9713_dai[] = {
.channels_max = 2,
.rates = WM9713_PCM_RATES,
.formats = WM9713_PCM_FORMATS,},
- .ops = {
- .hw_params = wm9713_pcm_hw_params,
- .shutdown = wm9713_voiceshutdown,
- .set_clkdiv = wm9713_set_dai_clkdiv,
- .set_pll = wm9713_set_dai_pll,
- .set_fmt = wm9713_set_dai_fmt,
- .set_tristate = wm9713_set_dai_tristate,
- },
+ .ops = &wm9713_dai_ops_voice,
},
};
EXPORT_SYMBOL_GPL(wm9713_dai);
@@ -1132,7 +1124,7 @@ static int wm9713_soc_suspend(struct platform_device *pdev,
pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
u16 reg;
/* Disable everything except touchpanel - that will be handled
@@ -1150,7 +1142,7 @@ static int wm9713_soc_suspend(struct platform_device *pdev,
static int wm9713_soc_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct wm9713_priv *wm9713 = codec->private_data;
int i, ret;
u16 *cache = codec->reg_cache;
@@ -1164,8 +1156,8 @@ static int wm9713_soc_resume(struct platform_device *pdev)
wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* do we need to re-start the PLL ? */
- if (wm9713->pll_out)
- wm9713_set_pll(codec, 0, wm9713->pll_in, wm9713->pll_out);
+ if (wm9713->pll_in)
+ wm9713_set_pll(codec, 0, wm9713->pll_in, 0);
/* only synchronise the codec if warm reset failed */
if (ret == 0) {
@@ -1191,10 +1183,11 @@ static int wm9713_soc_probe(struct platform_device *pdev)
printk(KERN_INFO "WM9713/WM9714 SoC Audio Codec %s\n", WM9713_VERSION);
- socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (socdev->codec == NULL)
+ socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec),
+ GFP_KERNEL);
+ if (socdev->card->codec == NULL)
return -ENOMEM;
- codec = socdev->codec;
+ codec = socdev->card->codec;
mutex_init(&codec->mutex);
codec->reg_cache = kmemdup(wm9713_reg, sizeof(wm9713_reg), GFP_KERNEL);
@@ -1245,7 +1238,8 @@ static int wm9713_soc_probe(struct platform_device *pdev)
reg = ac97_read(codec, AC97_CD) & 0x7fff;
ac97_write(codec, AC97_CD, reg);
- wm9713_add_controls(codec);
+ snd_soc_add_controls(codec, wm9713_snd_ac97_controls,
+ ARRAY_SIZE(wm9713_snd_ac97_controls));
wm9713_add_widgets(codec);
ret = snd_soc_init_card(socdev);
if (ret < 0)
@@ -1265,15 +1259,15 @@ priv_err:
kfree(codec->reg_cache);
cache_err:
- kfree(socdev->codec);
- socdev->codec = NULL;
+ kfree(socdev->card->codec);
+ socdev->card->codec = NULL;
return ret;
}
static int wm9713_soc_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
if (codec == NULL)
return 0;
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
index b502741692d..bd7392c9657 100644
--- a/sound/soc/davinci/Kconfig
+++ b/sound/soc/davinci/Kconfig
@@ -20,7 +20,7 @@ config SND_DAVINCI_SOC_EVM
config SND_DAVINCI_SOC_SFFSDR
tristate "SoC Audio support for SFFSDR"
- depends on SND_DAVINCI_SOC && MACH_DAVINCI_SFFSDR
+ depends on SND_DAVINCI_SOC && MACH_SFFSDR
select SND_DAVINCI_SOC_I2S
select SND_SOC_PCM3008
select SFFSDR_FPGA
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 54851f31856..9b90b347007 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -186,7 +186,8 @@ static int __init evm_init(void)
platform_set_drvdata(evm_snd_device, &evm_snd_devdata);
evm_snd_devdata.dev = &evm_snd_device->dev;
- evm_snd_device->dev.platform_data = &evm_snd_data;
+ platform_device_add_data(evm_snd_device, &evm_snd_data,
+ sizeof(evm_snd_data));
ret = platform_device_add_resources(evm_snd_device, evm_snd_resources,
ARRAY_SIZE(evm_snd_resources));
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index 0fee779e3c7..ffdb9439d3d 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -499,6 +499,13 @@ static void davinci_i2s_remove(struct platform_device *pdev,
#define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000
+static struct snd_soc_dai_ops davinci_i2s_dai_ops = {
+ .startup = davinci_i2s_startup,
+ .trigger = davinci_i2s_trigger,
+ .hw_params = davinci_i2s_hw_params,
+ .set_fmt = davinci_i2s_set_dai_fmt,
+};
+
struct snd_soc_dai davinci_i2s_dai = {
.name = "davinci-i2s",
.id = 0,
@@ -514,12 +521,7 @@ struct snd_soc_dai davinci_i2s_dai = {
.channels_max = 2,
.rates = DAVINCI_I2S_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = {
- .startup = davinci_i2s_startup,
- .trigger = davinci_i2s_trigger,
- .hw_params = davinci_i2s_hw_params,
- .set_fmt = davinci_i2s_set_dai_fmt,
- },
+ .ops = &davinci_i2s_dai_ops,
};
EXPORT_SYMBOL_GPL(davinci_i2s_dai);
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index 366049d8578..7af3b5b3a53 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -286,7 +286,7 @@ static int davinci_pcm_mmap(struct snd_pcm_substream *substream,
runtime->dma_bytes);
}
-struct snd_pcm_ops davinci_pcm_ops = {
+static struct snd_pcm_ops davinci_pcm_ops = {
.open = davinci_pcm_open,
.close = davinci_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c
index 4935d1bcbd8..40eccfe9e35 100644
--- a/sound/soc/davinci/davinci-sffsdr.c
+++ b/sound/soc/davinci/davinci-sffsdr.c
@@ -25,7 +25,9 @@
#include <asm/dma.h>
#include <asm/mach-types.h>
+#ifdef CONFIG_SFFSDR_FPGA
#include <asm/plat-sffsdr/sffsdr-fpga.h>
+#endif
#include <mach/mcbsp.h>
#include <mach/edma.h>
@@ -34,31 +36,45 @@
#include "davinci-pcm.h"
#include "davinci-i2s.h"
+/*
+ * CLKX and CLKR are the inputs for the Sample Rate Generator.
+ * FSX and FSR are outputs, driven by the sample Rate Generator.
+ */
+#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \
+ SND_SOC_DAIFMT_CBM_CFS | \
+ SND_SOC_DAIFMT_IB_NF)
+
static int sffsdr_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+ struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
int fs;
int ret = 0;
- /* Set cpu DAI configuration:
- * CLKX and CLKR are the inputs for the Sample Rate Generator.
- * FSX and FSR are outputs, driven by the sample Rate Generator. */
- ret = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_RIGHT_J |
- SND_SOC_DAIFMT_CBM_CFS |
- SND_SOC_DAIFMT_IB_NF);
- if (ret < 0)
- return ret;
-
/* Fsref can be 32000, 44100 or 48000. */
fs = params_rate(params);
+#ifndef CONFIG_SFFSDR_FPGA
+ /* Without the FPGA module, the Fs is fixed at 44100 Hz */
+ if (fs != 44100) {
+ pr_debug("warning: only 44.1 kHz is supported without SFFSDR FPGA module\n");
+ return -EINVAL;
+ }
+#endif
+
+ /* set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT);
+ if (ret < 0)
+ return ret;
+
pr_debug("sffsdr_hw_params: rate = %d Hz\n", fs);
+#ifndef CONFIG_SFFSDR_FPGA
+ return 0;
+#else
return sffsdr_fpga_set_codec_fs(fs);
+#endif
}
static struct snd_soc_ops sffsdr_ops = {
@@ -127,7 +143,8 @@ static int __init sffsdr_init(void)
platform_set_drvdata(sffsdr_snd_device, &sffsdr_snd_devdata);
sffsdr_snd_devdata.dev = &sffsdr_snd_device->dev;
- sffsdr_snd_device->dev.platform_data = &sffsdr_snd_data;
+ platform_device_add_data(sffsdr_snd_device, &sffsdr_snd_data,
+ sizeof(sffsdr_snd_data));
ret = platform_device_add_resources(sffsdr_snd_device,
sffsdr_snd_resources,
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 95c12b26fe3..9fc90828337 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -1,17 +1,18 @@
config SND_SOC_OF_SIMPLE
tristate
+# ASoC platform support for the Freescale MPC8610 SOC. This compiles drivers
+# for the SSI and the Elo DMA controller. You will still need to select
+# a platform driver and a codec driver.
config SND_SOC_MPC8610
- bool "ALSA SoC support for the MPC8610 SOC"
- depends on MPC8610_HPCD
- default y if MPC8610
- help
- Say Y if you want to add support for codecs attached to the SSI
- device on an MPC8610.
+ tristate
+ depends on MPC8610
config SND_SOC_MPC8610_HPCD
- bool "ALSA SoC support for the Freescale MPC8610 HPCD board"
- depends on SND_SOC_MPC8610
+ tristate "ALSA SoC support for the Freescale MPC8610 HPCD board"
+ # I2C is necessary for the CS4270 driver
+ depends on MPC8610_HPCD && I2C
+ select SND_SOC_MPC8610
select SND_SOC_CS4270
select SND_SOC_CS4270_VD33_ERRATA
default y if MPC8610_HPCD
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 035da4afec3..f85134c8638 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -2,10 +2,13 @@
obj-$(CONFIG_SND_SOC_OF_SIMPLE) += soc-of-simple.o
# MPC8610 HPCD Machine Support
-obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += mpc8610_hpcd.o
+snd-soc-mpc8610-hpcd-objs := mpc8610_hpcd.o
+obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += snd-soc-mpc8610-hpcd.o
# MPC8610 Platform Support
-obj-$(CONFIG_SND_SOC_MPC8610) += fsl_ssi.o fsl_dma.o
+snd-soc-fsl-ssi-objs := fsl_ssi.o
+snd-soc-fsl-dma-objs := fsl_dma.o
+obj-$(CONFIG_SND_SOC_MPC8610) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index 64993eda567..b3eb8570cd7 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -142,7 +142,8 @@ static const struct snd_pcm_hardware fsl_dma_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_JOINT_DUPLEX,
+ SNDRV_PCM_INFO_JOINT_DUPLEX |
+ SNDRV_PCM_INFO_PAUSE,
.formats = FSLDMA_PCM_FORMATS,
.rates = FSLDMA_PCM_RATES,
.rate_min = 5512,
@@ -464,11 +465,7 @@ static int fsl_dma_open(struct snd_pcm_substream *substream)
sizeof(struct fsl_dma_link_descriptor);
for (i = 0; i < NUM_DMA_LINKS; i++) {
- struct fsl_dma_link_descriptor *link = &dma_private->link[i];
-
- link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
- link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
- link->next = cpu_to_be64(temp_link);
+ dma_private->link[i].next = cpu_to_be64(temp_link);
temp_link += sizeof(struct fsl_dma_link_descriptor);
}
@@ -525,79 +522,9 @@ static int fsl_dma_open(struct snd_pcm_substream *substream)
* This function obtains hardware parameters about the opened stream and
* programs the DMA controller accordingly.
*
- * Note that due to a quirk of the SSI's STX register, the target address
- * for the DMA operations depends on the sample size. So we don't program
- * the dest_addr (for playback -- source_addr for capture) fields in the
- * link descriptors here. We do that in fsl_dma_prepare()
- */
-static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct fsl_dma_private *dma_private = runtime->private_data;
-
- dma_addr_t temp_addr; /* Pointer to next period */
-
- unsigned int i;
-
- /* Get all the parameters we need */
- size_t buffer_size = params_buffer_bytes(hw_params);
- size_t period_size = params_period_bytes(hw_params);
-
- /* Initialize our DMA tracking variables */
- dma_private->period_size = period_size;
- dma_private->num_periods = params_periods(hw_params);
- dma_private->dma_buf_end = dma_private->dma_buf_phys + buffer_size;
- dma_private->dma_buf_next = dma_private->dma_buf_phys +
- (NUM_DMA_LINKS * period_size);
- if (dma_private->dma_buf_next >= dma_private->dma_buf_end)
- dma_private->dma_buf_next = dma_private->dma_buf_phys;
-
- /*
- * The actual address in STX0 (destination for playback, source for
- * capture) is based on the sample size, but we don't know the sample
- * size in this function, so we'll have to adjust that later. See
- * comments in fsl_dma_prepare().
- *
- * The DMA controller does not have a cache, so the CPU does not
- * need to tell it to flush its cache. However, the DMA
- * controller does need to tell the CPU to flush its cache.
- * That's what the SNOOP bit does.
- *
- * Also, even though the DMA controller supports 36-bit addressing, for
- * simplicity we currently support only 32-bit addresses for the audio
- * buffer itself.
- */
- temp_addr = substream->dma_buffer.addr;
-
- for (i = 0; i < NUM_DMA_LINKS; i++) {
- struct fsl_dma_link_descriptor *link = &dma_private->link[i];
-
- link->count = cpu_to_be32(period_size);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- link->source_addr = cpu_to_be32(temp_addr);
- else
- link->dest_addr = cpu_to_be32(temp_addr);
-
- temp_addr += period_size;
- }
-
- return 0;
-}
-
-/**
- * fsl_dma_prepare - prepare the DMA registers for playback.
- *
- * This function is called after the specifics of the audio data are known,
- * i.e. snd_pcm_runtime is initialized.
- *
- * In this function, we finish programming the registers of the DMA
- * controller that are dependent on the sample size.
- *
- * One of the drawbacks with big-endian is that when copying integers of
- * different sizes to a fixed-sized register, the address to which the
- * integer must be copied is dependent on the size of the integer.
+ * One drawback of big-endian is that when copying integers of different
+ * sizes to a fixed-sized register, the address to which the integer must be
+ * copied is dependent on the size of the integer.
*
* For example, if P is the address of a 32-bit register, and X is a 32-bit
* integer, then X should be copied to address P. However, if X is a 16-bit
@@ -613,22 +540,58 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
* and 8 bytes at a time). So we do not support packed 24-bit samples.
* 24-bit data must be padded to 32 bits.
*/
-static int fsl_dma_prepare(struct snd_pcm_substream *substream)
+static int fsl_dma_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct fsl_dma_private *dma_private = runtime->private_data;
+
+ /* Number of bits per sample */
+ unsigned int sample_size =
+ snd_pcm_format_physical_width(params_format(hw_params));
+
+ /* Number of bytes per frame */
+ unsigned int frame_size = 2 * (sample_size / 8);
+
+ /* Bus address of SSI STX register */
+ dma_addr_t ssi_sxx_phys = dma_private->ssi_sxx_phys;
+
+ /* Size of the DMA buffer, in bytes */
+ size_t buffer_size = params_buffer_bytes(hw_params);
+
+ /* Number of bytes per period */
+ size_t period_size = params_period_bytes(hw_params);
+
+ /* Pointer to next period */
+ dma_addr_t temp_addr = substream->dma_buffer.addr;
+
+ /* Pointer to DMA controller */
struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel;
- u32 mr;
+
+ u32 mr; /* DMA Mode Register */
+
unsigned int i;
- dma_addr_t ssi_sxx_phys; /* Bus address of SSI STX register */
- unsigned int frame_size; /* Number of bytes per frame */
- ssi_sxx_phys = dma_private->ssi_sxx_phys;
+ /* Initialize our DMA tracking variables */
+ dma_private->period_size = period_size;
+ dma_private->num_periods = params_periods(hw_params);
+ dma_private->dma_buf_end = dma_private->dma_buf_phys + buffer_size;
+ dma_private->dma_buf_next = dma_private->dma_buf_phys +
+ (NUM_DMA_LINKS * period_size);
+
+ if (dma_private->dma_buf_next >= dma_private->dma_buf_end)
+ /* This happens if the number of periods == NUM_DMA_LINKS */
+ dma_private->dma_buf_next = dma_private->dma_buf_phys;
mr = in_be32(&dma_channel->mr) & ~(CCSR_DMA_MR_BWC_MASK |
CCSR_DMA_MR_SAHTS_MASK | CCSR_DMA_MR_DAHTS_MASK);
- switch (runtime->sample_bits) {
+ /* Due to a quirk of the SSI's STX register, the target address
+ * for the DMA operations depends on the sample size. So we calculate
+ * that offset here. While we're at it, also tell the DMA controller
+ * how much data to transfer per sample.
+ */
+ switch (sample_size) {
case 8:
mr |= CCSR_DMA_MR_DAHTS_1 | CCSR_DMA_MR_SAHTS_1;
ssi_sxx_phys += 3;
@@ -641,12 +604,12 @@ static int fsl_dma_prepare(struct snd_pcm_substream *substream)
mr |= CCSR_DMA_MR_DAHTS_4 | CCSR_DMA_MR_SAHTS_4;
break;
default:
+ /* We should never get here */
dev_err(substream->pcm->card->dev,
- "unsupported sample size %u\n", runtime->sample_bits);
+ "unsupported sample size %u\n", sample_size);
return -EINVAL;
}
- frame_size = runtime->frame_bits / 8;
/*
* BWC should always be a multiple of the frame size. BWC determines
* how many bytes are sent/received before the DMA controller checks the
@@ -655,7 +618,6 @@ static int fsl_dma_prepare(struct snd_pcm_substream *substream)
* capture, the receive FIFO is triggered when it contains one frame, so
* we want to receive one frame at a time.
*/
-
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
mr |= CCSR_DMA_MR_BWC(2 * frame_size);
else
@@ -663,16 +625,48 @@ static int fsl_dma_prepare(struct snd_pcm_substream *substream)
out_be32(&dma_channel->mr, mr);
- /*
- * Program the address of the DMA transfer to/from the SSI.
- */
for (i = 0; i < NUM_DMA_LINKS; i++) {
struct fsl_dma_link_descriptor *link = &dma_private->link[i];
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ link->count = cpu_to_be32(period_size);
+
+ /* Even though the DMA controller supports 36-bit addressing,
+ * for simplicity we allow only 32-bit addresses for the audio
+ * buffer itself. This was enforced in fsl_dma_new() with the
+ * DMA mask.
+ *
+ * The snoop bit tells the DMA controller whether it should tell
+ * the ECM to snoop during a read or write to an address. For
+ * audio, we use DMA to transfer data between memory and an I/O
+ * device (the SSI's STX0 or SRX0 register). Snooping is only
+ * needed if there is a cache, so we need to snoop memory
+ * addresses only. For playback, that means we snoop the source
+ * but not the destination. For capture, we snoop the
+ * destination but not the source.
+ *
+ * Note that failing to snoop properly is unlikely to cause
+ * cache incoherency if the period size is larger than the
+ * size of L1 cache. This is because filling in one period will
+ * flush out the data for the previous period. So if you
+ * increased period_bytes_min to a large enough size, you might
+ * get more performance by not snooping, and you'll still be
+ * okay.
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ link->source_addr = cpu_to_be32(temp_addr);
+ link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
+
link->dest_addr = cpu_to_be32(ssi_sxx_phys);
- else
+ link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP);
+ } else {
link->source_addr = cpu_to_be32(ssi_sxx_phys);
+ link->source_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP);
+
+ link->dest_addr = cpu_to_be32(temp_addr);
+ link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP);
+ }
+
+ temp_addr += period_size;
}
return 0;
@@ -808,7 +802,6 @@ static struct snd_pcm_ops fsl_dma_ops = {
.ioctl = snd_pcm_lib_ioctl,
.hw_params = fsl_dma_hw_params,
.hw_free = fsl_dma_hw_free,
- .prepare = fsl_dma_prepare,
.pointer = fsl_dma_pointer,
};
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index c6d6eb71dc1..169bca295b7 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -72,6 +72,7 @@
* @dev: struct device pointer
* @playback: the number of playback streams opened
* @capture: the number of capture streams opened
+ * @asynchronous: 0=synchronous mode, 1=asynchronous mode
* @cpu_dai: the CPU DAI for this device
* @dev_attr: the sysfs device attribute structure
* @stats: SSI statistics
@@ -86,6 +87,7 @@ struct fsl_ssi_private {
struct device *dev;
unsigned int playback;
unsigned int capture;
+ int asynchronous;
struct snd_soc_dai cpu_dai;
struct device_attribute dev_attr;
@@ -301,9 +303,10 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
*
* FIXME: Little-endian samples require a different shift dir
*/
- clrsetbits_be32(&ssi->scr, CCSR_SSI_SCR_I2S_MODE_MASK,
- CCSR_SSI_SCR_TFR_CLK_DIS |
- CCSR_SSI_SCR_I2S_MODE_SLAVE | CCSR_SSI_SCR_SYN);
+ clrsetbits_be32(&ssi->scr,
+ CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
+ CCSR_SSI_SCR_TFR_CLK_DIS | CCSR_SSI_SCR_I2S_MODE_SLAVE
+ | (ssi_private->asynchronous ? 0 : CCSR_SSI_SCR_SYN));
out_be32(&ssi->stcr,
CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
@@ -382,10 +385,15 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
SNDRV_PCM_HW_PARAM_RATE,
first_runtime->rate, first_runtime->rate);
- snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
- first_runtime->sample_bits,
- first_runtime->sample_bits);
+ /* If we're in synchronous mode, then we need to constrain
+ * the sample size as well. We don't support independent sample
+ * rates in asynchronous mode.
+ */
+ if (!ssi_private->asynchronous)
+ snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+ first_runtime->sample_bits,
+ first_runtime->sample_bits);
ssi_private->second_stream = substream;
}
@@ -400,7 +408,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
}
/**
- * fsl_ssi_prepare: prepare the SSI.
+ * fsl_ssi_hw_params - program the sample size
*
* Most of the SSI registers have been programmed in the startup function,
* but the word length must be programmed here. Unfortunately, programming
@@ -412,23 +420,27 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
* Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the
* clock master.
*/
-static int fsl_ssi_prepare(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
-
- struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+ struct fsl_ssi_private *ssi_private = cpu_dai->private_data;
if (substream == ssi_private->first_stream) {
- u32 wl;
+ struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+ unsigned int sample_size =
+ snd_pcm_format_width(params_format(hw_params));
+ u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
/* The SSI should always be disabled at this points (SSIEN=0) */
- wl = CCSR_SSI_SxCCR_WL(snd_pcm_format_width(runtime->format));
/* In synchronous mode, the SSI uses STCCR for capture */
- clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
+ if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ||
+ !ssi_private->asynchronous)
+ clrsetbits_be32(&ssi->stccr,
+ CCSR_SSI_SxCCR_WL_MASK, wl);
+ else
+ clrsetbits_be32(&ssi->srccr,
+ CCSR_SSI_SxCCR_WL_MASK, wl);
}
return 0;
@@ -452,28 +464,33 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
+ clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
setbits32(&ssi->scr,
CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE);
} else {
- clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
+ long timeout = jiffies + 10;
+
setbits32(&ssi->scr,
CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE);
- /*
- * I think we need this delay to allow time for the SSI
- * to put data into its FIFO. Without it, ALSA starts
- * to complain about overruns.
+ /* Wait until the SSI has filled its FIFO. Without this
+ * delay, ALSA complains about overruns. When the FIFO
+ * is full, the DMA controller initiates its first
+ * transfer. Until then, however, the DMA's DAR
+ * register is zero, which translates to an
+ * out-of-bounds pointer. This makes ALSA think an
+ * overrun has occurred.
*/
- mdelay(1);
+ while (!(in_be32(&ssi->sisr) & CCSR_SSI_SISR_RFF0) &&
+ (jiffies < timeout));
+ if (!(in_be32(&ssi->sisr) & CCSR_SSI_SISR_RFF0))
+ return -EIO;
}
break;
case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
clrbits32(&ssi->scr, CCSR_SSI_SCR_TE);
@@ -563,6 +580,15 @@ static int fsl_ssi_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
/**
* fsl_ssi_dai_template: template CPU DAI for the SSI
*/
+static struct snd_soc_dai_ops fsl_ssi_dai_ops = {
+ .startup = fsl_ssi_startup,
+ .hw_params = fsl_ssi_hw_params,
+ .shutdown = fsl_ssi_shutdown,
+ .trigger = fsl_ssi_trigger,
+ .set_sysclk = fsl_ssi_set_sysclk,
+ .set_fmt = fsl_ssi_set_fmt,
+};
+
static struct snd_soc_dai fsl_ssi_dai_template = {
.playback = {
/* The SSI does not support monaural audio. */
@@ -577,14 +603,7 @@ static struct snd_soc_dai fsl_ssi_dai_template = {
.rates = FSLSSI_I2S_RATES,
.formats = FSLSSI_I2S_FORMATS,
},
- .ops = {
- .startup = fsl_ssi_startup,
- .prepare = fsl_ssi_prepare,
- .shutdown = fsl_ssi_shutdown,
- .trigger = fsl_ssi_trigger,
- .set_sysclk = fsl_ssi_set_sysclk,
- .set_fmt = fsl_ssi_set_fmt,
- },
+ .ops = &fsl_ssi_dai_ops,
};
/**
@@ -654,6 +673,7 @@ struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info)
ssi_private->ssi_phys = ssi_info->ssi_phys;
ssi_private->irq = ssi_info->irq;
ssi_private->dev = ssi_info->dev;
+ ssi_private->asynchronous = ssi_info->asynchronous;
ssi_private->dev->driver_data = fsl_ssi_dai;
@@ -704,6 +724,14 @@ void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai)
}
EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai);
+static int __init fsl_ssi_init(void)
+{
+ printk(KERN_INFO "Freescale Synchronous Serial Interface (SSI) ASoC Driver\n");
+
+ return 0;
+}
+module_init(fsl_ssi_init);
+
MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h
index 83b44d700e3..eade01feaab 100644
--- a/sound/soc/fsl/fsl_ssi.h
+++ b/sound/soc/fsl/fsl_ssi.h
@@ -208,6 +208,7 @@ struct ccsr_ssi {
* ssi_phys: physical address of the SSI registers
* irq: IRQ of this SSI
* dev: struct device, used to create the sysfs statistics file
+ * asynchronous: 0=synchronous mode, 1=asynchronous mode
*/
struct fsl_ssi_info {
unsigned int id;
@@ -215,6 +216,7 @@ struct fsl_ssi_info {
dma_addr_t ssi_phys;
unsigned int irq;
struct device *dev;
+ int asynchronous;
};
struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info);
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index 9eb1ce185bd..3aa729df27b 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -468,6 +468,16 @@ static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
/**
* psc_i2s_dai_template: template CPU Digital Audio Interface
*/
+static struct snd_soc_dai_ops psc_i2s_dai_ops = {
+ .startup = psc_i2s_startup,
+ .hw_params = psc_i2s_hw_params,
+ .hw_free = psc_i2s_hw_free,
+ .shutdown = psc_i2s_shutdown,
+ .trigger = psc_i2s_trigger,
+ .set_sysclk = psc_i2s_set_sysclk,
+ .set_fmt = psc_i2s_set_fmt,
+};
+
static struct snd_soc_dai psc_i2s_dai_template = {
.playback = {
.channels_min = 2,
@@ -481,15 +491,7 @@ static struct snd_soc_dai psc_i2s_dai_template = {
.rates = PSC_I2S_RATES,
.formats = PSC_I2S_FORMATS,
},
- .ops = {
- .startup = psc_i2s_startup,
- .hw_params = psc_i2s_hw_params,
- .hw_free = psc_i2s_hw_free,
- .shutdown = psc_i2s_shutdown,
- .trigger = psc_i2s_trigger,
- .set_sysclk = psc_i2s_set_sysclk,
- .set_fmt = psc_i2s_set_fmt,
- },
+ .ops = &psc_i2s_dai_ops,
};
/* ---------------------------------------------------------------------
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index acf39a646b2..ef67d1cdffe 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -353,6 +353,11 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev,
}
ssi_info.irq = machine_data->ssi_irq;
+ /* Do we want to use asynchronous mode? */
+ ssi_info.asynchronous =
+ of_find_property(np, "fsl,ssi-asynchronous", NULL) ? 1 : 0;
+ if (ssi_info.asynchronous)
+ dev_info(&ofdev->dev, "using asynchronous mode\n");
/* Map the global utilities registers. */
guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index 4f7f0401458..675732e724d 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -8,7 +8,7 @@ config SND_OMAP_SOC_MCBSP
config SND_OMAP_SOC_N810
tristate "SoC Audio support for Nokia N810"
- depends on SND_OMAP_SOC && MACH_NOKIA_N810
+ depends on SND_OMAP_SOC && MACH_NOKIA_N810 && I2C
select SND_OMAP_SOC_MCBSP
select OMAP_MUX
select SND_SOC_TLV320AIC3X
@@ -17,7 +17,7 @@ config SND_OMAP_SOC_N810
config SND_OMAP_SOC_OSK5912
tristate "SoC Audio support for omap osk5912"
- depends on SND_OMAP_SOC && MACH_OMAP_OSK
+ depends on SND_OMAP_SOC && MACH_OMAP_OSK && I2C
select SND_OMAP_SOC_MCBSP
select SND_SOC_TLV320AIC23
help
@@ -55,3 +55,13 @@ config SND_OMAP_SOC_OMAP3_PANDORA
select SND_SOC_TWL4030
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"
+ depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_BEAGLE
+ select SND_OMAP_SOC_MCBSP
+ select SND_SOC_TWL4030
+ help
+ Say Y if you want to add support for SoC audio on the Beagleboard.
+
+
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index 76fedd96e36..0c9e4ac3766 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -12,6 +12,7 @@ snd-soc-overo-objs := overo.o
snd-soc-omap2evm-objs := omap2evm.o
snd-soc-sdp3430-objs := sdp3430.o
snd-soc-omap3pandora-objs := omap3pandora.o
+snd-soc-omap3beagle-objs := omap3beagle.o
obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
@@ -19,3 +20,4 @@ obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o
obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o
obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
+obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index 25593fee912..a6d1178ce12 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -40,6 +40,13 @@
#define N810_HEADSET_AMP_GPIO 10
#define N810_SPEAKER_AMP_GPIO 101
+enum {
+ N810_JACK_DISABLED,
+ N810_JACK_HP,
+ N810_JACK_HS,
+ N810_JACK_MIC,
+};
+
static struct clk *sys_clkout2;
static struct clk *sys_clkout2_src;
static struct clk *func96m_clk;
@@ -50,15 +57,32 @@ static int n810_dmic_func;
static void n810_ext_control(struct snd_soc_codec *codec)
{
+ int hp = 0, line1l = 0;
+
+ switch (n810_jack_func) {
+ case N810_JACK_HS:
+ line1l = 1;
+ case N810_JACK_HP:
+ hp = 1;
+ break;
+ case N810_JACK_MIC:
+ line1l = 1;
+ break;
+ }
+
if (n810_spk_func)
snd_soc_dapm_enable_pin(codec, "Ext Spk");
else
snd_soc_dapm_disable_pin(codec, "Ext Spk");
- if (n810_jack_func)
+ if (hp)
snd_soc_dapm_enable_pin(codec, "Headphone Jack");
else
snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+ if (line1l)
+ snd_soc_dapm_enable_pin(codec, "LINE1L");
+ else
+ snd_soc_dapm_disable_pin(codec, "LINE1L");
if (n810_dmic_func)
snd_soc_dapm_enable_pin(codec, "DMic");
@@ -72,7 +96,7 @@ static int n810_startup(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->codec;
+ struct snd_soc_codec *codec = rtd->socdev->card->codec;
snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
@@ -229,7 +253,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
};
static const char *spk_function[] = {"Off", "On"};
-static const char *jack_function[] = {"Off", "Headphone"};
+static const char *jack_function[] = {"Off", "Headphone", "Headset", "Mic"};
static const char *input_function[] = {"ADC", "Digital Mic"};
static const struct soc_enum n810_enum[] = {
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
@@ -248,20 +272,23 @@ static const struct snd_kcontrol_new aic33_n810_controls[] = {
static int n810_aic33_init(struct snd_soc_codec *codec)
{
- int i, err;
+ int err;
/* Not connected */
snd_soc_dapm_nc_pin(codec, "MONO_LOUT");
snd_soc_dapm_nc_pin(codec, "HPLCOM");
snd_soc_dapm_nc_pin(codec, "HPRCOM");
+ snd_soc_dapm_nc_pin(codec, "MIC3L");
+ snd_soc_dapm_nc_pin(codec, "MIC3R");
+ snd_soc_dapm_nc_pin(codec, "LINE1R");
+ snd_soc_dapm_nc_pin(codec, "LINE2L");
+ snd_soc_dapm_nc_pin(codec, "LINE2R");
/* Add N810 specific controls */
- for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&aic33_n810_controls[i], codec, NULL));
- if (err < 0)
- return err;
- }
+ err = snd_soc_add_controls(codec, aic33_n810_controls,
+ ARRAY_SIZE(aic33_n810_controls));
+ if (err < 0)
+ return err;
/* Add N810 specific widgets */
snd_soc_dapm_new_controls(codec, aic33_dapm_widgets,
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index ec5e18a7875..d6882be3345 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -302,6 +302,10 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
regs->spcr1 |= RINTM(3);
regs->rcr2 |= RFIG;
regs->xcr2 |= XFIG;
+ if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+ regs->xccr = DXENDLY(1) | XDMAEN;
+ regs->rccr = RFULL_CYCLE | RDMAEN;
+ }
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
@@ -457,6 +461,16 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
return err;
}
+static struct snd_soc_dai_ops omap_mcbsp_dai_ops = {
+ .startup = omap_mcbsp_dai_startup,
+ .shutdown = omap_mcbsp_dai_shutdown,
+ .trigger = omap_mcbsp_dai_trigger,
+ .hw_params = omap_mcbsp_dai_hw_params,
+ .set_fmt = omap_mcbsp_dai_set_dai_fmt,
+ .set_clkdiv = omap_mcbsp_dai_set_clkdiv,
+ .set_sysclk = omap_mcbsp_dai_set_dai_sysclk,
+};
+
#define OMAP_MCBSP_DAI_BUILDER(link_id) \
{ \
.name = "omap-mcbsp-dai-"#link_id, \
@@ -473,15 +487,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
.rates = OMAP_MCBSP_RATES, \
.formats = SNDRV_PCM_FMTBIT_S16_LE, \
}, \
- .ops = { \
- .startup = omap_mcbsp_dai_startup, \
- .shutdown = omap_mcbsp_dai_shutdown, \
- .trigger = omap_mcbsp_dai_trigger, \
- .hw_params = omap_mcbsp_dai_hw_params, \
- .set_fmt = omap_mcbsp_dai_set_dai_fmt, \
- .set_clkdiv = omap_mcbsp_dai_set_clkdiv, \
- .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, \
- }, \
+ .ops = &omap_mcbsp_dai_ops, \
.private_data = &mcbsp_data[(link_id)].bus_id, \
}
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index b0362dfd5b7..8e1431cb46b 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -175,9 +175,10 @@ 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;
+ unsigned long flags;
int ret = 0;
- spin_lock_irq(&prtd->lock);
+ spin_lock_irqsave(&prtd->lock, flags);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
@@ -195,7 +196,7 @@ static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
default:
ret = -EINVAL;
}
- spin_unlock_irq(&prtd->lock);
+ spin_unlock_irqrestore(&prtd->lock, flags);
return ret;
}
@@ -264,7 +265,7 @@ static int omap_pcm_mmap(struct snd_pcm_substream *substream,
runtime->dma_bytes);
}
-struct snd_pcm_ops omap_pcm_ops = {
+static struct snd_pcm_ops omap_pcm_ops = {
.open = omap_pcm_open,
.close = omap_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
index fcc2f5d9a87..fe282d4ef42 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/omap/omap3pandora.c
@@ -143,7 +143,7 @@ static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = {
};
static const struct snd_soc_dapm_widget omap3pandora_in_dapm_widgets[] = {
- SND_SOC_DAPM_MIC("Mic (Internal)", NULL),
+ SND_SOC_DAPM_MIC("Mic (internal)", NULL),
SND_SOC_DAPM_MIC("Mic (external)", NULL),
SND_SOC_DAPM_LINE("Line In", NULL),
};
@@ -155,16 +155,33 @@ static const struct snd_soc_dapm_route omap3pandora_out_map[] = {
};
static const struct snd_soc_dapm_route omap3pandora_in_map[] = {
- {"INL", NULL, "Line In"},
- {"INR", NULL, "Line In"},
- {"INL", NULL, "Mic (Internal)"},
- {"INR", NULL, "Mic (external)"},
+ {"AUXL", NULL, "Line In"},
+ {"AUXR", NULL, "Line In"},
+
+ {"MAINMIC", NULL, "Mic Bias 1"},
+ {"Mic Bias 1", NULL, "Mic (internal)"},
+
+ {"SUBMIC", NULL, "Mic Bias 2"},
+ {"Mic Bias 2", NULL, "Mic (external)"},
};
static int omap3pandora_out_init(struct snd_soc_codec *codec)
{
int ret;
+ /* All TWL4030 output pins are floating */
+ snd_soc_dapm_nc_pin(codec, "OUTL");
+ snd_soc_dapm_nc_pin(codec, "OUTR");
+ snd_soc_dapm_nc_pin(codec, "EARPIECE");
+ snd_soc_dapm_nc_pin(codec, "PREDRIVEL");
+ snd_soc_dapm_nc_pin(codec, "PREDRIVER");
+ snd_soc_dapm_nc_pin(codec, "HSOL");
+ snd_soc_dapm_nc_pin(codec, "HSOR");
+ snd_soc_dapm_nc_pin(codec, "CARKITL");
+ snd_soc_dapm_nc_pin(codec, "CARKITR");
+ snd_soc_dapm_nc_pin(codec, "HFL");
+ snd_soc_dapm_nc_pin(codec, "HFR");
+
ret = snd_soc_dapm_new_controls(codec, omap3pandora_out_dapm_widgets,
ARRAY_SIZE(omap3pandora_out_dapm_widgets));
if (ret < 0)
@@ -180,18 +197,11 @@ static int omap3pandora_in_init(struct snd_soc_codec *codec)
{
int ret;
- /* All TWL4030 output pins are floating */
- snd_soc_dapm_nc_pin(codec, "OUTL"),
- snd_soc_dapm_nc_pin(codec, "OUTR"),
- snd_soc_dapm_nc_pin(codec, "EARPIECE"),
- snd_soc_dapm_nc_pin(codec, "PREDRIVEL"),
- snd_soc_dapm_nc_pin(codec, "PREDRIVER"),
- snd_soc_dapm_nc_pin(codec, "HSOL"),
- snd_soc_dapm_nc_pin(codec, "HSOR"),
- snd_soc_dapm_nc_pin(codec, "CARKITL"),
- snd_soc_dapm_nc_pin(codec, "CARKITR"),
- snd_soc_dapm_nc_pin(codec, "HFL"),
- snd_soc_dapm_nc_pin(codec, "HFR"),
+ /* Not comnnected */
+ snd_soc_dapm_nc_pin(codec, "HSMIC");
+ snd_soc_dapm_nc_pin(codec, "CARKITMIC");
+ snd_soc_dapm_nc_pin(codec, "DIGIMIC0");
+ snd_soc_dapm_nc_pin(codec, "DIGIMIC1");
ret = snd_soc_dapm_new_controls(codec, omap3pandora_in_dapm_widgets,
ARRAY_SIZE(omap3pandora_in_dapm_widgets));
@@ -251,10 +261,9 @@ static int __init omap3pandora_soc_init(void)
{
int ret;
- if (!machine_is_omap3_pandora()) {
- pr_debug(PREFIX "Not OMAP3 Pandora\n");
+ if (!machine_is_omap3_pandora())
return -ENODEV;
- }
+
pr_info("OMAP3 Pandora SoC init\n");
ret = gpio_request(OMAP3_PANDORA_DAC_POWER_GPIO, "dac_power");
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
index cd41a948df7..a952a4eb336 100644
--- a/sound/soc/omap/osk5912.c
+++ b/sound/soc/omap/osk5912.c
@@ -186,13 +186,6 @@ static int __init osk_soc_init(void)
return -ENODEV;
}
- if (clk_get_usecount(tlv320aic23_mclk) > 0) {
- /* MCLK is already in use */
- printk(KERN_WARNING
- "MCLK in use at %d Hz. We change it to %d Hz\n",
- (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK);
- }
-
/*
* Configure 12 MHz output on MCLK.
*/
@@ -205,9 +198,8 @@ static int __init osk_soc_init(void)
}
}
- printk(KERN_INFO "MCLK = %d [%d], usecount = %d\n",
- (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK,
- clk_get_usecount(tlv320aic23_mclk));
+ printk(KERN_INFO "MCLK = %d [%d]\n",
+ (uint) clk_get_rate(tlv320aic23_mclk), CODEC_CLOCK);
return 0;
err1:
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c
index ad97836818b..10f1c867f11 100644
--- a/sound/soc/omap/sdp3430.c
+++ b/sound/soc/omap/sdp3430.c
@@ -28,6 +28,7 @@
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
+#include <sound/jack.h>
#include <asm/mach-types.h>
#include <mach/hardware.h>
@@ -38,6 +39,8 @@
#include "omap-pcm.h"
#include "../codecs/twl4030.h"
+static struct snd_soc_card snd_soc_sdp3430;
+
static int sdp3430_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -81,17 +84,126 @@ static struct snd_soc_ops sdp3430_ops = {
.hw_params = sdp3430_hw_params,
};
+/* Headset jack */
+static struct snd_soc_jack hs_jack;
+
+/* Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+ {
+ .pin = "Headset Stereophone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+};
+
+/* Headset jack detection gpios */
+static struct snd_soc_jack_gpio hs_jack_gpios[] = {
+ {
+ .gpio = (OMAP_MAX_GPIO_LINES + 2),
+ .name = "hsdet-gpio",
+ .report = SND_JACK_HEADSET,
+ .debounce_time = 200,
+ },
+};
+
+/* SDP3430 machine DAPM */
+static const struct snd_soc_dapm_widget sdp3430_twl4030_dapm_widgets[] = {
+ SND_SOC_DAPM_MIC("Ext Mic", NULL),
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* External Mics: MAINMIC, SUBMIC with bias*/
+ {"MAINMIC", NULL, "Mic Bias 1"},
+ {"SUBMIC", NULL, "Mic Bias 2"},
+ {"Mic Bias 1", NULL, "Ext Mic"},
+ {"Mic Bias 2", NULL, "Ext Mic"},
+
+ /* External Speakers: HFL, HFR */
+ {"Ext Spk", NULL, "HFL"},
+ {"Ext Spk", NULL, "HFR"},
+
+ /* Headset Mic: HSMIC with bias */
+ {"HSMIC", NULL, "Headset Mic Bias"},
+ {"Headset Mic Bias", NULL, "Headset Mic"},
+
+ /* Headset Stereophone (Headphone): HSOL, HSOR */
+ {"Headset Stereophone", NULL, "HSOL"},
+ {"Headset Stereophone", NULL, "HSOR"},
+};
+
+static int sdp3430_twl4030_init(struct snd_soc_codec *codec)
+{
+ int ret;
+
+ /* Add SDP3430 specific widgets */
+ ret = snd_soc_dapm_new_controls(codec, sdp3430_twl4030_dapm_widgets,
+ ARRAY_SIZE(sdp3430_twl4030_dapm_widgets));
+ if (ret)
+ return ret;
+
+ /* Set up SDP3430 specific audio path audio_map */
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ /* SDP3430 connected pins */
+ snd_soc_dapm_enable_pin(codec, "Ext Mic");
+ snd_soc_dapm_enable_pin(codec, "Ext Spk");
+ snd_soc_dapm_disable_pin(codec, "Headset Mic");
+ snd_soc_dapm_disable_pin(codec, "Headset Stereophone");
+
+ /* TWL4030 not connected pins */
+ snd_soc_dapm_nc_pin(codec, "AUXL");
+ snd_soc_dapm_nc_pin(codec, "AUXR");
+ snd_soc_dapm_nc_pin(codec, "CARKITMIC");
+ snd_soc_dapm_nc_pin(codec, "DIGIMIC0");
+ snd_soc_dapm_nc_pin(codec, "DIGIMIC1");
+
+ snd_soc_dapm_nc_pin(codec, "OUTL");
+ snd_soc_dapm_nc_pin(codec, "OUTR");
+ snd_soc_dapm_nc_pin(codec, "EARPIECE");
+ snd_soc_dapm_nc_pin(codec, "PREDRIVEL");
+ snd_soc_dapm_nc_pin(codec, "PREDRIVER");
+ snd_soc_dapm_nc_pin(codec, "CARKITL");
+ snd_soc_dapm_nc_pin(codec, "CARKITR");
+
+ ret = snd_soc_dapm_sync(codec);
+ if (ret)
+ return ret;
+
+ /* Headset jack detection */
+ ret = snd_soc_jack_new(&snd_soc_sdp3430, "Headset Jack",
+ SND_JACK_HEADSET, &hs_jack);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
+ hs_jack_pins);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
+ hs_jack_gpios);
+
+ return ret;
+}
+
/* Digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link sdp3430_dai = {
.name = "TWL4030",
.stream_name = "TWL4030",
.cpu_dai = &omap_mcbsp_dai[0],
.codec_dai = &twl4030_dai,
+ .init = sdp3430_twl4030_init,
.ops = &sdp3430_ops,
};
/* Audio machine driver */
-static struct snd_soc_machine snd_soc_machine_sdp3430 = {
+static struct snd_soc_card snd_soc_sdp3430 = {
.name = "SDP3430",
.platform = &omap_soc_platform,
.dai_link = &sdp3430_dai,
@@ -100,7 +212,7 @@ static struct snd_soc_machine snd_soc_machine_sdp3430 = {
/* Audio subsystem */
static struct snd_soc_device sdp3430_snd_devdata = {
- .machine = &snd_soc_machine_sdp3430,
+ .card = &snd_soc_sdp3430,
.codec_dev = &soc_codec_dev_twl4030,
};
@@ -142,6 +254,9 @@ module_init(sdp3430_soc_init);
static void __exit sdp3430_soc_exit(void)
{
+ snd_soc_jack_free_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
+ hs_jack_gpios);
+
platform_device_unregister(sdp3430_snd_device);
}
module_exit(sdp3430_soc_exit);
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index f82e1069947..5998ab366e8 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -61,6 +61,24 @@ config SND_PXA2XX_SOC_TOSA
Say Y if you want to add support for SoC audio on Sharp
Zaurus SL-C6000x models (Tosa).
+config SND_PXA2XX_SOC_E740
+ tristate "SoC AC97 Audio support for e740"
+ depends on SND_PXA2XX_SOC && MACH_E740
+ select SND_SOC_WM9705
+ select SND_PXA2XX_SOC_AC97
+ help
+ Say Y if you want to add support for SoC audio on the
+ toshiba e740 PDA
+
+config SND_PXA2XX_SOC_E750
+ tristate "SoC AC97 Audio support for e750"
+ depends on SND_PXA2XX_SOC && MACH_E750
+ select SND_SOC_WM9705
+ select SND_PXA2XX_SOC_AC97
+ help
+ Say Y if you want to add support for SoC audio on the
+ toshiba e750 PDA
+
config SND_PXA2XX_SOC_E800
tristate "SoC AC97 Audio support for e800"
depends on SND_PXA2XX_SOC && MACH_E800
@@ -97,3 +115,12 @@ config SND_SOC_ZYLONITE
help
Say Y if you want to add support for SoC audio on the
Marvell Zylonite reference platform.
+
+config SND_PXA2XX_SOC_MIOA701
+ tristate "SoC Audio support for MIO A701"
+ depends on SND_PXA2XX_SOC && MACH_MIOA701
+ select SND_PXA2XX_SOC_AC97
+ select SND_SOC_WM9713
+ help
+ Say Y if you want to add support for SoC audio on the
+ MIO A701.
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile
index 08a9f279772..8ed881c5e5c 100644
--- a/sound/soc/pxa/Makefile
+++ b/sound/soc/pxa/Makefile
@@ -13,17 +13,23 @@ obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o
snd-soc-corgi-objs := corgi.o
snd-soc-poodle-objs := poodle.o
snd-soc-tosa-objs := tosa.o
+snd-soc-e740-objs := e740_wm9705.o
+snd-soc-e750-objs := e750_wm9705.o
snd-soc-e800-objs := e800_wm9712.o
snd-soc-spitz-objs := spitz.o
snd-soc-em-x270-objs := em-x270.o
snd-soc-palm27x-objs := palm27x.o
snd-soc-zylonite-objs := zylonite.o
+snd-soc-mioa701-objs := mioa701_wm9713.o
obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o
obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o
obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o
+obj-$(CONFIG_SND_PXA2XX_SOC_E740) += snd-soc-e740.o
+obj-$(CONFIG_SND_PXA2XX_SOC_E750) += snd-soc-e750.o
obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o
obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o
obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o
obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o
+obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
index 1ba25a55952..02263e5d8f0 100644
--- a/sound/soc/pxa/corgi.c
+++ b/sound/soc/pxa/corgi.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/timer.h>
+#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
@@ -100,7 +101,7 @@ static void corgi_ext_control(struct snd_soc_codec *codec)
static int corgi_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->codec;
+ struct snd_soc_codec *codec = rtd->socdev->card->codec;
/* check the jack status at stream startup */
corgi_ext_control(codec);
@@ -275,18 +276,16 @@ static const struct snd_kcontrol_new wm8731_corgi_controls[] = {
*/
static int corgi_wm8731_init(struct snd_soc_codec *codec)
{
- int i, err;
+ int err;
snd_soc_dapm_nc_pin(codec, "LLINEIN");
snd_soc_dapm_nc_pin(codec, "RLINEIN");
/* Add corgi specific controls */
- for (i = 0; i < ARRAY_SIZE(wm8731_corgi_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm8731_corgi_controls[i], codec, NULL));
- if (err < 0)
- return err;
- }
+ err = snd_soc_add_controls(codec, wm8731_corgi_controls,
+ ARRAY_SIZE(wm8731_corgi_controls));
+ if (err < 0)
+ return err;
/* Add corgi specific widgets */
snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets,
@@ -317,19 +316,44 @@ static struct snd_soc_card snd_soc_corgi = {
.num_links = 1,
};
-/* corgi audio private data */
-static struct wm8731_setup_data corgi_wm8731_setup = {
- .i2c_bus = 0,
- .i2c_address = 0x1b,
-};
-
/* corgi audio subsystem */
static struct snd_soc_device corgi_snd_devdata = {
.card = &snd_soc_corgi,
.codec_dev = &soc_codec_dev_wm8731,
- .codec_data = &corgi_wm8731_setup,
};
+/*
+ * FIXME: This is a temporary bodge to avoid cross-tree merge issues.
+ * New drivers should register the wm8731 I2C device in the machine
+ * setup code (under arch/arm for ARM systems).
+ */
+static int wm8731_i2c_register(void)
+{
+ struct i2c_board_info info;
+ struct i2c_adapter *adapter;
+ struct i2c_client *client;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ info.addr = 0x1b;
+ strlcpy(info.type, "wm8731", I2C_NAME_SIZE);
+
+ adapter = i2c_get_adapter(0);
+ if (!adapter) {
+ printk(KERN_ERR "can't get i2c adapter 0\n");
+ return -ENODEV;
+ }
+
+ client = i2c_new_device(adapter, &info);
+ i2c_put_adapter(adapter);
+ if (!client) {
+ printk(KERN_ERR "can't add i2c device at 0x%x\n",
+ (unsigned int)info.addr);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
static struct platform_device *corgi_snd_device;
static int __init corgi_init(void)
@@ -340,6 +364,10 @@ static int __init corgi_init(void)
machine_is_husky()))
return -ENODEV;
+ ret = wm8731_i2c_register();
+ if (ret != 0)
+ return ret;
+
corgi_snd_device = platform_device_alloc("soc-audio", -1);
if (!corgi_snd_device)
return -ENOMEM;
diff --git a/sound/soc/pxa/e740_wm9705.c b/sound/soc/pxa/e740_wm9705.c
new file mode 100644
index 00000000000..7cd2f89d7b1
--- /dev/null
+++ b/sound/soc/pxa/e740_wm9705.c
@@ -0,0 +1,211 @@
+/*
+ * e740-wm9705.c -- SoC audio for e740
+ *
+ * Copyright 2007 (c) Ian Molton <spyro@f2s.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 ONLY.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <mach/audio.h>
+#include <mach/eseries-gpio.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/wm9705.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-ac97.h"
+
+
+#define E740_AUDIO_OUT 1
+#define E740_AUDIO_IN 2
+
+static int e740_audio_power;
+
+static void e740_sync_audio_power(int status)
+{
+ gpio_set_value(GPIO_E740_WM9705_nAVDD2, !status);
+ gpio_set_value(GPIO_E740_AMP_ON, (status & E740_AUDIO_OUT) ? 1 : 0);
+ gpio_set_value(GPIO_E740_MIC_ON, (status & E740_AUDIO_IN) ? 1 : 0);
+}
+
+static int e740_mic_amp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ if (event & SND_SOC_DAPM_PRE_PMU)
+ e740_audio_power |= E740_AUDIO_IN;
+ else if (event & SND_SOC_DAPM_POST_PMD)
+ e740_audio_power &= ~E740_AUDIO_IN;
+
+ e740_sync_audio_power(e740_audio_power);
+
+ return 0;
+}
+
+static int e740_output_amp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ if (event & SND_SOC_DAPM_PRE_PMU)
+ e740_audio_power |= E740_AUDIO_OUT;
+ else if (event & SND_SOC_DAPM_POST_PMD)
+ e740_audio_power &= ~E740_AUDIO_OUT;
+
+ e740_sync_audio_power(e740_audio_power);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget e740_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_MIC("Mic (Internal)", NULL),
+ SND_SOC_DAPM_PGA_E("Output Amp", SND_SOC_NOPM, 0, 0, NULL, 0,
+ e740_output_amp_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("Mic Amp", SND_SOC_NOPM, 0, 0, NULL, 0,
+ e740_mic_amp_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ {"Output Amp", NULL, "LOUT"},
+ {"Output Amp", NULL, "ROUT"},
+ {"Output Amp", NULL, "MONOOUT"},
+
+ {"Speaker", NULL, "Output Amp"},
+ {"Headphone Jack", NULL, "Output Amp"},
+
+ {"MIC1", NULL, "Mic Amp"},
+ {"Mic Amp", NULL, "Mic (Internal)"},
+};
+
+static int e740_ac97_init(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_nc_pin(codec, "HPOUTL");
+ snd_soc_dapm_nc_pin(codec, "HPOUTR");
+ snd_soc_dapm_nc_pin(codec, "PHONE");
+ snd_soc_dapm_nc_pin(codec, "LINEINL");
+ snd_soc_dapm_nc_pin(codec, "LINEINR");
+ snd_soc_dapm_nc_pin(codec, "CDINL");
+ snd_soc_dapm_nc_pin(codec, "CDINR");
+ snd_soc_dapm_nc_pin(codec, "PCBEEP");
+ snd_soc_dapm_nc_pin(codec, "MIC2");
+
+ snd_soc_dapm_new_controls(codec, e740_dapm_widgets,
+ ARRAY_SIZE(e740_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ snd_soc_dapm_sync(codec);
+
+ return 0;
+}
+
+static struct snd_soc_dai_link e740_dai[] = {
+ {
+ .name = "AC97",
+ .stream_name = "AC97 HiFi",
+ .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
+ .codec_dai = &wm9705_dai[WM9705_DAI_AC97_HIFI],
+ .init = e740_ac97_init,
+ },
+ {
+ .name = "AC97 Aux",
+ .stream_name = "AC97 Aux",
+ .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
+ .codec_dai = &wm9705_dai[WM9705_DAI_AC97_AUX],
+ },
+};
+
+static struct snd_soc_card e740 = {
+ .name = "Toshiba e740",
+ .platform = &pxa2xx_soc_platform,
+ .dai_link = e740_dai,
+ .num_links = ARRAY_SIZE(e740_dai),
+};
+
+static struct snd_soc_device e740_snd_devdata = {
+ .card = &e740,
+ .codec_dev = &soc_codec_dev_wm9705,
+};
+
+static struct platform_device *e740_snd_device;
+
+static int __init e740_init(void)
+{
+ int ret;
+
+ if (!machine_is_e740())
+ return -ENODEV;
+
+ ret = gpio_request(GPIO_E740_MIC_ON, "Mic amp");
+ if (ret)
+ return ret;
+
+ ret = gpio_request(GPIO_E740_AMP_ON, "Output amp");
+ if (ret)
+ goto free_mic_amp_gpio;
+
+ ret = gpio_request(GPIO_E740_WM9705_nAVDD2, "Audio power");
+ if (ret)
+ goto free_op_amp_gpio;
+
+ /* Disable audio */
+ ret = gpio_direction_output(GPIO_E740_MIC_ON, 0);
+ if (ret)
+ goto free_apwr_gpio;
+ ret = gpio_direction_output(GPIO_E740_AMP_ON, 0);
+ if (ret)
+ goto free_apwr_gpio;
+ ret = gpio_direction_output(GPIO_E740_WM9705_nAVDD2, 1);
+ if (ret)
+ goto free_apwr_gpio;
+
+ e740_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!e740_snd_device) {
+ ret = -ENOMEM;
+ goto free_apwr_gpio;
+ }
+
+ platform_set_drvdata(e740_snd_device, &e740_snd_devdata);
+ e740_snd_devdata.dev = &e740_snd_device->dev;
+ ret = platform_device_add(e740_snd_device);
+
+ if (!ret)
+ return 0;
+
+/* Fail gracefully */
+ platform_device_put(e740_snd_device);
+free_apwr_gpio:
+ gpio_free(GPIO_E740_WM9705_nAVDD2);
+free_op_amp_gpio:
+ gpio_free(GPIO_E740_AMP_ON);
+free_mic_amp_gpio:
+ gpio_free(GPIO_E740_MIC_ON);
+
+ return ret;
+}
+
+static void __exit e740_exit(void)
+{
+ platform_device_unregister(e740_snd_device);
+}
+
+module_init(e740_init);
+module_exit(e740_exit);
+
+/* Module information */
+MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
+MODULE_DESCRIPTION("ALSA SoC driver for e740");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/pxa/e750_wm9705.c b/sound/soc/pxa/e750_wm9705.c
new file mode 100644
index 00000000000..8dceccc5e05
--- /dev/null
+++ b/sound/soc/pxa/e750_wm9705.c
@@ -0,0 +1,187 @@
+/*
+ * e750-wm9705.c -- SoC audio for e750
+ *
+ * Copyright 2007 (c) Ian Molton <spyro@f2s.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 ONLY.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <mach/audio.h>
+#include <mach/eseries-gpio.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/wm9705.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-ac97.h"
+
+static int e750_spk_amp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ if (event & SND_SOC_DAPM_PRE_PMU)
+ gpio_set_value(GPIO_E750_SPK_AMP_OFF, 0);
+ else if (event & SND_SOC_DAPM_POST_PMD)
+ gpio_set_value(GPIO_E750_SPK_AMP_OFF, 1);
+
+ return 0;
+}
+
+static int e750_hp_amp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ if (event & SND_SOC_DAPM_PRE_PMU)
+ gpio_set_value(GPIO_E750_HP_AMP_OFF, 0);
+ else if (event & SND_SOC_DAPM_POST_PMD)
+ gpio_set_value(GPIO_E750_HP_AMP_OFF, 1);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget e750_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_MIC("Mic (Internal)", NULL),
+ SND_SOC_DAPM_PGA_E("Headphone Amp", SND_SOC_NOPM, 0, 0, NULL, 0,
+ e750_hp_amp_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("Speaker Amp", SND_SOC_NOPM, 0, 0, NULL, 0,
+ e750_spk_amp_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ {"Headphone Amp", NULL, "HPOUTL"},
+ {"Headphone Amp", NULL, "HPOUTR"},
+ {"Headphone Jack", NULL, "Headphone Amp"},
+
+ {"Speaker Amp", NULL, "MONOOUT"},
+ {"Speaker", NULL, "Speaker Amp"},
+
+ {"MIC1", NULL, "Mic (Internal)"},
+};
+
+static int e750_ac97_init(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_nc_pin(codec, "LOUT");
+ snd_soc_dapm_nc_pin(codec, "ROUT");
+ snd_soc_dapm_nc_pin(codec, "PHONE");
+ snd_soc_dapm_nc_pin(codec, "LINEINL");
+ snd_soc_dapm_nc_pin(codec, "LINEINR");
+ snd_soc_dapm_nc_pin(codec, "CDINL");
+ snd_soc_dapm_nc_pin(codec, "CDINR");
+ snd_soc_dapm_nc_pin(codec, "PCBEEP");
+ snd_soc_dapm_nc_pin(codec, "MIC2");
+
+ snd_soc_dapm_new_controls(codec, e750_dapm_widgets,
+ ARRAY_SIZE(e750_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ snd_soc_dapm_sync(codec);
+
+ return 0;
+}
+
+static struct snd_soc_dai_link e750_dai[] = {
+ {
+ .name = "AC97",
+ .stream_name = "AC97 HiFi",
+ .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
+ .codec_dai = &wm9705_dai[WM9705_DAI_AC97_HIFI],
+ .init = e750_ac97_init,
+ /* use ops to check startup state */
+ },
+ {
+ .name = "AC97 Aux",
+ .stream_name = "AC97 Aux",
+ .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
+ .codec_dai = &wm9705_dai[WM9705_DAI_AC97_AUX],
+ },
+};
+
+static struct snd_soc_card e750 = {
+ .name = "Toshiba e750",
+ .platform = &pxa2xx_soc_platform,
+ .dai_link = e750_dai,
+ .num_links = ARRAY_SIZE(e750_dai),
+};
+
+static struct snd_soc_device e750_snd_devdata = {
+ .card = &e750,
+ .codec_dev = &soc_codec_dev_wm9705,
+};
+
+static struct platform_device *e750_snd_device;
+
+static int __init e750_init(void)
+{
+ int ret;
+
+ if (!machine_is_e750())
+ return -ENODEV;
+
+ ret = gpio_request(GPIO_E750_HP_AMP_OFF, "Headphone amp");
+ if (ret)
+ return ret;
+
+ ret = gpio_request(GPIO_E750_SPK_AMP_OFF, "Speaker amp");
+ if (ret)
+ goto free_hp_amp_gpio;
+
+ ret = gpio_direction_output(GPIO_E750_HP_AMP_OFF, 1);
+ if (ret)
+ goto free_spk_amp_gpio;
+
+ ret = gpio_direction_output(GPIO_E750_SPK_AMP_OFF, 1);
+ if (ret)
+ goto free_spk_amp_gpio;
+
+ e750_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!e750_snd_device) {
+ ret = -ENOMEM;
+ goto free_spk_amp_gpio;
+ }
+
+ platform_set_drvdata(e750_snd_device, &e750_snd_devdata);
+ e750_snd_devdata.dev = &e750_snd_device->dev;
+ ret = platform_device_add(e750_snd_device);
+
+ if (!ret)
+ return 0;
+
+/* Fail gracefully */
+ platform_device_put(e750_snd_device);
+free_spk_amp_gpio:
+ gpio_free(GPIO_E750_SPK_AMP_OFF);
+free_hp_amp_gpio:
+ gpio_free(GPIO_E750_HP_AMP_OFF);
+
+ return ret;
+}
+
+static void __exit e750_exit(void)
+{
+ platform_device_unregister(e750_snd_device);
+ gpio_free(GPIO_E750_SPK_AMP_OFF);
+ gpio_free(GPIO_E750_HP_AMP_OFF);
+}
+
+module_init(e750_init);
+module_exit(e750_exit);
+
+/* Module information */
+MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
+MODULE_DESCRIPTION("ALSA SoC driver for e750");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c
index 2e3386dfa0f..bc019cdce42 100644
--- a/sound/soc/pxa/e800_wm9712.c
+++ b/sound/soc/pxa/e800_wm9712.c
@@ -1,8 +1,6 @@
/*
* e800-wm9712.c -- SoC audio for e800
*
- * Based on tosa.c
- *
* Copyright 2007 (c) Ian Molton <spyro@f2s.com>
*
* This program is free software; you can redistribute it and/or modify it
@@ -13,7 +11,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/device.h>
+#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -21,23 +19,85 @@
#include <sound/soc-dapm.h>
#include <asm/mach-types.h>
-#include <mach/pxa-regs.h>
-#include <mach/hardware.h>
#include <mach/audio.h>
+#include <mach/eseries-gpio.h>
#include "../codecs/wm9712.h"
#include "pxa2xx-pcm.h"
#include "pxa2xx-ac97.h"
-static struct snd_soc_card e800;
+static int e800_spk_amp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ if (event & SND_SOC_DAPM_PRE_PMU)
+ gpio_set_value(GPIO_E800_SPK_AMP_ON, 1);
+ else if (event & SND_SOC_DAPM_POST_PMD)
+ gpio_set_value(GPIO_E800_SPK_AMP_ON, 0);
-static struct snd_soc_dai_link e800_dai[] = {
+ return 0;
+}
+
+static int e800_hp_amp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ if (event & SND_SOC_DAPM_PRE_PMU)
+ gpio_set_value(GPIO_E800_HP_AMP_OFF, 0);
+ else if (event & SND_SOC_DAPM_POST_PMD)
+ gpio_set_value(GPIO_E800_HP_AMP_OFF, 1);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget e800_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic (Internal1)", NULL),
+ SND_SOC_DAPM_MIC("Mic (Internal2)", NULL),
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+ SND_SOC_DAPM_PGA_E("Headphone Amp", SND_SOC_NOPM, 0, 0, NULL, 0,
+ e800_hp_amp_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("Speaker Amp", SND_SOC_NOPM, 0, 0, NULL, 0,
+ e800_spk_amp_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ {"Headphone Jack", NULL, "HPOUTL"},
+ {"Headphone Jack", NULL, "HPOUTR"},
+ {"Headphone Jack", NULL, "Headphone Amp"},
+
+ {"Speaker Amp", NULL, "MONOOUT"},
+ {"Speaker", NULL, "Speaker Amp"},
+
+ {"MIC1", NULL, "Mic (Internal1)"},
+ {"MIC2", NULL, "Mic (Internal2)"},
+};
+
+static int e800_ac97_init(struct snd_soc_codec *codec)
{
- .name = "AC97 Aux",
- .stream_name = "AC97 Aux",
- .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
- .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
-},
+ snd_soc_dapm_new_controls(codec, e800_dapm_widgets,
+ ARRAY_SIZE(e800_dapm_widgets));
+
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+ snd_soc_dapm_sync(codec);
+
+ return 0;
+}
+
+static struct snd_soc_dai_link e800_dai[] = {
+ {
+ .name = "AC97",
+ .stream_name = "AC97 HiFi",
+ .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
+ .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+ .init = e800_ac97_init,
+ },
+ {
+ .name = "AC97 Aux",
+ .stream_name = "AC97 Aux",
+ .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
+ .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+ },
};
static struct snd_soc_card e800 = {
@@ -61,6 +121,22 @@ static int __init e800_init(void)
if (!machine_is_e800())
return -ENODEV;
+ ret = gpio_request(GPIO_E800_HP_AMP_OFF, "Headphone amp");
+ if (ret)
+ return ret;
+
+ ret = gpio_request(GPIO_E800_SPK_AMP_ON, "Speaker amp");
+ if (ret)
+ goto free_hp_amp_gpio;
+
+ ret = gpio_direction_output(GPIO_E800_HP_AMP_OFF, 1);
+ if (ret)
+ goto free_spk_amp_gpio;
+
+ ret = gpio_direction_output(GPIO_E800_SPK_AMP_ON, 1);
+ if (ret)
+ goto free_spk_amp_gpio;
+
e800_snd_device = platform_device_alloc("soc-audio", -1);
if (!e800_snd_device)
return -ENOMEM;
@@ -69,8 +145,15 @@ static int __init e800_init(void)
e800_snd_devdata.dev = &e800_snd_device->dev;
ret = platform_device_add(e800_snd_device);
- if (ret)
- platform_device_put(e800_snd_device);
+ if (!ret)
+ return 0;
+
+/* Fail gracefully */
+ platform_device_put(e800_snd_device);
+free_spk_amp_gpio:
+ gpio_free(GPIO_E800_SPK_AMP_ON);
+free_hp_amp_gpio:
+ gpio_free(GPIO_E800_HP_AMP_OFF);
return ret;
}
@@ -78,6 +161,8 @@ static int __init e800_init(void)
static void __exit e800_exit(void)
{
platform_device_unregister(e800_snd_device);
+ gpio_free(GPIO_E800_SPK_AMP_ON);
+ gpio_free(GPIO_E800_HP_AMP_OFF);
}
module_init(e800_init);
@@ -86,4 +171,4 @@ module_exit(e800_exit);
/* Module information */
MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
MODULE_DESCRIPTION("ALSA SoC driver for e800");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c
new file mode 100644
index 00000000000..19eda8bbfda
--- /dev/null
+++ b/sound/soc/pxa/mioa701_wm9713.c
@@ -0,0 +1,250 @@
+/*
+ * Handles the Mitac mioa701 SoC system
+ *
+ * Copyright (C) 2008 Robert Jarzmik
+ *
+ * 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 in 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
+ *
+ * This is a little schema of the sound interconnections :
+ *
+ * Sagem X200 Wolfson WM9713
+ * +--------+ +-------------------+ Rear Speaker
+ * | | | | /-+
+ * | +--->----->---+MONOIN SPKL+--->----+-+ |
+ * | GSM | | | | | |
+ * | +--->----->---+PCBEEP SPKR+--->----+-+ |
+ * | CHIP | | | \-+
+ * | +---<-----<---+MONO |
+ * | | | | Front Speaker
+ * +--------+ | | /-+
+ * | HPL+--->----+-+ |
+ * | | | | |
+ * | OUT3+--->----+-+ |
+ * | | \-+
+ * | |
+ * | | Front Micro
+ * | | +
+ * | MIC1+-----<--+o+
+ * | | +
+ * +-------------------+ ---
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <mach/audio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/ac97_codec.h>
+
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-ac97.h"
+#include "../codecs/wm9713.h"
+
+#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x)
+
+#define AC97_GPIO_PULL 0x58
+
+/* Use GPIO8 for rear speaker amplifier */
+static int rear_amp_power(struct snd_soc_codec *codec, int power)
+{
+ unsigned short reg;
+
+ if (power) {
+ reg = snd_soc_read(codec, AC97_GPIO_CFG);
+ snd_soc_write(codec, AC97_GPIO_CFG, reg | 0x0100);
+ reg = snd_soc_read(codec, AC97_GPIO_PULL);
+ snd_soc_write(codec, AC97_GPIO_PULL, reg | (1<<15));
+ } else {
+ reg = snd_soc_read(codec, AC97_GPIO_CFG);
+ snd_soc_write(codec, AC97_GPIO_CFG, reg & ~0x0100);
+ reg = snd_soc_read(codec, AC97_GPIO_PULL);
+ snd_soc_write(codec, AC97_GPIO_PULL, reg & ~(1<<15));
+ }
+
+ return 0;
+}
+
+static int rear_amp_event(struct snd_soc_dapm_widget *widget,
+ struct snd_kcontrol *kctl, int event)
+{
+ struct snd_soc_codec *codec = widget->codec;
+
+ return rear_amp_power(codec, SND_SOC_DAPM_EVENT_ON(event));
+}
+
+/* mioa701 machine dapm widgets */
+static const struct snd_soc_dapm_widget mioa701_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Front Speaker", NULL),
+ SND_SOC_DAPM_SPK("Rear Speaker", rear_amp_event),
+ SND_SOC_DAPM_MIC("Headset", NULL),
+ SND_SOC_DAPM_LINE("GSM Line Out", NULL),
+ SND_SOC_DAPM_LINE("GSM Line In", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Front Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* Call Mic */
+ {"Mic Bias", NULL, "Front Mic"},
+ {"MIC1", NULL, "Mic Bias"},
+
+ /* Headset Mic */
+ {"LINEL", NULL, "Headset Mic"},
+ {"LINER", NULL, "Headset Mic"},
+
+ /* GSM Module */
+ {"MONOIN", NULL, "GSM Line Out"},
+ {"PCBEEP", NULL, "GSM Line Out"},
+ {"GSM Line In", NULL, "MONO"},
+
+ /* headphone connected to HPL, HPR */
+ {"Headset", NULL, "HPL"},
+ {"Headset", NULL, "HPR"},
+
+ /* front speaker connected to HPL, OUT3 */
+ {"Front Speaker", NULL, "HPL"},
+ {"Front Speaker", NULL, "OUT3"},
+
+ /* rear speaker connected to SPKL, SPKR */
+ {"Rear Speaker", NULL, "SPKL"},
+ {"Rear Speaker", NULL, "SPKR"},
+};
+
+static int mioa701_wm9713_init(struct snd_soc_codec *codec)
+{
+ unsigned short reg;
+
+ /* Add mioa701 specific widgets */
+ snd_soc_dapm_new_controls(codec, ARRAY_AND_SIZE(mioa701_dapm_widgets));
+
+ /* Set up mioa701 specific audio path audio_mapnects */
+ snd_soc_dapm_add_routes(codec, ARRAY_AND_SIZE(audio_map));
+
+ /* Prepare GPIO8 for rear speaker amplifier */
+ reg = codec->read(codec, AC97_GPIO_CFG);
+ codec->write(codec, AC97_GPIO_CFG, reg | 0x0100);
+
+ /* Prepare MIC input */
+ reg = codec->read(codec, AC97_3D_CONTROL);
+ codec->write(codec, AC97_3D_CONTROL, reg | 0xc000);
+
+ snd_soc_dapm_enable_pin(codec, "Front Speaker");
+ snd_soc_dapm_enable_pin(codec, "Rear Speaker");
+ snd_soc_dapm_enable_pin(codec, "Front Mic");
+ snd_soc_dapm_enable_pin(codec, "GSM Line In");
+ snd_soc_dapm_enable_pin(codec, "GSM Line Out");
+ snd_soc_dapm_sync(codec);
+
+ return 0;
+}
+
+static struct snd_soc_ops mioa701_ops;
+
+static struct snd_soc_dai_link mioa701_dai[] = {
+ {
+ .name = "AC97",
+ .stream_name = "AC97 HiFi",
+ .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
+ .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
+ .init = mioa701_wm9713_init,
+ .ops = &mioa701_ops,
+ },
+ {
+ .name = "AC97 Aux",
+ .stream_name = "AC97 Aux",
+ .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
+ .codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX],
+ .ops = &mioa701_ops,
+ },
+};
+
+static struct snd_soc_card mioa701 = {
+ .name = "MioA701",
+ .platform = &pxa2xx_soc_platform,
+ .dai_link = mioa701_dai,
+ .num_links = ARRAY_SIZE(mioa701_dai),
+};
+
+static struct snd_soc_device mioa701_snd_devdata = {
+ .card = &mioa701,
+ .codec_dev = &soc_codec_dev_wm9713,
+};
+
+static struct platform_device *mioa701_snd_device;
+
+static int mioa701_wm9713_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ if (!machine_is_mioa701())
+ return -ENODEV;
+
+ dev_warn(&pdev->dev, "Be warned that incorrect mixers/muxes setup will"
+ "lead to overheating and possible destruction of your device."
+ "Do not use without a good knowledge of mio's board design!\n");
+
+ mioa701_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!mioa701_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(mioa701_snd_device, &mioa701_snd_devdata);
+ mioa701_snd_devdata.dev = &mioa701_snd_device->dev;
+
+ ret = platform_device_add(mioa701_snd_device);
+ if (!ret)
+ return 0;
+
+ platform_device_put(mioa701_snd_device);
+ return ret;
+}
+
+static int __devexit mioa701_wm9713_remove(struct platform_device *pdev)
+{
+ platform_device_unregister(mioa701_snd_device);
+ return 0;
+}
+
+static struct platform_driver mioa701_wm9713_driver = {
+ .probe = mioa701_wm9713_probe,
+ .remove = __devexit_p(mioa701_wm9713_remove),
+ .driver = {
+ .name = "mioa701-wm9713",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init mioa701_asoc_init(void)
+{
+ return platform_driver_register(&mioa701_wm9713_driver);
+}
+
+static void __exit mioa701_asoc_exit(void)
+{
+ platform_driver_unregister(&mioa701_wm9713_driver);
+}
+
+module_init(mioa701_asoc_init);
+module_exit(mioa701_asoc_exit);
+
+/* Module information */
+MODULE_AUTHOR("Robert Jarzmik (rjarzmik@free.fr)");
+MODULE_DESCRIPTION("ALSA SoC WM9713 MIO A701");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c
index 4a9cf3083af..48a73f64500 100644
--- a/sound/soc/pxa/palm27x.c
+++ b/sound/soc/pxa/palm27x.c
@@ -55,7 +55,7 @@ static void palm27x_ext_control(struct snd_soc_codec *codec)
static int palm27x_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->codec;
+ struct snd_soc_codec *codec = rtd->socdev->card->codec;
/* check the jack status at stream startup */
palm27x_ext_control(codec);
@@ -146,19 +146,16 @@ static const struct snd_kcontrol_new palm27x_controls[] = {
static int palm27x_ac97_init(struct snd_soc_codec *codec)
{
- int i, err;
+ int err;
snd_soc_dapm_nc_pin(codec, "OUT3");
snd_soc_dapm_nc_pin(codec, "MONOOUT");
/* add palm27x specific controls */
- for (i = 0; i < ARRAY_SIZE(palm27x_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&palm27x_controls[i],
- codec, NULL));
- if (err < 0)
- return err;
- }
+ err = snd_soc_add_controls(codec, palm27x_controls,
+ ARRAY_SIZE(palm27x_controls));
+ if (err < 0)
+ return err;
/* add palm27x specific widgets */
snd_soc_dapm_new_controls(codec, palm27x_dapm_widgets,
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index 6e9827189ff..ef7c6c8dc8f 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/timer.h>
+#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <sound/core.h>
@@ -77,7 +78,7 @@ static void poodle_ext_control(struct snd_soc_codec *codec)
static int poodle_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->codec;
+ struct snd_soc_codec *codec = rtd->socdev->card->codec;
/* check the jack status at stream startup */
poodle_ext_control(codec);
@@ -240,19 +241,17 @@ static const struct snd_kcontrol_new wm8731_poodle_controls[] = {
*/
static int poodle_wm8731_init(struct snd_soc_codec *codec)
{
- int i, err;
+ int err;
snd_soc_dapm_nc_pin(codec, "LLINEIN");
snd_soc_dapm_nc_pin(codec, "RLINEIN");
snd_soc_dapm_enable_pin(codec, "MICIN");
/* Add poodle specific controls */
- for (i = 0; i < ARRAY_SIZE(wm8731_poodle_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm8731_poodle_controls[i], codec, NULL));
- if (err < 0)
- return err;
- }
+ err = snd_soc_add_controls(codec, wm8731_poodle_controls,
+ ARRAY_SIZE(wm8731_poodle_controls));
+ if (err < 0)
+ return err;
/* Add poodle specific widgets */
snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets,
@@ -283,17 +282,42 @@ static struct snd_soc_card snd_soc_poodle = {
.num_links = 1,
};
-/* poodle audio private data */
-static struct wm8731_setup_data poodle_wm8731_setup = {
- .i2c_bus = 0,
- .i2c_address = 0x1b,
-};
+/*
+ * FIXME: This is a temporary bodge to avoid cross-tree merge issues.
+ * New drivers should register the wm8731 I2C device in the machine
+ * setup code (under arch/arm for ARM systems).
+ */
+static int wm8731_i2c_register(void)
+{
+ struct i2c_board_info info;
+ struct i2c_adapter *adapter;
+ struct i2c_client *client;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ info.addr = 0x1b;
+ strlcpy(info.type, "wm8731", I2C_NAME_SIZE);
+
+ adapter = i2c_get_adapter(0);
+ if (!adapter) {
+ printk(KERN_ERR "can't get i2c adapter 0\n");
+ return -ENODEV;
+ }
+
+ client = i2c_new_device(adapter, &info);
+ i2c_put_adapter(adapter);
+ if (!client) {
+ printk(KERN_ERR "can't add i2c device at 0x%x\n",
+ (unsigned int)info.addr);
+ return -ENODEV;
+ }
+
+ return 0;
+}
/* poodle audio subsystem */
static struct snd_soc_device poodle_snd_devdata = {
.card = &snd_soc_poodle,
.codec_dev = &soc_codec_dev_wm8731,
- .codec_data = &poodle_wm8731_setup,
};
static struct platform_device *poodle_snd_device;
@@ -305,6 +329,10 @@ static int __init poodle_init(void)
if (!machine_is_poodle())
return -ENODEV;
+ ret = wm8731_i2c_register();
+ if (ret != 0)
+ return ret;
+
locomo_gpio_set_dir(&poodle_locomo_device.dev,
POODLE_LOCOMO_GPIO_AMP_ON, 0);
/* should we mute HP at startup - burning power ?*/
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index 73cb6b4c2f2..b0bf40973d5 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -1,4 +1,3 @@
-#define DEBUG
/*
* pxa-ssp.c -- ALSA Soc Audio Layer
*
@@ -21,6 +20,8 @@
#include <linux/clk.h>
#include <linux/io.h>
+#include <asm/irq.h>
+
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/initval.h>
@@ -221,9 +222,9 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,
int ret = 0;
if (!cpu_dai->active) {
- ret = ssp_init(&priv->dev, cpu_dai->id + 1, SSP_NO_IRQ);
- if (ret < 0)
- return ret;
+ priv->dev.port = cpu_dai->id + 1;
+ priv->dev.irq = NO_IRQ;
+ clk_enable(priv->dev.ssp->clk);
ssp_disable(&priv->dev);
}
return ret;
@@ -238,7 +239,7 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,
if (!cpu_dai->active) {
ssp_disable(&priv->dev);
- ssp_exit(&priv->dev);
+ clk_disable(priv->dev.ssp->clk);
}
}
@@ -298,7 +299,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
int val;
u32 sscr0 = ssp_read_reg(ssp, SSCR0) &
- ~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ADC);
+ ~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
dev_dbg(&ssp->pdev->dev,
"pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %d\n",
@@ -326,7 +327,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
case PXA_SSP_CLK_AUDIO:
priv->sysclk = 0;
ssp_set_scr(&priv->dev, 1);
- sscr0 |= SSCR0_ADC;
+ sscr0 |= SSCR0_ACS;
break;
default:
return -ENODEV;
@@ -520,9 +521,20 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
u32 sscr1;
u32 sspsp;
+ /* check if we need to change anything at all */
+ if (priv->dai_fmt == fmt)
+ return 0;
+
+ /* we can only change the settings if the port is not in use */
+ if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) {
+ dev_err(&ssp->pdev->dev,
+ "can't change hardware dai format: stream is in use");
+ return -EINVAL;
+ }
+
/* reset port settings */
sscr0 = ssp_read_reg(ssp, SSCR0) &
- (SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ADC);
+ (SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7);
sspsp = 0;
@@ -545,18 +557,18 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
- sscr0 |= SSCR0_MOD | SSCR0_PSP;
+ sscr0 |= SSCR0_PSP;
sscr1 |= SSCR1_RWOT | SSCR1_TRAIL;
+ /* See hw_params() */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
- sspsp |= SSPSP_FSRT;
+ sspsp |= SSPSP_SFRMP;
break;
case SND_SOC_DAIFMT_NB_IF:
- sspsp |= SSPSP_SFRMP | SSPSP_FSRT;
break;
case SND_SOC_DAIFMT_IB_IF:
- sspsp |= SSPSP_SFRMP;
+ sspsp |= SSPSP_SCMODE(3);
break;
default:
return -EINVAL;
@@ -642,34 +654,65 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
sscr0 |= SSCR0_FPCKE;
#endif
sscr0 |= SSCR0_DataSize(16);
- if (params_channels(params) > 1)
- sscr0 |= SSCR0_EDSS;
break;
case SNDRV_PCM_FORMAT_S24_LE:
sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(8));
- /* we must be in network mode (2 slots) for 24 bit stereo */
break;
case SNDRV_PCM_FORMAT_S32_LE:
sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(16));
- /* we must be in network mode (2 slots) for 32 bit stereo */
break;
}
ssp_write_reg(ssp, SSCR0, sscr0);
switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
- /* Cleared when the DAI format is set */
- sspsp = ssp_read_reg(ssp, SSPSP) | SSPSP_SFRMWDTH(width);
+ sspsp = ssp_read_reg(ssp, SSPSP);
+
+ if (((sscr0 & SSCR0_SCR) == SSCR0_SerClkDiv(4)) &&
+ (width == 16)) {
+ /* This is a special case where the bitclk is 64fs
+ * and we're not dealing with 2*32 bits of audio
+ * samples.
+ *
+ * The SSP values used for that are all found out by
+ * trying and failing a lot; some of the registers
+ * needed for that mode are only available on PXA3xx.
+ */
+
+#ifdef CONFIG_PXA3xx
+ if (!cpu_is_pxa3xx())
+ return -EINVAL;
+
+ sspsp |= SSPSP_SFRMWDTH(width * 2);
+ sspsp |= SSPSP_SFRMDLY(width * 4);
+ sspsp |= SSPSP_EDMYSTOP(3);
+ sspsp |= SSPSP_DMYSTOP(3);
+ sspsp |= SSPSP_DMYSTRT(1);
+#else
+ return -EINVAL;
+#endif
+ } else {
+ /* The frame width is the width the LRCLK is
+ * asserted for; the delay is expressed in
+ * half cycle units. We need the extra cycle
+ * because the data starts clocking out one BCLK
+ * after LRCLK changes polarity.
+ */
+ sspsp |= SSPSP_SFRMWDTH(width + 1);
+ sspsp |= SSPSP_SFRMDLY((width + 1) * 2);
+ sspsp |= SSPSP_DMYSTRT(1);
+ }
+
ssp_write_reg(ssp, SSPSP, sspsp);
break;
default:
break;
}
- /* We always use a network mode so we always require TDM slots
+ /* When we use a network mode, we always require TDM slots
* - complain loudly and fail if they've not been set up yet.
*/
- if (!(ssp_read_reg(ssp, SSTSA) & 0xf)) {
+ if ((sscr0 & SSCR0_MOD) && !(ssp_read_reg(ssp, SSTSA) & 0xf)) {
dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n");
return -EINVAL;
}
@@ -751,7 +794,7 @@ static int pxa_ssp_probe(struct platform_device *pdev,
if (!priv)
return -ENOMEM;
- priv->dev.ssp = ssp_request(dai->id, "SoC audio");
+ priv->dev.ssp = ssp_request(dai->id + 1, "SoC audio");
if (priv->dev.ssp == NULL) {
ret = -ENODEV;
goto err_priv;
@@ -782,6 +825,19 @@ static void pxa_ssp_remove(struct platform_device *pdev,
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
+static struct snd_soc_dai_ops pxa_ssp_dai_ops = {
+ .startup = pxa_ssp_startup,
+ .shutdown = pxa_ssp_shutdown,
+ .trigger = pxa_ssp_trigger,
+ .hw_params = pxa_ssp_hw_params,
+ .set_sysclk = pxa_ssp_set_dai_sysclk,
+ .set_clkdiv = pxa_ssp_set_dai_clkdiv,
+ .set_pll = pxa_ssp_set_dai_pll,
+ .set_fmt = pxa_ssp_set_dai_fmt,
+ .set_tdm_slot = pxa_ssp_set_dai_tdm_slot,
+ .set_tristate = pxa_ssp_set_dai_tristate,
+};
+
struct snd_soc_dai pxa_ssp_dai[] = {
{
.name = "pxa2xx-ssp1",
@@ -802,18 +858,7 @@ struct snd_soc_dai pxa_ssp_dai[] = {
.rates = PXA_SSP_RATES,
.formats = PXA_SSP_FORMATS,
},
- .ops = {
- .startup = pxa_ssp_startup,
- .shutdown = pxa_ssp_shutdown,
- .trigger = pxa_ssp_trigger,
- .hw_params = pxa_ssp_hw_params,
- .set_sysclk = pxa_ssp_set_dai_sysclk,
- .set_clkdiv = pxa_ssp_set_dai_clkdiv,
- .set_pll = pxa_ssp_set_dai_pll,
- .set_fmt = pxa_ssp_set_dai_fmt,
- .set_tdm_slot = pxa_ssp_set_dai_tdm_slot,
- .set_tristate = pxa_ssp_set_dai_tristate,
- },
+ .ops = &pxa_ssp_dai_ops,
},
{ .name = "pxa2xx-ssp2",
.id = 1,
@@ -833,18 +878,7 @@ struct snd_soc_dai pxa_ssp_dai[] = {
.rates = PXA_SSP_RATES,
.formats = PXA_SSP_FORMATS,
},
- .ops = {
- .startup = pxa_ssp_startup,
- .shutdown = pxa_ssp_shutdown,
- .trigger = pxa_ssp_trigger,
- .hw_params = pxa_ssp_hw_params,
- .set_sysclk = pxa_ssp_set_dai_sysclk,
- .set_clkdiv = pxa_ssp_set_dai_clkdiv,
- .set_pll = pxa_ssp_set_dai_pll,
- .set_fmt = pxa_ssp_set_dai_fmt,
- .set_tdm_slot = pxa_ssp_set_dai_tdm_slot,
- .set_tristate = pxa_ssp_set_dai_tristate,
- },
+ .ops = &pxa_ssp_dai_ops,
},
{
.name = "pxa2xx-ssp3",
@@ -865,18 +899,7 @@ struct snd_soc_dai pxa_ssp_dai[] = {
.rates = PXA_SSP_RATES,
.formats = PXA_SSP_FORMATS,
},
- .ops = {
- .startup = pxa_ssp_startup,
- .shutdown = pxa_ssp_shutdown,
- .trigger = pxa_ssp_trigger,
- .hw_params = pxa_ssp_hw_params,
- .set_sysclk = pxa_ssp_set_dai_sysclk,
- .set_clkdiv = pxa_ssp_set_dai_clkdiv,
- .set_pll = pxa_ssp_set_dai_pll,
- .set_fmt = pxa_ssp_set_dai_fmt,
- .set_tdm_slot = pxa_ssp_set_dai_tdm_slot,
- .set_tristate = pxa_ssp_set_dai_tristate,
- },
+ .ops = &pxa_ssp_dai_ops,
},
{
.name = "pxa2xx-ssp4",
@@ -897,18 +920,7 @@ struct snd_soc_dai pxa_ssp_dai[] = {
.rates = PXA_SSP_RATES,
.formats = PXA_SSP_FORMATS,
},
- .ops = {
- .startup = pxa_ssp_startup,
- .shutdown = pxa_ssp_shutdown,
- .trigger = pxa_ssp_trigger,
- .hw_params = pxa_ssp_hw_params,
- .set_sysclk = pxa_ssp_set_dai_sysclk,
- .set_clkdiv = pxa_ssp_set_dai_clkdiv,
- .set_pll = pxa_ssp_set_dai_pll,
- .set_fmt = pxa_ssp_set_dai_fmt,
- .set_tdm_slot = pxa_ssp_set_dai_tdm_slot,
- .set_tristate = pxa_ssp_set_dai_tristate,
- },
+ .ops = &pxa_ssp_dai_ops,
},
};
EXPORT_SYMBOL_GPL(pxa_ssp_dai);
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index 812c2b4d3e0..01c21c6cdbb 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -106,13 +106,13 @@ static int pxa2xx_ac97_resume(struct snd_soc_dai *dai)
static int pxa2xx_ac97_probe(struct platform_device *pdev,
struct snd_soc_dai *dai)
{
- return pxa2xx_ac97_hw_probe(pdev);
+ return pxa2xx_ac97_hw_probe(to_platform_device(dai->dev));
}
static void pxa2xx_ac97_remove(struct platform_device *pdev,
struct snd_soc_dai *dai)
{
- pxa2xx_ac97_hw_remove(pdev);
+ pxa2xx_ac97_hw_remove(to_platform_device(dai->dev));
}
static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
@@ -164,6 +164,18 @@ static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream,
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000)
+static struct snd_soc_dai_ops pxa_ac97_hifi_dai_ops = {
+ .hw_params = pxa2xx_ac97_hw_params,
+};
+
+static struct snd_soc_dai_ops pxa_ac97_aux_dai_ops = {
+ .hw_params = pxa2xx_ac97_hw_aux_params,
+};
+
+static struct snd_soc_dai_ops pxa_ac97_mic_dai_ops = {
+ .hw_params = pxa2xx_ac97_hw_mic_params,
+};
+
/*
* There is only 1 physical AC97 interface for pxa2xx, but it
* has extra fifo's that can be used for aux DACs and ADCs.
@@ -189,8 +201,7 @@ struct snd_soc_dai pxa_ac97_dai[] = {
.channels_max = 2,
.rates = PXA2XX_AC97_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = {
- .hw_params = pxa2xx_ac97_hw_params,},
+ .ops = &pxa_ac97_hifi_dai_ops,
},
{
.name = "pxa2xx-ac97-aux",
@@ -208,8 +219,7 @@ struct snd_soc_dai pxa_ac97_dai[] = {
.channels_max = 1,
.rates = PXA2XX_AC97_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = {
- .hw_params = pxa2xx_ac97_hw_aux_params,},
+ .ops = &pxa_ac97_aux_dai_ops,
},
{
.name = "pxa2xx-ac97-mic",
@@ -221,23 +231,52 @@ struct snd_soc_dai pxa_ac97_dai[] = {
.channels_max = 1,
.rates = PXA2XX_AC97_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = {
- .hw_params = pxa2xx_ac97_hw_mic_params,},
+ .ops = &pxa_ac97_mic_dai_ops,
},
};
EXPORT_SYMBOL_GPL(pxa_ac97_dai);
EXPORT_SYMBOL_GPL(soc_ac97_ops);
-static int __init pxa_ac97_init(void)
+static int __devinit pxa2xx_ac97_dev_probe(struct platform_device *pdev)
{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pxa_ac97_dai); i++)
+ pxa_ac97_dai[i].dev = &pdev->dev;
+
+ /* Punt most of the init to the SoC probe; we may need the machine
+ * driver to do interesting things with the clocking to get us up
+ * and running.
+ */
return snd_soc_register_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai));
}
+
+static int __devexit pxa2xx_ac97_dev_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai));
+
+ return 0;
+}
+
+static struct platform_driver pxa2xx_ac97_driver = {
+ .probe = pxa2xx_ac97_dev_probe,
+ .remove = __devexit_p(pxa2xx_ac97_dev_remove),
+ .driver = {
+ .name = "pxa2xx-ac97",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pxa_ac97_init(void)
+{
+ return platform_driver_register(&pxa2xx_ac97_driver);
+}
module_init(pxa_ac97_init);
static void __exit pxa_ac97_exit(void)
{
- snd_soc_unregister_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai));
+ platform_driver_unregister(&pxa2xx_ac97_driver);
}
module_exit(pxa_ac97_exit);
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index 517991fb109..e6c24408c5f 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -25,20 +25,11 @@
#include <mach/hardware.h>
#include <mach/pxa-regs.h>
-#include <mach/pxa2xx-gpio.h>
#include <mach/audio.h>
#include "pxa2xx-pcm.h"
#include "pxa2xx-i2s.h"
-struct pxa2xx_gpio {
- u32 sys;
- u32 rx;
- u32 tx;
- u32 clk;
- u32 frm;
-};
-
/*
* I2S Controller Register and Bit Definitions
*/
@@ -106,21 +97,6 @@ static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_in = {
DCMD_BURST32 | DCMD_WIDTH4,
};
-static struct pxa2xx_gpio gpio_bus[] = {
- { /* I2S SoC Slave */
- .rx = GPIO29_SDATA_IN_I2S_MD,
- .tx = GPIO30_SDATA_OUT_I2S_MD,
- .clk = GPIO28_BITCLK_IN_I2S_MD,
- .frm = GPIO31_SYNC_I2S_MD,
- },
- { /* I2S SoC Master */
- .rx = GPIO29_SDATA_IN_I2S_MD,
- .tx = GPIO30_SDATA_OUT_I2S_MD,
- .clk = GPIO28_BITCLK_OUT_I2S_MD,
- .frm = GPIO31_SYNC_I2S_MD,
- },
-};
-
static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -181,9 +157,6 @@ static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
if (clk_id != PXA2XX_I2S_SYSCLK)
return -ENODEV;
- if (pxa_i2s.master && dir == SND_SOC_CLOCK_OUT)
- pxa_gpio_mode(gpio_bus[pxa_i2s.master].sys);
-
return 0;
}
@@ -194,10 +167,6 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
- pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx);
- pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx);
- pxa_gpio_mode(gpio_bus[pxa_i2s.master].frm);
- pxa_gpio_mode(gpio_bus[pxa_i2s.master].clk);
BUG_ON(IS_ERR(clk_i2s));
clk_enable(clk_i2s);
pxa_i2s_wait();
@@ -335,6 +304,15 @@ static int pxa2xx_i2s_resume(struct snd_soc_dai *dai)
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
+static struct snd_soc_dai_ops pxa_i2s_dai_ops = {
+ .startup = pxa2xx_i2s_startup,
+ .shutdown = pxa2xx_i2s_shutdown,
+ .trigger = pxa2xx_i2s_trigger,
+ .hw_params = pxa2xx_i2s_hw_params,
+ .set_fmt = pxa2xx_i2s_set_dai_fmt,
+ .set_sysclk = pxa2xx_i2s_set_dai_sysclk,
+};
+
struct snd_soc_dai pxa_i2s_dai = {
.name = "pxa2xx-i2s",
.id = 0,
@@ -350,14 +328,7 @@ struct snd_soc_dai pxa_i2s_dai = {
.channels_max = 2,
.rates = PXA2XX_I2S_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = {
- .startup = pxa2xx_i2s_startup,
- .shutdown = pxa2xx_i2s_shutdown,
- .trigger = pxa2xx_i2s_trigger,
- .hw_params = pxa2xx_i2s_hw_params,
- .set_fmt = pxa2xx_i2s_set_dai_fmt,
- .set_sysclk = pxa2xx_i2s_set_dai_sysclk,
- },
+ .ops = &pxa_i2s_dai_ops,
};
EXPORT_SYMBOL_GPL(pxa_i2s_dai);
@@ -398,11 +369,6 @@ static struct platform_driver pxa2xx_i2s_driver = {
static int __init pxa2xx_i2s_init(void)
{
- if (cpu_is_pxa27x())
- gpio_bus[1].sys = GPIO113_I2S_SYSCLK_MD;
- else
- gpio_bus[1].sys = GPIO32_SYSCLK_I2S_MD;
-
clk_i2s = ERR_PTR(-ENOENT);
return platform_driver_register(&pxa2xx_i2s_driver);
}
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index a3b9e6bdf97..6ca9f53080c 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -109,7 +109,7 @@ static void spitz_ext_control(struct snd_soc_codec *codec)
static int spitz_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->codec;
+ struct snd_soc_codec *codec = rtd->socdev->card->codec;
/* check the jack status at stream startup */
spitz_ext_control(codec);
@@ -278,7 +278,7 @@ static const struct snd_kcontrol_new wm8750_spitz_controls[] = {
*/
static int spitz_wm8750_init(struct snd_soc_codec *codec)
{
- int i, err;
+ int err;
/* NC codec pins */
snd_soc_dapm_nc_pin(codec, "RINPUT1");
@@ -290,12 +290,10 @@ static int spitz_wm8750_init(struct snd_soc_codec *codec)
snd_soc_dapm_nc_pin(codec, "MONO1");
/* Add spitz specific controls */
- for (i = 0; i < ARRAY_SIZE(wm8750_spitz_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm8750_spitz_controls[i], codec, NULL));
- if (err < 0)
- return err;
- }
+ err = snd_soc_add_controls(codec, wm8750_spitz_controls,
+ ARRAY_SIZE(wm8750_spitz_controls));
+ if (err < 0)
+ return err;
/* Add spitz specific widgets */
snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets,
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
index c77194f74c9..fc781374b1b 100644
--- a/sound/soc/pxa/tosa.c
+++ b/sound/soc/pxa/tosa.c
@@ -82,7 +82,7 @@ static void tosa_ext_control(struct snd_soc_codec *codec)
static int tosa_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->socdev->codec;
+ struct snd_soc_codec *codec = rtd->socdev->card->codec;
/* check the jack status at stream startup */
tosa_ext_control(codec);
@@ -188,18 +188,16 @@ static const struct snd_kcontrol_new tosa_controls[] = {
static int tosa_ac97_init(struct snd_soc_codec *codec)
{
- int i, err;
+ int err;
snd_soc_dapm_nc_pin(codec, "OUT3");
snd_soc_dapm_nc_pin(codec, "MONOOUT");
/* add tosa specific controls */
- for (i = 0; i < ARRAY_SIZE(tosa_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&tosa_controls[i],codec, NULL));
- if (err < 0)
- return err;
- }
+ err = snd_soc_add_controls(codec, tosa_controls,
+ ARRAY_SIZE(tosa_controls));
+ if (err < 0)
+ return err;
/* add tosa specific widgets */
snd_soc_dapm_new_controls(codec, tosa_dapm_widgets,
diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c
index f8e9ecd589d..9a386b4c4ed 100644
--- a/sound/soc/pxa/zylonite.c
+++ b/sound/soc/pxa/zylonite.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
+#include <linux/clk.h>
#include <linux/i2c.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -26,6 +27,17 @@
#include "pxa2xx-ac97.h"
#include "pxa-ssp.h"
+/*
+ * There is a physical switch SW15 on the board which changes the MCLK
+ * for the WM9713 between the standard AC97 master clock and the
+ * output of the CLK_POUT signal from the PXA.
+ */
+static int clk_pout;
+module_param(clk_pout, int, 0);
+MODULE_PARM_DESC(clk_pout, "Use CLK_POUT as WM9713 MCLK (SW15 on board).");
+
+static struct clk *pout;
+
static struct snd_soc_card zylonite;
static const struct snd_soc_dapm_widget zylonite_dapm_widgets[] = {
@@ -61,10 +73,8 @@ static const struct snd_soc_dapm_route audio_map[] = {
static int zylonite_wm9713_init(struct snd_soc_codec *codec)
{
- /* Currently we only support use of the AC97 clock here. If
- * CLK_POUT is selected by SW15 then the clock API will need
- * to be used to request and enable it here.
- */
+ if (clk_pout)
+ snd_soc_dai_set_pll(&codec->dai[0], 0, clk_get_rate(pout), 0);
snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets,
ARRAY_SIZE(zylonite_dapm_widgets));
@@ -86,40 +96,35 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
unsigned int pll_out = 0;
- unsigned int acds = 0;
unsigned int wm9713_div = 0;
int ret = 0;
+ int rate = params_rate(params);
+ int width = snd_pcm_format_physical_width(params_format(params));
- switch (params_rate(params)) {
+ /* Only support ratios that we can generate neatly from the AC97
+ * based master clock - in particular, this excludes 44.1kHz.
+ * In most applications the voice DAC will be used for telephony
+ * data so multiples of 8kHz will be the common case.
+ */
+ switch (rate) {
case 8000:
wm9713_div = 12;
- pll_out = 2048000;
break;
case 16000:
wm9713_div = 6;
- pll_out = 4096000;
break;
case 48000:
- default:
wm9713_div = 2;
- pll_out = 12288000;
- acds = 1;
break;
+ default:
+ /* Don't support OSS emulation */
+ return -EINVAL;
}
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
- if (ret < 0)
- return ret;
+ /* Add 1 to the width for the leading clock cycle */
+ pll_out = rate * (width + 1) * 8;
- ret = snd_soc_dai_set_tdm_slot(cpu_dai,
- params_channels(params),
- params_channels(params));
+ ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1);
if (ret < 0)
return ret;
@@ -127,19 +132,22 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
- ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_AUDIO_DIV_ACDS, acds);
+ if (clk_pout)
+ ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_PLL_DIV,
+ WM9713_PCMDIV(wm9713_div));
+ else
+ ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV,
+ WM9713_PCMDIV(wm9713_div));
if (ret < 0)
return ret;
- ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1);
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
if (ret < 0)
return ret;
- /* Note that if the PLL is in use the WM9713_PCMCLK_PLL_DIV needs
- * to be set instead.
- */
- ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV,
- WM9713_PCMDIV(wm9713_div));
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
if (ret < 0)
return ret;
@@ -173,8 +181,72 @@ static struct snd_soc_dai_link zylonite_dai[] = {
},
};
+static int zylonite_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ if (clk_pout) {
+ pout = clk_get(NULL, "CLK_POUT");
+ if (IS_ERR(pout)) {
+ dev_err(&pdev->dev, "Unable to obtain CLK_POUT: %ld\n",
+ PTR_ERR(pout));
+ return PTR_ERR(pout);
+ }
+
+ ret = clk_enable(pout);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Unable to enable CLK_POUT: %d\n",
+ ret);
+ clk_put(pout);
+ return ret;
+ }
+
+ dev_dbg(&pdev->dev, "MCLK enabled at %luHz\n",
+ clk_get_rate(pout));
+ }
+
+ return 0;
+}
+
+static int zylonite_remove(struct platform_device *pdev)
+{
+ if (clk_pout) {
+ clk_disable(pout);
+ clk_put(pout);
+ }
+
+ return 0;
+}
+
+static int zylonite_suspend_post(struct platform_device *pdev,
+ pm_message_t state)
+{
+ if (clk_pout)
+ clk_disable(pout);
+
+ return 0;
+}
+
+static int zylonite_resume_pre(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ if (clk_pout) {
+ ret = clk_enable(pout);
+ if (ret != 0)
+ dev_err(&pdev->dev, "Unable to enable CLK_POUT: %d\n",
+ ret);
+ }
+
+ return ret;
+}
+
static struct snd_soc_card zylonite = {
.name = "Zylonite",
+ .probe = &zylonite_probe,
+ .remove = &zylonite_remove,
+ .suspend_post = &zylonite_suspend_post,
+ .resume_pre = &zylonite_resume_pre,
.platform = &pxa2xx_soc_platform,
.dai_link = zylonite_dai,
.num_links = ARRAY_SIZE(zylonite_dai),
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index fcd03acf10f..2f3a21eee05 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -1,19 +1,31 @@
config SND_S3C24XX_SOC
- tristate "SoC Audio for the Samsung S3C24XX chips"
- depends on ARCH_S3C2410
+ tristate "SoC Audio for the Samsung S3CXXXX chips"
+ depends on ARCH_S3C2410 || ARCH_S3C64XX
help
Say Y or M if you want to add support for codecs attached to
- the S3C24XX AC97, I2S or SSP interface. You will also need
- to select the audio interfaces to support below.
+ the S3C24XX and S3C64XX AC97, I2S or SSP interface. You will
+ also need to select the audio interfaces to support below.
config SND_S3C24XX_SOC_I2S
tristate
+ select S3C2410_DMA
+
+config SND_S3C_I2SV2_SOC
+ tristate
config SND_S3C2412_SOC_I2S
tristate
+ select SND_S3C_I2SV2_SOC
+ select S3C2410_DMA
+
+config SND_S3C64XX_SOC_I2S
+ tristate
+ select SND_S3C_I2SV2_SOC
+ select S3C64XX_DMA
config SND_S3C2443_SOC_AC97
tristate
+ select S3C2410_DMA
select AC97_BUS
select SND_SOC_AC97_BUS
@@ -26,6 +38,14 @@ config SND_S3C24XX_SOC_NEO1973_WM8753
Say Y if you want to add support for SoC audio on smdk2440
with the WM8753.
+config SND_S3C24XX_SOC_JIVE_WM8750
+ tristate "SoC I2S Audio support for Jive"
+ depends on SND_S3C24XX_SOC && MACH_JIVE
+ select SND_SOC_WM8750
+ select SND_S3C2412_SOC_I2S
+ help
+ Sat Y if you want to add support for SoC audio on the Jive.
+
config SND_S3C24XX_SOC_SMDK2443_WM9710
tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
depends on SND_S3C24XX_SOC && MACH_SMDK2443
@@ -48,4 +68,5 @@ config SND_S3C24XX_SOC_S3C24XX_UDA134X
tristate "SoC I2S Audio support UDA134X wired to a S3C24XX"
depends on SND_S3C24XX_SOC
select SND_S3C24XX_SOC_I2S
+ select SND_SOC_L3
select SND_SOC_UDA134X
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 96b3f3f617d..07a93a2ebe5 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -2,19 +2,25 @@
snd-soc-s3c24xx-objs := s3c24xx-pcm.o
snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
+snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o
snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o
+snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o
obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
+obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o
+obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
# S3C24XX Machine Support
+snd-soc-jive-wm8750-objs := jive_wm8750.o
snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o
snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o
snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o
+obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o
obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o
diff --git a/sound/soc/s3c24xx/jive_wm8750.c b/sound/soc/s3c24xx/jive_wm8750.c
new file mode 100644
index 00000000000..32063790d95
--- /dev/null
+++ b/sound/soc/s3c24xx/jive_wm8750.c
@@ -0,0 +1,201 @@
+/* sound/soc/s3c24xx/jive_wm8750.c
+ *
+ * Copyright 2007,2008 Simtec Electronics
+ *
+ * Based on sound/soc/pxa/spitz.c
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+
+#include "s3c24xx-pcm.h"
+#include "s3c2412-i2s.h"
+
+#include "../codecs/wm8750.h"
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ { "Headphone Jack", NULL, "LOUT1" },
+ { "Headphone Jack", NULL, "ROUT1" },
+ { "Internal Speaker", NULL, "LOUT2" },
+ { "Internal Speaker", NULL, "ROUT2" },
+ { "LINPUT1", NULL, "Line Input" },
+ { "RINPUT1", NULL, "Line Input" },
+};
+
+static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_SPK("Internal Speaker", NULL),
+ SND_SOC_DAPM_LINE("Line In", NULL),
+};
+
+static int jive_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct s3c_i2sv2_rate_calc div;
+ unsigned int clk = 0;
+ int ret = 0;
+
+ switch (params_rate(params)) {
+ case 8000:
+ case 16000:
+ case 48000:
+ case 96000:
+ clk = 12288000;
+ break;
+ case 11025:
+ case 22050:
+ case 44100:
+ clk = 11289600;
+ break;
+ }
+
+ s3c_i2sv2_calc_rate(&div, NULL, params_rate(params),
+ s3c2412_get_iisclk());
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock for DAC and ADC */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_RCLK, div.fs_div);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_PRESCALER,
+ div.clk_div - 1);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops jive_ops = {
+ .hw_params = jive_hw_params,
+};
+
+static int jive_wm8750_init(struct snd_soc_codec *codec)
+{
+ int err;
+
+ /* These endpoints are not being used. */
+ snd_soc_dapm_nc_pin(codec, "LINPUT2");
+ snd_soc_dapm_nc_pin(codec, "RINPUT2");
+ snd_soc_dapm_nc_pin(codec, "LINPUT3");
+ snd_soc_dapm_nc_pin(codec, "RINPUT3");
+ snd_soc_dapm_nc_pin(codec, "OUT3");
+ snd_soc_dapm_nc_pin(codec, "MONO");
+
+ /* Add jive specific widgets */
+ err = snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets,
+ ARRAY_SIZE(wm8750_dapm_widgets));
+ if (err) {
+ printk(KERN_ERR "%s: failed to add widgets (%d)\n",
+ __func__, err);
+ return err;
+ }
+
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+ snd_soc_dapm_sync(codec);
+
+ return 0;
+}
+
+static struct snd_soc_dai_link jive_dai = {
+ .name = "wm8750",
+ .stream_name = "WM8750",
+ .cpu_dai = &s3c2412_i2s_dai,
+ .codec_dai = &wm8750_dai,
+ .init = jive_wm8750_init,
+ .ops = &jive_ops,
+};
+
+/* jive audio machine driver */
+static struct snd_soc_machine snd_soc_machine_jive = {
+ .name = "Jive",
+ .dai_link = &jive_dai,
+ .num_links = 1,
+};
+
+/* jive audio private data */
+static struct wm8750_setup_data jive_wm8750_setup = {
+};
+
+/* jive audio subsystem */
+static struct snd_soc_device jive_snd_devdata = {
+ .machine = &snd_soc_machine_jive,
+ .platform = &s3c24xx_soc_platform,
+ .codec_dev = &soc_codec_dev_wm8750_spi,
+ .codec_data = &jive_wm8750_setup,
+};
+
+static struct platform_device *jive_snd_device;
+
+static int __init jive_init(void)
+{
+ int ret;
+
+ if (!machine_is_jive())
+ return 0;
+
+ printk("JIVE WM8750 Audio support\n");
+
+ jive_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!jive_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(jive_snd_device, &jive_snd_devdata);
+ jive_snd_devdata.dev = &jive_snd_device->dev;
+ ret = platform_device_add(jive_snd_device);
+
+ if (ret)
+ platform_device_put(jive_snd_device);
+
+ return ret;
+}
+
+static void __exit jive_exit(void)
+{
+ platform_device_unregister(jive_snd_device);
+}
+
+module_init(jive_init);
+module_exit(jive_exit);
+
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("ALSA SoC Jive Audio support");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
index 45bb12e8ea4..289fadf60b1 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -29,25 +29,17 @@
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
-#include <mach/audio.h>
+#include <plat/audio.h>
#include <linux/io.h>
#include <mach/spi-gpio.h>
-#include <asm/plat-s3c24xx/regs-iis.h>
+#include <plat/regs-iis.h>
#include "../codecs/wm8753.h"
#include "lm4857.h"
#include "s3c24xx-pcm.h"
#include "s3c24xx-i2s.h"
-/* Debugging stuff */
-#define S3C24XX_SOC_NEO1973_WM8753_DEBUG 0
-#if S3C24XX_SOC_NEO1973_WM8753_DEBUG
-#define DBG(x...) printk(KERN_DEBUG "s3c24xx-soc-neo1973-wm8753: " x)
-#else
-#define DBG(x...)
-#endif
-
/* define the scenarios */
#define NEO_AUDIO_OFF 0
#define NEO_GSM_CALL_AUDIO_HANDSET 1
@@ -72,7 +64,7 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
int ret = 0;
unsigned long iis_clkrate;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
iis_clkrate = s3c24xx_i2s_get_clockrate();
@@ -158,7 +150,7 @@ static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
/* disable the PLL */
return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0);
@@ -181,7 +173,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
int ret = 0;
unsigned long iis_clkrate;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
iis_clkrate = s3c24xx_i2s_get_clockrate();
@@ -224,7 +216,7 @@ static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
/* disable the PLL */
return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0);
@@ -246,7 +238,7 @@ static int neo1973_get_scenario(struct snd_kcontrol *kcontrol,
static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario)
{
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
switch (neo1973_scenario) {
case NEO_AUDIO_OFF:
@@ -330,7 +322,7 @@ static int neo1973_set_scenario(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
if (neo1973_scenario == ucontrol->value.integer.value[0])
return 0;
@@ -344,7 +336,7 @@ static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0};
static void lm4857_write_regs(void)
{
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
if (i2c_master_send(i2c, lm4857_regs, 4) != 4)
printk(KERN_ERR "lm4857: i2c write failed\n");
@@ -357,7 +349,7 @@ static int lm4857_get_reg(struct snd_kcontrol *kcontrol,
int shift = (kcontrol->private_value >> 8) & 0x0F;
int mask = (kcontrol->private_value >> 16) & 0xFF;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask;
return 0;
@@ -385,7 +377,7 @@ static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
{
u8 value = lm4857_regs[LM4857_CTRL] & 0x0F;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
if (value)
value -= 5;
@@ -399,7 +391,7 @@ static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
{
u8 value = ucontrol->value.integer.value[0];
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
if (value)
value += 5;
@@ -506,9 +498,9 @@ static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
*/
static int neo1973_wm8753_init(struct snd_soc_codec *codec)
{
- int i, err;
+ int err;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
/* set up NC codec pins */
snd_soc_dapm_nc_pin(codec, "LOUT2");
@@ -526,13 +518,10 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec)
set_scenario_endpoints(codec, NEO_AUDIO_OFF);
/* add neo1973 specific controls */
- for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) {
- err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm8753_neo1973_controls[i],
- codec, NULL));
- if (err < 0)
- return err;
- }
+ err = snd_soc_add_controls(codec, wm8753_neo1973_controls,
+ ARRAY_SIZE(8753_neo1973_controls));
+ if (err < 0)
+ return err;
/* set up neo1973 specific audio routes */
err = snd_soc_dapm_add_routes(codec, dapm_routes,
@@ -585,21 +574,15 @@ static struct snd_soc_card neo1973 = {
.num_links = ARRAY_SIZE(neo1973_dai),
};
-static struct wm8753_setup_data neo1973_wm8753_setup = {
- .i2c_bus = 0,
- .i2c_address = 0x1a,
-};
-
static struct snd_soc_device neo1973_snd_devdata = {
.card = &neo1973,
.codec_dev = &soc_codec_dev_wm8753,
- .codec_data = &neo1973_wm8753_setup,
};
static int lm4857_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
i2c = client;
@@ -609,7 +592,7 @@ static int lm4857_i2c_probe(struct i2c_client *client,
static int lm4857_i2c_remove(struct i2c_client *client)
{
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
i2c = NULL;
@@ -620,7 +603,7 @@ static u8 lm4857_state;
static int lm4857_suspend(struct i2c_client *dev, pm_message_t state)
{
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
dev_dbg(&dev->dev, "lm4857_suspend\n");
lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf;
@@ -633,7 +616,7 @@ static int lm4857_suspend(struct i2c_client *dev, pm_message_t state)
static int lm4857_resume(struct i2c_client *dev)
{
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
if (lm4857_state) {
lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f);
@@ -644,7 +627,7 @@ static int lm4857_resume(struct i2c_client *dev)
static void lm4857_shutdown(struct i2c_client *dev)
{
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
dev_dbg(&dev->dev, "lm4857_shutdown\n");
lm4857_regs[LM4857_CTRL] &= 0xf0;
@@ -675,7 +658,7 @@ static int __init neo1973_init(void)
{
int ret;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
if (!machine_is_neo1973_gta01()) {
printk(KERN_INFO
@@ -706,7 +689,7 @@ static int __init neo1973_init(void)
static void __exit neo1973_exit(void)
{
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
i2c_del_driver(&lm4857_i2c_driver);
platform_device_unregister(neo1973_snd_device);
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c
new file mode 100644
index 00000000000..295a4c91026
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.c
@@ -0,0 +1,638 @@
+/* sound/soc/s3c24xx/s3c-i2c-v2.c
+ *
+ * ALSA Soc Audio Layer - I2S core for newer Samsung SoCs.
+ *
+ * Copyright (c) 2006 Wolfson Microelectronics PLC.
+ * Graeme Gregory graeme.gregory@wolfsonmicro.com
+ * linux@wolfsonmicro.com
+ *
+ * Copyright (c) 2008, 2007, 2004-2005 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <plat/regs-s3c2412-iis.h>
+
+#include <plat/audio.h>
+#include <mach/dma.h>
+
+#include "s3c-i2s-v2.h"
+
+#define S3C2412_I2S_DEBUG_CON 0
+
+static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
+{
+ return cpu_dai->private_data;
+}
+
+#define bit_set(v, b) (((v) & (b)) ? 1 : 0)
+
+#if S3C2412_I2S_DEBUG_CON
+static void dbg_showcon(const char *fn, u32 con)
+{
+ printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn,
+ bit_set(con, S3C2412_IISCON_LRINDEX),
+ bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY),
+ bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY),
+ bit_set(con, S3C2412_IISCON_TXFIFO_FULL),
+ bit_set(con, S3C2412_IISCON_RXFIFO_FULL));
+
+ printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n",
+ fn,
+ bit_set(con, S3C2412_IISCON_TXDMA_PAUSE),
+ bit_set(con, S3C2412_IISCON_RXDMA_PAUSE),
+ bit_set(con, S3C2412_IISCON_TXCH_PAUSE),
+ bit_set(con, S3C2412_IISCON_RXCH_PAUSE));
+ printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn,
+ bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE),
+ bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE),
+ bit_set(con, S3C2412_IISCON_IIS_ACTIVE));
+}
+#else
+static inline void dbg_showcon(const char *fn, u32 con)
+{
+}
+#endif
+
+
+/* Turn on or off the transmission path. */
+void s3c2412_snd_txctrl(struct s3c_i2sv2_info *i2s, int on)
+{
+ void __iomem *regs = i2s->regs;
+ u32 fic, con, mod;
+
+ pr_debug("%s(%d)\n", __func__, on);
+
+ fic = readl(regs + S3C2412_IISFIC);
+ con = readl(regs + S3C2412_IISCON);
+ mod = readl(regs + S3C2412_IISMOD);
+
+ pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
+
+ if (on) {
+ con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
+ con &= ~S3C2412_IISCON_TXDMA_PAUSE;
+ con &= ~S3C2412_IISCON_TXCH_PAUSE;
+
+ switch (mod & S3C2412_IISMOD_MODE_MASK) {
+ case S3C2412_IISMOD_MODE_TXONLY:
+ case S3C2412_IISMOD_MODE_TXRX:
+ /* do nothing, we are in the right mode */
+ break;
+
+ case S3C2412_IISMOD_MODE_RXONLY:
+ mod &= ~S3C2412_IISMOD_MODE_MASK;
+ mod |= S3C2412_IISMOD_MODE_TXRX;
+ break;
+
+ default:
+ dev_err(i2s->dev, "TXEN: Invalid MODE in IISMOD\n");
+ }
+
+ writel(con, regs + S3C2412_IISCON);
+ writel(mod, regs + S3C2412_IISMOD);
+ } else {
+ /* Note, we do not have any indication that the FIFO problems
+ * tha the S3C2410/2440 had apply here, so we should be able
+ * to disable the DMA and TX without resetting the FIFOS.
+ */
+
+ con |= S3C2412_IISCON_TXDMA_PAUSE;
+ con |= S3C2412_IISCON_TXCH_PAUSE;
+ con &= ~S3C2412_IISCON_TXDMA_ACTIVE;
+
+ switch (mod & S3C2412_IISMOD_MODE_MASK) {
+ case S3C2412_IISMOD_MODE_TXRX:
+ mod &= ~S3C2412_IISMOD_MODE_MASK;
+ mod |= S3C2412_IISMOD_MODE_RXONLY;
+ break;
+
+ case S3C2412_IISMOD_MODE_TXONLY:
+ mod &= ~S3C2412_IISMOD_MODE_MASK;
+ con &= ~S3C2412_IISCON_IIS_ACTIVE;
+ break;
+
+ default:
+ dev_err(i2s->dev, "TXDIS: Invalid MODE in IISMOD\n");
+ }
+
+ writel(mod, regs + S3C2412_IISMOD);
+ writel(con, regs + S3C2412_IISCON);
+ }
+
+ fic = readl(regs + S3C2412_IISFIC);
+ dbg_showcon(__func__, con);
+ pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
+}
+EXPORT_SYMBOL_GPL(s3c2412_snd_txctrl);
+
+void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on)
+{
+ void __iomem *regs = i2s->regs;
+ u32 fic, con, mod;
+
+ pr_debug("%s(%d)\n", __func__, on);
+
+ fic = readl(regs + S3C2412_IISFIC);
+ con = readl(regs + S3C2412_IISCON);
+ mod = readl(regs + S3C2412_IISMOD);
+
+ pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
+
+ if (on) {
+ con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
+ con &= ~S3C2412_IISCON_RXDMA_PAUSE;
+ con &= ~S3C2412_IISCON_RXCH_PAUSE;
+
+ switch (mod & S3C2412_IISMOD_MODE_MASK) {
+ case S3C2412_IISMOD_MODE_TXRX:
+ case S3C2412_IISMOD_MODE_RXONLY:
+ /* do nothing, we are in the right mode */
+ break;
+
+ case S3C2412_IISMOD_MODE_TXONLY:
+ mod &= ~S3C2412_IISMOD_MODE_MASK;
+ mod |= S3C2412_IISMOD_MODE_TXRX;
+ break;
+
+ default:
+ dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
+ }
+
+ writel(mod, regs + S3C2412_IISMOD);
+ writel(con, regs + S3C2412_IISCON);
+ } else {
+ /* See txctrl notes on FIFOs. */
+
+ con &= ~S3C2412_IISCON_RXDMA_ACTIVE;
+ con |= S3C2412_IISCON_RXDMA_PAUSE;
+ con |= S3C2412_IISCON_RXCH_PAUSE;
+
+ switch (mod & S3C2412_IISMOD_MODE_MASK) {
+ case S3C2412_IISMOD_MODE_RXONLY:
+ con &= ~S3C2412_IISCON_IIS_ACTIVE;
+ mod &= ~S3C2412_IISMOD_MODE_MASK;
+ break;
+
+ case S3C2412_IISMOD_MODE_TXRX:
+ mod &= ~S3C2412_IISMOD_MODE_MASK;
+ mod |= S3C2412_IISMOD_MODE_TXONLY;
+ break;
+
+ default:
+ dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
+ }
+
+ writel(con, regs + S3C2412_IISCON);
+ writel(mod, regs + S3C2412_IISMOD);
+ }
+
+ fic = readl(regs + S3C2412_IISFIC);
+ pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
+}
+EXPORT_SYMBOL_GPL(s3c2412_snd_rxctrl);
+
+/*
+ * Wait for the LR signal to allow synchronisation to the L/R clock
+ * from the codec. May only be needed for slave mode.
+ */
+static int s3c2412_snd_lrsync(struct s3c_i2sv2_info *i2s)
+{
+ u32 iiscon;
+ unsigned long timeout = jiffies + msecs_to_jiffies(5);
+
+ pr_debug("Entered %s\n", __func__);
+
+ while (1) {
+ iiscon = readl(i2s->regs + S3C2412_IISCON);
+ if (iiscon & S3C2412_IISCON_LRINDEX)
+ break;
+
+ if (timeout < jiffies) {
+ printk(KERN_ERR "%s: timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Set S3C2412 I2S DAI format
+ */
+static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
+ unsigned int fmt)
+{
+ struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+ u32 iismod;
+
+ pr_debug("Entered %s\n", __func__);
+
+ iismod = readl(i2s->regs + S3C2412_IISMOD);
+ pr_debug("hw_params r: IISMOD: %x \n", iismod);
+
+#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
+#define IISMOD_MASTER_MASK S3C2412_IISMOD_MASTER_MASK
+#define IISMOD_SLAVE S3C2412_IISMOD_SLAVE
+#define IISMOD_MASTER S3C2412_IISMOD_MASTER_INTERNAL
+#endif
+
+#if defined(CONFIG_PLAT_S3C64XX)
+/* From Rev1.1 datasheet, we have two master and two slave modes:
+ * IMS[11:10]:
+ * 00 = master mode, fed from PCLK
+ * 01 = master mode, fed from CLKAUDIO
+ * 10 = slave mode, using PCLK
+ * 11 = slave mode, using I2SCLK
+ */
+#define IISMOD_MASTER_MASK (1 << 11)
+#define IISMOD_SLAVE (1 << 11)
+#define IISMOD_MASTER (0x0)
+#endif
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ i2s->master = 0;
+ iismod &= ~IISMOD_MASTER_MASK;
+ iismod |= IISMOD_SLAVE;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ i2s->master = 1;
+ iismod &= ~IISMOD_MASTER_MASK;
+ iismod |= IISMOD_MASTER;
+ break;
+ default:
+ pr_debug("unknwon master/slave format\n");
+ return -EINVAL;
+ }
+
+ iismod &= ~S3C2412_IISMOD_SDF_MASK;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_RIGHT_J:
+ iismod |= S3C2412_IISMOD_SDF_MSB;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ iismod |= S3C2412_IISMOD_SDF_LSB;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ iismod |= S3C2412_IISMOD_SDF_IIS;
+ break;
+ default:
+ pr_debug("Unknown data format\n");
+ return -EINVAL;
+ }
+
+ writel(iismod, i2s->regs + S3C2412_IISMOD);
+ pr_debug("hw_params w: IISMOD: %x \n", iismod);
+ return 0;
+}
+
+static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *socdai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai_link *dai = rtd->dai;
+ struct s3c_i2sv2_info *i2s = to_info(dai->cpu_dai);
+ u32 iismod;
+
+ pr_debug("Entered %s\n", __func__);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dai->cpu_dai->dma_data = i2s->dma_playback;
+ else
+ dai->cpu_dai->dma_data = i2s->dma_capture;
+
+ /* Working copies of register */
+ iismod = readl(i2s->regs + S3C2412_IISMOD);
+ pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ iismod |= S3C2412_IISMOD_8BIT;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ iismod &= ~S3C2412_IISMOD_8BIT;
+ break;
+ }
+
+ writel(iismod, i2s->regs + S3C2412_IISMOD);
+ pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
+ return 0;
+}
+
+static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct s3c_i2sv2_info *i2s = to_info(rtd->dai->cpu_dai);
+ int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+ unsigned long irqs;
+ int ret = 0;
+
+ pr_debug("Entered %s\n", __func__);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ /* On start, ensure that the FIFOs are cleared and reset. */
+
+ writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH,
+ i2s->regs + S3C2412_IISFIC);
+
+ /* clear again, just in case */
+ writel(0x0, i2s->regs + S3C2412_IISFIC);
+
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (!i2s->master) {
+ ret = s3c2412_snd_lrsync(i2s);
+ if (ret)
+ goto exit_err;
+ }
+
+ local_irq_save(irqs);
+
+ if (capture)
+ s3c2412_snd_rxctrl(i2s, 1);
+ else
+ s3c2412_snd_txctrl(i2s, 1);
+
+ local_irq_restore(irqs);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ local_irq_save(irqs);
+
+ if (capture)
+ s3c2412_snd_rxctrl(i2s, 0);
+ else
+ s3c2412_snd_txctrl(i2s, 0);
+
+ local_irq_restore(irqs);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+exit_err:
+ return ret;
+}
+
+/*
+ * Set S3C2412 Clock dividers
+ */
+static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
+ int div_id, int div)
+{
+ struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+ u32 reg;
+
+ pr_debug("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
+
+ switch (div_id) {
+ case S3C_I2SV2_DIV_BCLK:
+ reg = readl(i2s->regs + S3C2412_IISMOD);
+ reg &= ~S3C2412_IISMOD_BCLK_MASK;
+ writel(reg | div, i2s->regs + S3C2412_IISMOD);
+
+ pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
+ break;
+
+ case S3C_I2SV2_DIV_RCLK:
+ if (div > 3) {
+ /* convert value to bit field */
+
+ switch (div) {
+ case 256:
+ div = S3C2412_IISMOD_RCLK_256FS;
+ break;
+
+ case 384:
+ div = S3C2412_IISMOD_RCLK_384FS;
+ break;
+
+ case 512:
+ div = S3C2412_IISMOD_RCLK_512FS;
+ break;
+
+ case 768:
+ div = S3C2412_IISMOD_RCLK_768FS;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ }
+
+ reg = readl(i2s->regs + S3C2412_IISMOD);
+ reg &= ~S3C2412_IISMOD_RCLK_MASK;
+ writel(reg | div, i2s->regs + S3C2412_IISMOD);
+ pr_debug("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
+ break;
+
+ case S3C_I2SV2_DIV_PRESCALER:
+ if (div >= 0) {
+ writel((div << 8) | S3C2412_IISPSR_PSREN,
+ i2s->regs + S3C2412_IISPSR);
+ } else {
+ writel(0x0, i2s->regs + S3C2412_IISPSR);
+ }
+ pr_debug("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR));
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* default table of all avaialable root fs divisors */
+static unsigned int iis_fs_tab[] = { 256, 512, 384, 768 };
+
+int s3c2412_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
+ unsigned int *fstab,
+ unsigned int rate, struct clk *clk)
+{
+ unsigned long clkrate = clk_get_rate(clk);
+ unsigned int div;
+ unsigned int fsclk;
+ unsigned int actual;
+ unsigned int fs;
+ unsigned int fsdiv;
+ signed int deviation = 0;
+ unsigned int best_fs = 0;
+ unsigned int best_div = 0;
+ unsigned int best_rate = 0;
+ unsigned int best_deviation = INT_MAX;
+
+ if (fstab == NULL)
+ fstab = iis_fs_tab;
+
+ for (fs = 0; fs < ARRAY_SIZE(iis_fs_tab); fs++) {
+ fsdiv = iis_fs_tab[fs];
+
+ fsclk = clkrate / fsdiv;
+ div = fsclk / rate;
+
+ if ((fsclk % rate) > (rate / 2))
+ div++;
+
+ if (div <= 1)
+ continue;
+
+ actual = clkrate / (fsdiv * div);
+ deviation = actual - rate;
+
+ printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n",
+ fsdiv, div, actual, deviation);
+
+ deviation = abs(deviation);
+
+ if (deviation < best_deviation) {
+ best_fs = fsdiv;
+ best_div = div;
+ best_rate = actual;
+ best_deviation = deviation;
+ }
+
+ if (deviation == 0)
+ break;
+ }
+
+ printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n",
+ best_fs, best_div, best_rate);
+
+ info->fs_div = best_fs;
+ info->clk_div = best_div;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(s3c2412_iis_calc_rate);
+
+int s3c_i2sv2_probe(struct platform_device *pdev,
+ struct snd_soc_dai *dai,
+ struct s3c_i2sv2_info *i2s,
+ unsigned long base)
+{
+ struct device *dev = &pdev->dev;
+
+ i2s->dev = dev;
+
+ /* record our i2s structure for later use in the callbacks */
+ dai->private_data = i2s;
+
+ i2s->regs = ioremap(base, 0x100);
+ if (i2s->regs == NULL) {
+ dev_err(dev, "cannot ioremap registers\n");
+ return -ENXIO;
+ }
+
+ i2s->iis_pclk = clk_get(dev, "iis");
+ if (i2s->iis_pclk == NULL) {
+ dev_err(dev, "failed to get iis_clock\n");
+ iounmap(i2s->regs);
+ return -ENOENT;
+ }
+
+ clk_enable(i2s->iis_pclk);
+
+ s3c2412_snd_txctrl(i2s, 0);
+ s3c2412_snd_rxctrl(i2s, 0);
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(s3c_i2sv2_probe);
+
+#ifdef CONFIG_PM
+static int s3c2412_i2s_suspend(struct snd_soc_dai *dai)
+{
+ struct s3c_i2sv2_info *i2s = to_info(dai);
+ u32 iismod;
+
+ if (dai->active) {
+ i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD);
+ i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON);
+ i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR);
+
+ /* some basic suspend checks */
+
+ iismod = readl(i2s->regs + S3C2412_IISMOD);
+
+ if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
+ pr_warning("%s: RXDMA active?\n", __func__);
+
+ if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
+ pr_warning("%s: TXDMA active?\n", __func__);
+
+ if (iismod & S3C2412_IISCON_IIS_ACTIVE)
+ pr_warning("%s: IIS active\n", __func__);
+ }
+
+ return 0;
+}
+
+static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
+{
+ struct s3c_i2sv2_info *i2s = to_info(dai);
+
+ pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n",
+ dai->active, i2s->suspend_iismod, i2s->suspend_iiscon);
+
+ if (dai->active) {
+ writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
+ writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD);
+ writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR);
+
+ writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH,
+ i2s->regs + S3C2412_IISFIC);
+
+ ndelay(250);
+ writel(0x0, i2s->regs + S3C2412_IISFIC);
+ }
+
+ return 0;
+}
+#else
+#define s3c2412_i2s_suspend NULL
+#define s3c2412_i2s_resume NULL
+#endif
+
+int s3c_i2sv2_register_dai(struct snd_soc_dai *dai)
+{
+ dai->ops.trigger = s3c2412_i2s_trigger;
+ dai->ops.hw_params = s3c2412_i2s_hw_params;
+ dai->ops.set_fmt = s3c2412_i2s_set_fmt;
+ dai->ops.set_clkdiv = s3c2412_i2s_set_clkdiv;
+
+ dai->suspend = s3c2412_i2s_suspend;
+ dai->resume = s3c2412_i2s_resume;
+
+ return snd_soc_register_dai(dai);
+}
+
+EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai);
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.h b/sound/soc/s3c24xx/s3c-i2s-v2.h
new file mode 100644
index 00000000000..f66854a77fb
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.h
@@ -0,0 +1,90 @@
+/* sound/soc/s3c24xx/s3c-i2s-v2.h
+ *
+ * ALSA Soc Audio Layer - S3C_I2SV2 I2S driver
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+*/
+
+/* This code is the core support for the I2S block found in a number of
+ * Samsung SoC devices which is unofficially named I2S-V2. Currently the
+ * S3C2412 and the S3C64XX series use this block to provide 1 or 2 I2S
+ * channels via configurable GPIO.
+ */
+
+#ifndef __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H
+#define __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H __FILE__
+
+#define S3C_I2SV2_DIV_BCLK (1)
+#define S3C_I2SV2_DIV_RCLK (2)
+#define S3C_I2SV2_DIV_PRESCALER (3)
+
+/**
+ * struct s3c_i2sv2_info - S3C I2S-V2 information
+ * @dev: The parent device passed to use from the probe.
+ * @regs: The pointer to the device registe block.
+ * @master: True if the I2S core is the I2S bit clock master.
+ * @dma_playback: DMA information for playback channel.
+ * @dma_capture: DMA information for capture channel.
+ * @suspend_iismod: PM save for the IISMOD register.
+ * @suspend_iiscon: PM save for the IISCON register.
+ * @suspend_iispsr: PM save for the IISPSR register.
+ *
+ * This is the private codec state for the hardware associated with an
+ * I2S channel such as the register mappings and clock sources.
+ */
+struct s3c_i2sv2_info {
+ struct device *dev;
+ void __iomem *regs;
+
+ struct clk *iis_pclk;
+ struct clk *iis_cclk;
+ struct clk *iis_clk;
+
+ unsigned char master;
+
+ struct s3c24xx_pcm_dma_params *dma_playback;
+ struct s3c24xx_pcm_dma_params *dma_capture;
+
+ u32 suspend_iismod;
+ u32 suspend_iiscon;
+ u32 suspend_iispsr;
+};
+
+struct s3c_i2sv2_rate_calc {
+ unsigned int clk_div; /* for prescaler */
+ unsigned int fs_div; /* for root frame clock */
+};
+
+extern int s3c_i2sv2_iis_calc_rate(struct s3c_i2sv2_rate_calc *info,
+ unsigned int *fstab,
+ unsigned int rate, struct clk *clk);
+
+/**
+ * s3c_i2sv2_probe - probe for i2s device helper
+ * @pdev: The platform device supplied to the original probe.
+ * @dai: The ASoC DAI structure supplied to the original probe.
+ * @i2s: Our local i2s structure to fill in.
+ * @base: The base address for the registers.
+ */
+extern int s3c_i2sv2_probe(struct platform_device *pdev,
+ struct snd_soc_dai *dai,
+ struct s3c_i2sv2_info *i2s,
+ unsigned long base);
+
+/**
+ * s3c_i2sv2_register_dai - register dai with soc core
+ * @dai: The snd_soc_dai structure to register
+ *
+ * Fill in any missing fields and then register the given dai with the
+ * soc core.
+ */
+extern int s3c_i2sv2_register_dai(struct snd_soc_dai *dai);
+
+#endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c
index f3fc0aba0aa..1ca3cdaa821 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.c
+++ b/sound/soc/s3c24xx/s3c2412-i2s.c
@@ -22,6 +22,7 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/kernel.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -30,26 +31,16 @@
#include <sound/soc.h>
#include <mach/hardware.h>
-#include <linux/io.h>
-#include <asm/dma.h>
-
-#include <asm/plat-s3c24xx/regs-s3c2412-iis.h>
+#include <plat/regs-s3c2412-iis.h>
-#include <mach/regs-gpio.h>
-#include <mach/audio.h>
+#include <plat/regs-gpio.h>
+#include <plat/audio.h>
#include <mach/dma.h>
#include "s3c24xx-pcm.h"
#include "s3c2412-i2s.h"
#define S3C2412_I2S_DEBUG 0
-#define S3C2412_I2S_DEBUG_CON 0
-
-#if S3C2412_I2S_DEBUG
-#define DBG(x...) printk(KERN_INFO x)
-#else
-#define DBG(x...) do { } while (0)
-#endif
static struct s3c2410_dma_client s3c2412_dma_client_out = {
.name = "I2S PCM Stereo out"
@@ -73,431 +64,7 @@ static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_in = {
.dma_size = 4,
};
-struct s3c2412_i2s_info {
- struct device *dev;
- void __iomem *regs;
- struct clk *iis_clk;
- struct clk *iis_pclk;
- struct clk *iis_cclk;
-
- u32 suspend_iismod;
- u32 suspend_iiscon;
- u32 suspend_iispsr;
-};
-
-static struct s3c2412_i2s_info s3c2412_i2s;
-
-#define bit_set(v, b) (((v) & (b)) ? 1 : 0)
-
-#if S3C2412_I2S_DEBUG_CON
-static void dbg_showcon(const char *fn, u32 con)
-{
- printk(KERN_DEBUG "%s: LRI=%d, TXFEMPT=%d, RXFEMPT=%d, TXFFULL=%d, RXFFULL=%d\n", fn,
- bit_set(con, S3C2412_IISCON_LRINDEX),
- bit_set(con, S3C2412_IISCON_TXFIFO_EMPTY),
- bit_set(con, S3C2412_IISCON_RXFIFO_EMPTY),
- bit_set(con, S3C2412_IISCON_TXFIFO_FULL),
- bit_set(con, S3C2412_IISCON_RXFIFO_FULL));
-
- printk(KERN_DEBUG "%s: PAUSE: TXDMA=%d, RXDMA=%d, TXCH=%d, RXCH=%d\n",
- fn,
- bit_set(con, S3C2412_IISCON_TXDMA_PAUSE),
- bit_set(con, S3C2412_IISCON_RXDMA_PAUSE),
- bit_set(con, S3C2412_IISCON_TXCH_PAUSE),
- bit_set(con, S3C2412_IISCON_RXCH_PAUSE));
- printk(KERN_DEBUG "%s: ACTIVE: TXDMA=%d, RXDMA=%d, IIS=%d\n", fn,
- bit_set(con, S3C2412_IISCON_TXDMA_ACTIVE),
- bit_set(con, S3C2412_IISCON_RXDMA_ACTIVE),
- bit_set(con, S3C2412_IISCON_IIS_ACTIVE));
-}
-#else
-static inline void dbg_showcon(const char *fn, u32 con)
-{
-}
-#endif
-
-/* Turn on or off the transmission path. */
-static void s3c2412_snd_txctrl(int on)
-{
- struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
- void __iomem *regs = i2s->regs;
- u32 fic, con, mod;
-
- DBG("%s(%d)\n", __func__, on);
-
- fic = readl(regs + S3C2412_IISFIC);
- con = readl(regs + S3C2412_IISCON);
- mod = readl(regs + S3C2412_IISMOD);
-
- DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
-
- if (on) {
- con |= S3C2412_IISCON_TXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
- con &= ~S3C2412_IISCON_TXDMA_PAUSE;
- con &= ~S3C2412_IISCON_TXCH_PAUSE;
-
- switch (mod & S3C2412_IISMOD_MODE_MASK) {
- case S3C2412_IISMOD_MODE_TXONLY:
- case S3C2412_IISMOD_MODE_TXRX:
- /* do nothing, we are in the right mode */
- break;
-
- case S3C2412_IISMOD_MODE_RXONLY:
- mod &= ~S3C2412_IISMOD_MODE_MASK;
- mod |= S3C2412_IISMOD_MODE_TXRX;
- break;
-
- default:
- dev_err(i2s->dev, "TXEN: Invalid MODE in IISMOD\n");
- }
-
- writel(con, regs + S3C2412_IISCON);
- writel(mod, regs + S3C2412_IISMOD);
- } else {
- /* Note, we do not have any indication that the FIFO problems
- * tha the S3C2410/2440 had apply here, so we should be able
- * to disable the DMA and TX without resetting the FIFOS.
- */
-
- con |= S3C2412_IISCON_TXDMA_PAUSE;
- con |= S3C2412_IISCON_TXCH_PAUSE;
- con &= ~S3C2412_IISCON_TXDMA_ACTIVE;
-
- switch (mod & S3C2412_IISMOD_MODE_MASK) {
- case S3C2412_IISMOD_MODE_TXRX:
- mod &= ~S3C2412_IISMOD_MODE_MASK;
- mod |= S3C2412_IISMOD_MODE_RXONLY;
- break;
-
- case S3C2412_IISMOD_MODE_TXONLY:
- mod &= ~S3C2412_IISMOD_MODE_MASK;
- con &= ~S3C2412_IISCON_IIS_ACTIVE;
- break;
-
- default:
- dev_err(i2s->dev, "TXDIS: Invalid MODE in IISMOD\n");
- }
-
- writel(mod, regs + S3C2412_IISMOD);
- writel(con, regs + S3C2412_IISCON);
- }
-
- fic = readl(regs + S3C2412_IISFIC);
- dbg_showcon(__func__, con);
- DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
-}
-
-static void s3c2412_snd_rxctrl(int on)
-{
- struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
- void __iomem *regs = i2s->regs;
- u32 fic, con, mod;
-
- DBG("%s(%d)\n", __func__, on);
-
- fic = readl(regs + S3C2412_IISFIC);
- con = readl(regs + S3C2412_IISCON);
- mod = readl(regs + S3C2412_IISMOD);
-
- DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
-
- if (on) {
- con |= S3C2412_IISCON_RXDMA_ACTIVE | S3C2412_IISCON_IIS_ACTIVE;
- con &= ~S3C2412_IISCON_RXDMA_PAUSE;
- con &= ~S3C2412_IISCON_RXCH_PAUSE;
-
- switch (mod & S3C2412_IISMOD_MODE_MASK) {
- case S3C2412_IISMOD_MODE_TXRX:
- case S3C2412_IISMOD_MODE_RXONLY:
- /* do nothing, we are in the right mode */
- break;
-
- case S3C2412_IISMOD_MODE_TXONLY:
- mod &= ~S3C2412_IISMOD_MODE_MASK;
- mod |= S3C2412_IISMOD_MODE_TXRX;
- break;
-
- default:
- dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
- }
-
- writel(mod, regs + S3C2412_IISMOD);
- writel(con, regs + S3C2412_IISCON);
- } else {
- /* See txctrl notes on FIFOs. */
-
- con &= ~S3C2412_IISCON_RXDMA_ACTIVE;
- con |= S3C2412_IISCON_RXDMA_PAUSE;
- con |= S3C2412_IISCON_RXCH_PAUSE;
-
- switch (mod & S3C2412_IISMOD_MODE_MASK) {
- case S3C2412_IISMOD_MODE_RXONLY:
- con &= ~S3C2412_IISCON_IIS_ACTIVE;
- mod &= ~S3C2412_IISMOD_MODE_MASK;
- break;
-
- case S3C2412_IISMOD_MODE_TXRX:
- mod &= ~S3C2412_IISMOD_MODE_MASK;
- mod |= S3C2412_IISMOD_MODE_TXONLY;
- break;
-
- default:
- dev_err(i2s->dev, "RXEN: Invalid MODE in IISMOD\n");
- }
-
- writel(con, regs + S3C2412_IISCON);
- writel(mod, regs + S3C2412_IISMOD);
- }
-
- fic = readl(regs + S3C2412_IISFIC);
- DBG("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic);
-}
-
-
-/*
- * Wait for the LR signal to allow synchronisation to the L/R clock
- * from the codec. May only be needed for slave mode.
- */
-static int s3c2412_snd_lrsync(void)
-{
- u32 iiscon;
- unsigned long timeout = jiffies + msecs_to_jiffies(5);
-
- DBG("Entered %s\n", __func__);
-
- while (1) {
- iiscon = readl(s3c2412_i2s.regs + S3C2412_IISCON);
- if (iiscon & S3C2412_IISCON_LRINDEX)
- break;
-
- if (timeout < jiffies) {
- printk(KERN_ERR "%s: timeout\n", __func__);
- return -ETIMEDOUT;
- }
- }
-
- return 0;
-}
-
-/*
- * Check whether CPU is the master or slave
- */
-static inline int s3c2412_snd_is_clkmaster(void)
-{
- u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
-
- DBG("Entered %s\n", __func__);
-
- iismod &= S3C2412_IISMOD_MASTER_MASK;
- return !(iismod == S3C2412_IISMOD_SLAVE);
-}
-
-/*
- * Set S3C2412 I2S DAI format
- */
-static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
- unsigned int fmt)
-{
- u32 iismod;
-
-
- DBG("Entered %s\n", __func__);
-
- iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
- DBG("hw_params r: IISMOD: %x \n", iismod);
-
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
- iismod &= ~S3C2412_IISMOD_MASTER_MASK;
- iismod |= S3C2412_IISMOD_SLAVE;
- break;
- case SND_SOC_DAIFMT_CBS_CFS:
- iismod &= ~S3C2412_IISMOD_MASTER_MASK;
- iismod |= S3C2412_IISMOD_MASTER_INTERNAL;
- break;
- default:
- DBG("unknwon master/slave format\n");
- return -EINVAL;
- }
-
- iismod &= ~S3C2412_IISMOD_SDF_MASK;
-
- switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_RIGHT_J:
- iismod |= S3C2412_IISMOD_SDF_MSB;
- break;
- case SND_SOC_DAIFMT_LEFT_J:
- iismod |= S3C2412_IISMOD_SDF_LSB;
- break;
- case SND_SOC_DAIFMT_I2S:
- iismod |= S3C2412_IISMOD_SDF_IIS;
- break;
- default:
- DBG("Unknown data format\n");
- return -EINVAL;
- }
-
- writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD);
- DBG("hw_params w: IISMOD: %x \n", iismod);
- return 0;
-}
-
-static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- u32 iismod;
-
- DBG("Entered %s\n", __func__);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- rtd->dai->cpu_dai->dma_data = &s3c2412_i2s_pcm_stereo_out;
- else
- rtd->dai->cpu_dai->dma_data = &s3c2412_i2s_pcm_stereo_in;
-
- /* Working copies of register */
- iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
- DBG("%s: r: IISMOD: %x\n", __func__, iismod);
-
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S8:
- iismod |= S3C2412_IISMOD_8BIT;
- break;
- case SNDRV_PCM_FORMAT_S16_LE:
- iismod &= ~S3C2412_IISMOD_8BIT;
- break;
- }
-
- writel(iismod, s3c2412_i2s.regs + S3C2412_IISMOD);
- DBG("%s: w: IISMOD: %x\n", __func__, iismod);
- return 0;
-}
-
-static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
-{
- int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
- unsigned long irqs;
- int ret = 0;
-
- DBG("Entered %s\n", __func__);
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- /* On start, ensure that the FIFOs are cleared and reset. */
-
- writel(capture ? S3C2412_IISFIC_RXFLUSH : S3C2412_IISFIC_TXFLUSH,
- s3c2412_i2s.regs + S3C2412_IISFIC);
-
- /* clear again, just in case */
- writel(0x0, s3c2412_i2s.regs + S3C2412_IISFIC);
-
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- if (!s3c2412_snd_is_clkmaster()) {
- ret = s3c2412_snd_lrsync();
- if (ret)
- goto exit_err;
- }
-
- local_irq_save(irqs);
-
- if (capture)
- s3c2412_snd_rxctrl(1);
- else
- s3c2412_snd_txctrl(1);
-
- local_irq_restore(irqs);
- break;
-
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- local_irq_save(irqs);
-
- if (capture)
- s3c2412_snd_rxctrl(0);
- else
- s3c2412_snd_txctrl(0);
-
- local_irq_restore(irqs);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
-exit_err:
- return ret;
-}
-
-/* default table of all avaialable root fs divisors */
-static unsigned int s3c2412_iis_fs[] = { 256, 512, 384, 768, 0 };
-
-int s3c2412_iis_calc_rate(struct s3c2412_rate_calc *info,
- unsigned int *fstab,
- unsigned int rate, struct clk *clk)
-{
- unsigned long clkrate = clk_get_rate(clk);
- unsigned int div;
- unsigned int fsclk;
- unsigned int actual;
- unsigned int fs;
- unsigned int fsdiv;
- signed int deviation = 0;
- unsigned int best_fs = 0;
- unsigned int best_div = 0;
- unsigned int best_rate = 0;
- unsigned int best_deviation = INT_MAX;
-
-
- if (fstab == NULL)
- fstab = s3c2412_iis_fs;
-
- for (fs = 0;; fs++) {
- fsdiv = s3c2412_iis_fs[fs];
-
- if (fsdiv == 0)
- break;
-
- fsclk = clkrate / fsdiv;
- div = fsclk / rate;
-
- if ((fsclk % rate) > (rate / 2))
- div++;
-
- if (div <= 1)
- continue;
-
- actual = clkrate / (fsdiv * div);
- deviation = actual - rate;
-
- printk(KERN_DEBUG "%dfs: div %d => result %d, deviation %d\n",
- fsdiv, div, actual, deviation);
-
- deviation = abs(deviation);
-
- if (deviation < best_deviation) {
- best_fs = fsdiv;
- best_div = div;
- best_rate = actual;
- best_deviation = deviation;
- }
-
- if (deviation == 0)
- break;
- }
-
- printk(KERN_DEBUG "best: fs=%d, div=%d, rate=%d\n",
- best_fs, best_div, best_rate);
-
- info->fs_div = best_fs;
- info->clk_div = best_div;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(s3c2412_iis_calc_rate);
+static struct s3c_i2sv2_info s3c2412_i2s;
/*
* Set S3C2412 Clock source
@@ -507,15 +74,17 @@ static int s3c2412_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
{
u32 iismod = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
- DBG("%s(%p, %d, %u, %d)\n", __func__, cpu_dai, clk_id,
+ pr_debug("%s(%p, %d, %u, %d)\n", __func__, cpu_dai, clk_id,
freq, dir);
switch (clk_id) {
case S3C2412_CLKSRC_PCLK:
+ s3c2412_i2s.master = 1;
iismod &= ~S3C2412_IISMOD_MASTER_MASK;
iismod |= S3C2412_IISMOD_MASTER_INTERNAL;
break;
case S3C2412_CLKSRC_I2SCLK:
+ s3c2412_i2s.master = 0;
iismod &= ~S3C2412_IISMOD_MASTER_MASK;
iismod |= S3C2412_IISMOD_MASTER_EXTERNAL;
break;
@@ -527,74 +96,6 @@ static int s3c2412_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
return 0;
}
-/*
- * Set S3C2412 Clock dividers
- */
-static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
- int div_id, int div)
-{
- struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
- u32 reg;
-
- DBG("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
-
- switch (div_id) {
- case S3C2412_DIV_BCLK:
- reg = readl(i2s->regs + S3C2412_IISMOD);
- reg &= ~S3C2412_IISMOD_BCLK_MASK;
- writel(reg | div, i2s->regs + S3C2412_IISMOD);
-
- DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
- break;
-
- case S3C2412_DIV_RCLK:
- if (div > 3) {
- /* convert value to bit field */
-
- switch (div) {
- case 256:
- div = S3C2412_IISMOD_RCLK_256FS;
- break;
-
- case 384:
- div = S3C2412_IISMOD_RCLK_384FS;
- break;
-
- case 512:
- div = S3C2412_IISMOD_RCLK_512FS;
- break;
-
- case 768:
- div = S3C2412_IISMOD_RCLK_768FS;
- break;
-
- default:
- return -EINVAL;
- }
- }
-
- reg = readl(s3c2412_i2s.regs + S3C2412_IISMOD);
- reg &= ~S3C2412_IISMOD_RCLK_MASK;
- writel(reg | div, i2s->regs + S3C2412_IISMOD);
- DBG("%s: MOD=%08x\n", __func__, readl(i2s->regs + S3C2412_IISMOD));
- break;
-
- case S3C2412_DIV_PRESCALER:
- if (div >= 0) {
- writel((div << 8) | S3C2412_IISPSR_PSREN,
- i2s->regs + S3C2412_IISPSR);
- } else {
- writel(0x0, i2s->regs + S3C2412_IISPSR);
- }
- DBG("%s: PSR=%08x\n", __func__, readl(i2s->regs + S3C2412_IISPSR));
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
struct clk *s3c2412_get_iisclk(void)
{
@@ -606,34 +107,30 @@ EXPORT_SYMBOL_GPL(s3c2412_get_iisclk);
static int s3c2412_i2s_probe(struct platform_device *pdev,
struct snd_soc_dai *dai)
{
- DBG("Entered %s\n", __func__);
+ int ret;
- s3c2412_i2s.dev = &pdev->dev;
+ pr_debug("Entered %s\n", __func__);
- s3c2412_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100);
- if (s3c2412_i2s.regs == NULL)
- return -ENXIO;
+ ret = s3c_i2sv2_probe(pdev, dai, &s3c2412_i2s, S3C2410_PA_IIS);
+ if (ret)
+ return ret;
- s3c2412_i2s.iis_pclk = clk_get(&pdev->dev, "iis");
- if (s3c2412_i2s.iis_pclk == NULL) {
- DBG("failed to get iis_clock\n");
- iounmap(s3c2412_i2s.regs);
- return -ENODEV;
- }
+ s3c2412_i2s.dma_capture = &s3c2412_i2s_pcm_stereo_in;
+ s3c2412_i2s.dma_playback = &s3c2412_i2s_pcm_stereo_out;
s3c2412_i2s.iis_cclk = clk_get(&pdev->dev, "i2sclk");
if (s3c2412_i2s.iis_cclk == NULL) {
- DBG("failed to get i2sclk clock\n");
+ pr_debug("failed to get i2sclk clock\n");
iounmap(s3c2412_i2s.regs);
return -ENODEV;
}
- clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll"));
+ /* Set MPLL as the source for IIS CLK */
- clk_enable(s3c2412_i2s.iis_pclk);
+ clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll"));
clk_enable(s3c2412_i2s.iis_cclk);
- s3c2412_i2s.iis_clk = s3c2412_i2s.iis_pclk;
+ s3c2412_i2s.iis_cclk = s3c2412_i2s.iis_pclk;
/* Configure the I2S pins in correct mode */
s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK);
@@ -642,78 +139,22 @@ static int s3c2412_i2s_probe(struct platform_device *pdev,
s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);
s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);
- s3c2412_snd_txctrl(0);
- s3c2412_snd_rxctrl(0);
-
return 0;
}
-#ifdef CONFIG_PM
-static int s3c2412_i2s_suspend(struct snd_soc_dai *dai)
-{
- struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
- u32 iismod;
-
- if (dai->active) {
- i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD);
- i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON);
- i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR);
-
- /* some basic suspend checks */
-
- iismod = readl(i2s->regs + S3C2412_IISMOD);
-
- if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
- pr_warning("%s: RXDMA active?\n", __func__);
-
- if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
- pr_warning("%s: TXDMA active?\n", __func__);
-
- if (iismod & S3C2412_IISCON_IIS_ACTIVE)
- pr_warning("%s: IIS active\n", __func__);
- }
-
- return 0;
-}
-
-static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
-{
- struct s3c2412_i2s_info *i2s = &s3c2412_i2s;
-
- pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n",
- dai->active, i2s->suspend_iismod, i2s->suspend_iiscon);
-
- if (dai->active) {
- writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
- writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD);
- writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR);
-
- writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH,
- i2s->regs + S3C2412_IISFIC);
-
- ndelay(250);
- writel(0x0, i2s->regs + S3C2412_IISFIC);
-
- }
-
- return 0;
-}
-#else
-#define s3c2412_i2s_suspend NULL
-#define s3c2412_i2s_resume NULL
-#endif /* CONFIG_PM */
-
#define S3C2412_I2S_RATES \
(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+static struct snd_soc_dai_ops s3c2412_i2s_dai_ops = {
+ .set_sysclk = s3c2412_i2s_set_sysclk,
+};
+
struct snd_soc_dai s3c2412_i2s_dai = {
- .name = "s3c2412-i2s",
- .id = 0,
- .probe = s3c2412_i2s_probe,
- .suspend = s3c2412_i2s_suspend,
- .resume = s3c2412_i2s_resume,
+ .name = "s3c2412-i2s",
+ .id = 0,
+ .probe = s3c2412_i2s_probe,
.playback = {
.channels_min = 2,
.channels_max = 2,
@@ -726,19 +167,13 @@ struct snd_soc_dai s3c2412_i2s_dai = {
.rates = S3C2412_I2S_RATES,
.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
},
- .ops = {
- .trigger = s3c2412_i2s_trigger,
- .hw_params = s3c2412_i2s_hw_params,
- .set_fmt = s3c2412_i2s_set_fmt,
- .set_clkdiv = s3c2412_i2s_set_clkdiv,
- .set_sysclk = s3c2412_i2s_set_sysclk,
- },
+ .ops = &s3c2412_i2s_dai_ops,
};
EXPORT_SYMBOL_GPL(s3c2412_i2s_dai);
static int __init s3c2412_i2s_init(void)
{
- return snd_soc_register_dai(&s3c2412_i2s_dai);
+ return s3c_i2sv2_register_dai(&s3c2412_i2s_dai);
}
module_init(s3c2412_i2s_init);
@@ -748,7 +183,6 @@ static void __exit s3c2412_i2s_exit(void)
}
module_exit(s3c2412_i2s_exit);
-
/* Module information */
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_DESCRIPTION("S3C2412 I2S SoC Interface");
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.h b/sound/soc/s3c24xx/s3c2412-i2s.h
index aac08a25e54..92848e54be1 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.h
+++ b/sound/soc/s3c24xx/s3c2412-i2s.h
@@ -15,9 +15,11 @@
#ifndef __SND_SOC_S3C24XX_S3C2412_I2S_H
#define __SND_SOC_S3C24XX_S3C2412_I2S_H __FILE__
-#define S3C2412_DIV_BCLK (1)
-#define S3C2412_DIV_RCLK (2)
-#define S3C2412_DIV_PRESCALER (3)
+#include "s3c-i2s-v2.h"
+
+#define S3C2412_DIV_BCLK S3C_I2SV2_DIV_BCLK
+#define S3C2412_DIV_RCLK S3C_I2SV2_DIV_RCLK
+#define S3C2412_DIV_PRESCALER S3C_I2SV2_DIV_PRESCALER
#define S3C2412_CLKSRC_PCLK (0)
#define S3C2412_CLKSRC_I2SCLK (1)
@@ -26,13 +28,4 @@ extern struct clk *s3c2412_get_iisclk(void);
extern struct snd_soc_dai s3c2412_i2s_dai;
-struct s3c2412_rate_calc {
- unsigned int clk_div; /* for prescaler */
- unsigned int fs_div; /* for root frame clock */
-};
-
-extern int s3c2412_iis_calc_rate(struct s3c2412_rate_calc *info,
- unsigned int *fstab,
- unsigned int rate, struct clk *clk);
-
#endif /* __SND_SOC_S3C24XX_S3C2412_I2S_H */
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c
index 5822d2dd49b..3698f707c44 100644
--- a/sound/soc/s3c24xx/s3c2443-ac97.c
+++ b/sound/soc/s3c24xx/s3c2443-ac97.c
@@ -31,7 +31,7 @@
#include <plat/regs-ac97.h>
#include <mach/regs-gpio.h>
#include <mach/regs-clock.h>
-#include <mach/audio.h>
+#include <plat/audio.h>
#include <asm/dma.h>
#include <mach/dma.h>
@@ -355,6 +355,16 @@ static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream,
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+static struct snd_soc_dai_ops s3c2443_ac97_dai_ops = {
+ .hw_params = s3c2443_ac97_hw_params,
+ .trigger = s3c2443_ac97_trigger,
+};
+
+static struct snd_soc_dai_ops s3c2443_ac97_mic_dai_ops = {
+ .hw_params = s3c2443_ac97_hw_mic_params,
+ .trigger = s3c2443_ac97_mic_trigger,
+};
+
struct snd_soc_dai s3c2443_ac97_dai[] = {
{
.name = "s3c2443-ac97",
@@ -374,9 +384,7 @@ struct snd_soc_dai s3c2443_ac97_dai[] = {
.channels_max = 2,
.rates = s3c2443_AC97_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = {
- .hw_params = s3c2443_ac97_hw_params,
- .trigger = s3c2443_ac97_trigger},
+ .ops = &s3c2443_ac97_dai_ops,
},
{
.name = "pxa2xx-ac97-mic",
@@ -388,9 +396,7 @@ struct snd_soc_dai s3c2443_ac97_dai[] = {
.channels_max = 1,
.rates = s3c2443_AC97_RATES,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = {
- .hw_params = s3c2443_ac97_hw_mic_params,
- .trigger = s3c2443_ac97_mic_trigger,},
+ .ops = &s3c2443_ac97_mic_dai_ops,
},
};
EXPORT_SYMBOL_GPL(s3c2443_ac97_dai);
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c
index 6f4d439b57a..cc066964dad 100644
--- a/sound/soc/s3c24xx/s3c24xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c24xx-i2s.c
@@ -4,7 +4,7 @@
* (c) 2006 Wolfson Microelectronics PLC.
* Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
*
- * (c) 2004-2005 Simtec Electronics
+ * Copyright 2004-2005 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
@@ -30,22 +30,15 @@
#include <mach/hardware.h>
#include <mach/regs-gpio.h>
#include <mach/regs-clock.h>
-#include <mach/audio.h>
+#include <plat/audio.h>
#include <asm/dma.h>
#include <mach/dma.h>
-#include <asm/plat-s3c24xx/regs-iis.h>
+#include <plat/regs-iis.h>
#include "s3c24xx-pcm.h"
#include "s3c24xx-i2s.h"
-#define S3C24XX_I2S_DEBUG 0
-#if S3C24XX_I2S_DEBUG
-#define DBG(x...) printk(KERN_DEBUG "s3c24xx-i2s: " x)
-#else
-#define DBG(x...)
-#endif
-
static struct s3c2410_dma_client s3c24xx_dma_client_out = {
.name = "I2S PCM Stereo out"
};
@@ -84,13 +77,13 @@ static void s3c24xx_snd_txctrl(int on)
u32 iiscon;
u32 iismod;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
- DBG("r: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon);
+ pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
if (on) {
iisfcon |= S3C2410_IISFCON_TXDMA | S3C2410_IISFCON_TXENABLE;
@@ -120,7 +113,7 @@ static void s3c24xx_snd_txctrl(int on)
writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
}
- DBG("w: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon);
+ pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
}
static void s3c24xx_snd_rxctrl(int on)
@@ -129,13 +122,13 @@ static void s3c24xx_snd_rxctrl(int on)
u32 iiscon;
u32 iismod;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
- DBG("r: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon);
+ pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
if (on) {
iisfcon |= S3C2410_IISFCON_RXDMA | S3C2410_IISFCON_RXENABLE;
@@ -165,7 +158,7 @@ static void s3c24xx_snd_rxctrl(int on)
writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
}
- DBG("w: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon);
+ pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
}
/*
@@ -177,7 +170,7 @@ static int s3c24xx_snd_lrsync(void)
u32 iiscon;
int timeout = 50; /* 5ms */
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
while (1) {
iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
@@ -197,7 +190,7 @@ static int s3c24xx_snd_lrsync(void)
*/
static inline int s3c24xx_snd_is_clkmaster(void)
{
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1;
}
@@ -210,10 +203,10 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
{
u32 iismod;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
- DBG("hw_params r: IISMOD: %lx \n", iismod);
+ pr_debug("hw_params r: IISMOD: %x \n", iismod);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
@@ -238,7 +231,7 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
}
writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
- DBG("hw_params w: IISMOD: %lx \n", iismod);
+ pr_debug("hw_params w: IISMOD: %x \n", iismod);
return 0;
}
@@ -249,7 +242,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
u32 iismod;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_out;
@@ -258,7 +251,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
/* Working copies of register */
iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
- DBG("hw_params r: IISMOD: %lx\n", iismod);
+ pr_debug("hw_params r: IISMOD: %x\n", iismod);
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
@@ -276,7 +269,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
}
writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
- DBG("hw_params w: IISMOD: %lx\n", iismod);
+ pr_debug("hw_params w: IISMOD: %x\n", iismod);
return 0;
}
@@ -285,7 +278,7 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
{
int ret = 0;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -327,7 +320,7 @@ static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
{
u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
iismod &= ~S3C2440_IISMOD_MPLL;
@@ -353,7 +346,7 @@ static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
{
u32 reg;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
switch (div_id) {
case S3C24XX_DIV_BCLK:
@@ -389,7 +382,7 @@ EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
static int s3c24xx_i2s_probe(struct platform_device *pdev,
struct snd_soc_dai *dai)
{
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
s3c24xx_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100);
if (s3c24xx_i2s.regs == NULL)
@@ -397,7 +390,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev,
s3c24xx_i2s.iis_clk = clk_get(&pdev->dev, "iis");
if (s3c24xx_i2s.iis_clk == NULL) {
- DBG("failed to get iis_clock\n");
+ pr_err("failed to get iis_clock\n");
iounmap(s3c24xx_i2s.regs);
return -ENODEV;
}
@@ -421,7 +414,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev,
#ifdef CONFIG_PM
static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)
{
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
@@ -435,7 +428,7 @@ static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)
static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)
{
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
clk_enable(s3c24xx_i2s.iis_clk);
writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
@@ -456,6 +449,14 @@ static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)
SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+static struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = {
+ .trigger = s3c24xx_i2s_trigger,
+ .hw_params = s3c24xx_i2s_hw_params,
+ .set_fmt = s3c24xx_i2s_set_fmt,
+ .set_clkdiv = s3c24xx_i2s_set_clkdiv,
+ .set_sysclk = s3c24xx_i2s_set_sysclk,
+};
+
struct snd_soc_dai s3c24xx_i2s_dai = {
.name = "s3c24xx-i2s",
.id = 0,
@@ -472,13 +473,7 @@ struct snd_soc_dai s3c24xx_i2s_dai = {
.channels_max = 2,
.rates = S3C24XX_I2S_RATES,
.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = {
- .trigger = s3c24xx_i2s_trigger,
- .hw_params = s3c24xx_i2s_hw_params,
- .set_fmt = s3c24xx_i2s_set_fmt,
- .set_clkdiv = s3c24xx_i2s_set_clkdiv,
- .set_sysclk = s3c24xx_i2s_set_sysclk,
- },
+ .ops = &s3c24xx_i2s_dai_ops,
};
EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai);
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c
index 7c64d31d067..a9d68fa2b34 100644
--- a/sound/soc/s3c24xx/s3c24xx-pcm.c
+++ b/sound/soc/s3c24xx/s3c24xx-pcm.c
@@ -4,7 +4,7 @@
* (c) 2006 Wolfson Microelectronics PLC.
* Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
*
- * (c) 2004-2005 Simtec Electronics
+ * Copyright 2004-2005 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
@@ -29,17 +29,10 @@
#include <asm/dma.h>
#include <mach/hardware.h>
#include <mach/dma.h>
-#include <mach/audio.h>
+#include <plat/audio.h>
#include "s3c24xx-pcm.h"
-#define S3C24XX_PCM_DEBUG 0
-#if S3C24XX_PCM_DEBUG
-#define DBG(x...) printk(KERN_DEBUG "s3c24xx-pcm: " x)
-#else
-#define DBG(x...)
-#endif
-
static const struct snd_pcm_hardware s3c24xx_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -84,16 +77,16 @@ static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream)
dma_addr_t pos = prtd->dma_pos;
int ret;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
while (prtd->dma_loaded < prtd->dma_limit) {
unsigned long len = prtd->dma_period;
- DBG("dma_loaded: %d\n", prtd->dma_loaded);
+ pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
if ((pos + len) > prtd->dma_end) {
len = prtd->dma_end - pos;
- DBG(KERN_DEBUG "%s: corrected dma len %ld\n",
+ pr_debug(KERN_DEBUG "%s: corrected dma len %ld\n",
__func__, len);
}
@@ -119,7 +112,7 @@ static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel,
struct snd_pcm_substream *substream = dev_id;
struct s3c24xx_runtime_data *prtd;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR)
return;
@@ -148,7 +141,7 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream,
unsigned long totbytes = params_buffer_bytes(params);
int ret = 0;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
/* return if this is a bufferless transfer e.g.
* codec <--> BT codec or GSM modem -- lg FIXME */
@@ -161,14 +154,14 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream,
/* prepare DMA */
prtd->params = dma;
- DBG("params %p, client %p, channel %d\n", prtd->params,
+ pr_debug("params %p, client %p, channel %d\n", prtd->params,
prtd->params->client, prtd->params->channel);
ret = s3c2410_dma_request(prtd->params->channel,
prtd->params->client, NULL);
if (ret < 0) {
- DBG(KERN_ERR "failed to get dma channel\n");
+ printk(KERN_ERR "failed to get dma channel\n");
return ret;
}
}
@@ -196,7 +189,7 @@ static int s3c24xx_pcm_hw_free(struct snd_pcm_substream *substream)
{
struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
/* TODO - do we need to ensure DMA flushed */
snd_pcm_set_runtime_buffer(substream, NULL);
@@ -214,7 +207,7 @@ static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream)
struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
int ret = 0;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
/* return if this is a bufferless transfer e.g.
* codec <--> BT codec or GSM modem -- lg FIXME */
@@ -259,7 +252,7 @@ static int s3c24xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
int ret = 0;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
spin_lock(&prtd->lock);
@@ -297,7 +290,7 @@ s3c24xx_pcm_pointer(struct snd_pcm_substream *substream)
unsigned long res;
dma_addr_t src, dst;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
spin_lock(&prtd->lock);
s3c2410_dma_getposition(prtd->params->channel, &src, &dst);
@@ -309,7 +302,7 @@ s3c24xx_pcm_pointer(struct snd_pcm_substream *substream)
spin_unlock(&prtd->lock);
- DBG("Pointer %x %x\n", src, dst);
+ pr_debug("Pointer %x %x\n", src, dst);
/* we seem to be getting the odd error from the pcm library due
* to out-of-bounds pointers. this is maybe due to the dma engine
@@ -330,7 +323,7 @@ static int s3c24xx_pcm_open(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct s3c24xx_runtime_data *prtd;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware);
@@ -349,10 +342,10 @@ static int s3c24xx_pcm_close(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct s3c24xx_runtime_data *prtd = runtime->private_data;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
if (!prtd)
- DBG("s3c24xx_pcm_close called with prtd == NULL\n");
+ pr_debug("s3c24xx_pcm_close called with prtd == NULL\n");
kfree(prtd);
@@ -364,7 +357,7 @@ static int s3c24xx_pcm_mmap(struct snd_pcm_substream *substream,
{
struct snd_pcm_runtime *runtime = substream->runtime;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
return dma_mmap_writecombine(substream->pcm->card->dev, vma,
runtime->dma_area,
@@ -390,7 +383,7 @@ static int s3c24xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
struct snd_dma_buffer *buf = &substream->dma_buffer;
size_t size = s3c24xx_pcm_hardware.buffer_bytes_max;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
buf->dev.type = SNDRV_DMA_TYPE_DEV;
buf->dev.dev = pcm->card->dev;
@@ -409,7 +402,7 @@ static void s3c24xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
struct snd_dma_buffer *buf;
int stream;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
for (stream = 0; stream < 2; stream++) {
substream = pcm->streams[stream].substream;
@@ -433,7 +426,7 @@ static int s3c24xx_pcm_new(struct snd_card *card,
{
int ret = 0;
- DBG("Entered %s\n", __func__);
+ pr_debug("Entered %s\n", __func__);
if (!card->dev->dma_mask)
card->dev->dma_mask = &s3c24xx_pcm_dmamask;
diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c
index a0a4d1832a1..8e79a416db5 100644
--- a/sound/soc/s3c24xx/s3c24xx_uda134x.c
+++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c
@@ -22,7 +22,7 @@
#include <sound/s3c24xx_uda134x.h>
#include <sound/uda134x.h>
-#include <asm/plat-s3c24xx/regs-iis.h>
+#include <plat/regs-iis.h>
#include "s3c24xx-pcm.h"
#include "s3c24xx-i2s.h"
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c
new file mode 100644
index 00000000000..33c5de7e255
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.c
@@ -0,0 +1,222 @@
+/* sound/soc/s3c24xx/s3c64xx-i2s.c
+ *
+ * ALSA SoC Audio Layer - S3C64XX I2S driver
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ * http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <plat/regs-s3c2412-iis.h>
+#include <plat/gpio-bank-d.h>
+#include <plat/gpio-bank-e.h>
+#include <plat/gpio-cfg.h>
+#include <plat/audio.h>
+
+#include <mach/map.h>
+#include <mach/dma.h>
+
+#include "s3c24xx-pcm.h"
+#include "s3c64xx-i2s.h"
+
+static struct s3c2410_dma_client s3c64xx_dma_client_out = {
+ .name = "I2S PCM Stereo out"
+};
+
+static struct s3c2410_dma_client s3c64xx_dma_client_in = {
+ .name = "I2S PCM Stereo in"
+};
+
+static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_out[2] = {
+ [0] = {
+ .channel = DMACH_I2S0_OUT,
+ .client = &s3c64xx_dma_client_out,
+ .dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISTXD,
+ .dma_size = 4,
+ },
+ [1] = {
+ .channel = DMACH_I2S1_OUT,
+ .client = &s3c64xx_dma_client_out,
+ .dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISTXD,
+ .dma_size = 4,
+ },
+};
+
+static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_in[2] = {
+ [0] = {
+ .channel = DMACH_I2S0_IN,
+ .client = &s3c64xx_dma_client_in,
+ .dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISRXD,
+ .dma_size = 4,
+ },
+ [1] = {
+ .channel = DMACH_I2S1_IN,
+ .client = &s3c64xx_dma_client_in,
+ .dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISRXD,
+ .dma_size = 4,
+ },
+};
+
+static struct s3c_i2sv2_info s3c64xx_i2s[2];
+
+static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
+{
+ return cpu_dai->private_data;
+}
+
+static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+ u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
+
+ switch (clk_id) {
+ case S3C64XX_CLKSRC_PCLK:
+ iismod &= ~S3C64XX_IISMOD_IMS_SYSMUX;
+ break;
+
+ case S3C64XX_CLKSRC_MUX:
+ iismod |= S3C64XX_IISMOD_IMS_SYSMUX;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ writel(iismod, i2s->regs + S3C2412_IISMOD);
+
+ return 0;
+}
+
+
+unsigned long s3c64xx_i2s_get_clockrate(struct snd_soc_dai *dai)
+{
+ struct s3c_i2sv2_info *i2s = to_info(dai);
+
+ return clk_get_rate(i2s->iis_cclk);
+}
+EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clockrate);
+
+static int s3c64xx_i2s_probe(struct platform_device *pdev,
+ struct snd_soc_dai *dai)
+{
+ struct device *dev = &pdev->dev;
+ struct s3c_i2sv2_info *i2s;
+ int ret;
+
+ dev_dbg(dev, "%s: probing dai %d\n", __func__, pdev->id);
+
+ if (pdev->id < 0 || pdev->id > ARRAY_SIZE(s3c64xx_i2s)) {
+ dev_err(dev, "id %d out of range\n", pdev->id);
+ return -EINVAL;
+ }
+
+ i2s = &s3c64xx_i2s[pdev->id];
+
+ ret = s3c_i2sv2_probe(pdev, dai, i2s,
+ pdev->id ? S3C64XX_PA_IIS1 : S3C64XX_PA_IIS0);
+ if (ret)
+ return ret;
+
+ i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id];
+ i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id];
+
+ i2s->iis_cclk = clk_get(dev, "audio-bus");
+ if (IS_ERR(i2s->iis_cclk)) {
+ dev_err(dev, "failed to get audio-bus");
+ iounmap(i2s->regs);
+ return -ENODEV;
+ }
+
+ /* configure GPIO for i2s port */
+ switch (pdev->id) {
+ case 0:
+ s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_I2S0_CLK);
+ s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_I2S0_CDCLK);
+ s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_I2S0_LRCLK);
+ s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_I2S0_DI);
+ s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_I2S0_D0);
+ break;
+ case 1:
+ s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_I2S1_CLK);
+ s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_I2S1_CDCLK);
+ s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_I2S1_LRCLK);
+ s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI);
+ s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0);
+ }
+
+ return 0;
+}
+
+
+#define S3C64XX_I2S_RATES \
+ (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define S3C64XX_I2S_FMTS \
+ (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE)
+
+static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops = {
+ .set_sysclk = s3c64xx_i2s_set_sysclk,
+};
+
+struct snd_soc_dai s3c64xx_i2s_dai = {
+ .name = "s3c64xx-i2s",
+ .id = 0,
+ .probe = s3c64xx_i2s_probe,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C64XX_I2S_RATES,
+ .formats = S3C64XX_I2S_FMTS,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = S3C64XX_I2S_RATES,
+ .formats = S3C64XX_I2S_FMTS,
+ },
+ .ops = &s3c64xx_i2s_dai_ops,
+};
+EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai);
+
+static int __init s3c64xx_i2s_init(void)
+{
+ return s3c_i2sv2_register_dai(&s3c64xx_i2s_dai);
+}
+module_init(s3c64xx_i2s_init);
+
+static void __exit s3c64xx_i2s_exit(void)
+{
+ snd_soc_unregister_dai(&s3c64xx_i2s_dai);
+}
+module_exit(s3c64xx_i2s_exit);
+
+/* Module information */
+MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("S3C64XX I2S SoC Interface");
+MODULE_LICENSE("GPL");
+
+
+
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h
new file mode 100644
index 00000000000..b7ffe3c38b6
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.h
@@ -0,0 +1,31 @@
+/* sound/soc/s3c24xx/s3c64xx-i2s.h
+ *
+ * ALSA SoC Audio Layer - S3C64XX I2S driver
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ * http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __SND_SOC_S3C24XX_S3C64XX_I2S_H
+#define __SND_SOC_S3C24XX_S3C64XX_I2S_H __FILE__
+
+#include "s3c-i2s-v2.h"
+
+#define S3C64XX_DIV_BCLK S3C_I2SV2_DIV_BCLK
+#define S3C64XX_DIV_RCLK S3C_I2SV2_DIV_RCLK
+#define S3C64XX_DIV_PRESCALER S3C_I2SV2_DIV_PRESCALER
+
+#define S3C64XX_CLKSRC_PCLK (0)
+#define S3C64XX_CLKSRC_MUX (1)
+
+extern struct snd_soc_dai s3c64xx_i2s_dai;
+
+extern unsigned long s3c64xx_i2s_get_clockrate(struct snd_soc_dai *cpu_dai);
+
+#endif /* __SND_SOC_S3C24XX_S3C64XX_I2S_H */
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c
index eab31838bad..41db75af3c6 100644
--- a/sound/soc/sh/hac.c
+++ b/sound/soc/sh/hac.c
@@ -267,6 +267,10 @@ static int hac_hw_params(struct snd_pcm_substream *substream,
#define AC97_FMTS \
SNDRV_PCM_FMTBIT_S16_LE
+static struct snd_soc_dai_ops hac_dai_ops = {
+ .hw_params = hac_hw_params,
+};
+
struct snd_soc_dai sh4_hac_dai[] = {
{
.name = "HAC0",
@@ -284,9 +288,7 @@ struct snd_soc_dai sh4_hac_dai[] = {
.channels_min = 2,
.channels_max = 2,
},
- .ops = {
- .hw_params = hac_hw_params,
- },
+ .ops = &hac_dai_ops,
},
#ifdef CONFIG_CPU_SUBTYPE_SH7760
{
@@ -305,9 +307,7 @@ struct snd_soc_dai sh4_hac_dai[] = {
.channels_min = 2,
.channels_max = 2,
},
- .ops = {
- .hw_params = hac_hw_params,
- },
+ .ops = &hac_dai_ops,
},
#endif
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c
index d1e5390fdde..56fa0872abb 100644
--- a/sound/soc/sh/ssi.c
+++ b/sound/soc/sh/ssi.c
@@ -336,6 +336,16 @@ static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE | \
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE)
+static struct snd_soc_dai_ops ssi_dai_ops = {
+ .startup = ssi_startup,
+ .shutdown = ssi_shutdown,
+ .trigger = ssi_trigger,
+ .hw_params = ssi_hw_params,
+ .set_sysclk = ssi_set_sysclk,
+ .set_clkdiv = ssi_set_clkdiv,
+ .set_fmt = ssi_set_fmt,
+};
+
struct snd_soc_dai sh4_ssi_dai[] = {
{
.name = "SSI0",
@@ -352,15 +362,7 @@ struct snd_soc_dai sh4_ssi_dai[] = {
.channels_min = 2,
.channels_max = 8,
},
- .ops = {
- .startup = ssi_startup,
- .shutdown = ssi_shutdown,
- .trigger = ssi_trigger,
- .hw_params = ssi_hw_params,
- .set_sysclk = ssi_set_sysclk,
- .set_clkdiv = ssi_set_clkdiv,
- .set_fmt = ssi_set_fmt,
- },
+ .ops = &ssi_dai_ops,
},
#ifdef CONFIG_CPU_SUBTYPE_SH7760
{
@@ -378,15 +380,7 @@ struct snd_soc_dai sh4_ssi_dai[] = {
.channels_min = 2,
.channels_max = 8,
},
- .ops = {
- .startup = ssi_startup,
- .shutdown = ssi_shutdown,
- .trigger = ssi_trigger,
- .hw_params = ssi_hw_params,
- .set_sysclk = ssi_set_sysclk,
- .set_clkdiv = ssi_set_clkdiv,
- .set_fmt = ssi_set_fmt,
- },
+ .ops = &ssi_dai_ops,
},
#endif
};
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 55fdb4abb17..6e710f705a7 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -133,8 +133,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
mutex_lock(&pcm_mutex);
/* startup the audio subsystem */
- if (cpu_dai->ops.startup) {
- ret = cpu_dai->ops.startup(substream, cpu_dai);
+ if (cpu_dai->ops->startup) {
+ ret = cpu_dai->ops->startup(substream, cpu_dai);
if (ret < 0) {
printk(KERN_ERR "asoc: can't open interface %s\n",
cpu_dai->name);
@@ -150,8 +150,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
}
}
- if (codec_dai->ops.startup) {
- ret = codec_dai->ops.startup(substream, codec_dai);
+ if (codec_dai->ops->startup) {
+ ret = codec_dai->ops->startup(substream, codec_dai);
if (ret < 0) {
printk(KERN_ERR "asoc: can't open codec %s\n",
codec_dai->name);
@@ -234,7 +234,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
cpu_dai->capture.active = codec_dai->capture.active = 1;
cpu_dai->active = codec_dai->active = 1;
cpu_dai->runtime = runtime;
- socdev->codec->active++;
+ card->codec->active++;
mutex_unlock(&pcm_mutex);
return 0;
@@ -247,8 +247,8 @@ codec_dai_err:
platform->pcm_ops->close(substream);
platform_err:
- if (cpu_dai->ops.shutdown)
- cpu_dai->ops.shutdown(substream, cpu_dai);
+ if (cpu_dai->ops->shutdown)
+ cpu_dai->ops->shutdown(substream, cpu_dai);
out:
mutex_unlock(&pcm_mutex);
return ret;
@@ -264,7 +264,7 @@ static void close_delayed_work(struct work_struct *work)
struct snd_soc_card *card = container_of(work, struct snd_soc_card,
delayed_work.work);
struct snd_soc_device *socdev = card->socdev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = card->codec;
struct snd_soc_dai *codec_dai;
int i;
@@ -319,7 +319,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
struct snd_soc_platform *platform = card->platform;
struct snd_soc_dai *cpu_dai = machine->cpu_dai;
struct snd_soc_dai *codec_dai = machine->codec_dai;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = card->codec;
mutex_lock(&pcm_mutex);
@@ -340,11 +340,11 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
snd_soc_dai_digital_mute(codec_dai, 1);
- if (cpu_dai->ops.shutdown)
- cpu_dai->ops.shutdown(substream, cpu_dai);
+ if (cpu_dai->ops->shutdown)
+ cpu_dai->ops->shutdown(substream, cpu_dai);
- if (codec_dai->ops.shutdown)
- codec_dai->ops.shutdown(substream, codec_dai);
+ if (codec_dai->ops->shutdown)
+ codec_dai->ops->shutdown(substream, codec_dai);
if (machine->ops && machine->ops->shutdown)
machine->ops->shutdown(substream);
@@ -387,7 +387,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
struct snd_soc_platform *platform = card->platform;
struct snd_soc_dai *cpu_dai = machine->cpu_dai;
struct snd_soc_dai *codec_dai = machine->codec_dai;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = card->codec;
int ret = 0;
mutex_lock(&pcm_mutex);
@@ -408,16 +408,16 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
}
}
- if (codec_dai->ops.prepare) {
- ret = codec_dai->ops.prepare(substream, codec_dai);
+ if (codec_dai->ops->prepare) {
+ ret = codec_dai->ops->prepare(substream, codec_dai);
if (ret < 0) {
printk(KERN_ERR "asoc: codec DAI prepare error\n");
goto out;
}
}
- if (cpu_dai->ops.prepare) {
- ret = cpu_dai->ops.prepare(substream, cpu_dai);
+ if (cpu_dai->ops->prepare) {
+ ret = cpu_dai->ops->prepare(substream, cpu_dai);
if (ret < 0) {
printk(KERN_ERR "asoc: cpu DAI prepare error\n");
goto out;
@@ -494,8 +494,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
}
}
- if (codec_dai->ops.hw_params) {
- ret = codec_dai->ops.hw_params(substream, params, codec_dai);
+ if (codec_dai->ops->hw_params) {
+ ret = codec_dai->ops->hw_params(substream, params, codec_dai);
if (ret < 0) {
printk(KERN_ERR "asoc: can't set codec %s hw params\n",
codec_dai->name);
@@ -503,8 +503,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
}
}
- if (cpu_dai->ops.hw_params) {
- ret = cpu_dai->ops.hw_params(substream, params, cpu_dai);
+ if (cpu_dai->ops->hw_params) {
+ ret = cpu_dai->ops->hw_params(substream, params, cpu_dai);
if (ret < 0) {
printk(KERN_ERR "asoc: interface %s hw params failed\n",
cpu_dai->name);
@@ -526,12 +526,12 @@ out:
return ret;
platform_err:
- if (cpu_dai->ops.hw_free)
- cpu_dai->ops.hw_free(substream, cpu_dai);
+ if (cpu_dai->ops->hw_free)
+ cpu_dai->ops->hw_free(substream, cpu_dai);
interface_err:
- if (codec_dai->ops.hw_free)
- codec_dai->ops.hw_free(substream, codec_dai);
+ if (codec_dai->ops->hw_free)
+ codec_dai->ops->hw_free(substream, codec_dai);
codec_err:
if (machine->ops && machine->ops->hw_free)
@@ -553,7 +553,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
struct snd_soc_platform *platform = card->platform;
struct snd_soc_dai *cpu_dai = machine->cpu_dai;
struct snd_soc_dai *codec_dai = machine->codec_dai;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = card->codec;
mutex_lock(&pcm_mutex);
@@ -570,11 +570,11 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
platform->pcm_ops->hw_free(substream);
/* now free hw params for the DAI's */
- if (codec_dai->ops.hw_free)
- codec_dai->ops.hw_free(substream, codec_dai);
+ if (codec_dai->ops->hw_free)
+ codec_dai->ops->hw_free(substream, codec_dai);
- if (cpu_dai->ops.hw_free)
- cpu_dai->ops.hw_free(substream, cpu_dai);
+ if (cpu_dai->ops->hw_free)
+ cpu_dai->ops->hw_free(substream, cpu_dai);
mutex_unlock(&pcm_mutex);
return 0;
@@ -591,8 +591,8 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
struct snd_soc_dai *codec_dai = machine->codec_dai;
int ret;
- if (codec_dai->ops.trigger) {
- ret = codec_dai->ops.trigger(substream, cmd, codec_dai);
+ if (codec_dai->ops->trigger) {
+ ret = codec_dai->ops->trigger(substream, cmd, codec_dai);
if (ret < 0)
return ret;
}
@@ -603,8 +603,8 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
return ret;
}
- if (cpu_dai->ops.trigger) {
- ret = cpu_dai->ops.trigger(substream, cmd, cpu_dai);
+ if (cpu_dai->ops->trigger) {
+ ret = cpu_dai->ops->trigger(substream, cmd, cpu_dai);
if (ret < 0)
return ret;
}
@@ -629,7 +629,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state)
struct snd_soc_card *card = socdev->card;
struct snd_soc_platform *platform = card->platform;
struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = card->codec;
int i;
/* Due to the resume being scheduled into a workqueue we could
@@ -645,8 +645,8 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state)
/* mute any active DAC's */
for (i = 0; i < card->num_links; i++) {
struct snd_soc_dai *dai = card->dai_link[i].codec_dai;
- if (dai->ops.digital_mute && dai->playback.active)
- dai->ops.digital_mute(dai, 1);
+ if (dai->ops->digital_mute && dai->playback.active)
+ dai->ops->digital_mute(dai, 1);
}
/* suspend all pcms */
@@ -705,7 +705,7 @@ static void soc_resume_deferred(struct work_struct *work)
struct snd_soc_device *socdev = card->socdev;
struct snd_soc_platform *platform = card->platform;
struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = card->codec;
struct platform_device *pdev = to_platform_device(socdev->dev);
int i;
@@ -741,8 +741,8 @@ static void soc_resume_deferred(struct work_struct *work)
/* unmute any active DACs */
for (i = 0; i < card->num_links; i++) {
struct snd_soc_dai *dai = card->dai_link[i].codec_dai;
- if (dai->ops.digital_mute && dai->playback.active)
- dai->ops.digital_mute(dai, 0);
+ if (dai->ops->digital_mute && dai->playback.active)
+ dai->ops->digital_mute(dai, 0);
}
for (i = 0; i < card->num_links; i++) {
@@ -982,8 +982,8 @@ static struct platform_driver soc_driver = {
static int soc_new_pcm(struct snd_soc_device *socdev,
struct snd_soc_dai_link *dai_link, int num)
{
- struct snd_soc_codec *codec = socdev->codec;
struct snd_soc_card *card = socdev->card;
+ struct snd_soc_codec *codec = card->codec;
struct snd_soc_platform *platform = card->platform;
struct snd_soc_dai *codec_dai = dai_link->codec_dai;
struct snd_soc_dai *cpu_dai = dai_link->cpu_dai;
@@ -998,7 +998,7 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
rtd->dai = dai_link;
rtd->socdev = socdev;
- codec_dai->codec = socdev->codec;
+ codec_dai->codec = card->codec;
/* check client and interface hw capabilities */
sprintf(new_name, "%s %s-%d", dai_link->stream_name, codec_dai->name,
@@ -1048,9 +1048,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
}
/* codec register dump */
-static ssize_t soc_codec_reg_show(struct snd_soc_device *devdata, char *buf)
+static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
{
- struct snd_soc_codec *codec = devdata->codec;
int i, step = 1, count = 0;
if (!codec->reg_cache_size)
@@ -1090,7 +1089,7 @@ static ssize_t codec_reg_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_soc_device *devdata = dev_get_drvdata(dev);
- return soc_codec_reg_show(devdata, buf);
+ return soc_codec_reg_show(devdata->card->codec, buf);
}
static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
@@ -1107,12 +1106,10 @@ static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf,
{
ssize_t ret;
struct snd_soc_codec *codec = file->private_data;
- struct device *card_dev = codec->card->dev;
- struct snd_soc_device *devdata = card_dev->driver_data;
char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- ret = soc_codec_reg_show(devdata, buf);
+ ret = soc_codec_reg_show(codec, buf);
if (ret >= 0)
ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
kfree(buf);
@@ -1309,19 +1306,19 @@ EXPORT_SYMBOL_GPL(snd_soc_test_bits);
*/
int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid)
{
- struct snd_soc_codec *codec = socdev->codec;
struct snd_soc_card *card = socdev->card;
- int ret = 0, i;
+ struct snd_soc_codec *codec = card->codec;
+ int ret, i;
mutex_lock(&codec->mutex);
/* register a sound card */
- codec->card = snd_card_new(idx, xid, codec->owner, 0);
- if (!codec->card) {
+ ret = snd_card_create(idx, xid, codec->owner, 0, &codec->card);
+ if (ret < 0) {
printk(KERN_ERR "asoc: can't create sound card for codec %s\n",
codec->name);
mutex_unlock(&codec->mutex);
- return -ENODEV;
+ return ret;
}
codec->card->dev = socdev->dev;
@@ -1355,8 +1352,8 @@ EXPORT_SYMBOL_GPL(snd_soc_new_pcms);
*/
int snd_soc_init_card(struct snd_soc_device *socdev)
{
- struct snd_soc_codec *codec = socdev->codec;
struct snd_soc_card *card = socdev->card;
+ struct snd_soc_codec *codec = card->codec;
int ret = 0, i, ac97 = 0, err = 0;
for (i = 0; i < card->num_links; i++) {
@@ -1385,7 +1382,10 @@ int snd_soc_init_card(struct snd_soc_device *socdev)
mutex_lock(&codec->mutex);
#ifdef CONFIG_SND_SOC_AC97_BUS
- if (ac97) {
+ /* Only instantiate AC97 if not already done by the adaptor
+ * for the generic AC97 subsystem.
+ */
+ if (ac97 && strcmp(codec->name, "AC97") != 0) {
ret = soc_ac97_dev_register(codec);
if (ret < 0) {
printk(KERN_ERR "asoc: AC97 device register failed\n");
@@ -1404,7 +1404,7 @@ int snd_soc_init_card(struct snd_soc_device *socdev)
if (err < 0)
printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
- soc_init_codec_debugfs(socdev->codec);
+ soc_init_codec_debugfs(codec);
mutex_unlock(&codec->mutex);
out:
@@ -1421,18 +1421,19 @@ EXPORT_SYMBOL_GPL(snd_soc_init_card);
*/
void snd_soc_free_pcms(struct snd_soc_device *socdev)
{
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
#ifdef CONFIG_SND_SOC_AC97_BUS
struct snd_soc_dai *codec_dai;
int i;
#endif
mutex_lock(&codec->mutex);
- soc_cleanup_codec_debugfs(socdev->codec);
+ soc_cleanup_codec_debugfs(codec);
#ifdef CONFIG_SND_SOC_AC97_BUS
for (i = 0; i < codec->num_dai; i++) {
codec_dai = &codec->dai[i];
- if (codec_dai->ac97_control && codec->ac97) {
+ if (codec_dai->ac97_control && codec->ac97 &&
+ strcmp(codec->name, "AC97") != 0) {
soc_ac97_dev_unregister(codec);
goto free_card;
}
@@ -1495,6 +1496,37 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
EXPORT_SYMBOL_GPL(snd_soc_cnew);
/**
+ * snd_soc_add_controls - add an array of controls to a codec.
+ * Convienience function to add a list of controls. Many codecs were
+ * duplicating this code.
+ *
+ * @codec: codec to add controls to
+ * @controls: array of controls to add
+ * @num_controls: number of elements in the array
+ *
+ * Return 0 for success, else error.
+ */
+int snd_soc_add_controls(struct snd_soc_codec *codec,
+ const struct snd_kcontrol_new *controls, int num_controls)
+{
+ struct snd_card *card = codec->card;
+ int err, i;
+
+ for (i = 0; i < num_controls; i++) {
+ const struct snd_kcontrol_new *control = &controls[i];
+ err = snd_ctl_add(card, snd_soc_cnew(control, codec, NULL));
+ if (err < 0) {
+ dev_err(codec->dev, "%s: Failed to add %s\n",
+ codec->name, control->name);
+ return err;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_add_controls);
+
+/**
* snd_soc_info_enum_double - enumerated double mixer info callback
* @kcontrol: mixer control
* @uinfo: control element information
@@ -2020,8 +2052,8 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8);
int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
- if (dai->ops.set_sysclk)
- return dai->ops.set_sysclk(dai, clk_id, freq, dir);
+ if (dai->ops->set_sysclk)
+ return dai->ops->set_sysclk(dai, clk_id, freq, dir);
else
return -EINVAL;
}
@@ -2040,8 +2072,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
int div_id, int div)
{
- if (dai->ops.set_clkdiv)
- return dai->ops.set_clkdiv(dai, div_id, div);
+ if (dai->ops->set_clkdiv)
+ return dai->ops->set_clkdiv(dai, div_id, div);
else
return -EINVAL;
}
@@ -2059,8 +2091,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
int pll_id, unsigned int freq_in, unsigned int freq_out)
{
- if (dai->ops.set_pll)
- return dai->ops.set_pll(dai, pll_id, freq_in, freq_out);
+ if (dai->ops->set_pll)
+ return dai->ops->set_pll(dai, pll_id, freq_in, freq_out);
else
return -EINVAL;
}
@@ -2075,8 +2107,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
*/
int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
- if (dai->ops.set_fmt)
- return dai->ops.set_fmt(dai, fmt);
+ if (dai->ops->set_fmt)
+ return dai->ops->set_fmt(dai, fmt);
else
return -EINVAL;
}
@@ -2094,8 +2126,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
unsigned int mask, int slots)
{
- if (dai->ops.set_sysclk)
- return dai->ops.set_tdm_slot(dai, mask, slots);
+ if (dai->ops->set_sysclk)
+ return dai->ops->set_tdm_slot(dai, mask, slots);
else
return -EINVAL;
}
@@ -2110,8 +2142,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
*/
int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
{
- if (dai->ops.set_sysclk)
- return dai->ops.set_tristate(dai, tristate);
+ if (dai->ops->set_sysclk)
+ return dai->ops->set_tristate(dai, tristate);
else
return -EINVAL;
}
@@ -2126,8 +2158,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
*/
int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute)
{
- if (dai->ops.digital_mute)
- return dai->ops.digital_mute(dai, mute);
+ if (dai->ops->digital_mute)
+ return dai->ops->digital_mute(dai, mute);
else
return -EINVAL;
}
@@ -2180,6 +2212,9 @@ static int snd_soc_unregister_card(struct snd_soc_card *card)
return 0;
}
+static struct snd_soc_dai_ops null_dai_ops = {
+};
+
/**
* snd_soc_register_dai - Register a DAI with the ASoC core
*
@@ -2194,6 +2229,9 @@ int snd_soc_register_dai(struct snd_soc_dai *dai)
if (!dai->dev)
printk(KERN_WARNING "No device for DAI %s\n", dai->name);
+ if (!dai->ops)
+ dai->ops = &null_dai_ops;
+
INIT_LIST_HEAD(&dai->list);
mutex_lock(&client_mutex);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index a2f1da8b464..735903a7467 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -54,14 +54,15 @@
static int dapm_up_seq[] = {
snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic,
snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_dac,
- snd_soc_dapm_mixer, snd_soc_dapm_pga, snd_soc_dapm_adc, snd_soc_dapm_hp,
- snd_soc_dapm_spk, snd_soc_dapm_post
+ snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_pga,
+ snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post
};
+
static int dapm_down_seq[] = {
snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
- snd_soc_dapm_pga, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic,
- snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_value_mux,
- snd_soc_dapm_post
+ snd_soc_dapm_pga, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_mixer,
+ snd_soc_dapm_dac, snd_soc_dapm_mic, snd_soc_dapm_micbias,
+ snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_post
};
static int dapm_status = 1;
@@ -101,7 +102,8 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
{
switch (w->id) {
case snd_soc_dapm_switch:
- case snd_soc_dapm_mixer: {
+ case snd_soc_dapm_mixer:
+ case snd_soc_dapm_mixer_named_ctl: {
int val;
struct soc_mixer_control *mc = (struct soc_mixer_control *)
w->kcontrols[i].private_value;
@@ -323,15 +325,32 @@ static int dapm_new_mixer(struct snd_soc_codec *codec,
if (path->name != (char*)w->kcontrols[i].name)
continue;
- /* add dapm control with long name */
- name_len = 2 + strlen(w->name)
- + strlen(w->kcontrols[i].name);
+ /* add dapm control with long name.
+ * for dapm_mixer this is the concatenation of the
+ * mixer and kcontrol name.
+ * for dapm_mixer_named_ctl this is simply the
+ * kcontrol name.
+ */
+ name_len = strlen(w->kcontrols[i].name) + 1;
+ if (w->id != snd_soc_dapm_mixer_named_ctl)
+ name_len += 1 + strlen(w->name);
+
path->long_name = kmalloc(name_len, GFP_KERNEL);
+
if (path->long_name == NULL)
return -ENOMEM;
- snprintf(path->long_name, name_len, "%s %s",
- w->name, w->kcontrols[i].name);
+ switch (w->id) {
+ default:
+ snprintf(path->long_name, name_len, "%s %s",
+ w->name, w->kcontrols[i].name);
+ break;
+ case snd_soc_dapm_mixer_named_ctl:
+ snprintf(path->long_name, name_len, "%s",
+ w->kcontrols[i].name);
+ break;
+ }
+
path->long_name[name_len - 1] = '\0';
path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w,
@@ -503,6 +522,137 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w,
EXPORT_SYMBOL_GPL(dapm_reg_event);
/*
+ * Scan a single DAPM widget for a complete audio path and update the
+ * power status appropriately.
+ */
+static int dapm_power_widget(struct snd_soc_codec *codec, int event,
+ struct snd_soc_dapm_widget *w)
+{
+ int in, out, power_change, power, ret;
+
+ /* vmid - no action */
+ if (w->id == snd_soc_dapm_vmid)
+ return 0;
+
+ /* active ADC */
+ if (w->id == snd_soc_dapm_adc && w->active) {
+ in = is_connected_input_ep(w);
+ dapm_clear_walk(w->codec);
+ w->power = (in != 0) ? 1 : 0;
+ dapm_update_bits(w);
+ return 0;
+ }
+
+ /* active DAC */
+ if (w->id == snd_soc_dapm_dac && w->active) {
+ out = is_connected_output_ep(w);
+ dapm_clear_walk(w->codec);
+ w->power = (out != 0) ? 1 : 0;
+ dapm_update_bits(w);
+ return 0;
+ }
+
+ /* pre and post event widgets */
+ if (w->id == snd_soc_dapm_pre) {
+ if (!w->event)
+ return 0;
+
+ if (event == SND_SOC_DAPM_STREAM_START) {
+ ret = w->event(w,
+ NULL, SND_SOC_DAPM_PRE_PMU);
+ if (ret < 0)
+ return ret;
+ } else if (event == SND_SOC_DAPM_STREAM_STOP) {
+ ret = w->event(w,
+ NULL, SND_SOC_DAPM_PRE_PMD);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+ }
+ if (w->id == snd_soc_dapm_post) {
+ if (!w->event)
+ return 0;
+
+ if (event == SND_SOC_DAPM_STREAM_START) {
+ ret = w->event(w,
+ NULL, SND_SOC_DAPM_POST_PMU);
+ if (ret < 0)
+ return ret;
+ } else if (event == SND_SOC_DAPM_STREAM_STOP) {
+ ret = w->event(w,
+ NULL, SND_SOC_DAPM_POST_PMD);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+ }
+
+ /* all other widgets */
+ in = is_connected_input_ep(w);
+ dapm_clear_walk(w->codec);
+ out = is_connected_output_ep(w);
+ dapm_clear_walk(w->codec);
+ power = (out != 0 && in != 0) ? 1 : 0;
+ power_change = (w->power == power) ? 0 : 1;
+ w->power = power;
+
+ if (!power_change)
+ return 0;
+
+ /* call any power change event handlers */
+ if (w->event)
+ pr_debug("power %s event for %s flags %x\n",
+ w->power ? "on" : "off",
+ w->name, w->event_flags);
+
+ /* power up pre event */
+ if (power && w->event &&
+ (w->event_flags & SND_SOC_DAPM_PRE_PMU)) {
+ ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* power down pre event */
+ if (!power && w->event &&
+ (w->event_flags & SND_SOC_DAPM_PRE_PMD)) {
+ ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Lower PGA volume to reduce pops */
+ if (w->id == snd_soc_dapm_pga && !power)
+ dapm_set_pga(w, power);
+
+ dapm_update_bits(w);
+
+ /* Raise PGA volume to reduce pops */
+ if (w->id == snd_soc_dapm_pga && power)
+ dapm_set_pga(w, power);
+
+ /* power up post event */
+ if (power && w->event &&
+ (w->event_flags & SND_SOC_DAPM_POST_PMU)) {
+ ret = w->event(w,
+ NULL, SND_SOC_DAPM_POST_PMU);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* power down post event */
+ if (!power && w->event &&
+ (w->event_flags & SND_SOC_DAPM_POST_PMD)) {
+ ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
* Scan each dapm widget for complete audio path.
* A complete path is a route that has valid endpoints i.e.:-
*
@@ -514,7 +664,7 @@ EXPORT_SYMBOL_GPL(dapm_reg_event);
static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
{
struct snd_soc_dapm_widget *w;
- int in, out, i, c = 1, *seq = NULL, ret = 0, power_change, power;
+ int i, c = 1, *seq = NULL, ret = 0;
/* do we have a sequenced stream event */
if (event == SND_SOC_DAPM_STREAM_START) {
@@ -525,135 +675,20 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
seq = dapm_down_seq;
}
- for(i = 0; i < c; i++) {
+ for (i = 0; i < c; i++) {
list_for_each_entry(w, &codec->dapm_widgets, list) {
/* is widget in stream order */
if (seq && seq[i] && w->id != seq[i])
continue;
- /* vmid - no action */
- if (w->id == snd_soc_dapm_vmid)
- continue;
-
- /* active ADC */
- if (w->id == snd_soc_dapm_adc && w->active) {
- in = is_connected_input_ep(w);
- dapm_clear_walk(w->codec);
- w->power = (in != 0) ? 1 : 0;
- dapm_update_bits(w);
- continue;
- }
-
- /* active DAC */
- if (w->id == snd_soc_dapm_dac && w->active) {
- out = is_connected_output_ep(w);
- dapm_clear_walk(w->codec);
- w->power = (out != 0) ? 1 : 0;
- dapm_update_bits(w);
- continue;
- }
-
- /* pre and post event widgets */
- if (w->id == snd_soc_dapm_pre) {
- if (!w->event)
- continue;
-
- if (event == SND_SOC_DAPM_STREAM_START) {
- ret = w->event(w,
- NULL, SND_SOC_DAPM_PRE_PMU);
- if (ret < 0)
- return ret;
- } else if (event == SND_SOC_DAPM_STREAM_STOP) {
- ret = w->event(w,
- NULL, SND_SOC_DAPM_PRE_PMD);
- if (ret < 0)
- return ret;
- }
- continue;
- }
- if (w->id == snd_soc_dapm_post) {
- if (!w->event)
- continue;
-
- if (event == SND_SOC_DAPM_STREAM_START) {
- ret = w->event(w,
- NULL, SND_SOC_DAPM_POST_PMU);
- if (ret < 0)
- return ret;
- } else if (event == SND_SOC_DAPM_STREAM_STOP) {
- ret = w->event(w,
- NULL, SND_SOC_DAPM_POST_PMD);
- if (ret < 0)
- return ret;
- }
- continue;
- }
-
- /* all other widgets */
- in = is_connected_input_ep(w);
- dapm_clear_walk(w->codec);
- out = is_connected_output_ep(w);
- dapm_clear_walk(w->codec);
- power = (out != 0 && in != 0) ? 1 : 0;
- power_change = (w->power == power) ? 0: 1;
- w->power = power;
-
- if (!power_change)
- continue;
-
- /* call any power change event handlers */
- if (w->event)
- pr_debug("power %s event for %s flags %x\n",
- w->power ? "on" : "off",
- w->name, w->event_flags);
-
- /* power up pre event */
- if (power && w->event &&
- (w->event_flags & SND_SOC_DAPM_PRE_PMU)) {
- ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU);
- if (ret < 0)
- return ret;
- }
-
- /* power down pre event */
- if (!power && w->event &&
- (w->event_flags & SND_SOC_DAPM_PRE_PMD)) {
- ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD);
- if (ret < 0)
- return ret;
- }
-
- /* Lower PGA volume to reduce pops */
- if (w->id == snd_soc_dapm_pga && !power)
- dapm_set_pga(w, power);
-
- dapm_update_bits(w);
-
- /* Raise PGA volume to reduce pops */
- if (w->id == snd_soc_dapm_pga && power)
- dapm_set_pga(w, power);
-
- /* power up post event */
- if (power && w->event &&
- (w->event_flags & SND_SOC_DAPM_POST_PMU)) {
- ret = w->event(w,
- NULL, SND_SOC_DAPM_POST_PMU);
- if (ret < 0)
- return ret;
- }
-
- /* power down post event */
- if (!power && w->event &&
- (w->event_flags & SND_SOC_DAPM_POST_PMD)) {
- ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD);
- if (ret < 0)
- return ret;
- }
+ ret = dapm_power_widget(codec, event, w);
+ if (ret != 0)
+ return ret;
}
}
- return ret;
+ return 0;
}
#ifdef DEBUG
@@ -687,6 +722,7 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action)
case snd_soc_dapm_adc:
case snd_soc_dapm_pga:
case snd_soc_dapm_mixer:
+ case snd_soc_dapm_mixer_named_ctl:
if (w->name) {
in = is_connected_input_ep(w);
dapm_clear_walk(w->codec);
@@ -760,6 +796,7 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
int found = 0;
if (widget->id != snd_soc_dapm_mixer &&
+ widget->id != snd_soc_dapm_mixer_named_ctl &&
widget->id != snd_soc_dapm_switch)
return -ENODEV;
@@ -795,7 +832,7 @@ static ssize_t dapm_widget_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_soc_device *devdata = dev_get_drvdata(dev);
- struct snd_soc_codec *codec = devdata->codec;
+ struct snd_soc_codec *codec = devdata->card->codec;
struct snd_soc_dapm_widget *w;
int count = 0;
char *state = "not set";
@@ -813,6 +850,7 @@ static ssize_t dapm_widget_show(struct device *dev,
case snd_soc_dapm_adc:
case snd_soc_dapm_pga:
case snd_soc_dapm_mixer:
+ case snd_soc_dapm_mixer_named_ctl:
if (w->name)
count += sprintf(buf + count, "%s: %s\n",
w->name, w->power ? "On":"Off");
@@ -876,7 +914,7 @@ static void dapm_free_widgets(struct snd_soc_codec *codec)
}
static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec,
- char *pin, int status)
+ const char *pin, int status)
{
struct snd_soc_dapm_widget *w;
@@ -991,6 +1029,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
break;
case snd_soc_dapm_switch:
case snd_soc_dapm_mixer:
+ case snd_soc_dapm_mixer_named_ctl:
ret = dapm_connect_mixer(codec, wsource, wsink, path, control);
if (ret != 0)
goto err;
@@ -1068,6 +1107,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
switch(w->id) {
case snd_soc_dapm_switch:
case snd_soc_dapm_mixer:
+ case snd_soc_dapm_mixer_named_ctl:
dapm_new_mixer(codec, w);
break;
case snd_soc_dapm_mux:
@@ -1396,6 +1436,76 @@ out:
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
/**
+ * snd_soc_dapm_info_pin_switch - Info for a pin switch
+ *
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information about a pin switch control.
+ */
+int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);
+
+/**
+ * snd_soc_dapm_get_pin_switch - Get information for a pin switch
+ *
+ * @kcontrol: mixer control
+ * @ucontrol: Value
+ */
+int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ const char *pin = (const char *)kcontrol->private_value;
+
+ mutex_lock(&codec->mutex);
+
+ ucontrol->value.integer.value[0] =
+ snd_soc_dapm_get_pin_status(codec, pin);
+
+ mutex_unlock(&codec->mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
+
+/**
+ * snd_soc_dapm_put_pin_switch - Set information for a pin switch
+ *
+ * @kcontrol: mixer control
+ * @ucontrol: Value
+ */
+int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ const char *pin = (const char *)kcontrol->private_value;
+
+ mutex_lock(&codec->mutex);
+
+ if (ucontrol->value.integer.value[0])
+ snd_soc_dapm_enable_pin(codec, pin);
+ else
+ snd_soc_dapm_disable_pin(codec, pin);
+
+ snd_soc_dapm_sync(codec);
+
+ mutex_unlock(&codec->mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
+
+/**
* snd_soc_dapm_new_control - create new dapm control
* @codec: audio codec
* @widget: widget template
@@ -1527,8 +1637,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
enum snd_soc_bias_level level)
{
- struct snd_soc_codec *codec = socdev->codec;
struct snd_soc_card *card = socdev->card;
+ struct snd_soc_codec *codec = socdev->card->codec;
int ret = 0;
if (card->set_bias_level)
@@ -1549,7 +1659,7 @@ int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
* NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
* do any widget power switching.
*/
-int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin)
+int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, const char *pin)
{
return snd_soc_dapm_set_pin(codec, pin, 1);
}
@@ -1564,7 +1674,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
* NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
* do any widget power switching.
*/
-int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin)
+int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, const char *pin)
{
return snd_soc_dapm_set_pin(codec, pin, 0);
}
@@ -1584,7 +1694,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
* NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
* do any widget power switching.
*/
-int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin)
+int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, const char *pin)
{
return snd_soc_dapm_set_pin(codec, pin, 0);
}
@@ -1599,7 +1709,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
*
* Returns 1 for connected otherwise 0.
*/
-int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin)
+int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, const char *pin)
{
struct snd_soc_dapm_widget *w;
@@ -1620,7 +1730,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
*/
void snd_soc_dapm_free(struct snd_soc_device *socdev)
{
- struct snd_soc_codec *codec = socdev->codec;
+ struct snd_soc_codec *codec = socdev->card->codec;
snd_soc_dapm_sys_remove(socdev->dev);
dapm_free_widgets(codec);
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
new file mode 100644
index 00000000000..28346fb2e70
--- /dev/null
+++ b/sound/soc/soc-jack.c
@@ -0,0 +1,267 @@
+/*
+ * soc-jack.c -- ALSA SoC jack handling
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+
+/**
+ * snd_soc_jack_new - Create a new jack
+ * @card: ASoC card
+ * @id: an identifying string for this jack
+ * @type: a bitmask of enum snd_jack_type values that can be detected by
+ * this jack
+ * @jack: structure to use for the jack
+ *
+ * Creates a new jack object.
+ *
+ * Returns zero if successful, or a negative error code on failure.
+ * On success jack will be initialised.
+ */
+int snd_soc_jack_new(struct snd_soc_card *card, const char *id, int type,
+ struct snd_soc_jack *jack)
+{
+ jack->card = card;
+ INIT_LIST_HEAD(&jack->pins);
+
+ return snd_jack_new(card->codec->card, id, type, &jack->jack);
+}
+EXPORT_SYMBOL_GPL(snd_soc_jack_new);
+
+/**
+ * snd_soc_jack_report - Report the current status for a jack
+ *
+ * @jack: the jack
+ * @status: a bitmask of enum snd_jack_type values that are currently detected.
+ * @mask: a bitmask of enum snd_jack_type values that being reported.
+ *
+ * If configured using snd_soc_jack_add_pins() then the associated
+ * DAPM pins will be enabled or disabled as appropriate and DAPM
+ * synchronised.
+ *
+ * Note: This function uses mutexes and should be called from a
+ * context which can sleep (such as a workqueue).
+ */
+void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
+{
+ struct snd_soc_codec *codec = jack->card->codec;
+ struct snd_soc_jack_pin *pin;
+ int enable;
+ int oldstatus;
+
+ if (!jack) {
+ WARN_ON_ONCE(!jack);
+ return;
+ }
+
+ mutex_lock(&codec->mutex);
+
+ oldstatus = jack->status;
+
+ jack->status &= ~mask;
+ jack->status |= status;
+
+ /* The DAPM sync is expensive enough to be worth skipping */
+ if (jack->status == oldstatus)
+ goto out;
+
+ list_for_each_entry(pin, &jack->pins, list) {
+ enable = pin->mask & status;
+
+ if (pin->invert)
+ enable = !enable;
+
+ if (enable)
+ snd_soc_dapm_enable_pin(codec, pin->pin);
+ else
+ snd_soc_dapm_disable_pin(codec, pin->pin);
+ }
+
+ snd_soc_dapm_sync(codec);
+
+ snd_jack_report(jack->jack, status);
+
+out:
+ mutex_unlock(&codec->mutex);
+}
+EXPORT_SYMBOL_GPL(snd_soc_jack_report);
+
+/**
+ * snd_soc_jack_add_pins - Associate DAPM pins with an ASoC jack
+ *
+ * @jack: ASoC jack
+ * @count: Number of pins
+ * @pins: Array of pins
+ *
+ * After this function has been called the DAPM pins specified in the
+ * pins array will have their status updated to reflect the current
+ * state of the jack whenever the jack status is updated.
+ */
+int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
+ struct snd_soc_jack_pin *pins)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (!pins[i].pin) {
+ printk(KERN_ERR "No name for pin %d\n", i);
+ return -EINVAL;
+ }
+ if (!pins[i].mask) {
+ printk(KERN_ERR "No mask for pin %d (%s)\n", i,
+ pins[i].pin);
+ return -EINVAL;
+ }
+
+ INIT_LIST_HEAD(&pins[i].list);
+ list_add(&(pins[i].list), &jack->pins);
+ }
+
+ /* Update to reflect the last reported status; canned jack
+ * implementations are likely to set their state before the
+ * card has an opportunity to associate pins.
+ */
+ snd_soc_jack_report(jack, 0, 0);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_jack_add_pins);
+
+#ifdef CONFIG_GPIOLIB
+/* gpio detect */
+static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio)
+{
+ struct snd_soc_jack *jack = gpio->jack;
+ int enable;
+ int report;
+
+ if (gpio->debounce_time > 0)
+ mdelay(gpio->debounce_time);
+
+ enable = gpio_get_value(gpio->gpio);
+ if (gpio->invert)
+ enable = !enable;
+
+ if (enable)
+ report = gpio->report;
+ else
+ report = 0;
+
+ snd_soc_jack_report(jack, report, gpio->report);
+}
+
+/* irq handler for gpio pin */
+static irqreturn_t gpio_handler(int irq, void *data)
+{
+ struct snd_soc_jack_gpio *gpio = data;
+
+ schedule_work(&gpio->work);
+
+ return IRQ_HANDLED;
+}
+
+/* gpio work */
+static void gpio_work(struct work_struct *work)
+{
+ struct snd_soc_jack_gpio *gpio;
+
+ gpio = container_of(work, struct snd_soc_jack_gpio, work);
+ snd_soc_jack_gpio_detect(gpio);
+}
+
+/**
+ * snd_soc_jack_add_gpios - Associate GPIO pins with an ASoC jack
+ *
+ * @jack: ASoC jack
+ * @count: number of pins
+ * @gpios: array of gpio pins
+ *
+ * This function will request gpio, set data direction and request irq
+ * for each gpio in the array.
+ */
+int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
+ struct snd_soc_jack_gpio *gpios)
+{
+ int i, ret;
+
+ for (i = 0; i < count; i++) {
+ if (!gpio_is_valid(gpios[i].gpio)) {
+ printk(KERN_ERR "Invalid gpio %d\n",
+ gpios[i].gpio);
+ ret = -EINVAL;
+ goto undo;
+ }
+ if (!gpios[i].name) {
+ printk(KERN_ERR "No name for gpio %d\n",
+ gpios[i].gpio);
+ ret = -EINVAL;
+ goto undo;
+ }
+
+ ret = gpio_request(gpios[i].gpio, gpios[i].name);
+ if (ret)
+ goto undo;
+
+ ret = gpio_direction_input(gpios[i].gpio);
+ if (ret)
+ goto err;
+
+ ret = request_irq(gpio_to_irq(gpios[i].gpio),
+ gpio_handler,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ jack->card->dev->driver->name,
+ &gpios[i]);
+ if (ret)
+ goto err;
+
+ INIT_WORK(&gpios[i].work, gpio_work);
+ gpios[i].jack = jack;
+ }
+
+ return 0;
+
+err:
+ gpio_free(gpios[i].gpio);
+undo:
+ snd_soc_jack_free_gpios(jack, i, gpios);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_jack_add_gpios);
+
+/**
+ * snd_soc_jack_free_gpios - Release GPIO pins' resources of an ASoC jack
+ *
+ * @jack: ASoC jack
+ * @count: number of pins
+ * @gpios: array of gpio pins
+ *
+ * Release gpio and irq resources for gpio pins associated with an ASoC jack.
+ */
+void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
+ struct snd_soc_jack_gpio *gpios)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ free_irq(gpio_to_irq(gpios[i].gpio), &gpios[i]);
+ gpio_free(gpios[i].gpio);
+ gpios[i].jack = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(snd_soc_jack_free_gpios);
+#endif /* CONFIG_GPIOLIB */
diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c
index f87933e4881..574af56ba8a 100644
--- a/sound/sparc/amd7930.c
+++ b/sound/sparc/amd7930.c
@@ -954,7 +954,8 @@ static int __devinit snd_amd7930_create(struct snd_card *card,
amd->regs = of_ioremap(&op->resource[0], 0,
resource_size(&op->resource[0]), "amd7930");
if (!amd->regs) {
- snd_printk("amd7930-%d: Unable to map chip registers.\n", dev);
+ snd_printk(KERN_ERR
+ "amd7930-%d: Unable to map chip registers.\n", dev);
return -EIO;
}
@@ -962,7 +963,7 @@ static int __devinit snd_amd7930_create(struct snd_card *card,
if (request_irq(irq, snd_amd7930_interrupt,
IRQF_DISABLED | IRQF_SHARED, "amd7930", amd)) {
- snd_printk("amd7930-%d: Unable to grab IRQ %d\n",
+ snd_printk(KERN_ERR "amd7930-%d: Unable to grab IRQ %d\n",
dev, irq);
snd_amd7930_free(amd);
return -EBUSY;
@@ -1018,9 +1019,10 @@ static int __devinit amd7930_sbus_probe(struct of_device *op, const struct of_de
return -ENOENT;
}
- card = snd_card_new(index[dev_num], id[dev_num], THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev_num], id[dev_num], THIS_MODULE, 0,
+ &card);
+ if (err < 0)
+ return err;
strcpy(card->driver, "AMD7930");
strcpy(card->shortname, "Sun AMD7930");
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c
index 41c38758747..7d93fa705cc 100644
--- a/sound/sparc/cs4231.c
+++ b/sound/sparc/cs4231.c
@@ -1563,6 +1563,7 @@ static int __init cs4231_attach_begin(struct snd_card **rcard)
{
struct snd_card *card;
struct snd_cs4231 *chip;
+ int err;
*rcard = NULL;
@@ -1574,10 +1575,10 @@ static int __init cs4231_attach_begin(struct snd_card **rcard)
return -ENOENT;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_cs4231));
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_cs4231), &card);
+ if (err < 0)
+ return err;
strcpy(card->driver, "CS4231");
strcpy(card->shortname, "Sun CS4231");
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
index 23ed6f04a71..af95ff1e126 100644
--- a/sound/sparc/dbri.c
+++ b/sound/sparc/dbri.c
@@ -2612,10 +2612,10 @@ static int __devinit dbri_probe(struct of_device *op, const struct of_device_id
return -ENODEV;
}
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct snd_dbri));
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct snd_dbri), &card);
+ if (err < 0)
+ return err;
strcpy(card->driver, "DBRI");
strcpy(card->shortname, "Sun DBRI");
diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c
index 09802e8a6fb..4c7b051f9d1 100644
--- a/sound/spi/at73c213.c
+++ b/sound/spi/at73c213.c
@@ -965,12 +965,11 @@ static int __devinit snd_at73c213_probe(struct spi_device *spi)
return PTR_ERR(board->dac_clk);
}
- retval = -ENOMEM;
-
/* Allocate "card" using some unused identifiers. */
snprintf(id, sizeof id, "at73c213_%d", board->ssc_id);
- card = snd_card_new(-1, id, THIS_MODULE, sizeof(struct snd_at73c213));
- if (!card)
+ retval = snd_card_create(-1, id, THIS_MODULE,
+ sizeof(struct snd_at73c213), &card);
+ if (retval < 0)
goto out;
chip = card->private_data;
diff --git a/sound/synth/emux/emux_hwdep.c b/sound/synth/emux/emux_hwdep.c
index 0a5391436ad..ff0b2a8fd25 100644
--- a/sound/synth/emux/emux_hwdep.c
+++ b/sound/synth/emux/emux_hwdep.c
@@ -24,25 +24,6 @@
#include <asm/uaccess.h>
#include "emux_voice.h"
-/*
- * open the hwdep device
- */
-static int
-snd_emux_hwdep_open(struct snd_hwdep *hw, struct file *file)
-{
- return 0;
-}
-
-
-/*
- * close the device
- */
-static int
-snd_emux_hwdep_release(struct snd_hwdep *hw, struct file *file)
-{
- return 0;
-}
-
#define TMP_CLIENT_ID 0x1001
@@ -146,8 +127,6 @@ snd_emux_init_hwdep(struct snd_emux *emu)
emu->hwdep = hw;
strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME);
hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE;
- hw->ops.open = snd_emux_hwdep_open;
- hw->ops.release = snd_emux_hwdep_release;
hw->ops.ioctl = snd_emux_hwdep_ioctl;
hw->exclusive = 1;
hw->private_data = emu;
diff --git a/sound/synth/emux/emux_oss.c b/sound/synth/emux/emux_oss.c
index 5c47b6c0926..87e42206c4e 100644
--- a/sound/synth/emux/emux_oss.c
+++ b/sound/synth/emux/emux_oss.c
@@ -132,7 +132,7 @@ snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure)
p = snd_emux_create_port(emu, tmpname, 32,
1, &callback);
if (p == NULL) {
- snd_printk("can't create port\n");
+ snd_printk(KERN_ERR "can't create port\n");
snd_emux_dec_count(emu);
mutex_unlock(&emu->register_mutex);
return -ENOMEM;
diff --git a/sound/synth/emux/emux_seq.c b/sound/synth/emux/emux_seq.c
index 335aa2ce257..ca5f7effb4d 100644
--- a/sound/synth/emux/emux_seq.c
+++ b/sound/synth/emux/emux_seq.c
@@ -74,15 +74,15 @@ snd_emux_init_seq(struct snd_emux *emu, struct snd_card *card, int index)
emu->client = snd_seq_create_kernel_client(card, index,
"%s WaveTable", emu->name);
if (emu->client < 0) {
- snd_printk("can't create client\n");
+ snd_printk(KERN_ERR "can't create client\n");
return -ENODEV;
}
if (emu->num_ports < 0) {
- snd_printk("seqports must be greater than zero\n");
+ snd_printk(KERN_WARNING "seqports must be greater than zero\n");
emu->num_ports = 1;
} else if (emu->num_ports >= SNDRV_EMUX_MAX_PORTS) {
- snd_printk("too many ports."
+ snd_printk(KERN_WARNING "too many ports."
"limited max. ports %d\n", SNDRV_EMUX_MAX_PORTS);
emu->num_ports = SNDRV_EMUX_MAX_PORTS;
}
@@ -100,7 +100,7 @@ snd_emux_init_seq(struct snd_emux *emu, struct snd_card *card, int index)
p = snd_emux_create_port(emu, tmpname, MIDI_CHANNELS,
0, &pinfo);
if (p == NULL) {
- snd_printk("can't create port\n");
+ snd_printk(KERN_ERR "can't create port\n");
return -ENOMEM;
}
@@ -147,12 +147,12 @@ snd_emux_create_port(struct snd_emux *emu, char *name,
/* Allocate structures for this channel */
if ((p = kzalloc(sizeof(*p), GFP_KERNEL)) == NULL) {
- snd_printk("no memory\n");
+ snd_printk(KERN_ERR "no memory\n");
return NULL;
}
p->chset.channels = kcalloc(max_channels, sizeof(struct snd_midi_channel), GFP_KERNEL);
if (p->chset.channels == NULL) {
- snd_printk("no memory\n");
+ snd_printk(KERN_ERR "no memory\n");
kfree(p);
return NULL;
}
@@ -376,12 +376,12 @@ int snd_emux_init_virmidi(struct snd_emux *emu, struct snd_card *card)
goto __error;
}
emu->vmidi[i] = rmidi;
- //snd_printk("virmidi %d ok\n", i);
+ /* snd_printk(KERN_DEBUG "virmidi %d ok\n", i); */
}
return 0;
__error:
- //snd_printk("error init..\n");
+ /* snd_printk(KERN_DEBUG "error init..\n"); */
snd_emux_delete_virmidi(emu);
return -ENOMEM;
}
diff --git a/sound/synth/emux/emux_synth.c b/sound/synth/emux/emux_synth.c
index 2cc6f6f7906..3e921b386fd 100644
--- a/sound/synth/emux/emux_synth.c
+++ b/sound/synth/emux/emux_synth.c
@@ -956,7 +956,8 @@ void snd_emux_lock_voice(struct snd_emux *emu, int voice)
if (emu->voices[voice].state == SNDRV_EMUX_ST_OFF)
emu->voices[voice].state = SNDRV_EMUX_ST_LOCKED;
else
- snd_printk("invalid voice for lock %d (state = %x)\n",
+ snd_printk(KERN_WARNING
+ "invalid voice for lock %d (state = %x)\n",
voice, emu->voices[voice].state);
spin_unlock_irqrestore(&emu->voice_lock, flags);
}
@@ -973,7 +974,8 @@ void snd_emux_unlock_voice(struct snd_emux *emu, int voice)
if (emu->voices[voice].state == SNDRV_EMUX_ST_LOCKED)
emu->voices[voice].state = SNDRV_EMUX_ST_OFF;
else
- snd_printk("invalid voice for unlock %d (state = %x)\n",
+ snd_printk(KERN_WARNING
+ "invalid voice for unlock %d (state = %x)\n",
voice, emu->voices[voice].state);
spin_unlock_irqrestore(&emu->voice_lock, flags);
}
diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c
index 36d53bd317e..63c8f45c0c2 100644
--- a/sound/synth/emux/soundfont.c
+++ b/sound/synth/emux/soundfont.c
@@ -133,7 +133,7 @@ snd_soundfont_load(struct snd_sf_list *sflist, const void __user *data,
int rc;
if (count < (long)sizeof(patch)) {
- snd_printk("patch record too small %ld\n", count);
+ snd_printk(KERN_ERR "patch record too small %ld\n", count);
return -EINVAL;
}
if (copy_from_user(&patch, data, sizeof(patch)))
@@ -143,15 +143,16 @@ snd_soundfont_load(struct snd_sf_list *sflist, const void __user *data,
data += sizeof(patch);
if (patch.key != SNDRV_OSS_SOUNDFONT_PATCH) {
- snd_printk("'The wrong kind of patch' %x\n", patch.key);
+ snd_printk(KERN_ERR "The wrong kind of patch %x\n", patch.key);
return -EINVAL;
}
if (count < patch.len) {
- snd_printk("Patch too short %ld, need %d\n", count, patch.len);
+ snd_printk(KERN_ERR "Patch too short %ld, need %d\n",
+ count, patch.len);
return -EINVAL;
}
if (patch.len < 0) {
- snd_printk("poor length %d\n", patch.len);
+ snd_printk(KERN_ERR "poor length %d\n", patch.len);
return -EINVAL;
}
@@ -195,7 +196,8 @@ snd_soundfont_load(struct snd_sf_list *sflist, const void __user *data,
case SNDRV_SFNT_REMOVE_INFO:
/* patch must be opened */
if (!sflist->currsf) {
- snd_printk("soundfont: remove_info: patch not opened\n");
+ snd_printk(KERN_ERR "soundfont: remove_info: "
+ "patch not opened\n");
rc = -EINVAL;
} else {
int bank, instr;
@@ -531,7 +533,7 @@ load_info(struct snd_sf_list *sflist, const void __user *data, long count)
return -EINVAL;
if (count < (long)sizeof(hdr)) {
- printk("Soundfont error: invalid patch zone length\n");
+ printk(KERN_ERR "Soundfont error: invalid patch zone length\n");
return -EINVAL;
}
if (copy_from_user((char*)&hdr, data, sizeof(hdr)))
@@ -541,12 +543,14 @@ load_info(struct snd_sf_list *sflist, const void __user *data, long count)
count -= sizeof(hdr);
if (hdr.nvoices <= 0 || hdr.nvoices >= 100) {
- printk("Soundfont error: Illegal voice number %d\n", hdr.nvoices);
+ printk(KERN_ERR "Soundfont error: Illegal voice number %d\n",
+ hdr.nvoices);
return -EINVAL;
}
if (count < (long)sizeof(struct soundfont_voice_info) * hdr.nvoices) {
- printk("Soundfont Error: patch length(%ld) is smaller than nvoices(%d)\n",
+ printk(KERN_ERR "Soundfont Error: "
+ "patch length(%ld) is smaller than nvoices(%d)\n",
count, hdr.nvoices);
return -EINVAL;
}
@@ -952,7 +956,7 @@ load_guspatch(struct snd_sf_list *sflist, const char __user *data,
int rc;
if (count < (long)sizeof(patch)) {
- snd_printk("patch record too small %ld\n", count);
+ snd_printk(KERN_ERR "patch record too small %ld\n", count);
return -EINVAL;
}
if (copy_from_user(&patch, data, sizeof(patch)))
@@ -1034,7 +1038,8 @@ load_guspatch(struct snd_sf_list *sflist, const char __user *data,
/* panning position; -128 - 127 => 0-127 */
zone->v.pan = (patch.panning + 128) / 2;
#if 0
- snd_printk("gus: basefrq=%d (ofs=%d) root=%d,tune=%d, range:%d-%d\n",
+ snd_printk(KERN_DEBUG
+ "gus: basefrq=%d (ofs=%d) root=%d,tune=%d, range:%d-%d\n",
(int)patch.base_freq, zone->v.rate_offset,
zone->v.root, zone->v.tune, zone->v.low, zone->v.high);
#endif
@@ -1068,7 +1073,8 @@ load_guspatch(struct snd_sf_list *sflist, const char __user *data,
zone->v.parm.volrelease = 0x8000 | snd_sf_calc_parm_decay(release);
zone->v.attenuation = calc_gus_attenuation(patch.env_offset[0]);
#if 0
- snd_printk("gus: atkhld=%x, dcysus=%x, volrel=%x, att=%d\n",
+ snd_printk(KERN_DEBUG
+ "gus: atkhld=%x, dcysus=%x, volrel=%x, att=%d\n",
zone->v.parm.volatkhld,
zone->v.parm.voldcysus,
zone->v.parm.volrelease,
diff --git a/sound/usb/caiaq/caiaq-device.c b/sound/usb/caiaq/caiaq-device.c
index 41c36b055f6..09aed2363cc 100644
--- a/sound/usb/caiaq/caiaq-device.c
+++ b/sound/usb/caiaq/caiaq-device.c
@@ -336,9 +336,10 @@ static void __devinit setup_card(struct snd_usb_caiaqdev *dev)
log("Unable to set up control system (ret=%d)\n", ret);
}
-static struct snd_card* create_card(struct usb_device* usb_dev)
+static int create_card(struct usb_device* usb_dev, struct snd_card **cardp)
{
int devnum;
+ int err;
struct snd_card *card;
struct snd_usb_caiaqdev *dev;
@@ -347,12 +348,12 @@ static struct snd_card* create_card(struct usb_device* usb_dev)
break;
if (devnum >= SNDRV_CARDS)
- return NULL;
+ return -ENODEV;
- card = snd_card_new(index[devnum], id[devnum], THIS_MODULE,
- sizeof(struct snd_usb_caiaqdev));
- if (!card)
- return NULL;
+ err = snd_card_create(index[devnum], id[devnum], THIS_MODULE,
+ sizeof(struct snd_usb_caiaqdev), &card);
+ if (err < 0)
+ return err;
dev = caiaqdev(card);
dev->chip.dev = usb_dev;
@@ -362,7 +363,8 @@ static struct snd_card* create_card(struct usb_device* usb_dev)
spin_lock_init(&dev->spinlock);
snd_card_set_dev(card, &usb_dev->dev);
- return card;
+ *cardp = card;
+ return 0;
}
static int __devinit init_card(struct snd_usb_caiaqdev *dev)
@@ -441,10 +443,10 @@ static int __devinit snd_probe(struct usb_interface *intf,
struct snd_card *card;
struct usb_device *device = interface_to_usbdev(intf);
- card = create_card(device);
+ ret = create_card(device, &card);
- if (!card)
- return -ENOMEM;
+ if (ret < 0)
+ return ret;
usb_set_intfdata(intf, card);
ret = init_card(caiaqdev(card));
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index c709b956322..8f3cdb37a0e 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -2524,7 +2524,6 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform
* build the rate table and bitmap flags
*/
int r, idx;
- unsigned int nonzero_rates = 0;
fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL);
if (fp->rate_table == NULL) {
@@ -2532,24 +2531,27 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform
return -1;
}
- fp->nr_rates = nr_rates;
- fp->rate_min = fp->rate_max = combine_triple(&fmt[8]);
+ fp->nr_rates = 0;
+ fp->rate_min = fp->rate_max = 0;
for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) {
unsigned int rate = combine_triple(&fmt[idx]);
+ if (!rate)
+ continue;
/* C-Media CM6501 mislabels its 96 kHz altsetting */
if (rate == 48000 && nr_rates == 1 &&
- chip->usb_id == USB_ID(0x0d8c, 0x0201) &&
+ (chip->usb_id == USB_ID(0x0d8c, 0x0201) ||
+ chip->usb_id == USB_ID(0x0d8c, 0x0102)) &&
fp->altsetting == 5 && fp->maxpacksize == 392)
rate = 96000;
- fp->rate_table[r] = rate;
- nonzero_rates |= rate;
- if (rate < fp->rate_min)
+ fp->rate_table[fp->nr_rates] = rate;
+ if (!fp->rate_min || rate < fp->rate_min)
fp->rate_min = rate;
- else if (rate > fp->rate_max)
+ if (!fp->rate_max || rate > fp->rate_max)
fp->rate_max = rate;
fp->rates |= snd_pcm_rate_to_rate_bit(rate);
+ fp->nr_rates++;
}
- if (!nonzero_rates) {
+ if (!fp->nr_rates) {
hwc_debug("All rates were zero. Skipping format!\n");
return -1;
}
@@ -2966,6 +2968,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
return -EINVAL;
}
alts = &iface->altsetting[fp->altset_idx];
+ fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
usb_set_interface(chip->dev, fp->iface, 0);
init_usb_pitch(chip->dev, fp->iface, alts, fp);
init_usb_sample_rate(chip->dev, fp->iface, alts, fp, fp->rate_max);
@@ -3463,10 +3466,10 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
return -ENXIO;
}
- card = snd_card_new(index[idx], id[idx], THIS_MODULE, 0);
- if (card == NULL) {
+ err = snd_card_create(index[idx], id[idx], THIS_MODULE, 0, &card);
+ if (err < 0) {
snd_printk(KERN_ERR "cannot create card instance %d\n", idx);
- return -ENOMEM;
+ return err;
}
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
index 320641ab5be..26bad373fe6 100644
--- a/sound/usb/usbmidi.c
+++ b/sound/usb/usbmidi.c
@@ -1625,6 +1625,7 @@ static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi* umidi,
}
ep_info.out_ep = get_endpoint(hostif, 2)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+ ep_info.out_interval = 0;
ep_info.out_cables = endpoint->out_cables & 0x5555;
err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]);
if (err < 0)
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index 00397c8a765..2bde79216fa 100644
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -78,7 +78,6 @@ struct usb_mixer_interface {
/* Sound Blaster remote control stuff */
const struct rc_config *rc_cfg;
- unsigned long rc_hwdep_open;
u32 rc_code;
wait_queue_head_t rc_waitq;
struct urb *rc_urb;
@@ -1797,24 +1796,6 @@ static void snd_usb_soundblaster_remote_complete(struct urb *urb)
wake_up(&mixer->rc_waitq);
}
-static int snd_usb_sbrc_hwdep_open(struct snd_hwdep *hw, struct file *file)
-{
- struct usb_mixer_interface *mixer = hw->private_data;
-
- if (test_and_set_bit(0, &mixer->rc_hwdep_open))
- return -EBUSY;
- return 0;
-}
-
-static int snd_usb_sbrc_hwdep_release(struct snd_hwdep *hw, struct file *file)
-{
- struct usb_mixer_interface *mixer = hw->private_data;
-
- clear_bit(0, &mixer->rc_hwdep_open);
- smp_mb__after_clear_bit();
- return 0;
-}
-
static long snd_usb_sbrc_hwdep_read(struct snd_hwdep *hw, char __user *buf,
long count, loff_t *offset)
{
@@ -1867,9 +1848,8 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer)
hwdep->iface = SNDRV_HWDEP_IFACE_SB_RC;
hwdep->private_data = mixer;
hwdep->ops.read = snd_usb_sbrc_hwdep_read;
- hwdep->ops.open = snd_usb_sbrc_hwdep_open;
- hwdep->ops.release = snd_usb_sbrc_hwdep_release;
hwdep->ops.poll = snd_usb_sbrc_hwdep_poll;
+ hwdep->exclusive = 1;
mixer->rc_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!mixer->rc_urb)
diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c
index 73e59f4403a..98276aafefe 100644
--- a/sound/usb/usx2y/us122l.c
+++ b/sound/usb/usx2y/us122l.c
@@ -478,19 +478,21 @@ static bool us122l_create_card(struct snd_card *card)
return true;
}
-static struct snd_card *usx2y_create_card(struct usb_device *device)
+static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp)
{
int dev;
struct snd_card *card;
+ int err;
+
for (dev = 0; dev < SNDRV_CARDS; ++dev)
if (enable[dev] && !snd_us122l_card_used[dev])
break;
if (dev >= SNDRV_CARDS)
- return NULL;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE,
- sizeof(struct us122l));
- if (!card)
- return NULL;
+ return -ENODEV;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct us122l), &card);
+ if (err < 0)
+ return err;
snd_us122l_card_used[US122L(card)->chip.index = dev] = 1;
US122L(card)->chip.dev = device;
@@ -509,46 +511,57 @@ static struct snd_card *usx2y_create_card(struct usb_device *device)
US122L(card)->chip.dev->devnum
);
snd_card_set_dev(card, &device->dev);
- return card;
+ *cardp = card;
+ return 0;
}
-static void *us122l_usb_probe(struct usb_interface *intf,
- const struct usb_device_id *device_id)
+static int us122l_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *device_id,
+ struct snd_card **cardp)
{
struct usb_device *device = interface_to_usbdev(intf);
- struct snd_card *card = usx2y_create_card(device);
+ struct snd_card *card;
+ int err;
- if (!card)
- return NULL;
+ err = usx2y_create_card(device, &card);
+ if (err < 0)
+ return err;
- if (!us122l_create_card(card) ||
- snd_card_register(card) < 0) {
+ if (!us122l_create_card(card)) {
snd_card_free(card);
- return NULL;
+ return -EINVAL;
+ }
+
+ err = snd_card_register(card);
+ if (err < 0) {
+ snd_card_free(card);
+ return err;
}
usb_get_dev(device);
- return card;
+ *cardp = card;
+ return 0;
}
static int snd_us122l_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct snd_card *card;
+ int err;
+
snd_printdd(KERN_DEBUG"%p:%i\n",
intf, intf->cur_altsetting->desc.bInterfaceNumber);
if (intf->cur_altsetting->desc.bInterfaceNumber != 1)
return 0;
- card = us122l_usb_probe(usb_get_intf(intf), id);
-
- if (card) {
- usb_set_intfdata(intf, card);
- return 0;
+ err = us122l_usb_probe(usb_get_intf(intf), id, &card);
+ if (err < 0) {
+ usb_put_intf(intf);
+ return err;
}
- usb_put_intf(intf);
- return -EIO;
+ usb_set_intfdata(intf, card);
+ return 0;
}
static void snd_us122l_disconnect(struct usb_interface *intf)
diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c
index 1558a5c4094..4af8740db71 100644
--- a/sound/usb/usx2y/usX2Yhwdep.c
+++ b/sound/usb/usx2y/usX2Yhwdep.c
@@ -30,9 +30,6 @@
#include "usbusx2y.h"
#include "usX2Yhwdep.h"
-int usX2Y_hwdep_pcm_new(struct snd_card *card);
-
-
static int snd_us428ctls_vm_fault(struct vm_area_struct *area,
struct vm_fault *vmf)
{
@@ -106,16 +103,6 @@ static unsigned int snd_us428ctls_poll(struct snd_hwdep *hw, struct file *file,
}
-static int snd_usX2Y_hwdep_open(struct snd_hwdep *hw, struct file *file)
-{
- return 0;
-}
-
-static int snd_usX2Y_hwdep_release(struct snd_hwdep *hw, struct file *file)
-{
- return 0;
-}
-
static int snd_usX2Y_hwdep_dsp_status(struct snd_hwdep *hw,
struct snd_hwdep_dsp_status *info)
{
@@ -267,8 +254,6 @@ int usX2Y_hwdep_new(struct snd_card *card, struct usb_device* device)
hw->iface = SNDRV_HWDEP_IFACE_USX2Y;
hw->private_data = usX2Y(card);
- hw->ops.open = snd_usX2Y_hwdep_open;
- hw->ops.release = snd_usX2Y_hwdep_release;
hw->ops.dsp_status = snd_usX2Y_hwdep_dsp_status;
hw->ops.dsp_load = snd_usX2Y_hwdep_dsp_load;
hw->ops.mmap = snd_us428ctls_mmap;
diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c
index 11639bd72a5..5ce0da23ee9 100644
--- a/sound/usb/usx2y/usbusx2y.c
+++ b/sound/usb/usx2y/usbusx2y.c
@@ -227,9 +227,9 @@ static void i_usX2Y_In04Int(struct urb *urb)
if (usX2Y->US04) {
if (0 == usX2Y->US04->submitted)
- do
+ do {
err = usb_submit_urb(usX2Y->US04->urb[usX2Y->US04->submitted++], GFP_ATOMIC);
- while (!err && usX2Y->US04->submitted < usX2Y->US04->len);
+ } while (!err && usX2Y->US04->submitted < usX2Y->US04->len);
} else
if (us428ctls && us428ctls->p4outLast >= 0 && us428ctls->p4outLast < N_us428_p4out_BUFS) {
if (us428ctls->p4outLast != us428ctls->p4outSent) {
@@ -333,18 +333,21 @@ static struct usb_device_id snd_usX2Y_usb_id_table[] = {
{ /* terminator */ }
};
-static struct snd_card *usX2Y_create_card(struct usb_device *device)
+static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp)
{
int dev;
struct snd_card * card;
+ int err;
+
for (dev = 0; dev < SNDRV_CARDS; ++dev)
if (enable[dev] && !snd_usX2Y_card_used[dev])
break;
if (dev >= SNDRV_CARDS)
- return NULL;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct usX2Ydev));
- if (!card)
- return NULL;
+ return -ENODEV;
+ err = snd_card_create(index[dev], id[dev], THIS_MODULE,
+ sizeof(struct usX2Ydev), &card);
+ if (err < 0)
+ return err;
snd_usX2Y_card_used[usX2Y(card)->chip.index = dev] = 1;
card->private_free = snd_usX2Y_card_private_free;
usX2Y(card)->chip.dev = device;
@@ -362,26 +365,36 @@ static struct snd_card *usX2Y_create_card(struct usb_device *device)
usX2Y(card)->chip.dev->bus->busnum, usX2Y(card)->chip.dev->devnum
);
snd_card_set_dev(card, &device->dev);
- return card;
+ *cardp = card;
+ return 0;
}
-static void *usX2Y_usb_probe(struct usb_device *device, struct usb_interface *intf, const struct usb_device_id *device_id)
+static int usX2Y_usb_probe(struct usb_device *device,
+ struct usb_interface *intf,
+ const struct usb_device_id *device_id,
+ struct snd_card **cardp)
{
int err;
struct snd_card * card;
+
+ *cardp = NULL;
if (le16_to_cpu(device->descriptor.idVendor) != 0x1604 ||
(le16_to_cpu(device->descriptor.idProduct) != USB_ID_US122 &&
le16_to_cpu(device->descriptor.idProduct) != USB_ID_US224 &&
- le16_to_cpu(device->descriptor.idProduct) != USB_ID_US428) ||
- !(card = usX2Y_create_card(device)))
- return NULL;
+ le16_to_cpu(device->descriptor.idProduct) != USB_ID_US428))
+ return -EINVAL;
+
+ err = usX2Y_create_card(device, &card);
+ if (err < 0)
+ return err;
if ((err = usX2Y_hwdep_new(card, device)) < 0 ||
(err = snd_card_register(card)) < 0) {
snd_card_free(card);
- return NULL;
+ return err;
}
- return card;
+ *cardp = card;
+ return 0;
}
/*
@@ -389,13 +402,14 @@ static void *usX2Y_usb_probe(struct usb_device *device, struct usb_interface *in
*/
static int snd_usX2Y_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
- void *chip;
- chip = usX2Y_usb_probe(interface_to_usbdev(intf), intf, id);
- if (chip) {
- usb_set_intfdata(intf, chip);
- return 0;
- } else
- return -EIO;
+ struct snd_card *card;
+ int err;
+
+ err = usX2Y_usb_probe(interface_to_usbdev(intf), intf, id, &card);
+ if (err < 0)
+ return err;
+ dev_set_drvdata(&intf->dev, card);
+ return 0;
}
static void snd_usX2Y_disconnect(struct usb_interface *intf)
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.h b/sound/usb/usx2y/usx2yhwdeppcm.h
index c3382fdc386..9c4fb84b2aa 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.h
+++ b/sound/usb/usx2y/usx2yhwdeppcm.h
@@ -18,3 +18,5 @@ struct snd_usX2Y_hwdep_pcm_shm {
volatile unsigned captured_iso_frames;
int capture_iso_start;
};
+
+int usX2Y_hwdep_pcm_new(struct snd_card *card);